commands.ts

2.5 KB · raw

1/**2 * Keyboard command handler — routing for summon-inline:3 *   1. Restricted URL (non-http/https) → open popup4 *   2. Ping content script (150ms timeout) → if alive, send SUMMON_AUTOFILL5 *      with source:"shortcut"; content script handles inline (autofill selector6 *      or search-mode palette). Always returns early — no popup fallback.7 *   3. Content script not ready → open popup fallback8 */910const PING_TIMEOUT_MS = 150;1112async function pingContentScript(tabId: number): Promise<boolean> {13  return new Promise((resolve) => {14    const timer = setTimeout(() => resolve(false), PING_TIMEOUT_MS);15    try {16      chrome.tabs.sendMessage(tabId, { type: "PING" }, (response) => {17        clearTimeout(timer);18        if (chrome.runtime.lastError) {19          resolve(false);20        } else {21          resolve(response?.ok === true);22        }23      });24    } catch {25      clearTimeout(timer);26      resolve(false);27    }28  });29}3031async function openPopup(): Promise<void> {32  try {33    // chrome.action.openPopup() requires Chrome 127+ and user gesture context;34    // it may throw — that's acceptable, we degrade gracefully.35    await (chrome.action as { openPopup?: () => Promise<void> }).openPopup?.();36  } catch {37    // Silently ignore — user can click the toolbar icon instead38  }39}4041export function setupCommands(): void {42  chrome.commands.onCommand.addListener(async (command) => {43    if (command !== "summon-inline") return;4445    const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });46    if (!tab?.id || !tab.url) return;4748    // ── Step 1: restricted URL? ───────────────────────────────────49    if (!/^https?:\/\//i.test(tab.url)) {50      await openPopup();51      return;52    }5354    const tabId = tab.id;5556    // ── Step 2: ping existing content script ─────────────────────57    const alive = await pingContentScript(tabId);58    if (alive) {59      // Content script fully handles SUMMON_AUTOFILL with source:"shortcut":60      // shows the autofill selector when a form is present, or falls back to61      // a search-mode palette that copies to clipboard. No popup fallback needed.62      chrome.tabs.sendMessage(tabId, { type: "SUMMON_AUTOFILL", source: "shortcut" }).catch(() => {});63      return;64    }6566    // ── Step 3: content script unavailable ───────────────────────67    await openPopup();68  });69}