chrome-shim.ts

4.2 KB · raw

1// Capacitor chrome shim. The mobile foreground imports background modules that2// were written for MV3, so this supplies the small chrome.* surface they touch.34import { Preferences } from "@capacitor/preferences";56type Listener<T extends (...args: any[]) => void> = {7  addListener: (_listener: T) => void;8  removeListener: (_listener: T) => void;9};1011const sessionStore = new Map<string, unknown>();1213function noopListener<T extends (...args: any[]) => void>(): Listener<T> {14  return {15    addListener: () => {},16    removeListener: () => {},17  };18}1920async function keysFor(input: string | string[] | Record<string, unknown> | null): Promise<string[]> {21  if (input === null) {22    const result = await Preferences.keys();23    return result.keys;24  }25  if (Array.isArray(input)) return input;26  if (typeof input === "string") return [input];27  return Object.keys(input);28}2930async function localGet(keys: string | string[] | Record<string, unknown> | null): Promise<Record<string, unknown>> {31  const result: Record<string, unknown> = {};32  for (const key of await keysFor(keys)) {33    const { value } = await Preferences.get({ key });34    if (value === null) continue;35    try {36      result[key] = JSON.parse(value);37    } catch {38      result[key] = value;39    }40  }41  return result;42}4344async function localSet(items: Record<string, unknown>): Promise<void> {45  for (const [key, value] of Object.entries(items)) {46    await Preferences.set({ key, value: JSON.stringify(value) });47  }48}4950async function localRemove(keys: string | string[]): Promise<void> {51  const keyArray = Array.isArray(keys) ? keys : [keys];52  for (const key of keyArray) {53    await Preferences.remove({ key });54  }55}5657function sessionKeys(input: string | string[] | Record<string, unknown> | null): string[] {58  if (input === null) return [...sessionStore.keys()];59  if (Array.isArray(input)) return input;60  if (typeof input === "string") return [input];61  return Object.keys(input);62}6364const chromeShim = {65  runtime: {66    id: "peach-mobile",67    sendMessage: (_msg: unknown, cb?: (response: unknown) => void) => {68      const response = { ok: false, error: "NO_SERVICE_WORKER" };69      cb?.(response);70      return Promise.resolve(response);71    },72    onMessage: noopListener<(message: unknown) => void>(),73    connect: () => ({74      disconnect: () => {},75      onMessage: noopListener<(message: unknown) => void>(),76      onDisconnect: noopListener<() => void>(),77      postMessage: () => {},78    }),79    lastError: null,80  },81  storage: {82    local: {83      get: localGet,84      set: localSet,85      remove: localRemove,86      clear: () => Preferences.clear(),87    },88    session: {89      get: async (keys: string | string[] | Record<string, unknown> | null) => {90        const result: Record<string, unknown> = {};91        for (const key of sessionKeys(keys)) {92          if (sessionStore.has(key)) result[key] = sessionStore.get(key);93        }94        return result;95      },96      set: async (items: Record<string, unknown>) => {97        for (const [key, value] of Object.entries(items)) {98          sessionStore.set(key, value);99        }100      },101      remove: async (keys: string | string[]) => {102        const keyArray = Array.isArray(keys) ? keys : [keys];103        for (const key of keyArray) sessionStore.delete(key);104      },105      clear: async () => {106        sessionStore.clear();107      },108    },109    onChanged: noopListener<(changes: Record<string, unknown>, areaName: string) => void>(),110  },111  alarms: {112    clear: () => {},113    create: () => {},114    onAlarm: noopListener<(alarm: { name: string }) => void>(),115  },116  idle: {117    setDetectionInterval: () => {},118    onStateChanged: noopListener<(state: string) => void>(),119  },120  tabs: {121    query: (_query: unknown, cb?: (tabs: any[]) => void) => {122      cb?.([]);123      return Promise.resolve([]);124    },125    sendMessage: () => Promise.resolve(undefined),126    create: () => Promise.resolve(undefined),127    onActivated: noopListener<() => void>(),128    onUpdated: noopListener<() => void>(),129  },130  action: {131    openPopup: () => Promise.resolve(),132    setBadgeText: () => Promise.resolve(),133    setBadgeBackgroundColor: () => Promise.resolve(),134  },135  scripting: {136    executeScript: () => Promise.resolve(),137  },138};139140(window as any).chrome = chromeShim;