@fairfox/polly 0.19.0 → 0.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +131 -943
- package/dist/cli/polly.js +25 -4
- package/dist/cli/polly.js.map +3 -3
- package/dist/src/background/index.js +22 -12
- package/dist/src/background/index.js.map +3 -3
- package/dist/src/background/message-router.js +22 -12
- package/dist/src/background/message-router.js.map +3 -3
- package/dist/src/client/index.js +187 -154
- package/dist/src/client/index.js.map +4 -4
- package/dist/src/elysia/index.js +19 -9
- package/dist/src/elysia/index.js.map +2 -2
- package/dist/src/elysia/plugin.d.ts +3 -3
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +67 -14
- package/dist/src/index.js.map +7 -6
- package/dist/src/shared/adapters/index.js +22 -12
- package/dist/src/shared/adapters/index.js.map +3 -3
- package/dist/src/shared/lib/context-helpers.js +22 -12
- package/dist/src/shared/lib/context-helpers.js.map +3 -3
- package/dist/src/shared/lib/errors.js +19 -9
- package/dist/src/shared/lib/errors.js.map +2 -2
- package/dist/src/shared/lib/message-bus.js +22 -12
- package/dist/src/shared/lib/message-bus.js.map +3 -3
- package/dist/src/shared/lib/resource.d.ts +54 -0
- package/dist/src/shared/lib/resource.js +593 -0
- package/dist/src/shared/lib/resource.js.map +13 -0
- package/dist/src/shared/lib/state.d.ts +1 -0
- package/dist/src/shared/lib/state.js +23 -12
- package/dist/src/shared/lib/state.js.map +4 -4
- package/dist/src/shared/lib/test-helpers.js +19 -9
- package/dist/src/shared/lib/test-helpers.js.map +2 -2
- package/dist/src/shared/state/app-state.js +22 -12
- package/dist/src/shared/state/app-state.js.map +4 -4
- package/dist/src/shared/types/messages.js +19 -9
- package/dist/src/shared/types/messages.js.map +2 -2
- package/dist/tools/init/src/cli.js +6 -2
- package/dist/tools/init/src/cli.js.map +2 -2
- package/dist/tools/init/templates/pwa/package.json.template +1 -2
- package/dist/tools/test/src/adapters/index.d.ts +2 -2
- package/dist/tools/test/src/adapters/index.js +19 -9
- package/dist/tools/test/src/adapters/index.js.map +3 -3
- package/dist/tools/test/src/index.js +19 -9
- package/dist/tools/test/src/index.js.map +3 -3
- package/dist/tools/test/src/test-utils.js +19 -9
- package/dist/tools/test/src/test-utils.js.map +2 -2
- package/dist/tools/verify/specs/docker-compose.yml +1 -1
- package/dist/tools/verify/src/cli.js +185 -14
- package/dist/tools/verify/src/cli.js.map +7 -7
- package/dist/tools/verify/src/config.js +19 -9
- package/dist/tools/verify/src/config.js.map +2 -2
- package/dist/tools/visualize/src/cli.js +144 -5
- package/dist/tools/visualize/src/cli.js.map +3 -3
- package/package.json +12 -14
- package/dist/src/elysia/tla-generator.d.ts +0 -16
- package/dist/tools/verify/specs/verification.config.ts +0 -64
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/shared/lib/storage-adapter.ts", "../src/shared/lib/sync-adapter.ts", "../src/shared/lib/state.ts", "../src/shared/lib/resource.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"// Storage adapters for different execution contexts\n// Automatically chooses the right storage mechanism based on environment\n\n/**\n * Universal storage adapter interface\n */\nexport interface StorageAdapter {\n get<T = unknown>(keys: string[]): Promise<Record<string, T>>;\n set(items: Record<string, unknown>): Promise<void>;\n remove(keys: string[]): Promise<void>;\n}\n\n/**\n * IndexedDB adapter for web apps\n */\nexport class IndexedDBAdapter implements StorageAdapter {\n private dbName: string;\n private storeName = \"state\";\n private dbPromise: Promise<IDBDatabase> | null = null;\n\n constructor(dbName = \"polly-state\") {\n this.dbName = dbName;\n }\n\n private getDB(): Promise<IDBDatabase> {\n if (this.dbPromise) return this.dbPromise;\n\n this.dbPromise = new Promise((resolve, reject) => {\n const request = indexedDB.open(this.dbName, 1);\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result);\n\n request.onupgradeneeded = (event) => {\n const db = (event.target as IDBOpenDBRequest).result;\n if (!db.objectStoreNames.contains(this.storeName)) {\n db.createObjectStore(this.storeName);\n }\n };\n });\n\n return this.dbPromise;\n }\n\n async get<T = unknown>(keys: string[]): Promise<Record<string, T>> {\n try {\n const db = await this.getDB();\n const result: Record<string, T> = {};\n\n await Promise.all(\n keys.map(\n (key) =>\n new Promise<void>((resolve, reject) => {\n const transaction = db.transaction([this.storeName], \"readonly\");\n const store = transaction.objectStore(this.storeName);\n const request = store.get(key);\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n if (request.result !== undefined) {\n result[key] = request.result as T;\n }\n resolve();\n };\n })\n )\n );\n\n return result;\n } catch (error) {\n console.warn(\"[Polly] IndexedDB get failed:\", error);\n return {};\n }\n }\n\n async set(items: Record<string, unknown>): Promise<void> {\n try {\n const db = await this.getDB();\n await Promise.all(\n Object.entries(items).map(\n ([key, value]) =>\n new Promise<void>((resolve, reject) => {\n const transaction = db.transaction([this.storeName], \"readwrite\");\n const store = transaction.objectStore(this.storeName);\n const request = store.put(value, key);\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n })\n )\n );\n } catch (error) {\n console.warn(\"[Polly] IndexedDB set failed:\", error);\n }\n }\n\n async remove(keys: string[]): Promise<void> {\n try {\n const db = await this.getDB();\n await Promise.all(\n keys.map(\n (key) =>\n new Promise<void>((resolve, reject) => {\n const transaction = db.transaction([this.storeName], \"readwrite\");\n const store = transaction.objectStore(this.storeName);\n const request = store.delete(key);\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n })\n )\n );\n } catch (error) {\n console.warn(\"[Polly] IndexedDB remove failed:\", error);\n }\n }\n}\n\n/**\n * Chrome storage adapter for extensions\n */\nexport class ChromeStorageAdapter implements StorageAdapter {\n async get<T = unknown>(keys: string[]): Promise<Record<string, T>> {\n if (typeof chrome === \"undefined\" || !chrome.storage) {\n return {};\n }\n\n try {\n return (await chrome.storage.local.get(keys)) as Record<string, T>;\n } catch (error) {\n console.warn(\"[Polly] Chrome storage get failed:\", error);\n return {};\n }\n }\n\n async set(items: Record<string, unknown>): Promise<void> {\n if (typeof chrome === \"undefined\" || !chrome.storage) {\n return;\n }\n\n try {\n await chrome.storage.local.set(items);\n } catch (error) {\n console.warn(\"[Polly] Chrome storage set failed:\", error);\n }\n }\n\n async remove(keys: string[]): Promise<void> {\n if (typeof chrome === \"undefined\" || !chrome.storage) {\n return;\n }\n\n try {\n await chrome.storage.local.remove(keys);\n } catch (error) {\n console.warn(\"[Polly] Chrome storage remove failed:\", error);\n }\n }\n}\n\n/**\n * In-memory adapter (no persistence) for testing or server contexts\n */\nexport class MemoryStorageAdapter implements StorageAdapter {\n private storage = new Map<string, unknown>();\n\n async get<T = unknown>(keys: string[]): Promise<Record<string, T>> {\n const result: Record<string, T> = {};\n for (const key of keys) {\n const value = this.storage.get(key);\n if (value !== undefined) {\n result[key] = value as T;\n }\n }\n return result;\n }\n\n async set(items: Record<string, unknown>): Promise<void> {\n for (const [key, value] of Object.entries(items)) {\n this.storage.set(key, value);\n }\n }\n\n async remove(keys: string[]): Promise<void> {\n for (const key of keys) {\n this.storage.delete(key);\n }\n }\n}\n\n/**\n * Detect execution context and return appropriate storage adapter\n */\nexport function createStorageAdapter(): StorageAdapter {\n // Chrome extension context\n if (typeof chrome !== \"undefined\" && chrome.storage && chrome.runtime) {\n return new ChromeStorageAdapter();\n }\n\n // Web app context (has IndexedDB)\n if (typeof indexedDB !== \"undefined\") {\n return new IndexedDBAdapter();\n }\n\n // Server/test context (no persistent storage available)\n return new MemoryStorageAdapter();\n}\n",
|
|
6
|
+
"// Sync adapter interface for cross-context state synchronization\n// Abstracts the transport mechanism (chrome.runtime, BroadcastChannel, etc.)\n//\n// Architecture Decision: BroadcastChannel vs SharedWorker\n// ------------------------------------------------------\n// We currently use BroadcastChannel for web app sync because:\n// - Simpler API with no lifecycle management complexity\n// - Decentralized (aligns with local-first/offline-first architecture)\n// - Better browser support (especially Safari and mobile)\n// - Perfect for message-passing with Lamport clock conflict resolution\n// - No single point of failure\n//\n// Future Consideration: SharedWorker Support\n// ------------------------------------------\n// SharedWorker could be added as an optional adapter for use cases requiring:\n// - Central coordination point for complex multi-tab workflows\n// - Shared WebSocket connections (one connection for all tabs)\n// - Heavy computation done once and shared across tabs\n// - Persistent background work when tabs are closed\n// - Transaction coordination across tabs\n//\n// For most Polly use cases, BroadcastChannel's peer-to-peer model is preferred,\n// but SharedWorker support could be valuable for advanced scenarios.\n\n/**\n * Message format for state synchronization\n */\nexport interface StateSyncMessage<T = unknown> {\n key: string;\n value: T;\n clock: number;\n}\n\n/**\n * Sync adapter interface - abstracts the transport mechanism for state sync\n *\n * Different contexts use different transports:\n * - Chrome extensions: chrome.runtime messaging\n * - Web apps (multi-tab): BroadcastChannel\n * - PWAs: BroadcastChannel + Service Worker messaging\n * - Single-context: NoOp (no sync needed)\n */\nexport interface SyncAdapter {\n /**\n * Broadcast a state update to other contexts\n */\n broadcast<T>(message: StateSyncMessage<T>): void;\n\n /**\n * Register a callback for incoming state updates\n */\n onMessage<T>(callback: (message: StateSyncMessage<T>) => void): () => void;\n\n /**\n * Optional: Connect to the sync mechanism\n * Some transports require explicit connection setup\n */\n connect?(): Promise<void>;\n\n /**\n * Optional: Disconnect from the sync mechanism\n */\n disconnect?(): void;\n\n /**\n * Optional: Check if connected\n */\n isConnected?(): boolean;\n}\n\n/**\n * NoOp sync adapter for single-context scenarios (no sync needed)\n */\nexport class NoOpSyncAdapter implements SyncAdapter {\n broadcast<T>(_message: StateSyncMessage<T>): void {\n // No-op: single context, no need to sync\n }\n\n onMessage<T>(_callback: (message: StateSyncMessage<T>) => void): () => void {\n // No-op: no messages will ever arrive\n return () => {\n // Empty cleanup function - nothing to clean up for null adapter\n };\n }\n}\n\n/**\n * Chrome runtime sync adapter for Chrome extensions\n * Uses chrome.runtime.sendMessage for cross-context messaging\n */\nexport class ChromeRuntimeSyncAdapter implements SyncAdapter {\n private listeners: Array<(message: StateSyncMessage<unknown>) => void> = [];\n private port: chrome.runtime.Port | null = null;\n\n constructor() {\n // Set up listener for incoming messages\n if (typeof chrome !== \"undefined\" && chrome.runtime) {\n chrome.runtime.onMessage.addListener((message, _sender, _sendResponse) => {\n if (message.type === \"STATE_SYNC\") {\n this.listeners.forEach((listener) => {\n listener(message);\n });\n }\n });\n }\n }\n\n broadcast<T>(message: StateSyncMessage<T>): void {\n if (typeof chrome === \"undefined\" || !chrome.runtime) {\n console.warn(\"[SyncAdapter] chrome.runtime not available\");\n return;\n }\n\n try {\n chrome.runtime.sendMessage({\n type: \"STATE_SYNC\",\n key: message.key,\n value: message.value,\n clock: message.clock,\n });\n } catch (error) {\n console.warn(\"[SyncAdapter] Failed to broadcast state update:\", error);\n }\n }\n\n onMessage<T>(callback: (message: StateSyncMessage<T>) => void): () => void {\n this.listeners.push(callback as (message: StateSyncMessage<unknown>) => void);\n\n // Return cleanup function\n return () => {\n const index = this.listeners.indexOf(\n callback as (message: StateSyncMessage<unknown>) => void\n );\n if (index > -1) {\n this.listeners.splice(index, 1);\n }\n };\n }\n\n connect(): Promise<void> {\n // Chrome runtime is always connected\n return Promise.resolve();\n }\n\n disconnect(): void {\n this.listeners = [];\n if (this.port) {\n this.port.disconnect();\n this.port = null;\n }\n }\n\n isConnected(): boolean {\n return typeof chrome !== \"undefined\" && !!chrome.runtime;\n }\n}\n\n/**\n * BroadcastChannel sync adapter for web apps (multi-tab)\n * Uses BroadcastChannel API for cross-tab messaging\n */\nexport class BroadcastChannelSyncAdapter implements SyncAdapter {\n private channel: BroadcastChannel | null = null;\n private listeners: Array<(message: StateSyncMessage<unknown>) => void> = [];\n\n constructor(channelName = \"polly-sync\") {\n if (typeof BroadcastChannel === \"undefined\") {\n console.warn(\"[SyncAdapter] BroadcastChannel not available\");\n } else {\n this.channel = new BroadcastChannel(channelName);\n\n this.channel.onmessage = (event) => {\n if (event.data.type === \"STATE_SYNC\") {\n this.listeners.forEach((listener) => {\n listener(event.data);\n });\n }\n };\n }\n }\n\n broadcast<T>(message: StateSyncMessage<T>): void {\n if (!this.channel) {\n console.warn(\"[SyncAdapter] BroadcastChannel not initialized\");\n return;\n }\n\n try {\n this.channel.postMessage({\n type: \"STATE_SYNC\",\n key: message.key,\n value: message.value,\n clock: message.clock,\n });\n } catch (error) {\n console.warn(\"[SyncAdapter] Failed to broadcast state update:\", error);\n }\n }\n\n onMessage<T>(callback: (message: StateSyncMessage<T>) => void): () => void {\n this.listeners.push(callback as (message: StateSyncMessage<unknown>) => void);\n\n // Return cleanup function\n return () => {\n const index = this.listeners.indexOf(\n callback as (message: StateSyncMessage<unknown>) => void\n );\n if (index > -1) {\n this.listeners.splice(index, 1);\n }\n };\n }\n\n connect(): Promise<void> {\n // BroadcastChannel connects immediately on construction\n return Promise.resolve();\n }\n\n disconnect(): void {\n this.listeners = [];\n if (this.channel) {\n this.channel.close();\n this.channel = null;\n }\n }\n\n isConnected(): boolean {\n return this.channel !== null;\n }\n}\n\n/**\n * Detect available sync mechanisms and create appropriate adapter\n */\nexport function createSyncAdapter(): SyncAdapter {\n // Chrome extension context - use chrome.runtime\n if (typeof chrome !== \"undefined\" && chrome.runtime) {\n return new ChromeRuntimeSyncAdapter();\n }\n\n // Web app with multi-tab support - use BroadcastChannel\n if (typeof BroadcastChannel !== \"undefined\") {\n return new BroadcastChannelSyncAdapter();\n }\n\n // Single context or no sync available - use NoOp\n return new NoOpSyncAdapter();\n}\n",
|
|
7
|
+
"// State primitives with optional sync and persistence\n\nimport { effect, type Signal, signal } from \"@preact/signals\";\nimport type { MessageBus } from \"./message-bus\";\nimport { createStorageAdapter, type StorageAdapter } from \"./storage-adapter\";\nimport { createSyncAdapter, type SyncAdapter } from \"./sync-adapter\";\n\n/**\n * Signal extended with .loaded promise for hydration control\n */\ntype SignalWithLoaded<T> = Signal<T> & { loaded: Promise<void> };\n\n/**\n * Signal extended with .loaded and .verify properties for verification tracking\n */\ntype SignalWithVerify<T> = Signal<T> & { loaded: Promise<void>; verify: T };\n\ntype StateEntry<T> = {\n signal: Signal<T>;\n clock: number; // Lamport clock for causal ordering\n loaded: Promise<void>;\n updating: boolean;\n};\n\ntype StateOptions<T = unknown> = {\n // Legacy MessageBus support (deprecated, will be removed in v2.0)\n bus?: MessageBus;\n\n // New adapter system (recommended)\n storage?: StorageAdapter; // Custom storage adapter\n sync?: SyncAdapter; // Custom sync adapter\n\n // Behavior options\n debounceMs?: number; // Debounce storage writes\n validator?: (value: unknown) => value is T; // Runtime type validation\n verify?: boolean; // Enable verification tracking (creates plain object mirror)\n};\n\nconst stateRegistry = new Map<string, StateEntry<unknown>>();\n\n/**\n * Shared state: synced across all contexts AND persisted to storage\n *\n * Uses Lamport clock for conflict resolution. State is automatically:\n * - Loaded from chrome.storage on initialization\n * - Synced to other contexts via broadcast messages\n * - Persisted to chrome.storage on every change\n *\n * Available in: background, popup, options, devtools, content scripts\n * ⚠️ NOT available in page scripts (use content script state instead)\n *\n * @param key - Unique identifier for this state (e.g., \"app-settings\")\n * @param initialValue - Default value if nothing is in storage\n * @param options - Optional configuration (bus, debounceMs)\n * @returns Reactive signal that stays in sync across all contexts\n *\n * @example\n * ```typescript\n * // Define once, use everywhere\n * const settings = $sharedState(\"settings\", { theme: \"dark\" })\n *\n * // Changes automatically sync\n * settings.value = { theme: \"light\" }\n * ```\n */\nexport function $sharedState<T>(\n key: string,\n initialValue: T,\n options: StateOptions<T> = {}\n): Signal<T> & { loaded: Promise<void>; verify?: T } {\n const sig = createState(key, initialValue, {\n ...options,\n enableSync: true,\n enablePersist: true,\n });\n\n // Expose loaded promise for awaiting hydration\n const entry = stateRegistry.get(key);\n if (entry) {\n (sig as SignalWithLoaded<T>).loaded = entry.loaded;\n }\n\n return sig as Signal<T> & { loaded: Promise<void> };\n}\n\n/**\n * Synced state: synced across all contexts but NOT persisted\n *\n * State is broadcast to all contexts in real-time but resets on extension reload.\n *\n * Available in: background, popup, options, devtools, content scripts\n * ⚠️ NOT available in page scripts\n *\n * @param key - Unique identifier for this state\n * @param initialValue - Default value\n * @param options - Optional configuration\n * @returns Reactive signal synced across contexts (but not persisted)\n *\n * @example\n * ```typescript\n * // Temporary shared state\n * const activeTabId = $syncedState(\"active-tab\", null)\n * ```\n */\nexport function $syncedState<T>(\n key: string,\n initialValue: T,\n options: StateOptions<T> = {}\n): Signal<T> {\n return createState(key, initialValue, {\n ...options,\n enableSync: true,\n enablePersist: false,\n });\n}\n\n/**\n * Persisted state: persisted to storage but NOT synced across contexts\n *\n * Each context has its own copy of the state, persisted independently.\n *\n * Available in: background, popup, options, devtools, content scripts\n * ⚠️ NOT available in page scripts\n *\n * @param key - Unique identifier (use prefix like \"popup:state\" to avoid collisions)\n * @param initialValue - Default value\n * @param options - Optional configuration\n * @returns Reactive signal persisted to storage (but not synced)\n *\n * @example\n * ```typescript\n * // Each context has its own persisted state\n * const popupState = $persistedState(\"popup:last-panel\", \"home\")\n * const devtoolsState = $persistedState(\"devtools:expanded\", true)\n * ```\n */\nexport function $persistedState<T>(\n key: string,\n initialValue: T,\n options: StateOptions<T> = {}\n): Signal<T> & { loaded: Promise<void> } {\n const sig = createState(key, initialValue, {\n ...options,\n enableSync: false,\n enablePersist: true,\n });\n\n // Expose loaded promise for awaiting hydration\n const entry = stateRegistry.get(key);\n if (entry) {\n (sig as SignalWithLoaded<T>).loaded = entry.loaded;\n }\n\n return sig as Signal<T> & { loaded: Promise<void> };\n}\n\n/**\n * Local state: not synced, not persisted (like regular Preact signal)\n *\n * Simple reactive state that lives only in the current context.\n * Resets on reload or context restart.\n *\n * Available in: all contexts (including page scripts)\n *\n * @param initialValue - Default value\n * @returns Reactive signal (local only)\n *\n * @example\n * ```typescript\n * // Local UI state\n * const isLoading = $state(false)\n * const error = $state<string | null>(null)\n * ```\n */\nexport function $state<T>(initialValue: T): Signal<T> {\n return signal(initialValue);\n}\n\ntype InternalStateOptions<T = unknown> = StateOptions<T> & {\n enableSync: boolean; // Whether to enable sync (avoid collision with sync?: SyncAdapter)\n enablePersist: boolean; // Whether to enable persistence\n};\n\n// Deep equality check to prevent redundant updates\nexport function deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a == null || b == null) return false;\n if (typeof a !== \"object\" || typeof b !== \"object\") return false;\n\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (!keysB.includes(key)) return false;\n if (!deepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key]))\n return false;\n }\n\n return true;\n}\n\n/**\n * Resolve storage and sync adapters with three-tier priority:\n * 1. Explicit adapters from options (highest priority)\n * 2. MessageBus adapters (legacy, deprecated)\n * 3. Auto-detected adapters (default behavior)\n */\nfunction resolveAdapters(options: InternalStateOptions): {\n storage: StorageAdapter | null;\n sync: SyncAdapter | null;\n} {\n // Priority 1: Explicit adapters (partial or full)\n if (options.storage || options.sync) {\n return {\n storage: options.storage || (options.enablePersist ? createStorageAdapter() : null),\n sync: options.sync || (options.enableSync ? createSyncAdapter() : null),\n };\n }\n\n // Priority 2: MessageBus (legacy support)\n // Note: MessageBus doesn't provide sync adapter, only Chrome storage\n if (options.bus) {\n return {\n storage: options.bus.adapters.storage,\n sync: options.enableSync ? createSyncAdapter() : null,\n };\n }\n\n // Priority 3: Auto-detect based on enableSync and enablePersist flags\n return {\n storage: options.enablePersist ? createStorageAdapter() : null,\n sync: options.enableSync ? createSyncAdapter() : null,\n };\n}\n\nfunction createState<T>(key: string, initialValue: T, options: InternalStateOptions<T>): Signal<T> {\n // Return existing signal if already registered\n if (stateRegistry.has(key)) {\n return stateRegistry.get(key)?.signal as Signal<T>;\n }\n\n const sig = signal(initialValue);\n\n // Create verification mirror if requested\n if (options.verify) {\n // Create plain object mirror for verification\n const mirror = JSON.parse(JSON.stringify(initialValue)) as T;\n (sig as SignalWithVerify<T>).verify = mirror;\n }\n\n const entry: StateEntry<T> = {\n signal: sig,\n clock: 0,\n loaded: Promise.resolve(),\n updating: false,\n };\n\n // Resolve adapters (explicit, MessageBus, or auto-detect)\n const adapters = resolveAdapters(options);\n\n // Load from storage if persist is enabled\n if (options.enablePersist && adapters.storage) {\n entry.loaded = loadFromStorage(key, sig, entry, adapters.storage, options.validator);\n }\n\n // Watch for changes after initial load\n entry.loaded.then(() => {\n let debounceTimer: NodeJS.Timeout | null = null;\n let previousValue = sig.value;\n let isFirstRun = true;\n\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Sync effect requires coordination of multiple state change scenarios\n effect(() => {\n // Skip if update in progress (from incoming message)\n if (entry.updating) return;\n\n const value = sig.value;\n\n // Skip first run (effect fires immediately on registration)\n if (isFirstRun) {\n isFirstRun = false;\n return;\n }\n\n // Skip if value hasn't changed (deep equality check)\n if (deepEqual(value, previousValue)) {\n return;\n }\n\n previousValue = value;\n\n // Update verification mirror if enabled\n if (options.verify) {\n const verifySignal = sig as SignalWithVerify<T>;\n if (verifySignal.verify) {\n Object.assign(verifySignal.verify, JSON.parse(JSON.stringify(value)));\n }\n }\n\n // Increment clock monotonically\n entry.clock++;\n\n const doUpdate = () => {\n // Persist to storage\n if (options.enablePersist && adapters.storage) {\n persistToStorage(key, value, entry.clock, adapters.storage);\n }\n\n // Broadcast to other contexts\n if (options.enableSync && adapters.sync) {\n broadcastUpdate(key, value, entry.clock, adapters.sync);\n }\n };\n\n // Debounce if specified\n if (options.debounceMs) {\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(doUpdate, options.debounceMs);\n } else {\n doUpdate();\n }\n });\n });\n\n // Listen for updates from other contexts (only if sync enabled)\n if (options.enableSync && adapters.sync) {\n // Connect if needed (some adapters require explicit connection)\n if (adapters.sync.connect) {\n adapters.sync.connect();\n }\n\n // Register sync message listener\n adapters.sync.onMessage<T>((message) => {\n if (message.key !== key) return;\n\n const oldClock = entry.clock;\n\n // Lamport clock rule: Always update to max(local, received)\n // This maintains causal ordering even when rejecting updates\n entry.clock = Math.max(entry.clock, message.clock);\n\n // Only accept value updates if received clock is strictly greater than old local clock\n // This ensures we only apply causally newer updates\n if (message.clock > oldClock) {\n // Validate incoming value if validator provided\n if (options.validator && !options.validator(message.value)) {\n console.warn(\n `[Polly] State \"${key}\": Received invalid value from sync (clock: ${message.clock})`,\n message.value\n );\n return;\n }\n\n // Skip redundant updates (deep equality check)\n if (deepEqual(entry.signal.value, message.value)) {\n return;\n }\n\n applyUpdate(entry, message.value as T, message.clock);\n }\n });\n }\n\n stateRegistry.set(key, entry as StateEntry<unknown>);\n return sig;\n}\n\nasync function loadFromStorage<T>(\n key: string,\n sig: Signal<T>,\n entry: StateEntry<T>,\n storage: StorageAdapter,\n validator?: (value: unknown) => value is T\n): Promise<void> {\n try {\n const result = await storage.get([key, `${key}:clock`]);\n\n if (result[key] !== undefined) {\n const storedValue = result[key];\n\n // Validate stored value if validator provided\n if (validator) {\n if (validator(storedValue)) {\n sig.value = storedValue;\n } else {\n console.warn(\n `[Polly] State \"${key}\": Stored value failed validation, using initial value`,\n storedValue\n );\n }\n } else {\n sig.value = storedValue as T;\n }\n }\n\n if (result[`${key}:clock`] !== undefined) {\n entry.clock = result[`${key}:clock`] as number;\n }\n } catch (error) {\n console.warn(`[Polly] Failed to load state from storage: ${key}`, error);\n }\n}\n\nfunction persistToStorage<T>(key: string, value: T, clock: number, storage: StorageAdapter): void {\n try {\n storage.set({\n [key]: value,\n [`${key}:clock`]: clock,\n });\n } catch (error) {\n console.warn(`[Polly] Failed to persist state to storage: ${key}`, error);\n }\n}\n\nfunction broadcastUpdate<T>(key: string, value: T, clock: number, sync: SyncAdapter): void {\n try {\n sync.broadcast({\n key,\n value,\n clock,\n });\n } catch (error) {\n console.warn(`[Polly] Failed to broadcast state update: ${key}`, error);\n }\n}\n\nfunction applyUpdate<T>(entry: StateEntry<T>, value: T, clock: number): void {\n entry.updating = true;\n entry.signal.value = value;\n entry.clock = clock;\n entry.updating = false;\n}\n\n/**\n * Get state by key (useful for retrieving state without re-creating)\n */\nexport function getStateByKey<T>(key: string): Signal<T> | undefined {\n const entry = stateRegistry.get(key);\n return entry?.signal as Signal<T> | undefined;\n}\n\n/**\n * Clear state registry (useful for testing)\n */\nexport function clearStateRegistry(): void {\n stateRegistry.clear();\n}\n",
|
|
8
|
+
"/**\n * $resource — Async signal primitive that separates sync dependency tracking from async work.\n *\n * Reactive signal dependency tracking breaks at `await` boundaries. When a `computed()` or\n * `effect()` hits an `await`, JavaScript suspends the function and the tracking context is\n * lost. Signal reads after the `await` are silently dropped from the dependency graph.\n *\n * `$resource` solves this by splitting the problem:\n * - `source` is a synchronous function whose signal reads are fully tracked\n * - `fetcher` is an async function that receives source output — no signal access needed\n *\n * For verification, `$resource` emits three synthetic state machine transitions:\n * - `{name}_FetchStart`: source deps available, triggers loading\n * - `{name}_FetchSuccess`: fetch resolved, data updated\n * - `{name}_FetchError`: fetch rejected, error captured\n *\n * @example\n * ```ts\n * const todos = $resource(\"todos\", {\n * source: () => ({ userId: authState.value.userId }),\n * fetcher: async ({ userId }) => {\n * const res = await fetch(`/api/todos?userId=${userId}`);\n * return await res.json();\n * },\n * initialValue: [],\n * });\n *\n * todos.data // Signal<Todo[]>\n * todos.status // Signal<\"idle\" | \"loading\" | \"success\" | \"error\">\n * todos.error // Signal<Error | undefined>\n * todos.refetch()\n * ```\n */\n\nimport { effect, type Signal, signal } from \"@preact/signals\";\nimport { deepEqual } from \"./state\";\n\nexport type ResourceStatus = \"idle\" | \"loading\" | \"success\" | \"error\";\n\nexport type ResourceOptions<TSource, TData> = {\n /** Synchronous function that reads signals. Fully tracked by the reactivity system. */\n source: () => TSource;\n /** Async function that receives source output. Must not read any signals. */\n fetcher: (source: TSource) => Promise<TData>;\n /** Initial data value before first fetch completes. */\n initialValue: TData;\n};\n\nexport type Resource<TData> = {\n /** The fetched data (or initialValue before first successful fetch). */\n data: Signal<TData>;\n /** Current lifecycle status: idle → loading → success | error. */\n status: Signal<ResourceStatus>;\n /** The error from the most recent failed fetch, or undefined. */\n error: Signal<Error | undefined>;\n /** Re-run the fetcher with the current source values. */\n refetch: () => void;\n};\n\nexport function $resource<TSource, TData>(\n _name: string,\n options: ResourceOptions<TSource, TData>\n): Resource<TData> {\n const { source, fetcher, initialValue } = options;\n\n const data = signal<TData>(initialValue);\n const status = signal<ResourceStatus>(\"idle\");\n const error = signal<Error | undefined>(undefined);\n\n let generation = 0;\n let lastSource: TSource | undefined;\n\n function runFetch(sourceValue: TSource) {\n const thisGeneration = ++generation;\n status.value = \"loading\";\n error.value = undefined;\n\n fetcher(sourceValue).then(\n (result) => {\n if (thisGeneration !== generation) return; // stale\n data.value = result;\n status.value = \"success\";\n error.value = undefined;\n },\n (err) => {\n if (thisGeneration !== generation) return; // stale\n status.value = \"error\";\n error.value = err instanceof Error ? err : new Error(String(err));\n }\n );\n }\n\n // Track source synchronously — when source output changes, call fetcher\n effect(() => {\n const sourceValue = source();\n\n if (lastSource !== undefined && deepEqual(lastSource, sourceValue)) {\n return;\n }\n lastSource = sourceValue;\n runFetch(sourceValue);\n });\n\n function refetch() {\n if (lastSource !== undefined) {\n runFetch(lastSource);\n }\n }\n\n return { data, status, error, refetch };\n}\n"
|
|
9
|
+
],
|
|
10
|
+
"mappings": "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",
|
|
11
|
+
"debugId": "CA95E0087865A45C64756E2164756E21",
|
|
12
|
+
"names": []
|
|
13
|
+
}
|
|
@@ -101,6 +101,7 @@ export declare function $persistedState<T>(key: string, initialValue: T, options
|
|
|
101
101
|
* ```
|
|
102
102
|
*/
|
|
103
103
|
export declare function $state<T>(initialValue: T): Signal<T>;
|
|
104
|
+
export declare function deepEqual(a: unknown, b: unknown): boolean;
|
|
104
105
|
/**
|
|
105
106
|
* Get state by key (useful for retrieving state without re-creating)
|
|
106
107
|
*/
|
|
@@ -2,27 +2,37 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
-
|
|
5
|
+
function __accessProp(key) {
|
|
6
|
+
return this[key];
|
|
7
|
+
}
|
|
6
8
|
var __toCommonJS = (from) => {
|
|
7
|
-
var entry = __moduleCache.get(from), desc;
|
|
9
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
8
10
|
if (entry)
|
|
9
11
|
return entry;
|
|
10
12
|
entry = __defProp({}, "__esModule", { value: true });
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function")
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (var key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(entry, key))
|
|
16
|
+
__defProp(entry, key, {
|
|
17
|
+
get: __accessProp.bind(from, key),
|
|
18
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
19
|
+
});
|
|
20
|
+
}
|
|
16
21
|
__moduleCache.set(from, entry);
|
|
17
22
|
return entry;
|
|
18
23
|
};
|
|
24
|
+
var __moduleCache;
|
|
25
|
+
var __returnValue = (v) => v;
|
|
26
|
+
function __exportSetter(name, newValue) {
|
|
27
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
28
|
+
}
|
|
19
29
|
var __export = (target, all) => {
|
|
20
30
|
for (var name in all)
|
|
21
31
|
__defProp(target, name, {
|
|
22
32
|
get: all[name],
|
|
23
33
|
enumerable: true,
|
|
24
34
|
configurable: true,
|
|
25
|
-
set: (
|
|
35
|
+
set: __exportSetter.bind(all, name)
|
|
26
36
|
});
|
|
27
37
|
};
|
|
28
38
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -259,7 +269,9 @@ class BroadcastChannelSyncAdapter {
|
|
|
259
269
|
channel = null;
|
|
260
270
|
listeners = [];
|
|
261
271
|
constructor(channelName = "polly-sync") {
|
|
262
|
-
if (typeof BroadcastChannel
|
|
272
|
+
if (typeof BroadcastChannel === "undefined") {
|
|
273
|
+
console.warn("[SyncAdapter] BroadcastChannel not available");
|
|
274
|
+
} else {
|
|
263
275
|
this.channel = new BroadcastChannel(channelName);
|
|
264
276
|
this.channel.onmessage = (event) => {
|
|
265
277
|
if (event.data.type === "STATE_SYNC") {
|
|
@@ -268,8 +280,6 @@ class BroadcastChannelSyncAdapter {
|
|
|
268
280
|
});
|
|
269
281
|
}
|
|
270
282
|
};
|
|
271
|
-
} else {
|
|
272
|
-
console.warn("[SyncAdapter] BroadcastChannel not available");
|
|
273
283
|
}
|
|
274
284
|
}
|
|
275
285
|
broadcast(message) {
|
|
@@ -536,6 +546,7 @@ function clearStateRegistry() {
|
|
|
536
546
|
}
|
|
537
547
|
export {
|
|
538
548
|
getStateByKey,
|
|
549
|
+
deepEqual,
|
|
539
550
|
clearStateRegistry,
|
|
540
551
|
$syncedState,
|
|
541
552
|
$state,
|
|
@@ -543,4 +554,4 @@ export {
|
|
|
543
554
|
$persistedState
|
|
544
555
|
};
|
|
545
556
|
|
|
546
|
-
//# debugId=
|
|
557
|
+
//# debugId=0F5EBC69C8D279A764756E2164756E21
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
"sources": ["../src/shared/lib/storage-adapter.ts", "../src/shared/lib/sync-adapter.ts", "../src/shared/lib/state.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"// Storage adapters for different execution contexts\n// Automatically chooses the right storage mechanism based on environment\n\n/**\n * Universal storage adapter interface\n */\nexport interface StorageAdapter {\n get<T = unknown>(keys: string[]): Promise<Record<string, T>>;\n set(items: Record<string, unknown>): Promise<void>;\n remove(keys: string[]): Promise<void>;\n}\n\n/**\n * IndexedDB adapter for web apps\n */\nexport class IndexedDBAdapter implements StorageAdapter {\n private dbName: string;\n private storeName = \"state\";\n private dbPromise: Promise<IDBDatabase> | null = null;\n\n constructor(dbName = \"polly-state\") {\n this.dbName = dbName;\n }\n\n private getDB(): Promise<IDBDatabase> {\n if (this.dbPromise) return this.dbPromise;\n\n this.dbPromise = new Promise((resolve, reject) => {\n const request = indexedDB.open(this.dbName, 1);\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result);\n\n request.onupgradeneeded = (event) => {\n const db = (event.target as IDBOpenDBRequest).result;\n if (!db.objectStoreNames.contains(this.storeName)) {\n db.createObjectStore(this.storeName);\n }\n };\n });\n\n return this.dbPromise;\n }\n\n async get<T = unknown>(keys: string[]): Promise<Record<string, T>> {\n try {\n const db = await this.getDB();\n const result: Record<string, T> = {};\n\n await Promise.all(\n keys.map(\n (key) =>\n new Promise<void>((resolve, reject) => {\n const transaction = db.transaction([this.storeName], \"readonly\");\n const store = transaction.objectStore(this.storeName);\n const request = store.get(key);\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n if (request.result !== undefined) {\n result[key] = request.result as T;\n }\n resolve();\n };\n })\n )\n );\n\n return result;\n } catch (error) {\n console.warn(\"[Polly] IndexedDB get failed:\", error);\n return {};\n }\n }\n\n async set(items: Record<string, unknown>): Promise<void> {\n try {\n const db = await this.getDB();\n await Promise.all(\n Object.entries(items).map(\n ([key, value]) =>\n new Promise<void>((resolve, reject) => {\n const transaction = db.transaction([this.storeName], \"readwrite\");\n const store = transaction.objectStore(this.storeName);\n const request = store.put(value, key);\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n })\n )\n );\n } catch (error) {\n console.warn(\"[Polly] IndexedDB set failed:\", error);\n }\n }\n\n async remove(keys: string[]): Promise<void> {\n try {\n const db = await this.getDB();\n await Promise.all(\n keys.map(\n (key) =>\n new Promise<void>((resolve, reject) => {\n const transaction = db.transaction([this.storeName], \"readwrite\");\n const store = transaction.objectStore(this.storeName);\n const request = store.delete(key);\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n })\n )\n );\n } catch (error) {\n console.warn(\"[Polly] IndexedDB remove failed:\", error);\n }\n }\n}\n\n/**\n * Chrome storage adapter for extensions\n */\nexport class ChromeStorageAdapter implements StorageAdapter {\n async get<T = unknown>(keys: string[]): Promise<Record<string, T>> {\n if (typeof chrome === \"undefined\" || !chrome.storage) {\n return {};\n }\n\n try {\n return (await chrome.storage.local.get(keys)) as Record<string, T>;\n } catch (error) {\n console.warn(\"[Polly] Chrome storage get failed:\", error);\n return {};\n }\n }\n\n async set(items: Record<string, unknown>): Promise<void> {\n if (typeof chrome === \"undefined\" || !chrome.storage) {\n return;\n }\n\n try {\n await chrome.storage.local.set(items);\n } catch (error) {\n console.warn(\"[Polly] Chrome storage set failed:\", error);\n }\n }\n\n async remove(keys: string[]): Promise<void> {\n if (typeof chrome === \"undefined\" || !chrome.storage) {\n return;\n }\n\n try {\n await chrome.storage.local.remove(keys);\n } catch (error) {\n console.warn(\"[Polly] Chrome storage remove failed:\", error);\n }\n }\n}\n\n/**\n * In-memory adapter (no persistence) for testing or server contexts\n */\nexport class MemoryStorageAdapter implements StorageAdapter {\n private storage = new Map<string, unknown>();\n\n async get<T = unknown>(keys: string[]): Promise<Record<string, T>> {\n const result: Record<string, T> = {};\n for (const key of keys) {\n const value = this.storage.get(key);\n if (value !== undefined) {\n result[key] = value as T;\n }\n }\n return result;\n }\n\n async set(items: Record<string, unknown>): Promise<void> {\n for (const [key, value] of Object.entries(items)) {\n this.storage.set(key, value);\n }\n }\n\n async remove(keys: string[]): Promise<void> {\n for (const key of keys) {\n this.storage.delete(key);\n }\n }\n}\n\n/**\n * Detect execution context and return appropriate storage adapter\n */\nexport function createStorageAdapter(): StorageAdapter {\n // Chrome extension context\n if (typeof chrome !== \"undefined\" && chrome.storage && chrome.runtime) {\n return new ChromeStorageAdapter();\n }\n\n // Web app context (has IndexedDB)\n if (typeof indexedDB !== \"undefined\") {\n return new IndexedDBAdapter();\n }\n\n // Server/test context (no persistent storage available)\n return new MemoryStorageAdapter();\n}\n",
|
|
6
|
-
"// Sync adapter interface for cross-context state synchronization\n// Abstracts the transport mechanism (chrome.runtime, BroadcastChannel, etc.)\n//\n// Architecture Decision: BroadcastChannel vs SharedWorker\n// ------------------------------------------------------\n// We currently use BroadcastChannel for web app sync because:\n// - Simpler API with no lifecycle management complexity\n// - Decentralized (aligns with local-first/offline-first architecture)\n// - Better browser support (especially Safari and mobile)\n// - Perfect for message-passing with Lamport clock conflict resolution\n// - No single point of failure\n//\n// Future Consideration: SharedWorker Support\n// ------------------------------------------\n// SharedWorker could be added as an optional adapter for use cases requiring:\n// - Central coordination point for complex multi-tab workflows\n// - Shared WebSocket connections (one connection for all tabs)\n// - Heavy computation done once and shared across tabs\n// - Persistent background work when tabs are closed\n// - Transaction coordination across tabs\n//\n// For most Polly use cases, BroadcastChannel's peer-to-peer model is preferred,\n// but SharedWorker support could be valuable for advanced scenarios.\n\n/**\n * Message format for state synchronization\n */\nexport interface StateSyncMessage<T = unknown> {\n key: string;\n value: T;\n clock: number;\n}\n\n/**\n * Sync adapter interface - abstracts the transport mechanism for state sync\n *\n * Different contexts use different transports:\n * - Chrome extensions: chrome.runtime messaging\n * - Web apps (multi-tab): BroadcastChannel\n * - PWAs: BroadcastChannel + Service Worker messaging\n * - Single-context: NoOp (no sync needed)\n */\nexport interface SyncAdapter {\n /**\n * Broadcast a state update to other contexts\n */\n broadcast<T>(message: StateSyncMessage<T>): void;\n\n /**\n * Register a callback for incoming state updates\n */\n onMessage<T>(callback: (message: StateSyncMessage<T>) => void): () => void;\n\n /**\n * Optional: Connect to the sync mechanism\n * Some transports require explicit connection setup\n */\n connect?(): Promise<void>;\n\n /**\n * Optional: Disconnect from the sync mechanism\n */\n disconnect?(): void;\n\n /**\n * Optional: Check if connected\n */\n isConnected?(): boolean;\n}\n\n/**\n * NoOp sync adapter for single-context scenarios (no sync needed)\n */\nexport class NoOpSyncAdapter implements SyncAdapter {\n broadcast<T>(_message: StateSyncMessage<T>): void {\n // No-op: single context, no need to sync\n }\n\n onMessage<T>(_callback: (message: StateSyncMessage<T>) => void): () => void {\n // No-op: no messages will ever arrive\n return () => {\n // Empty cleanup function - nothing to clean up for null adapter\n };\n }\n}\n\n/**\n * Chrome runtime sync adapter for Chrome extensions\n * Uses chrome.runtime.sendMessage for cross-context messaging\n */\nexport class ChromeRuntimeSyncAdapter implements SyncAdapter {\n private listeners: Array<(message: StateSyncMessage<unknown>) => void> = [];\n private port: chrome.runtime.Port | null = null;\n\n constructor() {\n // Set up listener for incoming messages\n if (typeof chrome !== \"undefined\" && chrome.runtime) {\n chrome.runtime.onMessage.addListener((message, _sender, _sendResponse) => {\n if (message.type === \"STATE_SYNC\") {\n this.listeners.forEach((listener) => {\n listener(message);\n });\n }\n });\n }\n }\n\n broadcast<T>(message: StateSyncMessage<T>): void {\n if (typeof chrome === \"undefined\" || !chrome.runtime) {\n console.warn(\"[SyncAdapter] chrome.runtime not available\");\n return;\n }\n\n try {\n chrome.runtime.sendMessage({\n type: \"STATE_SYNC\",\n key: message.key,\n value: message.value,\n clock: message.clock,\n });\n } catch (error) {\n console.warn(\"[SyncAdapter] Failed to broadcast state update:\", error);\n }\n }\n\n onMessage<T>(callback: (message: StateSyncMessage<T>) => void): () => void {\n this.listeners.push(callback as (message: StateSyncMessage<unknown>) => void);\n\n // Return cleanup function\n return () => {\n const index = this.listeners.indexOf(\n callback as (message: StateSyncMessage<unknown>) => void\n );\n if (index > -1) {\n this.listeners.splice(index, 1);\n }\n };\n }\n\n connect(): Promise<void> {\n // Chrome runtime is always connected\n return Promise.resolve();\n }\n\n disconnect(): void {\n this.listeners = [];\n if (this.port) {\n this.port.disconnect();\n this.port = null;\n }\n }\n\n isConnected(): boolean {\n return typeof chrome !== \"undefined\" && !!chrome.runtime;\n }\n}\n\n/**\n * BroadcastChannel sync adapter for web apps (multi-tab)\n * Uses BroadcastChannel API for cross-tab messaging\n */\nexport class BroadcastChannelSyncAdapter implements SyncAdapter {\n private channel: BroadcastChannel | null = null;\n private listeners: Array<(message: StateSyncMessage<unknown>) => void> = [];\n\n constructor(channelName = \"polly-sync\") {\n if (typeof BroadcastChannel
|
|
7
|
-
"// State primitives with optional sync and persistence\n\nimport { effect, type Signal, signal } from \"@preact/signals\";\nimport type { MessageBus } from \"./message-bus\";\nimport { createStorageAdapter, type StorageAdapter } from \"./storage-adapter\";\nimport { createSyncAdapter, type SyncAdapter } from \"./sync-adapter\";\n\n/**\n * Signal extended with .loaded promise for hydration control\n */\ntype SignalWithLoaded<T> = Signal<T> & { loaded: Promise<void> };\n\n/**\n * Signal extended with .loaded and .verify properties for verification tracking\n */\ntype SignalWithVerify<T> = Signal<T> & { loaded: Promise<void>; verify: T };\n\ntype StateEntry<T> = {\n signal: Signal<T>;\n clock: number; // Lamport clock for causal ordering\n loaded: Promise<void>;\n updating: boolean;\n};\n\ntype StateOptions<T = unknown> = {\n // Legacy MessageBus support (deprecated, will be removed in v2.0)\n bus?: MessageBus;\n\n // New adapter system (recommended)\n storage?: StorageAdapter; // Custom storage adapter\n sync?: SyncAdapter; // Custom sync adapter\n\n // Behavior options\n debounceMs?: number; // Debounce storage writes\n validator?: (value: unknown) => value is T; // Runtime type validation\n verify?: boolean; // Enable verification tracking (creates plain object mirror)\n};\n\nconst stateRegistry = new Map<string, StateEntry<unknown>>();\n\n/**\n * Shared state: synced across all contexts AND persisted to storage\n *\n * Uses Lamport clock for conflict resolution. State is automatically:\n * - Loaded from chrome.storage on initialization\n * - Synced to other contexts via broadcast messages\n * - Persisted to chrome.storage on every change\n *\n * Available in: background, popup, options, devtools, content scripts\n * ⚠️ NOT available in page scripts (use content script state instead)\n *\n * @param key - Unique identifier for this state (e.g., \"app-settings\")\n * @param initialValue - Default value if nothing is in storage\n * @param options - Optional configuration (bus, debounceMs)\n * @returns Reactive signal that stays in sync across all contexts\n *\n * @example\n * ```typescript\n * // Define once, use everywhere\n * const settings = $sharedState(\"settings\", { theme: \"dark\" })\n *\n * // Changes automatically sync\n * settings.value = { theme: \"light\" }\n * ```\n */\nexport function $sharedState<T>(\n key: string,\n initialValue: T,\n options: StateOptions<T> = {}\n): Signal<T> & { loaded: Promise<void>; verify?: T } {\n const sig = createState(key, initialValue, {\n ...options,\n enableSync: true,\n enablePersist: true,\n });\n\n // Expose loaded promise for awaiting hydration\n const entry = stateRegistry.get(key);\n if (entry) {\n (sig as SignalWithLoaded<T>).loaded = entry.loaded;\n }\n\n return sig as Signal<T> & { loaded: Promise<void> };\n}\n\n/**\n * Synced state: synced across all contexts but NOT persisted\n *\n * State is broadcast to all contexts in real-time but resets on extension reload.\n *\n * Available in: background, popup, options, devtools, content scripts\n * ⚠️ NOT available in page scripts\n *\n * @param key - Unique identifier for this state\n * @param initialValue - Default value\n * @param options - Optional configuration\n * @returns Reactive signal synced across contexts (but not persisted)\n *\n * @example\n * ```typescript\n * // Temporary shared state\n * const activeTabId = $syncedState(\"active-tab\", null)\n * ```\n */\nexport function $syncedState<T>(\n key: string,\n initialValue: T,\n options: StateOptions<T> = {}\n): Signal<T> {\n return createState(key, initialValue, {\n ...options,\n enableSync: true,\n enablePersist: false,\n });\n}\n\n/**\n * Persisted state: persisted to storage but NOT synced across contexts\n *\n * Each context has its own copy of the state, persisted independently.\n *\n * Available in: background, popup, options, devtools, content scripts\n * ⚠️ NOT available in page scripts\n *\n * @param key - Unique identifier (use prefix like \"popup:state\" to avoid collisions)\n * @param initialValue - Default value\n * @param options - Optional configuration\n * @returns Reactive signal persisted to storage (but not synced)\n *\n * @example\n * ```typescript\n * // Each context has its own persisted state\n * const popupState = $persistedState(\"popup:last-panel\", \"home\")\n * const devtoolsState = $persistedState(\"devtools:expanded\", true)\n * ```\n */\nexport function $persistedState<T>(\n key: string,\n initialValue: T,\n options: StateOptions<T> = {}\n): Signal<T> & { loaded: Promise<void> } {\n const sig = createState(key, initialValue, {\n ...options,\n enableSync: false,\n enablePersist: true,\n });\n\n // Expose loaded promise for awaiting hydration\n const entry = stateRegistry.get(key);\n if (entry) {\n (sig as SignalWithLoaded<T>).loaded = entry.loaded;\n }\n\n return sig as Signal<T> & { loaded: Promise<void> };\n}\n\n/**\n * Local state: not synced, not persisted (like regular Preact signal)\n *\n * Simple reactive state that lives only in the current context.\n * Resets on reload or context restart.\n *\n * Available in: all contexts (including page scripts)\n *\n * @param initialValue - Default value\n * @returns Reactive signal (local only)\n *\n * @example\n * ```typescript\n * // Local UI state\n * const isLoading = $state(false)\n * const error = $state<string | null>(null)\n * ```\n */\nexport function $state<T>(initialValue: T): Signal<T> {\n return signal(initialValue);\n}\n\ntype InternalStateOptions<T = unknown> = StateOptions<T> & {\n enableSync: boolean; // Whether to enable sync (avoid collision with sync?: SyncAdapter)\n enablePersist: boolean; // Whether to enable persistence\n};\n\n// Deep equality check to prevent redundant updates\nfunction deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a == null || b == null) return false;\n if (typeof a !== \"object\" || typeof b !== \"object\") return false;\n\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (!keysB.includes(key)) return false;\n if (!deepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key]))\n return false;\n }\n\n return true;\n}\n\n/**\n * Resolve storage and sync adapters with three-tier priority:\n * 1. Explicit adapters from options (highest priority)\n * 2. MessageBus adapters (legacy, deprecated)\n * 3. Auto-detected adapters (default behavior)\n */\nfunction resolveAdapters(options: InternalStateOptions): {\n storage: StorageAdapter | null;\n sync: SyncAdapter | null;\n} {\n // Priority 1: Explicit adapters (partial or full)\n if (options.storage || options.sync) {\n return {\n storage: options.storage || (options.enablePersist ? createStorageAdapter() : null),\n sync: options.sync || (options.enableSync ? createSyncAdapter() : null),\n };\n }\n\n // Priority 2: MessageBus (legacy support)\n // Note: MessageBus doesn't provide sync adapter, only Chrome storage\n if (options.bus) {\n return {\n storage: options.bus.adapters.storage,\n sync: options.enableSync ? createSyncAdapter() : null,\n };\n }\n\n // Priority 3: Auto-detect based on enableSync and enablePersist flags\n return {\n storage: options.enablePersist ? createStorageAdapter() : null,\n sync: options.enableSync ? createSyncAdapter() : null,\n };\n}\n\nfunction createState<T>(key: string, initialValue: T, options: InternalStateOptions<T>): Signal<T> {\n // Return existing signal if already registered\n if (stateRegistry.has(key)) {\n return stateRegistry.get(key)?.signal as Signal<T>;\n }\n\n const sig = signal(initialValue);\n\n // Create verification mirror if requested\n if (options.verify) {\n // Create plain object mirror for verification\n const mirror = JSON.parse(JSON.stringify(initialValue)) as T;\n (sig as SignalWithVerify<T>).verify = mirror;\n }\n\n const entry: StateEntry<T> = {\n signal: sig,\n clock: 0,\n loaded: Promise.resolve(),\n updating: false,\n };\n\n // Resolve adapters (explicit, MessageBus, or auto-detect)\n const adapters = resolveAdapters(options);\n\n // Load from storage if persist is enabled\n if (options.enablePersist && adapters.storage) {\n entry.loaded = loadFromStorage(key, sig, entry, adapters.storage, options.validator);\n }\n\n // Watch for changes after initial load\n entry.loaded.then(() => {\n let debounceTimer: NodeJS.Timeout | null = null;\n let previousValue = sig.value;\n let isFirstRun = true;\n\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Sync effect requires coordination of multiple state change scenarios\n effect(() => {\n // Skip if update in progress (from incoming message)\n if (entry.updating) return;\n\n const value = sig.value;\n\n // Skip first run (effect fires immediately on registration)\n if (isFirstRun) {\n isFirstRun = false;\n return;\n }\n\n // Skip if value hasn't changed (deep equality check)\n if (deepEqual(value, previousValue)) {\n return;\n }\n\n previousValue = value;\n\n // Update verification mirror if enabled\n if (options.verify) {\n const verifySignal = sig as SignalWithVerify<T>;\n if (verifySignal.verify) {\n Object.assign(verifySignal.verify, JSON.parse(JSON.stringify(value)));\n }\n }\n\n // Increment clock monotonically\n entry.clock++;\n\n const doUpdate = () => {\n // Persist to storage\n if (options.enablePersist && adapters.storage) {\n persistToStorage(key, value, entry.clock, adapters.storage);\n }\n\n // Broadcast to other contexts\n if (options.enableSync && adapters.sync) {\n broadcastUpdate(key, value, entry.clock, adapters.sync);\n }\n };\n\n // Debounce if specified\n if (options.debounceMs) {\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(doUpdate, options.debounceMs);\n } else {\n doUpdate();\n }\n });\n });\n\n // Listen for updates from other contexts (only if sync enabled)\n if (options.enableSync && adapters.sync) {\n // Connect if needed (some adapters require explicit connection)\n if (adapters.sync.connect) {\n adapters.sync.connect();\n }\n\n // Register sync message listener\n adapters.sync.onMessage<T>((message) => {\n if (message.key !== key) return;\n\n const oldClock = entry.clock;\n\n // Lamport clock rule: Always update to max(local, received)\n // This maintains causal ordering even when rejecting updates\n entry.clock = Math.max(entry.clock, message.clock);\n\n // Only accept value updates if received clock is strictly greater than old local clock\n // This ensures we only apply causally newer updates\n if (message.clock > oldClock) {\n // Validate incoming value if validator provided\n if (options.validator && !options.validator(message.value)) {\n console.warn(\n `[Polly] State \"${key}\": Received invalid value from sync (clock: ${message.clock})`,\n message.value\n );\n return;\n }\n\n // Skip redundant updates (deep equality check)\n if (deepEqual(entry.signal.value, message.value)) {\n return;\n }\n\n applyUpdate(entry, message.value as T, message.clock);\n }\n });\n }\n\n stateRegistry.set(key, entry as StateEntry<unknown>);\n return sig;\n}\n\nasync function loadFromStorage<T>(\n key: string,\n sig: Signal<T>,\n entry: StateEntry<T>,\n storage: StorageAdapter,\n validator?: (value: unknown) => value is T\n): Promise<void> {\n try {\n const result = await storage.get([key, `${key}:clock`]);\n\n if (result[key] !== undefined) {\n const storedValue = result[key];\n\n // Validate stored value if validator provided\n if (validator) {\n if (validator(storedValue)) {\n sig.value = storedValue;\n } else {\n console.warn(\n `[Polly] State \"${key}\": Stored value failed validation, using initial value`,\n storedValue\n );\n }\n } else {\n sig.value = storedValue as T;\n }\n }\n\n if (result[`${key}:clock`] !== undefined) {\n entry.clock = result[`${key}:clock`] as number;\n }\n } catch (error) {\n console.warn(`[Polly] Failed to load state from storage: ${key}`, error);\n }\n}\n\nfunction persistToStorage<T>(key: string, value: T, clock: number, storage: StorageAdapter): void {\n try {\n storage.set({\n [key]: value,\n [`${key}:clock`]: clock,\n });\n } catch (error) {\n console.warn(`[Polly] Failed to persist state to storage: ${key}`, error);\n }\n}\n\nfunction broadcastUpdate<T>(key: string, value: T, clock: number, sync: SyncAdapter): void {\n try {\n sync.broadcast({\n key,\n value,\n clock,\n });\n } catch (error) {\n console.warn(`[Polly] Failed to broadcast state update: ${key}`, error);\n }\n}\n\nfunction applyUpdate<T>(entry: StateEntry<T>, value: T, clock: number): void {\n entry.updating = true;\n entry.signal.value = value;\n entry.clock = clock;\n entry.updating = false;\n}\n\n/**\n * Get state by key (useful for retrieving state without re-creating)\n */\nexport function getStateByKey<T>(key: string): Signal<T> | undefined {\n const entry = stateRegistry.get(key);\n return entry?.signal as Signal<T> | undefined;\n}\n\n/**\n * Clear state registry (useful for testing)\n */\nexport function clearStateRegistry(): void {\n stateRegistry.clear();\n}\n"
|
|
6
|
+
"// Sync adapter interface for cross-context state synchronization\n// Abstracts the transport mechanism (chrome.runtime, BroadcastChannel, etc.)\n//\n// Architecture Decision: BroadcastChannel vs SharedWorker\n// ------------------------------------------------------\n// We currently use BroadcastChannel for web app sync because:\n// - Simpler API with no lifecycle management complexity\n// - Decentralized (aligns with local-first/offline-first architecture)\n// - Better browser support (especially Safari and mobile)\n// - Perfect for message-passing with Lamport clock conflict resolution\n// - No single point of failure\n//\n// Future Consideration: SharedWorker Support\n// ------------------------------------------\n// SharedWorker could be added as an optional adapter for use cases requiring:\n// - Central coordination point for complex multi-tab workflows\n// - Shared WebSocket connections (one connection for all tabs)\n// - Heavy computation done once and shared across tabs\n// - Persistent background work when tabs are closed\n// - Transaction coordination across tabs\n//\n// For most Polly use cases, BroadcastChannel's peer-to-peer model is preferred,\n// but SharedWorker support could be valuable for advanced scenarios.\n\n/**\n * Message format for state synchronization\n */\nexport interface StateSyncMessage<T = unknown> {\n key: string;\n value: T;\n clock: number;\n}\n\n/**\n * Sync adapter interface - abstracts the transport mechanism for state sync\n *\n * Different contexts use different transports:\n * - Chrome extensions: chrome.runtime messaging\n * - Web apps (multi-tab): BroadcastChannel\n * - PWAs: BroadcastChannel + Service Worker messaging\n * - Single-context: NoOp (no sync needed)\n */\nexport interface SyncAdapter {\n /**\n * Broadcast a state update to other contexts\n */\n broadcast<T>(message: StateSyncMessage<T>): void;\n\n /**\n * Register a callback for incoming state updates\n */\n onMessage<T>(callback: (message: StateSyncMessage<T>) => void): () => void;\n\n /**\n * Optional: Connect to the sync mechanism\n * Some transports require explicit connection setup\n */\n connect?(): Promise<void>;\n\n /**\n * Optional: Disconnect from the sync mechanism\n */\n disconnect?(): void;\n\n /**\n * Optional: Check if connected\n */\n isConnected?(): boolean;\n}\n\n/**\n * NoOp sync adapter for single-context scenarios (no sync needed)\n */\nexport class NoOpSyncAdapter implements SyncAdapter {\n broadcast<T>(_message: StateSyncMessage<T>): void {\n // No-op: single context, no need to sync\n }\n\n onMessage<T>(_callback: (message: StateSyncMessage<T>) => void): () => void {\n // No-op: no messages will ever arrive\n return () => {\n // Empty cleanup function - nothing to clean up for null adapter\n };\n }\n}\n\n/**\n * Chrome runtime sync adapter for Chrome extensions\n * Uses chrome.runtime.sendMessage for cross-context messaging\n */\nexport class ChromeRuntimeSyncAdapter implements SyncAdapter {\n private listeners: Array<(message: StateSyncMessage<unknown>) => void> = [];\n private port: chrome.runtime.Port | null = null;\n\n constructor() {\n // Set up listener for incoming messages\n if (typeof chrome !== \"undefined\" && chrome.runtime) {\n chrome.runtime.onMessage.addListener((message, _sender, _sendResponse) => {\n if (message.type === \"STATE_SYNC\") {\n this.listeners.forEach((listener) => {\n listener(message);\n });\n }\n });\n }\n }\n\n broadcast<T>(message: StateSyncMessage<T>): void {\n if (typeof chrome === \"undefined\" || !chrome.runtime) {\n console.warn(\"[SyncAdapter] chrome.runtime not available\");\n return;\n }\n\n try {\n chrome.runtime.sendMessage({\n type: \"STATE_SYNC\",\n key: message.key,\n value: message.value,\n clock: message.clock,\n });\n } catch (error) {\n console.warn(\"[SyncAdapter] Failed to broadcast state update:\", error);\n }\n }\n\n onMessage<T>(callback: (message: StateSyncMessage<T>) => void): () => void {\n this.listeners.push(callback as (message: StateSyncMessage<unknown>) => void);\n\n // Return cleanup function\n return () => {\n const index = this.listeners.indexOf(\n callback as (message: StateSyncMessage<unknown>) => void\n );\n if (index > -1) {\n this.listeners.splice(index, 1);\n }\n };\n }\n\n connect(): Promise<void> {\n // Chrome runtime is always connected\n return Promise.resolve();\n }\n\n disconnect(): void {\n this.listeners = [];\n if (this.port) {\n this.port.disconnect();\n this.port = null;\n }\n }\n\n isConnected(): boolean {\n return typeof chrome !== \"undefined\" && !!chrome.runtime;\n }\n}\n\n/**\n * BroadcastChannel sync adapter for web apps (multi-tab)\n * Uses BroadcastChannel API for cross-tab messaging\n */\nexport class BroadcastChannelSyncAdapter implements SyncAdapter {\n private channel: BroadcastChannel | null = null;\n private listeners: Array<(message: StateSyncMessage<unknown>) => void> = [];\n\n constructor(channelName = \"polly-sync\") {\n if (typeof BroadcastChannel === \"undefined\") {\n console.warn(\"[SyncAdapter] BroadcastChannel not available\");\n } else {\n this.channel = new BroadcastChannel(channelName);\n\n this.channel.onmessage = (event) => {\n if (event.data.type === \"STATE_SYNC\") {\n this.listeners.forEach((listener) => {\n listener(event.data);\n });\n }\n };\n }\n }\n\n broadcast<T>(message: StateSyncMessage<T>): void {\n if (!this.channel) {\n console.warn(\"[SyncAdapter] BroadcastChannel not initialized\");\n return;\n }\n\n try {\n this.channel.postMessage({\n type: \"STATE_SYNC\",\n key: message.key,\n value: message.value,\n clock: message.clock,\n });\n } catch (error) {\n console.warn(\"[SyncAdapter] Failed to broadcast state update:\", error);\n }\n }\n\n onMessage<T>(callback: (message: StateSyncMessage<T>) => void): () => void {\n this.listeners.push(callback as (message: StateSyncMessage<unknown>) => void);\n\n // Return cleanup function\n return () => {\n const index = this.listeners.indexOf(\n callback as (message: StateSyncMessage<unknown>) => void\n );\n if (index > -1) {\n this.listeners.splice(index, 1);\n }\n };\n }\n\n connect(): Promise<void> {\n // BroadcastChannel connects immediately on construction\n return Promise.resolve();\n }\n\n disconnect(): void {\n this.listeners = [];\n if (this.channel) {\n this.channel.close();\n this.channel = null;\n }\n }\n\n isConnected(): boolean {\n return this.channel !== null;\n }\n}\n\n/**\n * Detect available sync mechanisms and create appropriate adapter\n */\nexport function createSyncAdapter(): SyncAdapter {\n // Chrome extension context - use chrome.runtime\n if (typeof chrome !== \"undefined\" && chrome.runtime) {\n return new ChromeRuntimeSyncAdapter();\n }\n\n // Web app with multi-tab support - use BroadcastChannel\n if (typeof BroadcastChannel !== \"undefined\") {\n return new BroadcastChannelSyncAdapter();\n }\n\n // Single context or no sync available - use NoOp\n return new NoOpSyncAdapter();\n}\n",
|
|
7
|
+
"// State primitives with optional sync and persistence\n\nimport { effect, type Signal, signal } from \"@preact/signals\";\nimport type { MessageBus } from \"./message-bus\";\nimport { createStorageAdapter, type StorageAdapter } from \"./storage-adapter\";\nimport { createSyncAdapter, type SyncAdapter } from \"./sync-adapter\";\n\n/**\n * Signal extended with .loaded promise for hydration control\n */\ntype SignalWithLoaded<T> = Signal<T> & { loaded: Promise<void> };\n\n/**\n * Signal extended with .loaded and .verify properties for verification tracking\n */\ntype SignalWithVerify<T> = Signal<T> & { loaded: Promise<void>; verify: T };\n\ntype StateEntry<T> = {\n signal: Signal<T>;\n clock: number; // Lamport clock for causal ordering\n loaded: Promise<void>;\n updating: boolean;\n};\n\ntype StateOptions<T = unknown> = {\n // Legacy MessageBus support (deprecated, will be removed in v2.0)\n bus?: MessageBus;\n\n // New adapter system (recommended)\n storage?: StorageAdapter; // Custom storage adapter\n sync?: SyncAdapter; // Custom sync adapter\n\n // Behavior options\n debounceMs?: number; // Debounce storage writes\n validator?: (value: unknown) => value is T; // Runtime type validation\n verify?: boolean; // Enable verification tracking (creates plain object mirror)\n};\n\nconst stateRegistry = new Map<string, StateEntry<unknown>>();\n\n/**\n * Shared state: synced across all contexts AND persisted to storage\n *\n * Uses Lamport clock for conflict resolution. State is automatically:\n * - Loaded from chrome.storage on initialization\n * - Synced to other contexts via broadcast messages\n * - Persisted to chrome.storage on every change\n *\n * Available in: background, popup, options, devtools, content scripts\n * ⚠️ NOT available in page scripts (use content script state instead)\n *\n * @param key - Unique identifier for this state (e.g., \"app-settings\")\n * @param initialValue - Default value if nothing is in storage\n * @param options - Optional configuration (bus, debounceMs)\n * @returns Reactive signal that stays in sync across all contexts\n *\n * @example\n * ```typescript\n * // Define once, use everywhere\n * const settings = $sharedState(\"settings\", { theme: \"dark\" })\n *\n * // Changes automatically sync\n * settings.value = { theme: \"light\" }\n * ```\n */\nexport function $sharedState<T>(\n key: string,\n initialValue: T,\n options: StateOptions<T> = {}\n): Signal<T> & { loaded: Promise<void>; verify?: T } {\n const sig = createState(key, initialValue, {\n ...options,\n enableSync: true,\n enablePersist: true,\n });\n\n // Expose loaded promise for awaiting hydration\n const entry = stateRegistry.get(key);\n if (entry) {\n (sig as SignalWithLoaded<T>).loaded = entry.loaded;\n }\n\n return sig as Signal<T> & { loaded: Promise<void> };\n}\n\n/**\n * Synced state: synced across all contexts but NOT persisted\n *\n * State is broadcast to all contexts in real-time but resets on extension reload.\n *\n * Available in: background, popup, options, devtools, content scripts\n * ⚠️ NOT available in page scripts\n *\n * @param key - Unique identifier for this state\n * @param initialValue - Default value\n * @param options - Optional configuration\n * @returns Reactive signal synced across contexts (but not persisted)\n *\n * @example\n * ```typescript\n * // Temporary shared state\n * const activeTabId = $syncedState(\"active-tab\", null)\n * ```\n */\nexport function $syncedState<T>(\n key: string,\n initialValue: T,\n options: StateOptions<T> = {}\n): Signal<T> {\n return createState(key, initialValue, {\n ...options,\n enableSync: true,\n enablePersist: false,\n });\n}\n\n/**\n * Persisted state: persisted to storage but NOT synced across contexts\n *\n * Each context has its own copy of the state, persisted independently.\n *\n * Available in: background, popup, options, devtools, content scripts\n * ⚠️ NOT available in page scripts\n *\n * @param key - Unique identifier (use prefix like \"popup:state\" to avoid collisions)\n * @param initialValue - Default value\n * @param options - Optional configuration\n * @returns Reactive signal persisted to storage (but not synced)\n *\n * @example\n * ```typescript\n * // Each context has its own persisted state\n * const popupState = $persistedState(\"popup:last-panel\", \"home\")\n * const devtoolsState = $persistedState(\"devtools:expanded\", true)\n * ```\n */\nexport function $persistedState<T>(\n key: string,\n initialValue: T,\n options: StateOptions<T> = {}\n): Signal<T> & { loaded: Promise<void> } {\n const sig = createState(key, initialValue, {\n ...options,\n enableSync: false,\n enablePersist: true,\n });\n\n // Expose loaded promise for awaiting hydration\n const entry = stateRegistry.get(key);\n if (entry) {\n (sig as SignalWithLoaded<T>).loaded = entry.loaded;\n }\n\n return sig as Signal<T> & { loaded: Promise<void> };\n}\n\n/**\n * Local state: not synced, not persisted (like regular Preact signal)\n *\n * Simple reactive state that lives only in the current context.\n * Resets on reload or context restart.\n *\n * Available in: all contexts (including page scripts)\n *\n * @param initialValue - Default value\n * @returns Reactive signal (local only)\n *\n * @example\n * ```typescript\n * // Local UI state\n * const isLoading = $state(false)\n * const error = $state<string | null>(null)\n * ```\n */\nexport function $state<T>(initialValue: T): Signal<T> {\n return signal(initialValue);\n}\n\ntype InternalStateOptions<T = unknown> = StateOptions<T> & {\n enableSync: boolean; // Whether to enable sync (avoid collision with sync?: SyncAdapter)\n enablePersist: boolean; // Whether to enable persistence\n};\n\n// Deep equality check to prevent redundant updates\nexport function deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a == null || b == null) return false;\n if (typeof a !== \"object\" || typeof b !== \"object\") return false;\n\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (!keysB.includes(key)) return false;\n if (!deepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key]))\n return false;\n }\n\n return true;\n}\n\n/**\n * Resolve storage and sync adapters with three-tier priority:\n * 1. Explicit adapters from options (highest priority)\n * 2. MessageBus adapters (legacy, deprecated)\n * 3. Auto-detected adapters (default behavior)\n */\nfunction resolveAdapters(options: InternalStateOptions): {\n storage: StorageAdapter | null;\n sync: SyncAdapter | null;\n} {\n // Priority 1: Explicit adapters (partial or full)\n if (options.storage || options.sync) {\n return {\n storage: options.storage || (options.enablePersist ? createStorageAdapter() : null),\n sync: options.sync || (options.enableSync ? createSyncAdapter() : null),\n };\n }\n\n // Priority 2: MessageBus (legacy support)\n // Note: MessageBus doesn't provide sync adapter, only Chrome storage\n if (options.bus) {\n return {\n storage: options.bus.adapters.storage,\n sync: options.enableSync ? createSyncAdapter() : null,\n };\n }\n\n // Priority 3: Auto-detect based on enableSync and enablePersist flags\n return {\n storage: options.enablePersist ? createStorageAdapter() : null,\n sync: options.enableSync ? createSyncAdapter() : null,\n };\n}\n\nfunction createState<T>(key: string, initialValue: T, options: InternalStateOptions<T>): Signal<T> {\n // Return existing signal if already registered\n if (stateRegistry.has(key)) {\n return stateRegistry.get(key)?.signal as Signal<T>;\n }\n\n const sig = signal(initialValue);\n\n // Create verification mirror if requested\n if (options.verify) {\n // Create plain object mirror for verification\n const mirror = JSON.parse(JSON.stringify(initialValue)) as T;\n (sig as SignalWithVerify<T>).verify = mirror;\n }\n\n const entry: StateEntry<T> = {\n signal: sig,\n clock: 0,\n loaded: Promise.resolve(),\n updating: false,\n };\n\n // Resolve adapters (explicit, MessageBus, or auto-detect)\n const adapters = resolveAdapters(options);\n\n // Load from storage if persist is enabled\n if (options.enablePersist && adapters.storage) {\n entry.loaded = loadFromStorage(key, sig, entry, adapters.storage, options.validator);\n }\n\n // Watch for changes after initial load\n entry.loaded.then(() => {\n let debounceTimer: NodeJS.Timeout | null = null;\n let previousValue = sig.value;\n let isFirstRun = true;\n\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Sync effect requires coordination of multiple state change scenarios\n effect(() => {\n // Skip if update in progress (from incoming message)\n if (entry.updating) return;\n\n const value = sig.value;\n\n // Skip first run (effect fires immediately on registration)\n if (isFirstRun) {\n isFirstRun = false;\n return;\n }\n\n // Skip if value hasn't changed (deep equality check)\n if (deepEqual(value, previousValue)) {\n return;\n }\n\n previousValue = value;\n\n // Update verification mirror if enabled\n if (options.verify) {\n const verifySignal = sig as SignalWithVerify<T>;\n if (verifySignal.verify) {\n Object.assign(verifySignal.verify, JSON.parse(JSON.stringify(value)));\n }\n }\n\n // Increment clock monotonically\n entry.clock++;\n\n const doUpdate = () => {\n // Persist to storage\n if (options.enablePersist && adapters.storage) {\n persistToStorage(key, value, entry.clock, adapters.storage);\n }\n\n // Broadcast to other contexts\n if (options.enableSync && adapters.sync) {\n broadcastUpdate(key, value, entry.clock, adapters.sync);\n }\n };\n\n // Debounce if specified\n if (options.debounceMs) {\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(doUpdate, options.debounceMs);\n } else {\n doUpdate();\n }\n });\n });\n\n // Listen for updates from other contexts (only if sync enabled)\n if (options.enableSync && adapters.sync) {\n // Connect if needed (some adapters require explicit connection)\n if (adapters.sync.connect) {\n adapters.sync.connect();\n }\n\n // Register sync message listener\n adapters.sync.onMessage<T>((message) => {\n if (message.key !== key) return;\n\n const oldClock = entry.clock;\n\n // Lamport clock rule: Always update to max(local, received)\n // This maintains causal ordering even when rejecting updates\n entry.clock = Math.max(entry.clock, message.clock);\n\n // Only accept value updates if received clock is strictly greater than old local clock\n // This ensures we only apply causally newer updates\n if (message.clock > oldClock) {\n // Validate incoming value if validator provided\n if (options.validator && !options.validator(message.value)) {\n console.warn(\n `[Polly] State \"${key}\": Received invalid value from sync (clock: ${message.clock})`,\n message.value\n );\n return;\n }\n\n // Skip redundant updates (deep equality check)\n if (deepEqual(entry.signal.value, message.value)) {\n return;\n }\n\n applyUpdate(entry, message.value as T, message.clock);\n }\n });\n }\n\n stateRegistry.set(key, entry as StateEntry<unknown>);\n return sig;\n}\n\nasync function loadFromStorage<T>(\n key: string,\n sig: Signal<T>,\n entry: StateEntry<T>,\n storage: StorageAdapter,\n validator?: (value: unknown) => value is T\n): Promise<void> {\n try {\n const result = await storage.get([key, `${key}:clock`]);\n\n if (result[key] !== undefined) {\n const storedValue = result[key];\n\n // Validate stored value if validator provided\n if (validator) {\n if (validator(storedValue)) {\n sig.value = storedValue;\n } else {\n console.warn(\n `[Polly] State \"${key}\": Stored value failed validation, using initial value`,\n storedValue\n );\n }\n } else {\n sig.value = storedValue as T;\n }\n }\n\n if (result[`${key}:clock`] !== undefined) {\n entry.clock = result[`${key}:clock`] as number;\n }\n } catch (error) {\n console.warn(`[Polly] Failed to load state from storage: ${key}`, error);\n }\n}\n\nfunction persistToStorage<T>(key: string, value: T, clock: number, storage: StorageAdapter): void {\n try {\n storage.set({\n [key]: value,\n [`${key}:clock`]: clock,\n });\n } catch (error) {\n console.warn(`[Polly] Failed to persist state to storage: ${key}`, error);\n }\n}\n\nfunction broadcastUpdate<T>(key: string, value: T, clock: number, sync: SyncAdapter): void {\n try {\n sync.broadcast({\n key,\n value,\n clock,\n });\n } catch (error) {\n console.warn(`[Polly] Failed to broadcast state update: ${key}`, error);\n }\n}\n\nfunction applyUpdate<T>(entry: StateEntry<T>, value: T, clock: number): void {\n entry.updating = true;\n entry.signal.value = value;\n entry.clock = clock;\n entry.updating = false;\n}\n\n/**\n * Get state by key (useful for retrieving state without re-creating)\n */\nexport function getStateByKey<T>(key: string): Signal<T> | undefined {\n const entry = stateRegistry.get(key);\n return entry?.signal as Signal<T> | undefined;\n}\n\n/**\n * Clear state registry (useful for testing)\n */\nexport function clearStateRegistry(): void {\n stateRegistry.clear();\n}\n"
|
|
8
8
|
],
|
|
9
|
-
"mappings": "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",
|
|
10
|
-
"debugId": "
|
|
9
|
+
"mappings": "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",
|
|
10
|
+
"debugId": "0F5EBC69C8D279A764756E2164756E21",
|
|
11
11
|
"names": []
|
|
12
12
|
}
|
|
@@ -2,27 +2,37 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
-
|
|
5
|
+
function __accessProp(key) {
|
|
6
|
+
return this[key];
|
|
7
|
+
}
|
|
6
8
|
var __toCommonJS = (from) => {
|
|
7
|
-
var entry = __moduleCache.get(from), desc;
|
|
9
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
8
10
|
if (entry)
|
|
9
11
|
return entry;
|
|
10
12
|
entry = __defProp({}, "__esModule", { value: true });
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function")
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (var key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(entry, key))
|
|
16
|
+
__defProp(entry, key, {
|
|
17
|
+
get: __accessProp.bind(from, key),
|
|
18
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
19
|
+
});
|
|
20
|
+
}
|
|
16
21
|
__moduleCache.set(from, entry);
|
|
17
22
|
return entry;
|
|
18
23
|
};
|
|
24
|
+
var __moduleCache;
|
|
25
|
+
var __returnValue = (v) => v;
|
|
26
|
+
function __exportSetter(name, newValue) {
|
|
27
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
28
|
+
}
|
|
19
29
|
var __export = (target, all) => {
|
|
20
30
|
for (var name in all)
|
|
21
31
|
__defProp(target, name, {
|
|
22
32
|
get: all[name],
|
|
23
33
|
enumerable: true,
|
|
24
34
|
configurable: true,
|
|
25
|
-
set: (
|
|
35
|
+
set: __exportSetter.bind(all, name)
|
|
26
36
|
});
|
|
27
37
|
};
|
|
28
38
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -169,4 +179,4 @@ export {
|
|
|
169
179
|
TestRunner
|
|
170
180
|
};
|
|
171
181
|
|
|
172
|
-
//# debugId=
|
|
182
|
+
//# debugId=1F36CE010C5B840264756E2164756E21
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * Test Helpers\n *\n * Built-in utilities for testing extensions with the framework.\n * Automatically exposes test results to window for Playwright validation.\n */\n\nimport type { BaseMessage, Context, ExtensionMessage } from \"../types/messages\";\nimport type { MessageBus } from \"./message-bus\";\n\n// Extend Window interface for test results\ndeclare global {\n interface Window {\n __TEST_RESULTS__?: Record<string, unknown>;\n }\n}\n\nexport interface TestCase {\n name: string;\n fn: () => Promise<unknown>;\n result?: unknown;\n error?: string;\n duration?: number;\n}\n\nexport interface TestSuite {\n context: Context;\n tests: Map<string, TestCase>;\n results: {\n passed: number;\n failed: number;\n total: number;\n timestamp: number;\n };\n}\n\nexport class TestRunner<TMessage extends BaseMessage = ExtensionMessage> {\n private suite: TestSuite;\n private bus: MessageBus<TMessage>;\n\n constructor(context: Context, bus: MessageBus<TMessage>) {\n this.bus = bus;\n this.suite = {\n context,\n tests: new Map(),\n results: {\n passed: 0,\n failed: 0,\n total: 0,\n timestamp: Date.now(),\n },\n };\n }\n\n /**\n * Add a test case.\n *\n * @example\n * ```typescript\n * const tests = createTestSuite('popup', bus)\n *\n * tests.add('storage works', async () => {\n * const result = await bus.send({ type: 'TEST_STORAGE' })\n * return result.success\n * })\n * ```\n */\n add(name: string, fn: () => Promise<unknown>): this {\n this.suite.tests.set(name, { name, fn });\n return this;\n }\n\n /**\n * Add a test that sends a message and validates the response.\n *\n * @example\n * ```typescript\n * tests.addMessageTest('storage', { type: 'TEST_STORAGE' }, (result) => {\n * return result.success === true\n * })\n * ```\n */\n addMessageTest<T extends TMessage>(\n name: string,\n message: T,\n validator?: (result: unknown) => boolean\n ): this {\n this.add(name, async () => {\n const result = await this.bus.send(message);\n if (validator) {\n return validator(result);\n }\n return result;\n });\n return this;\n }\n\n /**\n * Run all tests and store results.\n *\n * @example\n * ```typescript\n * await tests.run() // Results stored at window.__TEST_RESULTS__.popup\n * ```\n */\n async run(): Promise<TestSuite> {\n this.suite.results = {\n passed: 0,\n failed: 0,\n total: this.suite.tests.size,\n timestamp: Date.now(),\n };\n\n for (const [_name, test] of this.suite.tests) {\n const startTime = Date.now();\n\n try {\n test.result = await test.fn();\n test.duration = Date.now() - startTime;\n this.suite.results.passed++;\n } catch (error) {\n test.error = error instanceof Error ? error.message : String(error);\n test.duration = Date.now() - startTime;\n this.suite.results.failed++;\n }\n }\n\n // Expose results to window for Playwright validation\n this.exposeResults();\n\n return this.suite;\n }\n\n /**\n * Run a single test by name.\n */\n async runTest(name: string): Promise<TestCase> {\n const test = this.suite.tests.get(name);\n if (!test) {\n throw new Error(`Test not found: ${name}`);\n }\n\n const startTime = Date.now();\n\n try {\n test.result = await test.fn();\n test.duration = Date.now() - startTime;\n } catch (error) {\n test.error = error instanceof Error ? error.message : String(error);\n test.duration = Date.now() - startTime;\n }\n\n return test;\n }\n\n /**\n * Get test results.\n */\n getResults(): TestSuite {\n return this.suite;\n }\n\n /**\n * Get a summary of test results.\n */\n getSummary(): {\n context: Context;\n passed: number;\n failed: number;\n total: number;\n duration: number;\n allPassed: boolean;\n } {\n let totalDuration = 0;\n for (const test of this.suite.tests.values()) {\n totalDuration += test.duration || 0;\n }\n\n return {\n context: this.suite.context,\n passed: this.suite.results.passed,\n failed: this.suite.results.failed,\n total: this.suite.results.total,\n duration: totalDuration,\n allPassed: this.suite.results.failed === 0,\n };\n }\n\n /**\n * Expose results to window for Playwright validation.\n * @private\n */\n private exposeResults(): void {\n if (typeof window === \"undefined\") return;\n\n // Create or get the global test results object\n if (!window.__TEST_RESULTS__) {\n window.__TEST_RESULTS__ = {};\n }\n const globalResults = window.__TEST_RESULTS__;\n\n // Convert Map to plain object for serialization\n const testsObject: Record<string, Omit<TestCase, \"fn\">> = {};\n for (const [name, test] of this.suite.tests) {\n testsObject[name] = {\n name: test.name,\n result: test.result,\n ...(test.error !== undefined && { error: test.error }),\n ...(test.duration !== undefined && { duration: test.duration }),\n };\n }\n\n globalResults[this.suite.context] = {\n tests: testsObject,\n results: this.suite.results,\n summary: this.getSummary(),\n };\n }\n\n /**\n * Print test results to console.\n */\n printResults(): void {\n console.group(`[${this.suite.context}] Test Results`);\n\n for (const test of this.suite.tests.values()) {\n if (test.error) {\n console.error(`❌ ${test.name}: ${test.error} (${test.duration}ms)`);\n }\n }\n\n console.groupEnd();\n }\n}\n\n/**\n * Create a test suite for a specific context.\n *\n * @example\n * ```typescript\n * import { createTestSuite } from '@/shared/lib/test-helpers'\n *\n * const tests = createTestSuite('popup', bus)\n *\n * tests.add('storage works', async () => {\n * const result = await bus.send({ type: 'TEST_STORAGE' })\n * return result.success\n * })\n *\n * tests.add('tabs query works', async () => {\n * const result = await bus.send({ type: 'TEST_TABS' })\n * return result.tabCount > 0\n * })\n *\n * await tests.run()\n * tests.printResults()\n * ```\n */\nexport function createTestSuite<TMessage extends BaseMessage = ExtensionMessage>(\n context: Context,\n bus: MessageBus<TMessage>\n): TestRunner<TMessage> {\n return new TestRunner<TMessage>(context, bus);\n}\n\n/**\n * Convenience function to run a quick test and log the result.\n *\n * @example\n * ```typescript\n * await quickTest('Storage', async () => {\n * const result = await bus.send({ type: 'TEST_STORAGE' })\n * return result.success\n * })\n * ```\n */\nexport async function quickTest(name: string, fn: () => Promise<unknown>): Promise<void> {\n const startTime = Date.now();\n\n try {\n await fn();\n } catch (error) {\n const duration = Date.now() - startTime;\n console.error(\n `❌ ${name}: ${error instanceof Error ? error.message : String(error)} (${duration}ms)`\n );\n }\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "1F36CE010C5B840264756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -2,27 +2,37 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
-
|
|
5
|
+
function __accessProp(key) {
|
|
6
|
+
return this[key];
|
|
7
|
+
}
|
|
6
8
|
var __toCommonJS = (from) => {
|
|
7
|
-
var entry = __moduleCache.get(from), desc;
|
|
9
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
8
10
|
if (entry)
|
|
9
11
|
return entry;
|
|
10
12
|
entry = __defProp({}, "__esModule", { value: true });
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function")
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (var key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(entry, key))
|
|
16
|
+
__defProp(entry, key, {
|
|
17
|
+
get: __accessProp.bind(from, key),
|
|
18
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
19
|
+
});
|
|
20
|
+
}
|
|
16
21
|
__moduleCache.set(from, entry);
|
|
17
22
|
return entry;
|
|
18
23
|
};
|
|
24
|
+
var __moduleCache;
|
|
25
|
+
var __returnValue = (v) => v;
|
|
26
|
+
function __exportSetter(name, newValue) {
|
|
27
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
28
|
+
}
|
|
19
29
|
var __export = (target, all) => {
|
|
20
30
|
for (var name in all)
|
|
21
31
|
__defProp(target, name, {
|
|
22
32
|
get: all[name],
|
|
23
33
|
enumerable: true,
|
|
24
34
|
configurable: true,
|
|
25
|
-
set: (
|
|
35
|
+
set: __exportSetter.bind(all, name)
|
|
26
36
|
});
|
|
27
37
|
};
|
|
28
38
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -259,7 +269,9 @@ class BroadcastChannelSyncAdapter {
|
|
|
259
269
|
channel = null;
|
|
260
270
|
listeners = [];
|
|
261
271
|
constructor(channelName = "polly-sync") {
|
|
262
|
-
if (typeof BroadcastChannel
|
|
272
|
+
if (typeof BroadcastChannel === "undefined") {
|
|
273
|
+
console.warn("[SyncAdapter] BroadcastChannel not available");
|
|
274
|
+
} else {
|
|
263
275
|
this.channel = new BroadcastChannel(channelName);
|
|
264
276
|
this.channel.onmessage = (event) => {
|
|
265
277
|
if (event.data.type === "STATE_SYNC") {
|
|
@@ -268,8 +280,6 @@ class BroadcastChannelSyncAdapter {
|
|
|
268
280
|
});
|
|
269
281
|
}
|
|
270
282
|
};
|
|
271
|
-
} else {
|
|
272
|
-
console.warn("[SyncAdapter] BroadcastChannel not available");
|
|
273
283
|
}
|
|
274
284
|
}
|
|
275
285
|
broadcast(message) {
|
|
@@ -570,4 +580,4 @@ export {
|
|
|
570
580
|
currentTab
|
|
571
581
|
};
|
|
572
582
|
|
|
573
|
-
//# debugId=
|
|
583
|
+
//# debugId=90836AFC087E673864756E2164756E21
|