@hexclave/js 1.0.75 → 1.0.77

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.
Files changed (150) hide show
  1. package/dist/{admin-app-impl-BhrjJlxj.d.ts → admin-app-impl-CHQtsn4f.d.ts} +11 -9
  2. package/dist/admin-app-impl-CHQtsn4f.d.ts.map +1 -0
  3. package/dist/clickmap/clickmap-core.d.ts +1 -1
  4. package/dist/clickmap/index.d.ts +1 -1
  5. package/dist/{client-app-WOX3pOo1.d.ts → client-app-R5X8wyeV.d.ts} +4 -1
  6. package/dist/client-app-R5X8wyeV.d.ts.map +1 -0
  7. package/dist/dev-tool/dev-tool-core.d.ts +1 -1
  8. package/dist/dev-tool/dev-tool-core.d.ts.map +1 -1
  9. package/dist/dev-tool/dev-tool-core.js +2 -2
  10. package/dist/dev-tool/dev-tool-core.js.map +1 -1
  11. package/dist/dev-tool/index.d.ts +1 -1
  12. package/dist/dev-tool/index.d.ts.map +1 -1
  13. package/dist/dev-tool/index.js +2 -8
  14. package/dist/dev-tool/index.js.map +1 -1
  15. package/dist/esm/dev-tool/dev-tool-core.d.ts.map +1 -1
  16. package/dist/esm/dev-tool/dev-tool-core.js +1 -1
  17. package/dist/esm/dev-tool/dev-tool-core.js.map +1 -1
  18. package/dist/esm/dev-tool/index.d.ts.map +1 -1
  19. package/dist/esm/dev-tool/index.js +2 -8
  20. package/dist/esm/dev-tool/index.js.map +1 -1
  21. package/dist/esm/in-page-ui/dev-environment.d.ts +5 -0
  22. package/dist/esm/in-page-ui/dev-environment.d.ts.map +1 -0
  23. package/dist/esm/in-page-ui/dev-environment.js +18 -0
  24. package/dist/esm/in-page-ui/dev-environment.js.map +1 -0
  25. package/dist/esm/in-page-ui/issue-card.d.ts +52 -0
  26. package/dist/esm/in-page-ui/issue-card.d.ts.map +1 -0
  27. package/dist/esm/in-page-ui/issue-card.js +392 -0
  28. package/dist/esm/in-page-ui/issue-card.js.map +1 -0
  29. package/dist/esm/in-page-ui/issue-card.test.d.ts +1 -0
  30. package/dist/esm/in-page-ui/issue-card.test.js +60 -0
  31. package/dist/esm/in-page-ui/issue-card.test.js.map +1 -0
  32. package/dist/esm/in-page-ui/logo.d.ts +5 -0
  33. package/dist/esm/in-page-ui/logo.d.ts.map +1 -0
  34. package/dist/esm/in-page-ui/logo.js +6 -0
  35. package/dist/esm/in-page-ui/logo.js.map +1 -0
  36. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +4 -4
  37. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
  38. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.automatic-side-effects.test.js +30 -1
  39. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.automatic-side-effects.test.js.map +1 -1
  40. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +140 -15
  41. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
  42. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +5 -3
  43. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
  44. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js +180 -27
  45. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  46. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.sign-out.test.d.ts +1 -0
  47. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.sign-out.test.js +83 -0
  48. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.sign-out.test.js.map +1 -0
  49. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.untrusted-redirect-card.test.d.ts +1 -0
  50. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.untrusted-redirect-card.test.js +120 -0
  51. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.untrusted-redirect-card.test.js.map +1 -0
  52. package/dist/esm/lib/hexclave-app/apps/implementations/common.js +2 -2
  53. package/dist/esm/lib/hexclave-app/apps/implementations/common.js.map +1 -1
  54. package/dist/esm/lib/hexclave-app/apps/implementations/index.d.ts +1 -1
  55. package/dist/esm/lib/hexclave-app/apps/implementations/index.js +1 -1
  56. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-page-urls.test.js +1 -0
  57. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-page-urls.test.js.map +1 -1
  58. package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -1
  59. package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.js +1 -1
  60. package/dist/esm/lib/hexclave-app/teams/index.d.ts +3 -0
  61. package/dist/esm/lib/hexclave-app/teams/index.d.ts.map +1 -1
  62. package/dist/esm/lib/hexclave-app/teams/index.js.map +1 -1
  63. package/dist/esm/pushed-config-error-overlay/index.d.ts.map +1 -1
  64. package/dist/esm/pushed-config-error-overlay/index.js +42 -343
  65. package/dist/esm/pushed-config-error-overlay/index.js.map +1 -1
  66. package/dist/esm/setup-error-overlay/index.d.ts +16 -0
  67. package/dist/esm/setup-error-overlay/index.d.ts.map +1 -0
  68. package/dist/esm/setup-error-overlay/index.js +106 -0
  69. package/dist/esm/setup-error-overlay/index.js.map +1 -0
  70. package/dist/esm/setup-error-overlay/index.test.d.ts +1 -0
  71. package/dist/esm/setup-error-overlay/index.test.js +125 -0
  72. package/dist/esm/setup-error-overlay/index.test.js.map +1 -0
  73. package/dist/in-page-ui/dev-environment.d.ts +5 -0
  74. package/dist/in-page-ui/dev-environment.d.ts.map +1 -0
  75. package/dist/in-page-ui/dev-environment.js +19 -0
  76. package/dist/in-page-ui/dev-environment.js.map +1 -0
  77. package/dist/in-page-ui/issue-card.d.ts +52 -0
  78. package/dist/in-page-ui/issue-card.d.ts.map +1 -0
  79. package/dist/in-page-ui/issue-card.js +397 -0
  80. package/dist/in-page-ui/issue-card.js.map +1 -0
  81. package/dist/in-page-ui/issue-card.test.d.ts +1 -0
  82. package/dist/in-page-ui/issue-card.test.js +59 -0
  83. package/dist/in-page-ui/issue-card.test.js.map +1 -0
  84. package/dist/in-page-ui/logo.d.ts +5 -0
  85. package/dist/in-page-ui/logo.d.ts.map +1 -0
  86. package/dist/in-page-ui/logo.js +7 -0
  87. package/dist/in-page-ui/logo.js.map +1 -0
  88. package/dist/index.d.ts +1 -1
  89. package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +1 -1
  90. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.automatic-side-effects.test.js +29 -0
  91. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.automatic-side-effects.test.js.map +1 -1
  92. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +140 -15
  93. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
  94. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +2 -2
  95. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js +178 -24
  96. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  97. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.sign-out.test.d.ts +1 -0
  98. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.sign-out.test.js +82 -0
  99. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.sign-out.test.js.map +1 -0
  100. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.untrusted-redirect-card.test.d.ts +1 -0
  101. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.untrusted-redirect-card.test.js +119 -0
  102. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.untrusted-redirect-card.test.js.map +1 -0
  103. package/dist/lib/hexclave-app/apps/implementations/common.js +2 -2
  104. package/dist/lib/hexclave-app/apps/implementations/common.js.map +1 -1
  105. package/dist/lib/hexclave-app/apps/implementations/index.d.ts +1 -1
  106. package/dist/lib/hexclave-app/apps/implementations/index.js +1 -1
  107. package/dist/lib/hexclave-app/apps/implementations/redirect-page-urls.test.js +1 -0
  108. package/dist/lib/hexclave-app/apps/implementations/redirect-page-urls.test.js.map +1 -1
  109. package/dist/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -1
  110. package/dist/lib/hexclave-app/apps/implementations/server-app-impl.js +1 -1
  111. package/dist/lib/hexclave-app/apps/index.d.ts +1 -1
  112. package/dist/lib/hexclave-app/apps/interfaces/admin-app.d.ts +1 -1
  113. package/dist/lib/hexclave-app/apps/interfaces/client-app.d.ts +1 -1
  114. package/dist/lib/hexclave-app/apps/interfaces/server-app.d.ts +1 -1
  115. package/dist/lib/hexclave-app/index.d.ts +1 -1
  116. package/dist/lib/hexclave-app/projects/index.d.ts +1 -1
  117. package/dist/lib/hexclave-app/teams/index.d.ts +1 -1
  118. package/dist/lib/hexclave-app/teams/index.js.map +1 -1
  119. package/dist/lib/hexclave-app/users/index.d.ts +1 -1
  120. package/dist/pushed-config-error-overlay/index.d.ts +1 -1
  121. package/dist/pushed-config-error-overlay/index.d.ts.map +1 -1
  122. package/dist/pushed-config-error-overlay/index.js +41 -342
  123. package/dist/pushed-config-error-overlay/index.js.map +1 -1
  124. package/dist/setup-error-overlay/index.d.ts +16 -0
  125. package/dist/setup-error-overlay/index.d.ts.map +1 -0
  126. package/dist/setup-error-overlay/index.js +108 -0
  127. package/dist/setup-error-overlay/index.js.map +1 -0
  128. package/dist/setup-error-overlay/index.test.d.ts +1 -0
  129. package/dist/setup-error-overlay/index.test.js +124 -0
  130. package/dist/setup-error-overlay/index.test.js.map +1 -0
  131. package/package.json +2 -2
  132. package/src/dev-tool/dev-tool-core.ts +1 -4
  133. package/src/dev-tool/index.ts +4 -15
  134. package/src/in-page-ui/dev-environment.ts +33 -0
  135. package/src/in-page-ui/issue-card.test.ts +67 -0
  136. package/src/in-page-ui/issue-card.ts +500 -0
  137. package/src/in-page-ui/logo.ts +8 -0
  138. package/src/lib/hexclave-app/apps/implementations/client-app-impl.automatic-side-effects.test.ts +38 -1
  139. package/src/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.ts +157 -0
  140. package/src/lib/hexclave-app/apps/implementations/client-app-impl.sign-out.test.ts +96 -0
  141. package/src/lib/hexclave-app/apps/implementations/client-app-impl.ts +247 -37
  142. package/src/lib/hexclave-app/apps/implementations/client-app-impl.untrusted-redirect-card.test.ts +146 -0
  143. package/src/lib/hexclave-app/apps/implementations/common.ts +1 -1
  144. package/src/lib/hexclave-app/apps/implementations/redirect-page-urls.test.ts +1 -0
  145. package/src/lib/hexclave-app/teams/index.ts +3 -0
  146. package/src/pushed-config-error-overlay/index.ts +45 -386
  147. package/src/setup-error-overlay/index.test.ts +133 -0
  148. package/src/setup-error-overlay/index.ts +150 -0
  149. package/dist/admin-app-impl-BhrjJlxj.d.ts.map +0 -1
  150. package/dist/client-app-WOX3pOo1.d.ts.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issue-card.js","names":["HEXCLAVE_LOGO_SVG"],"sources":["../../src/in-page-ui/issue-card.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// Shared renderer for Hexclave's in-page issue cards: the modal-style card (plus its minimized pill) that the SDK uses\n// to tell developers about problems it cannot recover from, like a broken pushed config or an untrusted auth domain.\n// Every issue surface renders the same shape, so the markup, styles and clipboard handling live here and each feature\n// only supplies its copy and callbacks.\n\nimport { runAsynchronously } from \"@hexclave/shared/dist/utils/promises\";\nimport { getInPageUiBaseCSS } from \"./base-styles\";\nimport { h, setHtml } from \"./dom\";\nimport { HEXCLAVE_LOGO_SVG } from \"./logo\";\n\nexport type IssueCardKind = \"error\" | \"warning\";\n\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\nexport function getIssueCardCSS(scopeSelector: string): string {\n return getInPageUiBaseCSS(scopeSelector) + `\n ${scopeSelector} .hic-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 ${scopeSelector} .hic-card {\n --hic-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(--hic-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 ${scopeSelector} .hic-card-warning {\n --hic-status: var(--sdt-warning);\n }\n\n ${scopeSelector} .hic-card-inner {\n padding: 18px;\n width: 100%;\n overflow: auto;\n }\n\n ${scopeSelector} .hic-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 12px;\n }\n\n ${scopeSelector} .hic-title-row {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n min-width: 0;\n }\n\n ${scopeSelector} .hic-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(--hic-status);\n color: white;\n box-shadow: 0 10px 30px color-mix(in srgb, var(--hic-status) 32%, transparent);\n }\n\n ${scopeSelector} .hic-badge {\n display: inline-flex;\n flex-shrink: 0;\n padding: 2px 6px;\n border-radius: 999px;\n background: var(--hic-status);\n color: white;\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n }\n\n ${scopeSelector} .hic-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 ${scopeSelector} .hic-actions {\n display: flex;\n gap: 4px;\n }\n\n ${scopeSelector} .hic-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 ${scopeSelector} .hic-icon-btn svg {\n display: block;\n flex-shrink: 0;\n }\n\n ${scopeSelector} .hic-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 ${scopeSelector} .hic-icon-btn:hover {\n background: var(--sdt-bg-hover);\n color: var(--sdt-text);\n }\n\n ${scopeSelector} .hic-body {\n color: var(--sdt-text-secondary);\n font-size: 14px;\n line-height: 1.5;\n }\n\n ${scopeSelector} .hic-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 ${scopeSelector} .hic-message-label {\n color: var(--sdt-text);\n font-size: 12px;\n font-weight: 650;\n }\n\n ${scopeSelector} .hic-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 ${scopeSelector} .hic-fix-list {\n margin: 8px 0 0;\n padding-left: 18px;\n color: var(--sdt-text);\n font-size: 13px;\n }\n\n ${scopeSelector} .hic-fix-list li + li {\n margin-top: 4px;\n }\n\n ${scopeSelector} .hic-footer {\n margin-top: 10px;\n color: var(--sdt-text-tertiary);\n font-size: 12px;\n }\n\n ${scopeSelector} .hic-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 --hic-status: var(--sdt-error);\n border: 1px solid color-mix(in srgb, var(--hic-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 ${scopeSelector} .hic-pill-warning {\n --hic-status: var(--sdt-warning);\n }\n\n ${scopeSelector} .hic-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(--hic-status);\n color: white;\n }\n\n @media (max-height: 520px) {\n ${scopeSelector} .hic-backdrop {\n align-items: flex-start;\n padding: 12px;\n }\n\n ${scopeSelector} .hic-card {\n width: min(720px, calc(100vw - 24px));\n max-height: calc(100dvh - 24px);\n }\n\n ${scopeSelector} .hic-card-inner {\n padding: 12px;\n }\n\n ${scopeSelector} .hic-header {\n margin-bottom: 8px;\n }\n\n ${scopeSelector} .hic-title {\n font-size: 16px;\n }\n\n ${scopeSelector} .hic-body {\n font-size: 13px;\n }\n\n ${scopeSelector} .hic-message {\n max-height: max(80px, 24dvh);\n }\n }\n`;\n}\n\nexport async 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 });\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 message.\");\n }\n}\n\n/**\n * A button that copies `getText()` and briefly reports the outcome in its own label. Copying can fail for reasons\n * outside our control (permissions, insecure contexts), so the failure is reported inline instead of being thrown into\n * a click handler where nothing would show it.\n */\nfunction renderCopyButton(options: {\n variant: \"icon\" | \"text\",\n title: string,\n ariaLabel: string,\n getText: () => string,\n onCopyError: (error: unknown) => void,\n}): HTMLElement {\n const idleHtml = options.variant === \"text\" ? `${COPY_ICON_SVG}Copy` : COPY_ICON_SVG;\n const button = h(\"button\", {\n className: options.variant === \"text\" ? \"hic-icon-btn hic-text-btn\" : \"hic-icon-btn\",\n type: \"button\",\n title: options.title,\n \"aria-label\": options.ariaLabel,\n onClick: () => {\n runAsynchronously(async () => {\n await copyTextToClipboard(options.getText());\n button.textContent = options.variant === \"text\" ? \"Copied\" : \"✓\";\n setTimeout(() => setHtml(button, idleHtml), 1500);\n }, {\n noErrorLogging: true,\n onError: (error) => {\n options.onCopyError(error);\n button.textContent = options.variant === \"text\" ? \"Copy failed\" : \"!\";\n setTimeout(() => setHtml(button, idleHtml), 1500);\n },\n });\n },\n });\n setHtml(button, idleHtml);\n return button;\n}\n\nexport type IssueCardOptions = {\n kind: IssueCardKind,\n /** Short uppercase label in the card's badge, eg. \"Config error\". */\n badge: string,\n title: string,\n /** One or two sentences on what this means for the running app. */\n bodyText: string,\n messageLabel: string,\n message: string,\n /** Concrete steps the developer should take; rendered as a list above the footer. */\n howToFix?: readonly string[],\n footerText: string,\n ariaLabel: string,\n /** Prompt for the \"copy AI prompt\" button, ie. the message plus enough context for a coding agent to fix it. */\n aiPrompt: string,\n onCopyError: (error: unknown) => void,\n onCopyAiPromptError: (error: unknown) => void,\n onMinimize: () => void,\n};\n\nexport function renderIssueCard(options: IssueCardOptions): HTMLElement {\n const logoSpan = h(\"span\", { className: \"hic-logo\" });\n setHtml(logoSpan, HEXCLAVE_LOGO_SVG);\n\n return h(\"div\", { className: \"hic-backdrop\" },\n h(\"div\", { className: options.kind === \"error\" ? \"hic-card\" : \"hic-card hic-card-warning\", role: \"alertdialog\", \"aria-modal\": \"true\", \"aria-label\": options.ariaLabel, tabindex: \"-1\" },\n h(\"div\", { className: \"hic-card-inner\" },\n h(\"div\", { className: \"hic-header\" },\n h(\"div\", { className: \"hic-title-row\" },\n logoSpan,\n h(\"div\", null,\n h(\"span\", { className: \"hic-badge\" }, options.badge),\n h(\"div\", { className: \"hic-title\" }, options.title),\n ),\n ),\n h(\"div\", { className: \"hic-actions\" },\n renderCopyButton({\n variant: \"icon\",\n title: \"Copy AI prompt\",\n ariaLabel: `Copy AI prompt for ${options.ariaLabel}`,\n getText: () => options.aiPrompt,\n onCopyError: options.onCopyAiPromptError,\n }),\n h(\"button\", {\n className: \"hic-icon-btn\",\n type: \"button\",\n title: \"Minimize\",\n \"aria-label\": `Minimize ${options.ariaLabel}`,\n onClick: options.onMinimize,\n }, \"–\"),\n ),\n ),\n h(\"div\", { className: \"hic-body\" },\n options.bodyText,\n h(\"div\", { className: \"hic-message-header\" },\n h(\"div\", { className: \"hic-message-label\" }, options.messageLabel),\n renderCopyButton({\n variant: \"text\",\n title: `Copy ${options.messageLabel.toLowerCase()}`,\n ariaLabel: `Copy ${options.ariaLabel} message`,\n getText: () => options.message,\n onCopyError: options.onCopyError,\n }),\n ),\n h(\"div\", { className: \"hic-message\" }, options.message),\n options.howToFix == null || options.howToFix.length === 0 ? null : h(\"div\", null,\n h(\"div\", { className: \"hic-message-header\" },\n h(\"div\", { className: \"hic-message-label\" }, \"How to fix\"),\n ),\n h(\"ul\",\n { className: \"hic-fix-list\" },\n ...options.howToFix.map((step) => h(\"li\", null, step)),\n ),\n ),\n h(\"div\", { className: \"hic-footer\" }, options.footerText),\n ),\n ),\n ),\n );\n}\n\nconst FOCUSABLE_SELECTOR = \"a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex='-1'])\";\n\nexport type IssueCardFocusTrap = {\n /**\n * Whatever had focus before the card first appeared. Callers that rebind the trap to a re-rendered card pass it back\n * in, so focus still returns to where the developer left it once the card is gone for good.\n */\n previouslyFocused: HTMLElement | null,\n release: (releaseOptions?: { restoreFocus?: boolean }) => void,\n};\n\n/**\n * Keeps keyboard focus inside a mounted card, which claims to be an `aria-modal` alertdialog and therefore has to behave\n * like one: the flow behind the card is dead until the problem is fixed, so tabbing into it would only let a keyboard\n * user wander through a page that cannot work while the card stays invisible to them.\n *\n * Call right after mounting the card, and release the trap when the card is minimized, replaced or removed. Releasing\n * hands focus back to `previouslyFocused` unless `restoreFocus: false` is passed, which is what a caller that is about\n * to rebind the trap to a freshly rendered card wants.\n */\nexport function trapFocusInIssueCard(cardRoot: HTMLElement, options: {\n moveFocusIntoCard?: boolean,\n previouslyFocused?: HTMLElement | null,\n} = {}): IssueCardFocusTrap {\n const previouslyFocused = options.previouslyFocused !== undefined\n ? options.previouslyFocused\n : document.activeElement instanceof HTMLElement ? document.activeElement : null;\n const card = cardRoot.querySelector(\".hic-card\");\n if (!(card instanceof HTMLElement)) return { previouslyFocused, release: () => {} };\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== \"Tab\") return;\n const focusable = [...card.querySelectorAll(FOCUSABLE_SELECTOR)].filter((element): element is HTMLElement => element instanceof HTMLElement);\n const first = focusable[0] ?? card;\n const last = focusable[focusable.length - 1] ?? card;\n const active = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n\n let target: HTMLElement | null = null;\n if (active == null || !card.contains(active)) {\n // Focus is outside the card (the page moved it, or it never got in): pull it back to the card's near end.\n target = event.shiftKey ? last : first;\n } else if (active === last && !event.shiftKey) {\n target = first;\n } else if (active === first && event.shiftKey) {\n target = last;\n }\n if (target == null) return;\n event.preventDefault();\n target.focus();\n };\n\n document.addEventListener(\"keydown\", onKeyDown, true);\n if (options.moveFocusIntoCard !== false) {\n card.focus();\n }\n\n return {\n previouslyFocused,\n release: (releaseOptions) => {\n document.removeEventListener(\"keydown\", onKeyDown, true);\n if (releaseOptions?.restoreFocus === false) return;\n if (previouslyFocused != null && previouslyFocused.isConnected) {\n previouslyFocused.focus();\n }\n },\n };\n}\n\nexport function renderIssuePill(options: {\n kind: IssueCardKind,\n label: string,\n ariaLabel: string,\n onClick: () => void,\n}): HTMLElement {\n const logoSpan = h(\"span\", { className: \"hic-pill-logo\" });\n setHtml(logoSpan, HEXCLAVE_LOGO_SVG);\n return h(\"button\", {\n className: options.kind === \"error\" ? \"hic-pill\" : \"hic-pill hic-pill-warning\",\n type: \"button\",\n \"aria-label\": options.ariaLabel,\n onClick: options.onClick,\n },\n logoSpan,\n h(\"span\", null, options.label),\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,59 @@
1
+ let vitest = require("vitest");
2
+ let __issue_card_js = require("./issue-card.js");
3
+ //#region src/in-page-ui/issue-card.test.ts
4
+ // @vitest-environment jsdom
5
+ function mountCard() {
6
+ const root = document.body.appendChild(document.createElement("div"));
7
+ root.appendChild((0, __issue_card_js.renderIssueCard)({
8
+ kind: "error",
9
+ badge: "Config error",
10
+ title: "Something is misconfigured",
11
+ bodyText: "Body",
12
+ messageLabel: "Error message",
13
+ message: "Message",
14
+ footerText: "Footer",
15
+ ariaLabel: "Hexclave config error",
16
+ aiPrompt: "prompt",
17
+ onCopyError: () => {},
18
+ onCopyAiPromptError: () => {},
19
+ onMinimize: () => {}
20
+ }));
21
+ return root;
22
+ }
23
+ function pressTab() {
24
+ document.dispatchEvent(new KeyboardEvent("keydown", {
25
+ key: "Tab",
26
+ bubbles: true,
27
+ cancelable: true
28
+ }));
29
+ }
30
+ function cardButtons(root) {
31
+ return [...root.querySelectorAll(".hic-card button")];
32
+ }
33
+ (0, vitest.describe)("issue card focus trap", () => {
34
+ (0, vitest.afterEach)(() => {
35
+ document.body.replaceChildren();
36
+ });
37
+ (0, vitest.it)("follows a re-rendered card without moving focus or losing the original focus owner", () => {
38
+ const pageButton = document.body.appendChild(document.createElement("button"));
39
+ pageButton.focus();
40
+ const firstRoot = mountCard();
41
+ const firstTrap = (0, __issue_card_js.trapFocusInIssueCard)(firstRoot);
42
+ (0, vitest.expect)(document.activeElement).toBe(firstRoot.querySelector(".hic-card"));
43
+ firstRoot.remove();
44
+ const secondRoot = mountCard();
45
+ firstTrap.release({ restoreFocus: false });
46
+ const secondTrap = (0, __issue_card_js.trapFocusInIssueCard)(secondRoot, {
47
+ moveFocusIntoCard: false,
48
+ previouslyFocused: firstTrap.previouslyFocused
49
+ });
50
+ (0, vitest.expect)(document.activeElement).not.toBe(secondRoot.querySelector(".hic-card"));
51
+ pressTab();
52
+ (0, vitest.expect)(document.activeElement).toBe(cardButtons(secondRoot)[0]);
53
+ secondTrap.release();
54
+ (0, vitest.expect)(document.activeElement).toBe(pageButton);
55
+ });
56
+ });
57
+ //#endregion
58
+
59
+ //# sourceMappingURL=issue-card.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issue-card.test.js","names":[],"sources":["../../src/in-page-ui/issue-card.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//===========================================\n// @vitest-environment jsdom\n\nimport { afterEach, describe, expect, it } from \"vitest\";\nimport { renderIssueCard, trapFocusInIssueCard } from \"./issue-card\";\n\nfunction mountCard(): HTMLElement {\n const root = document.body.appendChild(document.createElement(\"div\"));\n root.appendChild(renderIssueCard({\n kind: \"error\",\n badge: \"Config error\",\n title: \"Something is misconfigured\",\n bodyText: \"Body\",\n messageLabel: \"Error message\",\n message: \"Message\",\n footerText: \"Footer\",\n ariaLabel: \"Hexclave config error\",\n aiPrompt: \"prompt\",\n onCopyError: () => {},\n onCopyAiPromptError: () => {},\n onMinimize: () => {},\n }));\n return root;\n}\n\nfunction pressTab() {\n document.dispatchEvent(new KeyboardEvent(\"keydown\", { key: \"Tab\", bubbles: true, cancelable: true }));\n}\n\nfunction cardButtons(root: HTMLElement): HTMLButtonElement[] {\n return [...root.querySelectorAll<HTMLButtonElement>(\".hic-card button\")];\n}\n\ndescribe(\"issue card focus trap\", () => {\n afterEach(() => {\n document.body.replaceChildren();\n });\n\n it(\"follows a re-rendered card without moving focus or losing the original focus owner\", () => {\n const pageButton = document.body.appendChild(document.createElement(\"button\"));\n pageButton.focus();\n\n const firstRoot = mountCard();\n const firstTrap = trapFocusInIssueCard(firstRoot);\n expect(document.activeElement).toBe(firstRoot.querySelector(\".hic-card\"));\n\n // What the pushed-config overlay does on every poll: throw the rendered card away and render a fresh one.\n firstRoot.remove();\n const secondRoot = mountCard();\n firstTrap.release({ restoreFocus: false });\n const secondTrap = trapFocusInIssueCard(secondRoot, {\n moveFocusIntoCard: false,\n previouslyFocused: firstTrap.previouslyFocused,\n });\n expect(document.activeElement).not.toBe(secondRoot.querySelector(\".hic-card\"));\n\n // The trap now belongs to the visible card, so Tab lands inside it instead of inside the detached one.\n pressTab();\n expect(document.activeElement).toBe(cardButtons(secondRoot)[0]);\n\n secondTrap.release();\n expect(document.activeElement).toBe(pageButton);\n });\n});\n"],"mappings":";;;;AASA,SAAS,YAAyB;CAChC,MAAM,OAAO,SAAS,KAAK,YAAY,SAAS,cAAc,KAAK,CAAC;CACpE,KAAK,aAAA,GAAA,gBAAA,gBAAA,CAA4B;EAC/B,MAAM;EACN,OAAO;EACP,OAAO;EACP,UAAU;EACV,cAAc;EACd,SAAS;EACT,YAAY;EACZ,WAAW;EACX,UAAU;EACV,mBAAmB,CAAC;EACpB,2BAA2B,CAAC;EAC5B,kBAAkB,CAAC;CACrB,CAAC,CAAC;CACF,OAAO;AACT;AAEA,SAAS,WAAW;CAClB,SAAS,cAAc,IAAI,cAAc,WAAW;EAAE,KAAK;EAAO,SAAS;EAAM,YAAY;CAAK,CAAC,CAAC;AACtG;AAEA,SAAS,YAAY,MAAwC;CAC3D,OAAO,CAAC,GAAG,KAAK,iBAAoC,kBAAkB,CAAC;AACzE;qBAES,+BAA+B;CACtC,CAAA,GAAA,OAAA,UAAA,OAAgB;EACd,SAAS,KAAK,gBAAgB;CAChC,CAAC;CAED,CAAA,GAAA,OAAA,GAAA,CAAG,4FAA4F;EAC7F,MAAM,aAAa,SAAS,KAAK,YAAY,SAAS,cAAc,QAAQ,CAAC;EAC7E,WAAW,MAAM;EAEjB,MAAM,YAAY,UAAU;EAC5B,MAAM,aAAA,GAAA,gBAAA,qBAAA,CAAiC,SAAS;EAChD,CAAA,GAAA,OAAA,OAAA,CAAO,SAAS,aAAa,CAAC,CAAC,KAAK,UAAU,cAAc,WAAW,CAAC;EAGxE,UAAU,OAAO;EACjB,MAAM,aAAa,UAAU;EAC7B,UAAU,QAAQ,EAAE,cAAc,MAAM,CAAC;EACzC,MAAM,cAAA,GAAA,gBAAA,qBAAA,CAAkC,YAAY;GAClD,mBAAmB;GACnB,mBAAmB,UAAU;EAC/B,CAAC;EACD,CAAA,GAAA,OAAA,OAAA,CAAO,SAAS,aAAa,CAAC,CAAC,IAAI,KAAK,WAAW,cAAc,WAAW,CAAC;EAG7E,SAAS;EACT,CAAA,GAAA,OAAA,OAAA,CAAO,SAAS,aAAa,CAAC,CAAC,KAAK,YAAY,UAAU,CAAC,CAAC,EAAE;EAE9D,WAAW,QAAQ;EACnB,CAAA,GAAA,OAAA,OAAA,CAAO,SAAS,aAAa,CAAC,CAAC,KAAK,UAAU;CAChD,CAAC;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ //#region src/in-page-ui/logo.d.ts
2
+ declare const 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>";
3
+ //#endregion
4
+ export { HEXCLAVE_LOGO_SVG };
5
+ //# sourceMappingURL=logo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logo.d.ts","names":[],"sources":["../../src/in-page-ui/logo.ts"],"mappings":";cAOa,iBAAA"}
@@ -0,0 +1,7 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/in-page-ui/logo.ts
3
+ const 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>";
4
+ //#endregion
5
+ exports.HEXCLAVE_LOGO_SVG = HEXCLAVE_LOGO_SVG;
6
+
7
+ //# sourceMappingURL=logo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logo.js","names":[],"sources":["../../src/in-page-ui/logo.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// Hexclave mark — hexagon outline with three radial bars, monochrome via currentColor so it inherits the surrounding\n// text color. Sourced from apps/dashboard/public/hexclave-icon.svg (gradient + glow stripped; this is a tiny glyph, not\n// the full brand mark). Shared by every in-page UI so the mark cannot drift between them.\nexport const 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>';\n"],"mappings":";;AAOA,MAAa,oBAAoB"}
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@ import { a as PlanUsageRow, i as PlanUsagePlanId, n as PlanUsageKind, r as PlanU
6
6
  import { a as AdminWorkflowRunState, c as AdminWorkflowStepAttempt, d as AdminWorkflowUpgradeResult, f as AdminWorkflowVersion, i as AdminWorkflowRunDetails, l as AdminWorkflowSyncResult, n as AdminWorkflowDivergenceDiagnostic, o as AdminWorkflowRunsFilter, r as AdminWorkflowRun, s as AdminWorkflowStep, t as AdminWorkflow, u as AdminWorkflowTrigger } from "./workflows-DEb7pIuQ.js";
7
7
  import { r as OAuthConnection, t as Connection } from "./index-ClBTM-St.js";
8
8
  import { i as ServerContactChannel, t as ContactChannel } from "./index-DN04TjLM.js";
9
- import { $ as TeamCreateOptions, B as StackServerAppConstructor, D as HexclaveAdminApp, E as EmailOutboxUpdateOptions, F as StackAdminAppConstructorOptions, H as EditableTeamMemberProfile, I as HexclaveServerApp, J as ServerTeamCreateOptions, K as ServerListUsersOptions, L as HexclaveServerAppConstructor, N as StackAdminApp, O as HexclaveAdminAppConstructor, Ot as User, P as StackAdminAppConstructor, Q as Team, R as HexclaveServerAppConstructorOptions, St as ServerUser, T as EmailOutboxListResult, U as ReceivedTeamInvitation, V as StackServerAppConstructorOptions, W as SentTeamInvitation, X as ServerTeamUpdateOptions, Y as ServerTeamMemberProfile, Z as ServerTeamUser, _ as AdminProjectCreateOptions, _t as OAuthProvider, a as StackClientApp, c as StackClientAppJson, d as AdminDeploymentEnvVarOptions, et as TeamInvitation, f as AdminDeploymentRunJson, ft as CurrentInternalServerUser, g as AdminProject, h as AdminOwnedProject, ht as CurrentUser, i as HexclaveClientAppJson, it as TeamUser, k as HexclaveAdminAppConstructorOptions, l as AdminDeploymentDomainJson, m as AdminDeploymentServiceJson, mt as CurrentServerUser, n as HexclaveClientAppConstructor, o as StackClientAppConstructor, p as AdminDeploymentServiceBuildOptions, pt as CurrentInternalUser, q as ServerTeam, r as HexclaveClientAppConstructorOptions, rt as TeamUpdateOptions, s as StackClientAppConstructorOptions, t as HexclaveClientApp, tt as TeamMemberProfile, u as AdminDeploymentEnvVarJson, ut as Auth, v as AdminProjectUpdateOptions, w as EmailOutboxListOptions, x as PushedConfigSource, xt as ServerOAuthProvider, y as Project, z as StackServerApp } from "./client-app-WOX3pOo1.js";
9
+ import { $ as TeamCreateOptions, B as StackServerAppConstructor, D as HexclaveAdminApp, E as EmailOutboxUpdateOptions, F as StackAdminAppConstructorOptions, H as EditableTeamMemberProfile, I as HexclaveServerApp, J as ServerTeamCreateOptions, K as ServerListUsersOptions, L as HexclaveServerAppConstructor, N as StackAdminApp, O as HexclaveAdminAppConstructor, Ot as User, P as StackAdminAppConstructor, Q as Team, R as HexclaveServerAppConstructorOptions, St as ServerUser, T as EmailOutboxListResult, U as ReceivedTeamInvitation, V as StackServerAppConstructorOptions, W as SentTeamInvitation, X as ServerTeamUpdateOptions, Y as ServerTeamMemberProfile, Z as ServerTeamUser, _ as AdminProjectCreateOptions, _t as OAuthProvider, a as StackClientApp, c as StackClientAppJson, d as AdminDeploymentEnvVarOptions, et as TeamInvitation, f as AdminDeploymentRunJson, ft as CurrentInternalServerUser, g as AdminProject, h as AdminOwnedProject, ht as CurrentUser, i as HexclaveClientAppJson, it as TeamUser, k as HexclaveAdminAppConstructorOptions, l as AdminDeploymentDomainJson, m as AdminDeploymentServiceJson, mt as CurrentServerUser, n as HexclaveClientAppConstructor, o as StackClientAppConstructor, p as AdminDeploymentServiceBuildOptions, pt as CurrentInternalUser, q as ServerTeam, r as HexclaveClientAppConstructorOptions, rt as TeamUpdateOptions, s as StackClientAppConstructorOptions, t as HexclaveClientApp, tt as TeamMemberProfile, u as AdminDeploymentEnvVarJson, ut as Auth, v as AdminProjectUpdateOptions, w as EmailOutboxListOptions, x as PushedConfigSource, xt as ServerOAuthProvider, y as Project, z as StackServerApp } from "./client-app-R5X8wyeV.js";
10
10
  import { a as AdminProjectConfigUpdateOptions, i as AdminProjectConfig, n as AdminEmailConfig, o as OAuthProviderConfig, r as AdminOAuthProviderConfig, s as ProjectConfig, t as AdminDomainConfig } from "./index-B-MazpM_.js";
11
11
  import { r as getPagePrompt } from "./url-targets-BJgkwPGW.js";
12
12
  import { getConvexProvidersConfig } from "./integrations/convex.js";
@@ -1,2 +1,2 @@
1
- import { t as _HexclaveAdminAppImplIncomplete } from "../../../../admin-app-impl-BhrjJlxj.js";
1
+ import { t as _HexclaveAdminAppImplIncomplete } from "../../../../admin-app-impl-CHQtsn4f.js";
2
2
  export { _HexclaveAdminAppImplIncomplete };
@@ -1,6 +1,7 @@
1
1
  let vitest = require("vitest");
2
2
  let ______common_js = require("../../common.js");
3
3
  let ___interfaces_client_app_js = require("../interfaces/client-app.js");
4
+ let __client_app_impl_js = require("./client-app-impl.js");
4
5
  //#region src/lib/hexclave-app/apps/implementations/client-app-impl.automatic-side-effects.test.ts
5
6
  const baseOptions = {
6
7
  baseUrl: "http://localhost:12345",
@@ -95,6 +96,34 @@ const baseOptions = {
95
96
  const first = ___interfaces_client_app_js.HexclaveClientApp[______common_js.hexclaveAppInternalsSymbol].fromClientJson(json);
96
97
  (0, vitest.expect)(___interfaces_client_app_js.HexclaveClientApp[______common_js.hexclaveAppInternalsSymbol].fromClientJson(json)).toBe(first);
97
98
  });
99
+ (0, vitest.it)("keeps stripping the browser action parameter after a router restores it", () => {
100
+ vitest.vi.useFakeTimers();
101
+ const previousWindow = Reflect.get(globalThis, "window");
102
+ const hadPreviousWindow = Reflect.has(globalThis, "window");
103
+ let currentHref = "http://localhost:12345/?hexclave_action_id=action-id";
104
+ Reflect.set(globalThis, "window", {
105
+ location: { get href() {
106
+ return currentHref;
107
+ } },
108
+ history: {
109
+ state: null,
110
+ replaceState: (_state, _title, url) => {
111
+ currentHref = String(url);
112
+ }
113
+ },
114
+ setTimeout
115
+ });
116
+ try {
117
+ (0, __client_app_impl_js.stripBrowserActionQueryParam)();
118
+ currentHref = "http://localhost:12345/?hexclave_action_id=action-id";
119
+ vitest.vi.runAllTimers();
120
+ (0, vitest.expect)(currentHref).toBe("http://localhost:12345/");
121
+ } finally {
122
+ vitest.vi.useRealTimers();
123
+ if (hadPreviousWindow) Reflect.set(globalThis, "window", previousWindow);
124
+ else Reflect.deleteProperty(globalThis, "window");
125
+ }
126
+ });
98
127
  });
99
128
  //#endregion
100
129
 
@@ -1 +1 @@
1
- {"version":3,"file":"client-app-impl.automatic-side-effects.test.js","names":["HexclaveClientApp","hexclaveAppInternalsSymbol"],"sources":["../../../../../src/lib/hexclave-app/apps/implementations/client-app-impl.automatic-side-effects.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 } from \"vitest\";\nimport { hexclaveAppInternalsSymbol } from \"../../common\";\nimport { HexclaveClientApp, HexclaveClientAppConstructorOptions, HexclaveClientAppJson } from \"../interfaces/client-app\";\n\nconst baseOptions = {\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000000\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"none\",\n} satisfies HexclaveClientAppConstructorOptions<true, string>;\n\ndescribe(\"HexclaveClientApp automatic side effects\", () => {\n it(\"does not inspect browser state when disabled\", () => {\n const previousWindow = Reflect.get(globalThis, \"window\");\n const previousDocument = Reflect.get(globalThis, \"document\");\n const hadPreviousWindow = Reflect.has(globalThis, \"window\");\n const hadPreviousDocument = Reflect.has(globalThis, \"document\");\n const browserGlobal = {};\n Object.defineProperty(browserGlobal, \"location\", {\n get() {\n throw new Error(\"Construction must not inspect the current URL when automatic side effects are disabled\");\n },\n });\n\n Reflect.set(globalThis, \"window\", browserGlobal);\n Object.defineProperty(globalThis, \"document\", {\n configurable: true,\n get() {\n throw new Error(\"Construction must not access the document when automatic side effects are disabled\");\n },\n });\n\n try {\n expect(() => new HexclaveClientApp({\n ...baseOptions,\n automaticSideEffects: false,\n })).not.toThrow();\n } finally {\n if (hadPreviousWindow) {\n Reflect.set(globalThis, \"window\", previousWindow);\n } else {\n Reflect.deleteProperty(globalThis, \"window\");\n }\n if (hadPreviousDocument) {\n Object.defineProperty(globalThis, \"document\", {\n configurable: true,\n value: previousDocument,\n writable: true,\n });\n } else {\n Reflect.deleteProperty(globalThis, \"document\");\n }\n }\n });\n\n it(\"does not initialize automatic side effects when disabled\", () => {\n const methodName = \"_initializeAutomaticSideEffects\";\n const originalInitializer = Reflect.get(HexclaveClientApp.prototype, methodName);\n let initializationCalls = 0;\n Reflect.set(HexclaveClientApp.prototype, methodName, () => {\n initializationCalls += 1;\n });\n\n try {\n new HexclaveClientApp({\n ...baseOptions,\n automaticSideEffects: false,\n });\n\n expect(initializationCalls).toBe(0);\n } finally {\n Reflect.set(HexclaveClientApp.prototype, methodName, originalInitializer);\n }\n });\n\n it.each([undefined, true])(\"retains automatic initialization when automaticSideEffects is %s\", (automaticSideEffects) => {\n const methodName = \"_initializeAutomaticSideEffects\";\n const originalInitializer = Reflect.get(HexclaveClientApp.prototype, methodName);\n let initializationCalls = 0;\n Reflect.set(HexclaveClientApp.prototype, methodName, () => {\n initializationCalls += 1;\n });\n\n try {\n new HexclaveClientApp({\n ...baseOptions,\n automaticSideEffects,\n });\n\n expect(initializationCalls).toBe(1);\n } finally {\n Reflect.set(HexclaveClientApp.prototype, methodName, originalInitializer);\n }\n });\n\n it(\"preserves the option through serialization\", () => {\n const app = new HexclaveClientApp({\n ...baseOptions,\n automaticSideEffects: false,\n });\n\n expect(app[hexclaveAppInternalsSymbol].toClientJson().automaticSideEffects).toBe(false);\n });\n\n it(\"preserves stable identity when deserializing with automatic side effects disabled\", () => {\n const json: HexclaveClientAppJson<false, string> = {\n baseUrl: baseOptions.baseUrl,\n projectId: baseOptions.projectId,\n publishableClientKey: baseOptions.publishableClientKey,\n tokenStore: null,\n redirectMethod: baseOptions.redirectMethod,\n automaticSideEffects: false,\n uniqueIdentifier: \"00000000-0000-4000-8000-000000000001\",\n };\n\n const first = HexclaveClientApp[hexclaveAppInternalsSymbol].fromClientJson(json);\n const second = HexclaveClientApp[hexclaveAppInternalsSymbol].fromClientJson(json);\n\n expect(second).toBe(first);\n });\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"client-app-impl.automatic-side-effects.test.js","names":["HexclaveClientApp","hexclaveAppInternalsSymbol"],"sources":["../../../../../src/lib/hexclave-app/apps/implementations/client-app-impl.automatic-side-effects.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 { hexclaveAppInternalsSymbol } from \"../../common\";\nimport { HexclaveClientApp, HexclaveClientAppConstructorOptions, HexclaveClientAppJson } from \"../interfaces/client-app\";\nimport { stripBrowserActionQueryParam } from \"./client-app-impl\";\n\nconst baseOptions = {\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000000\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"none\",\n} satisfies HexclaveClientAppConstructorOptions<true, string>;\n\ndescribe(\"HexclaveClientApp automatic side effects\", () => {\n it(\"does not inspect browser state when disabled\", () => {\n const previousWindow = Reflect.get(globalThis, \"window\");\n const previousDocument = Reflect.get(globalThis, \"document\");\n const hadPreviousWindow = Reflect.has(globalThis, \"window\");\n const hadPreviousDocument = Reflect.has(globalThis, \"document\");\n const browserGlobal = {};\n Object.defineProperty(browserGlobal, \"location\", {\n get() {\n throw new Error(\"Construction must not inspect the current URL when automatic side effects are disabled\");\n },\n });\n\n Reflect.set(globalThis, \"window\", browserGlobal);\n Object.defineProperty(globalThis, \"document\", {\n configurable: true,\n get() {\n throw new Error(\"Construction must not access the document when automatic side effects are disabled\");\n },\n });\n\n try {\n expect(() => new HexclaveClientApp({\n ...baseOptions,\n automaticSideEffects: false,\n })).not.toThrow();\n } finally {\n if (hadPreviousWindow) {\n Reflect.set(globalThis, \"window\", previousWindow);\n } else {\n Reflect.deleteProperty(globalThis, \"window\");\n }\n if (hadPreviousDocument) {\n Object.defineProperty(globalThis, \"document\", {\n configurable: true,\n value: previousDocument,\n writable: true,\n });\n } else {\n Reflect.deleteProperty(globalThis, \"document\");\n }\n }\n });\n\n it(\"does not initialize automatic side effects when disabled\", () => {\n const methodName = \"_initializeAutomaticSideEffects\";\n const originalInitializer = Reflect.get(HexclaveClientApp.prototype, methodName);\n let initializationCalls = 0;\n Reflect.set(HexclaveClientApp.prototype, methodName, () => {\n initializationCalls += 1;\n });\n\n try {\n new HexclaveClientApp({\n ...baseOptions,\n automaticSideEffects: false,\n });\n\n expect(initializationCalls).toBe(0);\n } finally {\n Reflect.set(HexclaveClientApp.prototype, methodName, originalInitializer);\n }\n });\n\n it.each([undefined, true])(\"retains automatic initialization when automaticSideEffects is %s\", (automaticSideEffects) => {\n const methodName = \"_initializeAutomaticSideEffects\";\n const originalInitializer = Reflect.get(HexclaveClientApp.prototype, methodName);\n let initializationCalls = 0;\n Reflect.set(HexclaveClientApp.prototype, methodName, () => {\n initializationCalls += 1;\n });\n\n try {\n new HexclaveClientApp({\n ...baseOptions,\n automaticSideEffects,\n });\n\n expect(initializationCalls).toBe(1);\n } finally {\n Reflect.set(HexclaveClientApp.prototype, methodName, originalInitializer);\n }\n });\n\n it(\"preserves the option through serialization\", () => {\n const app = new HexclaveClientApp({\n ...baseOptions,\n automaticSideEffects: false,\n });\n\n expect(app[hexclaveAppInternalsSymbol].toClientJson().automaticSideEffects).toBe(false);\n });\n\n it(\"preserves stable identity when deserializing with automatic side effects disabled\", () => {\n const json: HexclaveClientAppJson<false, string> = {\n baseUrl: baseOptions.baseUrl,\n projectId: baseOptions.projectId,\n publishableClientKey: baseOptions.publishableClientKey,\n tokenStore: null,\n redirectMethod: baseOptions.redirectMethod,\n automaticSideEffects: false,\n uniqueIdentifier: \"00000000-0000-4000-8000-000000000001\",\n };\n\n const first = HexclaveClientApp[hexclaveAppInternalsSymbol].fromClientJson(json);\n const second = HexclaveClientApp[hexclaveAppInternalsSymbol].fromClientJson(json);\n\n expect(second).toBe(first);\n });\n\n it(\"keeps stripping the browser action parameter after a router restores it\", () => {\n vi.useFakeTimers();\n const previousWindow = Reflect.get(globalThis, \"window\");\n const hadPreviousWindow = Reflect.has(globalThis, \"window\");\n let currentHref = \"http://localhost:12345/?hexclave_action_id=action-id\";\n const browserGlobal = {\n location: {\n get href() {\n return currentHref;\n },\n },\n history: {\n state: null,\n replaceState: (_state: null, _title: string, url: string | URL) => {\n currentHref = String(url);\n },\n },\n setTimeout,\n };\n\n Reflect.set(globalThis, \"window\", browserGlobal);\n try {\n stripBrowserActionQueryParam();\n currentHref = \"http://localhost:12345/?hexclave_action_id=action-id\";\n vi.runAllTimers();\n expect(currentHref).toBe(\"http://localhost:12345/\");\n } finally {\n vi.useRealTimers();\n if (hadPreviousWindow) {\n Reflect.set(globalThis, \"window\", previousWindow);\n } else {\n Reflect.deleteProperty(globalThis, \"window\");\n }\n }\n });\n});\n"],"mappings":";;;;;AASA,MAAM,cAAc;CAClB,SAAS;CACT,WAAW;CACX,sBAAsB;CACtB,YAAY;CACZ,gBAAgB;AAClB;qBAES,kDAAkD;CACzD,CAAA,GAAA,OAAA,GAAA,CAAG,sDAAsD;EACvD,MAAM,iBAAiB,QAAQ,IAAI,YAAY,QAAQ;EACvD,MAAM,mBAAmB,QAAQ,IAAI,YAAY,UAAU;EAC3D,MAAM,oBAAoB,QAAQ,IAAI,YAAY,QAAQ;EAC1D,MAAM,sBAAsB,QAAQ,IAAI,YAAY,UAAU;EAC9D,MAAM,gBAAgB,CAAC;EACvB,OAAO,eAAe,eAAe,YAAY,EAC/C,MAAM;GACJ,MAAM,IAAI,MAAM,wFAAwF;EAC1G,EACF,CAAC;EAED,QAAQ,IAAI,YAAY,UAAU,aAAa;EAC/C,OAAO,eAAe,YAAY,YAAY;GAC5C,cAAc;GACd,MAAM;IACJ,MAAM,IAAI,MAAM,oFAAoF;GACtG;EACF,CAAC;EAED,IAAI;GACF,CAAA,GAAA,OAAA,OAAA,OAAa,IAAIA,4BAAAA,kBAAkB;IACjC,GAAG;IACH,sBAAsB;GACxB,CAAC,CAAC,CAAC,CAAC,IAAI,QAAQ;EAClB,UAAU;GACR,IAAI,mBACF,QAAQ,IAAI,YAAY,UAAU,cAAc;QAEhD,QAAQ,eAAe,YAAY,QAAQ;GAE7C,IAAI,qBACF,OAAO,eAAe,YAAY,YAAY;IAC5C,cAAc;IACd,OAAO;IACP,UAAU;GACZ,CAAC;QAED,QAAQ,eAAe,YAAY,UAAU;EAEjD;CACF,CAAC;CAED,CAAA,GAAA,OAAA,GAAA,CAAG,kEAAkE;EACnE,MAAM,aAAa;EACnB,MAAM,sBAAsB,QAAQ,IAAIA,4BAAAA,kBAAkB,WAAW,UAAU;EAC/E,IAAI,sBAAsB;EAC1B,QAAQ,IAAIA,4BAAAA,kBAAkB,WAAW,kBAAkB;GACzD,uBAAuB;EACzB,CAAC;EAED,IAAI;GACF,IAAIA,4BAAAA,kBAAkB;IACpB,GAAG;IACH,sBAAsB;GACxB,CAAC;GAED,CAAA,GAAA,OAAA,OAAA,CAAO,mBAAmB,CAAC,CAAC,KAAK,CAAC;EACpC,UAAU;GACR,QAAQ,IAAIA,4BAAAA,kBAAkB,WAAW,YAAY,mBAAmB;EAC1E;CACF,CAAC;CAED,OAAA,GAAG,KAAK,CAAC,KAAA,GAAW,IAAI,CAAC,CAAC,CAAC,qEAAqE,yBAAyB;EACvH,MAAM,aAAa;EACnB,MAAM,sBAAsB,QAAQ,IAAIA,4BAAAA,kBAAkB,WAAW,UAAU;EAC/E,IAAI,sBAAsB;EAC1B,QAAQ,IAAIA,4BAAAA,kBAAkB,WAAW,kBAAkB;GACzD,uBAAuB;EACzB,CAAC;EAED,IAAI;GACF,IAAIA,4BAAAA,kBAAkB;IACpB,GAAG;IACH;GACF,CAAC;GAED,CAAA,GAAA,OAAA,OAAA,CAAO,mBAAmB,CAAC,CAAC,KAAK,CAAC;EACpC,UAAU;GACR,QAAQ,IAAIA,4BAAAA,kBAAkB,WAAW,YAAY,mBAAmB;EAC1E;CACF,CAAC;CAED,CAAA,GAAA,OAAA,GAAA,CAAG,oDAAoD;EAMrD,CAAA,GAAA,OAAA,OAAA,CAAO,IALSA,4BAAAA,kBAAkB;GAChC,GAAG;GACH,sBAAsB;EACxB,CAES,CAAC,CAACC,gBAAAA,2BAA2B,CAAC,aAAa,CAAC,CAAC,oBAAoB,CAAC,CAAC,KAAK,KAAK;CACxF,CAAC;CAED,CAAA,GAAA,OAAA,GAAA,CAAG,2FAA2F;EAC5F,MAAM,OAA6C;GACjD,SAAS,YAAY;GACrB,WAAW,YAAY;GACvB,sBAAsB,YAAY;GAClC,YAAY;GACZ,gBAAgB,YAAY;GAC5B,sBAAsB;GACtB,kBAAkB;EACpB;EAEA,MAAM,QAAQD,4BAAAA,kBAAkBC,gBAAAA,2BAA2B,CAAC,eAAe,IAAI;EAG/E,CAAA,GAAA,OAAA,OAAA,CAFeD,4BAAAA,kBAAkBC,gBAAAA,2BAA2B,CAAC,eAAe,IAEhE,CAAC,CAAC,CAAC,KAAK,KAAK;CAC3B,CAAC;CAED,CAAA,GAAA,OAAA,GAAA,CAAG,iFAAiF;EAClF,OAAA,GAAG,cAAc;EACjB,MAAM,iBAAiB,QAAQ,IAAI,YAAY,QAAQ;EACvD,MAAM,oBAAoB,QAAQ,IAAI,YAAY,QAAQ;EAC1D,IAAI,cAAc;EAgBlB,QAAQ,IAAI,YAAY,UAAU;GAdhC,UAAU,EACR,IAAI,OAAO;IACT,OAAO;GACT,EACF;GACA,SAAS;IACP,OAAO;IACP,eAAe,QAAc,QAAgB,QAAsB;KACjE,cAAc,OAAO,GAAG;IAC1B;GACF;GACA;EAG4C,CAAC;EAC/C,IAAI;GACF,CAAA,GAAA,qBAAA,6BAAA,CAA6B;GAC7B,cAAc;GACd,OAAA,GAAG,aAAa;GAChB,CAAA,GAAA,OAAA,OAAA,CAAO,WAAW,CAAC,CAAC,KAAK,yBAAyB;EACpD,UAAU;GACR,OAAA,GAAG,cAAc;GACjB,IAAI,mBACF,QAAQ,IAAI,YAAY,UAAU,cAAc;QAEhD,QAAQ,eAAe,YAAY,QAAQ;EAE/C;CACF,CAAC;AACH,CAAC"}
@@ -1,3 +1,4 @@
1
+ let _hexclave_shared_dist_utils_errors = require("@hexclave/shared/dist/utils/errors");
1
2
  let vitest = require("vitest");
2
3
  let ______common_js = require("../../common.js");
3
4
  let ___interfaces_client_app_js = require("../interfaces/client-app.js");
@@ -51,6 +52,22 @@ function createMockDocument() {
51
52
  createElement: () => ({})
52
53
  };
53
54
  }
55
+ /**
56
+ * Installs a stand-in for `window` with only the parts the code under test touches. `globalThis.window` is typed as a
57
+ * full `Window`, which a hand-written stub can never be, so the assignment goes through `Reflect.set` — the stub's own
58
+ * shape stays checked, unlike with a cast on the object literal.
59
+ */
60
+ function setMockWindow(mockWindow) {
61
+ Reflect.set(globalThis, "window", mockWindow);
62
+ }
63
+ /**
64
+ * Calls one of the app's `protected` methods, which are part of the flows under test but not of the public SDK surface.
65
+ */
66
+ function callProtectedMethod(app, methodName, ...args) {
67
+ const method = Reflect.get(app, methodName);
68
+ if (typeof method !== "function") throw new Error(`Expected StackClientApp to have a ${methodName} method in tests.`);
69
+ return method.apply(app, args);
70
+ }
54
71
  (0, vitest.describe)("StackClientApp cross-domain auth", () => {
55
72
  (0, vitest.it)("keeps noRedirectBack same-domain redirects free of redirect-back state", async () => {
56
73
  (0, vitest.expect)(await (0, __redirect_page_urls_js.planRedirectToHandler)({
@@ -115,7 +132,8 @@ function createMockDocument() {
115
132
  tokenStore: "memory",
116
133
  redirectMethod: "none",
117
134
  urls: { signIn: "/handler/sign-in" },
118
- noAutomaticPrefetch: true
135
+ noAutomaticPrefetch: true,
136
+ devTool: false
119
137
  })[______common_js.hexclaveAppInternalsSymbol].getRedirectToHandlerUrl("signIn");
120
138
  const resolved = new URL(redirectUrl, "http://localhost");
121
139
  (0, vitest.expect)(resolved.pathname).toBe("/handler/sign-in");
@@ -136,7 +154,8 @@ function createMockDocument() {
136
154
  refreshToken: "stale-refresh-token"
137
155
  },
138
156
  redirectMethod: "none",
139
- noAutomaticPrefetch: true
157
+ noAutomaticPrefetch: true,
158
+ devTool: false
140
159
  });
141
160
  const clientInterface = Reflect.get(clientApp, "_interface");
142
161
  const originalSendClientRequest = Reflect.get(clientInterface, "sendClientRequest");
@@ -198,7 +217,8 @@ function createMockDocument() {
198
217
  tokenStore: "memory",
199
218
  redirectMethod: "window",
200
219
  urls: { default: { type: "hosted" } },
201
- noAutomaticPrefetch: true
220
+ noAutomaticPrefetch: true,
221
+ devTool: false
202
222
  });
203
223
  const outerState = "outer-cross-domain-state";
204
224
  const outerCodeChallenge = "abcdefghijklmnopqrstuvwxyzABCDEFG_0123456789-._~";
@@ -250,7 +270,8 @@ function createMockDocument() {
250
270
  tokenStore: "memory",
251
271
  redirectMethod: "window",
252
272
  urls: { default: { type: "hosted" } },
253
- noAutomaticPrefetch: true
273
+ noAutomaticPrefetch: true,
274
+ devTool: false
254
275
  });
255
276
  const tokenStore = Reflect.get(clientApp, "_memoryTokenStore");
256
277
  if (!(tokenStore instanceof _hexclave_shared_dist_utils_stores.Store)) throw new Error("Expected StackClientApp to use a memory token store in this test.");
@@ -316,7 +337,8 @@ function createMockDocument() {
316
337
  publishableClientKey: "stack-pk-test",
317
338
  tokenStore: "cookie",
318
339
  redirectMethod: "none",
319
- noAutomaticPrefetch: true
340
+ noAutomaticPrefetch: true,
341
+ devTool: false
320
342
  });
321
343
  const clientInterface = Reflect.get(clientApp, "_interface");
322
344
  const originalFetchNewAccessToken = Reflect.get(clientInterface, "fetchNewAccessToken");
@@ -367,7 +389,8 @@ function createMockDocument() {
367
389
  publishableClientKey: "stack-pk-test",
368
390
  tokenStore: "memory",
369
391
  redirectMethod: "window",
370
- noAutomaticPrefetch: true
392
+ noAutomaticPrefetch: true,
393
+ devTool: false
371
394
  });
372
395
  globalThis.document = createMockDocument();
373
396
  globalThis.window = { location: {
@@ -392,6 +415,99 @@ function createMockDocument() {
392
415
  globalThis.document = previousDocument;
393
416
  }
394
417
  });
418
+ (0, vitest.it)("reports malformed nested cross-domain auth URLs as setup errors", async () => {
419
+ const projectId = "00000000-0000-4000-8000-000000000012";
420
+ const previousWindow = globalThis.window;
421
+ const previousDocument = globalThis.document;
422
+ globalThis.document = createMockDocument();
423
+ const malformedCases = [
424
+ {
425
+ description: "redirect URI",
426
+ currentRefreshTokenId: "source-refresh-token-id",
427
+ params: {
428
+ redirect_uri: "not-a-url",
429
+ state: "nested-state",
430
+ code_challenge: "nested-code-challenge"
431
+ }
432
+ },
433
+ {
434
+ description: "after-callback redirect URL",
435
+ currentRefreshTokenId: "source-refresh-token-id",
436
+ params: {
437
+ redirect_uri: "https://source.example.test/handler/account-settings",
438
+ state: "nested-state",
439
+ code_challenge: "nested-code-challenge",
440
+ after_callback_redirect_url: "http://["
441
+ }
442
+ },
443
+ {
444
+ description: "callback URL",
445
+ currentRefreshTokenId: null,
446
+ params: { stack_nested_cross_domain_auth_callback_url: "http://[" }
447
+ }
448
+ ];
449
+ try {
450
+ for (const malformedCase of malformedCases) {
451
+ const currentUrl = new URL("https://target.example.test/nested-provider");
452
+ currentUrl.searchParams.set("stack_nested_cross_domain_auth_refresh_token_id", "source-refresh-token-id");
453
+ for (const [key, value] of Object.entries(malformedCase.params)) currentUrl.searchParams.set(key, value);
454
+ globalThis.window = previousWindow;
455
+ const clientApp = new ___interfaces_client_app_js.StackClientApp({
456
+ baseUrl: "http://localhost:12345",
457
+ projectId,
458
+ publishableClientKey: "stack-pk-test",
459
+ tokenStore: "memory",
460
+ redirectMethod: "window",
461
+ noAutomaticPrefetch: true,
462
+ devTool: false
463
+ });
464
+ setMockWindow({ location: { href: currentUrl.toString() } });
465
+ Reflect.set(clientApp, "_fetchCurrentRefreshTokenIdIfSignedIn", async () => malformedCase.currentRefreshTokenId);
466
+ Reflect.set(clientApp, "_isTrusted", async () => true);
467
+ const nestedAuthPromise = callProtectedMethod(clientApp, "_maybeHandleNestedCrossDomainAuth");
468
+ await (0, vitest.expect)(nestedAuthPromise).rejects.toThrowError(new RegExp(`${malformedCase.description} .* is not a valid absolute URL`));
469
+ await (0, vitest.expect)(nestedAuthPromise).rejects.toSatisfy((error) => _hexclave_shared_dist_utils_errors.HexclaveSetupError.isSetupError(error));
470
+ }
471
+ } finally {
472
+ globalThis.window = previousWindow;
473
+ globalThis.document = previousDocument;
474
+ }
475
+ });
476
+ (0, vitest.it)("keeps nested cross-domain auth failures off the page for a handoff that does not own the session", async () => {
477
+ const projectId = "00000000-0000-4000-8000-000000000013";
478
+ const previousWindow = globalThis.window;
479
+ const previousDocument = globalThis.document;
480
+ globalThis.document = createMockDocument();
481
+ const craftedRedirectUris = ["https://evil.example.test/handler/account-settings", "not-a-url"];
482
+ try {
483
+ for (const craftedRedirectUri of craftedRedirectUris) {
484
+ const currentUrl = new URL("https://target.example.test/nested-provider");
485
+ currentUrl.searchParams.set("stack_nested_cross_domain_auth_refresh_token_id", "attacker-chosen-refresh-token-id");
486
+ currentUrl.searchParams.set("redirect_uri", craftedRedirectUri);
487
+ currentUrl.searchParams.set("state", "nested-state");
488
+ currentUrl.searchParams.set("code_challenge", "nested-code-challenge");
489
+ globalThis.window = previousWindow;
490
+ const clientApp = new ___interfaces_client_app_js.StackClientApp({
491
+ baseUrl: "http://localhost:12345",
492
+ projectId,
493
+ publishableClientKey: "stack-pk-test",
494
+ tokenStore: "memory",
495
+ redirectMethod: "window",
496
+ noAutomaticPrefetch: true,
497
+ devTool: false
498
+ });
499
+ setMockWindow({ location: { href: currentUrl.toString() } });
500
+ Reflect.set(clientApp, "_fetchCurrentRefreshTokenIdIfSignedIn", async () => "this-apps-refresh-token-id");
501
+ Reflect.set(clientApp, "_isTrusted", async () => false);
502
+ const nestedAuthPromise = callProtectedMethod(clientApp, "_maybeHandleNestedCrossDomainAuth");
503
+ await (0, vitest.expect)(nestedAuthPromise).rejects.toThrowError(/does not match the requested refresh token ID/);
504
+ await (0, vitest.expect)(nestedAuthPromise).rejects.toSatisfy((error) => !_hexclave_shared_dist_utils_errors.HexclaveSetupError.isSetupError(error));
505
+ }
506
+ } finally {
507
+ globalThis.window = previousWindow;
508
+ globalThis.document = previousDocument;
509
+ }
510
+ });
395
511
  (0, vitest.it)("passes the construction-time URL to the nested cross-domain auth handler", async () => {
396
512
  const projectId = "00000000-0000-4000-8000-000000000009";
397
513
  const previousWindow = globalThis.window;
@@ -413,7 +529,8 @@ function createMockDocument() {
413
529
  publishableClientKey: "stack-pk-test",
414
530
  tokenStore: "memory",
415
531
  redirectMethod: "window",
416
- noAutomaticPrefetch: true
532
+ noAutomaticPrefetch: true,
533
+ devTool: false
417
534
  });
418
535
  globalThis.window.location.href = strippedUrl.toString();
419
536
  await new Promise((resolve) => setTimeout(resolve, 0));
@@ -468,7 +585,8 @@ function createMockDocument() {
468
585
  tokenStore: "memory",
469
586
  redirectMethod: "window",
470
587
  urls: { default: { type: "hosted" } },
471
- noAutomaticPrefetch: true
588
+ noAutomaticPrefetch: true,
589
+ devTool: false
472
590
  });
473
591
  await new Promise((resolve) => setTimeout(resolve, 0));
474
592
  await new Promise((resolve) => setTimeout(resolve, 0));
@@ -497,7 +615,8 @@ function createMockDocument() {
497
615
  handler: "/handler",
498
616
  signOut: { type: "hosted" }
499
617
  },
500
- noAutomaticPrefetch: true
618
+ noAutomaticPrefetch: true,
619
+ devTool: false
501
620
  });
502
621
  const signOutSpy = vitest.vi.spyOn(clientApp, "signOut").mockRejectedValue(/* @__PURE__ */ new Error("INTENTIONAL_TEST_ABORT"));
503
622
  try {
@@ -515,7 +634,8 @@ function createMockDocument() {
515
634
  tokenStore: "memory",
516
635
  redirectMethod: "window",
517
636
  urls: { default: { type: "hosted" } },
518
- noAutomaticPrefetch: true
637
+ noAutomaticPrefetch: true,
638
+ devTool: false
519
639
  });
520
640
  (0, vitest.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);
521
641
  (0, vitest.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);
@@ -529,7 +649,8 @@ function createMockDocument() {
529
649
  tokenStore: "memory",
530
650
  redirectMethod: "window",
531
651
  urls: { handler: "/custom-handler" },
532
- noAutomaticPrefetch: true
652
+ noAutomaticPrefetch: true,
653
+ devTool: false
533
654
  }).urls.signIn).toBe("/custom-handler/sign-in");
534
655
  });
535
656
  (0, vitest.it)("keeps default hosted signOut() on the source domain when afterSignOut is not configured", async () => {
@@ -540,7 +661,8 @@ function createMockDocument() {
540
661
  tokenStore: "memory",
541
662
  redirectMethod: "window",
542
663
  urls: { default: { type: "hosted" } },
543
- noAutomaticPrefetch: true
664
+ noAutomaticPrefetch: true,
665
+ devTool: false
544
666
  });
545
667
  const currentHref = "https://demo.stack-auth.com/settings?tab=profile";
546
668
  const clientInterface = Reflect.get(clientApp, "_interface");
@@ -594,7 +716,8 @@ function createMockDocument() {
594
716
  publishableClientKey: "stack-pk-test",
595
717
  tokenStore: "memory",
596
718
  redirectMethod: "window",
597
- noAutomaticPrefetch: true
719
+ noAutomaticPrefetch: true,
720
+ devTool: false
598
721
  });
599
722
  windowMock.location.href = "https://demo.example.test/handler/mfa";
600
723
  (0, vitest.expect)(await clientApp[______common_js.hexclaveAppInternalsSymbol].getRedirectToHandlerUrl("afterSignIn")).toBe("/music?track=1");
@@ -646,7 +769,8 @@ function createMockDocument() {
646
769
  publishableClientKey: "stack-pk-test",
647
770
  tokenStore: "memory",
648
771
  redirectMethod: "window",
649
- noAutomaticPrefetch: true
772
+ noAutomaticPrefetch: true,
773
+ devTool: false
650
774
  });
651
775
  const crossDomainAuthorizeRedirect = "https://demo.example.test/handler/oauth-callback?code=minted-code&state=mirror-handoff-state";
652
776
  const createCrossDomainAuthRedirectUrlSpy = vitest.vi.spyOn(clientApp, "_createCrossDomainAuthRedirectUrl").mockResolvedValue(crossDomainAuthorizeRedirect);
@@ -672,7 +796,8 @@ function createMockDocument() {
672
796
  publishableClientKey: "stack-pk-test",
673
797
  tokenStore: "memory",
674
798
  redirectMethod: "none",
675
- noAutomaticPrefetch: true
799
+ noAutomaticPrefetch: true,
800
+ devTool: false
676
801
  });
677
802
  const oldAccessToken = createAccessTokenString("old-refresh-token-id");
678
803
  const refreshedOldAccessToken = createAccessTokenString("refreshed-old-refresh-token-id");