@hexclave/js 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +183 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js +31 -9
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/common.js +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.js +1 -1
- package/dist/esm/lib/hexclave-app/url-targets.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/url-targets.js +21 -7
- package/dist/esm/lib/hexclave-app/url-targets.js.map +1 -1
- package/dist/esm/lib/hexclave-app/url-targets.test.js +12 -0
- package/dist/esm/lib/hexclave-app/url-targets.test.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +183 -0
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -0
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js +30 -8
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/common.js +1 -1
- package/dist/lib/hexclave-app/apps/implementations/server-app-impl.js +1 -1
- package/dist/lib/hexclave-app/url-targets.d.ts.map +1 -1
- package/dist/lib/hexclave-app/url-targets.js +21 -7
- package/dist/lib/hexclave-app/url-targets.js.map +1 -1
- package/dist/lib/hexclave-app/url-targets.test.js +12 -0
- package/dist/lib/hexclave-app/url-targets.test.js.map +1 -1
- package/package.json +2 -2
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.ts +212 -0
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.ts +36 -7
- package/src/lib/hexclave-app/url-targets.test.ts +17 -0
- package/src/lib/hexclave-app/url-targets.ts +21 -3
|
@@ -12,7 +12,7 @@ import { AsyncCache } from "@hexclave/shared/dist/utils/caches";
|
|
|
12
12
|
import { createGlobal, getGlobal } from "@hexclave/shared/dist/utils/globals";
|
|
13
13
|
|
|
14
14
|
//#region src/lib/hexclave-app/apps/implementations/common.ts
|
|
15
|
-
const clientVersion = "js @hexclave/js@1.0.
|
|
15
|
+
const clientVersion = "js @hexclave/js@1.0.6";
|
|
16
16
|
if (clientVersion.startsWith("STACK_COMPILE_TIME")) throw new HexclaveAssertionError("Client version was not replaced. Something went wrong during build!");
|
|
17
17
|
const replaceHexclavePortPrefix = (input) => {
|
|
18
18
|
if (!input) return input;
|
|
@@ -2,8 +2,8 @@ import { HexclaveAssertionError, captureError, throwErr } from "@hexclave/shared
|
|
|
2
2
|
import { HexclaveServerInterface, KnownErrors } from "@hexclave/shared";
|
|
3
3
|
import { Result } from "@hexclave/shared/dist/utils/results";
|
|
4
4
|
import { clientVersion, createCache, createCacheBySession, getDefaultExtraRequestHeaders, getDefaultProjectId, getDefaultPublishableClientKey, getDefaultSecretServerKey, resolveApiUrls, resolveConstructorOptions } from "./common.js";
|
|
5
|
-
import { WebAuthnError, startRegistration } from "@simplewebauthn/browser";
|
|
6
5
|
import { InternalSession } from "@hexclave/shared/dist/sessions";
|
|
6
|
+
import { WebAuthnError, startRegistration } from "@simplewebauthn/browser";
|
|
7
7
|
import { constructRedirectUrl } from "../../../../utils/url.js";
|
|
8
8
|
import { apiKeyCreationOptionsToCrud, apiKeyUpdateOptionsToCrud } from "../../api-keys/index.js";
|
|
9
9
|
import { serverContactChannelCreateOptionsToCrud, serverContactChannelUpdateOptionsToCrud } from "../../contact-channels/index.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"url-targets.d.ts","names":[],"sources":["../../../../src/lib/hexclave-app/url-targets.ts"],"mappings":";;;cA2Ga,mBAAA,GAAuB,OAAA;EAAW,SAAA;EAAmB,QAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"url-targets.d.ts","names":[],"sources":["../../../../src/lib/hexclave-app/url-targets.ts"],"mappings":";;;cA2Ga,mBAAA,GAAuB,OAAA;EAAW,SAAA;EAAmB,QAAA;AAAA;AAAA,cAyBrD,uBAAA,GAA2B,OAAA;EACtC,SAAA;EACA,WAAA;EACA,aAAA;AAAA;AAAA,cA+DW,kBAAA,GAAsB,OAAA;EAAW,IAAA,EAAM,iBAAA;EAA+B,SAAA;AAAA,MAAsB,mBAAA;AAAA,cAqJ5F,sBAAA,GAA0B,OAAA;EACrC,iBAAA,UAvNA;EAyNA,MAAA;EACA,SAAA;AAAA;AAAA,cAOW,oCAAA,GAAwC,OAAA;EACnD,aAAA,EAAe,uBAAA;EACf,SAAA;EACA,WAAA;AAAA;AAAA,iBAiBc,aAAA,CAAc,QAAA,UAAkB,cAAA;EAA4B,KAAA;EAAe,UAAA;EAAoB,aAAA;EAA8B,aAAA;AAAA;AAAA,cAuBhI,4BAAA,GAAgC,OAAA;EAAW,GAAA;EAAa,SAAA;AAAA"}
|
|
@@ -59,6 +59,11 @@ const isRelativeUrlString = (url) => {
|
|
|
59
59
|
if (url.startsWith("//")) return false;
|
|
60
60
|
return !schemePrefixRegex.test(url);
|
|
61
61
|
};
|
|
62
|
+
const nonHostedHandlerNames = new Set([
|
|
63
|
+
"afterSignIn",
|
|
64
|
+
"afterSignUp",
|
|
65
|
+
"afterSignOut"
|
|
66
|
+
]);
|
|
62
67
|
const isLocalHandlerUrlTarget = (options) => {
|
|
63
68
|
const urlObject = new URL(options.targetUrl, localUrlPlaceholderOrigin);
|
|
64
69
|
if (!(urlObject.pathname === options.handlerPath || urlObject.pathname.startsWith(`${options.handlerPath}/`))) return false;
|
|
@@ -69,10 +74,12 @@ const resolveUrlTarget = (options) => {
|
|
|
69
74
|
if (typeof options.target === "string") return options.target;
|
|
70
75
|
switch (options.target.type) {
|
|
71
76
|
case "handler-component": return options.fallbackPath;
|
|
72
|
-
case "hosted":
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
77
|
+
case "hosted":
|
|
78
|
+
if (nonHostedHandlerNames.has(options.handlerName)) return options.fallbackPath;
|
|
79
|
+
return getHostedHandlerUrl({
|
|
80
|
+
projectId: options.projectId,
|
|
81
|
+
pagePath: getHostedPagePathForHandlerName(options.handlerName)
|
|
82
|
+
});
|
|
76
83
|
case "custom": return resolveCustomTargetUrl({
|
|
77
84
|
target: options.target,
|
|
78
85
|
handlerName: options.handlerName
|
|
@@ -97,15 +104,22 @@ const resolveHandlerUrls = (options) => {
|
|
|
97
104
|
target: configuredUrls.handler,
|
|
98
105
|
handlerName: "handler"
|
|
99
106
|
});
|
|
107
|
+
const homeTarget = configuredUrls?.home ?? defaultTarget;
|
|
108
|
+
const localHome = resolveUrlTarget({
|
|
109
|
+
target: typeof homeTarget !== "string" && homeTarget.type === "hosted" ? { type: "handler-component" } : homeTarget,
|
|
110
|
+
fallbackPath: "/",
|
|
111
|
+
handlerName: "home",
|
|
112
|
+
projectId: options.projectId
|
|
113
|
+
});
|
|
100
114
|
const home = resolveUrlTarget({
|
|
101
|
-
target:
|
|
115
|
+
target: homeTarget,
|
|
102
116
|
fallbackPath: "/",
|
|
103
117
|
handlerName: "home",
|
|
104
118
|
projectId: options.projectId
|
|
105
119
|
});
|
|
106
120
|
const afterSignIn = resolveUrlTarget({
|
|
107
121
|
target: configuredUrls?.afterSignIn ?? defaultTarget,
|
|
108
|
-
fallbackPath:
|
|
122
|
+
fallbackPath: localHome,
|
|
109
123
|
handlerName: "afterSignIn",
|
|
110
124
|
projectId: options.projectId
|
|
111
125
|
});
|
|
@@ -143,7 +157,7 @@ const resolveHandlerUrls = (options) => {
|
|
|
143
157
|
}),
|
|
144
158
|
afterSignOut: resolveUrlTarget({
|
|
145
159
|
target: configuredUrls?.afterSignOut ?? defaultTarget,
|
|
146
|
-
fallbackPath:
|
|
160
|
+
fallbackPath: localHome,
|
|
147
161
|
handlerName: "afterSignOut",
|
|
148
162
|
projectId: options.projectId
|
|
149
163
|
}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"url-targets.js","names":[],"sources":["../../../../src/lib/hexclave-app/url-targets.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 { getCustomPagePrompts, type CustomPagePrompt } from \"@hexclave/shared/dist/interface/handler-urls\";\nimport { HexclaveAssertionError } from \"@hexclave/shared/dist/utils/errors\";\nimport { getHostedHandlerUrlFromConfig } from \"@hexclave/shared/dist/utils/redirect-urls\";\nimport { envVars } from \"../env\";\nimport { DefaultHandlerUrlTarget, HandlerPageUrls, HandlerUrlOptions, HandlerUrlTarget, HandlerUrls, ResolvedHandlerUrls } from \"./common\";\n\nconst localUrlPlaceholderOrigin = \"http://example.com\";\nconst schemePrefixRegex = /^[a-zA-Z][a-zA-Z\\d+\\-.]*:/;\n\nconst customPagePrompts: Record<keyof Omit<HandlerPageUrls, \"handler\">, CustomPagePrompt> = getCustomPagePrompts();\n\nconst joinHandlerComponentPath = (basePath: string, pagePath: string): string => {\n const normalizedBasePath = basePath.endsWith(\"/\") && basePath.length > 1\n ? basePath.slice(0, -1)\n : basePath;\n if (pagePath.length === 0) {\n return normalizedBasePath;\n }\n if (normalizedBasePath === \"/\") {\n return `/${pagePath}`;\n }\n return `${normalizedBasePath}/${pagePath}`;\n};\n\nconst getHostedPagePathForHandlerName = (handlerName: keyof HandlerUrls): string => {\n switch (handlerName) {\n case \"handler\": {\n return \"\";\n }\n case \"home\": {\n return \"\";\n }\n case \"afterSignIn\": {\n return \"\";\n }\n case \"afterSignUp\": {\n return \"\";\n }\n case \"afterSignOut\": {\n return \"\";\n }\n case \"signIn\": {\n return \"sign-in\";\n }\n case \"signUp\": {\n return \"sign-up\";\n }\n case \"signOut\": {\n return \"sign-out\";\n }\n case \"emailVerification\": {\n return \"email-verification\";\n }\n case \"passwordReset\": {\n return \"password-reset\";\n }\n case \"forgotPassword\": {\n return \"forgot-password\";\n }\n case \"oauthCallback\": {\n return \"oauth-callback\";\n }\n case \"magicLinkCallback\": {\n return \"magic-link-callback\";\n }\n case \"accountSettings\": {\n return \"account-settings\";\n }\n case \"teamInvitation\": {\n return \"team-invitation\";\n }\n case \"cliAuthConfirm\": {\n return \"cli-auth-confirm\";\n }\n case \"mfa\": {\n return \"mfa\";\n }\n case \"error\": {\n return \"error\";\n }\n case \"onboarding\": {\n return \"onboarding\";\n }\n }\n};\n\nconst resolveCustomTargetUrl = (options: {\n target: { type: \"custom\", url: string, version: number },\n handlerName: keyof HandlerUrls,\n}): string => {\n const handlerName = options.handlerName;\n if (handlerName in customPagePrompts) {\n const customPagePrompt = customPagePrompts[handlerName as keyof typeof customPagePrompts];\n if (options.target.version === 0 || options.target.version in customPagePrompt.versions) {\n return options.target.url;\n }\n\n throw new Error(`Unsupported custom page version ${options.target.version} for ${options.handlerName} page at ${options.target.url}. The latest supported version of this page is ${Math.max(0, ...Object.keys(customPagePrompt.versions).map(Number))}. Please upgrade your Hexclave SDK to a version that supports this version.`);\n } else {\n throw new Error(`URL target ${options.handlerName} cannot be a custom page. Please specify the URL as a string instead.`);\n }\n};\n\nexport const getHostedHandlerUrl = (options: { projectId: string, pagePath: string }): string => {\n const normalizedPagePath = options.pagePath.replace(/^\\/+/, \"\");\n const hostedPath = normalizedPagePath.length > 0 ? `handler/${normalizedPagePath}` : \"handler\";\n return getHostedHandlerUrlFromConfig({\n projectId: options.projectId,\n hostedPath,\n hostedHandlerDomainSuffix: envVars.NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX,\n hostedHandlerUrlTemplate: envVars.NEXT_PUBLIC_STACK_HOSTED_HANDLER_URL_TEMPLATE,\n hexclavePortPrefix: envVars.NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX,\n });\n};\n\nconst isRelativeUrlString = (url: string): boolean => {\n if (url.startsWith(\"//\")) {\n return false;\n }\n return !schemePrefixRegex.test(url);\n};\n\nexport const isLocalHandlerUrlTarget = (options: {\n targetUrl: string,\n handlerPath: string,\n currentOrigin?: string,\n}): boolean => {\n const urlObject = new URL(options.targetUrl, localUrlPlaceholderOrigin);\n const isHandlerPathTarget = urlObject.pathname === options.handlerPath\n || urlObject.pathname.startsWith(`${options.handlerPath}/`);\n if (!isHandlerPathTarget) {\n return false;\n }\n\n // On server we only have path information, so treat matching handler paths as local.\n if (options.currentOrigin == null) {\n return true;\n }\n\n return isRelativeUrlString(options.targetUrl) || urlObject.origin === options.currentOrigin;\n};\n\nconst resolveUrlTarget = (options: {\n target: HandlerUrlTarget,\n fallbackPath: string,\n handlerName: keyof HandlerUrls,\n projectId: string,\n}): string => {\n if (typeof options.target === \"string\") {\n return options.target;\n }\n\n switch (options.target.type) {\n case \"handler-component\": {\n return options.fallbackPath;\n }\n case \"hosted\": {\n return getHostedHandlerUrl({\n projectId: options.projectId,\n pagePath: getHostedPagePathForHandlerName(options.handlerName),\n });\n }\n case \"custom\": {\n return resolveCustomTargetUrl({\n target: options.target,\n handlerName: options.handlerName,\n });\n }\n }\n};\n\nconst assertOAuthCallbackTargetIsRelative = (target: HandlerUrlTarget): void => {\n const url = typeof target === \"string\"\n ? target\n : target.type === \"custom\"\n ? target.url\n : null;\n if (url != null && !isRelativeUrlString(url)) {\n throw new HexclaveAssertionError(\"OAuth callback URLs must be relative.\", {\n oauthCallbackUrl: url,\n hint: \"Use a relative URL like '/handler/oauth-callback', or use { type: 'hosted' } to let Stack use the current page for hosted callbacks.\",\n });\n }\n};\n\nexport const resolveHandlerUrls = (options: { urls: HandlerUrlOptions | undefined, projectId: string }): ResolvedHandlerUrls => {\n const configuredUrls = options.urls;\n const defaultTarget = configuredUrls?.default ?? { type: \"handler-component\" } as const;\n const oauthCallbackTarget: HandlerUrlTarget = configuredUrls?.oauthCallback ?? (\n defaultTarget.type === \"hosted\"\n ? defaultTarget\n : { type: \"handler-component\" }\n );\n assertOAuthCallbackTargetIsRelative(oauthCallbackTarget);\n let handlerComponentBasePath = \"/handler\";\n if (typeof configuredUrls?.handler === \"string\") {\n handlerComponentBasePath = configuredUrls.handler;\n } else if (configuredUrls?.handler != null && configuredUrls.handler.type === \"custom\") {\n handlerComponentBasePath = resolveCustomTargetUrl({\n target: configuredUrls.handler,\n handlerName: \"handler\",\n });\n }\n\n const home = resolveUrlTarget({\n target: configuredUrls?.home ?? defaultTarget,\n fallbackPath: \"/\",\n handlerName: \"home\",\n projectId: options.projectId,\n });\n const afterSignIn = resolveUrlTarget({\n target: configuredUrls?.afterSignIn ?? defaultTarget,\n fallbackPath: home,\n handlerName: \"afterSignIn\",\n projectId: options.projectId,\n });\n\n return {\n handler: resolveUrlTarget({\n target: configuredUrls?.handler ?? defaultTarget,\n fallbackPath: handlerComponentBasePath,\n handlerName: \"handler\",\n projectId: options.projectId,\n }),\n signIn: resolveUrlTarget({\n target: configuredUrls?.signIn ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"sign-in\"),\n handlerName: \"signIn\",\n projectId: options.projectId,\n }),\n signUp: resolveUrlTarget({\n target: configuredUrls?.signUp ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"sign-up\"),\n handlerName: \"signUp\",\n projectId: options.projectId,\n }),\n afterSignIn,\n afterSignUp: resolveUrlTarget({\n target: configuredUrls?.afterSignUp ?? defaultTarget,\n fallbackPath: afterSignIn,\n handlerName: \"afterSignUp\",\n projectId: options.projectId,\n }),\n signOut: resolveUrlTarget({\n target: configuredUrls?.signOut ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"sign-out\"),\n handlerName: \"signOut\",\n projectId: options.projectId,\n }),\n afterSignOut: resolveUrlTarget({\n target: configuredUrls?.afterSignOut ?? defaultTarget,\n fallbackPath: home,\n handlerName: \"afterSignOut\",\n projectId: options.projectId,\n }),\n emailVerification: resolveUrlTarget({\n target: configuredUrls?.emailVerification ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"email-verification\"),\n handlerName: \"emailVerification\",\n projectId: options.projectId,\n }),\n passwordReset: resolveUrlTarget({\n target: configuredUrls?.passwordReset ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"password-reset\"),\n handlerName: \"passwordReset\",\n projectId: options.projectId,\n }),\n forgotPassword: resolveUrlTarget({\n target: configuredUrls?.forgotPassword ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"forgot-password\"),\n handlerName: \"forgotPassword\",\n projectId: options.projectId,\n }),\n home,\n oauthCallback: resolveUrlTarget({\n target: oauthCallbackTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"oauth-callback\"),\n handlerName: \"oauthCallback\",\n projectId: options.projectId,\n }),\n magicLinkCallback: resolveUrlTarget({\n target: configuredUrls?.magicLinkCallback ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"magic-link-callback\"),\n handlerName: \"magicLinkCallback\",\n projectId: options.projectId,\n }),\n accountSettings: resolveUrlTarget({\n target: configuredUrls?.accountSettings ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"account-settings\"),\n handlerName: \"accountSettings\",\n projectId: options.projectId,\n }),\n teamInvitation: resolveUrlTarget({\n target: configuredUrls?.teamInvitation ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"team-invitation\"),\n handlerName: \"teamInvitation\",\n projectId: options.projectId,\n }),\n cliAuthConfirm: resolveUrlTarget({\n target: configuredUrls?.cliAuthConfirm ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"cli-auth-confirm\"),\n handlerName: \"cliAuthConfirm\",\n projectId: options.projectId,\n }),\n mfa: resolveUrlTarget({\n target: configuredUrls?.mfa ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"mfa\"),\n handlerName: \"mfa\",\n projectId: options.projectId,\n }),\n error: resolveUrlTarget({\n target: configuredUrls?.error ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"error\"),\n handlerName: \"error\",\n projectId: options.projectId,\n }),\n onboarding: resolveUrlTarget({\n target: configuredUrls?.onboarding ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"onboarding\"),\n handlerName: \"onboarding\",\n projectId: options.projectId,\n }),\n };\n};\n\nexport const buildCliAuthConfirmUrl = (options: {\n cliAuthConfirmUrl: string,\n /** Used as the base URL only when cliAuthConfirmUrl is relative. */\n appUrl: string,\n loginCode: string,\n}): string => {\n const url = new URL(options.cliAuthConfirmUrl, options.appUrl);\n url.searchParams.set(\"login_code\", options.loginCode);\n return url.toString();\n};\n\nexport const resolveUnknownHandlerPathFallbackUrl = (options: {\n defaultTarget: DefaultHandlerUrlTarget | undefined,\n projectId: string,\n unknownPath: string,\n}): string | null => {\n const defaultTarget = options.defaultTarget ?? { type: \"handler-component\" } satisfies DefaultHandlerUrlTarget;\n\n switch (defaultTarget.type) {\n case \"handler-component\": {\n return null;\n }\n case \"hosted\": {\n return getHostedHandlerUrl({\n projectId: options.projectId,\n pagePath: options.unknownPath,\n });\n }\n }\n};\n\nexport function getPagePrompt(pageName: string, currentVersion?: number): { title: string; fullPrompt: string; upgradePrompt: string | null; latestVersion: number } | null {\n if (!(pageName in customPagePrompts)) return null;\n const prompt = customPagePrompts[pageName as keyof typeof customPagePrompts];\n const versionKeys = Object.keys(prompt.versions).map(Number);\n const latestVersion = versionKeys.length > 0 ? Math.max(...versionKeys) : 0;\n\n let upgradePrompt: string | null = null;\n if (currentVersion != null) {\n const relevantVersions = versionKeys\n .filter(v => v > currentVersion)\n .sort((a, b) => a - b);\n const prompts = relevantVersions\n .map(v => prompt.versions[v].upgradePrompt)\n .filter(p => p.length > 0);\n upgradePrompt = prompts.length > 0 ? prompts.join(\"\\n\\n\") : null;\n } else {\n const upgradeEntry = latestVersion > 0 ? prompt.versions[latestVersion] : undefined;\n upgradePrompt = upgradeEntry?.upgradePrompt ?? null;\n }\n\n return { title: prompt.title, fullPrompt: prompt.fullPrompt, upgradePrompt, latestVersion };\n}\n\nexport const isHostedHandlerUrlForProject = (options: { url: string, projectId: string }): boolean => {\n let parsedUrl: URL;\n try {\n parsedUrl = new URL(options.url);\n } catch {\n return false;\n }\n\n const hostedBaseUrl = new URL(getHostedHandlerUrl({ projectId: options.projectId, pagePath: \"\" }));\n return parsedUrl.origin === hostedBaseUrl.origin\n && (parsedUrl.pathname === hostedBaseUrl.pathname || parsedUrl.pathname.startsWith(`${hostedBaseUrl.pathname}/`));\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"url-targets.js","names":[],"sources":["../../../../src/lib/hexclave-app/url-targets.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 { getCustomPagePrompts, type CustomPagePrompt } from \"@hexclave/shared/dist/interface/handler-urls\";\nimport { HexclaveAssertionError } from \"@hexclave/shared/dist/utils/errors\";\nimport { getHostedHandlerUrlFromConfig } from \"@hexclave/shared/dist/utils/redirect-urls\";\nimport { envVars } from \"../env\";\nimport { DefaultHandlerUrlTarget, HandlerPageUrls, HandlerUrlOptions, HandlerUrlTarget, HandlerUrls, ResolvedHandlerUrls } from \"./common\";\n\nconst localUrlPlaceholderOrigin = \"http://example.com\";\nconst schemePrefixRegex = /^[a-zA-Z][a-zA-Z\\d+\\-.]*:/;\n\nconst customPagePrompts: Record<keyof Omit<HandlerPageUrls, \"handler\">, CustomPagePrompt> = getCustomPagePrompts();\n\nconst joinHandlerComponentPath = (basePath: string, pagePath: string): string => {\n const normalizedBasePath = basePath.endsWith(\"/\") && basePath.length > 1\n ? basePath.slice(0, -1)\n : basePath;\n if (pagePath.length === 0) {\n return normalizedBasePath;\n }\n if (normalizedBasePath === \"/\") {\n return `/${pagePath}`;\n }\n return `${normalizedBasePath}/${pagePath}`;\n};\n\nconst getHostedPagePathForHandlerName = (handlerName: keyof HandlerUrls): string => {\n switch (handlerName) {\n case \"handler\": {\n return \"\";\n }\n case \"home\": {\n return \"\";\n }\n case \"afterSignIn\": {\n return \"\";\n }\n case \"afterSignUp\": {\n return \"\";\n }\n case \"afterSignOut\": {\n return \"\";\n }\n case \"signIn\": {\n return \"sign-in\";\n }\n case \"signUp\": {\n return \"sign-up\";\n }\n case \"signOut\": {\n return \"sign-out\";\n }\n case \"emailVerification\": {\n return \"email-verification\";\n }\n case \"passwordReset\": {\n return \"password-reset\";\n }\n case \"forgotPassword\": {\n return \"forgot-password\";\n }\n case \"oauthCallback\": {\n return \"oauth-callback\";\n }\n case \"magicLinkCallback\": {\n return \"magic-link-callback\";\n }\n case \"accountSettings\": {\n return \"account-settings\";\n }\n case \"teamInvitation\": {\n return \"team-invitation\";\n }\n case \"cliAuthConfirm\": {\n return \"cli-auth-confirm\";\n }\n case \"mfa\": {\n return \"mfa\";\n }\n case \"error\": {\n return \"error\";\n }\n case \"onboarding\": {\n return \"onboarding\";\n }\n }\n};\n\nconst resolveCustomTargetUrl = (options: {\n target: { type: \"custom\", url: string, version: number },\n handlerName: keyof HandlerUrls,\n}): string => {\n const handlerName = options.handlerName;\n if (handlerName in customPagePrompts) {\n const customPagePrompt = customPagePrompts[handlerName as keyof typeof customPagePrompts];\n if (options.target.version === 0 || options.target.version in customPagePrompt.versions) {\n return options.target.url;\n }\n\n throw new Error(`Unsupported custom page version ${options.target.version} for ${options.handlerName} page at ${options.target.url}. The latest supported version of this page is ${Math.max(0, ...Object.keys(customPagePrompt.versions).map(Number))}. Please upgrade your Hexclave SDK to a version that supports this version.`);\n } else {\n throw new Error(`URL target ${options.handlerName} cannot be a custom page. Please specify the URL as a string instead.`);\n }\n};\n\nexport const getHostedHandlerUrl = (options: { projectId: string, pagePath: string }): string => {\n const normalizedPagePath = options.pagePath.replace(/^\\/+/, \"\");\n const hostedPath = normalizedPagePath.length > 0 ? `handler/${normalizedPagePath}` : \"handler\";\n return getHostedHandlerUrlFromConfig({\n projectId: options.projectId,\n hostedPath,\n hostedHandlerDomainSuffix: envVars.NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX,\n hostedHandlerUrlTemplate: envVars.NEXT_PUBLIC_STACK_HOSTED_HANDLER_URL_TEMPLATE,\n hexclavePortPrefix: envVars.NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX,\n });\n};\n\nconst isRelativeUrlString = (url: string): boolean => {\n if (url.startsWith(\"//\")) {\n return false;\n }\n return !schemePrefixRegex.test(url);\n};\n\nconst nonHostedHandlerNames = new Set<keyof HandlerUrls>([\n \"afterSignIn\",\n \"afterSignUp\",\n \"afterSignOut\",\n]);\n\nexport const isLocalHandlerUrlTarget = (options: {\n targetUrl: string,\n handlerPath: string,\n currentOrigin?: string,\n}): boolean => {\n const urlObject = new URL(options.targetUrl, localUrlPlaceholderOrigin);\n const isHandlerPathTarget = urlObject.pathname === options.handlerPath\n || urlObject.pathname.startsWith(`${options.handlerPath}/`);\n if (!isHandlerPathTarget) {\n return false;\n }\n\n // On server we only have path information, so treat matching handler paths as local.\n if (options.currentOrigin == null) {\n return true;\n }\n\n return isRelativeUrlString(options.targetUrl) || urlObject.origin === options.currentOrigin;\n};\n\nconst resolveUrlTarget = (options: {\n target: HandlerUrlTarget,\n fallbackPath: string,\n handlerName: keyof HandlerUrls,\n projectId: string,\n}): string => {\n if (typeof options.target === \"string\") {\n return options.target;\n }\n\n switch (options.target.type) {\n case \"handler-component\": {\n return options.fallbackPath;\n }\n case \"hosted\": {\n if (nonHostedHandlerNames.has(options.handlerName)) {\n return options.fallbackPath;\n }\n return getHostedHandlerUrl({\n projectId: options.projectId,\n pagePath: getHostedPagePathForHandlerName(options.handlerName),\n });\n }\n case \"custom\": {\n return resolveCustomTargetUrl({\n target: options.target,\n handlerName: options.handlerName,\n });\n }\n }\n};\n\nconst assertOAuthCallbackTargetIsRelative = (target: HandlerUrlTarget): void => {\n const url = typeof target === \"string\"\n ? target\n : target.type === \"custom\"\n ? target.url\n : null;\n if (url != null && !isRelativeUrlString(url)) {\n throw new HexclaveAssertionError(\"OAuth callback URLs must be relative.\", {\n oauthCallbackUrl: url,\n hint: \"Use a relative URL like '/handler/oauth-callback', or use { type: 'hosted' } to let Stack use the current page for hosted callbacks.\",\n });\n }\n};\n\nexport const resolveHandlerUrls = (options: { urls: HandlerUrlOptions | undefined, projectId: string }): ResolvedHandlerUrls => {\n const configuredUrls = options.urls;\n const defaultTarget = configuredUrls?.default ?? { type: \"handler-component\" } as const;\n const oauthCallbackTarget: HandlerUrlTarget = configuredUrls?.oauthCallback ?? (\n defaultTarget.type === \"hosted\"\n ? defaultTarget\n : { type: \"handler-component\" }\n );\n assertOAuthCallbackTargetIsRelative(oauthCallbackTarget);\n let handlerComponentBasePath = \"/handler\";\n if (typeof configuredUrls?.handler === \"string\") {\n handlerComponentBasePath = configuredUrls.handler;\n } else if (configuredUrls?.handler != null && configuredUrls.handler.type === \"custom\") {\n handlerComponentBasePath = resolveCustomTargetUrl({\n target: configuredUrls.handler,\n handlerName: \"handler\",\n });\n }\n\n const homeTarget = configuredUrls?.home ?? defaultTarget;\n const localHome = resolveUrlTarget({\n target: typeof homeTarget !== \"string\" && homeTarget.type === \"hosted\"\n ? { type: \"handler-component\" }\n : homeTarget,\n fallbackPath: \"/\",\n handlerName: \"home\",\n projectId: options.projectId,\n });\n const home = resolveUrlTarget({\n target: homeTarget,\n fallbackPath: \"/\",\n handlerName: \"home\",\n projectId: options.projectId,\n });\n const afterSignIn = resolveUrlTarget({\n target: configuredUrls?.afterSignIn ?? defaultTarget,\n fallbackPath: localHome,\n handlerName: \"afterSignIn\",\n projectId: options.projectId,\n });\n\n return {\n handler: resolveUrlTarget({\n target: configuredUrls?.handler ?? defaultTarget,\n fallbackPath: handlerComponentBasePath,\n handlerName: \"handler\",\n projectId: options.projectId,\n }),\n signIn: resolveUrlTarget({\n target: configuredUrls?.signIn ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"sign-in\"),\n handlerName: \"signIn\",\n projectId: options.projectId,\n }),\n signUp: resolveUrlTarget({\n target: configuredUrls?.signUp ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"sign-up\"),\n handlerName: \"signUp\",\n projectId: options.projectId,\n }),\n afterSignIn,\n afterSignUp: resolveUrlTarget({\n target: configuredUrls?.afterSignUp ?? defaultTarget,\n fallbackPath: afterSignIn,\n handlerName: \"afterSignUp\",\n projectId: options.projectId,\n }),\n signOut: resolveUrlTarget({\n target: configuredUrls?.signOut ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"sign-out\"),\n handlerName: \"signOut\",\n projectId: options.projectId,\n }),\n afterSignOut: resolveUrlTarget({\n target: configuredUrls?.afterSignOut ?? defaultTarget,\n fallbackPath: localHome,\n handlerName: \"afterSignOut\",\n projectId: options.projectId,\n }),\n emailVerification: resolveUrlTarget({\n target: configuredUrls?.emailVerification ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"email-verification\"),\n handlerName: \"emailVerification\",\n projectId: options.projectId,\n }),\n passwordReset: resolveUrlTarget({\n target: configuredUrls?.passwordReset ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"password-reset\"),\n handlerName: \"passwordReset\",\n projectId: options.projectId,\n }),\n forgotPassword: resolveUrlTarget({\n target: configuredUrls?.forgotPassword ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"forgot-password\"),\n handlerName: \"forgotPassword\",\n projectId: options.projectId,\n }),\n home,\n oauthCallback: resolveUrlTarget({\n target: oauthCallbackTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"oauth-callback\"),\n handlerName: \"oauthCallback\",\n projectId: options.projectId,\n }),\n magicLinkCallback: resolveUrlTarget({\n target: configuredUrls?.magicLinkCallback ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"magic-link-callback\"),\n handlerName: \"magicLinkCallback\",\n projectId: options.projectId,\n }),\n accountSettings: resolveUrlTarget({\n target: configuredUrls?.accountSettings ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"account-settings\"),\n handlerName: \"accountSettings\",\n projectId: options.projectId,\n }),\n teamInvitation: resolveUrlTarget({\n target: configuredUrls?.teamInvitation ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"team-invitation\"),\n handlerName: \"teamInvitation\",\n projectId: options.projectId,\n }),\n cliAuthConfirm: resolveUrlTarget({\n target: configuredUrls?.cliAuthConfirm ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"cli-auth-confirm\"),\n handlerName: \"cliAuthConfirm\",\n projectId: options.projectId,\n }),\n mfa: resolveUrlTarget({\n target: configuredUrls?.mfa ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"mfa\"),\n handlerName: \"mfa\",\n projectId: options.projectId,\n }),\n error: resolveUrlTarget({\n target: configuredUrls?.error ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"error\"),\n handlerName: \"error\",\n projectId: options.projectId,\n }),\n onboarding: resolveUrlTarget({\n target: configuredUrls?.onboarding ?? defaultTarget,\n fallbackPath: joinHandlerComponentPath(handlerComponentBasePath, \"onboarding\"),\n handlerName: \"onboarding\",\n projectId: options.projectId,\n }),\n };\n};\n\nexport const buildCliAuthConfirmUrl = (options: {\n cliAuthConfirmUrl: string,\n /** Used as the base URL only when cliAuthConfirmUrl is relative. */\n appUrl: string,\n loginCode: string,\n}): string => {\n const url = new URL(options.cliAuthConfirmUrl, options.appUrl);\n url.searchParams.set(\"login_code\", options.loginCode);\n return url.toString();\n};\n\nexport const resolveUnknownHandlerPathFallbackUrl = (options: {\n defaultTarget: DefaultHandlerUrlTarget | undefined,\n projectId: string,\n unknownPath: string,\n}): string | null => {\n const defaultTarget = options.defaultTarget ?? { type: \"handler-component\" } satisfies DefaultHandlerUrlTarget;\n\n switch (defaultTarget.type) {\n case \"handler-component\": {\n return null;\n }\n case \"hosted\": {\n return getHostedHandlerUrl({\n projectId: options.projectId,\n pagePath: options.unknownPath,\n });\n }\n }\n};\n\nexport function getPagePrompt(pageName: string, currentVersion?: number): { title: string; fullPrompt: string; upgradePrompt: string | null; latestVersion: number } | null {\n if (!(pageName in customPagePrompts)) return null;\n const prompt = customPagePrompts[pageName as keyof typeof customPagePrompts];\n const versionKeys = Object.keys(prompt.versions).map(Number);\n const latestVersion = versionKeys.length > 0 ? Math.max(...versionKeys) : 0;\n\n let upgradePrompt: string | null = null;\n if (currentVersion != null) {\n const relevantVersions = versionKeys\n .filter(v => v > currentVersion)\n .sort((a, b) => a - b);\n const prompts = relevantVersions\n .map(v => prompt.versions[v].upgradePrompt)\n .filter(p => p.length > 0);\n upgradePrompt = prompts.length > 0 ? prompts.join(\"\\n\\n\") : null;\n } else {\n const upgradeEntry = latestVersion > 0 ? prompt.versions[latestVersion] : undefined;\n upgradePrompt = upgradeEntry?.upgradePrompt ?? null;\n }\n\n return { title: prompt.title, fullPrompt: prompt.fullPrompt, upgradePrompt, latestVersion };\n}\n\nexport const isHostedHandlerUrlForProject = (options: { url: string, projectId: string }): boolean => {\n let parsedUrl: URL;\n try {\n parsedUrl = new URL(options.url);\n } catch {\n return false;\n }\n\n const hostedBaseUrl = new URL(getHostedHandlerUrl({ projectId: options.projectId, pagePath: \"\" }));\n return parsedUrl.origin === hostedBaseUrl.origin\n && (parsedUrl.pathname === hostedBaseUrl.pathname || parsedUrl.pathname.startsWith(`${hostedBaseUrl.pathname}/`));\n};\n"],"mappings":"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"}
|
|
@@ -88,6 +88,18 @@ describe("handler URL targets", () => {
|
|
|
88
88
|
expect(urls.signIn).toBe("https://project-id.example-stack-hosted.test/handler/sign-in");
|
|
89
89
|
expect(urls.cliAuthConfirm).toBe("https://project-id.example-stack-hosted.test/handler/cli-auth-confirm");
|
|
90
90
|
});
|
|
91
|
+
it("keeps redirect-only post-auth targets local even when the default target is hosted", () => {
|
|
92
|
+
vi.stubEnv("NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX", ".example-stack-hosted.test");
|
|
93
|
+
const urls = resolveHandlerUrls({
|
|
94
|
+
projectId: "project-id",
|
|
95
|
+
urls: { default: { type: "hosted" } }
|
|
96
|
+
});
|
|
97
|
+
expect(urls.signIn).toBe("https://project-id.example-stack-hosted.test/handler/sign-in");
|
|
98
|
+
expect(urls.signOut).toBe("https://project-id.example-stack-hosted.test/handler/sign-out");
|
|
99
|
+
expect(urls.afterSignIn).toBe("/");
|
|
100
|
+
expect(urls.afterSignUp).toBe("/");
|
|
101
|
+
expect(urls.afterSignOut).toBe("/");
|
|
102
|
+
});
|
|
91
103
|
it("rejects absolute OAuth callback string targets", () => {
|
|
92
104
|
expect(() => resolveHandlerUrls({
|
|
93
105
|
projectId: "project-id",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"url-targets.test.js","names":[],"sources":["../../../../src/lib/hexclave-app/url-targets.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 { afterEach, describe, expect, it, vi } from \"vitest\";\nimport { buildCliAuthConfirmUrl, getPagePrompt, isLocalHandlerUrlTarget, resolveHandlerUrls, resolveUnknownHandlerPathFallbackUrl } from \"./url-targets\";\n\ndescribe(\"handler URL targets\", () => {\n afterEach(() => {\n vi.unstubAllEnvs();\n });\n\n it(\"treats handler-component targets the same as omitted values\", () => {\n const urls = resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n handler: \"/custom-handler\",\n signIn: { type: \"handler-component\" },\n },\n });\n\n expect(urls.signIn).toBe(\"/custom-handler/sign-in\");\n });\n\n it(\"treats custom v0 page targets like legacy string targets\", () => {\n const urls = resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n handler: \"/custom-handler\",\n signIn: { type: \"handler-component\" },\n signUp: { type: \"custom\", url: \"/sign-up-explicit\", version: 0 },\n },\n });\n\n expect(urls.signIn).toBe(\"/custom-handler/sign-in\");\n expect(urls.signUp).toBe(\"/sign-up-explicit\");\n });\n\n it(\"throws on v0 custom target for handler page\", () => {\n expect(() => resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n handler: { type: \"custom\", url: \"/custom-handler\", version: 0 },\n },\n })).toThrowError(/cannot be a custom page/);\n });\n\n it(\"supports the latest documented custom target version\", () => {\n const signInPrompt = getPagePrompt(\"signIn\");\n if (signInPrompt == null) {\n throw new Error(\"Expected signIn prompt metadata to exist\");\n }\n\n const urls = resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n signIn: { type: \"custom\", url: \"/custom-sign-in\", version: signInPrompt.latestVersion },\n },\n });\n\n expect(urls.signIn).toBe(\"/custom-sign-in\");\n });\n\n it(\"throws on custom target versions newer than the latest supported version\", () => {\n const signInPrompt = getPagePrompt(\"signIn\");\n if (signInPrompt == null) {\n throw new Error(\"Expected signIn prompt metadata to exist\");\n }\n\n expect(() => resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n signIn: { type: \"custom\", url: \"/custom-sign-in\", version: signInPrompt.latestVersion + 1 },\n },\n })).toThrowError(/Unsupported custom page version/);\n });\n\n it(\"throws on non-zero custom version for handler page\", () => {\n expect(() => resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n handler: { type: \"custom\", url: \"/custom-handler\", version: 1 },\n },\n })).toThrowError(/cannot be a custom page/);\n });\n\n it(\"uses hosted defaults for unspecified URLs\", () => {\n vi.stubEnv(\"NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX\", \".example-stack-hosted.test\");\n\n const urls = resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n signUp: \"/sign-up\",\n default: { type: \"hosted\" },\n },\n });\n\n expect(urls.signUp).toBe(\"/sign-up\");\n expect(urls.signIn).toBe(\"https://project-id.example-stack-hosted.test/handler/sign-in\");\n expect(urls.cliAuthConfirm).toBe(\"https://project-id.example-stack-hosted.test/handler/cli-auth-confirm\");\n });\n\n it(\"rejects absolute OAuth callback string targets\", () => {\n expect(() => resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n oauthCallback: \"https://app.example.test/oauth-callback\",\n },\n })).toThrowErrorMatchingInlineSnapshot(`\n [HexclaveAssertionError: OAuth callback URLs must be relative.\n\n This is likely an error in Hexclave. Please make sure you are running the newest version and report it.]\n `);\n });\n\n it(\"rejects absolute OAuth callback custom targets\", () => {\n expect(() => resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n oauthCallback: { type: \"custom\", url: \"https://app.example.test/oauth-callback\", version: 0 },\n },\n })).toThrowErrorMatchingInlineSnapshot(`\n [HexclaveAssertionError: OAuth callback URLs must be relative.\n\n This is likely an error in Hexclave. Please make sure you are running the newest version and report it.]\n `);\n });\n\n it(\"inherits a hosted default target for the OAuth callback\", () => {\n vi.stubEnv(\"NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX\", \".example-stack-hosted.test\");\n\n const urls = resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n default: { type: \"hosted\" },\n },\n });\n\n expect(urls.signIn).toBe(\"https://project-id.example-stack-hosted.test/handler/sign-in\");\n expect(urls.oauthCallback).toBe(\"https://project-id.example-stack-hosted.test/handler/oauth-callback\");\n });\n\n it(\"supports custom CLI auth confirmation targets\", () => {\n const cliAuthConfirmPrompt = getPagePrompt(\"cliAuthConfirm\");\n if (cliAuthConfirmPrompt == null) {\n throw new Error(\"Expected cliAuthConfirm prompt metadata to exist\");\n }\n\n const urls = resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n cliAuthConfirm: { type: \"custom\", url: \"/cli/authorize\", version: cliAuthConfirmPrompt.latestVersion },\n },\n });\n\n expect(urls.cliAuthConfirm).toBe(\"/cli/authorize\");\n });\n\n it(\"builds CLI auth login URLs from the resolved confirmation target\", () => {\n expect(buildCliAuthConfirmUrl({\n cliAuthConfirmUrl: \"/cli/authorize\",\n appUrl: \"https://app.example.test/base\",\n loginCode: \"login-code\",\n })).toBe(\"https://app.example.test/cli/authorize?login_code=login-code\");\n });\n\n it(\"uses default target for unknown /handler/* pages\", () => {\n vi.stubEnv(\"NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX\", \".example-stack-hosted.test\");\n\n const url = resolveUnknownHandlerPathFallbackUrl({\n defaultTarget: { type: \"hosted\" },\n projectId: \"project-id\",\n unknownPath: \"custom-page\",\n });\n\n expect(url).toBe(\"https://project-id.example-stack-hosted.test/handler/custom-page\");\n });\n\n it(\"uses the full hosted handler URL template when configured\", () => {\n vi.stubEnv(\"NEXT_PUBLIC_STACK_HOSTED_HANDLER_URL_TEMPLATE\", \"http://{projectId}.localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}09/{hostedPath}\");\n vi.stubEnv(\"NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX\", \"93\");\n\n const urls = resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n default: { type: \"hosted\" },\n },\n });\n\n expect(urls.signIn).toBe(\"http://project-id.localhost:9309/handler/sign-in\");\n expect(urls.accountSettings).toBe(\"http://project-id.localhost:9309/handler/account-settings\");\n });\n\n it(\"validates the hosted handler URL template placeholders\", () => {\n vi.stubEnv(\"NEXT_PUBLIC_STACK_HOSTED_HANDLER_URL_TEMPLATE\", \"http://localhost:9309/{projectId}/handler\");\n\n expect(() => resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n default: { type: \"hosted\" },\n },\n })).toThrowError(/\\{projectId\\} and \\{hostedPath\\}/);\n });\n\n it(\"rejects hosted handler URL templates that put the project ID in the path\", () => {\n vi.stubEnv(\"NEXT_PUBLIC_STACK_HOSTED_HANDLER_URL_TEMPLATE\", \"http://localhost:9309/{projectId}/{hostedPath}\");\n\n expect(() => resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n default: { type: \"hosted\" },\n },\n })).toThrowErrorMatchingInlineSnapshot(`\n [HexclaveAssertionError: The hosted handler URL template must put {projectId} in the hostname.\n\n This is likely an error in Hexclave. Please make sure you are running the newest version and report it.]\n `);\n });\n});\n\ndescribe(\"isLocalHandlerUrlTarget\", () => {\n it(\"treats relative handler URLs as local targets\", () => {\n expect(isLocalHandlerUrlTarget({\n targetUrl: \"/handler/sign-in\",\n handlerPath: \"/handler\",\n currentOrigin: \"http://p91.localhost:9101\",\n })).toBe(true);\n });\n\n it(\"treats same-origin absolute handler URLs as local targets\", () => {\n expect(isLocalHandlerUrlTarget({\n targetUrl: \"http://p91.localhost:9101/handler/sign-in\",\n handlerPath: \"/handler\",\n currentOrigin: \"http://p91.localhost:9101\",\n })).toBe(true);\n });\n\n it(\"treats cross-origin absolute handler URLs as non-local targets\", () => {\n expect(isLocalHandlerUrlTarget({\n targetUrl: \"https://project-id.built-with-hexclave.com/handler/sign-in\",\n handlerPath: \"/handler\",\n currentOrigin: \"http://p91.localhost:9101\",\n })).toBe(false);\n });\n\n it(\"treats non-handler paths as non-local targets\", () => {\n expect(isLocalHandlerUrlTarget({\n targetUrl: \"/projects\",\n handlerPath: \"/handler\",\n currentOrigin: \"http://p91.localhost:9101\",\n })).toBe(false);\n });\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"url-targets.test.js","names":[],"sources":["../../../../src/lib/hexclave-app/url-targets.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 { afterEach, describe, expect, it, vi } from \"vitest\";\nimport { buildCliAuthConfirmUrl, getPagePrompt, isLocalHandlerUrlTarget, resolveHandlerUrls, resolveUnknownHandlerPathFallbackUrl } from \"./url-targets\";\n\ndescribe(\"handler URL targets\", () => {\n afterEach(() => {\n vi.unstubAllEnvs();\n });\n\n it(\"treats handler-component targets the same as omitted values\", () => {\n const urls = resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n handler: \"/custom-handler\",\n signIn: { type: \"handler-component\" },\n },\n });\n\n expect(urls.signIn).toBe(\"/custom-handler/sign-in\");\n });\n\n it(\"treats custom v0 page targets like legacy string targets\", () => {\n const urls = resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n handler: \"/custom-handler\",\n signIn: { type: \"handler-component\" },\n signUp: { type: \"custom\", url: \"/sign-up-explicit\", version: 0 },\n },\n });\n\n expect(urls.signIn).toBe(\"/custom-handler/sign-in\");\n expect(urls.signUp).toBe(\"/sign-up-explicit\");\n });\n\n it(\"throws on v0 custom target for handler page\", () => {\n expect(() => resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n handler: { type: \"custom\", url: \"/custom-handler\", version: 0 },\n },\n })).toThrowError(/cannot be a custom page/);\n });\n\n it(\"supports the latest documented custom target version\", () => {\n const signInPrompt = getPagePrompt(\"signIn\");\n if (signInPrompt == null) {\n throw new Error(\"Expected signIn prompt metadata to exist\");\n }\n\n const urls = resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n signIn: { type: \"custom\", url: \"/custom-sign-in\", version: signInPrompt.latestVersion },\n },\n });\n\n expect(urls.signIn).toBe(\"/custom-sign-in\");\n });\n\n it(\"throws on custom target versions newer than the latest supported version\", () => {\n const signInPrompt = getPagePrompt(\"signIn\");\n if (signInPrompt == null) {\n throw new Error(\"Expected signIn prompt metadata to exist\");\n }\n\n expect(() => resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n signIn: { type: \"custom\", url: \"/custom-sign-in\", version: signInPrompt.latestVersion + 1 },\n },\n })).toThrowError(/Unsupported custom page version/);\n });\n\n it(\"throws on non-zero custom version for handler page\", () => {\n expect(() => resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n handler: { type: \"custom\", url: \"/custom-handler\", version: 1 },\n },\n })).toThrowError(/cannot be a custom page/);\n });\n\n it(\"uses hosted defaults for unspecified URLs\", () => {\n vi.stubEnv(\"NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX\", \".example-stack-hosted.test\");\n\n const urls = resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n signUp: \"/sign-up\",\n default: { type: \"hosted\" },\n },\n });\n\n expect(urls.signUp).toBe(\"/sign-up\");\n expect(urls.signIn).toBe(\"https://project-id.example-stack-hosted.test/handler/sign-in\");\n expect(urls.cliAuthConfirm).toBe(\"https://project-id.example-stack-hosted.test/handler/cli-auth-confirm\");\n });\n\n it(\"keeps redirect-only post-auth targets local even when the default target is hosted\", () => {\n vi.stubEnv(\"NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX\", \".example-stack-hosted.test\");\n\n const urls = resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n default: { type: \"hosted\" },\n },\n });\n\n expect(urls.signIn).toBe(\"https://project-id.example-stack-hosted.test/handler/sign-in\");\n expect(urls.signOut).toBe(\"https://project-id.example-stack-hosted.test/handler/sign-out\");\n expect(urls.afterSignIn).toBe(\"/\");\n expect(urls.afterSignUp).toBe(\"/\");\n expect(urls.afterSignOut).toBe(\"/\");\n });\n\n it(\"rejects absolute OAuth callback string targets\", () => {\n expect(() => resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n oauthCallback: \"https://app.example.test/oauth-callback\",\n },\n })).toThrowErrorMatchingInlineSnapshot(`\n [HexclaveAssertionError: OAuth callback URLs must be relative.\n\n This is likely an error in Hexclave. Please make sure you are running the newest version and report it.]\n `);\n });\n\n it(\"rejects absolute OAuth callback custom targets\", () => {\n expect(() => resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n oauthCallback: { type: \"custom\", url: \"https://app.example.test/oauth-callback\", version: 0 },\n },\n })).toThrowErrorMatchingInlineSnapshot(`\n [HexclaveAssertionError: OAuth callback URLs must be relative.\n\n This is likely an error in Hexclave. Please make sure you are running the newest version and report it.]\n `);\n });\n\n it(\"inherits a hosted default target for the OAuth callback\", () => {\n vi.stubEnv(\"NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX\", \".example-stack-hosted.test\");\n\n const urls = resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n default: { type: \"hosted\" },\n },\n });\n\n expect(urls.signIn).toBe(\"https://project-id.example-stack-hosted.test/handler/sign-in\");\n expect(urls.oauthCallback).toBe(\"https://project-id.example-stack-hosted.test/handler/oauth-callback\");\n });\n\n it(\"supports custom CLI auth confirmation targets\", () => {\n const cliAuthConfirmPrompt = getPagePrompt(\"cliAuthConfirm\");\n if (cliAuthConfirmPrompt == null) {\n throw new Error(\"Expected cliAuthConfirm prompt metadata to exist\");\n }\n\n const urls = resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n cliAuthConfirm: { type: \"custom\", url: \"/cli/authorize\", version: cliAuthConfirmPrompt.latestVersion },\n },\n });\n\n expect(urls.cliAuthConfirm).toBe(\"/cli/authorize\");\n });\n\n it(\"builds CLI auth login URLs from the resolved confirmation target\", () => {\n expect(buildCliAuthConfirmUrl({\n cliAuthConfirmUrl: \"/cli/authorize\",\n appUrl: \"https://app.example.test/base\",\n loginCode: \"login-code\",\n })).toBe(\"https://app.example.test/cli/authorize?login_code=login-code\");\n });\n\n it(\"uses default target for unknown /handler/* pages\", () => {\n vi.stubEnv(\"NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX\", \".example-stack-hosted.test\");\n\n const url = resolveUnknownHandlerPathFallbackUrl({\n defaultTarget: { type: \"hosted\" },\n projectId: \"project-id\",\n unknownPath: \"custom-page\",\n });\n\n expect(url).toBe(\"https://project-id.example-stack-hosted.test/handler/custom-page\");\n });\n\n it(\"uses the full hosted handler URL template when configured\", () => {\n vi.stubEnv(\"NEXT_PUBLIC_STACK_HOSTED_HANDLER_URL_TEMPLATE\", \"http://{projectId}.localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}09/{hostedPath}\");\n vi.stubEnv(\"NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX\", \"93\");\n\n const urls = resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n default: { type: \"hosted\" },\n },\n });\n\n expect(urls.signIn).toBe(\"http://project-id.localhost:9309/handler/sign-in\");\n expect(urls.accountSettings).toBe(\"http://project-id.localhost:9309/handler/account-settings\");\n });\n\n it(\"validates the hosted handler URL template placeholders\", () => {\n vi.stubEnv(\"NEXT_PUBLIC_STACK_HOSTED_HANDLER_URL_TEMPLATE\", \"http://localhost:9309/{projectId}/handler\");\n\n expect(() => resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n default: { type: \"hosted\" },\n },\n })).toThrowError(/\\{projectId\\} and \\{hostedPath\\}/);\n });\n\n it(\"rejects hosted handler URL templates that put the project ID in the path\", () => {\n vi.stubEnv(\"NEXT_PUBLIC_STACK_HOSTED_HANDLER_URL_TEMPLATE\", \"http://localhost:9309/{projectId}/{hostedPath}\");\n\n expect(() => resolveHandlerUrls({\n projectId: \"project-id\",\n urls: {\n default: { type: \"hosted\" },\n },\n })).toThrowErrorMatchingInlineSnapshot(`\n [HexclaveAssertionError: The hosted handler URL template must put {projectId} in the hostname.\n\n This is likely an error in Hexclave. Please make sure you are running the newest version and report it.]\n `);\n });\n});\n\ndescribe(\"isLocalHandlerUrlTarget\", () => {\n it(\"treats relative handler URLs as local targets\", () => {\n expect(isLocalHandlerUrlTarget({\n targetUrl: \"/handler/sign-in\",\n handlerPath: \"/handler\",\n currentOrigin: \"http://p91.localhost:9101\",\n })).toBe(true);\n });\n\n it(\"treats same-origin absolute handler URLs as local targets\", () => {\n expect(isLocalHandlerUrlTarget({\n targetUrl: \"http://p91.localhost:9101/handler/sign-in\",\n handlerPath: \"/handler\",\n currentOrigin: \"http://p91.localhost:9101\",\n })).toBe(true);\n });\n\n it(\"treats cross-origin absolute handler URLs as non-local targets\", () => {\n expect(isLocalHandlerUrlTarget({\n targetUrl: \"https://project-id.built-with-hexclave.com/handler/sign-in\",\n handlerPath: \"/handler\",\n currentOrigin: \"http://p91.localhost:9101\",\n })).toBe(false);\n });\n\n it(\"treats non-handler paths as non-local targets\", () => {\n expect(isLocalHandlerUrlTarget({\n targetUrl: \"/projects\",\n handlerPath: \"/handler\",\n currentOrigin: \"http://p91.localhost:9101\",\n })).toBe(false);\n });\n});\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-app-impl.d.ts","names":[],"sources":["../../../../../src/lib/hexclave-app/apps/implementations/admin-app-impl.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAyEa,+BAAA,kEAAiG,gCAAA,CAAiC,aAAA,EAAe,SAAA,aAAsB,aAAA,CAAc,aAAA,EAAe,SAAA;EAAA,UAC7L,UAAA,EAAY,sBAAA;EAAA,iBAEb,kBAAA;EAAA,iBAGA,qBAAA;EAAA,iBAIA,qBAAA;EAAA,iBAGA,sBAAA;EAAA,iBAGA,yBAAA;EAAA,iBAGA,sBAAA;EAAA,iBAGA,oCAAA;EAAA,iBAGA,uCAAA;EAAA,iBAGA,eAAA;EAAA,iBAGA,aAAA;EAAA,iBAGA,kBAAA;EAAA,iBAGA,uBAAA;EAAA,iBAGA,kBAAA;EAAA,iBAGA,qCAAA;EAAA,iBAGA,qBAAA;EAAA,iBAGA,uBAAA;EAAA,iBAUA,kBAAA;cAIL,OAAA,EAAS,+BAAA,CAAgC,aAAA,EAAe,SAAA,GAAY,YAAA;IAAiB,gBAAA;IAA2B,WAAA;IAAsB,SAAA,GAAY,sBAAA;EAAA;EA2B9J,oBAAA,CAAqB,IAAA;IAAQ,aAAA;EAAA,IAA0B,cAAA;EAIvD,0BAAA,CAA2B,IAAA,EAAM,YAAA,mBAA+B,SAAA,QAAiB,OAAA,SAAgB,iBAAA;EAUjG,qBAAA,CAAsB,IAAA,EAAM,YAAA,mBAA+B,SAAA,QAAiB,OAAA,SAAgB,YAAA;EAsI5F,2BAAA,CAA4B,IAAA,EAAM,iBAAA,oBAAqC,kBAAA;EASxD,UAAA,CAAA,GAAc,OAAA,CAAQ,YAAA;EAAA,UAQ3B,iCAAA,CAAkC,IAAA,EAAM,0BAAA,GAA6B,kBAAA;EAAA,UAwBrE,6BAAA,CAA8B,IAAA,EAAM,mBAAA,oBAAuC,cAAA;EAAA,UAS3E,sCAAA,CAAuC,IAAA,EAAM,gCAAA,GAAmC,uBAAA;EASpF,mBAAA,CAAA,GAAuB,OAAA,CAAQ,cAAA;EAM/B,oBAAA,CAAqB,OAAA,EAAS,2BAAA,GAA8B,OAAA,CAAQ,uBAAA;EAOpE,eAAA,CAAA,GAAmB,OAAA;IAAU,EAAA;IAAY,WAAA;EAAA;EAQzC,kBAAA,CAAA,GAAsB,OAAA;IAAU,EAAA;IAAY,WAAA;IAAqB,OAAA;IAAkB,SAAA;EAAA;EAUnF,eAAA,CAAA,GAAmB,OAAA;IAAU,EAAA;IAAY,WAAA;IAAqB,OAAA;IAAqC,SAAA;IAAmB,MAAA,EAAQ,IAAA;EAAA;EAY9H,8BAAA,CAA+B,IAAA,EAAM,0CAAA,GAA6C,OAAA,CAAQ,mBAAA;EAM1F,8BAAA,CAA+B,YAAA,UAAsB,IAAA,EAAM,0CAAA,GAA0C,OAAA;EAKrG,8BAAA,CAA+B,YAAA,WAAuB,OAAA;EAKtD,6BAAA,CAAA,GAAiC,OAAA,CAAQ,6BAAA;EAKzC,sCAAA,CACJ,OAAA;IAAW,KAAA;IAAe,MAAA;IAAiB,KAAA;EAAA,IAC1C,OAAA;IAAU,KAAA,EAAO,6BAAA;IAAiC,UAAA;EAAA;EAS/C,iCAAA,CAAkC,IAAA,EAAM,6CAAA,GAAgD,OAAA,CAAQ,sBAAA;EAMhG,iCAAA,CAAkC,YAAA,UAAsB,IAAA,EAAM,6CAAA,GAA6C,OAAA;EAK3G,iCAAA,CAAkC,YAAA,WAAuB,OAAA;EAKzD,gCAAA,CAAA,GAAoC,OAAA,CAAQ,gCAAA;EAAA,UAMzB,eAAA,CAAA,GAAe,OAAA;EAAA,UAOxB,qBAAA,CAAA,GAAqB,OAAA;EAAA,UAOrB,uBAAA,CAAA,GAAuB,OAAA;EAAA,UAId,aAAA,CAAA,GAAa,OAAA;EAAA,KASjC,0BAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"admin-app-impl.d.ts","names":[],"sources":["../../../../../src/lib/hexclave-app/apps/implementations/admin-app-impl.ts"],"mappings":"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"}
|
|
@@ -1,8 +1,41 @@
|
|
|
1
1
|
const require_chunk = require('../../../../chunk-BE-pF4vm.js');
|
|
2
2
|
let vitest = require("vitest");
|
|
3
|
+
let _hexclave_shared_dist_sessions = require("@hexclave/shared/dist/sessions");
|
|
4
|
+
let _hexclave_shared_dist_utils_stores = require("@hexclave/shared/dist/utils/stores");
|
|
3
5
|
let ___interfaces_client_app_js = require("../interfaces/client-app.js");
|
|
4
6
|
|
|
5
7
|
//#region src/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.ts
|
|
8
|
+
function createAccessTokenString(refreshTokenId) {
|
|
9
|
+
const encode = (value) => Buffer.from(JSON.stringify(value)).toString("base64url");
|
|
10
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
11
|
+
return [
|
|
12
|
+
encode({
|
|
13
|
+
alg: "none",
|
|
14
|
+
typ: "JWT"
|
|
15
|
+
}),
|
|
16
|
+
encode({
|
|
17
|
+
sub: "user-id",
|
|
18
|
+
exp: nowSeconds + 60,
|
|
19
|
+
iat: nowSeconds,
|
|
20
|
+
iss: "https://api.example.test",
|
|
21
|
+
aud: "project-id",
|
|
22
|
+
project_id: "project-id",
|
|
23
|
+
branch_id: "main",
|
|
24
|
+
refresh_token_id: refreshTokenId,
|
|
25
|
+
role: "authenticated",
|
|
26
|
+
name: null,
|
|
27
|
+
email: null,
|
|
28
|
+
email_verified: false,
|
|
29
|
+
selected_team_id: null,
|
|
30
|
+
signed_up_at: nowSeconds,
|
|
31
|
+
is_anonymous: false,
|
|
32
|
+
is_restricted: false,
|
|
33
|
+
restricted_reason: null,
|
|
34
|
+
requires_totp_mfa: false
|
|
35
|
+
}),
|
|
36
|
+
""
|
|
37
|
+
].join(".");
|
|
38
|
+
}
|
|
6
39
|
function createMockDocument() {
|
|
7
40
|
const cookieJar = /* @__PURE__ */ new Map();
|
|
8
41
|
return {
|
|
@@ -115,6 +148,156 @@ function createMockDocument() {
|
|
|
115
148
|
(0, vitest.expect)(redirectUri.searchParams.get("hexclave_cross_domain_code_challenge")).toBe(outerCodeChallenge);
|
|
116
149
|
(0, vitest.expect)(redirectUri.searchParams.get("hexclave_cross_domain_after_callback_redirect_url")).toBe("https://demo.stack-auth.com/");
|
|
117
150
|
});
|
|
151
|
+
(0, vitest.it)("clears a stale target-domain session before deferring to the source-domain session", async () => {
|
|
152
|
+
const projectId = "00000000-0000-4000-8000-000000000006";
|
|
153
|
+
const hostedAccessToken = createAccessTokenString("hosted-old-refresh-token-id");
|
|
154
|
+
const clientApp = new ___interfaces_client_app_js.StackClientApp({
|
|
155
|
+
baseUrl: "http://localhost:12345",
|
|
156
|
+
projectId,
|
|
157
|
+
publishableClientKey: "stack-pk-test",
|
|
158
|
+
tokenStore: "memory",
|
|
159
|
+
redirectMethod: "window",
|
|
160
|
+
urls: { default: { type: "hosted" } },
|
|
161
|
+
noAutomaticPrefetch: true
|
|
162
|
+
});
|
|
163
|
+
const tokenStore = Reflect.get(clientApp, "_memoryTokenStore");
|
|
164
|
+
if (!(tokenStore instanceof _hexclave_shared_dist_utils_stores.Store)) throw new Error("Expected StackClientApp to use a memory token store in this test.");
|
|
165
|
+
tokenStore.set({
|
|
166
|
+
refreshToken: "hosted-old-refresh-token",
|
|
167
|
+
accessToken: hostedAccessToken
|
|
168
|
+
});
|
|
169
|
+
const currentUrl = new URL(`https://${projectId}.example-stack-hosted.test/handler/sign-in`);
|
|
170
|
+
currentUrl.searchParams.set("stack_nested_cross_domain_auth_refresh_token_id", "source-anonymous-refresh-token-id");
|
|
171
|
+
currentUrl.searchParams.set("stack_nested_cross_domain_auth_callback_url", "https://demo.stack-auth.com/handler/oauth-callback");
|
|
172
|
+
currentUrl.searchParams.set("hexclave_cross_domain_state", "outer-state");
|
|
173
|
+
currentUrl.searchParams.set("hexclave_cross_domain_code_challenge", "outer-code-challenge");
|
|
174
|
+
currentUrl.searchParams.set("hexclave_cross_domain_after_callback_redirect_url", "https://demo.stack-auth.com/app");
|
|
175
|
+
const previousWindow = globalThis.window;
|
|
176
|
+
const previousDocument = globalThis.document;
|
|
177
|
+
let redirectedUrl = "";
|
|
178
|
+
vitest.vi.spyOn(clientApp, "_isTrusted").mockResolvedValue(true);
|
|
179
|
+
globalThis.document = createMockDocument();
|
|
180
|
+
globalThis.window = { location: {
|
|
181
|
+
href: currentUrl.toString(),
|
|
182
|
+
replace: (url) => {
|
|
183
|
+
redirectedUrl = url;
|
|
184
|
+
throw new Error("INTENTIONAL_TEST_ABORT");
|
|
185
|
+
}
|
|
186
|
+
} };
|
|
187
|
+
try {
|
|
188
|
+
await (0, vitest.expect)(clientApp._maybeHandleNestedCrossDomainAuth()).rejects.toThrowError("INTENTIONAL_TEST_ABORT");
|
|
189
|
+
} finally {
|
|
190
|
+
globalThis.window = previousWindow;
|
|
191
|
+
globalThis.document = previousDocument;
|
|
192
|
+
}
|
|
193
|
+
(0, vitest.expect)(tokenStore.get()).toEqual({
|
|
194
|
+
refreshToken: null,
|
|
195
|
+
accessToken: null
|
|
196
|
+
});
|
|
197
|
+
(0, vitest.expect)(new URL(redirectedUrl).origin).toBe("https://demo.stack-auth.com");
|
|
198
|
+
});
|
|
199
|
+
(0, vitest.it)("uses direct sign-out instead of hosted sign-out redirects when code execution is available", async () => {
|
|
200
|
+
const clientApp = new ___interfaces_client_app_js.StackClientApp({
|
|
201
|
+
baseUrl: "http://localhost:12345",
|
|
202
|
+
projectId: "00000000-0000-4000-8000-000000000003",
|
|
203
|
+
publishableClientKey: "stack-pk-test",
|
|
204
|
+
tokenStore: "memory",
|
|
205
|
+
redirectMethod: "window",
|
|
206
|
+
urls: {
|
|
207
|
+
handler: "/handler",
|
|
208
|
+
signOut: { type: "hosted" }
|
|
209
|
+
},
|
|
210
|
+
noAutomaticPrefetch: true
|
|
211
|
+
});
|
|
212
|
+
const signOutSpy = vitest.vi.spyOn(clientApp, "signOut").mockRejectedValue(/* @__PURE__ */ new Error("INTENTIONAL_TEST_ABORT"));
|
|
213
|
+
try {
|
|
214
|
+
await (0, vitest.expect)(clientApp.redirectToSignOut()).rejects.toThrowError("INTENTIONAL_TEST_ABORT");
|
|
215
|
+
(0, vitest.expect)(signOutSpy).toHaveBeenCalledWith();
|
|
216
|
+
} finally {
|
|
217
|
+
signOutSpy.mockRestore();
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
(0, vitest.it)("keeps default hosted signOut() on the source domain when afterSignOut is not configured", async () => {
|
|
221
|
+
const clientApp = new ___interfaces_client_app_js.StackClientApp({
|
|
222
|
+
baseUrl: "http://localhost:12345",
|
|
223
|
+
projectId: "00000000-0000-4000-8000-000000000004",
|
|
224
|
+
publishableClientKey: "stack-pk-test",
|
|
225
|
+
tokenStore: "memory",
|
|
226
|
+
redirectMethod: "window",
|
|
227
|
+
urls: { default: { type: "hosted" } },
|
|
228
|
+
noAutomaticPrefetch: true
|
|
229
|
+
});
|
|
230
|
+
const currentHref = "https://demo.stack-auth.com/settings?tab=profile";
|
|
231
|
+
const clientInterface = Reflect.get(clientApp, "_interface");
|
|
232
|
+
const originalSignOut = Reflect.get(clientInterface, "signOut");
|
|
233
|
+
Reflect.set(clientInterface, "signOut", async () => {});
|
|
234
|
+
const previousWindow = globalThis.window;
|
|
235
|
+
const previousDocument = globalThis.document;
|
|
236
|
+
let redirectedUrl = "";
|
|
237
|
+
globalThis.document = createMockDocument();
|
|
238
|
+
globalThis.window = { location: {
|
|
239
|
+
href: currentHref,
|
|
240
|
+
replace: (url) => {
|
|
241
|
+
redirectedUrl = url;
|
|
242
|
+
throw new Error("INTENTIONAL_TEST_ABORT");
|
|
243
|
+
}
|
|
244
|
+
} };
|
|
245
|
+
try {
|
|
246
|
+
const signOut = Reflect.get(clientApp, "_signOut");
|
|
247
|
+
if (typeof signOut !== "function") throw new Error("Expected StackClientApp to expose _signOut in tests.");
|
|
248
|
+
await (0, vitest.expect)(signOut.call(clientApp, {})).rejects.toThrowError("INTENTIONAL_TEST_ABORT");
|
|
249
|
+
} finally {
|
|
250
|
+
Reflect.set(clientInterface, "signOut", originalSignOut);
|
|
251
|
+
globalThis.window = previousWindow;
|
|
252
|
+
globalThis.document = previousDocument;
|
|
253
|
+
}
|
|
254
|
+
(0, vitest.expect)(redirectedUrl).toBe("/settings?tab=profile");
|
|
255
|
+
});
|
|
256
|
+
(0, vitest.it)("ignores stale session callbacks after a newer refresh token owns the token store", async () => {
|
|
257
|
+
const clientApp = new ___interfaces_client_app_js.StackClientApp({
|
|
258
|
+
baseUrl: "http://localhost:12345",
|
|
259
|
+
projectId: "00000000-0000-4000-8000-000000000005",
|
|
260
|
+
publishableClientKey: "stack-pk-test",
|
|
261
|
+
tokenStore: "memory",
|
|
262
|
+
redirectMethod: "none",
|
|
263
|
+
noAutomaticPrefetch: true
|
|
264
|
+
});
|
|
265
|
+
const oldAccessToken = createAccessTokenString("old-refresh-token-id");
|
|
266
|
+
const refreshedOldAccessToken = createAccessTokenString("refreshed-old-refresh-token-id");
|
|
267
|
+
const newAccessToken = createAccessTokenString("new-refresh-token-id");
|
|
268
|
+
const tokenStore = new _hexclave_shared_dist_utils_stores.Store({
|
|
269
|
+
refreshToken: "old-refresh-token",
|
|
270
|
+
accessToken: oldAccessToken
|
|
271
|
+
});
|
|
272
|
+
const clientInterface = Reflect.get(clientApp, "_interface");
|
|
273
|
+
const originalFetchNewAccessToken = Reflect.get(clientInterface, "fetchNewAccessToken");
|
|
274
|
+
Reflect.set(clientInterface, "fetchNewAccessToken", async () => {
|
|
275
|
+
return _hexclave_shared_dist_sessions.AccessToken.createIfValid(refreshedOldAccessToken) ?? (() => {
|
|
276
|
+
throw new Error("Expected test access token to be valid");
|
|
277
|
+
})();
|
|
278
|
+
});
|
|
279
|
+
try {
|
|
280
|
+
const getSessionFromTokenStore = Reflect.get(clientApp, "_getSessionFromTokenStore");
|
|
281
|
+
if (typeof getSessionFromTokenStore !== "function") throw new Error("Expected StackClientApp to expose _getSessionFromTokenStore in tests.");
|
|
282
|
+
const oldSession = getSessionFromTokenStore.call(clientApp, tokenStore);
|
|
283
|
+
tokenStore.set({
|
|
284
|
+
refreshToken: "new-refresh-token",
|
|
285
|
+
accessToken: newAccessToken
|
|
286
|
+
});
|
|
287
|
+
await oldSession.fetchNewTokens();
|
|
288
|
+
(0, vitest.expect)(tokenStore.get()).toEqual({
|
|
289
|
+
refreshToken: "new-refresh-token",
|
|
290
|
+
accessToken: newAccessToken
|
|
291
|
+
});
|
|
292
|
+
oldSession.markInvalid();
|
|
293
|
+
(0, vitest.expect)(tokenStore.get()).toEqual({
|
|
294
|
+
refreshToken: "new-refresh-token",
|
|
295
|
+
accessToken: newAccessToken
|
|
296
|
+
});
|
|
297
|
+
} finally {
|
|
298
|
+
Reflect.set(clientInterface, "fetchNewAccessToken", originalFetchNewAccessToken);
|
|
299
|
+
}
|
|
300
|
+
});
|
|
118
301
|
});
|
|
119
302
|
|
|
120
303
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-app-impl.cross-domain.test.js","names":["StackClientApp"],"sources":["../../../../../src/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { describe, expect, it, vi } from \"vitest\";\nimport { StackClientApp } from \"../interfaces/client-app\";\n\nfunction createMockDocument(): Document {\n const cookieJar = new Map<string, string>();\n return {\n get cookie() {\n return [...cookieJar.entries()].map(([key, value]) => `${key}=${value}`).join(\"; \");\n },\n set cookie(str: string) {\n const [nameValue] = str.split(\";\");\n const eqIndex = nameValue.indexOf(\"=\");\n if (eqIndex < 0) return;\n cookieJar.set(nameValue.slice(0, eqIndex).trim(), nameValue.slice(eqIndex + 1).trim());\n },\n createElement: () => ({}),\n } as any;\n}\n\ndescribe(\"StackClientApp cross-domain auth\", () => {\n it(\"uses the fresh post-auth refresh token when minting a cross-domain handoff\", async () => {\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000000\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: {\n accessToken: \"stale-access-token\",\n refreshToken: \"stale-refresh-token\",\n },\n redirectMethod: \"none\",\n noAutomaticPrefetch: true,\n });\n\n const clientInterface = Reflect.get(clientApp, \"_interface\");\n const originalSendClientRequest = Reflect.get(clientInterface, \"sendClientRequest\");\n const capturedRefreshTokens: string[] = [];\n\n Reflect.set(clientInterface, \"sendClientRequest\", async (_path: unknown, _requestOptions: unknown, session: unknown) => {\n const getRefreshToken = Reflect.get(session ?? {}, \"getRefreshToken\");\n if (typeof getRefreshToken !== \"function\") {\n throw new Error(\"Expected cross-domain auth to pass a session to the client interface.\");\n }\n const refreshToken = getRefreshToken.call(session);\n const refreshTokenString = Reflect.get(refreshToken ?? {}, \"token\");\n if (typeof refreshTokenString !== \"string\") {\n throw new Error(\"Expected cross-domain auth to pass a refresh-token-backed session.\");\n }\n capturedRefreshTokens.push(refreshTokenString);\n return {\n ok: true,\n json: async () => ({ redirect_url: \"https://example.com/handler/oauth-callback?code=handoff-code&state=handoff-state\" }),\n };\n });\n\n try {\n const createCrossDomainAuthRedirectUrl = Reflect.get(clientApp, \"_createCrossDomainAuthRedirectUrl\");\n if (typeof createCrossDomainAuthRedirectUrl !== \"function\") {\n throw new Error(\"Expected StackClientApp to expose _createCrossDomainAuthRedirectUrl in tests.\");\n }\n\n await expect(createCrossDomainAuthRedirectUrl.call(clientApp, {\n redirectUri: \"https://example.com/handler/oauth-callback\",\n state: \"handoff-state\",\n codeChallenge: \"abcdefghijklmnopqrstuvwxyzABCDEFG_0123456789-._~\",\n afterCallbackRedirectUrl: \"https://example.com/account-settings\",\n overrideTokenStoreInit: {\n accessToken: \"fresh-access-token\",\n refreshToken: \"fresh-refresh-token\",\n },\n })).resolves.toBe(\"https://example.com/handler/oauth-callback?code=handoff-code&state=handoff-state\");\n } finally {\n Reflect.set(clientInterface, \"sendClientRequest\", originalSendClientRequest);\n }\n\n expect(capturedRefreshTokens).toEqual([\"fresh-refresh-token\"]);\n });\n\n it(\"uses a fresh nested OAuth state while preserving the outer cross-domain return state\", async () => {\n const projectId = \"00000000-0000-4000-8000-000000000002\";\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId,\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n urls: {\n default: { type: \"hosted\" },\n },\n noAutomaticPrefetch: true,\n });\n const outerState = \"outer-cross-domain-state\";\n const outerCodeChallenge = \"abcdefghijklmnopqrstuvwxyzABCDEFG_0123456789-._~\";\n const currentUrl = new URL(`https://${projectId}.example-stack-hosted.test/handler/sign-in`);\n currentUrl.searchParams.set(\"after_auth_return_to\", `https://demo.stack-auth.com/?hexclave_cross_domain_auth=1&hexclave_cross_domain_state=${outerState}`);\n currentUrl.searchParams.set(\"hexclave_cross_domain_state\", outerState);\n currentUrl.searchParams.set(\"hexclave_cross_domain_code_challenge\", outerCodeChallenge);\n currentUrl.searchParams.set(\"hexclave_cross_domain_after_callback_redirect_url\", \"https://demo.stack-auth.com/\");\n currentUrl.searchParams.set(\"stack_nested_cross_domain_auth_refresh_token_id\", \"source-session\");\n currentUrl.searchParams.set(\"stack_nested_cross_domain_auth_callback_url\", \"https://demo.stack-auth.com/\");\n\n const previousWindow = globalThis.window;\n const previousDocument = globalThis.document;\n let redirectedUrl = \"\";\n vi.spyOn(clientApp as any, \"_getCurrentRefreshTokenIdIfSignedIn\").mockResolvedValue(null);\n vi.spyOn(clientApp as any, \"_getCrossDomainHandoffParamsForRedirect\").mockResolvedValue({\n state: \"fresh-nested-state\",\n codeChallenge: \"fresh-nested-code-challenge\",\n });\n vi.spyOn(clientApp as any, \"_isTrusted\").mockResolvedValue(true);\n\n globalThis.document = createMockDocument();\n globalThis.window = {\n location: {\n href: currentUrl.toString(),\n replace: (url: string) => {\n redirectedUrl = url;\n throw new Error(\"INTENTIONAL_TEST_ABORT\");\n },\n },\n } as any;\n\n try {\n await expect((clientApp as any)._maybeHandleNestedCrossDomainAuth()).rejects.toThrowError(\"INTENTIONAL_TEST_ABORT\");\n } finally {\n globalThis.window = previousWindow;\n globalThis.document = previousDocument;\n }\n\n const redirectUrl = new URL(redirectedUrl);\n expect(redirectUrl.searchParams.get(\"state\")).toBe(\"fresh-nested-state\");\n expect(redirectUrl.searchParams.get(\"code_challenge\")).toBe(\"fresh-nested-code-challenge\");\n const redirectUri = new URL(redirectUrl.searchParams.get(\"redirect_uri\") ?? \"\");\n expect(redirectUri.searchParams.get(\"hexclave_cross_domain_state\")).toBe(outerState);\n expect(redirectUri.searchParams.get(\"hexclave_cross_domain_code_challenge\")).toBe(outerCodeChallenge);\n expect(redirectUri.searchParams.get(\"hexclave_cross_domain_after_callback_redirect_url\")).toBe(\"https://demo.stack-auth.com/\");\n });\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client-app-impl.cross-domain.test.js","names":["StackClientApp","Store","vi","AccessToken"],"sources":["../../../../../src/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { describe, expect, it, vi } from \"vitest\";\nimport { AccessToken } from \"@hexclave/shared/dist/sessions\";\nimport { Store } from \"@hexclave/shared/dist/utils/stores\";\nimport { StackClientApp } from \"../interfaces/client-app\";\n\nfunction createAccessTokenString(refreshTokenId: string): string {\n const encode = (value: unknown) => Buffer.from(JSON.stringify(value)).toString(\"base64url\");\n const nowSeconds = Math.floor(Date.now() / 1000);\n return [\n encode({ alg: \"none\", typ: \"JWT\" }),\n encode({\n sub: \"user-id\",\n exp: nowSeconds + 60,\n iat: nowSeconds,\n iss: \"https://api.example.test\",\n aud: \"project-id\",\n project_id: \"project-id\",\n branch_id: \"main\",\n refresh_token_id: refreshTokenId,\n role: \"authenticated\",\n name: null,\n email: null,\n email_verified: false,\n selected_team_id: null,\n signed_up_at: nowSeconds,\n is_anonymous: false,\n is_restricted: false,\n restricted_reason: null,\n requires_totp_mfa: false,\n }),\n \"\",\n ].join(\".\");\n}\n\nfunction createMockDocument(): Document {\n const cookieJar = new Map<string, string>();\n return {\n get cookie() {\n return [...cookieJar.entries()].map(([key, value]) => `${key}=${value}`).join(\"; \");\n },\n set cookie(str: string) {\n const [nameValue] = str.split(\";\");\n const eqIndex = nameValue.indexOf(\"=\");\n if (eqIndex < 0) return;\n cookieJar.set(nameValue.slice(0, eqIndex).trim(), nameValue.slice(eqIndex + 1).trim());\n },\n createElement: () => ({}),\n } as any;\n}\n\ndescribe(\"StackClientApp cross-domain auth\", () => {\n it(\"uses the fresh post-auth refresh token when minting a cross-domain handoff\", async () => {\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000000\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: {\n accessToken: \"stale-access-token\",\n refreshToken: \"stale-refresh-token\",\n },\n redirectMethod: \"none\",\n noAutomaticPrefetch: true,\n });\n\n const clientInterface = Reflect.get(clientApp, \"_interface\");\n const originalSendClientRequest = Reflect.get(clientInterface, \"sendClientRequest\");\n const capturedRefreshTokens: string[] = [];\n\n Reflect.set(clientInterface, \"sendClientRequest\", async (_path: unknown, _requestOptions: unknown, session: unknown) => {\n const getRefreshToken = Reflect.get(session ?? {}, \"getRefreshToken\");\n if (typeof getRefreshToken !== \"function\") {\n throw new Error(\"Expected cross-domain auth to pass a session to the client interface.\");\n }\n const refreshToken = getRefreshToken.call(session);\n const refreshTokenString = Reflect.get(refreshToken ?? {}, \"token\");\n if (typeof refreshTokenString !== \"string\") {\n throw new Error(\"Expected cross-domain auth to pass a refresh-token-backed session.\");\n }\n capturedRefreshTokens.push(refreshTokenString);\n return {\n ok: true,\n json: async () => ({ redirect_url: \"https://example.com/handler/oauth-callback?code=handoff-code&state=handoff-state\" }),\n };\n });\n\n try {\n const createCrossDomainAuthRedirectUrl = Reflect.get(clientApp, \"_createCrossDomainAuthRedirectUrl\");\n if (typeof createCrossDomainAuthRedirectUrl !== \"function\") {\n throw new Error(\"Expected StackClientApp to expose _createCrossDomainAuthRedirectUrl in tests.\");\n }\n\n await expect(createCrossDomainAuthRedirectUrl.call(clientApp, {\n redirectUri: \"https://example.com/handler/oauth-callback\",\n state: \"handoff-state\",\n codeChallenge: \"abcdefghijklmnopqrstuvwxyzABCDEFG_0123456789-._~\",\n afterCallbackRedirectUrl: \"https://example.com/account-settings\",\n overrideTokenStoreInit: {\n accessToken: \"fresh-access-token\",\n refreshToken: \"fresh-refresh-token\",\n },\n })).resolves.toBe(\"https://example.com/handler/oauth-callback?code=handoff-code&state=handoff-state\");\n } finally {\n Reflect.set(clientInterface, \"sendClientRequest\", originalSendClientRequest);\n }\n\n expect(capturedRefreshTokens).toEqual([\"fresh-refresh-token\"]);\n });\n\n it(\"uses a fresh nested OAuth state while preserving the outer cross-domain return state\", async () => {\n const projectId = \"00000000-0000-4000-8000-000000000002\";\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId,\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n urls: {\n default: { type: \"hosted\" },\n },\n noAutomaticPrefetch: true,\n });\n const outerState = \"outer-cross-domain-state\";\n const outerCodeChallenge = \"abcdefghijklmnopqrstuvwxyzABCDEFG_0123456789-._~\";\n const currentUrl = new URL(`https://${projectId}.example-stack-hosted.test/handler/sign-in`);\n currentUrl.searchParams.set(\"after_auth_return_to\", `https://demo.stack-auth.com/?hexclave_cross_domain_auth=1&hexclave_cross_domain_state=${outerState}`);\n currentUrl.searchParams.set(\"hexclave_cross_domain_state\", outerState);\n currentUrl.searchParams.set(\"hexclave_cross_domain_code_challenge\", outerCodeChallenge);\n currentUrl.searchParams.set(\"hexclave_cross_domain_after_callback_redirect_url\", \"https://demo.stack-auth.com/\");\n currentUrl.searchParams.set(\"stack_nested_cross_domain_auth_refresh_token_id\", \"source-session\");\n currentUrl.searchParams.set(\"stack_nested_cross_domain_auth_callback_url\", \"https://demo.stack-auth.com/\");\n\n const previousWindow = globalThis.window;\n const previousDocument = globalThis.document;\n let redirectedUrl = \"\";\n vi.spyOn(clientApp as any, \"_getCurrentRefreshTokenIdIfSignedIn\").mockResolvedValue(null);\n vi.spyOn(clientApp as any, \"_getCrossDomainHandoffParamsForRedirect\").mockResolvedValue({\n state: \"fresh-nested-state\",\n codeChallenge: \"fresh-nested-code-challenge\",\n });\n vi.spyOn(clientApp as any, \"_isTrusted\").mockResolvedValue(true);\n\n globalThis.document = createMockDocument();\n globalThis.window = {\n location: {\n href: currentUrl.toString(),\n replace: (url: string) => {\n redirectedUrl = url;\n throw new Error(\"INTENTIONAL_TEST_ABORT\");\n },\n },\n } as any;\n\n try {\n await expect((clientApp as any)._maybeHandleNestedCrossDomainAuth()).rejects.toThrowError(\"INTENTIONAL_TEST_ABORT\");\n } finally {\n globalThis.window = previousWindow;\n globalThis.document = previousDocument;\n }\n\n const redirectUrl = new URL(redirectedUrl);\n expect(redirectUrl.searchParams.get(\"state\")).toBe(\"fresh-nested-state\");\n expect(redirectUrl.searchParams.get(\"code_challenge\")).toBe(\"fresh-nested-code-challenge\");\n const redirectUri = new URL(redirectUrl.searchParams.get(\"redirect_uri\") ?? \"\");\n expect(redirectUri.searchParams.get(\"hexclave_cross_domain_state\")).toBe(outerState);\n expect(redirectUri.searchParams.get(\"hexclave_cross_domain_code_challenge\")).toBe(outerCodeChallenge);\n expect(redirectUri.searchParams.get(\"hexclave_cross_domain_after_callback_redirect_url\")).toBe(\"https://demo.stack-auth.com/\");\n });\n\n it(\"clears a stale target-domain session before deferring to the source-domain session\", async () => {\n const projectId = \"00000000-0000-4000-8000-000000000006\";\n const hostedAccessToken = createAccessTokenString(\"hosted-old-refresh-token-id\");\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId,\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n urls: {\n default: { type: \"hosted\" },\n },\n noAutomaticPrefetch: true,\n });\n const tokenStore = Reflect.get(clientApp, \"_memoryTokenStore\");\n if (!(tokenStore instanceof Store)) {\n throw new Error(\"Expected StackClientApp to use a memory token store in this test.\");\n }\n tokenStore.set({\n refreshToken: \"hosted-old-refresh-token\",\n accessToken: hostedAccessToken,\n });\n\n const currentUrl = new URL(`https://${projectId}.example-stack-hosted.test/handler/sign-in`);\n currentUrl.searchParams.set(\"stack_nested_cross_domain_auth_refresh_token_id\", \"source-anonymous-refresh-token-id\");\n currentUrl.searchParams.set(\"stack_nested_cross_domain_auth_callback_url\", \"https://demo.stack-auth.com/handler/oauth-callback\");\n currentUrl.searchParams.set(\"hexclave_cross_domain_state\", \"outer-state\");\n currentUrl.searchParams.set(\"hexclave_cross_domain_code_challenge\", \"outer-code-challenge\");\n currentUrl.searchParams.set(\"hexclave_cross_domain_after_callback_redirect_url\", \"https://demo.stack-auth.com/app\");\n\n const previousWindow = globalThis.window;\n const previousDocument = globalThis.document;\n let redirectedUrl = \"\";\n vi.spyOn(clientApp as any, \"_isTrusted\").mockResolvedValue(true);\n\n globalThis.document = createMockDocument();\n globalThis.window = {\n location: {\n href: currentUrl.toString(),\n replace: (url: string) => {\n redirectedUrl = url;\n throw new Error(\"INTENTIONAL_TEST_ABORT\");\n },\n },\n } as any;\n\n try {\n await expect((clientApp as any)._maybeHandleNestedCrossDomainAuth()).rejects.toThrowError(\"INTENTIONAL_TEST_ABORT\");\n } finally {\n globalThis.window = previousWindow;\n globalThis.document = previousDocument;\n }\n\n expect(tokenStore.get()).toEqual({\n refreshToken: null,\n accessToken: null,\n });\n expect(new URL(redirectedUrl).origin).toBe(\"https://demo.stack-auth.com\");\n });\n\n it(\"uses direct sign-out instead of hosted sign-out redirects when code execution is available\", async () => {\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000003\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n urls: {\n handler: \"/handler\",\n signOut: { type: \"hosted\" },\n },\n noAutomaticPrefetch: true,\n });\n const signOutSpy = vi.spyOn(clientApp, \"signOut\").mockRejectedValue(new Error(\"INTENTIONAL_TEST_ABORT\"));\n\n try {\n await expect(clientApp.redirectToSignOut()).rejects.toThrowError(\"INTENTIONAL_TEST_ABORT\");\n expect(signOutSpy).toHaveBeenCalledWith();\n } finally {\n signOutSpy.mockRestore();\n }\n });\n\n it(\"keeps default hosted signOut() on the source domain when afterSignOut is not configured\", async () => {\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000004\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"window\",\n urls: {\n default: { type: \"hosted\" },\n },\n noAutomaticPrefetch: true,\n });\n const currentHref = \"https://demo.stack-auth.com/settings?tab=profile\";\n\n const clientInterface = Reflect.get(clientApp, \"_interface\");\n const originalSignOut = Reflect.get(clientInterface, \"signOut\");\n Reflect.set(clientInterface, \"signOut\", async () => {});\n const previousWindow = globalThis.window;\n const previousDocument = globalThis.document;\n let redirectedUrl = \"\";\n\n globalThis.document = createMockDocument();\n globalThis.window = {\n location: {\n href: currentHref,\n replace: (url: string) => {\n redirectedUrl = url;\n throw new Error(\"INTENTIONAL_TEST_ABORT\");\n },\n },\n } as any;\n\n try {\n const signOut = Reflect.get(clientApp, \"_signOut\");\n if (typeof signOut !== \"function\") {\n throw new Error(\"Expected StackClientApp to expose _signOut in tests.\");\n }\n await expect(signOut.call(clientApp, {})).rejects.toThrowError(\"INTENTIONAL_TEST_ABORT\");\n } finally {\n Reflect.set(clientInterface, \"signOut\", originalSignOut);\n globalThis.window = previousWindow;\n globalThis.document = previousDocument;\n }\n\n expect(redirectedUrl).toBe(\"/settings?tab=profile\");\n });\n\n it(\"ignores stale session callbacks after a newer refresh token owns the token store\", async () => {\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000005\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"none\",\n noAutomaticPrefetch: true,\n });\n const oldAccessToken = createAccessTokenString(\"old-refresh-token-id\");\n const refreshedOldAccessToken = createAccessTokenString(\"refreshed-old-refresh-token-id\");\n const newAccessToken = createAccessTokenString(\"new-refresh-token-id\");\n const tokenStore = new Store({\n refreshToken: \"old-refresh-token\",\n accessToken: oldAccessToken,\n });\n const clientInterface = Reflect.get(clientApp, \"_interface\");\n const originalFetchNewAccessToken = Reflect.get(clientInterface, \"fetchNewAccessToken\");\n Reflect.set(clientInterface, \"fetchNewAccessToken\", async () => {\n return AccessToken.createIfValid(refreshedOldAccessToken) ?? (() => {\n throw new Error(\"Expected test access token to be valid\");\n })();\n });\n\n try {\n const getSessionFromTokenStore = Reflect.get(clientApp, \"_getSessionFromTokenStore\");\n if (typeof getSessionFromTokenStore !== \"function\") {\n throw new Error(\"Expected StackClientApp to expose _getSessionFromTokenStore in tests.\");\n }\n const oldSession = getSessionFromTokenStore.call(clientApp, tokenStore);\n tokenStore.set({\n refreshToken: \"new-refresh-token\",\n accessToken: newAccessToken,\n });\n\n await oldSession.fetchNewTokens();\n expect(tokenStore.get()).toEqual({\n refreshToken: \"new-refresh-token\",\n accessToken: newAccessToken,\n });\n\n oldSession.markInvalid();\n expect(tokenStore.get()).toEqual({\n refreshToken: \"new-refresh-token\",\n accessToken: newAccessToken,\n });\n } finally {\n Reflect.set(clientInterface, \"fetchNewAccessToken\", originalFetchNewAccessToken);\n }\n });\n});\n"],"mappings":"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"}
|
|
@@ -446,6 +446,7 @@ declare class _HexclaveClientAppImplIncomplete<HasTokenStore extends boolean, Pr
|
|
|
446
446
|
protected _signOut(session: InternalSession, options?: {
|
|
447
447
|
redirectUrl?: URL | string;
|
|
448
448
|
}): Promise<void>;
|
|
449
|
+
protected _redirectToDefaultAfterSignOut(): Promise<void>;
|
|
449
450
|
signOut(options?: {
|
|
450
451
|
redirectUrl?: URL | string;
|
|
451
452
|
tokenStore?: TokenStoreInit;
|