commands.ts

2.6 KB · raw

1/**2 * Keyboard command handler — routing for summon-autofill:3 *   1. Restricted URL (non-http/https) → open popup4 *   2. Ping content script (150ms timeout) → if alive, send SUMMON_AUTOFILL5 *      (content script opens the same unified inline selector used for field focus)6 *   3. Content script not ready / no login form detected → open popup fallback7 */89const PING_TIMEOUT_MS = 150;1011async function pingContentScript(tabId: number): Promise<boolean> {12  return new Promise((resolve) => {13    const timer = setTimeout(() => resolve(false), PING_TIMEOUT_MS);14    try {15      chrome.tabs.sendMessage(tabId, { type: "PING" }, (response) => {16        clearTimeout(timer);17        if (chrome.runtime.lastError) {18          resolve(false);19        } else {20          resolve(response?.ok === true);21        }22      });23    } catch {24      clearTimeout(timer);25      resolve(false);26    }27  });28}2930async function openPopup(): Promise<void> {31  try {32    // chrome.action.openPopup() requires Chrome 127+ and user gesture context;33    // it may throw — that's acceptable, we degrade gracefully.34    await (chrome.action as { openPopup?: () => Promise<void> }).openPopup?.();35  } catch {36    // Silently ignore — user can click the toolbar icon instead37  }38}3940export function setupCommands(): void {41  chrome.commands.onCommand.addListener(async (command) => {42    if (command !== "summon-autofill") return;4344    const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });45    if (!tab?.id || !tab.url) return;4647    // ── Step 1: restricted URL? ───────────────────────────────────48    if (!/^https?:\/\//i.test(tab.url)) {49      await openPopup();50      return;51    }5253    const tabId = tab.id;5455    // ── Step 2: ping existing content script ─────────────────────56    const alive = await pingContentScript(tabId);57    if (alive) {58      // Content script handles SUMMON_AUTOFILL by opening the unified inline59      // selector. It returns ok: true only when it found a login/signup form.60      // If ok: false (no form on page), fall through to open the popup.61      const response = await new Promise<{ ok?: boolean }>((resolve) => {62        try {63          chrome.tabs.sendMessage(tabId, { type: "SUMMON_AUTOFILL" }, (r) => {64            resolve((r as { ok?: boolean }) ?? {});65          });66        } catch {67          resolve({});68        }69      });70      if (response?.ok) return;71    }7273    // ── Step 3: content script unavailable or no login form ──────74    // Open the popup as a universal fallback.75    await openPopup();76  });77}