handle function application

Last updated: 2026-03-04T23:21:38.366Z

Metrics

LOC: 124 Complexity: 20 Params: 1

Signature

handle(message: ExtensionMessage): : Promise<unknown>

Architecture violations

View all

  • [warning] max-cyclomatic-complexity: 'handle' has cyclomatic complexity 20 (max 10)
  • [warning] max-lines: 'handle' has 124 lines (max 80)

Source Code

async function handle(message: ExtensionMessage): Promise<unknown> {
  switch (message.type) {
    case "GET_RULES":
      return getRules();

    case "SAVE_RULE": {
      const rule = parseRulePayload(message.payload);
      if (!rule) return { error: "Invalid payload for SAVE_RULE" };

      // Upsert by selector + URL pattern: if a rule already exists for the same
      // fieldSelector and matching URL pattern, re-use its ID so it gets updated
      // instead of creating a duplicate with a different ID.
      const allRules = await getRules();
      const existing = allRules.find(
        (r) =>
          r.fieldSelector === rule.fieldSelector &&
          r.urlPattern === rule.urlPattern,
      );
      const ruleToSave = existing
        ? { ...rule, id: existing.id, createdAt: existing.createdAt }
        : rule;

      await saveRule(ruleToSave);
      const signals = buildSignalsFromRule(ruleToSave);
      if (signals) {
        await storeLearnedEntry(
          signals,
          ruleToSave.fieldType,
          undefined,
          "rule",
        );
        await addDatasetEntry({
          signals,
          type: ruleToSave.fieldType,
          source: "manual",
          difficulty: "easy",
        });
      }
      void broadcastToAllTabs({ type: "INVALIDATE_CLASSIFIER" });
      return { success: true };
    }

    case "DELETE_RULE": {
      const ruleId = parseStringPayload(message.payload);
      if (!ruleId) return { error: "Invalid payload for DELETE_RULE" };
      await deleteRule(ruleId);
      return { success: true };
    }

    case "SAVE_FIELD_OVERRIDE": {
      const p = parseSaveFieldOverridePayload(message.payload);
      if (!p) return { error: "Invalid payload for SAVE_FIELD_OVERRIDE" };

      // Derive a hostname-level URL pattern so the rule applies to all pages
      // on the same domain (e.g. *://example.com/*)
      let urlPattern = "*";
      try {
        const parsed = new URL(p.url);
        urlPattern = `${parsed.protocol}//${parsed.hostname}/*`;
      } catch {
        // Fallback: use the raw URL as pattern
        urlPattern = p.url;
      }

      // Find existing rule for same URL pattern + fieldSelector
      const allRules = await getRules();
      const existing = allRules.find(
        (r) =>
          r.fieldSelector === p.fieldSelector &&
          matchUrlPattern(p.url, r.urlPattern),
      );

      const now = Date.now();
      const rule: FieldRule = {
        id: existing?.id ?? crypto.randomUUID(),
        urlPattern,
        fieldSelector: p.fieldSelector,
        fieldName: p.fieldName,
        fieldType: p.fieldType,
        generator: p.generator,
        fixedValue: p.fixedValue,
        aiPrompt: p.aiPrompt,
        generatorParams: p.generatorParams,
        selectOptionIndex: p.selectOptionIndex,
        priority: 100,
        createdAt: existing?.createdAt ?? now,
        updatedAt: now,
      };

      await saveRule(rule);
      const signals = buildSignalsFromRule(rule);
      if (signals) {
        await storeLearnedEntry(signals, rule.fieldType, undefined, "rule");
        await addDatasetEntry({
          signals,
          type: rule.fieldType,
          source: "manual",
          difficulty: "easy",
        });
      }
      void broadcastToAllTabs({ type: "INVALIDATE_CLASSIFIER" });
      return { success: true, rule };
    }

    case "DELETE_FIELD_OVERRIDE": {
      const p = parseDeleteFieldOverridePayload(message.payload);
      if (!p) return { error: "Invalid payload for DELETE_FIELD_OVERRIDE" };

      const allRules = await getRules();
      const match = allRules.find(
        (r) =>
          r.fieldSelector === p.fieldSelector &&
          matchUrlPattern(p.url, r.urlPattern),
      );
      if (!match) return { success: true }; // no rule to delete

      await deleteRule(match.id);
      return { success: true };
    }

    default:
      return { error: `Unhandled type in rulesHandler: ${message.type}` };
  }
}

Dependencies (Outgoing)

graph LR handle["handle"] MessageHandler["MessageHandler"] ExtensionMessage["ExtensionMessage"] FieldRule["FieldRule"] MessageType["MessageType"] getRules["getRules"] saveRule["saveRule"] deleteRule["deleteRule"] buildSignalsFromRule["buildSignalsFromRule"] storeLearnedEntry["storeLearnedEntry"] addDatasetEntry["addDatasetEntry"] parseRulePayload["parseRulePayload"] parseStringPayload["parseStringPayload"] parseSaveFieldOverridePayload["parseSaveFieldOverridePayload"] parseDeleteFieldOverridePayload["parseDeleteFieldOverridePayload"] broadcastToAllTabs["broadcastToAllTabs"] matchUrlPattern["matchUrlPattern"] handle -->|uses| MessageHandler handle -->|uses| ExtensionMessage handle -->|uses| FieldRule handle -->|uses| MessageType handle -->|uses| getRules handle -->|uses| saveRule handle -->|uses| deleteRule handle -->|uses| buildSignalsFromRule handle -->|uses| storeLearnedEntry handle -->|uses| addDatasetEntry handle -->|uses| parseRulePayload handle -->|uses| parseStringPayload handle -->|uses| parseSaveFieldOverridePayload handle -->|uses| parseDeleteFieldOverridePayload handle -->|uses| broadcastToAllTabs handle -->|uses| matchUrlPattern style handle fill:#dbeafe,stroke:#2563eb,stroke-width:2px click handle "57ebaea8374ad16b.html" click MessageHandler "ab334f3bc9eb52d7.html" click ExtensionMessage "c70465261f6c12b8.html" click FieldRule "2faad09a4e9d7546.html" click MessageType "2ef3f4e4b1044d26.html" click getRules "69aeb172cce4aa1c.html" click saveRule "63edd701c4b09a38.html" click deleteRule "a510ce97ee47641a.html" click buildSignalsFromRule "4c1a03d6233ed8c2.html" click storeLearnedEntry "2904bc5fab5c017a.html" click addDatasetEntry "85b3f0de7e9f307e.html" click parseRulePayload "7f38eb7a1d01b99b.html" click parseStringPayload "a410bc3f13516882.html" click parseSaveFieldOverridePayload "81328160cedd3c7f.html" click parseDeleteFieldOverridePayload "d4a9f12f91024e57.html" click broadcastToAllTabs "33948cfdc4069058.html" click matchUrlPattern "eb53b35bb6b3b7d8.html"

No incoming dependencies.