@hexclave/next 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/components-page/account-settings/payments/payments-panel.js +3 -3
- package/dist/components-page/account-settings/payments/payments-panel.js.map +1 -1
- package/dist/components-page/hexclave-handler-client.d.ts +13 -1
- package/dist/components-page/hexclave-handler-client.d.ts.map +1 -1
- package/dist/components-page/hexclave-handler-client.js +44 -9
- package/dist/components-page/hexclave-handler-client.js.map +1 -1
- package/dist/components-page/hexclave-handler-client.test.d.ts +1 -0
- package/dist/components-page/hexclave-handler-client.test.js +51 -0
- package/dist/components-page/hexclave-handler-client.test.js.map +1 -0
- package/dist/dev-tool/dev-tool-core.js +2 -2
- package/dist/dev-tool/dev-tool-core.js.map +1 -1
- package/dist/esm/components-page/account-settings/payments/payments-panel.js +2 -2
- package/dist/esm/components-page/account-settings/payments/payments-panel.js.map +1 -1
- package/dist/esm/components-page/hexclave-handler-client.d.ts +12 -1
- package/dist/esm/components-page/hexclave-handler-client.d.ts.map +1 -1
- package/dist/esm/components-page/hexclave-handler-client.js +46 -12
- package/dist/esm/components-page/hexclave-handler-client.js.map +1 -1
- package/dist/esm/components-page/hexclave-handler-client.test.d.ts +1 -0
- package/dist/esm/components-page/hexclave-handler-client.test.js +51 -0
- package/dist/esm/components-page/hexclave-handler-client.test.js.map +1 -0
- package/dist/esm/dev-tool/dev-tool-core.js +2 -2
- package/dist/esm/dev-tool/dev-tool-core.js.map +1 -1
- package/dist/esm/generated/env.d.ts +26 -0
- package/dist/esm/{lib → generated}/env.d.ts.map +1 -1
- package/dist/esm/generated/env.js +67 -0
- package/dist/esm/generated/env.js.map +1 -0
- package/dist/esm/generated/quetzal-translations.d.ts +2 -2
- package/dist/esm/global.d.ts +8 -1
- package/dist/esm/global.d.ts.map +1 -0
- 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 +263 -3
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +3 -1
- 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 +53 -26
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/common.d.ts +8 -8
- package/dist/esm/lib/hexclave-app/apps/implementations/common.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/common.js +28 -14
- package/dist/esm/lib/hexclave-app/apps/implementations/common.js.map +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 +25 -11
- 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/generated/env.d.ts +26 -0
- package/dist/{lib → generated}/env.d.ts.map +1 -1
- package/dist/generated/env.js +69 -0
- package/dist/generated/env.js.map +1 -0
- package/dist/generated/quetzal-translations.d.ts +2 -2
- package/dist/global.d.ts +8 -1
- package/dist/global.d.ts.map +1 -0
- 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 +263 -3
- 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 +3 -1
- 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 +52 -25
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/common.d.ts +8 -8
- package/dist/lib/hexclave-app/apps/implementations/common.d.ts.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/common.js +28 -14
- package/dist/lib/hexclave-app/apps/implementations/common.js.map +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 +25 -11
- 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 +9 -7
- package/src/components-page/account-settings/payments/payments-panel.tsx +2 -2
- package/src/components-page/hexclave-handler-client.test.tsx +64 -0
- package/src/components-page/hexclave-handler-client.tsx +50 -11
- package/src/dev-tool/dev-tool-core.ts +2 -2
- package/src/generated/.gitignore +1 -1
- package/src/global.d.ts +8 -1
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.ts +316 -3
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.ts +69 -25
- package/src/lib/hexclave-app/apps/implementations/common.ts +34 -14
- package/src/lib/hexclave-app/url-targets.test.ts +17 -0
- package/src/lib/hexclave-app/url-targets.ts +25 -7
- package/dist/esm/lib/env.d.ts +0 -42
- package/dist/esm/lib/env.js +0 -93
- package/dist/esm/lib/env.js.map +0 -1
- package/dist/lib/env.d.ts +0 -42
- package/dist/lib/env.js +0 -95
- package/dist/lib/env.js.map +0 -1
- package/src/lib/env.ts +0 -93
|
@@ -21,10 +21,10 @@ declare function resolveConstructorOptions<T extends {
|
|
|
21
21
|
declare function getUrls(partial: HandlerUrlOptions, options: {
|
|
22
22
|
projectId: string;
|
|
23
23
|
}): ResolvedHandlerUrls;
|
|
24
|
-
declare function getDefaultProjectId():
|
|
25
|
-
declare function getDefaultPublishableClientKey():
|
|
26
|
-
declare function getDefaultSecretServerKey():
|
|
27
|
-
declare function getDefaultSuperSecretAdminKey():
|
|
24
|
+
declare function getDefaultProjectId(): any;
|
|
25
|
+
declare function getDefaultPublishableClientKey(): any;
|
|
26
|
+
declare function getDefaultSecretServerKey(): any;
|
|
27
|
+
declare function getDefaultSuperSecretAdminKey(): any;
|
|
28
28
|
declare function getDefaultExtraRequestHeaders(): any;
|
|
29
29
|
/**
|
|
30
30
|
* Returns the base URL for the Stack API.
|
|
@@ -32,9 +32,9 @@ declare function getDefaultExtraRequestHeaders(): any;
|
|
|
32
32
|
* The URL can be specified in several ways, in order of precedence:
|
|
33
33
|
* 1. Directly through userSpecifiedBaseUrl parameter as string or browser/server object
|
|
34
34
|
* 2. Through environment variables:
|
|
35
|
-
* - Browser:
|
|
36
|
-
* - Server:
|
|
37
|
-
* -
|
|
35
|
+
* - Browser: NEXT_PUBLIC_HEXCLAVE_API_URL_BROWSER/VITE_HEXCLAVE_API_URL_BROWSER
|
|
36
|
+
* - Server: HEXCLAVE_API_URL_SERVER
|
|
37
|
+
* - Default: HEXCLAVE_API_URL
|
|
38
38
|
* 3. Default base URL if none of the above are specified
|
|
39
39
|
*
|
|
40
40
|
* The function also ensures the URL doesn't end with a trailing slash
|
|
@@ -47,7 +47,7 @@ declare function getDefaultExtraRequestHeaders(): any;
|
|
|
47
47
|
declare function getBaseUrl(userSpecifiedBaseUrl: string | {
|
|
48
48
|
browser: string;
|
|
49
49
|
server: string;
|
|
50
|
-
} | undefined):
|
|
50
|
+
} | undefined): any;
|
|
51
51
|
declare const defaultBaseUrl = "https://api.hexclave.com";
|
|
52
52
|
declare const defaultAnalyticsBaseUrl = "https://r.hexclave.com";
|
|
53
53
|
declare function getAnalyticsBaseUrl(regularBaseUrl: string): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.d.ts","names":[],"sources":["../../../../../../src/lib/hexclave-app/apps/implementations/common.ts"],"mappings":";;;;;;;cAoBa,aAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"common.d.ts","names":[],"sources":["../../../../../../src/lib/hexclave-app/apps/implementations/common.ts"],"mappings":";;;;;;;cAoBa,aAAA;AAAA,cAgCA,WAAA,uBAAmC,OAAA,GAAU,YAAA,EAAc,CAAA,KAAM,OAAA,CAAQ,CAAA,MAAE,UAAA,CAAA,CAAA,EAAA,MAAA,CAAA,CAAA;AAAA,cAO3E,oBAAA,uBAA4C,OAAA,GAAU,OAAA,EAAS,eAAA,EAAiB,iBAAA,EAAmB,CAAA,KAAM,OAAA,CAAQ,CAAA,MAAE,UAAA,EAAA,eAAA,KAAA,CAAA,GAAA,MAAA,CAAA,CAAA;AAAA,KAa3H,OAAA;EAAA,CAAa,0BAAA;IAA+B,qBAAA;EAAA;AAAA;AAAA,iBACjC,yBAAA;EAAsC,YAAA,GAAe,OAAA;AAAA,EAAA,CAAW,OAAA,EAAS,CAAA,GAAI,CAAA;EAAM,YAAA;AAAA;AAAA,iBAOnF,OAAA,CAAQ,OAAA,EAAS,iBAAA,EAAmB,OAAA;EAAW,SAAA;AAAA,IAAsB,mBAAA;AAAA,iBAOrE,mBAAA,CAAA;AAAA,iBAIA,8BAAA,CAAA;AAAA,iBAIA,yBAAA,CAAA;AAAA,iBAIA,6BAAA,CAAA;AAAA,iBAIA,6BAAA,CAAA;;;;;;;;;;;;AA5ChB;;;;;;;iBAkEgB,UAAA,CAAW,oBAAA;EAAiC,OAAA;EAAiB,MAAA;AAAA;AAAA,cAwBhE,cAAA;AAAA,cACA,uBAAA;AAAA,iBAOG,mBAAA,CAAoB,cAAA;AAAA,iBA0BpB,cAAA,CAAe,mBAAA;EAAgC,OAAA;EAAiB,MAAA;AAAA;AAAA,KAcpE,WAAA;EACV,WAAA;EACA,YAAA;AAAA;AAAA,iBAGc,qBAAA,CAAA,GAAqB,KAAA,CAAA,WAAA;AAAA,iBASrB,aAAA,oBAAA,CAAkC,KAAA,EAAO,UAAA,CAAW,CAAA,EAAG,MAAA,CAAO,CAAA,IAAK,YAAA,EAAc,CAAA,EAAG,MAAA,WAAiB,CAAA"}
|
|
@@ -10,17 +10,31 @@ import { isBrowserLike } from "@hexclave/shared/dist/utils/env";
|
|
|
10
10
|
import { createGlobal, getGlobal } from "@hexclave/shared/dist/utils/globals";
|
|
11
11
|
import { hexclaveAppInternalsSymbol } from "../../common.js";
|
|
12
12
|
import { Store } from "@hexclave/shared/dist/utils/stores";
|
|
13
|
-
import { envVars } from "
|
|
13
|
+
import { envVars } from "../../../../generated/env.js";
|
|
14
14
|
import { resolveHandlerUrls } from "../../url-targets.js";
|
|
15
15
|
|
|
16
16
|
//#region src/lib/hexclave-app/apps/implementations/common.ts
|
|
17
|
-
const clientVersion = "js @hexclave/next@1.0.
|
|
17
|
+
const clientVersion = "js @hexclave/next@1.0.6";
|
|
18
18
|
if (clientVersion.startsWith("STACK_COMPILE_TIME")) throw new HexclaveAssertionError("Client version was not replaced. Something went wrong during build!");
|
|
19
19
|
const replaceHexclavePortPrefix = (input) => {
|
|
20
20
|
if (!input) return input;
|
|
21
|
-
const prefix = envVars.
|
|
21
|
+
const prefix = envVars.HEXCLAVE_PORT_PREFIX;
|
|
22
22
|
return prefix ? input.replace(/\$\{NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81\}/g, prefix) : input;
|
|
23
23
|
};
|
|
24
|
+
const showMissingConfigAlertInBrowser = (message) => {
|
|
25
|
+
if (!isBrowserLike()) return;
|
|
26
|
+
const global = globalThis;
|
|
27
|
+
const alertAlreadyShownKey = "__hexclave_missing_config_alert_already_shown";
|
|
28
|
+
if (global[alertAlreadyShownKey]) return;
|
|
29
|
+
global[alertAlreadyShownKey] = true;
|
|
30
|
+
const alertFn = global.alert;
|
|
31
|
+
if (typeof alertFn === "function") alertFn(message);
|
|
32
|
+
};
|
|
33
|
+
const throwMissingProjectIdError = () => {
|
|
34
|
+
const message = "Welcome to Hexclave! It seems that you haven't provided a project ID. Please create a project on the Hexclave dashboard at https://app.hexclave.com and put it in the HEXCLAVE_PROJECT_ID environment variable.";
|
|
35
|
+
showMissingConfigAlertInBrowser(message);
|
|
36
|
+
return throwErr(new Error(message));
|
|
37
|
+
};
|
|
24
38
|
const createCache = (fetcher) => {
|
|
25
39
|
return new AsyncCache(async (dependencies) => await Result.fromThrowingAsync(async () => await fetcher(dependencies)), {});
|
|
26
40
|
};
|
|
@@ -43,19 +57,19 @@ function getUrls(partial, options) {
|
|
|
43
57
|
});
|
|
44
58
|
}
|
|
45
59
|
function getDefaultProjectId() {
|
|
46
|
-
return envVars.
|
|
60
|
+
return envVars.HEXCLAVE_PROJECT_ID || throwMissingProjectIdError();
|
|
47
61
|
}
|
|
48
62
|
function getDefaultPublishableClientKey() {
|
|
49
|
-
return envVars.
|
|
63
|
+
return envVars.HEXCLAVE_PUBLISHABLE_CLIENT_KEY;
|
|
50
64
|
}
|
|
51
65
|
function getDefaultSecretServerKey() {
|
|
52
|
-
return envVars.
|
|
66
|
+
return envVars.HEXCLAVE_SECRET_SERVER_KEY || throwErr(/* @__PURE__ */ new Error("No secret server key provided. Please copy your key from the Hexclave dashboard and put it in the HEXCLAVE_SECRET_SERVER_KEY environment variable."));
|
|
53
67
|
}
|
|
54
68
|
function getDefaultSuperSecretAdminKey() {
|
|
55
|
-
return envVars.
|
|
69
|
+
return envVars.HEXCLAVE_SUPER_SECRET_ADMIN_KEY || throwErr(/* @__PURE__ */ new Error("No super secret admin key provided. Please copy your key from the Hexclave dashboard and put it in the HEXCLAVE_SUPER_SECRET_ADMIN_KEY environment variable."));
|
|
56
70
|
}
|
|
57
71
|
function getDefaultExtraRequestHeaders() {
|
|
58
|
-
return JSON.parse(envVars.
|
|
72
|
+
return JSON.parse(envVars.HEXCLAVE_EXTRA_REQUEST_HEADERS || "{}");
|
|
59
73
|
}
|
|
60
74
|
/**
|
|
61
75
|
* Returns the base URL for the Stack API.
|
|
@@ -63,9 +77,9 @@ function getDefaultExtraRequestHeaders() {
|
|
|
63
77
|
* The URL can be specified in several ways, in order of precedence:
|
|
64
78
|
* 1. Directly through userSpecifiedBaseUrl parameter as string or browser/server object
|
|
65
79
|
* 2. Through environment variables:
|
|
66
|
-
* - Browser:
|
|
67
|
-
* - Server:
|
|
68
|
-
* -
|
|
80
|
+
* - Browser: NEXT_PUBLIC_HEXCLAVE_API_URL_BROWSER/VITE_HEXCLAVE_API_URL_BROWSER
|
|
81
|
+
* - Server: HEXCLAVE_API_URL_SERVER
|
|
82
|
+
* - Default: HEXCLAVE_API_URL
|
|
69
83
|
* 3. Default base URL if none of the above are specified
|
|
70
84
|
*
|
|
71
85
|
* The function also ensures the URL doesn't end with a trailing slash
|
|
@@ -81,9 +95,9 @@ function getBaseUrl(userSpecifiedBaseUrl) {
|
|
|
81
95
|
else if (isBrowserLike()) url = userSpecifiedBaseUrl.browser;
|
|
82
96
|
else url = userSpecifiedBaseUrl.server;
|
|
83
97
|
else {
|
|
84
|
-
if (isBrowserLike()) url = envVars.
|
|
85
|
-
else url = envVars.
|
|
86
|
-
url = url || envVars.
|
|
98
|
+
if (isBrowserLike()) url = envVars.HEXCLAVE_API_URL_BROWSER;
|
|
99
|
+
else url = envVars.HEXCLAVE_API_URL_SERVER;
|
|
100
|
+
url = url || envVars.HEXCLAVE_API_URL || defaultBaseUrl;
|
|
87
101
|
}
|
|
88
102
|
return replaceHexclavePortPrefix(url.endsWith("/") ? url.slice(0, -1) : url);
|
|
89
103
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.js","names":[],"sources":["../../../../../../src/lib/hexclave-app/apps/implementations/common.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 { InternalSession } from \"@hexclave/shared/dist/sessions\";\nimport { AsyncCache } from \"@hexclave/shared/dist/utils/caches\";\nimport { isBrowserLike } from \"@hexclave/shared/dist/utils/env\";\nimport { HexclaveAssertionError, captureError, concatStacktraces, throwErr } from \"@hexclave/shared/dist/utils/errors\";\nimport { createGlobal, getGlobal } from \"@hexclave/shared/dist/utils/globals\";\nimport { filterUndefined, omit } from \"@hexclave/shared/dist/utils/objects\";\nimport { ReactPromise, runAsynchronously } from \"@hexclave/shared/dist/utils/promises\";\nimport { suspendIfSsr, use } from \"@hexclave/shared/dist/utils/react\";\nimport { Result } from \"@hexclave/shared/dist/utils/results\";\nimport { Store } from \"@hexclave/shared/dist/utils/stores\";\nimport { getDefaultApiUrls } from \"@hexclave/shared/dist/utils/urls\";\nimport React, { useCallback } from \"react\"; // THIS_LINE_PLATFORM react-like\nimport { envVars } from \"../../../env\";\nimport { HandlerUrlOptions, ResolvedHandlerUrls, hexclaveAppInternalsSymbol } from \"../../common\";\nimport { resolveHandlerUrls } from \"../../url-targets\";\n\nexport const clientVersion = \"STACK_COMPILE_TIME_CLIENT_PACKAGE_VERSION_SENTINEL\";\nif (clientVersion.startsWith(\"STACK_COMPILE_TIME\")) {\n throw new HexclaveAssertionError(\"Client version was not replaced. Something went wrong during build!\");\n}\n\nconst replaceHexclavePortPrefix = <T extends string | undefined>(input: T): T => {\n if (!input) return input;\n const prefix = envVars.NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX;\n return prefix ? input.replace(/\\$\\{NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81\\}/g, prefix) as T : input;\n};\n\n\nexport const createCache = <D extends any[], T>(fetcher: (dependencies: D) => Promise<T>) => {\n return new AsyncCache<D, Result<T>>(\n async (dependencies) => await Result.fromThrowingAsync(async () => await fetcher(dependencies)),\n {},\n );\n};\n\nexport const createCacheBySession = <D extends any[], T>(fetcher: (session: InternalSession, extraDependencies: D) => Promise<T> ) => {\n return new AsyncCache<[InternalSession, ...D], Result<T>>(\n async ([session, ...extraDependencies]) => await Result.fromThrowingAsync(async () => await fetcher(session, extraDependencies)),\n {\n onSubscribe: ([session], refresh) => {\n const handler = session.onInvalidate(() => refresh());\n return () => handler.unsubscribe();\n },\n },\n );\n};\n\n\ntype AppLike = { [hexclaveAppInternalsSymbol]: { getConstructorOptions: () => any } };\nexport function resolveConstructorOptions<T extends { inheritsFrom?: AppLike }>(options: T): T & { inheritsFrom?: undefined } {\n return {\n ...options.inheritsFrom?.[hexclaveAppInternalsSymbol].getConstructorOptions() ?? {},\n ...filterUndefined(omit(options, [\"inheritsFrom\"])),\n };\n}\n\nexport function getUrls(partial: HandlerUrlOptions, options: { projectId: string }): ResolvedHandlerUrls {\n return resolveHandlerUrls({\n urls: partial,\n projectId: options.projectId,\n });\n}\n\nexport function getDefaultProjectId() {\n return envVars.NEXT_PUBLIC_STACK_PROJECT_ID || envVars.STACK_PROJECT_ID || throwErr(new Error(\"Welcome to Hexclave! It seems that you haven't provided a project ID. Please create a project on the Hexclave dashboard at https://app.hexclave.com and put it in the NEXT_PUBLIC_STACK_PROJECT_ID environment variable.\"));\n}\n\nexport function getDefaultPublishableClientKey() {\n return envVars.NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY || envVars.STACK_PUBLISHABLE_CLIENT_KEY;\n}\n\nexport function getDefaultSecretServerKey() {\n return envVars.STACK_SECRET_SERVER_KEY || throwErr(new Error(\"No secret server key provided. Please copy your key from the Hexclave dashboard and put it in the STACK_SECRET_SERVER_KEY environment variable.\"));\n}\n\nexport function getDefaultSuperSecretAdminKey() {\n return envVars.STACK_SUPER_SECRET_ADMIN_KEY || throwErr(new Error(\"No super secret admin key provided. Please copy your key from the Hexclave dashboard and put it in the STACK_SUPER_SECRET_ADMIN_KEY environment variable.\"));\n}\n\nexport function getDefaultExtraRequestHeaders() {\n return JSON.parse(envVars.NEXT_PUBLIC_STACK_EXTRA_REQUEST_HEADERS || envVars.STACK_EXTRA_REQUEST_HEADERS || '{}');\n}\n\n/**\n * Returns the base URL for the Stack API.\n *\n * The URL can be specified in several ways, in order of precedence:\n * 1. Directly through userSpecifiedBaseUrl parameter as string or browser/server object\n * 2. Through environment variables:\n * - Browser: NEXT_PUBLIC_BROWSER_STACK_API_URL\n * - Server: NEXT_PUBLIC_SERVER_STACK_API_URL\n * - Fallback: NEXT_PUBLIC_STACK_API_URL or NEXT_PUBLIC_STACK_URL\n * 3. Default base URL if none of the above are specified\n *\n * The function also ensures the URL doesn't end with a trailing slash\n * by removing it if present.\n *\n * @param userSpecifiedBaseUrl - Optional URL override as string or {browser, server} object\n * @returns The configured base URL without trailing slash\n\n */\nexport function getBaseUrl(userSpecifiedBaseUrl: string | { browser: string, server: string } | undefined) {\n let url;\n if (userSpecifiedBaseUrl) {\n if (typeof userSpecifiedBaseUrl === \"string\") {\n url = userSpecifiedBaseUrl;\n } else {\n if (isBrowserLike()) {\n url = userSpecifiedBaseUrl.browser;\n } else {\n url = userSpecifiedBaseUrl.server;\n }\n }\n } else {\n // note: NEXT_PUBLIC_BROWSER_STACK_API_URL was renamed to NEXT_PUBLIC_STACK_API_URL_BROWSER, and NEXT_PUBLIC_STACK_URL to NEXT_PUBLIC_STACK_API_URL\n if (isBrowserLike()) {\n url = envVars.NEXT_PUBLIC_BROWSER_STACK_API_URL || envVars.NEXT_PUBLIC_STACK_API_URL_BROWSER || envVars.STACK_API_URL_BROWSER;\n } else {\n url = envVars.NEXT_PUBLIC_SERVER_STACK_API_URL || envVars.NEXT_PUBLIC_STACK_API_URL_SERVER || envVars.STACK_API_URL_SERVER;\n }\n url = url || envVars.NEXT_PUBLIC_STACK_API_URL || envVars.STACK_API_URL || envVars.NEXT_PUBLIC_STACK_URL || defaultBaseUrl;\n }\n\n return replaceHexclavePortPrefix(url.endsWith('/') ? url.slice(0, -1) : url);\n}\n\nexport const defaultBaseUrl = \"https://api.hexclave.com\";\nexport const defaultAnalyticsBaseUrl = \"https://r.hexclave.com\";\n\nconst analyticsBaseUrlsByApiBaseUrl = new Map<string, string>([\n [defaultBaseUrl, defaultAnalyticsBaseUrl],\n [\"https://api.stack-auth.com\", \"https://r.stack-auth.com\"],\n]);\n\nexport function getAnalyticsBaseUrl(regularBaseUrl: string): string {\n return analyticsBaseUrlsByApiBaseUrl.get(regularBaseUrl) ?? regularBaseUrl;\n}\n\n\nfunction fetchBackendUrlsInBackground(primaryBaseUrl: string): void {\n createGlobal('__stack-fetch-backend-urls-started', () => {\n runAsynchronously(async () => {\n try {\n const res = await fetch(`${primaryBaseUrl}/api/v1/internal/backend-urls`);\n if (!res.ok) {\n return;\n }\n const data = await res.json();\n if (!Array.isArray(data.urls) || !data.urls.every((u: unknown) => typeof u === 'string')) {\n return;\n }\n createGlobal('__stack-fetched-backend-urls', () => data.urls as string[]);\n } catch (e) {\n captureError('fetch-backend-urls-in-background', e);\n }\n });\n return true;\n });\n}\n\nexport function resolveApiUrls(userExplicitBaseUrl: string | { browser: string, server: string } | undefined): () => string[] {\n return () => {\n if (userExplicitBaseUrl != null) {\n return [getBaseUrl(userExplicitBaseUrl)];\n }\n const primary = getBaseUrl(undefined);\n // Always try to fetch server-configured URLs (supports custom domains via\n // STACK_BACKEND_URLS_CONFIG). Hardcoded fallbacks are used as a default\n // until the background fetch completes.\n fetchBackendUrlsInBackground(primary);\n return getGlobal('__stack-fetched-backend-urls') ?? getDefaultApiUrls(primary);\n };\n}\n\nexport type TokenObject = {\n accessToken: string | null,\n refreshToken: string | null,\n};\n\nexport function createEmptyTokenStore() {\n return new Store<TokenObject>({\n refreshToken: null,\n accessToken: null,\n });\n}\n\n\nconst cachePromiseByHookId = new Map<string, ReactPromise<Result<unknown>>>();\nexport function useAsyncCache<D extends any[], T>(cache: AsyncCache<D, Result<T>>, dependencies: D, caller: string): T {\n // we explicitly don't want to run this hook in SSR\n suspendIfSsr(caller);\n\n // on the dashboard, we do some perf monitoring for pre-fetching which should hook right in here\n const asyncCacheHooks: any[] = getGlobal(\"use-async-cache-execution-hooks\") ?? [];\n for (const hook of asyncCacheHooks) {\n hook({ cache, caller, dependencies });\n }\n\n const id = React.useId();\n\n // whenever the dependencies change, we need to refresh the promise cache\n React.useEffect(() => {\n cachePromiseByHookId.delete(id);\n }, [...dependencies, id]);\n\n const subscribe = useCallback((cb: () => void) => {\n const { unsubscribe } = cache.onStateChange(dependencies, () => {\n cachePromiseByHookId.delete(id);\n cb();\n });\n return unsubscribe;\n }, [cache, ...dependencies]);\n const getSnapshot = useCallback(() => {\n // React checks whether a promise passed to `use` is still the same as the previous one by comparing the reference.\n // If we didn't cache here, this wouldn't work because the promise would be recreated every time the value changes.\n if (!cachePromiseByHookId.has(id)) {\n cachePromiseByHookId.set(id, cache.getOrWait(dependencies, \"read-write\"));\n }\n return cachePromiseByHookId.get(id) as ReactPromise<Result<T>>;\n }, [cache, ...dependencies]);\n\n // note: we must use React.useSyncExternalStore instead of importing the function directly, as it will otherwise\n // throw an error on Next.js (\"can't import useSyncExternalStore from the server\")\n const promise = React.useSyncExternalStore(\n subscribe,\n getSnapshot,\n getSnapshot,\n );\n\n const result = use(promise);\n if (result.status === \"error\") {\n const error = result.error;\n if (error instanceof Error && !(error as any).__stackHasConcatenatedStacktraces) {\n concatStacktraces(error, new Error());\n (error as any).__stackHasConcatenatedStacktraces = true;\n }\n throw error;\n }\n return result.data;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAoBA,MAAa,gBAAgB;AAC7B,IAAI,cAAc,WAAW,qBAAqB,CAChD,OAAM,IAAI,uBAAuB,sEAAsE;AAGzG,MAAM,6BAA2D,UAAgB;AAC/E,KAAI,CAAC,MAAO,QAAO;CACnB,MAAM,SAAS,QAAQ;AACvB,QAAO,SAAS,MAAM,QAAQ,+CAA+C,OAAO,GAAQ;;AAI9F,MAAa,eAAmC,YAA6C;AAC3F,QAAO,IAAI,WACT,OAAO,iBAAiB,MAAM,OAAO,kBAAkB,YAAY,MAAM,QAAQ,aAAa,CAAC,EAC/F,EAAE,CACH;;AAGH,MAAa,wBAA4C,YAA6E;AACpI,QAAO,IAAI,WACT,OAAO,CAAC,SAAS,GAAG,uBAAuB,MAAM,OAAO,kBAAkB,YAAY,MAAM,QAAQ,SAAS,kBAAkB,CAAC,EAChI,EACE,cAAc,CAAC,UAAU,YAAY;EACnC,MAAM,UAAU,QAAQ,mBAAmB,SAAS,CAAC;AACrD,eAAa,QAAQ,aAAa;IAErC,CACF;;AAKH,SAAgB,0BAAgE,SAA8C;AAC5H,QAAO;EACL,GAAG,QAAQ,eAAe,4BAA4B,uBAAuB,IAAI,EAAE;EACnF,GAAG,gBAAgB,KAAK,SAAS,CAAC,eAAe,CAAC,CAAC;EACpD;;AAGH,SAAgB,QAAQ,SAA4B,SAAqD;AACvG,QAAO,mBAAmB;EACxB,MAAM;EACN,WAAW,QAAQ;EACpB,CAAC;;AAGJ,SAAgB,sBAAsB;AACpC,QAAO,QAAQ,gCAAgC,QAAQ,oBAAoB,yBAAS,IAAI,MAAM,2NAA2N,CAAC;;AAG5T,SAAgB,iCAAiC;AAC/C,QAAO,QAAQ,4CAA4C,QAAQ;;AAGrE,SAAgB,4BAA4B;AAC1C,QAAO,QAAQ,2BAA2B,yBAAS,IAAI,MAAM,kJAAkJ,CAAC;;AAGlN,SAAgB,gCAAgC;AAC9C,QAAO,QAAQ,gCAAgC,yBAAS,IAAI,MAAM,4JAA4J,CAAC;;AAGjO,SAAgB,gCAAgC;AAC9C,QAAO,KAAK,MAAM,QAAQ,2CAA2C,QAAQ,+BAA+B,KAAK;;;;;;;;;;;;;;;;;;;;AAqBnH,SAAgB,WAAW,sBAAgF;CACzG,IAAI;AACJ,KAAI,qBACF,KAAI,OAAO,yBAAyB,SAClC,OAAM;UAEF,eAAe,CACjB,OAAM,qBAAqB;KAE3B,OAAM,qBAAqB;MAG1B;AAEL,MAAI,eAAe,CACjB,OAAM,QAAQ,qCAAqC,QAAQ,qCAAqC,QAAQ;MAExG,OAAM,QAAQ,oCAAoC,QAAQ,oCAAoC,QAAQ;AAExG,QAAM,OAAO,QAAQ,6BAA6B,QAAQ,iBAAiB,QAAQ,yBAAyB;;AAG9G,QAAO,0BAA0B,IAAI,SAAS,IAAI,GAAG,IAAI,MAAM,GAAG,GAAG,GAAG,IAAI;;AAG9E,MAAa,iBAAiB;AAC9B,MAAa,0BAA0B;AAEvC,MAAM,gCAAgC,IAAI,IAAoB,CAC5D,CAAC,gBAAgB,wBAAwB,EACzC,CAAC,8BAA8B,2BAA2B,CAC3D,CAAC;AAEF,SAAgB,oBAAoB,gBAAgC;AAClE,QAAO,8BAA8B,IAAI,eAAe,IAAI;;AAI9D,SAAS,6BAA6B,gBAA8B;AAClE,cAAa,4CAA4C;AACvD,oBAAkB,YAAY;AAC5B,OAAI;IACF,MAAM,MAAM,MAAM,MAAM,GAAG,eAAe,+BAA+B;AACzE,QAAI,CAAC,IAAI,GACP;IAEF,MAAM,OAAO,MAAM,IAAI,MAAM;AAC7B,QAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,IAAI,CAAC,KAAK,KAAK,OAAO,MAAe,OAAO,MAAM,SAAS,CACtF;AAEF,iBAAa,sCAAsC,KAAK,KAAiB;YAClE,GAAG;AACV,iBAAa,oCAAoC,EAAE;;IAErD;AACF,SAAO;GACP;;AAGJ,SAAgB,eAAe,qBAA+F;AAC5H,cAAa;AACX,MAAI,uBAAuB,KACzB,QAAO,CAAC,WAAW,oBAAoB,CAAC;EAE1C,MAAM,UAAU,WAAW,OAAU;AAIrC,+BAA6B,QAAQ;AACrC,SAAO,UAAU,+BAA+B,IAAI,kBAAkB,QAAQ;;;AASlF,SAAgB,wBAAwB;AACtC,QAAO,IAAI,MAAmB;EAC5B,cAAc;EACd,aAAa;EACd,CAAC;;AAIJ,MAAM,uCAAuB,IAAI,KAA4C;AAC7E,SAAgB,cAAkC,OAAiC,cAAiB,QAAmB;AAErH,cAAa,OAAO;CAGpB,MAAM,kBAAyB,UAAU,kCAAkC,IAAI,EAAE;AACjF,MAAK,MAAM,QAAQ,gBACjB,MAAK;EAAE;EAAO;EAAQ;EAAc,CAAC;CAGvC,MAAM,KAAK,MAAM,OAAO;AAGxB,OAAM,gBAAgB;AACpB,uBAAqB,OAAO,GAAG;IAC9B,CAAC,GAAG,cAAc,GAAG,CAAC;CAEzB,MAAM,YAAY,aAAa,OAAmB;EAChD,MAAM,EAAE,gBAAgB,MAAM,cAAc,oBAAoB;AAC9D,wBAAqB,OAAO,GAAG;AAC/B,OAAI;IACJ;AACF,SAAO;IACN,CAAC,OAAO,GAAG,aAAa,CAAC;CAC5B,MAAM,cAAc,kBAAkB;AAGpC,MAAI,CAAC,qBAAqB,IAAI,GAAG,CAC/B,sBAAqB,IAAI,IAAI,MAAM,UAAU,cAAc,aAAa,CAAC;AAE3E,SAAO,qBAAqB,IAAI,GAAG;IAClC,CAAC,OAAO,GAAG,aAAa,CAAC;CAU5B,MAAM,SAAS,IANC,MAAM,qBACpB,WACA,aACA,YACD,CAE0B;AAC3B,KAAI,OAAO,WAAW,SAAS;EAC7B,MAAM,QAAQ,OAAO;AACrB,MAAI,iBAAiB,SAAS,CAAE,MAAc,mCAAmC;AAC/E,qBAAkB,uBAAO,IAAI,OAAO,CAAC;AACrC,GAAC,MAAc,oCAAoC;;AAErD,QAAM;;AAER,QAAO,OAAO"}
|
|
1
|
+
{"version":3,"file":"common.js","names":[],"sources":["../../../../../../src/lib/hexclave-app/apps/implementations/common.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 { InternalSession } from \"@hexclave/shared/dist/sessions\";\nimport { AsyncCache } from \"@hexclave/shared/dist/utils/caches\";\nimport { isBrowserLike } from \"@hexclave/shared/dist/utils/env\";\nimport { HexclaveAssertionError, captureError, concatStacktraces, throwErr } from \"@hexclave/shared/dist/utils/errors\";\nimport { createGlobal, getGlobal } from \"@hexclave/shared/dist/utils/globals\";\nimport { filterUndefined, omit } from \"@hexclave/shared/dist/utils/objects\";\nimport { ReactPromise, runAsynchronously } from \"@hexclave/shared/dist/utils/promises\";\nimport { suspendIfSsr, use } from \"@hexclave/shared/dist/utils/react\";\nimport { Result } from \"@hexclave/shared/dist/utils/results\";\nimport { Store } from \"@hexclave/shared/dist/utils/stores\";\nimport { getDefaultApiUrls } from \"@hexclave/shared/dist/utils/urls\";\nimport React, { useCallback } from \"react\"; // THIS_LINE_PLATFORM react-like\nimport { envVars } from \"../../../../generated/env\";\nimport { HandlerUrlOptions, ResolvedHandlerUrls, hexclaveAppInternalsSymbol } from \"../../common\";\nimport { resolveHandlerUrls } from \"../../url-targets\";\n\nexport const clientVersion = \"STACK_COMPILE_TIME_CLIENT_PACKAGE_VERSION_SENTINEL\";\nif (clientVersion.startsWith(\"STACK_COMPILE_TIME\")) {\n throw new HexclaveAssertionError(\"Client version was not replaced. Something went wrong during build!\");\n}\n\nconst replaceHexclavePortPrefix = <T extends string | undefined>(input: T): T => {\n if (!input) return input;\n const prefix = envVars.HEXCLAVE_PORT_PREFIX;\n return prefix ? input.replace(/\\$\\{NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81\\}/g, prefix) as T : input;\n};\n\nconst showMissingConfigAlertInBrowser = (message: string) => {\n if (!isBrowserLike()) return;\n\n const global = globalThis as any;\n const alertAlreadyShownKey = \"__hexclave_missing_config_alert_already_shown\";\n if (global[alertAlreadyShownKey]) return;\n global[alertAlreadyShownKey] = true;\n\n const alertFn = global.alert;\n if (typeof alertFn === \"function\") {\n alertFn(message);\n }\n};\n\nconst throwMissingProjectIdError = (): never => {\n const message = \"Welcome to Hexclave! It seems that you haven't provided a project ID. Please create a project on the Hexclave dashboard at https://app.hexclave.com and put it in the HEXCLAVE_PROJECT_ID environment variable.\";\n showMissingConfigAlertInBrowser(message);\n return throwErr(new Error(message));\n};\n\n\nexport const createCache = <D extends any[], T>(fetcher: (dependencies: D) => Promise<T>) => {\n return new AsyncCache<D, Result<T>>(\n async (dependencies) => await Result.fromThrowingAsync(async () => await fetcher(dependencies)),\n {},\n );\n};\n\nexport const createCacheBySession = <D extends any[], T>(fetcher: (session: InternalSession, extraDependencies: D) => Promise<T> ) => {\n return new AsyncCache<[InternalSession, ...D], Result<T>>(\n async ([session, ...extraDependencies]) => await Result.fromThrowingAsync(async () => await fetcher(session, extraDependencies)),\n {\n onSubscribe: ([session], refresh) => {\n const handler = session.onInvalidate(() => refresh());\n return () => handler.unsubscribe();\n },\n },\n );\n};\n\n\ntype AppLike = { [hexclaveAppInternalsSymbol]: { getConstructorOptions: () => any } };\nexport function resolveConstructorOptions<T extends { inheritsFrom?: AppLike }>(options: T): T & { inheritsFrom?: undefined } {\n return {\n ...options.inheritsFrom?.[hexclaveAppInternalsSymbol].getConstructorOptions() ?? {},\n ...filterUndefined(omit(options, [\"inheritsFrom\"])),\n };\n}\n\nexport function getUrls(partial: HandlerUrlOptions, options: { projectId: string }): ResolvedHandlerUrls {\n return resolveHandlerUrls({\n urls: partial,\n projectId: options.projectId,\n });\n}\n\nexport function getDefaultProjectId() {\n return envVars.HEXCLAVE_PROJECT_ID || throwMissingProjectIdError();\n}\n\nexport function getDefaultPublishableClientKey() {\n return envVars.HEXCLAVE_PUBLISHABLE_CLIENT_KEY;\n}\n\nexport function getDefaultSecretServerKey() {\n return envVars.HEXCLAVE_SECRET_SERVER_KEY || throwErr(new Error(\"No secret server key provided. Please copy your key from the Hexclave dashboard and put it in the HEXCLAVE_SECRET_SERVER_KEY environment variable.\"));\n}\n\nexport function getDefaultSuperSecretAdminKey() {\n return envVars.HEXCLAVE_SUPER_SECRET_ADMIN_KEY || throwErr(new Error(\"No super secret admin key provided. Please copy your key from the Hexclave dashboard and put it in the HEXCLAVE_SUPER_SECRET_ADMIN_KEY environment variable.\"));\n}\n\nexport function getDefaultExtraRequestHeaders() {\n return JSON.parse(envVars.HEXCLAVE_EXTRA_REQUEST_HEADERS || '{}');\n}\n\n/**\n * Returns the base URL for the Stack API.\n *\n * The URL can be specified in several ways, in order of precedence:\n * 1. Directly through userSpecifiedBaseUrl parameter as string or browser/server object\n * 2. Through environment variables:\n * - Browser: NEXT_PUBLIC_HEXCLAVE_API_URL_BROWSER/VITE_HEXCLAVE_API_URL_BROWSER\n * - Server: HEXCLAVE_API_URL_SERVER\n * - Default: HEXCLAVE_API_URL\n * 3. Default base URL if none of the above are specified\n *\n * The function also ensures the URL doesn't end with a trailing slash\n * by removing it if present.\n *\n * @param userSpecifiedBaseUrl - Optional URL override as string or {browser, server} object\n * @returns The configured base URL without trailing slash\n\n */\nexport function getBaseUrl(userSpecifiedBaseUrl: string | { browser: string, server: string } | undefined) {\n let url;\n if (userSpecifiedBaseUrl) {\n if (typeof userSpecifiedBaseUrl === \"string\") {\n url = userSpecifiedBaseUrl;\n } else {\n if (isBrowserLike()) {\n url = userSpecifiedBaseUrl.browser;\n } else {\n url = userSpecifiedBaseUrl.server;\n }\n }\n } else {\n if (isBrowserLike()) {\n url = envVars.HEXCLAVE_API_URL_BROWSER;\n } else {\n url = envVars.HEXCLAVE_API_URL_SERVER;\n }\n url = url || envVars.HEXCLAVE_API_URL || defaultBaseUrl;\n }\n\n return replaceHexclavePortPrefix(url.endsWith('/') ? url.slice(0, -1) : url);\n}\n\nexport const defaultBaseUrl = \"https://api.hexclave.com\";\nexport const defaultAnalyticsBaseUrl = \"https://r.hexclave.com\";\n\nconst analyticsBaseUrlsByApiBaseUrl = new Map<string, string>([\n [defaultBaseUrl, defaultAnalyticsBaseUrl],\n [\"https://api.stack-auth.com\", \"https://r.stack-auth.com\"],\n]);\n\nexport function getAnalyticsBaseUrl(regularBaseUrl: string): string {\n return analyticsBaseUrlsByApiBaseUrl.get(regularBaseUrl) ?? regularBaseUrl;\n}\n\n\nfunction fetchBackendUrlsInBackground(primaryBaseUrl: string): void {\n createGlobal('__stack-fetch-backend-urls-started', () => {\n runAsynchronously(async () => {\n try {\n const res = await fetch(`${primaryBaseUrl}/api/v1/internal/backend-urls`);\n if (!res.ok) {\n return;\n }\n const data = await res.json();\n if (!Array.isArray(data.urls) || !data.urls.every((u: unknown) => typeof u === 'string')) {\n return;\n }\n createGlobal('__stack-fetched-backend-urls', () => data.urls as string[]);\n } catch (e) {\n captureError('fetch-backend-urls-in-background', e);\n }\n });\n return true;\n });\n}\n\nexport function resolveApiUrls(userExplicitBaseUrl: string | { browser: string, server: string } | undefined): () => string[] {\n return () => {\n if (userExplicitBaseUrl != null) {\n return [getBaseUrl(userExplicitBaseUrl)];\n }\n const primary = getBaseUrl(undefined);\n // Always try to fetch server-configured URLs (supports custom domains via\n // STACK_BACKEND_URLS_CONFIG). Hardcoded fallbacks are used as a default\n // until the background fetch completes.\n fetchBackendUrlsInBackground(primary);\n return getGlobal('__stack-fetched-backend-urls') ?? getDefaultApiUrls(primary);\n };\n}\n\nexport type TokenObject = {\n accessToken: string | null,\n refreshToken: string | null,\n};\n\nexport function createEmptyTokenStore() {\n return new Store<TokenObject>({\n refreshToken: null,\n accessToken: null,\n });\n}\n\n\nconst cachePromiseByHookId = new Map<string, ReactPromise<Result<unknown>>>();\nexport function useAsyncCache<D extends any[], T>(cache: AsyncCache<D, Result<T>>, dependencies: D, caller: string): T {\n // we explicitly don't want to run this hook in SSR\n suspendIfSsr(caller);\n\n // on the dashboard, we do some perf monitoring for pre-fetching which should hook right in here\n const asyncCacheHooks: any[] = getGlobal(\"use-async-cache-execution-hooks\") ?? [];\n for (const hook of asyncCacheHooks) {\n hook({ cache, caller, dependencies });\n }\n\n const id = React.useId();\n\n // whenever the dependencies change, we need to refresh the promise cache\n React.useEffect(() => {\n cachePromiseByHookId.delete(id);\n }, [...dependencies, id]);\n\n const subscribe = useCallback((cb: () => void) => {\n const { unsubscribe } = cache.onStateChange(dependencies, () => {\n cachePromiseByHookId.delete(id);\n cb();\n });\n return unsubscribe;\n }, [cache, ...dependencies]);\n\n const getSnapshot = useCallback(() => {\n // React checks whether a promise passed to `use` is still the same as the previous one by comparing the reference.\n // If we didn't cache here, this wouldn't work because the promise would be recreated every time the value changes.\n if (!cachePromiseByHookId.has(id)) {\n cachePromiseByHookId.set(id, cache.getOrWait(dependencies, \"read-write\"));\n }\n return cachePromiseByHookId.get(id) as ReactPromise<Result<T>>;\n }, [cache, ...dependencies]);\n\n // note: we must use React.useSyncExternalStore instead of importing the function directly, as it will otherwise\n // throw an error on Next.js (\"can't import useSyncExternalStore from the server\")\n const promise = React.useSyncExternalStore(\n subscribe,\n getSnapshot,\n getSnapshot,\n );\n\n const result = use(promise);\n if (result.status === \"error\") {\n const error = result.error;\n if (error instanceof Error && !(error as any).__stackHasConcatenatedStacktraces) {\n concatStacktraces(error, new Error());\n (error as any).__stackHasConcatenatedStacktraces = true;\n }\n throw error;\n }\n return result.data;\n}\n"],"mappings":"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"}
|
|
@@ -5,8 +5,8 @@ import { HexclaveServerInterface, KnownErrors } from "@hexclave/shared";
|
|
|
5
5
|
import { suspend } from "@hexclave/shared/dist/utils/react";
|
|
6
6
|
import { Result } from "@hexclave/shared/dist/utils/results";
|
|
7
7
|
import { clientVersion, createCache, createCacheBySession, getDefaultExtraRequestHeaders, getDefaultProjectId, getDefaultPublishableClientKey, getDefaultSecretServerKey, resolveApiUrls, resolveConstructorOptions, useAsyncCache } from "./common.js";
|
|
8
|
-
import { WebAuthnError, startRegistration } from "@simplewebauthn/browser";
|
|
9
8
|
import { InternalSession } from "@hexclave/shared/dist/sessions";
|
|
9
|
+
import { WebAuthnError, startRegistration } from "@simplewebauthn/browser";
|
|
10
10
|
import { constructRedirectUrl } from "../../../../utils/url.js";
|
|
11
11
|
import { apiKeyCreationOptionsToCrud, apiKeyUpdateOptionsToCrud } from "../../api-keys/index.js";
|
|
12
12
|
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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { HexclaveAssertionError } from "@hexclave/shared/dist/utils/errors";
|
|
2
2
|
import { getCustomPagePrompts } from "@hexclave/shared/dist/interface/handler-urls";
|
|
3
3
|
import { getHostedHandlerUrlFromConfig } from "@hexclave/shared/dist/utils/redirect-urls";
|
|
4
|
-
import { envVars } from "
|
|
4
|
+
import { envVars } from "../../generated/env.js";
|
|
5
5
|
|
|
6
6
|
//#region src/lib/hexclave-app/url-targets.ts
|
|
7
7
|
const localUrlPlaceholderOrigin = "http://example.com";
|
|
@@ -50,15 +50,20 @@ const getHostedHandlerUrl = (options) => {
|
|
|
50
50
|
return getHostedHandlerUrlFromConfig({
|
|
51
51
|
projectId: options.projectId,
|
|
52
52
|
hostedPath,
|
|
53
|
-
hostedHandlerDomainSuffix: envVars.
|
|
54
|
-
hostedHandlerUrlTemplate: envVars.
|
|
55
|
-
hexclavePortPrefix: envVars.
|
|
53
|
+
hostedHandlerDomainSuffix: envVars.HEXCLAVE_HOSTED_HANDLER_DOMAIN_SUFFIX,
|
|
54
|
+
hostedHandlerUrlTemplate: envVars.HEXCLAVE_HOSTED_HANDLER_URL_TEMPLATE,
|
|
55
|
+
hexclavePortPrefix: envVars.HEXCLAVE_PORT_PREFIX
|
|
56
56
|
});
|
|
57
57
|
};
|
|
58
58
|
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":";;;;;;AAUA,MAAM,4BAA4B;AAClC,MAAM,oBAAoB;AAE1B,MAAM,oBAAsF,sBAAsB;AAElH,MAAM,4BAA4B,UAAkB,aAA6B;CAC/E,MAAM,qBAAqB,SAAS,SAAS,IAAI,IAAI,SAAS,SAAS,IACnE,SAAS,MAAM,GAAG,GAAG,GACrB;AACJ,KAAI,SAAS,WAAW,EACtB,QAAO;AAET,KAAI,uBAAuB,IACzB,QAAO,IAAI;AAEb,QAAO,GAAG,mBAAmB,GAAG;;AAGlC,MAAM,mCAAmC,gBAA2C;AAClF,SAAQ,aAAR;EACE,KAAK,UACH,QAAO;EAET,KAAK,OACH,QAAO;EAET,KAAK,cACH,QAAO;EAET,KAAK,cACH,QAAO;EAET,KAAK,eACH,QAAO;EAET,KAAK,SACH,QAAO;EAET,KAAK,SACH,QAAO;EAET,KAAK,UACH,QAAO;EAET,KAAK,oBACH,QAAO;EAET,KAAK,gBACH,QAAO;EAET,KAAK,iBACH,QAAO;EAET,KAAK,gBACH,QAAO;EAET,KAAK,oBACH,QAAO;EAET,KAAK,kBACH,QAAO;EAET,KAAK,iBACH,QAAO;EAET,KAAK,iBACH,QAAO;EAET,KAAK,MACH,QAAO;EAET,KAAK,QACH,QAAO;EAET,KAAK,aACH,QAAO;;;AAKb,MAAM,0BAA0B,YAGlB;CACZ,MAAM,cAAc,QAAQ;AAC5B,KAAI,eAAe,mBAAmB;EACpC,MAAM,mBAAmB,kBAAkB;AAC3C,MAAI,QAAQ,OAAO,YAAY,KAAK,QAAQ,OAAO,WAAW,iBAAiB,SAC7E,QAAO,QAAQ,OAAO;AAGxB,QAAM,IAAI,MAAM,mCAAmC,QAAQ,OAAO,QAAQ,OAAO,QAAQ,YAAY,WAAW,QAAQ,OAAO,IAAI,iDAAiD,KAAK,IAAI,GAAG,GAAG,OAAO,KAAK,iBAAiB,SAAS,CAAC,IAAI,OAAO,CAAC,CAAC,6EAA6E;OAEpU,OAAM,IAAI,MAAM,cAAc,QAAQ,YAAY,uEAAuE;;AAI7H,MAAa,uBAAuB,YAA6D;CAC/F,MAAM,qBAAqB,QAAQ,SAAS,QAAQ,QAAQ,GAAG;CAC/D,MAAM,aAAa,mBAAmB,SAAS,IAAI,WAAW,uBAAuB;AACrF,QAAO,8BAA8B;EACnC,WAAW,QAAQ;EACnB;EACA,2BAA2B,QAAQ;EACnC,0BAA0B,QAAQ;EAClC,oBAAoB,QAAQ;EAC7B,CAAC;;AAGJ,MAAM,uBAAuB,QAAyB;AACpD,KAAI,IAAI,WAAW,KAAK,CACtB,QAAO;AAET,QAAO,CAAC,kBAAkB,KAAK,IAAI;;AAGrC,MAAa,2BAA2B,YAIzB;CACb,MAAM,YAAY,IAAI,IAAI,QAAQ,WAAW,0BAA0B;AAGvE,KAAI,EAFwB,UAAU,aAAa,QAAQ,eACtD,UAAU,SAAS,WAAW,GAAG,QAAQ,YAAY,GAAG,EAE3D,QAAO;AAIT,KAAI,QAAQ,iBAAiB,KAC3B,QAAO;AAGT,QAAO,oBAAoB,QAAQ,UAAU,IAAI,UAAU,WAAW,QAAQ;;AAGhF,MAAM,oBAAoB,YAKZ;AACZ,KAAI,OAAO,QAAQ,WAAW,SAC5B,QAAO,QAAQ;AAGjB,SAAQ,QAAQ,OAAO,MAAvB;EACE,KAAK,oBACH,QAAO,QAAQ;EAEjB,KAAK,SACH,QAAO,oBAAoB;GACzB,WAAW,QAAQ;GACnB,UAAU,gCAAgC,QAAQ,YAAY;GAC/D,CAAC;EAEJ,KAAK,SACH,QAAO,uBAAuB;GAC5B,QAAQ,QAAQ;GAChB,aAAa,QAAQ;GACtB,CAAC;;;AAKR,MAAM,uCAAuC,WAAmC;CAC9E,MAAM,MAAM,OAAO,WAAW,WAC1B,SACA,OAAO,SAAS,WACd,OAAO,MACP;AACN,KAAI,OAAO,QAAQ,CAAC,oBAAoB,IAAI,CAC1C,OAAM,IAAI,uBAAuB,yCAAyC;EACxE,kBAAkB;EAClB,MAAM;EACP,CAAC;;AAIN,MAAa,sBAAsB,YAA6F;CAC9H,MAAM,iBAAiB,QAAQ;CAC/B,MAAM,gBAAgB,gBAAgB,WAAW,EAAE,MAAM,qBAAqB;CAC9E,MAAM,sBAAwC,gBAAgB,kBAC5D,cAAc,SAAS,WACnB,gBACA,EAAE,MAAM,qBAAqB;AAEnC,qCAAoC,oBAAoB;CACxD,IAAI,2BAA2B;AAC/B,KAAI,OAAO,gBAAgB,YAAY,SACrC,4BAA2B,eAAe;UACjC,gBAAgB,WAAW,QAAQ,eAAe,QAAQ,SAAS,SAC5E,4BAA2B,uBAAuB;EAChD,QAAQ,eAAe;EACvB,aAAa;EACd,CAAC;CAGJ,MAAM,OAAO,iBAAiB;EAC5B,QAAQ,gBAAgB,QAAQ;EAChC,cAAc;EACd,aAAa;EACb,WAAW,QAAQ;EACpB,CAAC;CACF,MAAM,cAAc,iBAAiB;EACnC,QAAQ,gBAAgB,eAAe;EACvC,cAAc;EACd,aAAa;EACb,WAAW,QAAQ;EACpB,CAAC;AAEF,QAAO;EACL,SAAS,iBAAiB;GACxB,QAAQ,gBAAgB,WAAW;GACnC,cAAc;GACd,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,QAAQ,iBAAiB;GACvB,QAAQ,gBAAgB,UAAU;GAClC,cAAc,yBAAyB,0BAA0B,UAAU;GAC3E,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,QAAQ,iBAAiB;GACvB,QAAQ,gBAAgB,UAAU;GAClC,cAAc,yBAAyB,0BAA0B,UAAU;GAC3E,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF;EACA,aAAa,iBAAiB;GAC5B,QAAQ,gBAAgB,eAAe;GACvC,cAAc;GACd,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,SAAS,iBAAiB;GACxB,QAAQ,gBAAgB,WAAW;GACnC,cAAc,yBAAyB,0BAA0B,WAAW;GAC5E,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,cAAc,iBAAiB;GAC7B,QAAQ,gBAAgB,gBAAgB;GACxC,cAAc;GACd,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,mBAAmB,iBAAiB;GAClC,QAAQ,gBAAgB,qBAAqB;GAC7C,cAAc,yBAAyB,0BAA0B,qBAAqB;GACtF,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,eAAe,iBAAiB;GAC9B,QAAQ,gBAAgB,iBAAiB;GACzC,cAAc,yBAAyB,0BAA0B,iBAAiB;GAClF,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,gBAAgB,iBAAiB;GAC/B,QAAQ,gBAAgB,kBAAkB;GAC1C,cAAc,yBAAyB,0BAA0B,kBAAkB;GACnF,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF;EACA,eAAe,iBAAiB;GAC9B,QAAQ;GACR,cAAc,yBAAyB,0BAA0B,iBAAiB;GAClF,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,mBAAmB,iBAAiB;GAClC,QAAQ,gBAAgB,qBAAqB;GAC7C,cAAc,yBAAyB,0BAA0B,sBAAsB;GACvF,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,iBAAiB,iBAAiB;GAChC,QAAQ,gBAAgB,mBAAmB;GAC3C,cAAc,yBAAyB,0BAA0B,mBAAmB;GACpF,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,gBAAgB,iBAAiB;GAC/B,QAAQ,gBAAgB,kBAAkB;GAC1C,cAAc,yBAAyB,0BAA0B,kBAAkB;GACnF,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,gBAAgB,iBAAiB;GAC/B,QAAQ,gBAAgB,kBAAkB;GAC1C,cAAc,yBAAyB,0BAA0B,mBAAmB;GACpF,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,KAAK,iBAAiB;GACpB,QAAQ,gBAAgB,OAAO;GAC/B,cAAc,yBAAyB,0BAA0B,MAAM;GACvE,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,OAAO,iBAAiB;GACtB,QAAQ,gBAAgB,SAAS;GACjC,cAAc,yBAAyB,0BAA0B,QAAQ;GACzE,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,YAAY,iBAAiB;GAC3B,QAAQ,gBAAgB,cAAc;GACtC,cAAc,yBAAyB,0BAA0B,aAAa;GAC9E,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACH;;AAGH,MAAa,0BAA0B,YAKzB;CACZ,MAAM,MAAM,IAAI,IAAI,QAAQ,mBAAmB,QAAQ,OAAO;AAC9D,KAAI,aAAa,IAAI,cAAc,QAAQ,UAAU;AACrD,QAAO,IAAI,UAAU;;AAGvB,MAAa,wCAAwC,YAIhC;AAGnB,UAFsB,QAAQ,iBAAiB,EAAE,MAAM,qBAAqB,EAEtD,MAAtB;EACE,KAAK,oBACH,QAAO;EAET,KAAK,SACH,QAAO,oBAAoB;GACzB,WAAW,QAAQ;GACnB,UAAU,QAAQ;GACnB,CAAC;;;AAKR,SAAgB,cAAc,UAAkB,gBAA4H;AAC1K,KAAI,EAAE,YAAY,mBAAoB,QAAO;CAC7C,MAAM,SAAS,kBAAkB;CACjC,MAAM,cAAc,OAAO,KAAK,OAAO,SAAS,CAAC,IAAI,OAAO;CAC5D,MAAM,gBAAgB,YAAY,SAAS,IAAI,KAAK,IAAI,GAAG,YAAY,GAAG;CAE1E,IAAI,gBAA+B;AACnC,KAAI,kBAAkB,MAAM;EAI1B,MAAM,UAHmB,YACtB,QAAO,MAAK,IAAI,eAAe,CAC/B,MAAM,GAAG,MAAM,IAAI,EAAE,CAErB,KAAI,MAAK,OAAO,SAAS,GAAG,cAAc,CAC1C,QAAO,MAAK,EAAE,SAAS,EAAE;AAC5B,kBAAgB,QAAQ,SAAS,IAAI,QAAQ,KAAK,OAAO,GAAG;OAG5D,kBADqB,gBAAgB,IAAI,OAAO,SAAS,iBAAiB,SAC5C,iBAAiB;AAGjD,QAAO;EAAE,OAAO,OAAO;EAAO,YAAY,OAAO;EAAY;EAAe;EAAe;;AAG7F,MAAa,gCAAgC,YAAyD;CACpG,IAAI;AACJ,KAAI;AACF,cAAY,IAAI,IAAI,QAAQ,IAAI;SAC1B;AACN,SAAO;;CAGT,MAAM,gBAAgB,IAAI,IAAI,oBAAoB;EAAE,WAAW,QAAQ;EAAW,UAAU;EAAI,CAAC,CAAC;AAClG,QAAO,UAAU,WAAW,cAAc,WACpC,UAAU,aAAa,cAAc,YAAY,UAAU,SAAS,WAAW,GAAG,cAAc,SAAS,GAAG"}
|
|
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 \"../../generated/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.HEXCLAVE_HOSTED_HANDLER_DOMAIN_SUFFIX,\n hostedHandlerUrlTemplate: envVars.HEXCLAVE_HOSTED_HANDLER_URL_TEMPLATE,\n hexclavePortPrefix: envVars.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":";;;;;;AAUA,MAAM,4BAA4B;AAClC,MAAM,oBAAoB;AAE1B,MAAM,oBAAsF,sBAAsB;AAElH,MAAM,4BAA4B,UAAkB,aAA6B;CAC/E,MAAM,qBAAqB,SAAS,SAAS,IAAI,IAAI,SAAS,SAAS,IACnE,SAAS,MAAM,GAAG,GAAG,GACrB;AACJ,KAAI,SAAS,WAAW,EACtB,QAAO;AAET,KAAI,uBAAuB,IACzB,QAAO,IAAI;AAEb,QAAO,GAAG,mBAAmB,GAAG;;AAGlC,MAAM,mCAAmC,gBAA2C;AAClF,SAAQ,aAAR;EACE,KAAK,UACH,QAAO;EAET,KAAK,OACH,QAAO;EAET,KAAK,cACH,QAAO;EAET,KAAK,cACH,QAAO;EAET,KAAK,eACH,QAAO;EAET,KAAK,SACH,QAAO;EAET,KAAK,SACH,QAAO;EAET,KAAK,UACH,QAAO;EAET,KAAK,oBACH,QAAO;EAET,KAAK,gBACH,QAAO;EAET,KAAK,iBACH,QAAO;EAET,KAAK,gBACH,QAAO;EAET,KAAK,oBACH,QAAO;EAET,KAAK,kBACH,QAAO;EAET,KAAK,iBACH,QAAO;EAET,KAAK,iBACH,QAAO;EAET,KAAK,MACH,QAAO;EAET,KAAK,QACH,QAAO;EAET,KAAK,aACH,QAAO;;;AAKb,MAAM,0BAA0B,YAGlB;CACZ,MAAM,cAAc,QAAQ;AAC5B,KAAI,eAAe,mBAAmB;EACpC,MAAM,mBAAmB,kBAAkB;AAC3C,MAAI,QAAQ,OAAO,YAAY,KAAK,QAAQ,OAAO,WAAW,iBAAiB,SAC7E,QAAO,QAAQ,OAAO;AAGxB,QAAM,IAAI,MAAM,mCAAmC,QAAQ,OAAO,QAAQ,OAAO,QAAQ,YAAY,WAAW,QAAQ,OAAO,IAAI,iDAAiD,KAAK,IAAI,GAAG,GAAG,OAAO,KAAK,iBAAiB,SAAS,CAAC,IAAI,OAAO,CAAC,CAAC,6EAA6E;OAEpU,OAAM,IAAI,MAAM,cAAc,QAAQ,YAAY,uEAAuE;;AAI7H,MAAa,uBAAuB,YAA6D;CAC/F,MAAM,qBAAqB,QAAQ,SAAS,QAAQ,QAAQ,GAAG;CAC/D,MAAM,aAAa,mBAAmB,SAAS,IAAI,WAAW,uBAAuB;AACrF,QAAO,8BAA8B;EACnC,WAAW,QAAQ;EACnB;EACA,2BAA2B,QAAQ;EACnC,0BAA0B,QAAQ;EAClC,oBAAoB,QAAQ;EAC7B,CAAC;;AAGJ,MAAM,uBAAuB,QAAyB;AACpD,KAAI,IAAI,WAAW,KAAK,CACtB,QAAO;AAET,QAAO,CAAC,kBAAkB,KAAK,IAAI;;AAGrC,MAAM,wBAAwB,IAAI,IAAuB;CACvD;CACA;CACA;CACD,CAAC;AAEF,MAAa,2BAA2B,YAIzB;CACb,MAAM,YAAY,IAAI,IAAI,QAAQ,WAAW,0BAA0B;AAGvE,KAAI,EAFwB,UAAU,aAAa,QAAQ,eACtD,UAAU,SAAS,WAAW,GAAG,QAAQ,YAAY,GAAG,EAE3D,QAAO;AAIT,KAAI,QAAQ,iBAAiB,KAC3B,QAAO;AAGT,QAAO,oBAAoB,QAAQ,UAAU,IAAI,UAAU,WAAW,QAAQ;;AAGhF,MAAM,oBAAoB,YAKZ;AACZ,KAAI,OAAO,QAAQ,WAAW,SAC5B,QAAO,QAAQ;AAGjB,SAAQ,QAAQ,OAAO,MAAvB;EACE,KAAK,oBACH,QAAO,QAAQ;EAEjB,KAAK;AACH,OAAI,sBAAsB,IAAI,QAAQ,YAAY,CAChD,QAAO,QAAQ;AAEjB,UAAO,oBAAoB;IACzB,WAAW,QAAQ;IACnB,UAAU,gCAAgC,QAAQ,YAAY;IAC/D,CAAC;EAEJ,KAAK,SACH,QAAO,uBAAuB;GAC5B,QAAQ,QAAQ;GAChB,aAAa,QAAQ;GACtB,CAAC;;;AAKR,MAAM,uCAAuC,WAAmC;CAC9E,MAAM,MAAM,OAAO,WAAW,WAC1B,SACA,OAAO,SAAS,WACd,OAAO,MACP;AACN,KAAI,OAAO,QAAQ,CAAC,oBAAoB,IAAI,CAC1C,OAAM,IAAI,uBAAuB,yCAAyC;EACxE,kBAAkB;EAClB,MAAM;EACP,CAAC;;AAIN,MAAa,sBAAsB,YAA6F;CAC9H,MAAM,iBAAiB,QAAQ;CAC/B,MAAM,gBAAgB,gBAAgB,WAAW,EAAE,MAAM,qBAAqB;CAC9E,MAAM,sBAAwC,gBAAgB,kBAC5D,cAAc,SAAS,WACnB,gBACA,EAAE,MAAM,qBAAqB;AAEnC,qCAAoC,oBAAoB;CACxD,IAAI,2BAA2B;AAC/B,KAAI,OAAO,gBAAgB,YAAY,SACrC,4BAA2B,eAAe;UACjC,gBAAgB,WAAW,QAAQ,eAAe,QAAQ,SAAS,SAC5E,4BAA2B,uBAAuB;EAChD,QAAQ,eAAe;EACvB,aAAa;EACd,CAAC;CAGJ,MAAM,aAAa,gBAAgB,QAAQ;CAC3C,MAAM,YAAY,iBAAiB;EACjC,QAAQ,OAAO,eAAe,YAAY,WAAW,SAAS,WAC1D,EAAE,MAAM,qBAAqB,GAC7B;EACJ,cAAc;EACd,aAAa;EACb,WAAW,QAAQ;EACpB,CAAC;CACF,MAAM,OAAO,iBAAiB;EAC5B,QAAQ;EACR,cAAc;EACd,aAAa;EACb,WAAW,QAAQ;EACpB,CAAC;CACF,MAAM,cAAc,iBAAiB;EACnC,QAAQ,gBAAgB,eAAe;EACvC,cAAc;EACd,aAAa;EACb,WAAW,QAAQ;EACpB,CAAC;AAEF,QAAO;EACL,SAAS,iBAAiB;GACxB,QAAQ,gBAAgB,WAAW;GACnC,cAAc;GACd,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,QAAQ,iBAAiB;GACvB,QAAQ,gBAAgB,UAAU;GAClC,cAAc,yBAAyB,0BAA0B,UAAU;GAC3E,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,QAAQ,iBAAiB;GACvB,QAAQ,gBAAgB,UAAU;GAClC,cAAc,yBAAyB,0BAA0B,UAAU;GAC3E,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF;EACA,aAAa,iBAAiB;GAC5B,QAAQ,gBAAgB,eAAe;GACvC,cAAc;GACd,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,SAAS,iBAAiB;GACxB,QAAQ,gBAAgB,WAAW;GACnC,cAAc,yBAAyB,0BAA0B,WAAW;GAC5E,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,cAAc,iBAAiB;GAC7B,QAAQ,gBAAgB,gBAAgB;GACxC,cAAc;GACd,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,mBAAmB,iBAAiB;GAClC,QAAQ,gBAAgB,qBAAqB;GAC7C,cAAc,yBAAyB,0BAA0B,qBAAqB;GACtF,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,eAAe,iBAAiB;GAC9B,QAAQ,gBAAgB,iBAAiB;GACzC,cAAc,yBAAyB,0BAA0B,iBAAiB;GAClF,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,gBAAgB,iBAAiB;GAC/B,QAAQ,gBAAgB,kBAAkB;GAC1C,cAAc,yBAAyB,0BAA0B,kBAAkB;GACnF,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF;EACA,eAAe,iBAAiB;GAC9B,QAAQ;GACR,cAAc,yBAAyB,0BAA0B,iBAAiB;GAClF,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,mBAAmB,iBAAiB;GAClC,QAAQ,gBAAgB,qBAAqB;GAC7C,cAAc,yBAAyB,0BAA0B,sBAAsB;GACvF,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,iBAAiB,iBAAiB;GAChC,QAAQ,gBAAgB,mBAAmB;GAC3C,cAAc,yBAAyB,0BAA0B,mBAAmB;GACpF,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,gBAAgB,iBAAiB;GAC/B,QAAQ,gBAAgB,kBAAkB;GAC1C,cAAc,yBAAyB,0BAA0B,kBAAkB;GACnF,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,gBAAgB,iBAAiB;GAC/B,QAAQ,gBAAgB,kBAAkB;GAC1C,cAAc,yBAAyB,0BAA0B,mBAAmB;GACpF,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,KAAK,iBAAiB;GACpB,QAAQ,gBAAgB,OAAO;GAC/B,cAAc,yBAAyB,0BAA0B,MAAM;GACvE,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,OAAO,iBAAiB;GACtB,QAAQ,gBAAgB,SAAS;GACjC,cAAc,yBAAyB,0BAA0B,QAAQ;GACzE,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACF,YAAY,iBAAiB;GAC3B,QAAQ,gBAAgB,cAAc;GACtC,cAAc,yBAAyB,0BAA0B,aAAa;GAC9E,aAAa;GACb,WAAW,QAAQ;GACpB,CAAC;EACH;;AAGH,MAAa,0BAA0B,YAKzB;CACZ,MAAM,MAAM,IAAI,IAAI,QAAQ,mBAAmB,QAAQ,OAAO;AAC9D,KAAI,aAAa,IAAI,cAAc,QAAQ,UAAU;AACrD,QAAO,IAAI,UAAU;;AAGvB,MAAa,wCAAwC,YAIhC;AAGnB,UAFsB,QAAQ,iBAAiB,EAAE,MAAM,qBAAqB,EAEtD,MAAtB;EACE,KAAK,oBACH,QAAO;EAET,KAAK,SACH,QAAO,oBAAoB;GACzB,WAAW,QAAQ;GACnB,UAAU,QAAQ;GACnB,CAAC;;;AAKR,SAAgB,cAAc,UAAkB,gBAA4H;AAC1K,KAAI,EAAE,YAAY,mBAAoB,QAAO;CAC7C,MAAM,SAAS,kBAAkB;CACjC,MAAM,cAAc,OAAO,KAAK,OAAO,SAAS,CAAC,IAAI,OAAO;CAC5D,MAAM,gBAAgB,YAAY,SAAS,IAAI,KAAK,IAAI,GAAG,YAAY,GAAG;CAE1E,IAAI,gBAA+B;AACnC,KAAI,kBAAkB,MAAM;EAI1B,MAAM,UAHmB,YACtB,QAAO,MAAK,IAAI,eAAe,CAC/B,MAAM,GAAG,MAAM,IAAI,EAAE,CAErB,KAAI,MAAK,OAAO,SAAS,GAAG,cAAc,CAC1C,QAAO,MAAK,EAAE,SAAS,EAAE;AAC5B,kBAAgB,QAAQ,SAAS,IAAI,QAAQ,KAAK,OAAO,GAAG;OAG5D,kBADqB,gBAAgB,IAAI,OAAO,SAAS,iBAAiB,SAC5C,iBAAiB;AAGjD,QAAO;EAAE,OAAO,OAAO;EAAO,YAAY,OAAO;EAAY;EAAe;EAAe;;AAG7F,MAAa,gCAAgC,YAAyD;CACpG,IAAI;AACJ,KAAI;AACF,cAAY,IAAI,IAAI,QAAQ,IAAI;SAC1B;AACN,SAAO;;CAGT,MAAM,gBAAgB,IAAI,IAAI,oBAAoB;EAAE,WAAW,QAAQ;EAAW,UAAU;EAAI,CAAC,CAAC;AAClG,QAAO,UAAU,WAAW,cAAc,WACpC,UAAU,aAAa,cAAc,YAAY,UAAU,SAAS,WAAW,GAAG,cAAc,SAAS,GAAG"}
|
|
@@ -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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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/generated/env.d.ts
|
|
2
|
+
declare const envVars: {
|
|
3
|
+
readonly HEXCLAVE_PORT_PREFIX: any;
|
|
4
|
+
readonly HEXCLAVE_PROJECT_ID: any;
|
|
5
|
+
readonly HEXCLAVE_PUBLISHABLE_CLIENT_KEY: any;
|
|
6
|
+
readonly HEXCLAVE_SECRET_SERVER_KEY: any;
|
|
7
|
+
readonly HEXCLAVE_SUPER_SECRET_ADMIN_KEY: any;
|
|
8
|
+
readonly HEXCLAVE_EXTRA_REQUEST_HEADERS: any;
|
|
9
|
+
readonly HEXCLAVE_API_URL_BROWSER: any;
|
|
10
|
+
readonly HEXCLAVE_API_URL_SERVER: any;
|
|
11
|
+
readonly HEXCLAVE_API_URL: any;
|
|
12
|
+
readonly HEXCLAVE_HOSTED_HANDLER_DOMAIN_SUFFIX: any;
|
|
13
|
+
readonly HEXCLAVE_HOSTED_HANDLER_URL_TEMPLATE: any;
|
|
14
|
+
readonly HEXCLAVE_STRIPE_PUBLISHABLE_KEY: any;
|
|
15
|
+
readonly HEXCLAVE_BOT_CHALLENGE_SITE_KEY: any;
|
|
16
|
+
readonly HEXCLAVE_BOT_CHALLENGE_INVISIBLE_SITE_KEY: any;
|
|
17
|
+
readonly HEXCLAVE_IS_LOCAL_EMULATOR: any;
|
|
18
|
+
readonly HEXCLAVE_POSTHOG_KEY: any;
|
|
19
|
+
readonly HEXCLAVE_SVIX_SERVER_URL: any;
|
|
20
|
+
readonly HEXCLAVE_SENTRY_DSN: any;
|
|
21
|
+
readonly HEXCLAVE_VERSION_ALERTER_SEVERE_ONLY: any;
|
|
22
|
+
readonly NODE_ENV: any;
|
|
23
|
+
};
|
|
24
|
+
//#endregion
|
|
25
|
+
export { envVars };
|
|
26
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.d.ts","names":[],"sources":["../../src/
|
|
1
|
+
{"version":3,"file":"env.d.ts","names":[],"sources":["../../src/generated/env.ts"],"mappings":";cAIa,OAAA;EAAA"}
|