@hexclave/next 1.0.102 → 1.0.104

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 (169) hide show
  1. package/dist/{admin-app-impl-B--_O9fz.d.ts → admin-app-impl-Bplmg79y.d.ts} +17 -17
  2. package/dist/{admin-app-impl-B--_O9fz.d.ts.map → admin-app-impl-Bplmg79y.d.ts.map} +1 -1
  3. package/dist/clickmap/clickmap-core.d.ts +1 -1
  4. package/dist/clickmap/index.d.ts +1 -1
  5. package/dist/{client-app-CZjsVpWa.d.ts → client-app-D84Jo2In.d.ts} +10 -10
  6. package/dist/client-app-D84Jo2In.d.ts.map +1 -0
  7. package/dist/components/api-key-dialogs.d.ts +1 -1
  8. package/dist/components/api-key-dialogs.js +4 -4
  9. package/dist/components/credential-sign-in.js +3 -3
  10. package/dist/components/credential-sign-up.js +5 -5
  11. package/dist/components/elements/sidebar-layout.js +1 -1
  12. package/dist/components/elements/user-avatar.js +1 -1
  13. package/dist/components/magic-link-sign-in.js +5 -5
  14. package/dist/components/message-cards/no-auth-methods-message-card.js +2 -2
  15. package/dist/components/message-cards/predefined-message-card.js +1 -1
  16. package/dist/components/passkey-button.js +1 -1
  17. package/dist/components/profile-image-editor.js +1 -1
  18. package/dist/components/selected-team-switcher.d.ts +1 -1
  19. package/dist/components/team-icon.d.ts +1 -1
  20. package/dist/components/team-icon.js +1 -1
  21. package/dist/components/team-switcher.d.ts +1 -1
  22. package/dist/components/team-switcher.js +1 -1
  23. package/dist/components/user-button.js +1 -1
  24. package/dist/components-page/account-settings/editable-text.js +1 -1
  25. package/dist/components-page/account-settings/email-and-auth/emails-section.js +3 -3
  26. package/dist/components-page/account-settings/email-and-auth/password-section.js +3 -3
  27. package/dist/components-page/account-settings/payments/payments-page.d.ts +1 -1
  28. package/dist/components-page/account-settings/teams/leave-team-section.d.ts +1 -1
  29. package/dist/components-page/account-settings/teams/team-api-keys-section.d.ts +1 -1
  30. package/dist/components-page/account-settings/teams/team-creation-page.js +3 -3
  31. package/dist/components-page/account-settings/teams/team-display-name-section.d.ts +1 -1
  32. package/dist/components-page/account-settings/teams/team-member-invitation-section.d.ts +1 -1
  33. package/dist/components-page/account-settings/teams/team-member-invitation-section.js +4 -4
  34. package/dist/components-page/account-settings/teams/team-member-list-section.d.ts +1 -1
  35. package/dist/components-page/account-settings/teams/team-page.d.ts +1 -1
  36. package/dist/components-page/account-settings/teams/team-profile-image-section.d.ts +1 -1
  37. package/dist/components-page/account-settings/teams/team-profile-user-section.d.ts +1 -1
  38. package/dist/components-page/account-settings.js +3 -3
  39. package/dist/components-page/auth-page.js +1 -1
  40. package/dist/components-page/cli-auth-confirm.js +1 -1
  41. package/dist/components-page/forgot-password.js +5 -5
  42. package/dist/components-page/hexclave-handler-client.d.ts +1 -1
  43. package/dist/components-page/hexclave-handler-client.js +1 -1
  44. package/dist/components-page/hexclave-handler.d.ts +1 -1
  45. package/dist/components-page/mfa.js +3 -3
  46. package/dist/components-page/oauth-callback.js +1 -1
  47. package/dist/components-page/onboarding.js +4 -4
  48. package/dist/components-page/password-reset.js +8 -8
  49. package/dist/components-page/team-creation.js +5 -5
  50. package/dist/dev-tool/dev-tool-core.d.ts +1 -1
  51. package/dist/dev-tool/index.d.ts +1 -1
  52. package/dist/esm/components/api-key-dialogs.d.ts +1 -1
  53. package/dist/esm/components/api-key-dialogs.js +4 -4
  54. package/dist/esm/components/credential-sign-in.js +3 -3
  55. package/dist/esm/components/credential-sign-up.js +5 -5
  56. package/dist/esm/components/elements/sidebar-layout.js +1 -1
  57. package/dist/esm/components/elements/user-avatar.js +1 -1
  58. package/dist/esm/components/magic-link-sign-in.js +5 -5
  59. package/dist/esm/components/message-cards/no-auth-methods-message-card.js +2 -2
  60. package/dist/esm/components/message-cards/predefined-message-card.js +1 -1
  61. package/dist/esm/components/passkey-button.js +1 -1
  62. package/dist/esm/components/profile-image-editor.js +1 -1
  63. package/dist/esm/components/team-icon.js +1 -1
  64. package/dist/esm/components/team-switcher.js +1 -1
  65. package/dist/esm/components/user-button.js +1 -1
  66. package/dist/esm/components-page/account-settings/editable-text.js +1 -1
  67. package/dist/esm/components-page/account-settings/email-and-auth/emails-section.js +3 -3
  68. package/dist/esm/components-page/account-settings/email-and-auth/password-section.js +3 -3
  69. package/dist/esm/components-page/account-settings/teams/team-creation-page.js +3 -3
  70. package/dist/esm/components-page/account-settings/teams/team-member-invitation-section.js +4 -4
  71. package/dist/esm/components-page/account-settings.js +3 -3
  72. package/dist/esm/components-page/auth-page.js +1 -1
  73. package/dist/esm/components-page/cli-auth-confirm.js +1 -1
  74. package/dist/esm/components-page/forgot-password.js +5 -5
  75. package/dist/esm/components-page/hexclave-handler-client.js +1 -1
  76. package/dist/esm/components-page/mfa.js +3 -3
  77. package/dist/esm/components-page/oauth-callback.js +1 -1
  78. package/dist/esm/components-page/onboarding.js +4 -4
  79. package/dist/esm/components-page/password-reset.js +7 -7
  80. package/dist/esm/components-page/team-creation.js +5 -5
  81. package/dist/esm/generated/quetzal-translations.d.ts +2 -2
  82. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +4 -14
  83. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
  84. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.js +0 -87
  85. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.js.map +1 -1
  86. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +22 -2
  87. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
  88. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +3 -3
  89. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
  90. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js +1 -1
  91. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  92. package/dist/esm/lib/hexclave-app/apps/implementations/common.js +2 -2
  93. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-page-urls.d.ts +1 -1
  94. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-page-urls.d.ts.map +1 -1
  95. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-page-urls.js +1 -1
  96. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-page-urls.js.map +1 -1
  97. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-page-urls.test.js +21 -1
  98. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-page-urls.test.js.map +1 -1
  99. package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +11 -1
  100. package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.d.ts.map +1 -1
  101. package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.js +87 -0
  102. package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.js.map +1 -1
  103. package/dist/esm/lib/hexclave-app/apps/interfaces/admin-app.d.ts +1 -11
  104. package/dist/esm/lib/hexclave-app/apps/interfaces/admin-app.d.ts.map +1 -1
  105. package/dist/esm/lib/hexclave-app/apps/interfaces/admin-app.js.map +1 -1
  106. package/dist/esm/lib/hexclave-app/apps/interfaces/server-app.d.ts +11 -1
  107. package/dist/esm/lib/hexclave-app/apps/interfaces/server-app.d.ts.map +1 -1
  108. package/dist/esm/lib/hexclave-app/apps/interfaces/server-app.js.map +1 -1
  109. package/dist/esm/lib/hexclave-app/index.d.ts +2 -1
  110. package/dist/esm/lib/hexclave-app/users/index.d.ts +1 -1
  111. package/dist/generated/quetzal-translations.d.ts +1 -1
  112. package/dist/{hexclave-provider-BlnLHwzv.d.ts → hexclave-provider-D2n_iIW3.d.ts} +3 -3
  113. package/dist/{hexclave-provider-BlnLHwzv.d.ts.map → hexclave-provider-D2n_iIW3.d.ts.map} +1 -1
  114. package/dist/{hooks-BLTs4rIm.d.ts → hooks-DNH1nVku.d.ts} +2 -2
  115. package/dist/{hooks-BLTs4rIm.d.ts.map → hooks-DNH1nVku.d.ts.map} +1 -1
  116. package/dist/{index-CnokyAXv.d.ts → index-CffsejeK.d.ts} +2 -2
  117. package/dist/{index-CnokyAXv.d.ts.map → index-CffsejeK.d.ts.map} +1 -1
  118. package/dist/index.d.ts +6 -5
  119. package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +1 -1
  120. package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.js +0 -87
  121. package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.js.map +1 -1
  122. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +22 -2
  123. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
  124. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -1
  125. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js +1 -1
  126. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  127. package/dist/lib/hexclave-app/apps/implementations/common.js +2 -2
  128. package/dist/lib/hexclave-app/apps/implementations/index.d.ts +1 -1
  129. package/dist/lib/hexclave-app/apps/implementations/redirect-page-urls.d.ts +1 -1
  130. package/dist/lib/hexclave-app/apps/implementations/redirect-page-urls.js +1 -1
  131. package/dist/lib/hexclave-app/apps/implementations/redirect-page-urls.js.map +1 -1
  132. package/dist/lib/hexclave-app/apps/implementations/redirect-page-urls.test.js +21 -1
  133. package/dist/lib/hexclave-app/apps/implementations/redirect-page-urls.test.js.map +1 -1
  134. package/dist/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -1
  135. package/dist/lib/hexclave-app/apps/implementations/server-app-impl.js +87 -0
  136. package/dist/lib/hexclave-app/apps/implementations/server-app-impl.js.map +1 -1
  137. package/dist/lib/hexclave-app/apps/index.d.ts +1 -1
  138. package/dist/lib/hexclave-app/apps/interfaces/admin-app.d.ts +2 -3
  139. package/dist/lib/hexclave-app/apps/interfaces/admin-app.js.map +1 -1
  140. package/dist/lib/hexclave-app/apps/interfaces/client-app.d.ts +1 -1
  141. package/dist/lib/hexclave-app/apps/interfaces/server-app.d.ts +3 -2
  142. package/dist/lib/hexclave-app/apps/interfaces/server-app.js.map +1 -1
  143. package/dist/lib/hexclave-app/index.d.ts +3 -2
  144. package/dist/lib/hexclave-app/projects/index.d.ts +1 -1
  145. package/dist/lib/hexclave-app/teams/index.d.ts +1 -1
  146. package/dist/lib/hexclave-app/users/index.d.ts +1 -1
  147. package/dist/lib/hooks.d.ts +1 -1
  148. package/dist/providers/hexclave-context.d.ts +1 -1
  149. package/dist/providers/hexclave-provider-client.d.ts +1 -1
  150. package/dist/providers/hexclave-provider.d.ts +1 -1
  151. package/dist/providers/translation-provider.d.ts +1 -1
  152. package/dist/pushed-config-error-overlay/index.d.ts +1 -1
  153. package/dist/{quetzal-translations-CwNB-iql.d.ts → quetzal-translations-CK45_4Dm.d.ts} +3 -3
  154. package/dist/{quetzal-translations-CwNB-iql.d.ts.map → quetzal-translations-CK45_4Dm.d.ts.map} +1 -1
  155. package/dist/{redirect-page-urls-BEWG0AtP.d.ts → redirect-page-urls-Jfs_-wyq.d.ts} +2 -2
  156. package/dist/{redirect-page-urls-BEWG0AtP.d.ts.map → redirect-page-urls-Jfs_-wyq.d.ts.map} +1 -1
  157. package/dist/{translation-provider-C0uPBd41.d.ts → translation-provider-DQ3BJepJ.d.ts} +2 -2
  158. package/dist/{translation-provider-C0uPBd41.d.ts.map → translation-provider-DQ3BJepJ.d.ts.map} +1 -1
  159. package/package.json +4 -4
  160. package/src/lib/hexclave-app/apps/implementations/admin-app-impl.ts +0 -100
  161. package/src/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.ts +31 -2
  162. package/src/lib/hexclave-app/apps/implementations/client-app-impl.ts +3 -1
  163. package/src/lib/hexclave-app/apps/implementations/redirect-page-urls.test.ts +24 -1
  164. package/src/lib/hexclave-app/apps/implementations/redirect-page-urls.ts +2 -2
  165. package/src/lib/hexclave-app/apps/implementations/server-app-impl.ts +100 -0
  166. package/src/lib/hexclave-app/apps/interfaces/admin-app.ts +0 -9
  167. package/src/lib/hexclave-app/apps/interfaces/server-app.ts +11 -0
  168. package/src/lib/hexclave-app/index.ts +10 -0
  169. package/dist/client-app-CZjsVpWa.d.ts.map +0 -1
@@ -18,8 +18,8 @@ let ____________generated_env_js = require("../../../../generated/env.js");
18
18
  let ____________utils_react_js = require("../../../../utils/react.js");
19
19
  let ______url_targets_js = require("../../url-targets.js");
20
20
  //#region src/lib/hexclave-app/apps/implementations/common.ts
21
- const clientVersion = "js @hexclave/next@1.0.102";
22
- if ("js @hexclave/next@1.0.102".startsWith("STACK_COMPILE_TIME"));
21
+ const clientVersion = "js @hexclave/next@1.0.104";
22
+ if ("js @hexclave/next@1.0.104".startsWith("STACK_COMPILE_TIME"));
23
23
  const replaceHexclavePortPrefix = (input) => {
24
24
  if (!input) return input;
25
25
  const prefix = ____________generated_env_js.envVars.HEXCLAVE_PORT_PREFIX;
@@ -1,4 +1,4 @@
1
- import { n as _HexclaveServerAppImplIncomplete, r as _HexclaveClientAppImplIncomplete, t as _HexclaveAdminAppImplIncomplete } from "../../../../admin-app-impl-B--_O9fz.js";
1
+ import { n as _HexclaveServerAppImplIncomplete, r as _HexclaveClientAppImplIncomplete, t as _HexclaveAdminAppImplIncomplete } from "../../../../admin-app-impl-Bplmg79y.js";
2
2
 
3
3
  //#region src/lib/hexclave-app/apps/implementations/index.d.ts
4
4
  declare const _HexclaveAdminAppImpl: typeof _HexclaveAdminAppImplIncomplete, _HexclaveClientAppImpl: typeof _HexclaveClientAppImplIncomplete, _HexclaveServerAppImpl: typeof _HexclaveServerAppImplIncomplete;
@@ -1,2 +1,2 @@
1
- import { i as planRedirectToHandler, n as crossDomainAuthQueryParams, r as getCrossDomainHandoffParamsFromCurrentUrl, t as CrossDomainHandoffParams } from "../../../../redirect-page-urls-BEWG0AtP.js";
1
+ import { i as planRedirectToHandler, n as crossDomainAuthQueryParams, r as getCrossDomainHandoffParamsFromCurrentUrl, t as CrossDomainHandoffParams } from "../../../../redirect-page-urls-Jfs_-wyq.js";
2
2
  export { CrossDomainHandoffParams, crossDomainAuthQueryParams, getCrossDomainHandoffParamsFromCurrentUrl, planRedirectToHandler };
@@ -212,7 +212,7 @@ async function planRedirectToHandler(options) {
212
212
  handlerName: options.handlerName,
213
213
  rawHandlerUrl: options.rawHandlerUrl,
214
214
  currentUrl: options.currentUrl,
215
- localOAuthCallbackUrl: options.localOAuthCallbackUrl,
215
+ localOAuthCallbackUrl: options.getLocalOAuthCallbackUrl(),
216
216
  getCrossDomainHandoffParams: options.getCrossDomainHandoffParams,
217
217
  noRedirectBack: options.noRedirectBack,
218
218
  afterCallbackRedirectUrlOverride
@@ -1 +1 @@
1
- {"version":3,"file":"redirect-page-urls.js","names":["HexclaveAssertionError"],"sources":["../../../../../src/lib/hexclave-app/apps/implementations/redirect-page-urls.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 { HexclaveAssertionError } from \"@hexclave/shared/dist/utils/errors\";\nimport { getRelativePart } from \"@hexclave/shared/dist/utils/urls\";\nimport { HandlerUrls } from \"../../common\";\n\nexport const crossDomainAuthQueryParams = {\n marker: \"hexclave_cross_domain_auth\",\n state: \"hexclave_cross_domain_state\",\n codeChallenge: \"hexclave_cross_domain_code_challenge\",\n afterCallbackRedirectUrl: \"hexclave_cross_domain_after_callback_redirect_url\",\n} as const;\n\ntype CrossDomainAuthQueryParamKey = keyof typeof crossDomainAuthQueryParams;\n\nfunction getCrossDomainParam(params: URLSearchParams, key: CrossDomainAuthQueryParamKey): string | null {\n return params.get(crossDomainAuthQueryParams[key]);\n}\n\nfunction hasCrossDomainParam(params: URLSearchParams, key: CrossDomainAuthQueryParamKey): boolean {\n return params.has(crossDomainAuthQueryParams[key]);\n}\n\nfunction setCrossDomainParam(params: URLSearchParams, key: CrossDomainAuthQueryParamKey, value: string): void {\n params.set(crossDomainAuthQueryParams[key], value);\n}\n\nexport type CrossDomainHandoffParams = {\n state: string,\n codeChallenge: string,\n};\n\nexport function getCrossDomainHandoffParamsFromCurrentUrl(currentUrl: URL): CrossDomainHandoffParams | null {\n const state = getCrossDomainParam(currentUrl.searchParams, \"state\");\n const codeChallenge = getCrossDomainParam(currentUrl.searchParams, \"codeChallenge\");\n if (state == null || codeChallenge == null) {\n return null;\n }\n return { state, codeChallenge };\n}\n\ntype RedirectBackAwareHandlerName = \"signIn\" | \"signUp\" | \"onboarding\" | \"signOut\";\ntype ContinuationAwareHandlerName = \"forgotPassword\" | \"passwordReset\";\ntype HandlerRedirectPolicy = \"none\" | \"redirect-back-aware\" | \"continuation-aware\" | \"after-auth-return\";\n\ntype CrossDomainHandoffParamsMaybeMissing = {\n state: string | null,\n codeChallenge: string | null,\n afterCallbackRedirectUrl: string | null,\n};\n\nfunction isRedirectBackAwareHandlerName(handlerName: keyof HandlerUrls): handlerName is RedirectBackAwareHandlerName {\n return handlerName === \"signIn\"\n || handlerName === \"signUp\"\n || handlerName === \"onboarding\"\n || handlerName === \"signOut\";\n}\n\nfunction isContinuationAwareHandlerName(handlerName: keyof HandlerUrls): handlerName is ContinuationAwareHandlerName {\n return handlerName === \"forgotPassword\" || handlerName === \"passwordReset\";\n}\n\nfunction hasCrossDomainHandoffParams(url: URL): boolean {\n return (\n hasCrossDomainParam(url.searchParams, \"state\")\n && hasCrossDomainParam(url.searchParams, \"codeChallenge\")\n && hasCrossDomainParam(url.searchParams, \"afterCallbackRedirectUrl\")\n );\n}\n\nfunction buildCrossDomainAuthCallbackUrl(options: {\n currentUrl: URL,\n localOAuthCallbackUrl: string,\n state?: string,\n codeChallenge?: string,\n afterCallbackRedirectUrl?: string,\n}): URL {\n const localOAuthCallbackUrl = new URL(options.localOAuthCallbackUrl, options.currentUrl);\n if (localOAuthCallbackUrl.origin !== options.currentUrl.origin) {\n throw new HexclaveAssertionError(\"Cross-domain auth callback URL must stay on the current origin\", {\n localOAuthCallbackUrl: localOAuthCallbackUrl.toString(),\n currentUrl: options.currentUrl.toString(),\n });\n }\n setCrossDomainParam(localOAuthCallbackUrl.searchParams, \"marker\", \"1\");\n if (options.state != null) {\n setCrossDomainParam(localOAuthCallbackUrl.searchParams, \"state\", options.state);\n }\n if (options.codeChallenge != null) {\n setCrossDomainParam(localOAuthCallbackUrl.searchParams, \"codeChallenge\", options.codeChallenge);\n }\n if (options.afterCallbackRedirectUrl != null) {\n setCrossDomainParam(localOAuthCallbackUrl.searchParams, \"afterCallbackRedirectUrl\", options.afterCallbackRedirectUrl);\n }\n return localOAuthCallbackUrl;\n}\n\nfunction buildRedirectBackAwareHandlerUrl(options: {\n handlerName: RedirectBackAwareHandlerName,\n rawHandlerUrl: string,\n currentUrl: URL,\n crossDomainHandoffParams: CrossDomainHandoffParams | null,\n localOAuthCallbackUrl: string,\n noRedirectBack: boolean,\n afterCallbackRedirectUrlOverride: string | null,\n}): string {\n const nextUrl = new URL(options.rawHandlerUrl, options.currentUrl);\n // Preserve after_auth_return_to verbatim (not a rebranded param).\n const currentAfterAuthReturnTo = options.currentUrl.searchParams.get(\"after_auth_return_to\");\n if (!options.noRedirectBack && currentAfterAuthReturnTo != null && !nextUrl.searchParams.has(\"after_auth_return_to\")) {\n nextUrl.searchParams.set(\"after_auth_return_to\", currentAfterAuthReturnTo);\n }\n for (const preservedParam of [\"state\", \"codeChallenge\", \"afterCallbackRedirectUrl\"] as const) {\n if (options.noRedirectBack && preservedParam === \"afterCallbackRedirectUrl\") {\n continue;\n }\n const currentValue = getCrossDomainParam(options.currentUrl.searchParams, preservedParam);\n if (currentValue != null && !hasCrossDomainParam(nextUrl.searchParams, preservedParam)) {\n setCrossDomainParam(nextUrl.searchParams, preservedParam, currentValue);\n }\n }\n\n if (options.handlerName === \"signOut\") {\n if (!nextUrl.searchParams.has(\"after_auth_return_to\")) {\n if (options.currentUrl.protocol === nextUrl.protocol && options.currentUrl.host === nextUrl.host) {\n nextUrl.searchParams.set(\"after_auth_return_to\", getRelativePart(options.currentUrl));\n } else {\n nextUrl.searchParams.set(\"after_auth_return_to\", options.currentUrl.toString());\n }\n }\n return nextUrl.origin === options.currentUrl.origin ? getRelativePart(nextUrl) : nextUrl.toString();\n }\n\n const isCrossDomainHandlerRedirect = options.currentUrl.origin !== nextUrl.origin;\n if (isCrossDomainHandlerRedirect) {\n if (!hasCrossDomainHandoffParams(nextUrl)) {\n const inheritedAfterAuthReturnTo = options.currentUrl.searchParams.get(\"after_auth_return_to\");\n const afterCallbackRedirectUrl = options.afterCallbackRedirectUrlOverride ?? (\n inheritedAfterAuthReturnTo\n ? new URL(inheritedAfterAuthReturnTo, options.currentUrl).toString()\n : options.currentUrl.toString()\n );\n const handoffParams = options.crossDomainHandoffParams\n ?? getCrossDomainHandoffParamsFromCurrentUrl(options.currentUrl);\n const callbackUrl = buildCrossDomainAuthCallbackUrl({\n currentUrl: options.currentUrl,\n localOAuthCallbackUrl: options.localOAuthCallbackUrl,\n state: handoffParams?.state,\n codeChallenge: handoffParams?.codeChallenge,\n afterCallbackRedirectUrl,\n });\n\n nextUrl.searchParams.set(\"after_auth_return_to\", callbackUrl.toString());\n setCrossDomainParam(nextUrl.searchParams, \"afterCallbackRedirectUrl\", afterCallbackRedirectUrl);\n if (handoffParams != null) {\n setCrossDomainParam(nextUrl.searchParams, \"state\", handoffParams.state);\n setCrossDomainParam(nextUrl.searchParams, \"codeChallenge\", handoffParams.codeChallenge);\n }\n }\n } else if (!options.noRedirectBack && options.currentUrl.protocol === nextUrl.protocol && options.currentUrl.host === nextUrl.host && !nextUrl.searchParams.has(\"after_auth_return_to\")) {\n nextUrl.searchParams.set(\"after_auth_return_to\", getRelativePart(options.currentUrl));\n }\n\n return nextUrl.origin === options.currentUrl.origin ? getRelativePart(nextUrl) : nextUrl.toString();\n}\n\n/**\n * Carries an auth flow's existing return state without ever making the current page the return\n * target. This distinction is important for password flows: forgot-password and password-reset\n * are continuation pages, not destinations customers should return to after signing in.\n */\nfunction buildContinuationAwareHandlerUrl(options: {\n rawHandlerUrl: string,\n currentUrl: URL,\n}): string {\n const nextUrl = new URL(options.rawHandlerUrl, options.currentUrl);\n const inheritedAfterAuthReturnTo = options.currentUrl.searchParams.get(\"after_auth_return_to\");\n if (inheritedAfterAuthReturnTo != null && !nextUrl.searchParams.has(\"after_auth_return_to\")) {\n nextUrl.searchParams.set(\"after_auth_return_to\", inheritedAfterAuthReturnTo);\n }\n for (const preservedParam of [\"state\", \"codeChallenge\", \"afterCallbackRedirectUrl\"] as const) {\n const currentValue = getCrossDomainParam(options.currentUrl.searchParams, preservedParam);\n if (currentValue != null && !hasCrossDomainParam(nextUrl.searchParams, preservedParam)) {\n setCrossDomainParam(nextUrl.searchParams, preservedParam, currentValue);\n }\n }\n return nextUrl.origin === options.currentUrl.origin ? getRelativePart(nextUrl) : nextUrl.toString();\n}\n\nfunction getHandlerRedirectPolicy(handlerName: keyof HandlerUrls): HandlerRedirectPolicy {\n if (handlerName === \"afterSignIn\" || handlerName === \"afterSignUp\") {\n return \"after-auth-return\";\n }\n if (isRedirectBackAwareHandlerName(handlerName)) {\n return \"redirect-back-aware\";\n }\n if (isContinuationAwareHandlerName(handlerName)) {\n return \"continuation-aware\";\n }\n return \"none\";\n}\n\ntype RedirectToHandlerPlan =\n | { type: \"redirect\", url: string }\n | {\n type: \"cross-domain-authorize\",\n redirectUri: string,\n state: string,\n codeChallenge: string,\n afterCallbackRedirectUrl: string,\n };\n\n\nasync function resolveRedirectBackAwareHandlerUrlForRedirect(options: {\n handlerName: RedirectBackAwareHandlerName,\n rawHandlerUrl: string,\n currentUrl: URL,\n localOAuthCallbackUrl: string,\n getCrossDomainHandoffParams: (currentUrl: URL) => Promise<CrossDomainHandoffParams>,\n noRedirectBack: boolean,\n afterCallbackRedirectUrlOverride: string | null,\n}): Promise<string> {\n const initial = buildRedirectBackAwareHandlerUrl({\n handlerName: options.handlerName,\n rawHandlerUrl: options.rawHandlerUrl,\n currentUrl: options.currentUrl,\n crossDomainHandoffParams: null,\n localOAuthCallbackUrl: options.localOAuthCallbackUrl,\n noRedirectBack: options.noRedirectBack,\n afterCallbackRedirectUrlOverride: options.afterCallbackRedirectUrlOverride,\n });\n if (options.handlerName === \"signOut\") {\n return initial;\n }\n\n const initialTarget = new URL(initial, options.currentUrl);\n const isCrossDomainHandlerRedirect = options.currentUrl.origin !== initialTarget.origin;\n if (!isCrossDomainHandlerRedirect || hasCrossDomainHandoffParams(initialTarget)) {\n return initial;\n }\n\n const crossDomainHandoffParams = await options.getCrossDomainHandoffParams(options.currentUrl);\n return buildRedirectBackAwareHandlerUrl({\n handlerName: options.handlerName,\n rawHandlerUrl: options.rawHandlerUrl,\n currentUrl: options.currentUrl,\n crossDomainHandoffParams,\n localOAuthCallbackUrl: options.localOAuthCallbackUrl,\n noRedirectBack: options.noRedirectBack,\n afterCallbackRedirectUrlOverride: options.afterCallbackRedirectUrlOverride,\n });\n}\n\nexport async function planRedirectToHandler(options: {\n handlerName: keyof HandlerUrls,\n rawHandlerUrl: string,\n noRedirectBack: boolean,\n currentUrl: URL | null,\n localOAuthCallbackUrl: string,\n rawHomeUrl: string,\n getCrossDomainHandoffParams: (currentUrl: URL) => Promise<CrossDomainHandoffParams>,\n}): Promise<RedirectToHandlerPlan> {\n if (options.currentUrl == null) {\n return { type: \"redirect\", url: options.rawHandlerUrl };\n }\n\n const policy = getHandlerRedirectPolicy(options.handlerName);\n if (options.noRedirectBack) {\n // Sign-in uses noRedirectBack from password-reset pages to avoid capturing the reset page.\n // Same-domain sign-in must still carry an already-inherited continuation. Cross-domain\n // sign-in falls through to the redirect-back-aware planner below because it needs to return\n // through the source app's callback before continuing to home.\n if (options.handlerName === \"signIn\") {\n const signInTarget = new URL(options.rawHandlerUrl, options.currentUrl);\n if (signInTarget.origin === options.currentUrl.origin) {\n return {\n type: \"redirect\",\n url: buildContinuationAwareHandlerUrl({\n rawHandlerUrl: options.rawHandlerUrl,\n currentUrl: options.currentUrl,\n }),\n };\n }\n } else {\n // Other handlers retain the historical noRedirectBack behavior, including\n // afterSignIn/afterSignUp ignoring all return state.\n return {\n type: \"redirect\",\n url: options.rawHandlerUrl,\n };\n }\n }\n if (policy === \"none\") {\n return { type: \"redirect\", url: options.rawHandlerUrl };\n }\n if (policy === \"continuation-aware\") {\n return {\n type: \"redirect\",\n url: buildContinuationAwareHandlerUrl({\n rawHandlerUrl: options.rawHandlerUrl,\n currentUrl: options.currentUrl,\n }),\n };\n }\n\n if (policy === \"after-auth-return\") {\n if (options.noRedirectBack) {\n return { type: \"redirect\", url: options.rawHandlerUrl };\n }\n const redirectBackUrl = options.currentUrl.searchParams.get(\"after_auth_return_to\");\n if (redirectBackUrl == null) {\n return { type: \"redirect\", url: options.rawHandlerUrl };\n }\n const redirectBackTarget = new URL(redirectBackUrl, options.currentUrl);\n const crossDomainHandoff = getCrossDomainHandoffForRedirect({\n currentUrl: options.currentUrl,\n redirectBackTarget,\n });\n if (crossDomainHandoff == null) {\n return { type: \"redirect\", url: redirectBackUrl };\n }\n let state = crossDomainHandoff.handoffParams.state;\n let codeChallenge = crossDomainHandoff.handoffParams.codeChallenge;\n let afterCallbackRedirectUrl = crossDomainHandoff.handoffParams.afterCallbackRedirectUrl;\n if (state == null || codeChallenge == null) {\n const generatedHandoffParams = await options.getCrossDomainHandoffParams(options.currentUrl);\n state ??= generatedHandoffParams.state;\n codeChallenge ??= generatedHandoffParams.codeChallenge;\n }\n afterCallbackRedirectUrl ??= options.currentUrl.toString();\n return {\n type: \"cross-domain-authorize\",\n redirectUri: crossDomainHandoff.redirectBackTarget.toString(),\n state,\n codeChallenge,\n afterCallbackRedirectUrl,\n };\n }\n\n if (\n options.handlerName !== \"signIn\"\n && options.handlerName !== \"signUp\"\n && options.handlerName !== \"onboarding\"\n && options.handlerName !== \"signOut\"\n ) {\n throw new HexclaveAssertionError(\"Unexpected redirect-back-aware handler policy mismatch\", {\n handlerName: options.handlerName,\n policy,\n });\n }\n\n // noRedirectBack suppresses the initiating deep link, not the return journey. Cross-domain auth\n // still needs to return through the source app's callback, but its final destination is home.\n const afterCallbackRedirectUrlOverride = options.noRedirectBack\n ? new URL(options.rawHomeUrl, options.currentUrl).toString()\n : null;\n\n return {\n type: \"redirect\",\n url: await resolveRedirectBackAwareHandlerUrlForRedirect({\n handlerName: options.handlerName,\n rawHandlerUrl: options.rawHandlerUrl,\n currentUrl: options.currentUrl,\n localOAuthCallbackUrl: options.localOAuthCallbackUrl,\n getCrossDomainHandoffParams: options.getCrossDomainHandoffParams,\n noRedirectBack: options.noRedirectBack,\n afterCallbackRedirectUrlOverride,\n }),\n };\n}\n\nfunction readCrossDomainHandoffParams(currentUrl: URL, redirectBackTarget: URL): CrossDomainHandoffParamsMaybeMissing {\n // Hexclave rebrand: accept either param name from both URLs.\n const state = getCrossDomainParam(currentUrl.searchParams, \"state\")\n ?? getCrossDomainParam(redirectBackTarget.searchParams, \"state\");\n const codeChallenge = getCrossDomainParam(currentUrl.searchParams, \"codeChallenge\")\n ?? getCrossDomainParam(redirectBackTarget.searchParams, \"codeChallenge\");\n const afterCallbackRedirectUrl = getCrossDomainParam(currentUrl.searchParams, \"afterCallbackRedirectUrl\")\n ?? getCrossDomainParam(redirectBackTarget.searchParams, \"afterCallbackRedirectUrl\");\n return {\n state,\n codeChallenge,\n afterCallbackRedirectUrl,\n };\n}\n\nfunction resolveCrossDomainRedirectBackTarget(options: {\n currentUrl: URL,\n redirectBackTarget: URL,\n handoffParams: CrossDomainHandoffParamsMaybeMissing,\n}): URL | null {\n if (options.redirectBackTarget.origin !== options.currentUrl.origin) {\n return options.redirectBackTarget;\n }\n if (\n options.handoffParams.state == null\n || options.handoffParams.codeChallenge == null\n || options.handoffParams.afterCallbackRedirectUrl == null\n ) {\n return null;\n }\n const afterCallbackRedirectTarget = new URL(options.handoffParams.afterCallbackRedirectUrl, options.currentUrl);\n if (afterCallbackRedirectTarget.origin === options.currentUrl.origin) {\n return null;\n }\n return new URL(\n `${options.redirectBackTarget.pathname}${options.redirectBackTarget.search}${options.redirectBackTarget.hash}`,\n afterCallbackRedirectTarget.origin,\n );\n}\n\nfunction getCrossDomainHandoffForRedirect(options: {\n currentUrl: URL,\n redirectBackTarget: URL,\n}): {\n redirectBackTarget: URL,\n handoffParams: CrossDomainHandoffParamsMaybeMissing,\n} | null {\n const handoffParams = readCrossDomainHandoffParams(options.currentUrl, options.redirectBackTarget);\n const crossDomainRedirectBackTarget = resolveCrossDomainRedirectBackTarget({\n currentUrl: options.currentUrl,\n redirectBackTarget: options.redirectBackTarget,\n handoffParams,\n });\n if (crossDomainRedirectBackTarget == null) {\n return null;\n }\n return {\n redirectBackTarget: crossDomainRedirectBackTarget,\n handoffParams,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"redirect-page-urls.js","names":["HexclaveAssertionError"],"sources":["../../../../../src/lib/hexclave-app/apps/implementations/redirect-page-urls.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 { HexclaveAssertionError } from \"@hexclave/shared/dist/utils/errors\";\nimport { getRelativePart } from \"@hexclave/shared/dist/utils/urls\";\nimport { HandlerUrls } from \"../../common\";\n\nexport const crossDomainAuthQueryParams = {\n marker: \"hexclave_cross_domain_auth\",\n state: \"hexclave_cross_domain_state\",\n codeChallenge: \"hexclave_cross_domain_code_challenge\",\n afterCallbackRedirectUrl: \"hexclave_cross_domain_after_callback_redirect_url\",\n} as const;\n\ntype CrossDomainAuthQueryParamKey = keyof typeof crossDomainAuthQueryParams;\n\nfunction getCrossDomainParam(params: URLSearchParams, key: CrossDomainAuthQueryParamKey): string | null {\n return params.get(crossDomainAuthQueryParams[key]);\n}\n\nfunction hasCrossDomainParam(params: URLSearchParams, key: CrossDomainAuthQueryParamKey): boolean {\n return params.has(crossDomainAuthQueryParams[key]);\n}\n\nfunction setCrossDomainParam(params: URLSearchParams, key: CrossDomainAuthQueryParamKey, value: string): void {\n params.set(crossDomainAuthQueryParams[key], value);\n}\n\nexport type CrossDomainHandoffParams = {\n state: string,\n codeChallenge: string,\n};\n\nexport function getCrossDomainHandoffParamsFromCurrentUrl(currentUrl: URL): CrossDomainHandoffParams | null {\n const state = getCrossDomainParam(currentUrl.searchParams, \"state\");\n const codeChallenge = getCrossDomainParam(currentUrl.searchParams, \"codeChallenge\");\n if (state == null || codeChallenge == null) {\n return null;\n }\n return { state, codeChallenge };\n}\n\ntype RedirectBackAwareHandlerName = \"signIn\" | \"signUp\" | \"onboarding\" | \"signOut\";\ntype ContinuationAwareHandlerName = \"forgotPassword\" | \"passwordReset\";\ntype HandlerRedirectPolicy = \"none\" | \"redirect-back-aware\" | \"continuation-aware\" | \"after-auth-return\";\n\ntype CrossDomainHandoffParamsMaybeMissing = {\n state: string | null,\n codeChallenge: string | null,\n afterCallbackRedirectUrl: string | null,\n};\n\nfunction isRedirectBackAwareHandlerName(handlerName: keyof HandlerUrls): handlerName is RedirectBackAwareHandlerName {\n return handlerName === \"signIn\"\n || handlerName === \"signUp\"\n || handlerName === \"onboarding\"\n || handlerName === \"signOut\";\n}\n\nfunction isContinuationAwareHandlerName(handlerName: keyof HandlerUrls): handlerName is ContinuationAwareHandlerName {\n return handlerName === \"forgotPassword\" || handlerName === \"passwordReset\";\n}\n\nfunction hasCrossDomainHandoffParams(url: URL): boolean {\n return (\n hasCrossDomainParam(url.searchParams, \"state\")\n && hasCrossDomainParam(url.searchParams, \"codeChallenge\")\n && hasCrossDomainParam(url.searchParams, \"afterCallbackRedirectUrl\")\n );\n}\n\nfunction buildCrossDomainAuthCallbackUrl(options: {\n currentUrl: URL,\n localOAuthCallbackUrl: string,\n state?: string,\n codeChallenge?: string,\n afterCallbackRedirectUrl?: string,\n}): URL {\n const localOAuthCallbackUrl = new URL(options.localOAuthCallbackUrl, options.currentUrl);\n if (localOAuthCallbackUrl.origin !== options.currentUrl.origin) {\n throw new HexclaveAssertionError(\"Cross-domain auth callback URL must stay on the current origin\", {\n localOAuthCallbackUrl: localOAuthCallbackUrl.toString(),\n currentUrl: options.currentUrl.toString(),\n });\n }\n setCrossDomainParam(localOAuthCallbackUrl.searchParams, \"marker\", \"1\");\n if (options.state != null) {\n setCrossDomainParam(localOAuthCallbackUrl.searchParams, \"state\", options.state);\n }\n if (options.codeChallenge != null) {\n setCrossDomainParam(localOAuthCallbackUrl.searchParams, \"codeChallenge\", options.codeChallenge);\n }\n if (options.afterCallbackRedirectUrl != null) {\n setCrossDomainParam(localOAuthCallbackUrl.searchParams, \"afterCallbackRedirectUrl\", options.afterCallbackRedirectUrl);\n }\n return localOAuthCallbackUrl;\n}\n\nfunction buildRedirectBackAwareHandlerUrl(options: {\n handlerName: RedirectBackAwareHandlerName,\n rawHandlerUrl: string,\n currentUrl: URL,\n crossDomainHandoffParams: CrossDomainHandoffParams | null,\n localOAuthCallbackUrl: string,\n noRedirectBack: boolean,\n afterCallbackRedirectUrlOverride: string | null,\n}): string {\n const nextUrl = new URL(options.rawHandlerUrl, options.currentUrl);\n // Preserve after_auth_return_to verbatim (not a rebranded param).\n const currentAfterAuthReturnTo = options.currentUrl.searchParams.get(\"after_auth_return_to\");\n if (!options.noRedirectBack && currentAfterAuthReturnTo != null && !nextUrl.searchParams.has(\"after_auth_return_to\")) {\n nextUrl.searchParams.set(\"after_auth_return_to\", currentAfterAuthReturnTo);\n }\n for (const preservedParam of [\"state\", \"codeChallenge\", \"afterCallbackRedirectUrl\"] as const) {\n if (options.noRedirectBack && preservedParam === \"afterCallbackRedirectUrl\") {\n continue;\n }\n const currentValue = getCrossDomainParam(options.currentUrl.searchParams, preservedParam);\n if (currentValue != null && !hasCrossDomainParam(nextUrl.searchParams, preservedParam)) {\n setCrossDomainParam(nextUrl.searchParams, preservedParam, currentValue);\n }\n }\n\n if (options.handlerName === \"signOut\") {\n if (!nextUrl.searchParams.has(\"after_auth_return_to\")) {\n if (options.currentUrl.protocol === nextUrl.protocol && options.currentUrl.host === nextUrl.host) {\n nextUrl.searchParams.set(\"after_auth_return_to\", getRelativePart(options.currentUrl));\n } else {\n nextUrl.searchParams.set(\"after_auth_return_to\", options.currentUrl.toString());\n }\n }\n return nextUrl.origin === options.currentUrl.origin ? getRelativePart(nextUrl) : nextUrl.toString();\n }\n\n const isCrossDomainHandlerRedirect = options.currentUrl.origin !== nextUrl.origin;\n if (isCrossDomainHandlerRedirect) {\n if (!hasCrossDomainHandoffParams(nextUrl)) {\n const inheritedAfterAuthReturnTo = options.currentUrl.searchParams.get(\"after_auth_return_to\");\n const afterCallbackRedirectUrl = options.afterCallbackRedirectUrlOverride ?? (\n inheritedAfterAuthReturnTo\n ? new URL(inheritedAfterAuthReturnTo, options.currentUrl).toString()\n : options.currentUrl.toString()\n );\n const handoffParams = options.crossDomainHandoffParams\n ?? getCrossDomainHandoffParamsFromCurrentUrl(options.currentUrl);\n const callbackUrl = buildCrossDomainAuthCallbackUrl({\n currentUrl: options.currentUrl,\n localOAuthCallbackUrl: options.localOAuthCallbackUrl,\n state: handoffParams?.state,\n codeChallenge: handoffParams?.codeChallenge,\n afterCallbackRedirectUrl,\n });\n\n nextUrl.searchParams.set(\"after_auth_return_to\", callbackUrl.toString());\n setCrossDomainParam(nextUrl.searchParams, \"afterCallbackRedirectUrl\", afterCallbackRedirectUrl);\n if (handoffParams != null) {\n setCrossDomainParam(nextUrl.searchParams, \"state\", handoffParams.state);\n setCrossDomainParam(nextUrl.searchParams, \"codeChallenge\", handoffParams.codeChallenge);\n }\n }\n } else if (!options.noRedirectBack && options.currentUrl.protocol === nextUrl.protocol && options.currentUrl.host === nextUrl.host && !nextUrl.searchParams.has(\"after_auth_return_to\")) {\n nextUrl.searchParams.set(\"after_auth_return_to\", getRelativePart(options.currentUrl));\n }\n\n return nextUrl.origin === options.currentUrl.origin ? getRelativePart(nextUrl) : nextUrl.toString();\n}\n\n/**\n * Carries an auth flow's existing return state without ever making the current page the return\n * target. This distinction is important for password flows: forgot-password and password-reset\n * are continuation pages, not destinations customers should return to after signing in.\n */\nfunction buildContinuationAwareHandlerUrl(options: {\n rawHandlerUrl: string,\n currentUrl: URL,\n}): string {\n const nextUrl = new URL(options.rawHandlerUrl, options.currentUrl);\n const inheritedAfterAuthReturnTo = options.currentUrl.searchParams.get(\"after_auth_return_to\");\n if (inheritedAfterAuthReturnTo != null && !nextUrl.searchParams.has(\"after_auth_return_to\")) {\n nextUrl.searchParams.set(\"after_auth_return_to\", inheritedAfterAuthReturnTo);\n }\n for (const preservedParam of [\"state\", \"codeChallenge\", \"afterCallbackRedirectUrl\"] as const) {\n const currentValue = getCrossDomainParam(options.currentUrl.searchParams, preservedParam);\n if (currentValue != null && !hasCrossDomainParam(nextUrl.searchParams, preservedParam)) {\n setCrossDomainParam(nextUrl.searchParams, preservedParam, currentValue);\n }\n }\n return nextUrl.origin === options.currentUrl.origin ? getRelativePart(nextUrl) : nextUrl.toString();\n}\n\nfunction getHandlerRedirectPolicy(handlerName: keyof HandlerUrls): HandlerRedirectPolicy {\n if (handlerName === \"afterSignIn\" || handlerName === \"afterSignUp\") {\n return \"after-auth-return\";\n }\n if (isRedirectBackAwareHandlerName(handlerName)) {\n return \"redirect-back-aware\";\n }\n if (isContinuationAwareHandlerName(handlerName)) {\n return \"continuation-aware\";\n }\n return \"none\";\n}\n\ntype RedirectToHandlerPlan =\n | { type: \"redirect\", url: string }\n | {\n type: \"cross-domain-authorize\",\n redirectUri: string,\n state: string,\n codeChallenge: string,\n afterCallbackRedirectUrl: string,\n };\n\n\nasync function resolveRedirectBackAwareHandlerUrlForRedirect(options: {\n handlerName: RedirectBackAwareHandlerName,\n rawHandlerUrl: string,\n currentUrl: URL,\n localOAuthCallbackUrl: string,\n getCrossDomainHandoffParams: (currentUrl: URL) => Promise<CrossDomainHandoffParams>,\n noRedirectBack: boolean,\n afterCallbackRedirectUrlOverride: string | null,\n}): Promise<string> {\n const initial = buildRedirectBackAwareHandlerUrl({\n handlerName: options.handlerName,\n rawHandlerUrl: options.rawHandlerUrl,\n currentUrl: options.currentUrl,\n crossDomainHandoffParams: null,\n localOAuthCallbackUrl: options.localOAuthCallbackUrl,\n noRedirectBack: options.noRedirectBack,\n afterCallbackRedirectUrlOverride: options.afterCallbackRedirectUrlOverride,\n });\n if (options.handlerName === \"signOut\") {\n return initial;\n }\n\n const initialTarget = new URL(initial, options.currentUrl);\n const isCrossDomainHandlerRedirect = options.currentUrl.origin !== initialTarget.origin;\n if (!isCrossDomainHandlerRedirect || hasCrossDomainHandoffParams(initialTarget)) {\n return initial;\n }\n\n const crossDomainHandoffParams = await options.getCrossDomainHandoffParams(options.currentUrl);\n return buildRedirectBackAwareHandlerUrl({\n handlerName: options.handlerName,\n rawHandlerUrl: options.rawHandlerUrl,\n currentUrl: options.currentUrl,\n crossDomainHandoffParams,\n localOAuthCallbackUrl: options.localOAuthCallbackUrl,\n noRedirectBack: options.noRedirectBack,\n afterCallbackRedirectUrlOverride: options.afterCallbackRedirectUrlOverride,\n });\n}\n\nexport async function planRedirectToHandler(options: {\n handlerName: keyof HandlerUrls,\n rawHandlerUrl: string,\n noRedirectBack: boolean,\n currentUrl: URL | null,\n getLocalOAuthCallbackUrl: () => string,\n rawHomeUrl: string,\n getCrossDomainHandoffParams: (currentUrl: URL) => Promise<CrossDomainHandoffParams>,\n}): Promise<RedirectToHandlerPlan> {\n if (options.currentUrl == null) {\n return { type: \"redirect\", url: options.rawHandlerUrl };\n }\n\n const policy = getHandlerRedirectPolicy(options.handlerName);\n if (options.noRedirectBack) {\n // Sign-in uses noRedirectBack from password-reset pages to avoid capturing the reset page.\n // Same-domain sign-in must still carry an already-inherited continuation. Cross-domain\n // sign-in falls through to the redirect-back-aware planner below because it needs to return\n // through the source app's callback before continuing to home.\n if (options.handlerName === \"signIn\") {\n const signInTarget = new URL(options.rawHandlerUrl, options.currentUrl);\n if (signInTarget.origin === options.currentUrl.origin) {\n return {\n type: \"redirect\",\n url: buildContinuationAwareHandlerUrl({\n rawHandlerUrl: options.rawHandlerUrl,\n currentUrl: options.currentUrl,\n }),\n };\n }\n } else {\n // Other handlers retain the historical noRedirectBack behavior, including\n // afterSignIn/afterSignUp ignoring all return state.\n return {\n type: \"redirect\",\n url: options.rawHandlerUrl,\n };\n }\n }\n if (policy === \"none\") {\n return { type: \"redirect\", url: options.rawHandlerUrl };\n }\n if (policy === \"continuation-aware\") {\n return {\n type: \"redirect\",\n url: buildContinuationAwareHandlerUrl({\n rawHandlerUrl: options.rawHandlerUrl,\n currentUrl: options.currentUrl,\n }),\n };\n }\n\n if (policy === \"after-auth-return\") {\n if (options.noRedirectBack) {\n return { type: \"redirect\", url: options.rawHandlerUrl };\n }\n const redirectBackUrl = options.currentUrl.searchParams.get(\"after_auth_return_to\");\n if (redirectBackUrl == null) {\n return { type: \"redirect\", url: options.rawHandlerUrl };\n }\n const redirectBackTarget = new URL(redirectBackUrl, options.currentUrl);\n const crossDomainHandoff = getCrossDomainHandoffForRedirect({\n currentUrl: options.currentUrl,\n redirectBackTarget,\n });\n if (crossDomainHandoff == null) {\n return { type: \"redirect\", url: redirectBackUrl };\n }\n let state = crossDomainHandoff.handoffParams.state;\n let codeChallenge = crossDomainHandoff.handoffParams.codeChallenge;\n let afterCallbackRedirectUrl = crossDomainHandoff.handoffParams.afterCallbackRedirectUrl;\n if (state == null || codeChallenge == null) {\n const generatedHandoffParams = await options.getCrossDomainHandoffParams(options.currentUrl);\n state ??= generatedHandoffParams.state;\n codeChallenge ??= generatedHandoffParams.codeChallenge;\n }\n afterCallbackRedirectUrl ??= options.currentUrl.toString();\n return {\n type: \"cross-domain-authorize\",\n redirectUri: crossDomainHandoff.redirectBackTarget.toString(),\n state,\n codeChallenge,\n afterCallbackRedirectUrl,\n };\n }\n\n if (\n options.handlerName !== \"signIn\"\n && options.handlerName !== \"signUp\"\n && options.handlerName !== \"onboarding\"\n && options.handlerName !== \"signOut\"\n ) {\n throw new HexclaveAssertionError(\"Unexpected redirect-back-aware handler policy mismatch\", {\n handlerName: options.handlerName,\n policy,\n });\n }\n\n // noRedirectBack suppresses the initiating deep link, not the return journey. Cross-domain auth\n // still needs to return through the source app's callback, but its final destination is home.\n const afterCallbackRedirectUrlOverride = options.noRedirectBack\n ? new URL(options.rawHomeUrl, options.currentUrl).toString()\n : null;\n\n return {\n type: \"redirect\",\n url: await resolveRedirectBackAwareHandlerUrlForRedirect({\n handlerName: options.handlerName,\n rawHandlerUrl: options.rawHandlerUrl,\n currentUrl: options.currentUrl,\n localOAuthCallbackUrl: options.getLocalOAuthCallbackUrl(),\n getCrossDomainHandoffParams: options.getCrossDomainHandoffParams,\n noRedirectBack: options.noRedirectBack,\n afterCallbackRedirectUrlOverride,\n }),\n };\n}\n\nfunction readCrossDomainHandoffParams(currentUrl: URL, redirectBackTarget: URL): CrossDomainHandoffParamsMaybeMissing {\n // Hexclave rebrand: accept either param name from both URLs.\n const state = getCrossDomainParam(currentUrl.searchParams, \"state\")\n ?? getCrossDomainParam(redirectBackTarget.searchParams, \"state\");\n const codeChallenge = getCrossDomainParam(currentUrl.searchParams, \"codeChallenge\")\n ?? getCrossDomainParam(redirectBackTarget.searchParams, \"codeChallenge\");\n const afterCallbackRedirectUrl = getCrossDomainParam(currentUrl.searchParams, \"afterCallbackRedirectUrl\")\n ?? getCrossDomainParam(redirectBackTarget.searchParams, \"afterCallbackRedirectUrl\");\n return {\n state,\n codeChallenge,\n afterCallbackRedirectUrl,\n };\n}\n\nfunction resolveCrossDomainRedirectBackTarget(options: {\n currentUrl: URL,\n redirectBackTarget: URL,\n handoffParams: CrossDomainHandoffParamsMaybeMissing,\n}): URL | null {\n if (options.redirectBackTarget.origin !== options.currentUrl.origin) {\n return options.redirectBackTarget;\n }\n if (\n options.handoffParams.state == null\n || options.handoffParams.codeChallenge == null\n || options.handoffParams.afterCallbackRedirectUrl == null\n ) {\n return null;\n }\n const afterCallbackRedirectTarget = new URL(options.handoffParams.afterCallbackRedirectUrl, options.currentUrl);\n if (afterCallbackRedirectTarget.origin === options.currentUrl.origin) {\n return null;\n }\n return new URL(\n `${options.redirectBackTarget.pathname}${options.redirectBackTarget.search}${options.redirectBackTarget.hash}`,\n afterCallbackRedirectTarget.origin,\n );\n}\n\nfunction getCrossDomainHandoffForRedirect(options: {\n currentUrl: URL,\n redirectBackTarget: URL,\n}): {\n redirectBackTarget: URL,\n handoffParams: CrossDomainHandoffParamsMaybeMissing,\n} | null {\n const handoffParams = readCrossDomainHandoffParams(options.currentUrl, options.redirectBackTarget);\n const crossDomainRedirectBackTarget = resolveCrossDomainRedirectBackTarget({\n currentUrl: options.currentUrl,\n redirectBackTarget: options.redirectBackTarget,\n handoffParams,\n });\n if (crossDomainRedirectBackTarget == null) {\n return null;\n }\n return {\n redirectBackTarget: crossDomainRedirectBackTarget,\n handoffParams,\n };\n}\n"],"mappings":"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"}
@@ -6,7 +6,7 @@ async function plan(options) {
6
6
  return await (0, __redirect_page_urls_js.planRedirectToHandler)({
7
7
  ...options,
8
8
  noRedirectBack: options.noRedirectBack === true,
9
- localOAuthCallbackUrl,
9
+ getLocalOAuthCallbackUrl: () => localOAuthCallbackUrl,
10
10
  rawHomeUrl: "/",
11
11
  getCrossDomainHandoffParams: async () => {
12
12
  throw new Error("Continuation-only redirects must not mint a new cross-domain handoff");
@@ -23,6 +23,26 @@ function expectContinuation(url, expectedReturnTo) {
23
23
  (0, vitest.expect)(url.searchParams.get(__redirect_page_urls_js.crossDomainAuthQueryParams.codeChallenge)).toBe("outer-challenge");
24
24
  (0, vitest.expect)(url.searchParams.get(__redirect_page_urls_js.crossDomainAuthQueryParams.afterCallbackRedirectUrl)).toBe("https://customer.example.test/dashboard");
25
25
  }
26
+ (0, vitest.describe)("server-side redirect planning", () => {
27
+ (0, vitest.it)("does not resolve a browser-only callback URL without a current URL", async () => {
28
+ (0, vitest.expect)(await (0, __redirect_page_urls_js.planRedirectToHandler)({
29
+ handlerName: "signIn",
30
+ rawHandlerUrl: "https://hosted.example.test/handler/sign-in",
31
+ noRedirectBack: false,
32
+ currentUrl: null,
33
+ getLocalOAuthCallbackUrl: () => {
34
+ throw new Error("Server-side redirect planning must not resolve the browser callback URL");
35
+ },
36
+ rawHomeUrl: "/",
37
+ getCrossDomainHandoffParams: async () => {
38
+ throw new Error("Server-side redirect planning must not mint cross-domain handoff parameters");
39
+ }
40
+ })).toEqual({
41
+ type: "redirect",
42
+ url: "https://hosted.example.test/handler/sign-in"
43
+ });
44
+ });
45
+ });
26
46
  (0, vitest.describe)("password-flow redirect continuation", () => {
27
47
  (0, vitest.it)("carries the complete customer return state through forgot-password and a reset-email new tab", async () => {
28
48
  const customerReturnTo = "https://customer.example.test/handler/oauth-callback?hexclave_cross_domain_auth=1";
@@ -1 +1 @@
1
- {"version":3,"file":"redirect-page-urls.test.js","names":["crossDomainAuthQueryParams"],"sources":["../../../../../src/lib/hexclave-app/apps/implementations/redirect-page-urls.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 { crossDomainAuthQueryParams, planRedirectToHandler } from \"./redirect-page-urls\";\n\nconst localOAuthCallbackUrl = \"https://hosted.example.test/handler/oauth-callback\";\n\nasync function plan(options: {\n handlerName: \"signIn\" | \"forgotPassword\" | \"passwordReset\" | \"afterSignIn\" | \"afterSignUp\",\n rawHandlerUrl: string,\n currentUrl: URL,\n noRedirectBack?: boolean,\n}) {\n return await planRedirectToHandler({\n ...options,\n noRedirectBack: options.noRedirectBack === true,\n localOAuthCallbackUrl,\n rawHomeUrl: \"/\",\n getCrossDomainHandoffParams: async () => {\n throw new Error(\"Continuation-only redirects must not mint a new cross-domain handoff\");\n },\n });\n}\n\nfunction expectRedirectUrl(planResult: Awaited<ReturnType<typeof plan>>, baseUrl: URL): URL {\n if (planResult.type !== \"redirect\") {\n throw new Error(\"Expected a direct redirect plan\");\n }\n return new URL(planResult.url, baseUrl);\n}\n\nfunction expectContinuation(url: URL, expectedReturnTo: string): void {\n expect(url.searchParams.get(\"after_auth_return_to\")).toBe(expectedReturnTo);\n expect(url.searchParams.get(crossDomainAuthQueryParams.state)).toBe(\"outer-state\");\n expect(url.searchParams.get(crossDomainAuthQueryParams.codeChallenge)).toBe(\"outer-challenge\");\n expect(url.searchParams.get(crossDomainAuthQueryParams.afterCallbackRedirectUrl)).toBe(\"https://customer.example.test/dashboard\");\n}\n\ndescribe(\"password-flow redirect continuation\", () => {\n it(\"carries the complete customer return state through forgot-password and a reset-email new tab\", async () => {\n const customerReturnTo = \"https://customer.example.test/handler/oauth-callback?hexclave_cross_domain_auth=1\";\n const signInUrl = new URL(\"https://hosted.example.test/handler/sign-in\");\n signInUrl.searchParams.set(\"after_auth_return_to\", customerReturnTo);\n signInUrl.searchParams.set(crossDomainAuthQueryParams.state, \"outer-state\");\n signInUrl.searchParams.set(crossDomainAuthQueryParams.codeChallenge, \"outer-challenge\");\n signInUrl.searchParams.set(crossDomainAuthQueryParams.afterCallbackRedirectUrl, \"https://customer.example.test/dashboard\");\n\n const forgotPlan = await plan({\n handlerName: \"forgotPassword\",\n rawHandlerUrl: \"/handler/forgot-password\",\n currentUrl: signInUrl,\n });\n const forgotUrl = expectRedirectUrl(forgotPlan, signInUrl);\n expectContinuation(forgotUrl, customerReturnTo);\n\n const callbackPlan = await plan({\n handlerName: \"passwordReset\",\n rawHandlerUrl: \"/handler/password-reset\",\n currentUrl: forgotUrl,\n });\n const resetEmailCallbackUrl = expectRedirectUrl(callbackPlan, forgotUrl);\n expectContinuation(resetEmailCallbackUrl, customerReturnTo);\n\n // Model opening the callback in a new tab: only URL state is available.\n resetEmailCallbackUrl.searchParams.set(\"code\", \"reset-code\");\n const signInPlan = await plan({\n handlerName: \"signIn\",\n rawHandlerUrl: \"/handler/sign-in\",\n currentUrl: resetEmailCallbackUrl,\n noRedirectBack: true,\n });\n const finalSignInUrl = expectRedirectUrl(signInPlan, resetEmailCallbackUrl);\n expectContinuation(finalSignInUrl, customerReturnTo);\n expect(finalSignInUrl.searchParams.has(\"code\")).toBe(false);\n });\n\n it.each([\n [\"forgotPassword\", \"/handler/forgot-password\"],\n [\"passwordReset\", \"/handler/password-reset\"],\n ] as const)(\"never synthesizes the current %s page as a return target\", async (handlerName, rawHandlerUrl) => {\n const currentUrl = new URL(`https://hosted.example.test${rawHandlerUrl}?code=reset-code`);\n const result = expectRedirectUrl(await plan({\n handlerName,\n rawHandlerUrl,\n currentUrl,\n }), currentUrl);\n\n expect(result.searchParams.has(\"after_auth_return_to\")).toBe(false);\n expect(result.searchParams.has(\"code\")).toBe(false);\n });\n\n it(\"makes sign-in noRedirectBack suppress capture while preserving only inherited state\", async () => {\n const resetUrlWithoutContinuation = new URL(\"https://hosted.example.test/handler/password-reset?code=reset-code\");\n const result = expectRedirectUrl(await plan({\n handlerName: \"signIn\",\n rawHandlerUrl: \"/handler/sign-in\",\n currentUrl: resetUrlWithoutContinuation,\n noRedirectBack: true,\n }), resetUrlWithoutContinuation);\n\n expect(result.toString()).toBe(\"https://hosted.example.test/handler/sign-in\");\n });\n\n it.each([\"afterSignIn\", \"afterSignUp\"] as const)(\n \"keeps existing %s noRedirectBack semantics\",\n async (handlerName) => {\n const currentUrl = new URL(\"https://hosted.example.test/handler/sign-in?after_auth_return_to=%2Fcustomer\");\n const result = expectRedirectUrl(await plan({\n handlerName,\n rawHandlerUrl: \"/default-after-auth\",\n currentUrl,\n noRedirectBack: true,\n }), currentUrl);\n\n expect(result.toString()).toBe(\"https://hosted.example.test/default-after-auth\");\n },\n );\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"redirect-page-urls.test.js","names":["crossDomainAuthQueryParams"],"sources":["../../../../../src/lib/hexclave-app/apps/implementations/redirect-page-urls.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 { crossDomainAuthQueryParams, planRedirectToHandler } from \"./redirect-page-urls\";\n\nconst localOAuthCallbackUrl = \"https://hosted.example.test/handler/oauth-callback\";\n\nasync function plan(options: {\n handlerName: \"signIn\" | \"forgotPassword\" | \"passwordReset\" | \"afterSignIn\" | \"afterSignUp\",\n rawHandlerUrl: string,\n currentUrl: URL,\n noRedirectBack?: boolean,\n}) {\n return await planRedirectToHandler({\n ...options,\n noRedirectBack: options.noRedirectBack === true,\n getLocalOAuthCallbackUrl: () => localOAuthCallbackUrl,\n rawHomeUrl: \"/\",\n getCrossDomainHandoffParams: async () => {\n throw new Error(\"Continuation-only redirects must not mint a new cross-domain handoff\");\n },\n });\n}\n\nfunction expectRedirectUrl(planResult: Awaited<ReturnType<typeof plan>>, baseUrl: URL): URL {\n if (planResult.type !== \"redirect\") {\n throw new Error(\"Expected a direct redirect plan\");\n }\n return new URL(planResult.url, baseUrl);\n}\n\nfunction expectContinuation(url: URL, expectedReturnTo: string): void {\n expect(url.searchParams.get(\"after_auth_return_to\")).toBe(expectedReturnTo);\n expect(url.searchParams.get(crossDomainAuthQueryParams.state)).toBe(\"outer-state\");\n expect(url.searchParams.get(crossDomainAuthQueryParams.codeChallenge)).toBe(\"outer-challenge\");\n expect(url.searchParams.get(crossDomainAuthQueryParams.afterCallbackRedirectUrl)).toBe(\"https://customer.example.test/dashboard\");\n}\n\ndescribe(\"server-side redirect planning\", () => {\n it(\"does not resolve a browser-only callback URL without a current URL\", async () => {\n const result = await planRedirectToHandler({\n handlerName: \"signIn\",\n rawHandlerUrl: \"https://hosted.example.test/handler/sign-in\",\n noRedirectBack: false,\n currentUrl: null,\n getLocalOAuthCallbackUrl: () => {\n throw new Error(\"Server-side redirect planning must not resolve the browser callback URL\");\n },\n rawHomeUrl: \"/\",\n getCrossDomainHandoffParams: async () => {\n throw new Error(\"Server-side redirect planning must not mint cross-domain handoff parameters\");\n },\n });\n\n expect(result).toEqual({\n type: \"redirect\",\n url: \"https://hosted.example.test/handler/sign-in\",\n });\n });\n});\n\ndescribe(\"password-flow redirect continuation\", () => {\n it(\"carries the complete customer return state through forgot-password and a reset-email new tab\", async () => {\n const customerReturnTo = \"https://customer.example.test/handler/oauth-callback?hexclave_cross_domain_auth=1\";\n const signInUrl = new URL(\"https://hosted.example.test/handler/sign-in\");\n signInUrl.searchParams.set(\"after_auth_return_to\", customerReturnTo);\n signInUrl.searchParams.set(crossDomainAuthQueryParams.state, \"outer-state\");\n signInUrl.searchParams.set(crossDomainAuthQueryParams.codeChallenge, \"outer-challenge\");\n signInUrl.searchParams.set(crossDomainAuthQueryParams.afterCallbackRedirectUrl, \"https://customer.example.test/dashboard\");\n\n const forgotPlan = await plan({\n handlerName: \"forgotPassword\",\n rawHandlerUrl: \"/handler/forgot-password\",\n currentUrl: signInUrl,\n });\n const forgotUrl = expectRedirectUrl(forgotPlan, signInUrl);\n expectContinuation(forgotUrl, customerReturnTo);\n\n const callbackPlan = await plan({\n handlerName: \"passwordReset\",\n rawHandlerUrl: \"/handler/password-reset\",\n currentUrl: forgotUrl,\n });\n const resetEmailCallbackUrl = expectRedirectUrl(callbackPlan, forgotUrl);\n expectContinuation(resetEmailCallbackUrl, customerReturnTo);\n\n // Model opening the callback in a new tab: only URL state is available.\n resetEmailCallbackUrl.searchParams.set(\"code\", \"reset-code\");\n const signInPlan = await plan({\n handlerName: \"signIn\",\n rawHandlerUrl: \"/handler/sign-in\",\n currentUrl: resetEmailCallbackUrl,\n noRedirectBack: true,\n });\n const finalSignInUrl = expectRedirectUrl(signInPlan, resetEmailCallbackUrl);\n expectContinuation(finalSignInUrl, customerReturnTo);\n expect(finalSignInUrl.searchParams.has(\"code\")).toBe(false);\n });\n\n it.each([\n [\"forgotPassword\", \"/handler/forgot-password\"],\n [\"passwordReset\", \"/handler/password-reset\"],\n ] as const)(\"never synthesizes the current %s page as a return target\", async (handlerName, rawHandlerUrl) => {\n const currentUrl = new URL(`https://hosted.example.test${rawHandlerUrl}?code=reset-code`);\n const result = expectRedirectUrl(await plan({\n handlerName,\n rawHandlerUrl,\n currentUrl,\n }), currentUrl);\n\n expect(result.searchParams.has(\"after_auth_return_to\")).toBe(false);\n expect(result.searchParams.has(\"code\")).toBe(false);\n });\n\n it(\"makes sign-in noRedirectBack suppress capture while preserving only inherited state\", async () => {\n const resetUrlWithoutContinuation = new URL(\"https://hosted.example.test/handler/password-reset?code=reset-code\");\n const result = expectRedirectUrl(await plan({\n handlerName: \"signIn\",\n rawHandlerUrl: \"/handler/sign-in\",\n currentUrl: resetUrlWithoutContinuation,\n noRedirectBack: true,\n }), resetUrlWithoutContinuation);\n\n expect(result.toString()).toBe(\"https://hosted.example.test/handler/sign-in\");\n });\n\n it.each([\"afterSignIn\", \"afterSignUp\"] as const)(\n \"keeps existing %s noRedirectBack semantics\",\n async (handlerName) => {\n const currentUrl = new URL(\"https://hosted.example.test/handler/sign-in?after_auth_return_to=%2Fcustomer\");\n const result = expectRedirectUrl(await plan({\n handlerName,\n rawHandlerUrl: \"/default-after-auth\",\n currentUrl,\n noRedirectBack: true,\n }), currentUrl);\n\n expect(result.toString()).toBe(\"https://hosted.example.test/default-after-auth\");\n },\n );\n});\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import { n as _HexclaveServerAppImplIncomplete } from "../../../../admin-app-impl-B--_O9fz.js";
1
+ import { n as _HexclaveServerAppImplIncomplete } from "../../../../admin-app-impl-Bplmg79y.js";
2
2
  export { _HexclaveServerAppImplIncomplete };
@@ -1387,6 +1387,93 @@ var _HexclaveServerAppImplIncomplete = class extends __client_app_impl_js._Hexcl
1387
1387
  async queryAnalytics(options) {
1388
1388
  return await this._interface.queryAnalytics(options);
1389
1389
  }
1390
+ async listSessionReplays(options) {
1391
+ const response = await this._interface.listSessionReplays({
1392
+ cursor: options?.cursor,
1393
+ limit: options?.limit,
1394
+ user_ids: options?.userIds,
1395
+ team_ids: options?.teamIds,
1396
+ duration_ms_min: options?.durationMsMin,
1397
+ duration_ms_max: options?.durationMsMax,
1398
+ last_event_at_from_millis: options?.lastEventAtFromMillis,
1399
+ last_event_at_to_millis: options?.lastEventAtToMillis,
1400
+ click_count_min: options?.clickCountMin
1401
+ });
1402
+ return {
1403
+ items: response.items.map((r) => ({
1404
+ id: r.id,
1405
+ refreshTokenId: r.refresh_token_id,
1406
+ projectUser: {
1407
+ id: r.project_user.id,
1408
+ displayName: r.project_user.display_name,
1409
+ primaryEmail: r.project_user.primary_email
1410
+ },
1411
+ startedAt: new Date(r.started_at_millis),
1412
+ lastEventAt: new Date(r.last_event_at_millis),
1413
+ chunkCount: r.chunk_count,
1414
+ eventCount: r.event_count
1415
+ })),
1416
+ nextCursor: response.pagination.next_cursor
1417
+ };
1418
+ }
1419
+ async getSessionReplay(sessionReplayId) {
1420
+ const response = await this._interface.getSessionReplay(sessionReplayId);
1421
+ return {
1422
+ id: response.id,
1423
+ refreshTokenId: response.refresh_token_id,
1424
+ projectUser: {
1425
+ id: response.project_user.id,
1426
+ displayName: response.project_user.display_name,
1427
+ primaryEmail: response.project_user.primary_email
1428
+ },
1429
+ startedAt: new Date(response.started_at_millis),
1430
+ lastEventAt: new Date(response.last_event_at_millis),
1431
+ chunkCount: response.chunk_count,
1432
+ eventCount: response.event_count
1433
+ };
1434
+ }
1435
+ async listSessionReplayChunks(sessionReplayId, options) {
1436
+ const response = await this._interface.listSessionReplayChunks(sessionReplayId, {
1437
+ cursor: options?.cursor,
1438
+ limit: options?.limit
1439
+ });
1440
+ return {
1441
+ items: response.items.map((c) => ({
1442
+ id: c.id,
1443
+ batchId: c.batch_id,
1444
+ sessionReplaySegmentId: c.session_replay_segment_id,
1445
+ browserSessionId: c.browser_session_id,
1446
+ eventCount: c.event_count,
1447
+ byteLength: c.byte_length,
1448
+ firstEventAt: new Date(c.first_event_at_millis),
1449
+ lastEventAt: new Date(c.last_event_at_millis),
1450
+ createdAt: new Date(c.created_at_millis)
1451
+ })),
1452
+ nextCursor: response.pagination.next_cursor
1453
+ };
1454
+ }
1455
+ async getSessionReplayChunkEvents(sessionReplayId, chunkId) {
1456
+ return await this._interface.getSessionReplayChunkEvents(sessionReplayId, chunkId);
1457
+ }
1458
+ async getSessionReplayEvents(sessionReplayId, options) {
1459
+ const response = await this._interface.getSessionReplayEvents(sessionReplayId, options);
1460
+ return {
1461
+ chunks: response.chunks.map((c) => ({
1462
+ id: c.id,
1463
+ batchId: c.batch_id,
1464
+ sessionReplaySegmentId: c.session_replay_segment_id,
1465
+ eventCount: c.event_count,
1466
+ byteLength: c.byte_length,
1467
+ firstEventAt: new Date(c.first_event_at_millis),
1468
+ lastEventAt: new Date(c.last_event_at_millis),
1469
+ createdAt: new Date(c.created_at_millis)
1470
+ })),
1471
+ chunkEvents: response.chunk_events.map((ce) => ({
1472
+ chunkId: ce.chunk_id,
1473
+ events: ce.events
1474
+ }))
1475
+ };
1476
+ }
1390
1477
  async _refreshSession(session) {
1391
1478
  await Promise.all([super._refreshUser(session), this._currentServerUserCache.refresh([session])]);
1392
1479
  }