@hexclave/js 1.0.51 → 1.0.52
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/dist/{admin-app-impl-Cz9Ub_C8.d.ts → admin-app-impl-DHs4il4z.d.ts} +11 -8
- package/dist/{admin-app-impl-Cz9Ub_C8.d.ts.map → admin-app-impl-DHs4il4z.d.ts.map} +1 -1
- package/dist/clickmap/clickmap-core.d.ts +1 -1
- package/dist/clickmap/index.d.ts +1 -1
- package/dist/{client-app-BgdvwktS.d.ts → client-app-BoOM8rxo.d.ts} +2 -1
- package/dist/{client-app-BgdvwktS.d.ts.map → client-app-BoOM8rxo.d.ts.map} +1 -1
- package/dist/common-CRu2FsO9.d.ts.map +1 -1
- package/dist/dev-tool/dev-tool-core.d.ts +1 -1
- package/dist/dev-tool/dev-tool-core.d.ts.map +1 -1
- package/dist/dev-tool/dev-tool-core.js +58 -28
- package/dist/dev-tool/dev-tool-core.js.map +1 -1
- package/dist/dev-tool/dev-tool-styles.js +35 -0
- package/dist/dev-tool/dev-tool-styles.js.map +1 -1
- package/dist/dev-tool/index.d.ts +1 -1
- package/dist/esm/dev-tool/dev-tool-core.d.ts.map +1 -1
- package/dist/esm/dev-tool/dev-tool-core.js +58 -28
- package/dist/esm/dev-tool/dev-tool-core.js.map +1 -1
- package/dist/esm/dev-tool/dev-tool-styles.js +35 -0
- package/dist/esm/dev-tool/dev-tool-styles.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +5 -4
- package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +97 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +3 -2
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js +26 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/common.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/common.js +21 -4
- package/dist/esm/lib/hexclave-app/apps/implementations/common.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.d.ts +37 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.d.ts.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.js +89 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.js.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.test.d.ts +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.test.js +134 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.test.js.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.d.ts +8 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.d.ts.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.js +73 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.js.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.d.ts +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.js +92 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.js.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.js +24 -3
- package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.d.ts +1 -0
- package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.js.map +1 -1
- package/dist/esm/pushed-config-error-overlay/index.js +1 -1
- package/dist/esm/pushed-config-error-overlay/index.js.map +1 -1
- package/dist/esm/pushed-config-error-overlay/index.test.js +1 -1
- package/dist/esm/utils/session-storage.d.ts +12 -0
- package/dist/esm/utils/session-storage.d.ts.map +1 -0
- package/dist/esm/utils/session-storage.js +30 -0
- package/dist/esm/utils/session-storage.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +97 -0
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js +26 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/common.js +21 -4
- package/dist/lib/hexclave-app/apps/implementations/common.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/index.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.d.ts +37 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.d.ts.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.js +92 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.js.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.test.d.ts +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.test.js +133 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.test.js.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.d.ts +8 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.d.ts.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.js +74 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.js.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.d.ts +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.js +91 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.js.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/server-app-impl.js +24 -3
- package/dist/lib/hexclave-app/apps/implementations/server-app-impl.js.map +1 -1
- package/dist/lib/hexclave-app/apps/index.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/interfaces/admin-app.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/interfaces/client-app.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/interfaces/client-app.js.map +1 -1
- package/dist/lib/hexclave-app/apps/interfaces/server-app.d.ts +1 -1
- package/dist/lib/hexclave-app/index.d.ts +1 -1
- package/dist/lib/hexclave-app/projects/index.d.ts +1 -1
- package/dist/lib/hexclave-app/teams/index.d.ts +1 -1
- package/dist/lib/hexclave-app/users/index.d.ts +1 -1
- package/dist/pushed-config-error-overlay/index.d.ts +1 -1
- package/dist/pushed-config-error-overlay/index.js +1 -1
- package/dist/pushed-config-error-overlay/index.js.map +1 -1
- package/dist/pushed-config-error-overlay/index.test.js +1 -1
- package/dist/utils/session-storage.d.ts +12 -0
- package/dist/utils/session-storage.d.ts.map +1 -0
- package/dist/utils/session-storage.js +33 -0
- package/dist/utils/session-storage.js.map +1 -0
- package/package.json +2 -2
- package/src/dev-tool/dev-tool-core.ts +100 -35
- package/src/dev-tool/dev-tool-styles.ts +35 -0
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.ts +127 -0
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.ts +34 -1
- package/src/lib/hexclave-app/apps/implementations/common.ts +18 -1
- package/src/lib/hexclave-app/apps/implementations/redirect-back-state.test.ts +134 -0
- package/src/lib/hexclave-app/apps/implementations/redirect-back-state.ts +140 -0
- package/src/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.ts +127 -0
- package/src/lib/hexclave-app/apps/implementations/redirect-loop-breaker.ts +117 -0
- package/src/lib/hexclave-app/apps/implementations/server-app-impl.ts +27 -2
- package/src/lib/hexclave-app/apps/interfaces/client-app.ts +1 -0
- package/src/pushed-config-error-overlay/index.ts +1 -1
- package/src/utils/session-storage.ts +45 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/pushed-config-error-overlay/index.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n\nimport { captureError } from \"@hexclave/shared/dist/utils/errors\";\nimport { runAsynchronously } from \"@hexclave/shared/dist/utils/promises\";\nimport { isLocalhost } from \"@hexclave/shared/dist/utils/urls\";\nimport { envVars } from \"../generated/env\";\nimport { getInPageUiBaseCSS } from \"../in-page-ui/base-styles\";\nimport { canMountIntoDom, getGlobalUiInstance, h, setGlobalUiInstance, setHtml } from \"../in-page-ui/dom\";\nimport type { StackClientApp } from \"../lib/hexclave-app\";\n\nconst GLOBAL_INSTANCE_KEY = \"__hexclave-pushed-config-error-overlay\";\nconst MINIMIZED_STORAGE_KEY = \"hexclave-pushed-config-error-minimized-key\";\nconst REFRESH_INTERVAL_MS = 5_000;\nconst HEXCLAVE_LOGO_SVG = '<svg width=\"16\" height=\"16\" viewBox=\"0 0 48 48\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linejoin=\"miter\"><path d=\"M 24 4 L 41.32 14 L 41.32 34 L 24 44 L 6.68 34 L 6.68 14 Z\"/><path d=\"M 11 16.87 L 14 15.13 L 14 32.87 L 11 31.13 Z\" fill=\"currentColor\" stroke=\"none\"/><path d=\"M 11 16.87 L 14 15.13 L 14 32.87 L 11 31.13 Z\" fill=\"currentColor\" stroke=\"none\" transform=\"rotate(120 24 24)\"/><path d=\"M 11 16.87 L 14 15.13 L 14 32.87 L 11 31.13 Z\" fill=\"currentColor\" stroke=\"none\" transform=\"rotate(240 24 24)\"/></svg>';\nconst COPY_ICON_SVG = '<svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\"/><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"/></svg>';\n\ntype ConfigIssue = {\n kind: \"error\" | \"warning\",\n messages: string[],\n};\n\nconst css = getInPageUiBaseCSS(\".hexclave-config-error-overlay\") + `\n .hexclave-config-error-overlay .hce-backdrop {\n position: fixed;\n inset: 0;\n z-index: 2147483647;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n background: rgba(0, 0, 0, 0.46);\n backdrop-filter: blur(6px);\n overflow: auto;\n }\n\n .hexclave-config-error-overlay .hce-card {\n --hce-status: var(--sdt-error);\n width: min(720px, calc(100vw - 32px));\n max-height: min(640px, calc(100dvh - 48px));\n border: 1px solid color-mix(in srgb, var(--hce-status) 35%, var(--sdt-border));\n border-radius: 18px;\n background: var(--sdt-overlay-bg);\n box-shadow: var(--sdt-shadow);\n backdrop-filter: blur(18px);\n display: flex;\n overflow: hidden;\n }\n\n .hexclave-config-error-overlay .hce-card-warning {\n --hce-status: var(--sdt-warning);\n }\n\n .hexclave-config-error-overlay .hce-card-inner {\n padding: 18px;\n width: 100%;\n overflow: auto;\n }\n\n .hexclave-config-error-overlay .hce-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 12px;\n }\n\n .hexclave-config-error-overlay .hce-title-row {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n min-width: 0;\n }\n\n .hexclave-config-error-overlay .hce-logo {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 34px;\n height: 34px;\n border-radius: 10px;\n background: var(--hce-status);\n color: white;\n box-shadow: 0 10px 30px color-mix(in srgb, var(--hce-status) 32%, transparent);\n }\n\n .hexclave-config-error-overlay .hce-badge {\n display: inline-flex;\n flex-shrink: 0;\n padding: 2px 6px;\n border-radius: 999px;\n background: var(--hce-status);\n color: white;\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n }\n\n .hexclave-config-error-overlay .hce-title {\n color: var(--sdt-text);\n margin-top: 4px;\n font-size: 18px;\n font-weight: 700;\n line-height: 1.25;\n }\n\n .hexclave-config-error-overlay .hce-actions {\n display: flex;\n gap: 4px;\n }\n\n .hexclave-config-error-overlay .hce-icon-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: 1px solid var(--sdt-border);\n border-radius: 8px;\n background: var(--sdt-bg-elevated);\n color: var(--sdt-text-secondary);\n cursor: pointer;\n font: inherit;\n line-height: 1;\n vertical-align: top;\n }\n\n .hexclave-config-error-overlay .hce-icon-btn svg {\n display: block;\n flex-shrink: 0;\n }\n\n .hexclave-config-error-overlay .hce-text-btn {\n align-items: center;\n gap: 6px;\n min-height: 28px;\n padding: 0 10px;\n width: auto;\n font-size: 12px;\n line-height: 1;\n }\n\n .hexclave-config-error-overlay .hce-icon-btn:hover {\n background: var(--sdt-bg-hover);\n color: var(--sdt-text);\n }\n\n .hexclave-config-error-overlay .hce-body {\n color: var(--sdt-text-secondary);\n font-size: 14px;\n line-height: 1.5;\n }\n\n .hexclave-config-error-overlay .hce-message-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 10px;\n margin-top: 14px;\n margin-bottom: 8px;\n }\n\n .hexclave-config-error-overlay .hce-message-label {\n color: var(--sdt-text);\n font-size: 12px;\n font-weight: 650;\n }\n\n .hexclave-config-error-overlay .hce-message {\n padding: 12px;\n max-height: min(260px, max(96px, 30dvh));\n overflow: auto;\n border: 1px solid var(--sdt-border-subtle);\n border-radius: 10px;\n background: var(--sdt-bg-subtle);\n color: var(--sdt-text);\n font-family: var(--sdt-font-mono);\n font-size: 12px;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n }\n\n .hexclave-config-error-overlay .hce-footer {\n margin-top: 10px;\n color: var(--sdt-text-tertiary);\n font-size: 12px;\n }\n\n .hexclave-config-error-overlay .hce-pill {\n position: fixed;\n right: 18px;\n bottom: 18px;\n z-index: 2147483647;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px 8px 8px;\n --hce-status: var(--sdt-error);\n border: 1px solid color-mix(in srgb, var(--hce-status) 35%, var(--sdt-border));\n border-radius: 999px;\n background: var(--sdt-overlay-bg);\n box-shadow: var(--sdt-trigger-shadow);\n color: var(--sdt-text);\n cursor: pointer;\n font: inherit;\n backdrop-filter: blur(18px);\n }\n\n .hexclave-config-error-overlay .hce-pill-warning {\n --hce-status: var(--sdt-warning);\n }\n\n .hexclave-config-error-overlay .hce-pill-logo {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n border-radius: 999px;\n background: var(--hce-status);\n color: white;\n }\n\n @media (max-height: 520px) {\n .hexclave-config-error-overlay .hce-backdrop {\n align-items: flex-start;\n padding: 12px;\n }\n\n .hexclave-config-error-overlay .hce-card {\n width: min(720px, calc(100vw - 24px));\n max-height: calc(100dvh - 24px);\n }\n\n .hexclave-config-error-overlay .hce-card-inner {\n padding: 12px;\n }\n\n .hexclave-config-error-overlay .hce-header {\n margin-bottom: 8px;\n }\n\n .hexclave-config-error-overlay .hce-title {\n font-size: 16px;\n }\n\n .hexclave-config-error-overlay .hce-body {\n font-size: 13px;\n }\n\n .hexclave-config-error-overlay .hce-message {\n max-height: max(80px, 24dvh);\n }\n }\n`;\n\nfunction storageGet(key: string): string | null {\n try {\n return localStorage.getItem(key);\n } catch {\n return null;\n }\n}\n\nfunction storageSet(key: string, value: string): void {\n try {\n localStorage.setItem(key, value);\n } catch {\n // Storage may be unavailable in private or embedded contexts.\n }\n}\n\nfunction storageRemove(key: string): void {\n try {\n localStorage.removeItem(key);\n } catch {\n // Storage may be unavailable in private or embedded contexts.\n }\n}\n\nfunction shouldMount(): boolean {\n if (!canMountIntoDom()) {\n return false;\n }\n\n const nodeEnv = envVars.NODE_ENV;\n if (nodeEnv !== undefined) {\n return nodeEnv === \"development\";\n }\n\n try {\n const url = new URL(window.location.href);\n if (url.protocol === \"file:\") {\n return true;\n }\n } catch {\n return false;\n }\n return isLocalhost(window.location.href);\n}\n\nasync function copyTextToClipboard(text: string): Promise<void> {\n const clipboard: unknown = Reflect.get(navigator, \"clipboard\");\n const writeText = clipboard != null && typeof clipboard === \"object\"\n ? Reflect.get(clipboard, \"writeText\")\n : null;\n if (typeof writeText === \"function\") {\n await writeText.call(clipboard, text);\n return;\n }\n\n const textarea = h(\"textarea\", {\n style: {\n position: \"fixed\",\n left: \"-9999px\",\n top: \"0\",\n opacity: \"0\",\n },\n readonly: \"true\",\n }) as HTMLTextAreaElement;\n textarea.value = text;\n document.body.appendChild(textarea);\n textarea.select();\n const copied = document.execCommand(\"copy\");\n textarea.remove();\n if (!copied) {\n throw new Error(\"Browser refused to copy the config error message.\");\n }\n}\n\nfunction buildConfigIssueAiPrompt(issue: ConfigIssue): string {\n const issueLabel = issue.kind === \"error\" ? \"error\" : \"warning\";\n return [\n `Help me fix this Hexclave config ${issueLabel}.`,\n \"\",\n \"Hexclave reminder:\",\n `This ${issueLabel} comes from a pushed Hexclave config file. The app may keep running with the synced Hexclave config, but I need to fix the config file mentioned in the message and save it again so Hexclave can sync the config successfully and clear the dialog. Use your web fetch tool to read https://skill.hexclave.com to learn more about Hexclave.`,\n \"\",\n issue.kind === \"error\" ? \"Error message:\" : \"Warning message:\",\n issue.messages.join(\"\\n\"),\n \"\",\n \"Please explain the likely cause, identify the config key or value I should change, and suggest the smallest safe fix.\",\n ].join(\"\\n\");\n}\n\nexport function mountPushedConfigErrorOverlay(app: StackClientApp<true>): () => void {\n if (!shouldMount()) {\n return () => {};\n }\n\n getGlobalUiInstance(GLOBAL_INSTANCE_KEY)?.cleanup();\n\n const root = h(\"div\", { className: \"hexclave-config-error-overlay\" });\n const style = h(\"style\", null, css);\n root.appendChild(style);\n document.body.appendChild(root);\n\n let disposed = false;\n let lastErrorKey: string | null = null;\n let lastConsoleErrorKey: string | null = null;\n let minimized = false;\n\n const render = (issue: ConfigIssue | null) => {\n root.replaceChildren(style);\n if (issue == null) {\n lastErrorKey = null;\n minimized = false;\n return;\n }\n\n const issueMessage = issue.messages.join(\"\\n\");\n const issueKey = `${app.projectId}:${issue.kind}:${issueMessage}`;\n const issueLabel = issue.kind === \"error\" ? \"error\" : \"warning\";\n const issueTitle = issue.kind === \"error\"\n ? \"Your Hexclave config has been saved, but contains errors\"\n : \"Your Hexclave config has been saved, but has warnings\";\n const bodyText = issue.kind === \"error\"\n ? \"Your app can keep running, but Hexclave is still using the last valid config until this is fixed.\"\n : \"Your app can keep running, but part of your Hexclave config may not behave the way you expect until this is fixed.\";\n const footerText = issue.kind === \"error\"\n ? \"Fix the config file mentioned above and save it again. This message will disappear after the config sync succeeds.\"\n : \"Fix the config file mentioned above and save it again. This warning will disappear after Hexclave syncs a config without warnings.\";\n if (issueKey !== lastConsoleErrorKey) {\n lastConsoleErrorKey = issueKey;\n const consoleMessage = `[Hexclave] Config ${issueLabel}: ${issueMessage}`;\n if (issue.kind === \"error\") {\n console.error(consoleMessage);\n } else {\n console.warn(consoleMessage);\n }\n }\n\n if (issueKey !== lastErrorKey) {\n lastErrorKey = issueKey;\n minimized = storageGet(MINIMIZED_STORAGE_KEY) === issueKey;\n }\n\n if (minimized) {\n const logoSpan = h(\"span\", { className: \"hce-pill-logo\" });\n setHtml(logoSpan, HEXCLAVE_LOGO_SVG);\n root.appendChild(h(\"button\", {\n className: issue.kind === \"error\" ? \"hce-pill\" : \"hce-pill hce-pill-warning\",\n type: \"button\",\n onClick: () => {\n minimized = false;\n storageRemove(MINIMIZED_STORAGE_KEY);\n render(issue);\n },\n },\n logoSpan,\n h(\"span\", null, issue.kind === \"error\" ? \"Config error\" : \"Config warning\")));\n return;\n }\n\n const logoSpan = h(\"span\", { className: \"hce-logo\" });\n setHtml(logoSpan, HEXCLAVE_LOGO_SVG);\n const copyButton = h(\"button\", {\n className: \"hce-icon-btn hce-text-btn\",\n type: \"button\",\n title: issue.kind === \"error\" ? \"Copy error message\" : \"Copy warning message\",\n \"aria-label\": issue.kind === \"error\" ? \"Copy config error message\" : \"Copy config warning message\",\n onClick: () => {\n runAsynchronously(async () => {\n await copyTextToClipboard(issueMessage);\n copyButton.textContent = \"Copied\";\n setTimeout(() => {\n setHtml(copyButton, `${COPY_ICON_SVG}Copy`);\n }, 1500);\n }, {\n noErrorLogging: true,\n onError: (copyError) => {\n captureError(\"pushed-config-error-overlay-copy\", copyError);\n copyButton.textContent = \"Copy failed\";\n setTimeout(() => {\n setHtml(copyButton, `${COPY_ICON_SVG}Copy`);\n }, 1500);\n },\n });\n },\n });\n setHtml(copyButton, `${COPY_ICON_SVG}Copy`);\n\n const aiPromptCopyButton = h(\"button\", {\n className: \"hce-icon-btn\",\n type: \"button\",\n title: \"Copy AI prompt\",\n \"aria-label\": issue.kind === \"error\" ? \"Copy AI prompt for config error\" : \"Copy AI prompt for config warning\",\n onClick: () => {\n runAsynchronously(async () => {\n await copyTextToClipboard(buildConfigIssueAiPrompt(issue));\n aiPromptCopyButton.textContent = \"✓\";\n setTimeout(() => {\n setHtml(aiPromptCopyButton, COPY_ICON_SVG);\n }, 1500);\n }, {\n noErrorLogging: true,\n onError: (copyError) => {\n captureError(\"pushed-config-error-overlay-copy-ai-prompt\", copyError);\n aiPromptCopyButton.textContent = \"!\";\n setTimeout(() => {\n setHtml(aiPromptCopyButton, COPY_ICON_SVG);\n }, 1500);\n },\n });\n },\n });\n setHtml(aiPromptCopyButton, COPY_ICON_SVG);\n\n root.appendChild(h(\"div\", { className: \"hce-backdrop\" },\n h(\"div\", { className: issue.kind === \"error\" ? \"hce-card\" : \"hce-card hce-card-warning\", role: \"alertdialog\", \"aria-modal\": \"true\", \"aria-label\": `Hexclave config ${issueLabel}` },\n h(\"div\", { className: \"hce-card-inner\" },\n h(\"div\", { className: \"hce-header\" },\n h(\"div\", { className: \"hce-title-row\" },\n logoSpan,\n h(\"div\", null,\n h(\"span\", { className: \"hce-badge\" }, `Config ${issueLabel}`),\n h(\"div\", { className: \"hce-title\" }, issueTitle),\n ),\n ),\n h(\"div\", { className: \"hce-actions\" },\n aiPromptCopyButton,\n h(\"button\", {\n className: \"hce-icon-btn\",\n type: \"button\",\n title: \"Minimize\",\n \"aria-label\": issue.kind === \"error\" ? \"Minimize config error\" : \"Minimize config warning\",\n onClick: () => {\n minimized = true;\n storageSet(MINIMIZED_STORAGE_KEY, issueKey);\n render(issue);\n },\n }, \"–\"),\n ),\n ),\n h(\"div\", { className: \"hce-body\" },\n bodyText,\n h(\"div\", { className: \"hce-message-header\" },\n h(\"div\", { className: \"hce-message-label\" }, issue.kind === \"error\" ? \"Error message\" : \"Warning message\"),\n copyButton,\n ),\n h(\"div\", { className: \"hce-message\" }, issueMessage),\n h(\"div\", { className: \"hce-footer\" }, footerText),\n ),\n ),\n )));\n };\n\n const refresh = () => {\n if (disposed || !canMountIntoDom()) {\n return;\n }\n runAsynchronously(async () => {\n const project = await app.getProject();\n if (disposed) {\n return;\n }\n render(project.pushedConfigError == null\n ? project.configWarnings.length === 0\n ? null\n : { kind: \"warning\", messages: project.configWarnings.map((warning) => warning.message) }\n : { kind: \"error\", messages: [project.pushedConfigError.message] });\n }, {\n noErrorLogging: true,\n onError: (error) => {\n captureError(\"pushed-config-error-overlay-refresh\", error);\n },\n });\n };\n\n // This is mounted from the base client-app constructor, which also runs\n // before subclass field initializers. Defer the first app call so overridden\n // methods like adminApp.getProject() can safely touch subclass caches.\n queueMicrotask(refresh);\n const interval = setInterval(refresh, REFRESH_INTERVAL_MS);\n\n const cleanup = () => {\n disposed = true;\n clearInterval(interval);\n root.remove();\n if (getGlobalUiInstance(GLOBAL_INSTANCE_KEY)?.cleanup === cleanup) {\n setGlobalUiInstance(GLOBAL_INSTANCE_KEY, null);\n }\n };\n setGlobalUiInstance(GLOBAL_INSTANCE_KEY, { cleanup });\n return cleanup;\n}\n\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/pushed-config-error-overlay/index.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n\nimport { captureError } from \"@hexclave/shared/dist/utils/errors\";\nimport { runAsynchronously } from \"@hexclave/shared/dist/utils/promises\";\nimport { isLocalhost } from \"@hexclave/shared/dist/utils/urls\";\nimport { envVars } from \"../generated/env\";\nimport { getInPageUiBaseCSS } from \"../in-page-ui/base-styles\";\nimport { canMountIntoDom, getGlobalUiInstance, h, setGlobalUiInstance, setHtml } from \"../in-page-ui/dom\";\nimport type { StackClientApp } from \"../lib/hexclave-app\";\n\nconst GLOBAL_INSTANCE_KEY = \"__hexclave-pushed-config-error-overlay\";\nconst MINIMIZED_STORAGE_KEY = \"hexclave-pushed-config-error-minimized-key\";\nconst REFRESH_INTERVAL_MS = 5_000;\nconst HEXCLAVE_LOGO_SVG = '<svg width=\"16\" height=\"16\" viewBox=\"0 0 48 48\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linejoin=\"miter\"><path d=\"M 24 4 L 41.32 14 L 41.32 34 L 24 44 L 6.68 34 L 6.68 14 Z\"/><path d=\"M 11 16.87 L 14 15.13 L 14 32.87 L 11 31.13 Z\" fill=\"currentColor\" stroke=\"none\"/><path d=\"M 11 16.87 L 14 15.13 L 14 32.87 L 11 31.13 Z\" fill=\"currentColor\" stroke=\"none\" transform=\"rotate(120 24 24)\"/><path d=\"M 11 16.87 L 14 15.13 L 14 32.87 L 11 31.13 Z\" fill=\"currentColor\" stroke=\"none\" transform=\"rotate(240 24 24)\"/></svg>';\nconst COPY_ICON_SVG = '<svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\"/><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"/></svg>';\n\ntype ConfigIssue = {\n kind: \"error\" | \"warning\",\n messages: string[],\n};\n\nconst css = getInPageUiBaseCSS(\".hexclave-config-error-overlay\") + `\n .hexclave-config-error-overlay .hce-backdrop {\n position: fixed;\n inset: 0;\n z-index: 2147483647;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n background: rgba(0, 0, 0, 0.46);\n backdrop-filter: blur(6px);\n overflow: auto;\n }\n\n .hexclave-config-error-overlay .hce-card {\n --hce-status: var(--sdt-error);\n width: min(720px, calc(100vw - 32px));\n max-height: min(640px, calc(100dvh - 48px));\n border: 1px solid color-mix(in srgb, var(--hce-status) 35%, var(--sdt-border));\n border-radius: 18px;\n background: var(--sdt-overlay-bg);\n box-shadow: var(--sdt-shadow);\n backdrop-filter: blur(18px);\n display: flex;\n overflow: hidden;\n }\n\n .hexclave-config-error-overlay .hce-card-warning {\n --hce-status: var(--sdt-warning);\n }\n\n .hexclave-config-error-overlay .hce-card-inner {\n padding: 18px;\n width: 100%;\n overflow: auto;\n }\n\n .hexclave-config-error-overlay .hce-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 12px;\n }\n\n .hexclave-config-error-overlay .hce-title-row {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n min-width: 0;\n }\n\n .hexclave-config-error-overlay .hce-logo {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 34px;\n height: 34px;\n border-radius: 10px;\n background: var(--hce-status);\n color: white;\n box-shadow: 0 10px 30px color-mix(in srgb, var(--hce-status) 32%, transparent);\n }\n\n .hexclave-config-error-overlay .hce-badge {\n display: inline-flex;\n flex-shrink: 0;\n padding: 2px 6px;\n border-radius: 999px;\n background: var(--hce-status);\n color: white;\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n }\n\n .hexclave-config-error-overlay .hce-title {\n color: var(--sdt-text);\n margin-top: 4px;\n font-size: 18px;\n font-weight: 700;\n line-height: 1.25;\n }\n\n .hexclave-config-error-overlay .hce-actions {\n display: flex;\n gap: 4px;\n }\n\n .hexclave-config-error-overlay .hce-icon-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: 1px solid var(--sdt-border);\n border-radius: 8px;\n background: var(--sdt-bg-elevated);\n color: var(--sdt-text-secondary);\n cursor: pointer;\n font: inherit;\n line-height: 1;\n vertical-align: top;\n }\n\n .hexclave-config-error-overlay .hce-icon-btn svg {\n display: block;\n flex-shrink: 0;\n }\n\n .hexclave-config-error-overlay .hce-text-btn {\n align-items: center;\n gap: 6px;\n min-height: 28px;\n padding: 0 10px;\n width: auto;\n font-size: 12px;\n line-height: 1;\n }\n\n .hexclave-config-error-overlay .hce-icon-btn:hover {\n background: var(--sdt-bg-hover);\n color: var(--sdt-text);\n }\n\n .hexclave-config-error-overlay .hce-body {\n color: var(--sdt-text-secondary);\n font-size: 14px;\n line-height: 1.5;\n }\n\n .hexclave-config-error-overlay .hce-message-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 10px;\n margin-top: 14px;\n margin-bottom: 8px;\n }\n\n .hexclave-config-error-overlay .hce-message-label {\n color: var(--sdt-text);\n font-size: 12px;\n font-weight: 650;\n }\n\n .hexclave-config-error-overlay .hce-message {\n padding: 12px;\n max-height: min(260px, max(96px, 30dvh));\n overflow: auto;\n border: 1px solid var(--sdt-border-subtle);\n border-radius: 10px;\n background: var(--sdt-bg-subtle);\n color: var(--sdt-text);\n font-family: var(--sdt-font-mono);\n font-size: 12px;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n }\n\n .hexclave-config-error-overlay .hce-footer {\n margin-top: 10px;\n color: var(--sdt-text-tertiary);\n font-size: 12px;\n }\n\n .hexclave-config-error-overlay .hce-pill {\n position: fixed;\n right: 18px;\n bottom: 18px;\n z-index: 2147483647;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px 8px 8px;\n --hce-status: var(--sdt-error);\n border: 1px solid color-mix(in srgb, var(--hce-status) 35%, var(--sdt-border));\n border-radius: 999px;\n background: var(--sdt-overlay-bg);\n box-shadow: var(--sdt-trigger-shadow);\n color: var(--sdt-text);\n cursor: pointer;\n font: inherit;\n backdrop-filter: blur(18px);\n }\n\n .hexclave-config-error-overlay .hce-pill-warning {\n --hce-status: var(--sdt-warning);\n }\n\n .hexclave-config-error-overlay .hce-pill-logo {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n border-radius: 999px;\n background: var(--hce-status);\n color: white;\n }\n\n @media (max-height: 520px) {\n .hexclave-config-error-overlay .hce-backdrop {\n align-items: flex-start;\n padding: 12px;\n }\n\n .hexclave-config-error-overlay .hce-card {\n width: min(720px, calc(100vw - 24px));\n max-height: calc(100dvh - 24px);\n }\n\n .hexclave-config-error-overlay .hce-card-inner {\n padding: 12px;\n }\n\n .hexclave-config-error-overlay .hce-header {\n margin-bottom: 8px;\n }\n\n .hexclave-config-error-overlay .hce-title {\n font-size: 16px;\n }\n\n .hexclave-config-error-overlay .hce-body {\n font-size: 13px;\n }\n\n .hexclave-config-error-overlay .hce-message {\n max-height: max(80px, 24dvh);\n }\n }\n`;\n\nfunction storageGet(key: string): string | null {\n try {\n return localStorage.getItem(key);\n } catch {\n return null;\n }\n}\n\nfunction storageSet(key: string, value: string): void {\n try {\n localStorage.setItem(key, value);\n } catch {\n // Storage may be unavailable in private or embedded contexts.\n }\n}\n\nfunction storageRemove(key: string): void {\n try {\n localStorage.removeItem(key);\n } catch {\n // Storage may be unavailable in private or embedded contexts.\n }\n}\n\nfunction shouldMount(): boolean {\n if (!canMountIntoDom()) {\n return false;\n }\n\n const nodeEnv = envVars.NODE_ENV;\n if (nodeEnv !== undefined) {\n return nodeEnv === \"development\";\n }\n\n try {\n const url = new URL(window.location.href);\n if (url.protocol === \"file:\") {\n return true;\n }\n } catch {\n return false;\n }\n return isLocalhost(window.location.href);\n}\n\nasync function copyTextToClipboard(text: string): Promise<void> {\n const clipboard: unknown = Reflect.get(navigator, \"clipboard\");\n const writeText = clipboard != null && typeof clipboard === \"object\"\n ? Reflect.get(clipboard, \"writeText\")\n : null;\n if (typeof writeText === \"function\") {\n await writeText.call(clipboard, text);\n return;\n }\n\n const textarea = h(\"textarea\", {\n style: {\n position: \"fixed\",\n left: \"-9999px\",\n top: \"0\",\n opacity: \"0\",\n },\n readonly: \"true\",\n }) as HTMLTextAreaElement;\n textarea.value = text;\n document.body.appendChild(textarea);\n textarea.select();\n const copied = document.execCommand(\"copy\");\n textarea.remove();\n if (!copied) {\n throw new Error(\"Browser refused to copy the config error message.\");\n }\n}\n\nfunction buildConfigIssueAiPrompt(issue: ConfigIssue): string {\n const issueLabel = issue.kind === \"error\" ? \"error\" : \"warning\";\n return [\n `Help me fix this Hexclave config ${issueLabel}.`,\n \"\",\n \"Hexclave reminder:\",\n `This ${issueLabel} comes from a pushed Hexclave config file. The app may keep running with the synced Hexclave config, but I need to fix the config file mentioned in the message and save it again so Hexclave can sync the config successfully and clear the dialog. Use your web fetch tool to read https://skill.hexclave.com to learn more about Hexclave.`,\n \"\",\n issue.kind === \"error\" ? \"Error message:\" : \"Warning message:\",\n issue.messages.join(\"\\n\"),\n \"\",\n \"Please explain the likely cause, identify the config key or value I should change, and suggest the smallest safe fix.\",\n ].join(\"\\n\");\n}\n\nexport function mountPushedConfigErrorOverlay(app: StackClientApp<true>): () => void {\n if (!shouldMount()) {\n return () => {};\n }\n\n getGlobalUiInstance(GLOBAL_INSTANCE_KEY)?.cleanup();\n\n const root = h(\"div\", { className: \"hexclave-config-error-overlay\" });\n const style = h(\"style\", null, css);\n root.appendChild(style);\n document.body.appendChild(root);\n\n let disposed = false;\n let lastErrorKey: string | null = null;\n let lastConsoleErrorKey: string | null = null;\n let minimized = false;\n\n const render = (issue: ConfigIssue | null) => {\n root.replaceChildren(style);\n if (issue == null) {\n lastErrorKey = null;\n minimized = false;\n return;\n }\n\n const issueMessage = \"Hexclave config \" + issue.kind + \": \" + issue.messages.join(\"\\n\");\n const issueKey = `${app.projectId}:${issue.kind}:${issueMessage}`;\n const issueLabel = issue.kind === \"error\" ? \"error\" : \"warning\";\n const issueTitle = issue.kind === \"error\"\n ? \"Your Hexclave config has been saved, but contains errors\"\n : \"Your Hexclave config has been saved, but has warnings\";\n const bodyText = issue.kind === \"error\"\n ? \"Your app can keep running, but Hexclave is still using the last valid config until this is fixed.\"\n : \"Your app can keep running, but part of your Hexclave config may not behave the way you expect until this is fixed.\";\n const footerText = issue.kind === \"error\"\n ? \"Fix the config file mentioned above and save it again. This message will disappear after the config sync succeeds.\"\n : \"Fix the config file mentioned above and save it again. This warning will disappear after Hexclave syncs a config without warnings.\";\n if (issueKey !== lastConsoleErrorKey) {\n lastConsoleErrorKey = issueKey;\n const consoleMessage = `[Hexclave] Config ${issueLabel}: ${issueMessage}`;\n if (issue.kind === \"error\") {\n console.error(consoleMessage);\n } else {\n console.warn(consoleMessage);\n }\n }\n\n if (issueKey !== lastErrorKey) {\n lastErrorKey = issueKey;\n minimized = storageGet(MINIMIZED_STORAGE_KEY) === issueKey;\n }\n\n if (minimized) {\n const logoSpan = h(\"span\", { className: \"hce-pill-logo\" });\n setHtml(logoSpan, HEXCLAVE_LOGO_SVG);\n root.appendChild(h(\"button\", {\n className: issue.kind === \"error\" ? \"hce-pill\" : \"hce-pill hce-pill-warning\",\n type: \"button\",\n onClick: () => {\n minimized = false;\n storageRemove(MINIMIZED_STORAGE_KEY);\n render(issue);\n },\n },\n logoSpan,\n h(\"span\", null, issue.kind === \"error\" ? \"Config error\" : \"Config warning\")));\n return;\n }\n\n const logoSpan = h(\"span\", { className: \"hce-logo\" });\n setHtml(logoSpan, HEXCLAVE_LOGO_SVG);\n const copyButton = h(\"button\", {\n className: \"hce-icon-btn hce-text-btn\",\n type: \"button\",\n title: issue.kind === \"error\" ? \"Copy error message\" : \"Copy warning message\",\n \"aria-label\": issue.kind === \"error\" ? \"Copy config error message\" : \"Copy config warning message\",\n onClick: () => {\n runAsynchronously(async () => {\n await copyTextToClipboard(issueMessage);\n copyButton.textContent = \"Copied\";\n setTimeout(() => {\n setHtml(copyButton, `${COPY_ICON_SVG}Copy`);\n }, 1500);\n }, {\n noErrorLogging: true,\n onError: (copyError) => {\n captureError(\"pushed-config-error-overlay-copy\", copyError);\n copyButton.textContent = \"Copy failed\";\n setTimeout(() => {\n setHtml(copyButton, `${COPY_ICON_SVG}Copy`);\n }, 1500);\n },\n });\n },\n });\n setHtml(copyButton, `${COPY_ICON_SVG}Copy`);\n\n const aiPromptCopyButton = h(\"button\", {\n className: \"hce-icon-btn\",\n type: \"button\",\n title: \"Copy AI prompt\",\n \"aria-label\": issue.kind === \"error\" ? \"Copy AI prompt for config error\" : \"Copy AI prompt for config warning\",\n onClick: () => {\n runAsynchronously(async () => {\n await copyTextToClipboard(buildConfigIssueAiPrompt(issue));\n aiPromptCopyButton.textContent = \"✓\";\n setTimeout(() => {\n setHtml(aiPromptCopyButton, COPY_ICON_SVG);\n }, 1500);\n }, {\n noErrorLogging: true,\n onError: (copyError) => {\n captureError(\"pushed-config-error-overlay-copy-ai-prompt\", copyError);\n aiPromptCopyButton.textContent = \"!\";\n setTimeout(() => {\n setHtml(aiPromptCopyButton, COPY_ICON_SVG);\n }, 1500);\n },\n });\n },\n });\n setHtml(aiPromptCopyButton, COPY_ICON_SVG);\n\n root.appendChild(h(\"div\", { className: \"hce-backdrop\" },\n h(\"div\", { className: issue.kind === \"error\" ? \"hce-card\" : \"hce-card hce-card-warning\", role: \"alertdialog\", \"aria-modal\": \"true\", \"aria-label\": `Hexclave config ${issueLabel}` },\n h(\"div\", { className: \"hce-card-inner\" },\n h(\"div\", { className: \"hce-header\" },\n h(\"div\", { className: \"hce-title-row\" },\n logoSpan,\n h(\"div\", null,\n h(\"span\", { className: \"hce-badge\" }, `Config ${issueLabel}`),\n h(\"div\", { className: \"hce-title\" }, issueTitle),\n ),\n ),\n h(\"div\", { className: \"hce-actions\" },\n aiPromptCopyButton,\n h(\"button\", {\n className: \"hce-icon-btn\",\n type: \"button\",\n title: \"Minimize\",\n \"aria-label\": issue.kind === \"error\" ? \"Minimize config error\" : \"Minimize config warning\",\n onClick: () => {\n minimized = true;\n storageSet(MINIMIZED_STORAGE_KEY, issueKey);\n render(issue);\n },\n }, \"–\"),\n ),\n ),\n h(\"div\", { className: \"hce-body\" },\n bodyText,\n h(\"div\", { className: \"hce-message-header\" },\n h(\"div\", { className: \"hce-message-label\" }, issue.kind === \"error\" ? \"Error message\" : \"Warning message\"),\n copyButton,\n ),\n h(\"div\", { className: \"hce-message\" }, issueMessage),\n h(\"div\", { className: \"hce-footer\" }, footerText),\n ),\n ),\n )));\n };\n\n const refresh = () => {\n if (disposed || !canMountIntoDom()) {\n return;\n }\n runAsynchronously(async () => {\n const project = await app.getProject();\n if (disposed) {\n return;\n }\n render(project.pushedConfigError == null\n ? project.configWarnings.length === 0\n ? null\n : { kind: \"warning\", messages: project.configWarnings.map((warning) => warning.message) }\n : { kind: \"error\", messages: [project.pushedConfigError.message] });\n }, {\n noErrorLogging: true,\n onError: (error) => {\n captureError(\"pushed-config-error-overlay-refresh\", error);\n },\n });\n };\n\n // This is mounted from the base client-app constructor, which also runs\n // before subclass field initializers. Defer the first app call so overridden\n // methods like adminApp.getProject() can safely touch subclass caches.\n queueMicrotask(refresh);\n const interval = setInterval(refresh, REFRESH_INTERVAL_MS);\n\n const cleanup = () => {\n disposed = true;\n clearInterval(interval);\n root.remove();\n if (getGlobalUiInstance(GLOBAL_INSTANCE_KEY)?.cleanup === cleanup) {\n setGlobalUiInstance(GLOBAL_INSTANCE_KEY, null);\n }\n };\n setGlobalUiInstance(GLOBAL_INSTANCE_KEY, { cleanup });\n return cleanup;\n}\n\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { envVars } from "../generated/env.js";
|
|
2
1
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { envVars } from "../generated/env.js";
|
|
3
3
|
import { StackClientApp } from "../lib/hexclave-app/index.js";
|
|
4
4
|
import { mountPushedConfigErrorOverlay } from "./index.js";
|
|
5
5
|
//#region src/pushed-config-error-overlay/index.test.ts
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/utils/session-storage.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Guarded sessionStorage access for resilience layers (redirect loop breaking, redirect-back state
|
|
4
|
+
* mirroring). These layers must degrade to "no stored value" when storage is unavailable, instead
|
|
5
|
+
* of breaking the auth flow they are trying to protect.
|
|
6
|
+
*/
|
|
7
|
+
declare function readSessionStorageItem(key: string): string | null;
|
|
8
|
+
declare function writeSessionStorageItem(key: string, value: string): void;
|
|
9
|
+
declare function removeSessionStorageItem(key: string): void;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { readSessionStorageItem, removeSessionStorageItem, writeSessionStorageItem };
|
|
12
|
+
//# sourceMappingURL=session-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-storage.d.ts","names":[],"sources":["../../../src/utils/session-storage.ts"],"mappings":";;AAUA;;;;iBAAgB,sBAAA,CAAuB,GAAW;AAAA,iBAalC,uBAAA,CAAwB,GAAA,UAAa,KAAa;AAAA,iBAYlD,wBAAA,CAAyB,GAAW"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region src/utils/session-storage.ts
|
|
2
|
+
/**
|
|
3
|
+
* Guarded sessionStorage access for resilience layers (redirect loop breaking, redirect-back state
|
|
4
|
+
* mirroring). These layers must degrade to "no stored value" when storage is unavailable, instead
|
|
5
|
+
* of breaking the auth flow they are trying to protect.
|
|
6
|
+
*/
|
|
7
|
+
function readSessionStorageItem(key) {
|
|
8
|
+
if (typeof window === "undefined") return null;
|
|
9
|
+
try {
|
|
10
|
+
return window.sessionStorage.getItem(key);
|
|
11
|
+
} catch {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function writeSessionStorageItem(key, value) {
|
|
16
|
+
if (typeof window === "undefined") return;
|
|
17
|
+
try {
|
|
18
|
+
window.sessionStorage.setItem(key, value);
|
|
19
|
+
} catch {}
|
|
20
|
+
}
|
|
21
|
+
function removeSessionStorageItem(key) {
|
|
22
|
+
if (typeof window === "undefined") return;
|
|
23
|
+
try {
|
|
24
|
+
window.sessionStorage.removeItem(key);
|
|
25
|
+
} catch {}
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { readSessionStorageItem, removeSessionStorageItem, writeSessionStorageItem };
|
|
29
|
+
|
|
30
|
+
//# sourceMappingURL=session-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-storage.js","names":[],"sources":["../../../src/utils/session-storage.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n/**\n * Guarded sessionStorage access for resilience layers (redirect loop breaking, redirect-back state\n * mirroring). These layers must degrade to \"no stored value\" when storage is unavailable, instead\n * of breaking the auth flow they are trying to protect.\n */\n\nexport function readSessionStorageItem(key: string): string | null {\n if (typeof window === \"undefined\") {\n return null;\n }\n try {\n return window.sessionStorage.getItem(key);\n } catch {\n // Storage can be blocked entirely (private browsing, sandboxed iframes, disabled cookies), in\n // which case accessing window.sessionStorage throws. Treat that as \"nothing stored\".\n return null;\n }\n}\n\nexport function writeSessionStorageItem(key: string, value: string): void {\n if (typeof window === \"undefined\") {\n return;\n }\n try {\n window.sessionStorage.setItem(key, value);\n } catch {\n // Storage can be blocked or full; see readSessionStorageItem. Values written here are only\n // used as a fallback, so failing to persist must not fail the caller.\n }\n}\n\nexport function removeSessionStorageItem(key: string): void {\n if (typeof window === \"undefined\") {\n return;\n }\n try {\n window.sessionStorage.removeItem(key);\n } catch {\n // See readSessionStorageItem.\n }\n}\n"],"mappings":";;;;;;AAUA,SAAgB,uBAAuB,KAA4B;CACjE,IAAI,OAAO,WAAW,aACpB,OAAO;CAET,IAAI;EACF,OAAO,OAAO,eAAe,QAAQ,GAAG;CAC1C,QAAQ;EAGN,OAAO;CACT;AACF;AAEA,SAAgB,wBAAwB,KAAa,OAAqB;CACxE,IAAI,OAAO,WAAW,aACpB;CAEF,IAAI;EACF,OAAO,eAAe,QAAQ,KAAK,KAAK;CAC1C,QAAQ,CAGR;AACF;AAEA,SAAgB,yBAAyB,KAAmB;CAC1D,IAAI,OAAO,WAAW,aACpB;CAEF,IAAI;EACF,OAAO,eAAe,WAAW,GAAG;CACtC,QAAQ,CAER;AACF"}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { a as AdminTeamPermission, c as AdminTeamPermissionDefinitionUpdateOptio
|
|
|
5
5
|
import { a as PlanUsageRow, i as PlanUsagePlanId, n as PlanUsageKind, r as PlanUsageNextPlanId, t as PlanUsage } from "./index-B594jg4e.js";
|
|
6
6
|
import { r as OAuthConnection, t as Connection } from "./index-ClBTM-St.js";
|
|
7
7
|
import { i as ServerContactChannel, t as ContactChannel } from "./index-DN04TjLM.js";
|
|
8
|
-
import { A as HexclaveServerApp, B as ServerListUsersOptions, C as HexclaveAdminAppConstructorOptions, D as StackAdminApp, F as StackServerAppConstructorOptions, G as ServerTeamUser, H as ServerTeamCreateOptions, I as EditableTeamMemberProfile, J as TeamInvitation, K as Team, L as ReceivedTeamInvitation, M as HexclaveServerAppConstructorOptions, N as StackServerApp, O as StackAdminAppConstructor, P as StackServerAppConstructor, Q as TeamUser, R as SentTeamInvitation, S as HexclaveAdminAppConstructor, St as User, U as ServerTeamMemberProfile, V as ServerTeam, W as ServerTeamUpdateOptions, Y as TeamMemberProfile, Z as TeamUpdateOptions, a as StackClientApp, b as EmailOutboxUpdateOptions, c as StackClientAppJson, ct as CurrentServerUser, d as AdminProjectCreateOptions, dt as OAuthProvider, f as AdminProjectUpdateOptions, gt as ServerUser, h as PushedConfigSource, ht as ServerOAuthProvider, i as HexclaveClientAppJson, it as Auth, j as HexclaveServerAppConstructor, k as StackAdminAppConstructorOptions, l as AdminOwnedProject, lt as CurrentUser, n as HexclaveClientAppConstructor, o as StackClientAppConstructor, ot as CurrentInternalServerUser, p as Project, q as TeamCreateOptions, r as HexclaveClientAppConstructorOptions, s as StackClientAppConstructorOptions, st as CurrentInternalUser, t as HexclaveClientApp, u as AdminProject, v as EmailOutboxListOptions, x as HexclaveAdminApp, y as EmailOutboxListResult } from "./client-app-
|
|
8
|
+
import { A as HexclaveServerApp, B as ServerListUsersOptions, C as HexclaveAdminAppConstructorOptions, D as StackAdminApp, F as StackServerAppConstructorOptions, G as ServerTeamUser, H as ServerTeamCreateOptions, I as EditableTeamMemberProfile, J as TeamInvitation, K as Team, L as ReceivedTeamInvitation, M as HexclaveServerAppConstructorOptions, N as StackServerApp, O as StackAdminAppConstructor, P as StackServerAppConstructor, Q as TeamUser, R as SentTeamInvitation, S as HexclaveAdminAppConstructor, St as User, U as ServerTeamMemberProfile, V as ServerTeam, W as ServerTeamUpdateOptions, Y as TeamMemberProfile, Z as TeamUpdateOptions, a as StackClientApp, b as EmailOutboxUpdateOptions, c as StackClientAppJson, ct as CurrentServerUser, d as AdminProjectCreateOptions, dt as OAuthProvider, f as AdminProjectUpdateOptions, gt as ServerUser, h as PushedConfigSource, ht as ServerOAuthProvider, i as HexclaveClientAppJson, it as Auth, j as HexclaveServerAppConstructor, k as StackAdminAppConstructorOptions, l as AdminOwnedProject, lt as CurrentUser, n as HexclaveClientAppConstructor, o as StackClientAppConstructor, ot as CurrentInternalServerUser, p as Project, q as TeamCreateOptions, r as HexclaveClientAppConstructorOptions, s as StackClientAppConstructorOptions, st as CurrentInternalUser, t as HexclaveClientApp, u as AdminProject, v as EmailOutboxListOptions, x as HexclaveAdminApp, y as EmailOutboxListResult } from "./client-app-BoOM8rxo.js";
|
|
9
9
|
import { a as AdminProjectConfigUpdateOptions, i as AdminProjectConfig, n as AdminEmailConfig, o as OAuthProviderConfig, r as AdminOAuthProviderConfig, s as ProjectConfig, t as AdminDomainConfig } from "./index-Dq4xsW7_.js";
|
|
10
10
|
import { r as getPagePrompt } from "./url-targets-BJgkwPGW.js";
|
|
11
11
|
import { getConvexProvidersConfig } from "./integrations/convex.js";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as _HexclaveAdminAppImplIncomplete } from "../../../../admin-app-impl-
|
|
1
|
+
import { t as _HexclaveAdminAppImplIncomplete } from "../../../../admin-app-impl-DHs4il4z.js";
|
|
2
2
|
export { _HexclaveAdminAppImplIncomplete };
|
|
@@ -512,6 +512,103 @@ function createMockDocument() {
|
|
|
512
512
|
}
|
|
513
513
|
(0, vitest.expect)(redirectedUrl).toBe("/settings?tab=profile");
|
|
514
514
|
});
|
|
515
|
+
(0, vitest.it)("restores a dropped after_auth_return_to from the sessionStorage mirror when redirecting after sign-in", async () => {
|
|
516
|
+
const previousWindow = globalThis.window;
|
|
517
|
+
const previousDocument = globalThis.document;
|
|
518
|
+
const hadPreviousWindow = Reflect.has(globalThis, "window");
|
|
519
|
+
const sessionStorageMap = /* @__PURE__ */ new Map();
|
|
520
|
+
const windowMock = {
|
|
521
|
+
location: { href: "https://demo.example.test/handler/sign-in?after_auth_return_to=%2Fmusic%3Ftrack%3D1" },
|
|
522
|
+
sessionStorage: {
|
|
523
|
+
getItem: (key) => sessionStorageMap.get(key) ?? null,
|
|
524
|
+
setItem: (key, value) => {
|
|
525
|
+
sessionStorageMap.set(key, value);
|
|
526
|
+
},
|
|
527
|
+
removeItem: (key) => {
|
|
528
|
+
sessionStorageMap.delete(key);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
Reflect.set(globalThis, "window", windowMock);
|
|
533
|
+
globalThis.document = createMockDocument();
|
|
534
|
+
try {
|
|
535
|
+
const clientApp = new ___interfaces_client_app_js.StackClientApp({
|
|
536
|
+
baseUrl: "http://localhost:12345",
|
|
537
|
+
projectId: "00000000-0000-4000-8000-000000000011",
|
|
538
|
+
publishableClientKey: "stack-pk-test",
|
|
539
|
+
tokenStore: "memory",
|
|
540
|
+
redirectMethod: "window",
|
|
541
|
+
noAutomaticPrefetch: true
|
|
542
|
+
});
|
|
543
|
+
windowMock.location.href = "https://demo.example.test/handler/mfa";
|
|
544
|
+
(0, vitest.expect)(await clientApp[______common_js.hexclaveAppInternalsSymbol].getRedirectToHandlerUrl("afterSignIn")).toBe("/music?track=1");
|
|
545
|
+
const noRedirectBackUrl = await clientApp[______common_js.hexclaveAppInternalsSymbol].getRedirectToHandlerUrl("afterSignIn", { noRedirectBack: true });
|
|
546
|
+
(0, vitest.expect)(new URL(noRedirectBackUrl, "https://demo.example.test").pathname).toBe("/");
|
|
547
|
+
} finally {
|
|
548
|
+
globalThis.document = previousDocument;
|
|
549
|
+
if (hadPreviousWindow) Reflect.set(globalThis, "window", previousWindow);
|
|
550
|
+
else Reflect.deleteProperty(globalThis, "window");
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
(0, vitest.it)("restores dropped cross-domain handoff state from the sessionStorage mirror when redirecting after sign-in", async () => {
|
|
554
|
+
const projectId = "00000000-0000-4000-8000-000000000012";
|
|
555
|
+
const previousWindow = globalThis.window;
|
|
556
|
+
const hadPreviousWindow = Reflect.has(globalThis, "window");
|
|
557
|
+
const sessionStorageMap = /* @__PURE__ */ new Map();
|
|
558
|
+
const handoffState = "mirror-handoff-state";
|
|
559
|
+
const handoffCodeChallenge = "abcdefghijklmnopqrstuvwxyzABCDEFG_0123456789-._~";
|
|
560
|
+
const handoffAfterCallbackRedirect = "https://demo.example.test/dashboard";
|
|
561
|
+
const redirectBackUrl = new URL("https://demo.example.test/handler/oauth-callback");
|
|
562
|
+
redirectBackUrl.searchParams.set("hexclave_cross_domain_auth", "1");
|
|
563
|
+
redirectBackUrl.searchParams.set("hexclave_cross_domain_state", handoffState);
|
|
564
|
+
redirectBackUrl.searchParams.set("hexclave_cross_domain_code_challenge", handoffCodeChallenge);
|
|
565
|
+
redirectBackUrl.searchParams.set("hexclave_cross_domain_after_callback_redirect_url", handoffAfterCallbackRedirect);
|
|
566
|
+
const arrivalUrl = new URL(`https://${projectId}.built-with-stack-auth.com/handler/sign-in`);
|
|
567
|
+
arrivalUrl.searchParams.set("after_auth_return_to", redirectBackUrl.toString());
|
|
568
|
+
arrivalUrl.searchParams.set("hexclave_cross_domain_state", handoffState);
|
|
569
|
+
arrivalUrl.searchParams.set("hexclave_cross_domain_code_challenge", handoffCodeChallenge);
|
|
570
|
+
arrivalUrl.searchParams.set("hexclave_cross_domain_after_callback_redirect_url", handoffAfterCallbackRedirect);
|
|
571
|
+
const previousDocument = globalThis.document;
|
|
572
|
+
const windowMock = {
|
|
573
|
+
location: { href: arrivalUrl.toString() },
|
|
574
|
+
sessionStorage: {
|
|
575
|
+
getItem: (key) => sessionStorageMap.get(key) ?? null,
|
|
576
|
+
setItem: (key, value) => {
|
|
577
|
+
sessionStorageMap.set(key, value);
|
|
578
|
+
},
|
|
579
|
+
removeItem: (key) => {
|
|
580
|
+
sessionStorageMap.delete(key);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
Reflect.set(globalThis, "window", windowMock);
|
|
585
|
+
globalThis.document = createMockDocument();
|
|
586
|
+
try {
|
|
587
|
+
const clientApp = new ___interfaces_client_app_js.StackClientApp({
|
|
588
|
+
baseUrl: "http://localhost:12345",
|
|
589
|
+
projectId,
|
|
590
|
+
publishableClientKey: "stack-pk-test",
|
|
591
|
+
tokenStore: "memory",
|
|
592
|
+
redirectMethod: "window",
|
|
593
|
+
noAutomaticPrefetch: true
|
|
594
|
+
});
|
|
595
|
+
const crossDomainAuthorizeRedirect = "https://demo.example.test/handler/oauth-callback?code=minted-code&state=mirror-handoff-state";
|
|
596
|
+
const createCrossDomainAuthRedirectUrlSpy = vitest.vi.spyOn(clientApp, "_createCrossDomainAuthRedirectUrl").mockResolvedValue(crossDomainAuthorizeRedirect);
|
|
597
|
+
windowMock.location.href = `https://${projectId}.built-with-stack-auth.com/handler/sign-in`;
|
|
598
|
+
const redirectUrl = await clientApp[______common_js.hexclaveAppInternalsSymbol].getRedirectToHandlerUrl("afterSignIn");
|
|
599
|
+
(0, vitest.expect)(createCrossDomainAuthRedirectUrlSpy).toHaveBeenCalledWith(vitest.expect.objectContaining({
|
|
600
|
+
redirectUri: redirectBackUrl.toString(),
|
|
601
|
+
state: handoffState,
|
|
602
|
+
codeChallenge: handoffCodeChallenge,
|
|
603
|
+
afterCallbackRedirectUrl: handoffAfterCallbackRedirect
|
|
604
|
+
}));
|
|
605
|
+
(0, vitest.expect)(redirectUrl).toBe(crossDomainAuthorizeRedirect);
|
|
606
|
+
} finally {
|
|
607
|
+
globalThis.document = previousDocument;
|
|
608
|
+
if (hadPreviousWindow) Reflect.set(globalThis, "window", previousWindow);
|
|
609
|
+
else Reflect.deleteProperty(globalThis, "window");
|
|
610
|
+
}
|
|
611
|
+
});
|
|
515
612
|
(0, vitest.it)("ignores stale session callbacks after a newer refresh token owns the token store", async () => {
|
|
516
613
|
const clientApp = new ___interfaces_client_app_js.StackClientApp({
|
|
517
614
|
baseUrl: "http://localhost:12345",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-app-impl.cross-domain.test.js","names":["StackClientApp","hexclaveAppInternalsSymbol","AccessToken","Store","vi"],"sources":["../../../../../src/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { describe, expect, it, vi } from \"vitest\";\nimport { AccessToken } from \"@hexclave/shared/dist/sessions\";\nimport { Store } from \"@hexclave/shared/dist/utils/stores\";\nimport { hexclaveAppInternalsSymbol } from \"../../common\";\nimport { StackClientApp } from \"../interfaces/client-app\";\n\nfunction createAccessTokenString(refreshTokenId: string): string {\n const encode = (value: unknown) => Buffer.from(JSON.stringify(value)).toString(\"base64url\");\n const nowSeconds = Math.floor(Date.now() / 1000);\n return [\n encode({ alg: \"none\", typ: \"JWT\" }),\n encode({\n sub: \"user-id\",\n exp: nowSeconds + 60,\n iat: nowSeconds,\n iss: \"https://api.example.test\",\n aud: \"project-id\",\n project_id: \"project-id\",\n branch_id: \"main\",\n refresh_token_id: refreshTokenId,\n role: \"authenticated\",\n name: null,\n email: null,\n email_verified: false,\n selected_team_id: null,\n signed_up_at: nowSeconds,\n is_anonymous: false,\n is_restricted: false,\n restricted_reason: null,\n requires_totp_mfa: false,\n }),\n \"\",\n ].join(\".\");\n}\n\nfunction createMockDocument(): Document {\n const cookieJar = new Map<string, string>();\n return {\n get cookie() {\n return [...cookieJar.entries()].map(([key, value]) => `${key}=${value}`).join(\"; \");\n },\n set cookie(str: string) {\n const [nameValue] = str.split(\";\");\n const eqIndex = nameValue.indexOf(\"=\");\n if (eqIndex < 0) return;\n cookieJar.set(nameValue.slice(0, eqIndex).trim(), nameValue.slice(eqIndex + 1).trim());\n },\n createElement: () => ({}),\n } as any;\n}\n\ndescribe(\"StackClientApp cross-domain auth\", () => {\n it(\"exposes redirect-back-aware handler URLs for devtool previews\", async () => {\n const previousWindow = Reflect.get(globalThis, \"window\");\n const hadPreviousWindow = Reflect.has(globalThis, \"window\");\n Reflect.set(globalThis, \"window\", {\n location: {\n href: \"http://localhost/music?track=1#song\",\n },\n });\n\n try {\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000000\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"none\",\n urls: {\n signIn: \"/handler/sign-in\",\n },\n noAutomaticPrefetch: true,\n });\n\n const redirectUrl = await clientApp[hexclaveAppInternalsSymbol].getRedirectToHandlerUrl(\"signIn\");\n\n const resolved = new URL(redirectUrl, \"http://localhost\");\n expect(resolved.pathname).toBe(\"/handler/sign-in\");\n expect(resolved.searchParams.get(\"after_auth_return_to\")).toBe(\"/music?track=1#song\");\n } finally {\n if (hadPreviousWindow) {\n Reflect.set(globalThis, \"window\", previousWindow);\n } else {\n Reflect.deleteProperty(globalThis, \"window\");\n }\n }\n });\n\n it(\"uses the fresh post-auth refresh token when minting a cross-domain handoff\", async () => {\n const freshAccessToken = createAccessTokenString(\"fresh-refresh-token-id\");\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000000\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: {\n accessToken: createAccessTokenString(\"stale-refresh-token-id\"),\n refreshToken: \"stale-refresh-token\",\n },\n redirectMethod: \"none\",\n noAutomaticPrefetch: true,\n });\n\n const clientInterface = Reflect.get(clientApp, \"_interface\");\n const originalSendClientRequest = Reflect.get(clientInterface, \"sendClientRequest\");\n const originalFetchNewAccessToken = Reflect.get(clientInterface, \"fetchNewAccessToken\");\n const capturedRefreshTokens: string[] = [];\n const capturedAccessTokenRefreshTokenIds: string[] = [];\n const refreshedRawRefreshTokens: string[] = [];\n\n Reflect.set(clientInterface, \"sendClientRequest\", async (_path: unknown, _requestOptions: unknown, session: unknown) => {\n const getRefreshToken = Reflect.get(session ?? {}, \"getRefreshToken\");\n const getOrFetchLikelyValidTokens = Reflect.get(session ?? {}, \"getOrFetchLikelyValidTokens\");\n if (typeof getRefreshToken !== \"function\") {\n throw new Error(\"Expected cross-domain auth to pass a session to the client interface.\");\n }\n if (typeof getOrFetchLikelyValidTokens !== \"function\") {\n throw new Error(\"Expected cross-domain auth to pass a session with token accessors.\");\n }\n const refreshToken = getRefreshToken.call(session);\n const refreshTokenString = Reflect.get(refreshToken ?? {}, \"token\");\n if (typeof refreshTokenString !== \"string\") {\n throw new Error(\"Expected cross-domain auth to pass a refresh-token-backed session.\");\n }\n capturedRefreshTokens.push(refreshTokenString);\n const tokens = await getOrFetchLikelyValidTokens.call(session, 0, null);\n capturedAccessTokenRefreshTokenIds.push(tokens.accessToken.payload.refresh_token_id);\n return {\n ok: true,\n json: async () => ({ redirect_url: \"https://example.com/handler/oauth-callback?code=handoff-code&state=handoff-state\" }),\n };\n });\n Reflect.set(clientInterface, \"fetchNewAccessToken\", async (refreshToken: unknown) => {\n const refreshTokenString = Reflect.get(refreshToken ?? {}, \"token\");\n if (typeof refreshTokenString !== \"string\") {\n throw new Error(\"Expected refresh token while fetching a new access token.\");\n }\n refreshedRawRefreshTokens.push(refreshTokenString);\n return AccessToken.createIfValid(freshAccessToken) ?? (() => {\n throw new Error(\"Expected test access token to be valid\");\n })();\n });\n\n try {\n const createCrossDomainAuthRedirectUrl = Reflect.get(clientApp, \"_createCrossDomainAuthRedirectUrl\");\n if (typeof createCrossDomainAuthRedirectUrl !== \"function\") {\n throw new Error(\"Expected StackClientApp to expose _createCrossDomainAuthRedirectUrl in tests.\");\n }\n\n await expect(createCrossDomainAuthRedirectUrl.call(clientApp, {\n redirectUri: \"https://example.com/handler/oauth-callback\",\n state: \"handoff-state\",\n codeChallenge: \"abcdefghijklmnopqrstuvwxyzABCDEFG_0123456789-._~\",\n afterCallbackRedirectUrl: \"https://example.com/account-settings\",\n overrideTokenStoreInit: {\n accessToken: createAccessTokenString(\"fresh-stale-refresh-token-id\"),\n refreshToken: \"fresh-refresh-token\",\n },\n })).resolves.toBe(\"https://example.com/handler/oauth-callback?code=handoff-code&state=handoff-state\");\n } finally {\n Reflect.set(clientInterface, \"sendClientRequest\", originalSendClientRequest);\n Reflect.set(clientInterface, \"fetchNewAccessToken\", originalFetchNewAccessToken);\n }\n\n expect(refreshedRawRefreshTokens).toEqual([\"fresh-refresh-token\"]);\n expect(capturedRefreshTokens).toEqual([\"fresh-refresh-token\"]);\n expect(capturedAccessTokenRefreshTokenIds).toEqual([\"fresh-refresh-token-id\"]);\n });\n\n it(\"uses a fresh nested OAuth state while preserving the outer cross-domain return state\", async () => {\n const projectId = \"00000000-0000-4000-8000-000000000002\";\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId,\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n urls: {\n default: { type: \"hosted\" },\n },\n noAutomaticPrefetch: true,\n });\n const outerState = \"outer-cross-domain-state\";\n const outerCodeChallenge = \"abcdefghijklmnopqrstuvwxyzABCDEFG_0123456789-._~\";\n const currentUrl = new URL(`https://${projectId}.example-stack-hosted.test/handler/sign-in`);\n currentUrl.searchParams.set(\"after_auth_return_to\", `https://demo.stack-auth.com/?hexclave_cross_domain_auth=1&hexclave_cross_domain_state=${outerState}`);\n currentUrl.searchParams.set(\"hexclave_cross_domain_state\", outerState);\n currentUrl.searchParams.set(\"hexclave_cross_domain_code_challenge\", outerCodeChallenge);\n currentUrl.searchParams.set(\"hexclave_cross_domain_after_callback_redirect_url\", \"https://demo.stack-auth.com/\");\n currentUrl.searchParams.set(\"stack_nested_cross_domain_auth_refresh_token_id\", \"source-session\");\n currentUrl.searchParams.set(\"stack_nested_cross_domain_auth_callback_url\", \"https://demo.stack-auth.com/\");\n\n const previousWindow = globalThis.window;\n const previousDocument = globalThis.document;\n let redirectedUrl = \"\";\n vi.spyOn(clientApp as any, \"_fetchCurrentRefreshTokenIdIfSignedIn\").mockResolvedValue(null);\n vi.spyOn(clientApp as any, \"_getCrossDomainHandoffParamsForRedirect\").mockResolvedValue({\n state: \"fresh-nested-state\",\n codeChallenge: \"fresh-nested-code-challenge\",\n });\n vi.spyOn(clientApp as any, \"_isTrusted\").mockResolvedValue(true);\n\n globalThis.document = createMockDocument();\n globalThis.window = {\n location: {\n href: currentUrl.toString(),\n replace: (url: string) => {\n redirectedUrl = url;\n throw new Error(\"INTENTIONAL_TEST_ABORT\");\n },\n },\n } as any;\n\n try {\n await expect((clientApp as any)._maybeHandleNestedCrossDomainAuth()).rejects.toThrowError(\"INTENTIONAL_TEST_ABORT\");\n } finally {\n globalThis.window = previousWindow;\n globalThis.document = previousDocument;\n }\n\n const redirectUrl = new URL(redirectedUrl);\n expect(redirectUrl.searchParams.get(\"state\")).toBe(\"fresh-nested-state\");\n expect(redirectUrl.searchParams.get(\"code_challenge\")).toBe(\"fresh-nested-code-challenge\");\n const redirectUri = new URL(redirectUrl.searchParams.get(\"redirect_uri\") ?? \"\");\n expect(redirectUri.searchParams.get(\"hexclave_cross_domain_state\")).toBe(outerState);\n expect(redirectUri.searchParams.get(\"hexclave_cross_domain_code_challenge\")).toBe(outerCodeChallenge);\n expect(redirectUri.searchParams.get(\"hexclave_cross_domain_after_callback_redirect_url\")).toBe(\"https://demo.stack-auth.com/\");\n });\n\n it(\"clears a stale target-domain session before deferring to the source-domain session\", async () => {\n const projectId = \"00000000-0000-4000-8000-000000000006\";\n const hostedAccessToken = createAccessTokenString(\"hosted-old-refresh-token-id\");\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId,\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n urls: {\n default: { type: \"hosted\" },\n },\n noAutomaticPrefetch: true,\n });\n const tokenStore = Reflect.get(clientApp, \"_memoryTokenStore\");\n if (!(tokenStore instanceof Store)) {\n throw new Error(\"Expected StackClientApp to use a memory token store in this test.\");\n }\n tokenStore.set({\n refreshToken: \"hosted-old-refresh-token\",\n accessToken: hostedAccessToken,\n });\n\n const currentUrl = new URL(`https://${projectId}.example-stack-hosted.test/handler/sign-in`);\n currentUrl.searchParams.set(\"stack_nested_cross_domain_auth_refresh_token_id\", \"source-anonymous-refresh-token-id\");\n currentUrl.searchParams.set(\"stack_nested_cross_domain_auth_callback_url\", \"https://demo.stack-auth.com/handler/oauth-callback\");\n currentUrl.searchParams.set(\"hexclave_cross_domain_state\", \"outer-state\");\n currentUrl.searchParams.set(\"hexclave_cross_domain_code_challenge\", \"outer-code-challenge\");\n currentUrl.searchParams.set(\"hexclave_cross_domain_after_callback_redirect_url\", \"https://demo.stack-auth.com/app\");\n\n const previousWindow = globalThis.window;\n const previousDocument = globalThis.document;\n let redirectedUrl = \"\";\n const clientInterface = Reflect.get(clientApp, \"_interface\");\n const originalFetchNewAccessToken = Reflect.get(clientInterface, \"fetchNewAccessToken\");\n Reflect.set(clientInterface, \"fetchNewAccessToken\", async () => {\n return AccessToken.createIfValid(hostedAccessToken) ?? (() => {\n throw new Error(\"Expected test access token to be valid\");\n })();\n });\n vi.spyOn(clientApp as any, \"_isTrusted\").mockResolvedValue(true);\n\n globalThis.document = createMockDocument();\n globalThis.window = {\n location: {\n href: currentUrl.toString(),\n replace: (url: string) => {\n redirectedUrl = url;\n throw new Error(\"INTENTIONAL_TEST_ABORT\");\n },\n },\n } as any;\n\n try {\n await expect((clientApp as any)._maybeHandleNestedCrossDomainAuth()).rejects.toThrowError(\"INTENTIONAL_TEST_ABORT\");\n } finally {\n Reflect.set(clientInterface, \"fetchNewAccessToken\", originalFetchNewAccessToken);\n globalThis.window = previousWindow;\n globalThis.document = previousDocument;\n }\n\n expect(tokenStore.get()).toEqual({\n refreshToken: null,\n accessToken: null,\n });\n expect(new URL(redirectedUrl).origin).toBe(\"https://demo.stack-auth.com\");\n });\n\n it(\"uses the latest browser refresh cookie before computing nested cross-domain session IDs\", async () => {\n const projectId = \"00000000-0000-4000-8000-000000000007\";\n const previousWindow = globalThis.window;\n const previousDocument = globalThis.document;\n\n globalThis.document = createMockDocument();\n globalThis.window = {\n location: {\n href: \"https://demo.stack-auth.com/\",\n protocol: \"https:\",\n hostname: \"demo.stack-auth.com\",\n },\n addEventListener: () => {},\n removeEventListener: () => {},\n } as any;\n\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId,\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"cookie\",\n redirectMethod: \"none\",\n noAutomaticPrefetch: true,\n });\n const clientInterface = Reflect.get(clientApp, \"_interface\");\n const originalFetchNewAccessToken = Reflect.get(clientInterface, \"fetchNewAccessToken\");\n const refreshedRawRefreshTokens: string[] = [];\n\n // Cookie-store writes queue a background trusted-parent-domain lookup. Without this stub, that\n // lookup fetches the (unreachable) baseUrl with retries while holding the global store lock,\n // which starves any later test that needs the write lock (e.g. signOut). Not restored on\n // purpose: queued tasks can still run after this test body finishes.\n vi.spyOn(clientApp as any, \"_getTrustedParentDomain\").mockResolvedValue(null);\n\n try {\n const getBrowserCookieTokenStore = Reflect.get(clientApp, \"_getBrowserCookieTokenStore\");\n if (typeof getBrowserCookieTokenStore !== \"function\") {\n throw new Error(\"Expected StackClientApp to expose _getBrowserCookieTokenStore in tests.\");\n }\n const tokenStore = getBrowserCookieTokenStore.call(clientApp);\n tokenStore.set({\n refreshToken: \"old-refresh-token\",\n accessToken: createAccessTokenString(\"old-refresh-token-id\"),\n });\n\n document.cookie = `__Host-hexclave-refresh-${projectId}--default=${JSON.stringify({\n refresh_token: \"new-refresh-token\",\n updated_at_millis: 1,\n })}`;\n Reflect.set(clientInterface, \"fetchNewAccessToken\", async (refreshToken: unknown) => {\n const refreshTokenString = Reflect.get(refreshToken ?? {}, \"token\");\n if (typeof refreshTokenString !== \"string\") {\n throw new Error(\"Expected refresh token while fetching a new access token.\");\n }\n refreshedRawRefreshTokens.push(refreshTokenString);\n return AccessToken.createIfValid(createAccessTokenString(\"new-refresh-token-id\")) ?? (() => {\n throw new Error(\"Expected test access token to be valid\");\n })();\n });\n\n const fetchCurrentRefreshTokenIdIfSignedIn = Reflect.get(clientApp, \"_fetchCurrentRefreshTokenIdIfSignedIn\");\n if (typeof fetchCurrentRefreshTokenIdIfSignedIn !== \"function\") {\n throw new Error(\"Expected StackClientApp to expose _fetchCurrentRefreshTokenIdIfSignedIn in tests.\");\n }\n await expect(fetchCurrentRefreshTokenIdIfSignedIn.call(clientApp, {\n awaitPendingAuthResolutions: false,\n })).resolves.toBe(\"new-refresh-token-id\");\n } finally {\n Reflect.set(clientInterface, \"fetchNewAccessToken\", originalFetchNewAccessToken);\n globalThis.window = previousWindow;\n globalThis.document = previousDocument;\n }\n\n expect(refreshedRawRefreshTokens).toEqual([\"new-refresh-token\"]);\n });\n\n it(\"does not re-bounce nested cross-domain auth after the OAuth callback consumed code+state from the URL\", async () => {\n const projectId = \"00000000-0000-4000-8000-000000000008\";\n const previousWindow = globalThis.window;\n const previousDocument = globalThis.document;\n\n const strippedUrl = new URL(`https://${projectId}.example-stack-hosted.test/handler/sign-in`);\n strippedUrl.searchParams.set(\"stack_nested_cross_domain_auth_refresh_token_id\", \"source-refresh-token-id\");\n strippedUrl.searchParams.set(\"stack_nested_cross_domain_auth_callback_url\", \"https://demo.stack-auth.com/\");\n const urlAtConstructionTime = new URL(strippedUrl);\n urlAtConstructionTime.searchParams.set(\"code\", \"one-time-code\");\n urlAtConstructionTime.searchParams.set(\"state\", \"nested-oauth-state\");\n\n // Construct before installing the window mock so the constructor does not schedule its own\n // nested-auth resolution; the assertions below drive the handler explicitly.\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId,\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n noAutomaticPrefetch: true,\n });\n\n globalThis.document = createMockDocument();\n globalThis.window = {\n location: {\n href: strippedUrl.toString(),\n replace: () => {\n throw new Error(\"INTENTIONAL_TEST_ABORT\");\n },\n },\n } as any;\n\n vi.spyOn(clientApp as any, \"_fetchCurrentRefreshTokenIdIfSignedIn\").mockResolvedValue(null);\n vi.spyOn(clientApp as any, \"_getCrossDomainHandoffParamsForRedirect\").mockResolvedValue({\n state: \"fresh-nested-state\",\n codeChallenge: \"fresh-nested-code-challenge\",\n });\n vi.spyOn(clientApp as any, \"_isTrusted\").mockResolvedValue(true);\n\n try {\n // Without the construction-time URL, the handler re-bounces (location.replace aborts).\n await expect((clientApp as any)._maybeHandleNestedCrossDomainAuth()).rejects.toThrowError(\"INTENTIONAL_TEST_ABORT\");\n // With it, the in-flight OAuth callback wins and the handler stands down.\n await expect((clientApp as any)._maybeHandleNestedCrossDomainAuth(urlAtConstructionTime)).resolves.toBe(false);\n // The live-URL guard must also stand down on its own when code+state are still present.\n (globalThis.window as any).location.href = urlAtConstructionTime.toString();\n await expect((clientApp as any)._maybeHandleNestedCrossDomainAuth()).resolves.toBe(false);\n } finally {\n globalThis.window = previousWindow;\n globalThis.document = previousDocument;\n }\n });\n\n it(\"passes the construction-time URL to the nested cross-domain auth handler\", async () => {\n const projectId = \"00000000-0000-4000-8000-000000000009\";\n const previousWindow = globalThis.window;\n const previousDocument = globalThis.document;\n\n const callbackUrl = new URL(`https://${projectId}.example-stack-hosted.test/handler/sign-in`);\n callbackUrl.searchParams.set(\"stack_nested_cross_domain_auth_refresh_token_id\", \"source-refresh-token-id\");\n callbackUrl.searchParams.set(\"code\", \"one-time-code\");\n callbackUrl.searchParams.set(\"state\", \"nested-oauth-state\");\n const strippedUrl = new URL(callbackUrl);\n strippedUrl.searchParams.delete(\"code\");\n strippedUrl.searchParams.delete(\"state\");\n\n globalThis.document = createMockDocument();\n globalThis.window = {\n location: {\n href: callbackUrl.toString(),\n },\n } as any;\n\n const nestedAuthSpy = vi.spyOn(StackClientApp.prototype as any, \"_maybeHandleNestedCrossDomainAuth\").mockResolvedValue(false);\n\n try {\n new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId,\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n noAutomaticPrefetch: true,\n });\n\n // Simulate consumeOAuthCallbackQueryParams stripping code+state before microtasks run.\n (globalThis.window as any).location.href = strippedUrl.toString();\n await new Promise((resolve) => setTimeout(resolve, 0));\n\n expect(nestedAuthSpy).toHaveBeenCalledTimes(1);\n const urlArgument = nestedAuthSpy.mock.calls[0][0] as URL;\n expect(urlArgument).toBeInstanceOf(URL);\n expect(urlArgument.searchParams.get(\"code\")).toBe(\"one-time-code\");\n expect(urlArgument.searchParams.get(\"state\")).toBe(\"nested-oauth-state\");\n } finally {\n nestedAuthSpy.mockRestore();\n globalThis.window = previousWindow;\n globalThis.document = previousDocument;\n }\n });\n\n it(\"redirects hosted current-page OAuth callback errors to the hosted error handler during startup\", async () => {\n const projectId = \"00000000-0000-4000-8000-000000000010\";\n const previousWindow = globalThis.window;\n const previousDocument = globalThis.document;\n const callbackUrl = new URL(\"https://demo.stack-auth.com/dashboard\");\n callbackUrl.searchParams.set(\"errorCode\", \"SIGN_UP_REJECTED\");\n callbackUrl.searchParams.set(\"message\", \"Your sign up was rejected by an administrator's sign-up rule.\");\n callbackUrl.searchParams.set(\"details\", JSON.stringify({\n message: \"Your sign up was rejected by an administrator's sign-up rule.\",\n }));\n let currentHref = callbackUrl.toString();\n let redirectedUrl = \"\";\n const redirectSpy = vi.spyOn(StackClientApp.prototype as any, \"_redirectTo\").mockImplementation(async (...args: unknown[]) => {\n const options = args[0] as { url: string | URL };\n redirectedUrl = options.url.toString();\n });\n\n globalThis.document = createMockDocument();\n globalThis.window = {\n location: {\n get href() {\n return currentHref;\n },\n set href(value: string) {\n currentHref = value;\n },\n origin: callbackUrl.origin,\n },\n history: {\n replaceState: (_state: unknown, _title: string, url: string) => {\n currentHref = new URL(url, currentHref).toString();\n },\n },\n addEventListener: () => {},\n removeEventListener: () => {},\n } as any;\n\n try {\n new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId,\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n urls: {\n default: { type: \"hosted\" },\n },\n noAutomaticPrefetch: true,\n });\n\n await new Promise((resolve) => setTimeout(resolve, 0));\n await new Promise((resolve) => setTimeout(resolve, 0));\n } finally {\n redirectSpy.mockRestore();\n globalThis.window = previousWindow;\n globalThis.document = previousDocument;\n }\n\n const errorUrl = new URL(redirectedUrl);\n expect(errorUrl.origin).toBe(`https://${projectId}.built-with-stack-auth.com`);\n expect(errorUrl.pathname).toBe(\"/handler/error\");\n expect(errorUrl.searchParams.get(\"errorCode\")).toBe(\"SIGN_UP_REJECTED\");\n expect(errorUrl.searchParams.get(\"message\")).toBe(\"Your sign up was rejected by an administrator's sign-up rule.\");\n expect(new URL(currentHref).searchParams.has(\"errorCode\")).toBe(false);\n });\n\n it(\"uses direct sign-out instead of hosted sign-out redirects when code execution is available\", async () => {\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000003\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n urls: {\n handler: \"/handler\",\n signOut: { type: \"hosted\" },\n },\n noAutomaticPrefetch: true,\n });\n const signOutSpy = vi.spyOn(clientApp, \"signOut\").mockRejectedValue(new Error(\"INTENTIONAL_TEST_ABORT\"));\n\n try {\n await expect(clientApp.redirectToSignOut()).rejects.toThrowError(\"INTENTIONAL_TEST_ABORT\");\n expect(signOutSpy).toHaveBeenCalledWith();\n } finally {\n signOutSpy.mockRestore();\n }\n });\n\n it(\"throws when public app.urls reads would return hosted component URLs\", () => {\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000003\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n urls: {\n default: { type: \"hosted\" },\n },\n noAutomaticPrefetch: true,\n });\n\n expect(() => clientApp.urls.signIn).toThrowError(/app\\.urls\\.signIn cannot be used when this app is configured to use hosted components.*Use app\\.redirectToSignIn\\(\\) instead/s);\n expect(() => clientApp.urls.signOut).toThrowError(/app\\.urls\\.signOut cannot be used when this app is configured to use hosted components.*Use app\\.redirectToSignOut\\(\\) instead/s);\n expect(clientApp.urls.afterSignIn).toBe(\"/\");\n });\n\n it(\"keeps public app.urls reads available for non-hosted targets\", () => {\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000003\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n urls: {\n handler: \"/custom-handler\",\n },\n noAutomaticPrefetch: true,\n });\n\n expect(clientApp.urls.signIn).toBe(\"/custom-handler/sign-in\");\n });\n\n it(\"keeps default hosted signOut() on the source domain when afterSignOut is not configured\", async () => {\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000004\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n urls: {\n default: { type: \"hosted\" },\n },\n noAutomaticPrefetch: true,\n });\n const currentHref = \"https://demo.stack-auth.com/settings?tab=profile\";\n\n const clientInterface = Reflect.get(clientApp, \"_interface\");\n const originalSignOut = Reflect.get(clientInterface, \"signOut\");\n Reflect.set(clientInterface, \"signOut\", async () => {});\n const previousWindow = globalThis.window;\n const previousDocument = globalThis.document;\n let redirectedUrl = \"\";\n\n globalThis.document = createMockDocument();\n globalThis.window = {\n location: {\n href: currentHref,\n replace: (url: string) => {\n redirectedUrl = url;\n throw new Error(\"INTENTIONAL_TEST_ABORT\");\n },\n },\n } as any;\n\n try {\n const signOut = Reflect.get(clientApp, \"_signOut\");\n if (typeof signOut !== \"function\") {\n throw new Error(\"Expected StackClientApp to expose _signOut in tests.\");\n }\n await expect(signOut.call(clientApp, Reflect.get(clientInterface, \"createSession\").call(clientInterface, {\n refreshToken: null,\n }))).rejects.toThrowError(\"INTENTIONAL_TEST_ABORT\");\n } finally {\n Reflect.set(clientInterface, \"signOut\", originalSignOut);\n globalThis.window = previousWindow;\n globalThis.document = previousDocument;\n }\n\n expect(redirectedUrl).toBe(\"/settings?tab=profile\");\n });\n\n it(\"ignores stale session callbacks after a newer refresh token owns the token store\", async () => {\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000005\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"none\",\n noAutomaticPrefetch: true,\n });\n const oldAccessToken = createAccessTokenString(\"old-refresh-token-id\");\n const refreshedOldAccessToken = createAccessTokenString(\"refreshed-old-refresh-token-id\");\n const newAccessToken = createAccessTokenString(\"new-refresh-token-id\");\n const tokenStore = new Store({\n refreshToken: \"old-refresh-token\",\n accessToken: oldAccessToken,\n });\n const clientInterface = Reflect.get(clientApp, \"_interface\");\n const originalFetchNewAccessToken = Reflect.get(clientInterface, \"fetchNewAccessToken\");\n Reflect.set(clientInterface, \"fetchNewAccessToken\", async () => {\n return AccessToken.createIfValid(refreshedOldAccessToken) ?? (() => {\n throw new Error(\"Expected test access token to be valid\");\n })();\n });\n\n try {\n const getSessionFromTokenStore = Reflect.get(clientApp, \"_getSessionFromTokenStore\");\n if (typeof getSessionFromTokenStore !== \"function\") {\n throw new Error(\"Expected StackClientApp to expose _getSessionFromTokenStore in tests.\");\n }\n const oldSession = getSessionFromTokenStore.call(clientApp, tokenStore);\n tokenStore.set({\n refreshToken: \"new-refresh-token\",\n accessToken: newAccessToken,\n });\n\n await oldSession.fetchNewTokens();\n expect(tokenStore.get()).toEqual({\n refreshToken: \"new-refresh-token\",\n accessToken: newAccessToken,\n });\n\n oldSession.markInvalid();\n expect(tokenStore.get()).toEqual({\n refreshToken: \"new-refresh-token\",\n accessToken: newAccessToken,\n });\n } finally {\n Reflect.set(clientInterface, \"fetchNewAccessToken\", originalFetchNewAccessToken);\n }\n });\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client-app-impl.cross-domain.test.js","names":["StackClientApp","hexclaveAppInternalsSymbol","AccessToken","Store","vi","expect"],"sources":["../../../../../src/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { describe, expect, it, vi } from \"vitest\";\nimport { AccessToken } from \"@hexclave/shared/dist/sessions\";\nimport { Store } from \"@hexclave/shared/dist/utils/stores\";\nimport { hexclaveAppInternalsSymbol } from \"../../common\";\nimport { StackClientApp } from \"../interfaces/client-app\";\n\nfunction createAccessTokenString(refreshTokenId: string): string {\n const encode = (value: unknown) => Buffer.from(JSON.stringify(value)).toString(\"base64url\");\n const nowSeconds = Math.floor(Date.now() / 1000);\n return [\n encode({ alg: \"none\", typ: \"JWT\" }),\n encode({\n sub: \"user-id\",\n exp: nowSeconds + 60,\n iat: nowSeconds,\n iss: \"https://api.example.test\",\n aud: \"project-id\",\n project_id: \"project-id\",\n branch_id: \"main\",\n refresh_token_id: refreshTokenId,\n role: \"authenticated\",\n name: null,\n email: null,\n email_verified: false,\n selected_team_id: null,\n signed_up_at: nowSeconds,\n is_anonymous: false,\n is_restricted: false,\n restricted_reason: null,\n requires_totp_mfa: false,\n }),\n \"\",\n ].join(\".\");\n}\n\nfunction createMockDocument(): Document {\n const cookieJar = new Map<string, string>();\n return {\n get cookie() {\n return [...cookieJar.entries()].map(([key, value]) => `${key}=${value}`).join(\"; \");\n },\n set cookie(str: string) {\n const [nameValue] = str.split(\";\");\n const eqIndex = nameValue.indexOf(\"=\");\n if (eqIndex < 0) return;\n cookieJar.set(nameValue.slice(0, eqIndex).trim(), nameValue.slice(eqIndex + 1).trim());\n },\n createElement: () => ({}),\n } as any;\n}\n\ndescribe(\"StackClientApp cross-domain auth\", () => {\n it(\"exposes redirect-back-aware handler URLs for devtool previews\", async () => {\n const previousWindow = Reflect.get(globalThis, \"window\");\n const hadPreviousWindow = Reflect.has(globalThis, \"window\");\n Reflect.set(globalThis, \"window\", {\n location: {\n href: \"http://localhost/music?track=1#song\",\n },\n });\n\n try {\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000000\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"none\",\n urls: {\n signIn: \"/handler/sign-in\",\n },\n noAutomaticPrefetch: true,\n });\n\n const redirectUrl = await clientApp[hexclaveAppInternalsSymbol].getRedirectToHandlerUrl(\"signIn\");\n\n const resolved = new URL(redirectUrl, \"http://localhost\");\n expect(resolved.pathname).toBe(\"/handler/sign-in\");\n expect(resolved.searchParams.get(\"after_auth_return_to\")).toBe(\"/music?track=1#song\");\n } finally {\n if (hadPreviousWindow) {\n Reflect.set(globalThis, \"window\", previousWindow);\n } else {\n Reflect.deleteProperty(globalThis, \"window\");\n }\n }\n });\n\n it(\"uses the fresh post-auth refresh token when minting a cross-domain handoff\", async () => {\n const freshAccessToken = createAccessTokenString(\"fresh-refresh-token-id\");\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000000\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: {\n accessToken: createAccessTokenString(\"stale-refresh-token-id\"),\n refreshToken: \"stale-refresh-token\",\n },\n redirectMethod: \"none\",\n noAutomaticPrefetch: true,\n });\n\n const clientInterface = Reflect.get(clientApp, \"_interface\");\n const originalSendClientRequest = Reflect.get(clientInterface, \"sendClientRequest\");\n const originalFetchNewAccessToken = Reflect.get(clientInterface, \"fetchNewAccessToken\");\n const capturedRefreshTokens: string[] = [];\n const capturedAccessTokenRefreshTokenIds: string[] = [];\n const refreshedRawRefreshTokens: string[] = [];\n\n Reflect.set(clientInterface, \"sendClientRequest\", async (_path: unknown, _requestOptions: unknown, session: unknown) => {\n const getRefreshToken = Reflect.get(session ?? {}, \"getRefreshToken\");\n const getOrFetchLikelyValidTokens = Reflect.get(session ?? {}, \"getOrFetchLikelyValidTokens\");\n if (typeof getRefreshToken !== \"function\") {\n throw new Error(\"Expected cross-domain auth to pass a session to the client interface.\");\n }\n if (typeof getOrFetchLikelyValidTokens !== \"function\") {\n throw new Error(\"Expected cross-domain auth to pass a session with token accessors.\");\n }\n const refreshToken = getRefreshToken.call(session);\n const refreshTokenString = Reflect.get(refreshToken ?? {}, \"token\");\n if (typeof refreshTokenString !== \"string\") {\n throw new Error(\"Expected cross-domain auth to pass a refresh-token-backed session.\");\n }\n capturedRefreshTokens.push(refreshTokenString);\n const tokens = await getOrFetchLikelyValidTokens.call(session, 0, null);\n capturedAccessTokenRefreshTokenIds.push(tokens.accessToken.payload.refresh_token_id);\n return {\n ok: true,\n json: async () => ({ redirect_url: \"https://example.com/handler/oauth-callback?code=handoff-code&state=handoff-state\" }),\n };\n });\n Reflect.set(clientInterface, \"fetchNewAccessToken\", async (refreshToken: unknown) => {\n const refreshTokenString = Reflect.get(refreshToken ?? {}, \"token\");\n if (typeof refreshTokenString !== \"string\") {\n throw new Error(\"Expected refresh token while fetching a new access token.\");\n }\n refreshedRawRefreshTokens.push(refreshTokenString);\n return AccessToken.createIfValid(freshAccessToken) ?? (() => {\n throw new Error(\"Expected test access token to be valid\");\n })();\n });\n\n try {\n const createCrossDomainAuthRedirectUrl = Reflect.get(clientApp, \"_createCrossDomainAuthRedirectUrl\");\n if (typeof createCrossDomainAuthRedirectUrl !== \"function\") {\n throw new Error(\"Expected StackClientApp to expose _createCrossDomainAuthRedirectUrl in tests.\");\n }\n\n await expect(createCrossDomainAuthRedirectUrl.call(clientApp, {\n redirectUri: \"https://example.com/handler/oauth-callback\",\n state: \"handoff-state\",\n codeChallenge: \"abcdefghijklmnopqrstuvwxyzABCDEFG_0123456789-._~\",\n afterCallbackRedirectUrl: \"https://example.com/account-settings\",\n overrideTokenStoreInit: {\n accessToken: createAccessTokenString(\"fresh-stale-refresh-token-id\"),\n refreshToken: \"fresh-refresh-token\",\n },\n })).resolves.toBe(\"https://example.com/handler/oauth-callback?code=handoff-code&state=handoff-state\");\n } finally {\n Reflect.set(clientInterface, \"sendClientRequest\", originalSendClientRequest);\n Reflect.set(clientInterface, \"fetchNewAccessToken\", originalFetchNewAccessToken);\n }\n\n expect(refreshedRawRefreshTokens).toEqual([\"fresh-refresh-token\"]);\n expect(capturedRefreshTokens).toEqual([\"fresh-refresh-token\"]);\n expect(capturedAccessTokenRefreshTokenIds).toEqual([\"fresh-refresh-token-id\"]);\n });\n\n it(\"uses a fresh nested OAuth state while preserving the outer cross-domain return state\", async () => {\n const projectId = \"00000000-0000-4000-8000-000000000002\";\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId,\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n urls: {\n default: { type: \"hosted\" },\n },\n noAutomaticPrefetch: true,\n });\n const outerState = \"outer-cross-domain-state\";\n const outerCodeChallenge = \"abcdefghijklmnopqrstuvwxyzABCDEFG_0123456789-._~\";\n const currentUrl = new URL(`https://${projectId}.example-stack-hosted.test/handler/sign-in`);\n currentUrl.searchParams.set(\"after_auth_return_to\", `https://demo.stack-auth.com/?hexclave_cross_domain_auth=1&hexclave_cross_domain_state=${outerState}`);\n currentUrl.searchParams.set(\"hexclave_cross_domain_state\", outerState);\n currentUrl.searchParams.set(\"hexclave_cross_domain_code_challenge\", outerCodeChallenge);\n currentUrl.searchParams.set(\"hexclave_cross_domain_after_callback_redirect_url\", \"https://demo.stack-auth.com/\");\n currentUrl.searchParams.set(\"stack_nested_cross_domain_auth_refresh_token_id\", \"source-session\");\n currentUrl.searchParams.set(\"stack_nested_cross_domain_auth_callback_url\", \"https://demo.stack-auth.com/\");\n\n const previousWindow = globalThis.window;\n const previousDocument = globalThis.document;\n let redirectedUrl = \"\";\n vi.spyOn(clientApp as any, \"_fetchCurrentRefreshTokenIdIfSignedIn\").mockResolvedValue(null);\n vi.spyOn(clientApp as any, \"_getCrossDomainHandoffParamsForRedirect\").mockResolvedValue({\n state: \"fresh-nested-state\",\n codeChallenge: \"fresh-nested-code-challenge\",\n });\n vi.spyOn(clientApp as any, \"_isTrusted\").mockResolvedValue(true);\n\n globalThis.document = createMockDocument();\n globalThis.window = {\n location: {\n href: currentUrl.toString(),\n replace: (url: string) => {\n redirectedUrl = url;\n throw new Error(\"INTENTIONAL_TEST_ABORT\");\n },\n },\n } as any;\n\n try {\n await expect((clientApp as any)._maybeHandleNestedCrossDomainAuth()).rejects.toThrowError(\"INTENTIONAL_TEST_ABORT\");\n } finally {\n globalThis.window = previousWindow;\n globalThis.document = previousDocument;\n }\n\n const redirectUrl = new URL(redirectedUrl);\n expect(redirectUrl.searchParams.get(\"state\")).toBe(\"fresh-nested-state\");\n expect(redirectUrl.searchParams.get(\"code_challenge\")).toBe(\"fresh-nested-code-challenge\");\n const redirectUri = new URL(redirectUrl.searchParams.get(\"redirect_uri\") ?? \"\");\n expect(redirectUri.searchParams.get(\"hexclave_cross_domain_state\")).toBe(outerState);\n expect(redirectUri.searchParams.get(\"hexclave_cross_domain_code_challenge\")).toBe(outerCodeChallenge);\n expect(redirectUri.searchParams.get(\"hexclave_cross_domain_after_callback_redirect_url\")).toBe(\"https://demo.stack-auth.com/\");\n });\n\n it(\"clears a stale target-domain session before deferring to the source-domain session\", async () => {\n const projectId = \"00000000-0000-4000-8000-000000000006\";\n const hostedAccessToken = createAccessTokenString(\"hosted-old-refresh-token-id\");\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId,\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n urls: {\n default: { type: \"hosted\" },\n },\n noAutomaticPrefetch: true,\n });\n const tokenStore = Reflect.get(clientApp, \"_memoryTokenStore\");\n if (!(tokenStore instanceof Store)) {\n throw new Error(\"Expected StackClientApp to use a memory token store in this test.\");\n }\n tokenStore.set({\n refreshToken: \"hosted-old-refresh-token\",\n accessToken: hostedAccessToken,\n });\n\n const currentUrl = new URL(`https://${projectId}.example-stack-hosted.test/handler/sign-in`);\n currentUrl.searchParams.set(\"stack_nested_cross_domain_auth_refresh_token_id\", \"source-anonymous-refresh-token-id\");\n currentUrl.searchParams.set(\"stack_nested_cross_domain_auth_callback_url\", \"https://demo.stack-auth.com/handler/oauth-callback\");\n currentUrl.searchParams.set(\"hexclave_cross_domain_state\", \"outer-state\");\n currentUrl.searchParams.set(\"hexclave_cross_domain_code_challenge\", \"outer-code-challenge\");\n currentUrl.searchParams.set(\"hexclave_cross_domain_after_callback_redirect_url\", \"https://demo.stack-auth.com/app\");\n\n const previousWindow = globalThis.window;\n const previousDocument = globalThis.document;\n let redirectedUrl = \"\";\n const clientInterface = Reflect.get(clientApp, \"_interface\");\n const originalFetchNewAccessToken = Reflect.get(clientInterface, \"fetchNewAccessToken\");\n Reflect.set(clientInterface, \"fetchNewAccessToken\", async () => {\n return AccessToken.createIfValid(hostedAccessToken) ?? (() => {\n throw new Error(\"Expected test access token to be valid\");\n })();\n });\n vi.spyOn(clientApp as any, \"_isTrusted\").mockResolvedValue(true);\n\n globalThis.document = createMockDocument();\n globalThis.window = {\n location: {\n href: currentUrl.toString(),\n replace: (url: string) => {\n redirectedUrl = url;\n throw new Error(\"INTENTIONAL_TEST_ABORT\");\n },\n },\n } as any;\n\n try {\n await expect((clientApp as any)._maybeHandleNestedCrossDomainAuth()).rejects.toThrowError(\"INTENTIONAL_TEST_ABORT\");\n } finally {\n Reflect.set(clientInterface, \"fetchNewAccessToken\", originalFetchNewAccessToken);\n globalThis.window = previousWindow;\n globalThis.document = previousDocument;\n }\n\n expect(tokenStore.get()).toEqual({\n refreshToken: null,\n accessToken: null,\n });\n expect(new URL(redirectedUrl).origin).toBe(\"https://demo.stack-auth.com\");\n });\n\n it(\"uses the latest browser refresh cookie before computing nested cross-domain session IDs\", async () => {\n const projectId = \"00000000-0000-4000-8000-000000000007\";\n const previousWindow = globalThis.window;\n const previousDocument = globalThis.document;\n\n globalThis.document = createMockDocument();\n globalThis.window = {\n location: {\n href: \"https://demo.stack-auth.com/\",\n protocol: \"https:\",\n hostname: \"demo.stack-auth.com\",\n },\n addEventListener: () => {},\n removeEventListener: () => {},\n } as any;\n\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId,\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"cookie\",\n redirectMethod: \"none\",\n noAutomaticPrefetch: true,\n });\n const clientInterface = Reflect.get(clientApp, \"_interface\");\n const originalFetchNewAccessToken = Reflect.get(clientInterface, \"fetchNewAccessToken\");\n const refreshedRawRefreshTokens: string[] = [];\n\n // Cookie-store writes queue a background trusted-parent-domain lookup. Without this stub, that\n // lookup fetches the (unreachable) baseUrl with retries while holding the global store lock,\n // which starves any later test that needs the write lock (e.g. signOut). Not restored on\n // purpose: queued tasks can still run after this test body finishes.\n vi.spyOn(clientApp as any, \"_getTrustedParentDomain\").mockResolvedValue(null);\n\n try {\n const getBrowserCookieTokenStore = Reflect.get(clientApp, \"_getBrowserCookieTokenStore\");\n if (typeof getBrowserCookieTokenStore !== \"function\") {\n throw new Error(\"Expected StackClientApp to expose _getBrowserCookieTokenStore in tests.\");\n }\n const tokenStore = getBrowserCookieTokenStore.call(clientApp);\n tokenStore.set({\n refreshToken: \"old-refresh-token\",\n accessToken: createAccessTokenString(\"old-refresh-token-id\"),\n });\n\n document.cookie = `__Host-hexclave-refresh-${projectId}--default=${JSON.stringify({\n refresh_token: \"new-refresh-token\",\n updated_at_millis: 1,\n })}`;\n Reflect.set(clientInterface, \"fetchNewAccessToken\", async (refreshToken: unknown) => {\n const refreshTokenString = Reflect.get(refreshToken ?? {}, \"token\");\n if (typeof refreshTokenString !== \"string\") {\n throw new Error(\"Expected refresh token while fetching a new access token.\");\n }\n refreshedRawRefreshTokens.push(refreshTokenString);\n return AccessToken.createIfValid(createAccessTokenString(\"new-refresh-token-id\")) ?? (() => {\n throw new Error(\"Expected test access token to be valid\");\n })();\n });\n\n const fetchCurrentRefreshTokenIdIfSignedIn = Reflect.get(clientApp, \"_fetchCurrentRefreshTokenIdIfSignedIn\");\n if (typeof fetchCurrentRefreshTokenIdIfSignedIn !== \"function\") {\n throw new Error(\"Expected StackClientApp to expose _fetchCurrentRefreshTokenIdIfSignedIn in tests.\");\n }\n await expect(fetchCurrentRefreshTokenIdIfSignedIn.call(clientApp, {\n awaitPendingAuthResolutions: false,\n })).resolves.toBe(\"new-refresh-token-id\");\n } finally {\n Reflect.set(clientInterface, \"fetchNewAccessToken\", originalFetchNewAccessToken);\n globalThis.window = previousWindow;\n globalThis.document = previousDocument;\n }\n\n expect(refreshedRawRefreshTokens).toEqual([\"new-refresh-token\"]);\n });\n\n it(\"does not re-bounce nested cross-domain auth after the OAuth callback consumed code+state from the URL\", async () => {\n const projectId = \"00000000-0000-4000-8000-000000000008\";\n const previousWindow = globalThis.window;\n const previousDocument = globalThis.document;\n\n const strippedUrl = new URL(`https://${projectId}.example-stack-hosted.test/handler/sign-in`);\n strippedUrl.searchParams.set(\"stack_nested_cross_domain_auth_refresh_token_id\", \"source-refresh-token-id\");\n strippedUrl.searchParams.set(\"stack_nested_cross_domain_auth_callback_url\", \"https://demo.stack-auth.com/\");\n const urlAtConstructionTime = new URL(strippedUrl);\n urlAtConstructionTime.searchParams.set(\"code\", \"one-time-code\");\n urlAtConstructionTime.searchParams.set(\"state\", \"nested-oauth-state\");\n\n // Construct before installing the window mock so the constructor does not schedule its own\n // nested-auth resolution; the assertions below drive the handler explicitly.\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId,\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n noAutomaticPrefetch: true,\n });\n\n globalThis.document = createMockDocument();\n globalThis.window = {\n location: {\n href: strippedUrl.toString(),\n replace: () => {\n throw new Error(\"INTENTIONAL_TEST_ABORT\");\n },\n },\n } as any;\n\n vi.spyOn(clientApp as any, \"_fetchCurrentRefreshTokenIdIfSignedIn\").mockResolvedValue(null);\n vi.spyOn(clientApp as any, \"_getCrossDomainHandoffParamsForRedirect\").mockResolvedValue({\n state: \"fresh-nested-state\",\n codeChallenge: \"fresh-nested-code-challenge\",\n });\n vi.spyOn(clientApp as any, \"_isTrusted\").mockResolvedValue(true);\n\n try {\n // Without the construction-time URL, the handler re-bounces (location.replace aborts).\n await expect((clientApp as any)._maybeHandleNestedCrossDomainAuth()).rejects.toThrowError(\"INTENTIONAL_TEST_ABORT\");\n // With it, the in-flight OAuth callback wins and the handler stands down.\n await expect((clientApp as any)._maybeHandleNestedCrossDomainAuth(urlAtConstructionTime)).resolves.toBe(false);\n // The live-URL guard must also stand down on its own when code+state are still present.\n (globalThis.window as any).location.href = urlAtConstructionTime.toString();\n await expect((clientApp as any)._maybeHandleNestedCrossDomainAuth()).resolves.toBe(false);\n } finally {\n globalThis.window = previousWindow;\n globalThis.document = previousDocument;\n }\n });\n\n it(\"passes the construction-time URL to the nested cross-domain auth handler\", async () => {\n const projectId = \"00000000-0000-4000-8000-000000000009\";\n const previousWindow = globalThis.window;\n const previousDocument = globalThis.document;\n\n const callbackUrl = new URL(`https://${projectId}.example-stack-hosted.test/handler/sign-in`);\n callbackUrl.searchParams.set(\"stack_nested_cross_domain_auth_refresh_token_id\", \"source-refresh-token-id\");\n callbackUrl.searchParams.set(\"code\", \"one-time-code\");\n callbackUrl.searchParams.set(\"state\", \"nested-oauth-state\");\n const strippedUrl = new URL(callbackUrl);\n strippedUrl.searchParams.delete(\"code\");\n strippedUrl.searchParams.delete(\"state\");\n\n globalThis.document = createMockDocument();\n globalThis.window = {\n location: {\n href: callbackUrl.toString(),\n },\n } as any;\n\n const nestedAuthSpy = vi.spyOn(StackClientApp.prototype as any, \"_maybeHandleNestedCrossDomainAuth\").mockResolvedValue(false);\n\n try {\n new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId,\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n noAutomaticPrefetch: true,\n });\n\n // Simulate consumeOAuthCallbackQueryParams stripping code+state before microtasks run.\n (globalThis.window as any).location.href = strippedUrl.toString();\n await new Promise((resolve) => setTimeout(resolve, 0));\n\n expect(nestedAuthSpy).toHaveBeenCalledTimes(1);\n const urlArgument = nestedAuthSpy.mock.calls[0][0] as URL;\n expect(urlArgument).toBeInstanceOf(URL);\n expect(urlArgument.searchParams.get(\"code\")).toBe(\"one-time-code\");\n expect(urlArgument.searchParams.get(\"state\")).toBe(\"nested-oauth-state\");\n } finally {\n nestedAuthSpy.mockRestore();\n globalThis.window = previousWindow;\n globalThis.document = previousDocument;\n }\n });\n\n it(\"redirects hosted current-page OAuth callback errors to the hosted error handler during startup\", async () => {\n const projectId = \"00000000-0000-4000-8000-000000000010\";\n const previousWindow = globalThis.window;\n const previousDocument = globalThis.document;\n const callbackUrl = new URL(\"https://demo.stack-auth.com/dashboard\");\n callbackUrl.searchParams.set(\"errorCode\", \"SIGN_UP_REJECTED\");\n callbackUrl.searchParams.set(\"message\", \"Your sign up was rejected by an administrator's sign-up rule.\");\n callbackUrl.searchParams.set(\"details\", JSON.stringify({\n message: \"Your sign up was rejected by an administrator's sign-up rule.\",\n }));\n let currentHref = callbackUrl.toString();\n let redirectedUrl = \"\";\n const redirectSpy = vi.spyOn(StackClientApp.prototype as any, \"_redirectTo\").mockImplementation(async (...args: unknown[]) => {\n const options = args[0] as { url: string | URL };\n redirectedUrl = options.url.toString();\n });\n\n globalThis.document = createMockDocument();\n globalThis.window = {\n location: {\n get href() {\n return currentHref;\n },\n set href(value: string) {\n currentHref = value;\n },\n origin: callbackUrl.origin,\n },\n history: {\n replaceState: (_state: unknown, _title: string, url: string) => {\n currentHref = new URL(url, currentHref).toString();\n },\n },\n addEventListener: () => {},\n removeEventListener: () => {},\n } as any;\n\n try {\n new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId,\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n urls: {\n default: { type: \"hosted\" },\n },\n noAutomaticPrefetch: true,\n });\n\n await new Promise((resolve) => setTimeout(resolve, 0));\n await new Promise((resolve) => setTimeout(resolve, 0));\n } finally {\n redirectSpy.mockRestore();\n globalThis.window = previousWindow;\n globalThis.document = previousDocument;\n }\n\n const errorUrl = new URL(redirectedUrl);\n expect(errorUrl.origin).toBe(`https://${projectId}.built-with-stack-auth.com`);\n expect(errorUrl.pathname).toBe(\"/handler/error\");\n expect(errorUrl.searchParams.get(\"errorCode\")).toBe(\"SIGN_UP_REJECTED\");\n expect(errorUrl.searchParams.get(\"message\")).toBe(\"Your sign up was rejected by an administrator's sign-up rule.\");\n expect(new URL(currentHref).searchParams.has(\"errorCode\")).toBe(false);\n });\n\n it(\"uses direct sign-out instead of hosted sign-out redirects when code execution is available\", async () => {\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000003\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n urls: {\n handler: \"/handler\",\n signOut: { type: \"hosted\" },\n },\n noAutomaticPrefetch: true,\n });\n const signOutSpy = vi.spyOn(clientApp, \"signOut\").mockRejectedValue(new Error(\"INTENTIONAL_TEST_ABORT\"));\n\n try {\n await expect(clientApp.redirectToSignOut()).rejects.toThrowError(\"INTENTIONAL_TEST_ABORT\");\n expect(signOutSpy).toHaveBeenCalledWith();\n } finally {\n signOutSpy.mockRestore();\n }\n });\n\n it(\"throws when public app.urls reads would return hosted component URLs\", () => {\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000003\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n urls: {\n default: { type: \"hosted\" },\n },\n noAutomaticPrefetch: true,\n });\n\n expect(() => clientApp.urls.signIn).toThrowError(/app\\.urls\\.signIn cannot be used when this app is configured to use hosted components.*Use app\\.redirectToSignIn\\(\\) instead/s);\n expect(() => clientApp.urls.signOut).toThrowError(/app\\.urls\\.signOut cannot be used when this app is configured to use hosted components.*Use app\\.redirectToSignOut\\(\\) instead/s);\n expect(clientApp.urls.afterSignIn).toBe(\"/\");\n });\n\n it(\"keeps public app.urls reads available for non-hosted targets\", () => {\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000003\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n urls: {\n handler: \"/custom-handler\",\n },\n noAutomaticPrefetch: true,\n });\n\n expect(clientApp.urls.signIn).toBe(\"/custom-handler/sign-in\");\n });\n\n it(\"keeps default hosted signOut() on the source domain when afterSignOut is not configured\", async () => {\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000004\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n urls: {\n default: { type: \"hosted\" },\n },\n noAutomaticPrefetch: true,\n });\n const currentHref = \"https://demo.stack-auth.com/settings?tab=profile\";\n\n const clientInterface = Reflect.get(clientApp, \"_interface\");\n const originalSignOut = Reflect.get(clientInterface, \"signOut\");\n Reflect.set(clientInterface, \"signOut\", async () => {});\n const previousWindow = globalThis.window;\n const previousDocument = globalThis.document;\n let redirectedUrl = \"\";\n\n globalThis.document = createMockDocument();\n globalThis.window = {\n location: {\n href: currentHref,\n replace: (url: string) => {\n redirectedUrl = url;\n throw new Error(\"INTENTIONAL_TEST_ABORT\");\n },\n },\n } as any;\n\n try {\n const signOut = Reflect.get(clientApp, \"_signOut\");\n if (typeof signOut !== \"function\") {\n throw new Error(\"Expected StackClientApp to expose _signOut in tests.\");\n }\n await expect(signOut.call(clientApp, Reflect.get(clientInterface, \"createSession\").call(clientInterface, {\n refreshToken: null,\n }))).rejects.toThrowError(\"INTENTIONAL_TEST_ABORT\");\n } finally {\n Reflect.set(clientInterface, \"signOut\", originalSignOut);\n globalThis.window = previousWindow;\n globalThis.document = previousDocument;\n }\n\n expect(redirectedUrl).toBe(\"/settings?tab=profile\");\n });\n\n it(\"restores a dropped after_auth_return_to from the sessionStorage mirror when redirecting after sign-in\", async () => {\n const previousWindow = globalThis.window;\n const previousDocument = globalThis.document;\n const hadPreviousWindow = Reflect.has(globalThis, \"window\");\n const sessionStorageMap = new Map<string, string>();\n const windowMock = {\n location: {\n href: \"https://demo.example.test/handler/sign-in?after_auth_return_to=%2Fmusic%3Ftrack%3D1\",\n },\n sessionStorage: {\n getItem: (key: string) => sessionStorageMap.get(key) ?? null,\n setItem: (key: string, value: string) => {\n sessionStorageMap.set(key, value);\n },\n removeItem: (key: string) => {\n sessionStorageMap.delete(key);\n },\n },\n };\n Reflect.set(globalThis, \"window\", windowMock);\n globalThis.document = createMockDocument();\n\n try {\n // The constructor mirrors the redirect-back state from the arrival URL into sessionStorage.\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000011\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n noAutomaticPrefetch: true,\n });\n\n // Intermediate hops (MFA, magic link, OAuth round-trips, ...) dropped the query params.\n windowMock.location.href = \"https://demo.example.test/handler/mfa\";\n\n const redirectUrl = await clientApp[hexclaveAppInternalsSymbol].getRedirectToHandlerUrl(\"afterSignIn\");\n expect(redirectUrl).toBe(\"/music?track=1\");\n\n // noRedirectBack opts out of the mirror just like it opts out of the query param.\n const noRedirectBackUrl = await clientApp[hexclaveAppInternalsSymbol].getRedirectToHandlerUrl(\"afterSignIn\", { noRedirectBack: true });\n expect(new URL(noRedirectBackUrl, \"https://demo.example.test\").pathname).toBe(\"/\");\n } finally {\n globalThis.document = previousDocument;\n if (hadPreviousWindow) {\n Reflect.set(globalThis, \"window\", previousWindow);\n } else {\n Reflect.deleteProperty(globalThis, \"window\");\n }\n }\n });\n\n it(\"restores dropped cross-domain handoff state from the sessionStorage mirror when redirecting after sign-in\", async () => {\n const projectId = \"00000000-0000-4000-8000-000000000012\";\n const previousWindow = globalThis.window;\n const hadPreviousWindow = Reflect.has(globalThis, \"window\");\n const sessionStorageMap = new Map<string, string>();\n\n const handoffState = \"mirror-handoff-state\";\n const handoffCodeChallenge = \"abcdefghijklmnopqrstuvwxyzABCDEFG_0123456789-._~\";\n const handoffAfterCallbackRedirect = \"https://demo.example.test/dashboard\";\n const redirectBackUrl = new URL(\"https://demo.example.test/handler/oauth-callback\");\n redirectBackUrl.searchParams.set(\"hexclave_cross_domain_auth\", \"1\");\n redirectBackUrl.searchParams.set(\"hexclave_cross_domain_state\", handoffState);\n redirectBackUrl.searchParams.set(\"hexclave_cross_domain_code_challenge\", handoffCodeChallenge);\n redirectBackUrl.searchParams.set(\"hexclave_cross_domain_after_callback_redirect_url\", handoffAfterCallbackRedirect);\n\n const arrivalUrl = new URL(`https://${projectId}.built-with-stack-auth.com/handler/sign-in`);\n arrivalUrl.searchParams.set(\"after_auth_return_to\", redirectBackUrl.toString());\n arrivalUrl.searchParams.set(\"hexclave_cross_domain_state\", handoffState);\n arrivalUrl.searchParams.set(\"hexclave_cross_domain_code_challenge\", handoffCodeChallenge);\n arrivalUrl.searchParams.set(\"hexclave_cross_domain_after_callback_redirect_url\", handoffAfterCallbackRedirect);\n\n const previousDocument = globalThis.document;\n const windowMock = {\n location: {\n href: arrivalUrl.toString(),\n },\n sessionStorage: {\n getItem: (key: string) => sessionStorageMap.get(key) ?? null,\n setItem: (key: string, value: string) => {\n sessionStorageMap.set(key, value);\n },\n removeItem: (key: string) => {\n sessionStorageMap.delete(key);\n },\n },\n };\n Reflect.set(globalThis, \"window\", windowMock);\n globalThis.document = createMockDocument();\n\n try {\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId,\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n noAutomaticPrefetch: true,\n });\n const crossDomainAuthorizeRedirect = \"https://demo.example.test/handler/oauth-callback?code=minted-code&state=mirror-handoff-state\";\n const createCrossDomainAuthRedirectUrlSpy = vi\n .spyOn(clientApp as any, \"_createCrossDomainAuthRedirectUrl\")\n .mockResolvedValue(crossDomainAuthorizeRedirect);\n\n // All redirect-back query params were dropped before the after-sign-in redirect.\n windowMock.location.href = `https://${projectId}.built-with-stack-auth.com/handler/sign-in`;\n\n const redirectUrl = await clientApp[hexclaveAppInternalsSymbol].getRedirectToHandlerUrl(\"afterSignIn\");\n\n expect(createCrossDomainAuthRedirectUrlSpy).toHaveBeenCalledWith(expect.objectContaining({\n redirectUri: redirectBackUrl.toString(),\n state: handoffState,\n codeChallenge: handoffCodeChallenge,\n afterCallbackRedirectUrl: handoffAfterCallbackRedirect,\n }));\n expect(redirectUrl).toBe(crossDomainAuthorizeRedirect);\n } finally {\n globalThis.document = previousDocument;\n if (hadPreviousWindow) {\n Reflect.set(globalThis, \"window\", previousWindow);\n } else {\n Reflect.deleteProperty(globalThis, \"window\");\n }\n }\n });\n\n it(\"ignores stale session callbacks after a newer refresh token owns the token store\", async () => {\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000005\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"none\",\n noAutomaticPrefetch: true,\n });\n const oldAccessToken = createAccessTokenString(\"old-refresh-token-id\");\n const refreshedOldAccessToken = createAccessTokenString(\"refreshed-old-refresh-token-id\");\n const newAccessToken = createAccessTokenString(\"new-refresh-token-id\");\n const tokenStore = new Store({\n refreshToken: \"old-refresh-token\",\n accessToken: oldAccessToken,\n });\n const clientInterface = Reflect.get(clientApp, \"_interface\");\n const originalFetchNewAccessToken = Reflect.get(clientInterface, \"fetchNewAccessToken\");\n Reflect.set(clientInterface, \"fetchNewAccessToken\", async () => {\n return AccessToken.createIfValid(refreshedOldAccessToken) ?? (() => {\n throw new Error(\"Expected test access token to be valid\");\n })();\n });\n\n try {\n const getSessionFromTokenStore = Reflect.get(clientApp, \"_getSessionFromTokenStore\");\n if (typeof getSessionFromTokenStore !== \"function\") {\n throw new Error(\"Expected StackClientApp to expose _getSessionFromTokenStore in tests.\");\n }\n const oldSession = getSessionFromTokenStore.call(clientApp, tokenStore);\n tokenStore.set({\n refreshToken: \"new-refresh-token\",\n accessToken: newAccessToken,\n });\n\n await oldSession.fetchNewTokens();\n expect(tokenStore.get()).toEqual({\n refreshToken: \"new-refresh-token\",\n accessToken: newAccessToken,\n });\n\n oldSession.markInvalid();\n expect(tokenStore.get()).toEqual({\n refreshToken: \"new-refresh-token\",\n accessToken: newAccessToken,\n });\n } finally {\n Reflect.set(clientInterface, \"fetchNewAccessToken\", originalFetchNewAccessToken);\n }\n });\n});\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { r as _HexclaveClientAppImplIncomplete } from "../../../../admin-app-impl-
|
|
1
|
+
import { r as _HexclaveClientAppImplIncomplete } from "../../../../admin-app-impl-DHs4il4z.js";
|
|
2
2
|
export { _HexclaveClientAppImplIncomplete };
|