@securitydept/client 0.3.0-beta.1 → 0.3.0-beta.10
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 +6 -0
- package/dist/create-i5VyYgN6.mjs +989 -0
- package/dist/create-i5VyYgN6.mjs.map +1 -0
- package/dist/handle-DwMgqe7R.mjs +638 -0
- package/dist/handle-DwMgqe7R.mjs.map +1 -0
- package/dist/index-Bo1BtjZH.d.mts +132 -0
- package/dist/index-CFAJ969E.d.mts +674 -0
- package/dist/index-CbeZ3AfB.d.mts +1680 -0
- package/dist/index.d.mts +3 -353
- package/dist/index.mjs +1196 -401
- package/dist/index.mjs.map +1 -1
- package/dist/router-at5bTdJQ.mjs +245 -0
- package/dist/router-at5bTdJQ.mjs.map +1 -0
- package/dist/rx/index.d.mts +68 -0
- package/dist/rx/index.mjs +2 -0
- package/dist/rx-DM6Ouv-m.mjs +1119 -0
- package/dist/rx-DM6Ouv-m.mjs.map +1 -0
- package/dist/server/index.d.mts +20 -0
- package/dist/server/index.mjs +29 -0
- package/dist/server/index.mjs.map +1 -0
- package/dist/test/index.d.mts +101 -0
- package/dist/test/index.mjs +270 -0
- package/dist/test/index.mjs.map +1 -0
- package/dist/uri-string-BPNbIMgv.mjs +300 -0
- package/dist/uri-string-BPNbIMgv.mjs.map +1 -0
- package/dist/web/index.d.mts +82 -337
- package/dist/web/index.mjs +334 -337
- package/dist/web/index.mjs.map +1 -1
- package/dist/webext/index.d.mts +73 -0
- package/dist/webext/index.mjs +231 -0
- package/dist/webext/index.mjs.map +1 -0
- package/package.json +28 -21
- package/dist/auth-coordination/index.d.mts +0 -198
- package/dist/auth-coordination/index.mjs +0 -107
- package/dist/auth-coordination/index.mjs.map +0 -1
- package/dist/events/index.d.mts +0 -2
- package/dist/events/index.mjs +0 -2
- package/dist/events-BUlfsRfl.mjs +0 -127
- package/dist/events-BUlfsRfl.mjs.map +0 -1
- package/dist/fetch-transport-Bd5RyWj2.d.mts +0 -339
- package/dist/fetch-transport-DtnSRWAH.mjs +0 -631
- package/dist/fetch-transport-DtnSRWAH.mjs.map +0 -1
- package/dist/index-C_wgl6dW.d.mts +0 -102
- package/dist/index-DbYSFHDe.d.mts +0 -39
- package/dist/persistence/index.d.mts +0 -3
- package/dist/persistence/index.mjs +0 -2
- package/dist/persistence/web/index.d.mts +0 -16
- package/dist/persistence/web/index.mjs +0 -51
- package/dist/persistence/web/index.mjs.map +0 -1
- package/dist/persistence-CSB8770k.mjs +0 -108
- package/dist/persistence-CSB8770k.mjs.map +0 -1
- package/dist/planner-host-CPyGNyQV.d.mts +0 -190
- package/dist/planner-host-CV38bMSn.mjs +0 -195
- package/dist/planner-host-CV38bMSn.mjs.map +0 -1
- package/dist/types-C59fcM5W.d.mts +0 -52
- package/dist/types-DQc088ZP.d.mts +0 -32
- package/dist/web-router/index.d.mts +0 -259
- package/dist/web-router/index.mjs +0 -395
- package/dist/web-router/index.mjs.map +0 -1
package/dist/web/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/web/cross-tab-sync.ts","../../src/web/page-resume-reconciler.ts","../../src/web/popup.ts","../../src/web/runtime.ts","../../src/web/visibility.ts","../../src/web/visibility-reconciler.ts"],"sourcesContent":["import { fromStorageEvent } from \"./input-sources\";\n\n// Cross-tab auth state sync — minimal baseline using storage events\n//\n// Provides a minimal, composable cross-tab sync mechanism for auth state.\n// When another tab writes to the auth persistence key (via localStorage),\n// this listener detects the change and notifies the current tab so it can\n// reconcile its in-memory state.\n//\n// This is intentionally thin — it uses the browser `storage` event which\n// fires on OTHER tabs when localStorage is modified. The reconciliation\n// callback is the adopter's responsibility (e.g. re-read from persistence,\n// compare with in-memory state, and update).\n//\n// Architecture boundary:\n// - This module does NOT own the persistence store.\n// - It only listens for cross-tab mutations and notifies via callback.\n// - The adopter wires this to their AuthMaterialController.\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Callback invoked when a cross-tab storage change is detected for the watched key. */\nexport type CrossTabSyncCallback = (event: {\n\t/** The new value written by the other tab, or null if the key was removed. */\n\tnewValue: string | null;\n\t/** The old value before the other tab's write. */\n\toldValue: string | null;\n}) => void;\n\n/** Options for {@link createCrossTabSync}. */\nexport interface CreateCrossTabSyncOptions {\n\t/** The localStorage key to watch for cross-tab changes. */\n\tkey: string;\n\n\t/** Called when another tab modifies the watched key. */\n\tonSync: CrossTabSyncCallback;\n\n\t/**\n\t * Override the window target (primarily for testing).\n\t * Defaults to `globalThis`.\n\t */\n\ttarget?: {\n\t\taddEventListener(type: string, listener: EventListener): void;\n\t\tremoveEventListener(type: string, listener: EventListener): void;\n\t};\n}\n\n/** Handle returned by {@link createCrossTabSync}. */\nexport interface CrossTabSync {\n\t/** Stop listening for cross-tab storage events. */\n\tdispose(): void;\n\t/** Number of times a sync event has been received. */\n\treadonly syncCount: number;\n}\n\n// ---------------------------------------------------------------------------\n// Implementation\n// ---------------------------------------------------------------------------\n\n/**\n * Create a cross-tab sync listener for a specific localStorage key.\n *\n * The browser `storage` event fires on ALL tabs EXCEPT the one that made the\n * change. This makes it a natural primitive for cross-tab state notification.\n *\n * @example\n * ```ts\n * const sync = createCrossTabSync({\n * key: \"auth:v1\",\n * onSync: ({ newValue }) => {\n * if (newValue) {\n * // Another tab updated auth state — reconcile\n * controller.restoreFromPersistence();\n * } else {\n * // Another tab cleared auth state — log out\n * controller.clearState({ clearPersisted: false });\n * }\n * },\n * });\n * // Later:\n * sync.dispose();\n * ```\n */\nexport function createCrossTabSync(\n\toptions: CreateCrossTabSyncOptions,\n): CrossTabSync {\n\tconst target = options.target ?? globalThis;\n\tlet syncCount = 0;\n\tconst subscription = fromStorageEvent({\n\t\ttarget,\n\t\tcallback: (storageEvent) => {\n\t\t\t// Only react to changes on our watched key.\n\t\t\tif (storageEvent.key !== options.key) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsyncCount++;\n\t\t\toptions.onSync({\n\t\t\t\tnewValue: storageEvent.newValue,\n\t\t\t\toldValue: storageEvent.oldValue,\n\t\t\t});\n\t\t},\n\t});\n\n\treturn {\n\t\tdispose() {\n\t\t\tsubscription.unsubscribe();\n\t\t},\n\t\tget syncCount() {\n\t\t\treturn syncCount;\n\t\t},\n\t};\n}\n","// Page resume reconciler — browser lifecycle hardening primitive.\n\nexport const PageResumeTriggerKind = {\n\tVisibility: \"visibility\",\n\tPageShow: \"pageshow\",\n\tFocus: \"focus\",\n\tOnline: \"online\",\n} as const;\n\nexport type PageResumeTriggerKind =\n\t(typeof PageResumeTriggerKind)[keyof typeof PageResumeTriggerKind];\n\nexport interface PageResumeEvent {\n\ttrigger: PageResumeTriggerKind;\n\tpersisted?: boolean;\n}\n\nexport type PageResumeCallback = (\n\tevent: PageResumeEvent,\n) => void | Promise<void>;\n\nexport interface PageResumeDocumentTarget {\n\taddEventListener(type: \"visibilitychange\", handler: EventListener): void;\n\tremoveEventListener(type: \"visibilitychange\", handler: EventListener): void;\n\tvisibilityState: DocumentVisibilityState;\n}\n\nexport interface PageResumeWindowTarget {\n\taddEventListener(\n\t\ttype: \"pageshow\" | \"focus\" | \"online\",\n\t\thandler: EventListener,\n\t): void;\n\tremoveEventListener(\n\t\ttype: \"pageshow\" | \"focus\" | \"online\",\n\t\thandler: EventListener,\n\t): void;\n}\n\nexport interface CreatePageResumeReconcilerOptions {\n\tonReconcile: PageResumeCallback;\n\t/** Defaults to 5000ms. Use 0 in deterministic tests. */\n\tthrottleMs?: number;\n\tdocument?: PageResumeDocumentTarget | null;\n\twindow?: PageResumeWindowTarget | null;\n\tnow?: () => number;\n\tonError?: (error: unknown, event: PageResumeEvent) => void;\n}\n\nexport interface PageResumeReconciler {\n\tdispose(): void;\n\treadonly reconcileCount: number;\n}\n\ntype Cleanup = () => void;\n\nexport function createPageResumeReconciler(\n\toptions: CreatePageResumeReconcilerOptions,\n): PageResumeReconciler {\n\tconst throttleMs = options.throttleMs ?? 5000;\n\tconst getNow = options.now ?? (() => Date.now());\n\tconst doc = options.document ?? maybeDocument();\n\tconst win = options.window ?? maybeWindow();\n\n\tlet previousVisibilityState: DocumentVisibilityState =\n\t\tdoc?.visibilityState ?? \"visible\";\n\tlet lastReconcileAt = 0;\n\tlet reconcileCount = 0;\n\tlet disposed = false;\n\tconst cleanups: Cleanup[] = [];\n\n\tconst reconcile = (event: PageResumeEvent): void => {\n\t\tif (disposed) return;\n\t\tconst now = getNow();\n\t\tif (now - lastReconcileAt < throttleMs) return;\n\n\t\tlastReconcileAt = now;\n\t\treconcileCount += 1;\n\t\ttry {\n\t\t\tconst result = options.onReconcile(event);\n\t\t\tif (isPromiseLike(result)) {\n\t\t\t\tresult.catch((error) => options.onError?.(error, event));\n\t\t\t}\n\t\t} catch (error) {\n\t\t\toptions.onError?.(error, event);\n\t\t}\n\t};\n\n\tif (doc) {\n\t\tconst handler: EventListener = () => {\n\t\t\tconst nextVisibilityState = doc.visibilityState;\n\t\t\tif (\n\t\t\t\tnextVisibilityState === \"visible\" &&\n\t\t\t\tpreviousVisibilityState !== \"visible\"\n\t\t\t) {\n\t\t\t\treconcile({ trigger: PageResumeTriggerKind.Visibility });\n\t\t\t}\n\t\t\tpreviousVisibilityState = nextVisibilityState;\n\t\t};\n\t\tdoc.addEventListener(\"visibilitychange\", handler);\n\t\tcleanups.push(() => doc.removeEventListener(\"visibilitychange\", handler));\n\t}\n\n\tif (win) {\n\t\tconst pageshowHandler: EventListener = (event) => {\n\t\t\treconcile({\n\t\t\t\ttrigger: PageResumeTriggerKind.PageShow,\n\t\t\t\tpersisted: Boolean((event as PageTransitionEvent).persisted),\n\t\t\t});\n\t\t};\n\t\tconst focusHandler: EventListener = () => {\n\t\t\treconcile({ trigger: PageResumeTriggerKind.Focus });\n\t\t};\n\t\tconst onlineHandler: EventListener = () => {\n\t\t\treconcile({ trigger: PageResumeTriggerKind.Online });\n\t\t};\n\n\t\twin.addEventListener(\"pageshow\", pageshowHandler);\n\t\twin.addEventListener(\"focus\", focusHandler);\n\t\twin.addEventListener(\"online\", onlineHandler);\n\t\tcleanups.push(() => win.removeEventListener(\"pageshow\", pageshowHandler));\n\t\tcleanups.push(() => win.removeEventListener(\"focus\", focusHandler));\n\t\tcleanups.push(() => win.removeEventListener(\"online\", onlineHandler));\n\t}\n\n\treturn {\n\t\tdispose() {\n\t\t\tif (disposed) return;\n\t\t\tdisposed = true;\n\t\t\tfor (const cleanup of cleanups.splice(0)) {\n\t\t\t\tcleanup();\n\t\t\t}\n\t\t},\n\t\tget reconcileCount() {\n\t\t\treturn reconcileCount;\n\t\t},\n\t};\n}\n\nfunction maybeDocument(): PageResumeDocumentTarget | null {\n\tconst documentTarget = globalThis.document;\n\treturn isPageResumeDocumentTarget(documentTarget) ? documentTarget : null;\n}\n\nfunction maybeWindow(): PageResumeWindowTarget | null {\n\tconst windowTarget = globalThis.window;\n\treturn isPageResumeWindowTarget(windowTarget) ? windowTarget : null;\n}\n\nfunction isPageResumeDocumentTarget(\n\tvalue: unknown,\n): value is PageResumeDocumentTarget {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"visibilityState\" in value &&\n\t\ttypeof (value as { addEventListener?: unknown }).addEventListener ===\n\t\t\t\"function\" &&\n\t\ttypeof (value as { removeEventListener?: unknown }).removeEventListener ===\n\t\t\t\"function\"\n\t);\n}\n\nfunction isPageResumeWindowTarget(\n\tvalue: unknown,\n): value is PageResumeWindowTarget {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\ttypeof (value as { addEventListener?: unknown }).addEventListener ===\n\t\t\t\"function\" &&\n\t\ttypeof (value as { removeEventListener?: unknown }).removeEventListener ===\n\t\t\t\"function\"\n\t);\n}\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<void> {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"then\" in value &&\n\t\ttypeof (value as { then?: unknown }).then === \"function\"\n\t);\n}\n","// Popup shared infrastructure — browser-only helpers\n//\n// Provides cross-mode popup window management for login flows.\n// Owned by @securitydept/client/web, consumed by backend-oidc-mode\n// and frontend-oidc-mode popup login entries.\n\nimport { ClientError, ClientErrorKind, UserRecovery } from \"../errors/index\";\n\n// ---------------------------------------------------------------------------\n// Error codes (stable contract)\n// ---------------------------------------------------------------------------\n\n/** Stable error codes for popup-related failures. */\nexport const PopupErrorCode = {\n\t/** The browser blocked the popup window from opening. */\n\tBlocked: \"popup.blocked\",\n\t/** The popup was closed by the user before completing the flow. */\n\tClosed: \"popup.closed_by_user\",\n\t/** The relay message was not received within the timeout. */\n\tTimeout: \"popup.relay_timeout\",\n\t/** The relay message contained an error from the callback page. */\n\tRelayError: \"popup.relay_error\",\n\t/** An unexpected error occurred during popup lifecycle. */\n\tInternal: \"popup.internal\",\n} as const;\n\nexport type PopupErrorCode =\n\t(typeof PopupErrorCode)[keyof typeof PopupErrorCode];\n\n// ---------------------------------------------------------------------------\n// Popup features\n// ---------------------------------------------------------------------------\n\n/**\n * Options for computing the popup window features string.\n */\nexport interface PopupFeaturesOptions {\n\t/** Width in pixels (default: 500). */\n\twidth?: number;\n\t/** Height in pixels (default: 600). */\n\theight?: number;\n}\n\n/**\n * Compute the `features` string for `window.open()`, centered on screen.\n */\nexport function computePopupFeatures(\n\toptions: PopupFeaturesOptions = {},\n): string {\n\tconst width = options.width ?? 500;\n\tconst height = options.height ?? 600;\n\tconst left = Math.max(\n\t\t0,\n\t\tMath.round(window.screenX + (window.innerWidth - width) / 2),\n\t);\n\tconst top = Math.max(\n\t\t0,\n\t\tMath.round(window.screenY + (window.innerHeight - height) / 2),\n\t);\n\n\treturn `width=${width},height=${height},left=${left},top=${top},popup=yes,toolbar=no,menubar=no`;\n}\n\n// ---------------------------------------------------------------------------\n// Popup open + blocked detection\n// ---------------------------------------------------------------------------\n\n/**\n * Result of opening a popup window.\n */\nexport interface PopupWindowHandle {\n\t/** The opened window reference. */\n\twindow: Window;\n}\n\n/**\n * Open a popup window to the given URL.\n *\n * Throws a `ClientError` with code `popup.blocked` if the browser\n * blocks the popup.\n */\nexport function openPopupWindow(\n\turl: string,\n\toptions?: PopupFeaturesOptions & { target?: string },\n): PopupWindowHandle {\n\tconst features = computePopupFeatures(options);\n\tconst target = options?.target ?? \"_blank\";\n\n\tconst win = window.open(url, target, features);\n\n\tif (!win || win.closed) {\n\t\tthrow new ClientError({\n\t\t\tkind: ClientErrorKind.Authorization,\n\t\t\tcode: PopupErrorCode.Blocked,\n\t\t\tmessage:\n\t\t\t\t\"Popup window was blocked by the browser. Please allow popups for this site.\",\n\t\t\trecovery: UserRecovery.Retry,\n\t\t\tsource: \"popup\",\n\t\t});\n\t}\n\n\treturn { window: win };\n}\n\n// ---------------------------------------------------------------------------\n// PostMessage relay\n// ---------------------------------------------------------------------------\n\n/**\n * Expected shape of a relay message from the popup callback page.\n */\nexport interface PopupRelayMessage {\n\t/** Discriminator for the message type. */\n\ttype: \"securitydept:popup_callback\";\n\t/** The callback URL or fragment received by the popup. */\n\tpayload: string;\n\t/** Optional error from the callback page. */\n\terror?: string;\n}\n\n/**\n * Options for waiting for a popup relay message.\n */\nexport interface WaitForPopupRelayOptions {\n\t/** The popup window handle to monitor. */\n\tpopup: PopupWindowHandle;\n\t/** Maximum time to wait in milliseconds (default: 120000 = 2 minutes). */\n\ttimeoutMs?: number;\n\t/** Expected origin for the relay message (default: current origin). */\n\texpectedOrigin?: string;\n\t/** Poll interval for checking if the popup is closed (default: 500ms). */\n\tpollIntervalMs?: number;\n}\n\n/**\n * Wait for a relay message from a popup callback page.\n *\n * The popup callback page should call `relayPopupCallback()` to post\n * the callback URL back to the opener.\n *\n * Resolves with the callback payload (URL or fragment string).\n * Rejects with a `ClientError` if:\n * - the popup is closed without relaying (popup.closed_by_user)\n * - the timeout expires (popup.relay_timeout)\n * - the relay message contains an error (popup.relay_error)\n */\nexport function waitForPopupRelay(\n\toptions: WaitForPopupRelayOptions,\n): Promise<string> {\n\tconst timeoutMs = options.timeoutMs ?? 120_000;\n\tconst expectedOrigin = options.expectedOrigin ?? window.location.origin;\n\tconst pollIntervalMs = options.pollIntervalMs ?? 500;\n\n\treturn new Promise<string>((resolve, reject) => {\n\t\tlet settled = false;\n\t\tlet timeoutId: ReturnType<typeof setTimeout>;\n\t\tlet pollId: ReturnType<typeof setInterval>;\n\n\t\tfunction cleanup() {\n\t\t\tsettled = true;\n\t\t\tclearTimeout(timeoutId);\n\t\t\tclearInterval(pollId);\n\t\t\twindow.removeEventListener(\"message\", onMessage);\n\t\t}\n\n\t\tfunction onMessage(event: MessageEvent) {\n\t\t\tif (settled) return;\n\t\t\tif (event.origin !== expectedOrigin) return;\n\n\t\t\tconst data = event.data as PopupRelayMessage | undefined;\n\t\t\tif (!data || data.type !== \"securitydept:popup_callback\") return;\n\n\t\t\tcleanup();\n\n\t\t\tif (data.error) {\n\t\t\t\treject(\n\t\t\t\t\tnew ClientError({\n\t\t\t\t\t\tkind: ClientErrorKind.Protocol,\n\t\t\t\t\t\tcode: PopupErrorCode.RelayError,\n\t\t\t\t\t\tmessage: `Popup callback relay error: ${data.error}`,\n\t\t\t\t\t\tsource: \"popup\",\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tresolve(data.payload);\n\t\t}\n\n\t\t// Listen for relay messages.\n\t\twindow.addEventListener(\"message\", onMessage);\n\n\t\t// Poll for popup closure.\n\t\tpollId = setInterval(() => {\n\t\t\tif (settled) return;\n\t\t\tif (options.popup.window.closed) {\n\t\t\t\tcleanup();\n\t\t\t\treject(\n\t\t\t\t\tnew ClientError({\n\t\t\t\t\t\tkind: ClientErrorKind.Authorization,\n\t\t\t\t\t\tcode: PopupErrorCode.Closed,\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\"Popup window was closed before completing the login flow.\",\n\t\t\t\t\t\trecovery: UserRecovery.RestartFlow,\n\t\t\t\t\t\tsource: \"popup\",\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t}, pollIntervalMs);\n\n\t\t// Timeout.\n\t\ttimeoutId = setTimeout(() => {\n\t\t\tif (settled) return;\n\t\t\tcleanup();\n\t\t\ttry {\n\t\t\t\toptions.popup.window.close();\n\t\t\t} catch {\n\t\t\t\t// Best-effort close.\n\t\t\t}\n\t\t\treject(\n\t\t\t\tnew ClientError({\n\t\t\t\t\tkind: ClientErrorKind.Timeout,\n\t\t\t\t\tcode: PopupErrorCode.Timeout,\n\t\t\t\t\tmessage: `Popup login timed out after ${timeoutMs}ms.`,\n\t\t\t\t\trecovery: UserRecovery.Retry,\n\t\t\t\t\tsource: \"popup\",\n\t\t\t\t}),\n\t\t\t);\n\t\t}, timeoutMs);\n\t});\n}\n\n// ---------------------------------------------------------------------------\n// Popup callback relay (for use in popup callback pages)\n// ---------------------------------------------------------------------------\n\n/**\n * Options for relaying the callback from the popup window back to the opener.\n */\nexport interface RelayPopupCallbackOptions {\n\t/** The callback payload (URL or fragment) to relay. */\n\tpayload?: string;\n\t/** An error message to relay instead of a successful payload. */\n\terror?: string;\n\t/** Whether to close the popup after relaying (default: true). */\n\tcloseAfterRelay?: boolean;\n\t/** Target origin for the postMessage (default: current origin). */\n\ttargetOrigin?: string;\n}\n\n/**\n * Relay the popup callback result back to the opener window.\n *\n * Call this function from the popup callback page to send the callback\n * URL/fragment back to the parent window that initiated the popup login.\n *\n * @example\n * ```html\n * <script type=\"module\">\n * import { relayPopupCallback } from \"@securitydept/client/web\";\n * relayPopupCallback({ payload: window.location.href });\n * </script>\n * ```\n */\nexport function relayPopupCallback(\n\toptions: RelayPopupCallbackOptions = {},\n): void {\n\tconst opener = window.opener;\n\tif (!opener) {\n\t\treturn;\n\t}\n\n\tconst targetOrigin = options.targetOrigin ?? window.location.origin;\n\tconst message: PopupRelayMessage = {\n\t\ttype: \"securitydept:popup_callback\",\n\t\tpayload: options.payload ?? window.location.href,\n\t\terror: options.error,\n\t};\n\n\topener.postMessage(message, targetOrigin);\n\n\tif (options.closeAfterRelay !== false) {\n\t\tsetTimeout(() => {\n\t\t\twindow.close();\n\t\t}, 0);\n\t}\n}\n","import { createRuntime } from \"../runtime/create-runtime\";\nimport type { ClientRuntime } from \"../runtime/types\";\nimport {\n\tcreateFetchTransport,\n\ttype FetchTransportOptions,\n} from \"../transport/fetch-transport\";\n\nexport interface CreateWebRuntimeOptions\n\textends Partial<Omit<ClientRuntime, \"transport\">> {\n\ttransport?: ClientRuntime[\"transport\"];\n\tfetchTransport?: FetchTransportOptions;\n}\n\n/**\n * Create a `ClientRuntime` for browser/Web-capable environments.\n */\nexport function createWebRuntime(\n\toverrides: CreateWebRuntimeOptions = {},\n): ClientRuntime {\n\tconst { fetchTransport, transport, ...runtime } = overrides;\n\treturn createRuntime({\n\t\t...runtime,\n\t\ttransport: transport ?? createFetchTransport(fetchTransport),\n\t});\n}\n","// Browser visibility change adapter — built on fromEventPattern.\n//\n// Adapts the browser `visibilitychange` event into the SDK's Subscription\n// model, built on the foundation fromEventPattern helper.\n\nimport { fromEventPattern, type Subscription } from \"../scheduling/helpers\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Visibility state snapshot passed to the callback. */\nexport const VisibilityState = {\n\tVisible: \"visible\",\n\tHidden: \"hidden\",\n} as const;\n\nexport type VisibilityState =\n\t(typeof VisibilityState)[keyof typeof VisibilityState];\n\n/** Options for {@link fromVisibilityChange}. */\nexport interface FromVisibilityChangeOptions {\n\t/**\n\t * Callback invoked when the document visibility state changes.\n\t *\n\t * The callback receives the new visibility state (\"visible\" or \"hidden\").\n\t */\n\tcallback: (state: VisibilityState) => void;\n\t/**\n\t * Override the document target (primarily for testing).\n\t * Defaults to `globalThis.document`.\n\t */\n\tdocument?: Pick<\n\t\tDocument,\n\t\t\"addEventListener\" | \"removeEventListener\" | \"visibilityState\"\n\t>;\n}\n\n// ---------------------------------------------------------------------------\n// Implementation\n// ---------------------------------------------------------------------------\n\n/**\n * Subscribe to browser document visibility changes.\n *\n * Built on {@link fromEventPattern} so it follows the same Subscription\n * contract. Returns a {@link Subscription} handle for cleanup.\n *\n * @example\n * ```ts\n * const sub = fromVisibilityChange({\n * callback: (state) => {\n * if (state === VisibilityState.Visible) {\n * scheduleRefresh();\n * }\n * },\n * });\n * // Cleanup:\n * sub.unsubscribe();\n * ```\n */\nexport function fromVisibilityChange(\n\toptions: FromVisibilityChangeOptions,\n): Subscription {\n\tconst doc = options.document ?? globalThis.document;\n\n\treturn fromEventPattern<Event>({\n\t\taddHandler: (handler) => {\n\t\t\tdoc.addEventListener(\"visibilitychange\", handler);\n\t\t},\n\t\tremoveHandler: (handler) => {\n\t\t\tdoc.removeEventListener(\"visibilitychange\", handler);\n\t\t},\n\t\tcallback: () => {\n\t\t\tconst state: VisibilityState =\n\t\t\t\tdoc.visibilityState === \"visible\"\n\t\t\t\t\t? VisibilityState.Visible\n\t\t\t\t\t: VisibilityState.Hidden;\n\t\t\toptions.callback(state);\n\t\t},\n\t});\n}\n","// Visibility reconciler — cross-tab / visibility lifecycle hardening baseline\n//\n// Provides a minimal, composable integration between the browser visibility\n// change adapter and the auth material lifecycle. When a tab transitions from\n// hidden → visible, the reconciler triggers a user-supplied reconciliation\n// callback (e.g. check token freshness, re-validate with server, or sync\n// cross-tab state).\n//\n// This is the SDK-side baseline that real projects (e.g. outposts) can wire\n// directly to their mode client's refresh or state-check logic.\n\nimport type { Subscription } from \"../scheduling/helpers\";\nimport type { FromVisibilityChangeOptions } from \"./visibility\";\nimport { fromVisibilityChange, VisibilityState } from \"./visibility\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Callback invoked when the page becomes visible and reconciliation is needed. */\nexport type ReconcileCallback = () => void | Promise<void>;\n\n/** Options for {@link createVisibilityReconciler}. */\nexport interface CreateVisibilityReconcilerOptions {\n\t/**\n\t * Called when the document transitions from hidden → visible.\n\t * The reconciler only fires on the hidden→visible edge; repeated\n\t * visible→visible events are suppressed.\n\t */\n\tonReconcile: ReconcileCallback;\n\n\t/**\n\t * Minimum interval (ms) between reconciliation triggers.\n\t * Prevents rapid-fire reconciliation when the user toggles tabs quickly.\n\t * Defaults to 5000ms (5 seconds).\n\t */\n\tthrottleMs?: number;\n\n\t/**\n\t * Override the document target (primarily for testing).\n\t * Defaults to `globalThis.document`.\n\t */\n\tdocument?: FromVisibilityChangeOptions[\"document\"];\n\n\t/**\n\t * Clock override for testing.\n\t */\n\tnow?: () => number;\n}\n\n/** Handle returned by {@link createVisibilityReconciler}. */\nexport interface VisibilityReconciler {\n\t/** Stop listening for visibility changes. */\n\tdispose(): void;\n\t/** Number of times reconciliation has been triggered. */\n\treadonly reconcileCount: number;\n}\n\n// ---------------------------------------------------------------------------\n// Implementation\n// ---------------------------------------------------------------------------\n\n/**\n * Create a visibility reconciler that triggers a callback when the page\n * transitions from hidden → visible.\n *\n * @example\n * ```ts\n * const reconciler = createVisibilityReconciler({\n * onReconcile: () => {\n * // Re-check token freshness or sync cross-tab state\n * if (controller.snapshot?.tokens.accessTokenExpiresAt) {\n * scheduleRefreshIfExpired();\n * }\n * },\n * });\n * // Later:\n * reconciler.dispose();\n * ```\n */\nexport function createVisibilityReconciler(\n\toptions: CreateVisibilityReconcilerOptions,\n): VisibilityReconciler {\n\tconst throttleMs = options.throttleMs ?? 5000;\n\tconst getNow = options.now ?? (() => Date.now());\n\n\tlet lastReconcileAt = 0;\n\tlet reconcileCount = 0;\n\t// Initialize from the real document state so that tabs opened in background\n\t// (initial hidden) will correctly trigger on their first visible transition.\n\tconst doc = options.document ?? globalThis.document;\n\tlet previousState: VisibilityState =\n\t\tdoc.visibilityState === \"visible\"\n\t\t\t? VisibilityState.Visible\n\t\t\t: VisibilityState.Hidden;\n\n\tconst subscription: Subscription = fromVisibilityChange({\n\t\tcallback: (state) => {\n\t\t\t// Only fire on the hidden → visible edge.\n\t\t\tif (\n\t\t\t\tstate === VisibilityState.Visible &&\n\t\t\t\tpreviousState === VisibilityState.Hidden\n\t\t\t) {\n\t\t\t\tconst now = getNow();\n\t\t\t\tif (now - lastReconcileAt >= throttleMs) {\n\t\t\t\t\tlastReconcileAt = now;\n\t\t\t\t\treconcileCount++;\n\t\t\t\t\toptions.onReconcile();\n\t\t\t\t}\n\t\t\t}\n\t\t\tpreviousState = state;\n\t\t},\n\t\tdocument: doc,\n\t});\n\n\treturn {\n\t\tdispose() {\n\t\t\tsubscription.unsubscribe();\n\t\t},\n\t\tget reconcileCount() {\n\t\t\treturn reconcileCount;\n\t\t},\n\t};\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["defineType","global","defineType"],"sources":["../../src/web/events/from-storage.ts","../../src/web/popup.ts","../../src/web/storage.ts","../../src/web/environment.ts","../../src/web/sync/cross-tab-sync.ts"],"sourcesContent":["import { fromEventPattern } from \"rxjs\";\nimport { type EventStreamTrait } from \"../../events\";\nimport { RxEventStream } from \"../../rx\";\n\nexport interface StorageEventTarget {\n\taddEventListener(type: \"storage\", listener: EventListener): void;\n\tremoveEventListener(type: \"storage\", listener: EventListener): void;\n}\n\nexport interface FromStorageEventOptions {\n\tstorageEventTarget: StorageEventTarget;\n}\n\n/**\n * Adapt browser `storage` events into an event stream.\n */\nexport function fromStorageEvent(\n\toptions: FromStorageEventOptions,\n): EventStreamTrait<StorageEvent> {\n\tconst { storageEventTarget } = options;\n\n\treturn RxEventStream.fromObservableInput(\n\t\tfromEventPattern<StorageEvent>(\n\t\t\t(handler) => {\n\t\t\t\tstorageEventTarget.addEventListener(\"storage\", handler);\n\t\t\t},\n\t\t\t(handler) => {\n\t\t\t\tstorageEventTarget.removeEventListener(\"storage\", handler);\n\t\t\t},\n\t\t),\n\t);\n}\n","import { type as defineType } from \"arktype\";\nimport { filter, fromEventPattern, map, take, timer } from \"rxjs\";\nimport { type EnvironmentValidators } from \"../environment/types\";\nimport { ClientError, ClientErrorKind, UserRecovery } from \"../errors\";\nimport { type EventSubjectTrait } from \"../events\";\nimport { type WithTraitDeps } from \"../injection\";\nimport {\n\tPopupAttachFailureReason,\n\ttype PopupAttachResult,\n\tPopupClientWindowHandle,\n\ttype PopupClientWindowHandleTrait,\n\tPopupErrorCode,\n\ttype PopupOpenOptions,\n\tPopupServerWindowHandle,\n\ttype PopupTrait,\n} from \"../popup\";\nimport { type JsonRpcMessage } from \"../protocol/json-rpc\";\nimport {\n\tcreateAsyncSchedulerWithTimestampProvider,\n\tRxEventStream,\n\tRxEventSubject,\n} from \"../rx\";\nimport { type TimeTrait } from \"../scheduling/types\";\nimport {\n\tthrowValidationClientError,\n\tvalidateTraitInput,\n\tvalidateWithSchemaSync,\n\ttype WithTraitInputValidator,\n} from \"../validation\";\n\nexport interface PopupForNativeWebCreateOptions {\n\twindow?: unknown;\n}\n\nexport interface PopupFeaturesOptions {\n\twidth?: number;\n\theight?: number;\n}\n\nexport interface NativeWebPopupWindowLike {\n\tclosed: boolean;\n\tclose(): void;\n\tpostMessage(message: unknown, targetOrigin: string): void;\n}\n\nexport type NativeWebPopupContextWindowLike = NativeWebWindowLike &\n\tNativeWebPopupWindowLike;\n\nexport interface NativeWebWindowLike {\n\topen(\n\t\turl: string,\n\t\ttarget?: string,\n\t\tfeatures?: string,\n\t): NativeWebPopupWindowLike | null;\n\taddEventListener(\n\t\ttype: \"message\",\n\t\thandler: (event: MessageEvent) => void,\n\t): void;\n\tremoveEventListener(\n\t\ttype: \"message\",\n\t\thandler: (event: MessageEvent) => void,\n\t): void;\n\tlocation?: {\n\t\thref?: string;\n\t\torigin?: string;\n\t};\n\tscreenX?: number;\n\tscreenY?: number;\n\tinnerWidth?: number;\n\tinnerHeight?: number;\n\tclose?(): void;\n\topener?: {\n\t\tpostMessage(message: unknown, targetOrigin: string): void;\n\t} | null;\n}\n\ninterface CreatePopupClientWindowHandleForNativeWebOptions\n\textends PopupFeaturesOptions,\n\t\tPopupOpenOptions {\n\turl: string;\n\ttime: TimeTrait;\n\twindow: NativeWebWindowLike;\n\texpectedOrigin?: string;\n\tpollIntervalMs?: number;\n}\n\nconst PopupForNativeWebCreateOptionsSchema = defineType({\n\twindow: {\n\t\topen: \"Function\",\n\t\taddEventListener: \"Function\",\n\t\tremoveEventListener: \"Function\",\n\t},\n});\n\nconst PopupForNativeWebUnavailableProbeSchema = defineType({\n\twindow: \"null | undefined\",\n});\n\nexport function createPopupForNativeWeb(\n\toptions: PopupForNativeWebCreateOptions &\n\t\tWithTraitInputValidator<Pick<EnvironmentValidators, \"popup\">> &\n\t\tWithTraitDeps<{ time: TimeTrait }>,\n): PopupTrait | null {\n\tconst { validators, time, ...createOptions } = options;\n\tconst global = globalThis as { window?: NativeWebWindowLike };\n\tconst resolvedCreateOptions = {\n\t\twindow: global.window ?? null,\n\t\t...createOptions,\n\t};\n\tconst unavailableProbeResult = validateWithSchemaSync(\n\t\tPopupForNativeWebUnavailableProbeSchema,\n\t\tresolvedCreateOptions,\n\t);\n\tif (unavailableProbeResult.success) {\n\t\treturn null;\n\t}\n\tvalidateTraitInput({\n\t\tvalue: resolvedCreateOptions,\n\t\tbundledSchema: PopupForNativeWebCreateOptionsSchema,\n\t\tvalidator: validators?.popup,\n\t\tonInvalid: (failure) =>\n\t\t\tthrowValidationClientError({\n\t\t\t\tcode: \"web.popup.invalid_native_web_popup_options\",\n\t\t\t\tsource: \"web\",\n\t\t\t\tmessagePrefix:\n\t\t\t\t\t\"createPopupForNativeWeb could not validate popupForNativeWebCreateOptions\",\n\t\t\t\tfailure,\n\t\t\t}),\n\t});\n\tconst nativeWebWindow = resolvedCreateOptions.window as NativeWebWindowLike;\n\treturn {\n\t\topen(url, openOptions) {\n\t\t\treturn createPopupClientWindowHandleForNativeWeb({\n\t\t\t\turl,\n\t\t\t\ttime,\n\t\t\t\twindow: nativeWebWindow,\n\t\t\t\t...openOptions,\n\t\t\t});\n\t\t},\n\t\tattach() {\n\t\t\treturn attachPopupWindowToOpenerForNativeWeb({\n\t\t\t\ttime,\n\t\t\t\twindow: nativeWebWindow,\n\t\t\t});\n\t\t},\n\t};\n}\n\nexport function computePopupFeatures(\n\toptions: PopupFeaturesOptions = {},\n\twindowLike: Pick<\n\t\tNativeWebWindowLike,\n\t\t\"screenX\" | \"screenY\" | \"innerWidth\" | \"innerHeight\"\n\t> = globalThis as NativeWebWindowLike,\n): string {\n\tconst width = options.width ?? 500;\n\tconst height = options.height ?? 600;\n\tconst left = Math.max(\n\t\t0,\n\t\tMath.round(\n\t\t\t(windowLike.screenX ?? 0) +\n\t\t\t\t((windowLike.innerWidth ?? width) - width) / 2,\n\t\t),\n\t);\n\tconst top = Math.max(\n\t\t0,\n\t\tMath.round(\n\t\t\t(windowLike.screenY ?? 0) +\n\t\t\t\t((windowLike.innerHeight ?? height) - height) / 2,\n\t\t),\n\t);\n\n\treturn `width=${width},height=${height},left=${left},top=${top},popup=yes,toolbar=no,menubar=no`;\n}\n\nfunction createPopupClientWindowHandleForNativeWeb(\n\toptions: CreatePopupClientWindowHandleForNativeWebOptions,\n): PopupClientWindowHandleTrait {\n\tconst hostWindow = options.window;\n\tconst features = computePopupFeatures(options, hostWindow);\n\tconst target = options.target ?? \"_blank\";\n\tconst popupWindow = hostWindow.open(options.url, target, features);\n\n\tif (!popupWindow || popupWindow.closed) {\n\t\tthrow new ClientError({\n\t\t\tkind: ClientErrorKind.Authorization,\n\t\t\tcode: PopupErrorCode.Blocked,\n\t\t\tmessage:\n\t\t\t\t\"Popup window was blocked by the browser. Please allow popups for this site.\",\n\t\t\trecovery: UserRecovery.Retry,\n\t\t\tsource: \"popup\",\n\t\t});\n\t}\n\n\tconst resolvedBaseHref = hostWindow.location?.href ?? \"http://localhost\";\n\tconst expectedOrigin =\n\t\toptions.expectedOrigin ?? new URL(options.url, resolvedBaseHref).origin;\n\tconst incoming = RxEventStream.fromObservableInput(\n\t\tfromEventPattern<MessageEvent>(\n\t\t\t(handler) => {\n\t\t\t\thostWindow.addEventListener(\"message\", handler);\n\t\t\t},\n\t\t\t(handler) => {\n\t\t\t\thostWindow.removeEventListener(\"message\", handler);\n\t\t\t},\n\t\t).pipe(\n\t\t\tfilter(\n\t\t\t\t(event) =>\n\t\t\t\t\tevent.origin === expectedOrigin && event.source === popupWindow,\n\t\t\t),\n\t\t\tmap((event) => event.data),\n\t\t),\n\t);\n\tconst outgoing = createPostMessageSubject((message) => {\n\t\tpopupWindow.postMessage(message, expectedOrigin);\n\t});\n\tconst closedStream = RxEventStream.fromObservableInput(\n\t\ttimer(\n\t\t\toptions.pollIntervalMs ?? 500,\n\t\t\toptions.pollIntervalMs ?? 500,\n\t\t\tcreateAsyncSchedulerWithTimestampProvider(options.time),\n\t\t).pipe(\n\t\t\tfilter(() => popupWindow.closed),\n\t\t\tmap(() => true),\n\t\t\ttake(1),\n\t\t),\n\t);\n\n\treturn new PopupClientWindowHandle({\n\t\tclose() {\n\t\t\tpopupWindow.close();\n\t\t},\n\t\tmessaging: {\n\t\t\tincoming,\n\t\t\toutgoing,\n\t\t},\n\t\ttime: options.time,\n\t\tclosedStream,\n\t});\n}\n\nfunction attachPopupWindowToOpenerForNativeWeb(options: {\n\ttime: TimeTrait;\n\twindow: NativeWebWindowLike;\n}): PopupAttachResult {\n\tconst currentWindow = options.window as NativeWebPopupContextWindowLike;\n\tconst opener = currentWindow.opener;\n\tif (!opener) {\n\t\treturn {\n\t\t\tkind: \"failure\",\n\t\t\treason: PopupAttachFailureReason.MissingOpener,\n\t\t\terror: new ClientError({\n\t\t\t\tkind: ClientErrorKind.Configuration,\n\t\t\t\tmessage:\n\t\t\t\t\t\"Current page is not attached to a popup opener and cannot attach popup messaging.\",\n\t\t\t\trecovery: UserRecovery.RestartFlow,\n\t\t\t\tsource: \"popup\",\n\t\t\t}),\n\t\t};\n\t}\n\n\tconst allowedParentOrigin = currentWindow.location?.origin ?? undefined;\n\tif (!allowedParentOrigin) {\n\t\treturn {\n\t\t\tkind: \"failure\",\n\t\t\treason: PopupAttachFailureReason.MissingOrigin,\n\t\t\terror: new ClientError({\n\t\t\t\tkind: ClientErrorKind.Configuration,\n\t\t\t\tmessage:\n\t\t\t\t\t\"Current page has no origin information and cannot attach popup messaging.\",\n\t\t\t\trecovery: UserRecovery.RestartFlow,\n\t\t\t\tsource: \"popup\",\n\t\t\t}),\n\t\t};\n\t}\n\n\tconst incoming = RxEventStream.fromObservableInput(\n\t\tfromEventPattern<MessageEvent>(\n\t\t\t(handler) => {\n\t\t\t\tcurrentWindow.addEventListener(\"message\", handler);\n\t\t\t},\n\t\t\t(handler) => {\n\t\t\t\tcurrentWindow.removeEventListener(\"message\", handler);\n\t\t\t},\n\t\t).pipe(\n\t\t\tfilter(\n\t\t\t\t(event) =>\n\t\t\t\t\tevent.origin === allowedParentOrigin && event.source === opener,\n\t\t\t),\n\t\t\tmap((event) => event.data),\n\t\t),\n\t);\n\tconst outgoing = createPostMessageSubject((message) => {\n\t\topener.postMessage(message, allowedParentOrigin);\n\t});\n\n\treturn {\n\t\tkind: \"success\",\n\t\thandle: new PopupServerWindowHandle({\n\t\t\tclose() {\n\t\t\t\tcurrentWindow.close();\n\t\t\t},\n\t\t\tmessaging: {\n\t\t\t\tincoming,\n\t\t\t\toutgoing,\n\t\t\t},\n\t\t}),\n\t};\n}\n\nfunction createPostMessageSubject(\n\tsend: (message: JsonRpcMessage) => void,\n): EventSubjectTrait<JsonRpcMessage> {\n\tconst outgoing = new RxEventSubject<JsonRpcMessage>();\n\toutgoing.subscribe({\n\t\tnext(message) {\n\t\t\tsend(message);\n\t\t},\n\t});\n\treturn outgoing;\n}\n","import { type as defineType } from \"arktype\";\nimport { filter, from, map, merge } from \"rxjs\";\nimport { type EnvironmentValidators } from \"../environment/types\";\nimport { RxEventStream, RxEventSubject } from \"../rx\";\nimport {\n\ttype StorageChangeEvent,\n\tStorageChangeEventOrigin,\n\ttype SyncStorageTrait,\n} from \"../storage/types\";\nimport {\n\tthrowValidationClientError,\n\tvalidateTraitInput,\n\tvalidateWithSchemaSync,\n\ttype WithTraitInputValidator,\n} from \"../validation\";\nimport {\n\tfromStorageEvent,\n\ttype StorageEventTarget,\n} from \"./events/from-storage\";\n\nexport interface NativeWebStorageLike {\n\tgetItem(key: string): string | null;\n\tsetItem(key: string, value: string): void;\n\tremoveItem(key: string): void;\n}\n\nconst NativeWebStorageLikeSchema = defineType({\n\tgetItem: \"Function\",\n\tsetItem: \"Function\",\n\tremoveItem: \"Function\",\n});\n\nconst StorageEventTargetSchema = defineType({\n\taddEventListener: \"Function\",\n\tremoveEventListener: \"Function\",\n});\n\nconst StorageForNativeWebCreateOptionsSchema = defineType({\n\tstorage: NativeWebStorageLikeSchema,\n\tstorageEventTarget: StorageEventTargetSchema.or(\"null\").or(\"undefined\"),\n\tprefix: \"string | undefined\",\n\tvalidatorKey: \"'persistentStorage' | 'sessionStorage'\",\n});\n\nconst StorageForNativeWebUnavailableProbeSchema = defineType({\n\tstorage: \"null | undefined\",\n\tstorageEventTarget: \"unknown\",\n\tprefix: \"string | undefined\",\n\tvalidatorKey: \"'persistentStorage' | 'sessionStorage'\",\n});\n\nexport interface StorageForNativeWebCreateOptions {\n\tstorage?: NativeWebStorageLike | null;\n\tstorageEventTarget?: StorageEventTarget | null;\n\tprefix?: string;\n\tvalidatorKey: \"persistentStorage\" | \"sessionStorage\";\n}\n\nconst DEFAULT_PERSISTENT_STORAGE_PREFIX = \"securitydept.web.client:\";\nconst DEFAULT_SESSION_STORAGE_PREFIX = \"securitydept.web.client:\";\n\nexport function createStorageForNativeWeb(\n\toptions: StorageForNativeWebCreateOptions &\n\t\tWithTraitInputValidator<\n\t\t\tPick<EnvironmentValidators, \"persistentStorage\" | \"sessionStorage\">\n\t\t>,\n): SyncStorageTrait | null {\n\tconst { validators, ...createOptions } = options;\n\tconst global = globalThis as {\n\t\tlocalStorage?: NativeWebStorageLike;\n\t\tsessionStorage?: NativeWebStorageLike;\n\t\taddEventListener?: StorageEventTarget[\"addEventListener\"];\n\t\tremoveEventListener?: StorageEventTarget[\"removeEventListener\"];\n\t};\n\tconst resolvedCreateOptions = {\n\t\tstorage:\n\t\t\toptions.validatorKey === \"persistentStorage\"\n\t\t\t\t? (global.localStorage ?? null)\n\t\t\t\t: (global.sessionStorage ?? null),\n\t\t...createOptions,\n\t\tstorageEventTarget:\n\t\t\tcreateOptions.storageEventTarget === undefined\n\t\t\t\t? typeof global.addEventListener === \"function\" &&\n\t\t\t\t\ttypeof global.removeEventListener === \"function\"\n\t\t\t\t\t? (global as StorageEventTarget)\n\t\t\t\t\t: null\n\t\t\t\t: createOptions.storageEventTarget,\n\t\tprefix:\n\t\t\tcreateOptions.prefix ??\n\t\t\t(options.validatorKey === \"persistentStorage\"\n\t\t\t\t? DEFAULT_PERSISTENT_STORAGE_PREFIX\n\t\t\t\t: DEFAULT_SESSION_STORAGE_PREFIX),\n\t};\n\tconst unavailableProbeResult = validateWithSchemaSync(\n\t\tStorageForNativeWebUnavailableProbeSchema,\n\t\tresolvedCreateOptions,\n\t);\n\tif (unavailableProbeResult.success) {\n\t\treturn null;\n\t}\n\tvalidateTraitInput({\n\t\tvalue: resolvedCreateOptions,\n\t\tbundledSchema: StorageForNativeWebCreateOptionsSchema,\n\t\tvalidator: validators?.[options.validatorKey],\n\t\tonInvalid: (failure) =>\n\t\t\tthrowValidationClientError({\n\t\t\t\tcode: \"web.storage.invalid_native_web_storage_options\",\n\t\t\t\tsource: \"web\",\n\t\t\t\tmessagePrefix: `createStorageForNativeWeb could not validate ${options.validatorKey}ForNativeWebCreateOptions`,\n\t\t\t\tfailure,\n\t\t\t}),\n\t});\n\tconst storage = resolvedCreateOptions.storage as NativeWebStorageLike;\n\tconst prefix = resolvedCreateOptions.prefix;\n\tconst localStorageEvent = new RxEventSubject<StorageChangeEvent>();\n\tconst externalStorageEvent = resolvedCreateOptions.storageEventTarget\n\t\t? from(\n\t\t\t\tfromStorageEvent({\n\t\t\t\t\tstorageEventTarget: resolvedCreateOptions.storageEventTarget,\n\t\t\t\t}),\n\t\t\t).pipe(\n\t\t\t\tfilter(\n\t\t\t\t\t(event) =>\n\t\t\t\t\t\t(event.storageArea === null || event.storageArea === storage) &&\n\t\t\t\t\t\t(event.key === null || event.key.startsWith(prefix)),\n\t\t\t\t),\n\t\t\t\tmap(\n\t\t\t\t\t(event): StorageChangeEvent => ({\n\t\t\t\t\t\torigin: StorageChangeEventOrigin.External,\n\t\t\t\t\t\tkey: event.key === null ? null : event.key.slice(prefix.length),\n\t\t\t\t\t\toldValue: event.oldValue,\n\t\t\t\t\t\tnewValue: event.newValue,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t)\n\t\t: null;\n\tconst storageEvent = RxEventStream.fromObservableInput(\n\t\texternalStorageEvent\n\t\t\t? merge(localStorageEvent, externalStorageEvent)\n\t\t\t: localStorageEvent,\n\t);\n\n\treturn {\n\t\tstorageEvent,\n\t\tget(key) {\n\t\t\treturn storage.getItem(prefix + key);\n\t\t},\n\t\tset(key, value) {\n\t\t\tconst storageKey = prefix + key;\n\t\t\tconst oldValue = storage.getItem(storageKey);\n\t\t\tstorage.setItem(storageKey, value);\n\t\t\tlocalStorageEvent.next({\n\t\t\t\torigin: StorageChangeEventOrigin.Local,\n\t\t\t\tkey,\n\t\t\t\toldValue,\n\t\t\t\tnewValue: value,\n\t\t\t});\n\t\t},\n\t\ttake(key) {\n\t\t\tconst storageKey = prefix + key;\n\t\t\tconst value = storage.getItem(storageKey);\n\t\t\tif (value !== null) {\n\t\t\t\tstorage.removeItem(storageKey);\n\t\t\t\tlocalStorageEvent.next({\n\t\t\t\t\torigin: StorageChangeEventOrigin.Local,\n\t\t\t\t\tkey,\n\t\t\t\t\toldValue: value,\n\t\t\t\t\tnewValue: null,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn value;\n\t\t},\n\t\tremove(key) {\n\t\t\tconst storageKey = prefix + key;\n\t\t\tconst oldValue = storage.getItem(storageKey);\n\t\t\tstorage.removeItem(storageKey);\n\t\t\tif (oldValue !== null) {\n\t\t\t\tlocalStorageEvent.next({\n\t\t\t\t\torigin: StorageChangeEventOrigin.Local,\n\t\t\t\t\tkey,\n\t\t\t\t\toldValue,\n\t\t\t\t\tnewValue: null,\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t};\n}\n\nexport function createPersistentStorageForNativeWeb(\n\toptions: Omit<StorageForNativeWebCreateOptions, \"validatorKey\"> &\n\t\tWithTraitInputValidator<\n\t\t\tPick<EnvironmentValidators, \"persistentStorage\" | \"sessionStorage\">\n\t\t>,\n): SyncStorageTrait | null {\n\treturn createStorageForNativeWeb({\n\t\t...options,\n\t\tvalidatorKey: \"persistentStorage\",\n\t});\n}\n\nexport function createSessionStorageForNativeWeb(\n\toptions: Omit<StorageForNativeWebCreateOptions, \"validatorKey\"> &\n\t\tWithTraitInputValidator<\n\t\t\tPick<EnvironmentValidators, \"persistentStorage\" | \"sessionStorage\">\n\t\t>,\n): SyncStorageTrait | null {\n\treturn createStorageForNativeWeb({\n\t\t...options,\n\t\tvalidatorKey: \"sessionStorage\",\n\t});\n}\n","import {\n\ttype CreateFoundationEnvironmentOptions,\n\tcreateFoundationEnvironment,\n} from \"../environment/create\";\nimport { type FoundationEnvironment } from \"../environment/types\";\nimport {\n\tcreateProviderIfTokenMissing,\n\tgetSecuritydeptProviderToken,\n\tnotMissingProvider,\n\ttype SecuritydeptDependencyDescriptor,\n\ttype SecuritydeptFactoryProvider,\n\ttype SecuritydeptProvider,\n\ttype SecuritydeptValueProvider,\n} from \"../injection\";\nimport { PAGE_LIFECYCLE_TRAIT_TOKEN } from \"../page\";\nimport { POPUP_TRAIT_TOKEN } from \"../popup\";\nimport { ROUTER_TRAIT_TOKEN, type RouterTrait } from \"../router\";\nimport { TIME_TRAIT_TOKEN, type TimeTrait } from \"../scheduling/types\";\nimport {\n\tPERSISTENT_STORAGE_TRAIT_TOKEN,\n\tSESSION_STORAGE_TRAIT_TOKEN,\n} from \"../storage/types\";\nimport {\n\tcreatePageLifecycleForNativeWeb,\n\ttype PageLifecycleForNativeWebCreateOptions,\n} from \"./page\";\nimport {\n\tcreatePopupForNativeWeb,\n\ttype PopupForNativeWebCreateOptions,\n} from \"./popup\";\nimport {\n\tcreateRouterForNativeWeb,\n\ttype RouterForNativeWebCreateOptions,\n} from \"./router\";\nimport {\n\tcreatePersistentStorageForNativeWeb,\n\tcreateSessionStorageForNativeWeb,\n\ttype StorageForNativeWebCreateOptions,\n} from \"./storage\";\n\nexport { type FoundationEnvironment } from \"../environment/types\";\n\nexport interface NativeWebEnvironment extends FoundationEnvironment {\n\trouter: RouterTrait;\n}\n\nexport interface CreateEnvironmentForNativeWebOptions\n\textends CreateFoundationEnvironmentOptions {\n\trouterForNativeWebCreateOptions?: RouterForNativeWebCreateOptions;\n\tpageLifecycleForNativeWebCreateOptions?: PageLifecycleForNativeWebCreateOptions;\n\tpopupForNativeWebCreateOptions?: PopupForNativeWebCreateOptions;\n\tpersistentStorageForNativeWebCreateOptions?: Omit<\n\t\tStorageForNativeWebCreateOptions,\n\t\t\"validatorKey\"\n\t>;\n\tsessionStorageForNativeWebCreateOptions?: Omit<\n\t\tStorageForNativeWebCreateOptions,\n\t\t\"validatorKey\"\n\t>;\n}\n\nexport function createEnvironmentForNativeWeb(\n\toptions: CreateEnvironmentForNativeWebOptions,\n): NativeWebEnvironment {\n\tconst userProviders = options.providers ?? [];\n\tconst externalProviderTokens = new Set(\n\t\tuserProviders.map((provider) => getSecuritydeptProviderToken(provider)),\n\t);\n\tconst providers = [\n\t\t...createNativeWebTraitProviders(options, externalProviderTokens),\n\t\t...userProviders,\n\t];\n\treturn createFoundationEnvironment({\n\t\tproviders,\n\t\ttransport: options.transport,\n\t\ttransportForStdFetchCreateOptions:\n\t\t\toptions.transportForStdFetchCreateOptions,\n\t\ttime: options.time,\n\t\ttimeForStdCreateOptions: options.timeForStdCreateOptions,\n\t\trealmStorage: options.realmStorage,\n\t\tidleCallback: options.idleCallback,\n\t\tspan: options.span,\n\t\tspanCreateOptions: options.spanCreateOptions,\n\t\ttracing: options.tracing,\n\t\ttracingCreateOptions: options.tracingCreateOptions,\n\t\tvalidators: options.validators,\n\t}) as NativeWebEnvironment;\n}\n\nfunction createNativeWebTraitProviders(\n\toptions: CreateEnvironmentForNativeWebOptions,\n\texternalProviderTokens: ReadonlySet<\n\t\tSecuritydeptValueProvider<unknown>[\"provide\"]\n\t>,\n): SecuritydeptProvider[] {\n\treturn [\n\t\tcreateProviderIfTokenMissing(\n\t\t\texternalProviderTokens,\n\t\t\tROUTER_TRAIT_TOKEN,\n\t\t\t() =>\n\t\t\t\tcreateNativeWebTraitUnit({\n\t\t\t\t\tprovide: ROUTER_TRAIT_TOKEN,\n\t\t\t\t\tvalue: options.router,\n\t\t\t\t\tcreateValue: () =>\n\t\t\t\t\t\tcreateRouterForNativeWeb({\n\t\t\t\t\t\t\t...options.routerForNativeWebCreateOptions,\n\t\t\t\t\t\t\tvalidators: options.validators,\n\t\t\t\t\t\t}),\n\t\t\t\t}),\n\t\t),\n\t\tcreateProviderIfTokenMissing(\n\t\t\texternalProviderTokens,\n\t\t\tPAGE_LIFECYCLE_TRAIT_TOKEN,\n\t\t\t() =>\n\t\t\t\tcreateNativeWebTraitUnit({\n\t\t\t\t\tprovide: PAGE_LIFECYCLE_TRAIT_TOKEN,\n\t\t\t\t\tvalue: options.pageLifecycle,\n\t\t\t\t\tcreateValue: () =>\n\t\t\t\t\t\tcreatePageLifecycleForNativeWeb({\n\t\t\t\t\t\t\t...options.pageLifecycleForNativeWebCreateOptions,\n\t\t\t\t\t\t\tvalidators: options.validators,\n\t\t\t\t\t\t}),\n\t\t\t\t}),\n\t\t),\n\t\tcreateProviderIfTokenMissing(\n\t\t\texternalProviderTokens,\n\t\t\tPOPUP_TRAIT_TOKEN,\n\t\t\t() =>\n\t\t\t\tcreateNativeWebTraitUnit({\n\t\t\t\t\tprovide: POPUP_TRAIT_TOKEN,\n\t\t\t\t\tvalue: options.popup,\n\t\t\t\t\tcreateValue: (time: TimeTrait) =>\n\t\t\t\t\t\tcreatePopupForNativeWeb({\n\t\t\t\t\t\t\ttime,\n\t\t\t\t\t\t\t...options.popupForNativeWebCreateOptions,\n\t\t\t\t\t\t\tvalidators: options.validators,\n\t\t\t\t\t\t}),\n\t\t\t\t\tdeps: [TIME_TRAIT_TOKEN],\n\t\t\t\t}),\n\t\t),\n\t\tcreateProviderIfTokenMissing(\n\t\t\texternalProviderTokens,\n\t\t\tPERSISTENT_STORAGE_TRAIT_TOKEN,\n\t\t\t() =>\n\t\t\t\tcreateNativeWebTraitUnit({\n\t\t\t\t\tprovide: PERSISTENT_STORAGE_TRAIT_TOKEN,\n\t\t\t\t\tvalue: options.persistentStorage,\n\t\t\t\t\tcreateValue: () =>\n\t\t\t\t\t\tcreatePersistentStorageForNativeWeb({\n\t\t\t\t\t\t\t...options.persistentStorageForNativeWebCreateOptions,\n\t\t\t\t\t\t\tvalidators: options.validators,\n\t\t\t\t\t\t}),\n\t\t\t\t}),\n\t\t),\n\t\tcreateProviderIfTokenMissing(\n\t\t\texternalProviderTokens,\n\t\t\tSESSION_STORAGE_TRAIT_TOKEN,\n\t\t\t() =>\n\t\t\t\tcreateNativeWebTraitUnit({\n\t\t\t\t\tprovide: SESSION_STORAGE_TRAIT_TOKEN,\n\t\t\t\t\tvalue: options.sessionStorage,\n\t\t\t\t\tcreateValue: () =>\n\t\t\t\t\t\tcreateSessionStorageForNativeWeb({\n\t\t\t\t\t\t\t...options.sessionStorageForNativeWebCreateOptions,\n\t\t\t\t\t\t\tvalidators: options.validators,\n\t\t\t\t\t\t}),\n\t\t\t\t}),\n\t\t),\n\t].filter(notMissingProvider);\n}\n\nfunction createNativeWebTraitUnit<T>(options: {\n\tprovide: SecuritydeptValueProvider<T | null>[\"provide\"];\n\tvalue: T | null | undefined;\n\tdeps?: readonly SecuritydeptDependencyDescriptor<unknown>[];\n\tcreateValue(...deps: readonly unknown[]): T | null;\n}): SecuritydeptProvider {\n\tif (options.value !== undefined) {\n\t\treturn {\n\t\t\tprovide: options.provide,\n\t\t\tuseValue: options.value,\n\t\t} satisfies SecuritydeptValueProvider<T | null>;\n\t}\n\n\treturn {\n\t\tprovide: options.provide,\n\t\tuseFactory: options.createValue as (...deps: never[]) => T | null,\n\t\tdeps: options.deps,\n\t} satisfies SecuritydeptFactoryProvider<T | null>;\n}\n","import { filter, map } from \"rxjs\";\nimport { type EventStreamTrait } from \"../../events\";\nimport { RxEventStream } from \"../../rx\";\nimport {\n\tfromStorageEvent,\n\ttype StorageEventTarget,\n} from \"../events/from-storage\";\n\n// Cross-tab auth state sync — minimal baseline using storage events\n//\n// Provides a minimal, composable cross-tab sync mechanism for auth state.\n// When another tab writes to the auth persistence key (via localStorage),\n// this listener detects the change and notifies the current tab so it can\n// reconcile its in-memory state.\n//\n// This is intentionally thin — it adapts the browser `storage` event into an\n// event stream. The reconciliation subscriber is the adopter's responsibility\n// (e.g. re-read from persistence, compare with in-memory state, and update).\n//\n// Architecture boundary:\n// - This module does NOT own the persistence store.\n// - It only publishes cross-tab mutations as a stream.\n// - The adopter wires this to their auth state owner.\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Event emitted when a cross-tab storage change is detected for the watched key. */\nexport interface CrossTabSyncEvent {\n\t/** The new value written by the other tab, or null if the key was removed. */\n\tnewValue: string | null;\n\t/** The old value before the other tab's write. */\n\toldValue: string | null;\n}\n\n/** Options for {@link createCrossTabSync}. */\nexport interface CreateCrossTabSyncOptions {\n\t/** The localStorage key to watch for cross-tab changes. */\n\tkey: string;\n\n\tstorageEventTarget: StorageEventTarget;\n}\n\n// ---------------------------------------------------------------------------\n// Implementation\n// ---------------------------------------------------------------------------\n\n/**\n * Create a cross-tab sync listener for a specific localStorage key.\n *\n * The browser `storage` event fires on ALL tabs EXCEPT the one that made the\n * change. This makes it a natural primitive for cross-tab state notification.\n *\n * @example\n * ```ts\n * const subscription = createCrossTabSync({\n * key: \"auth:v1\",\n * storageEventTarget: window,\n * }).subscribe({\n * next: ({ newValue }) => {\n * if (newValue) {\n * // Another tab updated auth state — reconcile\n * client.restorePersistedState();\n * } else {\n * // Another tab cleared auth state — log out\n * controller.clearState({ persistPolicy: \"skip\" });\n * }\n * },\n * });\n * // Later:\n * subscription.unsubscribe();\n * ```\n */\nexport function createCrossTabSync(\n\toptions: CreateCrossTabSyncOptions,\n): EventStreamTrait<CrossTabSyncEvent> {\n\treturn RxEventStream.fromObservableInput(\n\t\tfromStorageEvent({\n\t\t\tstorageEventTarget: options.storageEventTarget,\n\t\t}),\n\t).pipe(\n\t\tfilter((storageEvent) => storageEvent.key === options.key),\n\t\tmap((storageEvent) => ({\n\t\t\tnewValue: storageEvent.newValue,\n\t\t\toldValue: storageEvent.oldValue,\n\t\t})),\n\t);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Bt as EnvironmentValidators, Hn as RouterTrait, Lt as CreateFoundationEnvironmentOptions, Mn as WithTraitInputValidator, Vt as FoundationEnvironment, ln as StorageTrait } from "../index-CbeZ3AfB.mjs";
|
|
2
|
+
import { o as RouterForNativeWebCreateOptions, u as PageLifecycleForNativeWebCreateOptions } from "../index-Bo1BtjZH.mjs";
|
|
3
|
+
//#region src/webext/router.d.ts
|
|
4
|
+
interface WebExtRouterBrowserLike {
|
|
5
|
+
runtime?: {
|
|
6
|
+
getURL(path: string): string;
|
|
7
|
+
};
|
|
8
|
+
tabs?: {
|
|
9
|
+
create?(options: {
|
|
10
|
+
url: string;
|
|
11
|
+
}): unknown;
|
|
12
|
+
update?(tabId: number, options: {
|
|
13
|
+
url: string;
|
|
14
|
+
}): unknown;
|
|
15
|
+
query?(options: {
|
|
16
|
+
active?: boolean;
|
|
17
|
+
currentWindow?: boolean;
|
|
18
|
+
}): unknown;
|
|
19
|
+
};
|
|
20
|
+
windows?: {
|
|
21
|
+
create?(options: {
|
|
22
|
+
url: string;
|
|
23
|
+
}): unknown;
|
|
24
|
+
getCurrent?(): unknown;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
interface RouterForWebExtCreateOptions {
|
|
28
|
+
browser?: WebExtRouterBrowserLike | null;
|
|
29
|
+
}
|
|
30
|
+
declare function createRouterForWebExt(options?: RouterForWebExtCreateOptions & WithTraitInputValidator<Pick<EnvironmentValidators, "router">>): RouterTrait | null;
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/webext/storage.d.ts
|
|
33
|
+
interface WebExtStorageAreaLike {
|
|
34
|
+
get(key: string): Promise<Record<string, unknown>> | Record<string, unknown>;
|
|
35
|
+
set(entries: Record<string, unknown>): Promise<void> | void;
|
|
36
|
+
remove(key: string): Promise<void> | void;
|
|
37
|
+
}
|
|
38
|
+
interface WebExtStorageBrowserLike {
|
|
39
|
+
storage?: {
|
|
40
|
+
local?: WebExtStorageAreaLike;
|
|
41
|
+
session?: WebExtStorageAreaLike;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
interface StorageForWebExtCreateOptions {
|
|
45
|
+
browser?: WebExtStorageBrowserLike | null;
|
|
46
|
+
storageArea?: WebExtStorageAreaLike | null;
|
|
47
|
+
prefix?: string;
|
|
48
|
+
validatorKey: "persistentStorage" | "sessionStorage";
|
|
49
|
+
}
|
|
50
|
+
declare function createStorageForWebExt(options: StorageForWebExtCreateOptions & WithTraitInputValidator<Pick<EnvironmentValidators, "persistentStorage" | "sessionStorage">>): StorageTrait | null;
|
|
51
|
+
declare function createPersistentStorageForWebExt(options?: Omit<StorageForWebExtCreateOptions, "validatorKey"> & WithTraitInputValidator<Pick<EnvironmentValidators, "persistentStorage" | "sessionStorage">>): StorageTrait | null;
|
|
52
|
+
declare function createSessionStorageForWebExt(options?: Omit<StorageForWebExtCreateOptions, "validatorKey"> & WithTraitInputValidator<Pick<EnvironmentValidators, "persistentStorage" | "sessionStorage">>): StorageTrait | null;
|
|
53
|
+
//#endregion
|
|
54
|
+
//#region src/webext/environment.d.ts
|
|
55
|
+
interface CreateEnvironmentForWebExtCoreOptions extends CreateFoundationEnvironmentOptions {
|
|
56
|
+
routerForWebExtCreateOptions?: RouterForWebExtCreateOptions;
|
|
57
|
+
persistentStorageForWebExtCreateOptions?: Omit<StorageForWebExtCreateOptions, "validatorKey">;
|
|
58
|
+
sessionStorageForWebExtCreateOptions?: Omit<StorageForWebExtCreateOptions, "validatorKey">;
|
|
59
|
+
}
|
|
60
|
+
interface CreateEnvironmentForWebExtBackgroundScriptOptions extends CreateEnvironmentForWebExtCoreOptions {}
|
|
61
|
+
interface CreateEnvironmentForWebExtUIOptions extends CreateEnvironmentForWebExtCoreOptions {
|
|
62
|
+
routerForNativeWebCreateOptions?: RouterForNativeWebCreateOptions;
|
|
63
|
+
pageLifecycleForNativeWebCreateOptions?: PageLifecycleForNativeWebCreateOptions;
|
|
64
|
+
}
|
|
65
|
+
interface WebExtCoreEnvironment extends FoundationEnvironment {}
|
|
66
|
+
interface WebExtBackgroundEnvironment extends WebExtCoreEnvironment {}
|
|
67
|
+
interface WebExtUIEnvironment extends WebExtCoreEnvironment {}
|
|
68
|
+
declare function createEnvironmentForWebExtCore(options: CreateEnvironmentForWebExtCoreOptions): WebExtCoreEnvironment;
|
|
69
|
+
declare function createEnvironmentForWebExtBackgroundScript(options: CreateEnvironmentForWebExtBackgroundScriptOptions): WebExtBackgroundEnvironment;
|
|
70
|
+
declare function createEnvironmentForWebExtUI(options: CreateEnvironmentForWebExtUIOptions): WebExtUIEnvironment;
|
|
71
|
+
//#endregion
|
|
72
|
+
export { type CreateEnvironmentForWebExtBackgroundScriptOptions, type CreateEnvironmentForWebExtCoreOptions, type CreateEnvironmentForWebExtUIOptions, type RouterForWebExtCreateOptions, type StorageForWebExtCreateOptions, type WebExtBackgroundEnvironment, type WebExtCoreEnvironment, type WebExtRouterBrowserLike, type WebExtStorageAreaLike, type WebExtStorageBrowserLike, type WebExtUIEnvironment, createEnvironmentForWebExtBackgroundScript, createEnvironmentForWebExtCore, createEnvironmentForWebExtUI, createPersistentStorageForWebExt, createRouterForWebExt, createSessionStorageForWebExt, createStorageForWebExt };
|
|
73
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { H as ClientError, U as ClientErrorKind } from "../rx-DM6Ouv-m.mjs";
|
|
2
|
+
import { $ as notMissingProvider, E as ROUTER_TRAIT_TOKEN, H as PAGE_LIFECYCLE_TRAIT_TOKEN, Q as getSecuritydeptProviderToken, R as throwValidationClientError, V as validateWithSchemaSync, Z as createProviderIfTokenMissing, d as SESSION_STORAGE_TRAIT_TOKEN, l as PERSISTENT_STORAGE_TRAIT_TOKEN, t as createFoundationEnvironment, z as validateTraitInput } from "../create-i5VyYgN6.mjs";
|
|
3
|
+
import { a as createPageLifecycleForNativeWeb, i as createRouterForNativeWeb } from "../router-at5bTdJQ.mjs";
|
|
4
|
+
import { type } from "arktype";
|
|
5
|
+
//#region src/webext/router.ts
|
|
6
|
+
const WebExtRuntimeRouterLikeSchema = type({ getURL: "Function" });
|
|
7
|
+
const WebExtTabsRouterLikeSchema = type({ create: "Function" });
|
|
8
|
+
const WebExtWindowsRouterLikeSchema = type({ create: "Function" });
|
|
9
|
+
const RouterForWebExtCreateOptionsSchema = type({ browser: {
|
|
10
|
+
runtime: WebExtRuntimeRouterLikeSchema.optional(),
|
|
11
|
+
tabs: WebExtTabsRouterLikeSchema.optional(),
|
|
12
|
+
windows: WebExtWindowsRouterLikeSchema.optional()
|
|
13
|
+
} });
|
|
14
|
+
const RouterForWebExtUnavailableProbeSchema = type({ browser: "null | undefined" });
|
|
15
|
+
function createRouterForWebExt(options = {}) {
|
|
16
|
+
const { validators, ...createOptions } = options;
|
|
17
|
+
const global = globalThis;
|
|
18
|
+
const browser = Object.hasOwn(options, "browser") ? options.browser ?? null : global.browser ?? null;
|
|
19
|
+
const resolvedCreateOptions = {
|
|
20
|
+
...createOptions,
|
|
21
|
+
browser
|
|
22
|
+
};
|
|
23
|
+
if (validateWithSchemaSync(RouterForWebExtUnavailableProbeSchema, resolvedCreateOptions).success || !resolvedCreateOptions.browser?.tabs && !resolvedCreateOptions.browser?.windows) return null;
|
|
24
|
+
validateTraitInput({
|
|
25
|
+
value: resolvedCreateOptions,
|
|
26
|
+
bundledSchema: RouterForWebExtCreateOptionsSchema,
|
|
27
|
+
validator: validators?.router,
|
|
28
|
+
onInvalid: (failure) => throwValidationClientError({
|
|
29
|
+
code: "webext.router.invalid_background_router_options",
|
|
30
|
+
source: "webext",
|
|
31
|
+
messagePrefix: "createRouterForWebExt could not validate routerForWebExtCreateOptions",
|
|
32
|
+
failure
|
|
33
|
+
})
|
|
34
|
+
});
|
|
35
|
+
const resolvedBrowser = resolvedCreateOptions.browser;
|
|
36
|
+
return {
|
|
37
|
+
currentUrl() {
|
|
38
|
+
return null;
|
|
39
|
+
},
|
|
40
|
+
async navigate(request) {
|
|
41
|
+
const url = request.url.toString();
|
|
42
|
+
if (resolvedBrowser.tabs?.create) {
|
|
43
|
+
await resolvedBrowser.tabs.create({ url });
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (resolvedBrowser.windows?.create) {
|
|
47
|
+
await resolvedBrowser.windows.create({ url });
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
throw new ClientError({
|
|
51
|
+
kind: ClientErrorKind.Configuration,
|
|
52
|
+
code: "webext.router.navigation_unavailable",
|
|
53
|
+
message: "Web extension router cannot open the requested URL",
|
|
54
|
+
source: "webext.router"
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/webext/storage.ts
|
|
61
|
+
const WebExtStorageAreaLikeSchema = type({
|
|
62
|
+
get: "Function",
|
|
63
|
+
set: "Function",
|
|
64
|
+
remove: "Function"
|
|
65
|
+
});
|
|
66
|
+
const StorageForWebExtCreateOptionsSchema = type({
|
|
67
|
+
storageArea: WebExtStorageAreaLikeSchema,
|
|
68
|
+
prefix: "string | undefined",
|
|
69
|
+
validatorKey: "'persistentStorage' | 'sessionStorage'"
|
|
70
|
+
});
|
|
71
|
+
const StorageForWebExtUnavailableProbeSchema = type({
|
|
72
|
+
storageArea: "null | undefined",
|
|
73
|
+
prefix: "string | undefined",
|
|
74
|
+
validatorKey: "'persistentStorage' | 'sessionStorage'"
|
|
75
|
+
});
|
|
76
|
+
const DEFAULT_PERSISTENT_STORAGE_PREFIX = "securitydept.webext.client:";
|
|
77
|
+
const DEFAULT_SESSION_STORAGE_PREFIX = "securitydept.webext.client:";
|
|
78
|
+
function createStorageForWebExt(options) {
|
|
79
|
+
const { validators, browser: _browser, ...createOptions } = options;
|
|
80
|
+
const global = globalThis;
|
|
81
|
+
const browser = Object.hasOwn(options, "browser") ? options.browser ?? null : global.browser ?? null;
|
|
82
|
+
const storageArea = Object.hasOwn(options, "storageArea") ? options.storageArea ?? null : options.validatorKey === "persistentStorage" ? browser?.storage?.local ?? null : browser?.storage?.session ?? null;
|
|
83
|
+
const resolvedCreateOptions = {
|
|
84
|
+
...createOptions,
|
|
85
|
+
storageArea,
|
|
86
|
+
prefix: createOptions.prefix ?? (options.validatorKey === "persistentStorage" ? DEFAULT_PERSISTENT_STORAGE_PREFIX : DEFAULT_SESSION_STORAGE_PREFIX)
|
|
87
|
+
};
|
|
88
|
+
if (validateWithSchemaSync(StorageForWebExtUnavailableProbeSchema, resolvedCreateOptions).success) return null;
|
|
89
|
+
validateTraitInput({
|
|
90
|
+
value: resolvedCreateOptions,
|
|
91
|
+
bundledSchema: StorageForWebExtCreateOptionsSchema,
|
|
92
|
+
validator: validators?.[options.validatorKey],
|
|
93
|
+
onInvalid: (failure) => throwValidationClientError({
|
|
94
|
+
code: "webext.storage.invalid_storage_options",
|
|
95
|
+
source: "webext",
|
|
96
|
+
messagePrefix: `createStorageForWebExt could not validate ${options.validatorKey}ForWebExtCreateOptions`,
|
|
97
|
+
failure
|
|
98
|
+
})
|
|
99
|
+
});
|
|
100
|
+
const storage = resolvedCreateOptions.storageArea;
|
|
101
|
+
const prefix = resolvedCreateOptions.prefix;
|
|
102
|
+
return {
|
|
103
|
+
async get(key) {
|
|
104
|
+
const value = (await storage.get(prefix + key))?.[prefix + key];
|
|
105
|
+
return typeof value === "string" ? value : null;
|
|
106
|
+
},
|
|
107
|
+
async set(key, value) {
|
|
108
|
+
await storage.set({ [prefix + key]: value });
|
|
109
|
+
},
|
|
110
|
+
async take(key) {
|
|
111
|
+
const storageKey = prefix + key;
|
|
112
|
+
const value = (await storage.get(storageKey))?.[storageKey];
|
|
113
|
+
if (typeof value === "string") {
|
|
114
|
+
await storage.remove(storageKey);
|
|
115
|
+
return value;
|
|
116
|
+
}
|
|
117
|
+
return null;
|
|
118
|
+
},
|
|
119
|
+
async remove(key) {
|
|
120
|
+
await storage.remove(prefix + key);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function createPersistentStorageForWebExt(options = {}) {
|
|
125
|
+
return createStorageForWebExt({
|
|
126
|
+
...options,
|
|
127
|
+
validatorKey: "persistentStorage"
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
function createSessionStorageForWebExt(options = {}) {
|
|
131
|
+
return createStorageForWebExt({
|
|
132
|
+
...options,
|
|
133
|
+
validatorKey: "sessionStorage"
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
//#endregion
|
|
137
|
+
//#region src/webext/environment.ts
|
|
138
|
+
function createEnvironmentForWebExtCore(options) {
|
|
139
|
+
const userProviders = options.providers ?? [];
|
|
140
|
+
const externalProviderTokens = new Set(userProviders.map((provider) => getSecuritydeptProviderToken(provider)));
|
|
141
|
+
return createFoundationEnvironment({
|
|
142
|
+
providers: [...createWebExtTraitProviders(options, externalProviderTokens), ...userProviders],
|
|
143
|
+
transport: options.transport,
|
|
144
|
+
transportForStdFetchCreateOptions: options.transportForStdFetchCreateOptions,
|
|
145
|
+
time: options.time,
|
|
146
|
+
timeForStdCreateOptions: options.timeForStdCreateOptions,
|
|
147
|
+
idleCallback: options.idleCallback,
|
|
148
|
+
span: options.span,
|
|
149
|
+
spanCreateOptions: options.spanCreateOptions,
|
|
150
|
+
tracing: options.tracing,
|
|
151
|
+
tracingCreateOptions: options.tracingCreateOptions,
|
|
152
|
+
validators: options.validators
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
function createEnvironmentForWebExtBackgroundScript(options) {
|
|
156
|
+
return createEnvironmentForWebExtCore(options);
|
|
157
|
+
}
|
|
158
|
+
function createEnvironmentForWebExtUI(options) {
|
|
159
|
+
const userProviders = options.providers ?? [];
|
|
160
|
+
const userProviderTokens = new Set(userProviders.map((provider) => getSecuritydeptProviderToken(provider)));
|
|
161
|
+
const uiProviders = createWebExtUITraitProviders(options, userProviderTokens);
|
|
162
|
+
const externalProviderTokens = /* @__PURE__ */ new Set([...userProviderTokens, ...uiProviders.map((provider) => getSecuritydeptProviderToken(provider))]);
|
|
163
|
+
return createFoundationEnvironment({
|
|
164
|
+
...options,
|
|
165
|
+
providers: [
|
|
166
|
+
...createWebExtTraitProviders(options, externalProviderTokens),
|
|
167
|
+
...uiProviders,
|
|
168
|
+
...userProviders
|
|
169
|
+
]
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
function createWebExtTraitProviders(options, externalProviderTokens) {
|
|
173
|
+
return [
|
|
174
|
+
createProviderIfTokenMissing(externalProviderTokens, ROUTER_TRAIT_TOKEN, () => createWebExtTraitUnit({
|
|
175
|
+
provide: ROUTER_TRAIT_TOKEN,
|
|
176
|
+
value: options.router,
|
|
177
|
+
createValue: () => createRouterForWebExt({
|
|
178
|
+
...options.routerForWebExtCreateOptions,
|
|
179
|
+
validators: options.validators
|
|
180
|
+
})
|
|
181
|
+
})),
|
|
182
|
+
createProviderIfTokenMissing(externalProviderTokens, PERSISTENT_STORAGE_TRAIT_TOKEN, () => createWebExtTraitUnit({
|
|
183
|
+
provide: PERSISTENT_STORAGE_TRAIT_TOKEN,
|
|
184
|
+
value: options.persistentStorage,
|
|
185
|
+
createValue: () => createPersistentStorageForWebExt({
|
|
186
|
+
...options.persistentStorageForWebExtCreateOptions,
|
|
187
|
+
validators: options.validators
|
|
188
|
+
})
|
|
189
|
+
})),
|
|
190
|
+
createProviderIfTokenMissing(externalProviderTokens, SESSION_STORAGE_TRAIT_TOKEN, () => createWebExtTraitUnit({
|
|
191
|
+
provide: SESSION_STORAGE_TRAIT_TOKEN,
|
|
192
|
+
value: options.sessionStorage,
|
|
193
|
+
createValue: () => createSessionStorageForWebExt({
|
|
194
|
+
...options.sessionStorageForWebExtCreateOptions,
|
|
195
|
+
validators: options.validators
|
|
196
|
+
})
|
|
197
|
+
}))
|
|
198
|
+
].filter(notMissingProvider);
|
|
199
|
+
}
|
|
200
|
+
function createWebExtUITraitProviders(options, externalProviderTokens) {
|
|
201
|
+
return [createProviderIfTokenMissing(externalProviderTokens, ROUTER_TRAIT_TOKEN, () => createWebExtTraitUnit({
|
|
202
|
+
provide: ROUTER_TRAIT_TOKEN,
|
|
203
|
+
value: options.router,
|
|
204
|
+
createValue: () => createRouterForNativeWeb({
|
|
205
|
+
...options.routerForNativeWebCreateOptions,
|
|
206
|
+
validators: options.validators
|
|
207
|
+
})
|
|
208
|
+
})), createProviderIfTokenMissing(externalProviderTokens, PAGE_LIFECYCLE_TRAIT_TOKEN, () => createWebExtTraitUnit({
|
|
209
|
+
provide: PAGE_LIFECYCLE_TRAIT_TOKEN,
|
|
210
|
+
value: options.pageLifecycle,
|
|
211
|
+
createValue: () => createPageLifecycleForNativeWeb({
|
|
212
|
+
...options.pageLifecycleForNativeWebCreateOptions,
|
|
213
|
+
validators: options.validators
|
|
214
|
+
})
|
|
215
|
+
}))].filter(notMissingProvider);
|
|
216
|
+
}
|
|
217
|
+
function createWebExtTraitUnit(options) {
|
|
218
|
+
if (options.value !== void 0) return {
|
|
219
|
+
provide: options.provide,
|
|
220
|
+
useValue: options.value
|
|
221
|
+
};
|
|
222
|
+
return {
|
|
223
|
+
provide: options.provide,
|
|
224
|
+
useFactory: options.createValue,
|
|
225
|
+
deps: options.deps
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
//#endregion
|
|
229
|
+
export { createEnvironmentForWebExtBackgroundScript, createEnvironmentForWebExtCore, createEnvironmentForWebExtUI, createPersistentStorageForWebExt, createRouterForWebExt, createSessionStorageForWebExt, createStorageForWebExt };
|
|
230
|
+
|
|
231
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["defineType","defineType"],"sources":["../../src/webext/router.ts","../../src/webext/storage.ts","../../src/webext/environment.ts"],"sourcesContent":["import { type as defineType } from \"arktype\";\nimport { type EnvironmentValidators } from \"../environment/types\";\nimport { ClientError, ClientErrorKind } from \"../errors\";\nimport { type RouterNavigationRequest, type RouterTrait } from \"../router\";\nimport { type UriReferenceString } from \"../struct/uri-string\";\nimport {\n\tthrowValidationClientError,\n\tvalidateTraitInput,\n\tvalidateWithSchemaSync,\n\ttype WithTraitInputValidator,\n} from \"../validation\";\n\nexport interface WebExtRouterBrowserLike {\n\truntime?: {\n\t\tgetURL(path: string): string;\n\t};\n\ttabs?: {\n\t\tcreate?(options: { url: string }): unknown;\n\t\tupdate?(tabId: number, options: { url: string }): unknown;\n\t\tquery?(options: { active?: boolean; currentWindow?: boolean }): unknown;\n\t};\n\twindows?: {\n\t\tcreate?(options: { url: string }): unknown;\n\t\tgetCurrent?(): unknown;\n\t};\n}\n\nexport interface RouterForWebExtCreateOptions {\n\tbrowser?: WebExtRouterBrowserLike | null;\n}\n\nconst WebExtRuntimeRouterLikeSchema = defineType({\n\tgetURL: \"Function\",\n});\n\nconst WebExtTabsRouterLikeSchema = defineType({\n\tcreate: \"Function\",\n});\n\nconst WebExtWindowsRouterLikeSchema = defineType({\n\tcreate: \"Function\",\n});\n\nconst RouterForWebExtCreateOptionsSchema = defineType({\n\tbrowser: {\n\t\truntime: WebExtRuntimeRouterLikeSchema.optional(),\n\t\ttabs: WebExtTabsRouterLikeSchema.optional(),\n\t\twindows: WebExtWindowsRouterLikeSchema.optional(),\n\t},\n});\n\nconst RouterForWebExtUnavailableProbeSchema = defineType({\n\tbrowser: \"null | undefined\",\n});\n\nexport function createRouterForWebExt(\n\toptions: RouterForWebExtCreateOptions &\n\t\tWithTraitInputValidator<Pick<EnvironmentValidators, \"router\">> = {},\n): RouterTrait | null {\n\tconst { validators, ...createOptions } = options;\n\tconst global = globalThis as { browser?: WebExtRouterBrowserLike };\n\tconst browser = Object.hasOwn(options, \"browser\")\n\t\t? (options.browser ?? null)\n\t\t: (global.browser ?? null);\n\tconst resolvedCreateOptions = {\n\t\t...createOptions,\n\t\tbrowser,\n\t};\n\tconst unavailableProbeResult = validateWithSchemaSync(\n\t\tRouterForWebExtUnavailableProbeSchema,\n\t\tresolvedCreateOptions,\n\t);\n\tif (\n\t\tunavailableProbeResult.success ||\n\t\t(!resolvedCreateOptions.browser?.tabs &&\n\t\t\t!resolvedCreateOptions.browser?.windows)\n\t) {\n\t\treturn null;\n\t}\n\tvalidateTraitInput({\n\t\tvalue: resolvedCreateOptions,\n\t\tbundledSchema: RouterForWebExtCreateOptionsSchema,\n\t\tvalidator: validators?.router,\n\t\tonInvalid: (failure) =>\n\t\t\tthrowValidationClientError({\n\t\t\t\tcode: \"webext.router.invalid_background_router_options\",\n\t\t\t\tsource: \"webext\",\n\t\t\t\tmessagePrefix:\n\t\t\t\t\t\"createRouterForWebExt could not validate routerForWebExtCreateOptions\",\n\t\t\t\tfailure,\n\t\t\t}),\n\t});\n\tconst resolvedBrowser =\n\t\tresolvedCreateOptions.browser as WebExtRouterBrowserLike;\n\n\tconst router: RouterTrait = {\n\t\tcurrentUrl(): UriReferenceString | null {\n\t\t\treturn null;\n\t\t},\n\t\tasync navigate(request: RouterNavigationRequest) {\n\t\t\tconst url = request.url.toString();\n\t\t\tif (resolvedBrowser.tabs?.create) {\n\t\t\t\tawait resolvedBrowser.tabs.create({ url });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (resolvedBrowser.windows?.create) {\n\t\t\t\tawait resolvedBrowser.windows.create({ url });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow new ClientError({\n\t\t\t\tkind: ClientErrorKind.Configuration,\n\t\t\t\tcode: \"webext.router.navigation_unavailable\",\n\t\t\t\tmessage: \"Web extension router cannot open the requested URL\",\n\t\t\t\tsource: \"webext.router\",\n\t\t\t});\n\t\t},\n\t};\n\treturn router;\n}\n","import { type as defineType } from \"arktype\";\nimport { type EnvironmentValidators } from \"../environment/types\";\nimport { type StorageTrait } from \"../storage/types\";\nimport {\n\tthrowValidationClientError,\n\tvalidateTraitInput,\n\tvalidateWithSchemaSync,\n\ttype WithTraitInputValidator,\n} from \"../validation\";\n\nexport interface WebExtStorageAreaLike {\n\tget(key: string): Promise<Record<string, unknown>> | Record<string, unknown>;\n\tset(entries: Record<string, unknown>): Promise<void> | void;\n\tremove(key: string): Promise<void> | void;\n}\n\nexport interface WebExtStorageBrowserLike {\n\tstorage?: {\n\t\tlocal?: WebExtStorageAreaLike;\n\t\tsession?: WebExtStorageAreaLike;\n\t};\n}\n\nexport interface StorageForWebExtCreateOptions {\n\tbrowser?: WebExtStorageBrowserLike | null;\n\tstorageArea?: WebExtStorageAreaLike | null;\n\tprefix?: string;\n\tvalidatorKey: \"persistentStorage\" | \"sessionStorage\";\n}\n\nconst WebExtStorageAreaLikeSchema = defineType({\n\tget: \"Function\",\n\tset: \"Function\",\n\tremove: \"Function\",\n});\n\nconst StorageForWebExtCreateOptionsSchema = defineType({\n\tstorageArea: WebExtStorageAreaLikeSchema,\n\tprefix: \"string | undefined\",\n\tvalidatorKey: \"'persistentStorage' | 'sessionStorage'\",\n});\n\nconst StorageForWebExtUnavailableProbeSchema = defineType({\n\tstorageArea: \"null | undefined\",\n\tprefix: \"string | undefined\",\n\tvalidatorKey: \"'persistentStorage' | 'sessionStorage'\",\n});\n\nconst DEFAULT_PERSISTENT_STORAGE_PREFIX = \"securitydept.webext.client:\";\nconst DEFAULT_SESSION_STORAGE_PREFIX = \"securitydept.webext.client:\";\n\nexport function createStorageForWebExt(\n\toptions: StorageForWebExtCreateOptions &\n\t\tWithTraitInputValidator<\n\t\t\tPick<EnvironmentValidators, \"persistentStorage\" | \"sessionStorage\">\n\t\t>,\n): StorageTrait | null {\n\tconst { validators, browser: _browser, ...createOptions } = options;\n\tconst global = globalThis as { browser?: WebExtStorageBrowserLike };\n\tconst browser = Object.hasOwn(options, \"browser\")\n\t\t? (options.browser ?? null)\n\t\t: (global.browser ?? null);\n\tconst storageArea = Object.hasOwn(options, \"storageArea\")\n\t\t? (options.storageArea ?? null)\n\t\t: options.validatorKey === \"persistentStorage\"\n\t\t\t? (browser?.storage?.local ?? null)\n\t\t\t: (browser?.storage?.session ?? null);\n\tconst resolvedCreateOptions = {\n\t\t...createOptions,\n\t\tstorageArea,\n\t\tprefix:\n\t\t\tcreateOptions.prefix ??\n\t\t\t(options.validatorKey === \"persistentStorage\"\n\t\t\t\t? DEFAULT_PERSISTENT_STORAGE_PREFIX\n\t\t\t\t: DEFAULT_SESSION_STORAGE_PREFIX),\n\t};\n\tconst unavailableProbeResult = validateWithSchemaSync(\n\t\tStorageForWebExtUnavailableProbeSchema,\n\t\tresolvedCreateOptions,\n\t);\n\tif (unavailableProbeResult.success) {\n\t\treturn null;\n\t}\n\tvalidateTraitInput({\n\t\tvalue: resolvedCreateOptions,\n\t\tbundledSchema: StorageForWebExtCreateOptionsSchema,\n\t\tvalidator: validators?.[options.validatorKey],\n\t\tonInvalid: (failure) =>\n\t\t\tthrowValidationClientError({\n\t\t\t\tcode: \"webext.storage.invalid_storage_options\",\n\t\t\t\tsource: \"webext\",\n\t\t\t\tmessagePrefix: `createStorageForWebExt could not validate ${options.validatorKey}ForWebExtCreateOptions`,\n\t\t\t\tfailure,\n\t\t\t}),\n\t});\n\tconst storage = resolvedCreateOptions.storageArea as WebExtStorageAreaLike;\n\tconst prefix = resolvedCreateOptions.prefix;\n\n\treturn {\n\t\tasync get(key) {\n\t\t\tconst result = await storage.get(prefix + key);\n\t\t\tconst value = result?.[prefix + key];\n\t\t\treturn typeof value === \"string\" ? value : null;\n\t\t},\n\t\tasync set(key, value) {\n\t\t\tawait storage.set({ [prefix + key]: value });\n\t\t},\n\t\tasync take(key) {\n\t\t\tconst storageKey = prefix + key;\n\t\t\tconst result = await storage.get(storageKey);\n\t\t\tconst value = result?.[storageKey];\n\t\t\tif (typeof value === \"string\") {\n\t\t\t\tawait storage.remove(storageKey);\n\t\t\t\treturn value;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\tasync remove(key) {\n\t\t\tawait storage.remove(prefix + key);\n\t\t},\n\t};\n}\n\nexport function createPersistentStorageForWebExt(\n\toptions: Omit<StorageForWebExtCreateOptions, \"validatorKey\"> &\n\t\tWithTraitInputValidator<\n\t\t\tPick<EnvironmentValidators, \"persistentStorage\" | \"sessionStorage\">\n\t\t> = {},\n): StorageTrait | null {\n\treturn createStorageForWebExt({\n\t\t...options,\n\t\tvalidatorKey: \"persistentStorage\",\n\t});\n}\n\nexport function createSessionStorageForWebExt(\n\toptions: Omit<StorageForWebExtCreateOptions, \"validatorKey\"> &\n\t\tWithTraitInputValidator<\n\t\t\tPick<EnvironmentValidators, \"persistentStorage\" | \"sessionStorage\">\n\t\t> = {},\n): StorageTrait | null {\n\treturn createStorageForWebExt({\n\t\t...options,\n\t\tvalidatorKey: \"sessionStorage\",\n\t});\n}\n","import {\n\ttype CreateFoundationEnvironmentOptions,\n\tcreateFoundationEnvironment,\n} from \"../environment/create\";\nimport { type FoundationEnvironment } from \"../environment/types\";\nimport {\n\tcreateProviderIfTokenMissing,\n\tgetSecuritydeptProviderToken,\n\tnotMissingProvider,\n\ttype SecuritydeptDependencyDescriptor,\n\ttype SecuritydeptFactoryProvider,\n\ttype SecuritydeptProvider,\n\ttype SecuritydeptValueProvider,\n} from \"../injection\";\nimport { PAGE_LIFECYCLE_TRAIT_TOKEN } from \"../page\";\nimport { ROUTER_TRAIT_TOKEN } from \"../router\";\nimport {\n\tPERSISTENT_STORAGE_TRAIT_TOKEN,\n\tSESSION_STORAGE_TRAIT_TOKEN,\n} from \"../storage/types\";\nimport {\n\tcreatePageLifecycleForNativeWeb,\n\ttype PageLifecycleForNativeWebCreateOptions,\n} from \"../web/page\";\nimport {\n\tcreateRouterForNativeWeb,\n\ttype RouterForNativeWebCreateOptions,\n} from \"../web/router\";\nimport {\n\tcreateRouterForWebExt,\n\ttype RouterForWebExtCreateOptions,\n} from \"./router\";\nimport {\n\tcreatePersistentStorageForWebExt,\n\tcreateSessionStorageForWebExt,\n\ttype StorageForWebExtCreateOptions,\n} from \"./storage\";\n\nexport interface CreateEnvironmentForWebExtCoreOptions\n\textends CreateFoundationEnvironmentOptions {\n\trouterForWebExtCreateOptions?: RouterForWebExtCreateOptions;\n\tpersistentStorageForWebExtCreateOptions?: Omit<\n\t\tStorageForWebExtCreateOptions,\n\t\t\"validatorKey\"\n\t>;\n\tsessionStorageForWebExtCreateOptions?: Omit<\n\t\tStorageForWebExtCreateOptions,\n\t\t\"validatorKey\"\n\t>;\n}\n\nexport interface CreateEnvironmentForWebExtBackgroundScriptOptions\n\textends CreateEnvironmentForWebExtCoreOptions {}\n\nexport interface CreateEnvironmentForWebExtUIOptions\n\textends CreateEnvironmentForWebExtCoreOptions {\n\trouterForNativeWebCreateOptions?: RouterForNativeWebCreateOptions;\n\tpageLifecycleForNativeWebCreateOptions?: PageLifecycleForNativeWebCreateOptions;\n}\n\nexport interface WebExtCoreEnvironment extends FoundationEnvironment {}\n\nexport interface WebExtBackgroundEnvironment extends WebExtCoreEnvironment {}\n\nexport interface WebExtUIEnvironment extends WebExtCoreEnvironment {}\n\nexport function createEnvironmentForWebExtCore(\n\toptions: CreateEnvironmentForWebExtCoreOptions,\n): WebExtCoreEnvironment {\n\tconst userProviders = options.providers ?? [];\n\tconst externalProviderTokens = new Set(\n\t\tuserProviders.map((provider) => getSecuritydeptProviderToken(provider)),\n\t);\n\n\treturn createFoundationEnvironment({\n\t\tproviders: [\n\t\t\t...createWebExtTraitProviders(options, externalProviderTokens),\n\t\t\t...userProviders,\n\t\t],\n\t\ttransport: options.transport,\n\t\ttransportForStdFetchCreateOptions:\n\t\t\toptions.transportForStdFetchCreateOptions,\n\t\ttime: options.time,\n\t\ttimeForStdCreateOptions: options.timeForStdCreateOptions,\n\t\tidleCallback: options.idleCallback,\n\t\tspan: options.span,\n\t\tspanCreateOptions: options.spanCreateOptions,\n\t\ttracing: options.tracing,\n\t\ttracingCreateOptions: options.tracingCreateOptions,\n\t\tvalidators: options.validators,\n\t}) as WebExtCoreEnvironment;\n}\n\nexport function createEnvironmentForWebExtBackgroundScript(\n\toptions: CreateEnvironmentForWebExtBackgroundScriptOptions,\n): WebExtBackgroundEnvironment {\n\treturn createEnvironmentForWebExtCore(options) as WebExtBackgroundEnvironment;\n}\n\nexport function createEnvironmentForWebExtUI(\n\toptions: CreateEnvironmentForWebExtUIOptions,\n): WebExtUIEnvironment {\n\tconst userProviders = options.providers ?? [];\n\tconst userProviderTokens = new Set(\n\t\tuserProviders.map((provider) => getSecuritydeptProviderToken(provider)),\n\t);\n\tconst uiProviders = createWebExtUITraitProviders(options, userProviderTokens);\n\tconst externalProviderTokens = new Set([\n\t\t...userProviderTokens,\n\t\t...uiProviders.map((provider) => getSecuritydeptProviderToken(provider)),\n\t]);\n\n\treturn createFoundationEnvironment({\n\t\t...options,\n\t\tproviders: [\n\t\t\t...createWebExtTraitProviders(options, externalProviderTokens),\n\t\t\t...uiProviders,\n\t\t\t...userProviders,\n\t\t],\n\t}) as WebExtUIEnvironment;\n}\n\nfunction createWebExtTraitProviders(\n\toptions: CreateEnvironmentForWebExtCoreOptions,\n\texternalProviderTokens: ReadonlySet<\n\t\tSecuritydeptValueProvider<unknown>[\"provide\"]\n\t>,\n): SecuritydeptProvider[] {\n\treturn [\n\t\tcreateProviderIfTokenMissing(\n\t\t\texternalProviderTokens,\n\t\t\tROUTER_TRAIT_TOKEN,\n\t\t\t() =>\n\t\t\t\tcreateWebExtTraitUnit({\n\t\t\t\t\tprovide: ROUTER_TRAIT_TOKEN,\n\t\t\t\t\tvalue: options.router,\n\t\t\t\t\tcreateValue: () =>\n\t\t\t\t\t\tcreateRouterForWebExt({\n\t\t\t\t\t\t\t...options.routerForWebExtCreateOptions,\n\t\t\t\t\t\t\tvalidators: options.validators,\n\t\t\t\t\t\t}),\n\t\t\t\t}),\n\t\t),\n\t\tcreateProviderIfTokenMissing(\n\t\t\texternalProviderTokens,\n\t\t\tPERSISTENT_STORAGE_TRAIT_TOKEN,\n\t\t\t() =>\n\t\t\t\tcreateWebExtTraitUnit({\n\t\t\t\t\tprovide: PERSISTENT_STORAGE_TRAIT_TOKEN,\n\t\t\t\t\tvalue: options.persistentStorage,\n\t\t\t\t\tcreateValue: () =>\n\t\t\t\t\t\tcreatePersistentStorageForWebExt({\n\t\t\t\t\t\t\t...options.persistentStorageForWebExtCreateOptions,\n\t\t\t\t\t\t\tvalidators: options.validators,\n\t\t\t\t\t\t}),\n\t\t\t\t}),\n\t\t),\n\t\tcreateProviderIfTokenMissing(\n\t\t\texternalProviderTokens,\n\t\t\tSESSION_STORAGE_TRAIT_TOKEN,\n\t\t\t() =>\n\t\t\t\tcreateWebExtTraitUnit({\n\t\t\t\t\tprovide: SESSION_STORAGE_TRAIT_TOKEN,\n\t\t\t\t\tvalue: options.sessionStorage,\n\t\t\t\t\tcreateValue: () =>\n\t\t\t\t\t\tcreateSessionStorageForWebExt({\n\t\t\t\t\t\t\t...options.sessionStorageForWebExtCreateOptions,\n\t\t\t\t\t\t\tvalidators: options.validators,\n\t\t\t\t\t\t}),\n\t\t\t\t}),\n\t\t),\n\t].filter(notMissingProvider);\n}\n\nfunction createWebExtUITraitProviders(\n\toptions: CreateEnvironmentForWebExtUIOptions,\n\texternalProviderTokens: ReadonlySet<\n\t\tSecuritydeptValueProvider<unknown>[\"provide\"]\n\t>,\n): SecuritydeptProvider[] {\n\treturn [\n\t\tcreateProviderIfTokenMissing(\n\t\t\texternalProviderTokens,\n\t\t\tROUTER_TRAIT_TOKEN,\n\t\t\t() =>\n\t\t\t\tcreateWebExtTraitUnit({\n\t\t\t\t\tprovide: ROUTER_TRAIT_TOKEN,\n\t\t\t\t\tvalue: options.router,\n\t\t\t\t\tcreateValue: () =>\n\t\t\t\t\t\tcreateRouterForNativeWeb({\n\t\t\t\t\t\t\t...options.routerForNativeWebCreateOptions,\n\t\t\t\t\t\t\tvalidators: options.validators,\n\t\t\t\t\t\t}),\n\t\t\t\t}),\n\t\t),\n\t\tcreateProviderIfTokenMissing(\n\t\t\texternalProviderTokens,\n\t\t\tPAGE_LIFECYCLE_TRAIT_TOKEN,\n\t\t\t() =>\n\t\t\t\tcreateWebExtTraitUnit({\n\t\t\t\t\tprovide: PAGE_LIFECYCLE_TRAIT_TOKEN,\n\t\t\t\t\tvalue: options.pageLifecycle,\n\t\t\t\t\tcreateValue: () =>\n\t\t\t\t\t\tcreatePageLifecycleForNativeWeb({\n\t\t\t\t\t\t\t...options.pageLifecycleForNativeWebCreateOptions,\n\t\t\t\t\t\t\tvalidators: options.validators,\n\t\t\t\t\t\t}),\n\t\t\t\t}),\n\t\t),\n\t].filter(notMissingProvider);\n}\n\nfunction createWebExtTraitUnit<T>(options: {\n\tprovide: SecuritydeptValueProvider<T | null>[\"provide\"];\n\tvalue: T | null | undefined;\n\tdeps?: readonly SecuritydeptDependencyDescriptor<unknown>[];\n\tcreateValue(...deps: readonly unknown[]): T | null;\n}): SecuritydeptProvider {\n\tif (options.value !== undefined) {\n\t\treturn {\n\t\t\tprovide: options.provide,\n\t\t\tuseValue: options.value,\n\t\t} satisfies SecuritydeptValueProvider<T | null>;\n\t}\n\n\treturn {\n\t\tprovide: options.provide,\n\t\tuseFactory: options.createValue as (...deps: never[]) => T | null,\n\t\tdeps: options.deps,\n\t} satisfies SecuritydeptFactoryProvider<T | null>;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@securitydept/client",
|
|
3
|
-
"version": "0.3.0-beta.
|
|
3
|
+
"version": "0.3.0-beta.10",
|
|
4
4
|
"description": "Client of the SecurityDept TypeScript SDK, a layered authentication and authorization toolkit built as reusable Rust crates, a TypeScript client SDK workspace, and reference server/web apps.",
|
|
5
5
|
"author": "Zhou Yeheng <root@aitiotekt.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -32,40 +32,47 @@
|
|
|
32
32
|
"types": "./dist/index.d.mts",
|
|
33
33
|
"import": "./dist/index.mjs"
|
|
34
34
|
},
|
|
35
|
-
"./persistence": {
|
|
36
|
-
"types": "./dist/persistence/index.d.mts",
|
|
37
|
-
"import": "./dist/persistence/index.mjs"
|
|
38
|
-
},
|
|
39
|
-
"./persistence/web": {
|
|
40
|
-
"types": "./dist/persistence/web/index.d.mts",
|
|
41
|
-
"import": "./dist/persistence/web/index.mjs"
|
|
42
|
-
},
|
|
43
35
|
"./web": {
|
|
44
36
|
"types": "./dist/web/index.d.mts",
|
|
45
37
|
"import": "./dist/web/index.mjs"
|
|
46
38
|
},
|
|
47
|
-
"./
|
|
48
|
-
"types": "./dist/
|
|
49
|
-
"import": "./dist/
|
|
39
|
+
"./webext": {
|
|
40
|
+
"types": "./dist/webext/index.d.mts",
|
|
41
|
+
"import": "./dist/webext/index.mjs"
|
|
50
42
|
},
|
|
51
|
-
"./
|
|
52
|
-
"types": "./dist/
|
|
53
|
-
"import": "./dist/
|
|
43
|
+
"./server": {
|
|
44
|
+
"types": "./dist/server/index.d.mts",
|
|
45
|
+
"import": "./dist/server/index.mjs"
|
|
54
46
|
},
|
|
55
|
-
"./
|
|
56
|
-
"types": "./dist/
|
|
57
|
-
"import": "./dist/
|
|
47
|
+
"./rx": {
|
|
48
|
+
"types": "./dist/rx/index.d.mts",
|
|
49
|
+
"import": "./dist/rx/index.mjs"
|
|
50
|
+
},
|
|
51
|
+
"./test": {
|
|
52
|
+
"types": "./dist/test/index.d.mts",
|
|
53
|
+
"import": "./dist/test/index.mjs"
|
|
58
54
|
}
|
|
59
55
|
},
|
|
60
56
|
"files": [
|
|
61
57
|
"dist"
|
|
62
58
|
],
|
|
63
59
|
"dependencies": {
|
|
64
|
-
"@standard-schema/spec": "^1.
|
|
65
|
-
"
|
|
60
|
+
"@standard-schema/spec": "^1.1.0",
|
|
61
|
+
"arktype": "^2.2.3",
|
|
62
|
+
"es-toolkit": "^1.50.0",
|
|
63
|
+
"injection-js": "^2.6.1",
|
|
64
|
+
"rxjs": "^7.8.2",
|
|
65
|
+
"uuid": "^14.0.1"
|
|
66
|
+
},
|
|
67
|
+
"devDependencies": {
|
|
68
|
+
"@types/node": "^26.1.2",
|
|
69
|
+
"vitest": "^4.1.10"
|
|
66
70
|
},
|
|
67
71
|
"scripts": {
|
|
68
72
|
"build": "tsdown",
|
|
69
|
-
"
|
|
73
|
+
"test": "vitest run --config ../../vitest.package.config.ts",
|
|
74
|
+
"test:watch": "vitest --config ../../vitest.package.config.ts",
|
|
75
|
+
"typecheck": "tsc -b --pretty false",
|
|
76
|
+
"build:dep": "pnpm run build"
|
|
70
77
|
}
|
|
71
78
|
}
|