@hexclave/js 1.0.115 → 1.0.117
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{admin-app-impl-BlUeKEd3.d.ts → admin-app-impl-C6zvB2sD.d.ts} +8 -7
- package/dist/admin-app-impl-C6zvB2sD.d.ts.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +4 -4
- package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cookie.test.d.ts +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cookie.test.js +166 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cookie.test.js.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +3 -2
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js +20 -9
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.next-server-session.test.js +0 -10
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.next-server-session.test.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/common.js +2 -2
- package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cookie.test.d.ts +1 -0
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cookie.test.js +165 -0
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cookie.test.js.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js +20 -9
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.next-server-session.test.js +0 -10
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.next-server-session.test.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/common.js +2 -2
- package/dist/lib/hexclave-app/apps/implementations/index.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -1
- package/package.json +2 -2
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.cookie.test.ts +176 -0
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.next-server-session.test.ts +1 -12
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.ts +35 -10
- package/dist/admin-app-impl-BlUeKEd3.d.ts.map +0 -1
package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.next-server-session.test.js
CHANGED
|
@@ -23,16 +23,6 @@ function createClientApp() {
|
|
|
23
23
|
});
|
|
24
24
|
}
|
|
25
25
|
describe("StackClientApp Next.js server sessions", () => {
|
|
26
|
-
it("shares one token store and session across cookie helpers from the same request", () => {
|
|
27
|
-
const clientApp = createClientApp();
|
|
28
|
-
const getTokenStore = Reflect.get(clientApp, "_getOrCreateTokenStore");
|
|
29
|
-
const getSession = Reflect.get(clientApp, "_getSessionFromTokenStore");
|
|
30
|
-
const requestIdentity = {};
|
|
31
|
-
const firstStore = getTokenStore.call(clientApp, createCookieHelper(requestIdentity), "nextjs-cookie");
|
|
32
|
-
const secondStore = getTokenStore.call(clientApp, createCookieHelper(requestIdentity), "nextjs-cookie");
|
|
33
|
-
expect(secondStore).toBe(firstStore);
|
|
34
|
-
expect(getSession.call(clientApp, secondStore)).toBe(getSession.call(clientApp, firstStore));
|
|
35
|
-
});
|
|
36
26
|
it("isolates token stores belonging to different requests", () => {
|
|
37
27
|
const clientApp = createClientApp();
|
|
38
28
|
const getTokenStore = Reflect.get(clientApp, "_getOrCreateTokenStore");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-app-impl.next-server-session.test.js","names":[],"sources":["../../../../../../src/lib/hexclave-app/apps/implementations/client-app-impl.next-server-session.test.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { describe, expect, it } from \"vitest\";\nimport { CookieHelper } from \"../../../cookie\";\nimport { StackClientApp } from \"../interfaces/client-app\";\n\nfunction createCookieHelper(identity: object): CookieHelper {\n return {\n identity,\n get: () => null,\n getAll: () => ({}),\n set: () => {},\n setOrDelete: () => {},\n delete: () => {},\n };\n}\n\nfunction createClientApp() {\n return new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000000\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"none\",\n noAutomaticPrefetch: true,\n devTool: false,\n });\n}\n\ndescribe(\"StackClientApp Next.js server sessions\", () => {\n
|
|
1
|
+
{"version":3,"file":"client-app-impl.next-server-session.test.js","names":[],"sources":["../../../../../../src/lib/hexclave-app/apps/implementations/client-app-impl.next-server-session.test.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { describe, expect, it } from \"vitest\";\nimport { CookieHelper } from \"../../../cookie\";\nimport { StackClientApp } from \"../interfaces/client-app\";\n\nfunction createCookieHelper(identity: object): CookieHelper {\n return {\n identity,\n get: () => null,\n getAll: () => ({}),\n set: () => {},\n setOrDelete: () => {},\n delete: () => {},\n };\n}\n\nfunction createClientApp() {\n return new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId: \"00000000-0000-4000-8000-000000000000\",\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"none\",\n noAutomaticPrefetch: true,\n devTool: false,\n });\n}\n\ndescribe(\"StackClientApp Next.js server sessions\", () => {\n // Only the Next.js SDK keys server token stores by the request's cookies() identity.\n\n it(\"isolates token stores belonging to different requests\", () => {\n const clientApp = createClientApp();\n const getTokenStore = Reflect.get(clientApp, \"_getOrCreateTokenStore\");\n\n const firstStore = getTokenStore.call(clientApp, createCookieHelper({}), \"nextjs-cookie\");\n const secondStore = getTokenStore.call(clientApp, createCookieHelper({}), \"nextjs-cookie\");\n\n expect(secondStore).not.toBe(firstStore);\n });\n});\n"],"mappings":";;;AAQA,SAAS,mBAAmB,UAAgC;CAC1D,OAAO;EACL;EACA,WAAW;EACX,eAAe,CAAC;EAChB,WAAW,CAAC;EACZ,mBAAmB,CAAC;EACpB,cAAc,CAAC;CACjB;AACF;AAEA,SAAS,kBAAkB;CACzB,OAAO,IAAI,eAAe;EACxB,SAAS;EACT,WAAW;EACX,sBAAsB;EACtB,YAAY;EACZ,gBAAgB;EAChB,qBAAqB;EACrB,SAAS;CACX,CAAC;AACH;AAEA,SAAS,gDAAgD;CAGvD,GAAG,+DAA+D;EAChE,MAAM,YAAY,gBAAgB;EAClC,MAAM,gBAAgB,QAAQ,IAAI,WAAW,wBAAwB;EAErE,MAAM,aAAa,cAAc,KAAK,WAAW,mBAAmB,CAAC,CAAC,GAAG,eAAe;EAGxF,OAFoB,cAAc,KAAK,WAAW,mBAAmB,CAAC,CAAC,GAAG,eAEzD,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU;CACzC,CAAC;AACH,CAAC"}
|
|
@@ -12,8 +12,8 @@ import { resolveHandlerUrls } from "../../url-targets.js";
|
|
|
12
12
|
import { AsyncCache } from "@hexclave/shared/dist/utils/caches";
|
|
13
13
|
import { createGlobal, getGlobal } from "@hexclave/shared/dist/utils/globals";
|
|
14
14
|
//#region src/lib/hexclave-app/apps/implementations/common.ts
|
|
15
|
-
const clientVersion = "js @hexclave/js@1.0.
|
|
16
|
-
if ("js @hexclave/js@1.0.
|
|
15
|
+
const clientVersion = "js @hexclave/js@1.0.117";
|
|
16
|
+
if ("js @hexclave/js@1.0.117".startsWith("STACK_COMPILE_TIME"));
|
|
17
17
|
const replaceHexclavePortPrefix = (input) => {
|
|
18
18
|
if (!input) return input;
|
|
19
19
|
const prefix = envVars.HEXCLAVE_PORT_PREFIX;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as _HexclaveAdminAppImplIncomplete } from "../../../../admin-app-impl-
|
|
1
|
+
import { t as _HexclaveAdminAppImplIncomplete } from "../../../../admin-app-impl-C6zvB2sD.js";
|
|
2
2
|
export { _HexclaveAdminAppImplIncomplete };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
let vitest = require("vitest");
|
|
2
|
+
let _hexclave_shared_dist_utils_redirect_urls = require("@hexclave/shared/dist/utils/redirect-urls");
|
|
3
|
+
let _hexclave_shared_dist_utils_bytes = require("@hexclave/shared/dist/utils/bytes");
|
|
4
|
+
let ___interfaces_client_app_js = require("../interfaces/client-app.js");
|
|
5
|
+
let util = require("util");
|
|
6
|
+
//#region src/lib/hexclave-app/apps/implementations/client-app-impl.cookie.test.ts
|
|
7
|
+
const serverCookieState = vitest.vi.hoisted(() => ({ values: /* @__PURE__ */ new Map() }));
|
|
8
|
+
vitest.vi.mock("../../../cookie", () => {
|
|
9
|
+
const getAll = () => Object.fromEntries(serverCookieState.values);
|
|
10
|
+
const remove = (name) => {
|
|
11
|
+
serverCookieState.values.delete(name);
|
|
12
|
+
};
|
|
13
|
+
const setOrDelete = (name, value) => {
|
|
14
|
+
if (value === null) remove(name);
|
|
15
|
+
else serverCookieState.values.set(name, value);
|
|
16
|
+
};
|
|
17
|
+
const helper = {
|
|
18
|
+
identity: {},
|
|
19
|
+
get: (name) => serverCookieState.values.get(name) ?? null,
|
|
20
|
+
getAll,
|
|
21
|
+
set: (name, value) => setOrDelete(name, value),
|
|
22
|
+
setOrDelete,
|
|
23
|
+
delete: remove
|
|
24
|
+
};
|
|
25
|
+
return {
|
|
26
|
+
createBrowserCookieHelper: () => helper,
|
|
27
|
+
createCookieHelper: async () => helper,
|
|
28
|
+
createPlaceholderCookieHelper: async () => helper,
|
|
29
|
+
deleteCookie: async (name) => remove(name),
|
|
30
|
+
deleteCookieClient: remove,
|
|
31
|
+
getCookieClient: (name) => serverCookieState.values.get(name) ?? null,
|
|
32
|
+
isSecure: async () => true,
|
|
33
|
+
saveVerifierAndState: async () => {
|
|
34
|
+
throw new Error("saveVerifierAndState is not used in this test");
|
|
35
|
+
},
|
|
36
|
+
setOrDeleteCookie: async (name, value) => setOrDelete(name, value),
|
|
37
|
+
setOrDeleteCookieClient: setOrDelete
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
(0, vitest.describe)("StackClientApp custom refresh cookie updates", () => {
|
|
41
|
+
(0, vitest.it)("preserves the existing custom and default cookies without a server hostname", async () => {
|
|
42
|
+
(0, vitest.expect)((0, _hexclave_shared_dist_utils_redirect_urls.getTrustedParentDomain)("_.example.com", ["https://example.com", "https://**.example.com"])).toBe("example.com");
|
|
43
|
+
const projectId = "00000000-0000-4000-8000-000000000000";
|
|
44
|
+
const customCookieName = `hexclave-refresh-${projectId}--custom-${(0, _hexclave_shared_dist_utils_bytes.encodeBase32)(new util.TextEncoder().encode("example.com"))}`;
|
|
45
|
+
const defaultCookieName = `__Host-hexclave-refresh-${projectId}--default`;
|
|
46
|
+
serverCookieState.values.clear();
|
|
47
|
+
serverCookieState.values.set(defaultCookieName, JSON.stringify({
|
|
48
|
+
refresh_token: "old-refresh",
|
|
49
|
+
updated_at_millis: 1
|
|
50
|
+
}));
|
|
51
|
+
serverCookieState.values.set(customCookieName, JSON.stringify({
|
|
52
|
+
refresh_token: "old-refresh",
|
|
53
|
+
updated_at_millis: 1
|
|
54
|
+
}));
|
|
55
|
+
const clientApp = new ___interfaces_client_app_js.StackClientApp({
|
|
56
|
+
baseUrl: "http://localhost:12345",
|
|
57
|
+
projectId,
|
|
58
|
+
publishableClientKey: "stack-pk-test",
|
|
59
|
+
tokenStore: "memory",
|
|
60
|
+
redirectMethod: "none",
|
|
61
|
+
noAutomaticPrefetch: true,
|
|
62
|
+
devTool: false
|
|
63
|
+
});
|
|
64
|
+
const trustedParentLookups = [];
|
|
65
|
+
Reflect.set(clientApp, "_getTrustedParentDomain", async (domain) => {
|
|
66
|
+
trustedParentLookups.push(domain);
|
|
67
|
+
return domain === "_.example.com" ? "example.com" : null;
|
|
68
|
+
});
|
|
69
|
+
const tokenStore = Reflect.get(clientApp, "_getOrCreateTokenStore").call(clientApp, {
|
|
70
|
+
identity: {},
|
|
71
|
+
get: (name) => serverCookieState.values.get(name) ?? null,
|
|
72
|
+
getAll: () => Object.fromEntries(serverCookieState.values),
|
|
73
|
+
set: (name, value) => serverCookieState.values.set(name, value),
|
|
74
|
+
setOrDelete: (name, value) => {
|
|
75
|
+
if (value === null) serverCookieState.values.delete(name);
|
|
76
|
+
else serverCookieState.values.set(name, value);
|
|
77
|
+
},
|
|
78
|
+
delete: (name) => serverCookieState.values.delete(name)
|
|
79
|
+
}, "nextjs-cookie");
|
|
80
|
+
const warnSpy = vitest.vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
81
|
+
tokenStore.set({
|
|
82
|
+
accessToken: "new-access",
|
|
83
|
+
refreshToken: "new-refresh"
|
|
84
|
+
});
|
|
85
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
86
|
+
vitest.expect.soft(warnSpy).not.toHaveBeenCalled();
|
|
87
|
+
const customCookieValue = serverCookieState.values.get(customCookieName);
|
|
88
|
+
vitest.expect.soft(customCookieValue).toBeDefined();
|
|
89
|
+
if (customCookieValue != null) vitest.expect.soft(JSON.parse(customCookieValue)).toEqual({
|
|
90
|
+
refresh_token: "new-refresh",
|
|
91
|
+
updated_at_millis: vitest.expect.any(Number)
|
|
92
|
+
});
|
|
93
|
+
vitest.expect.soft(serverCookieState.values.has(defaultCookieName)).toBe(true);
|
|
94
|
+
vitest.expect.soft(trustedParentLookups).toEqual(["_.example.com"]);
|
|
95
|
+
warnSpy.mockRestore();
|
|
96
|
+
});
|
|
97
|
+
(0, vitest.it)("recovers the custom cookie after overlapping server updates", async () => {
|
|
98
|
+
const projectId = "00000000-0000-4000-8000-000000000001";
|
|
99
|
+
const customCookieName = `hexclave-refresh-${projectId}--custom-${(0, _hexclave_shared_dist_utils_bytes.encodeBase32)(new util.TextEncoder().encode("example.com"))}`;
|
|
100
|
+
const defaultCookieName = `__Host-hexclave-refresh-${projectId}--default`;
|
|
101
|
+
serverCookieState.values.clear();
|
|
102
|
+
serverCookieState.values.set(defaultCookieName, JSON.stringify({
|
|
103
|
+
refresh_token: "old-refresh",
|
|
104
|
+
updated_at_millis: 1
|
|
105
|
+
}));
|
|
106
|
+
serverCookieState.values.set(customCookieName, JSON.stringify({
|
|
107
|
+
refresh_token: "old-refresh",
|
|
108
|
+
updated_at_millis: 1
|
|
109
|
+
}));
|
|
110
|
+
const clientApp = new ___interfaces_client_app_js.StackClientApp({
|
|
111
|
+
baseUrl: "http://localhost:12345",
|
|
112
|
+
projectId,
|
|
113
|
+
publishableClientKey: "stack-pk-test",
|
|
114
|
+
tokenStore: "memory",
|
|
115
|
+
redirectMethod: "none",
|
|
116
|
+
noAutomaticPrefetch: true,
|
|
117
|
+
devTool: false
|
|
118
|
+
});
|
|
119
|
+
let releaseTrustedParentLookup;
|
|
120
|
+
let shouldBlockTrustedParentLookup = true;
|
|
121
|
+
Reflect.set(clientApp, "_getTrustedParentDomain", async (domain) => {
|
|
122
|
+
if (shouldBlockTrustedParentLookup) {
|
|
123
|
+
shouldBlockTrustedParentLookup = false;
|
|
124
|
+
await new Promise((resolve) => {
|
|
125
|
+
releaseTrustedParentLookup = resolve;
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return domain === "_.example.com" ? "example.com" : null;
|
|
129
|
+
});
|
|
130
|
+
const tokenStore = Reflect.get(clientApp, "_getOrCreateTokenStore").call(clientApp, {
|
|
131
|
+
identity: {},
|
|
132
|
+
get: (name) => serverCookieState.values.get(name) ?? null,
|
|
133
|
+
getAll: () => Object.fromEntries(serverCookieState.values),
|
|
134
|
+
set: (name, value) => serverCookieState.values.set(name, value),
|
|
135
|
+
setOrDelete: (name, value) => {
|
|
136
|
+
if (value === null) serverCookieState.values.delete(name);
|
|
137
|
+
else serverCookieState.values.set(name, value);
|
|
138
|
+
},
|
|
139
|
+
delete: (name) => serverCookieState.values.delete(name)
|
|
140
|
+
}, "nextjs-cookie");
|
|
141
|
+
tokenStore.set({
|
|
142
|
+
accessToken: "first-access",
|
|
143
|
+
refreshToken: "first-refresh"
|
|
144
|
+
});
|
|
145
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
146
|
+
if (releaseTrustedParentLookup == null) throw new Error("Expected the first custom cookie recovery lookup to be pending.");
|
|
147
|
+
tokenStore.set({
|
|
148
|
+
accessToken: "second-access",
|
|
149
|
+
refreshToken: "second-refresh"
|
|
150
|
+
});
|
|
151
|
+
releaseTrustedParentLookup();
|
|
152
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
153
|
+
const customCookieValue = serverCookieState.values.get(customCookieName);
|
|
154
|
+
(0, vitest.expect)(customCookieValue).toBeDefined();
|
|
155
|
+
if (customCookieValue == null) throw new Error("Expected the custom refresh cookie to be recovered.");
|
|
156
|
+
(0, vitest.expect)(JSON.parse(customCookieValue)).toMatchObject({
|
|
157
|
+
refresh_token: "second-refresh",
|
|
158
|
+
updated_at_millis: vitest.expect.any(Number)
|
|
159
|
+
});
|
|
160
|
+
(0, vitest.expect)(serverCookieState.values.has(defaultCookieName)).toBe(true);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
//#endregion
|
|
164
|
+
|
|
165
|
+
//# sourceMappingURL=client-app-impl.cookie.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-app-impl.cookie.test.js","names":["vi","TextEncoder","StackClientApp","expect"],"sources":["../../../../../src/lib/hexclave-app/apps/implementations/client-app-impl.cookie.test.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { describe, expect, it, vi } from \"vitest\";\nimport { encodeBase32 } from \"@hexclave/shared/dist/utils/bytes\";\nimport { getTrustedParentDomain } from \"@hexclave/shared/dist/utils/redirect-urls\";\nimport { TextEncoder } from \"util\";\nimport type { CookieHelper } from \"../../../cookie\";\nimport { StackClientApp } from \"../interfaces/client-app\";\n\nconst serverCookieState = vi.hoisted(() => ({\n values: new Map<string, string>(),\n}));\n\nvi.mock(\"../../../cookie\", () => {\n const getAll = () => Object.fromEntries(serverCookieState.values);\n const remove = (name: string) => {\n serverCookieState.values.delete(name);\n };\n const setOrDelete = (name: string, value: string | null) => {\n if (value === null) {\n remove(name);\n } else {\n serverCookieState.values.set(name, value);\n }\n };\n const helper = {\n identity: {},\n get: (name: string) => serverCookieState.values.get(name) ?? null,\n getAll,\n set: (name: string, value: string) => setOrDelete(name, value),\n setOrDelete,\n delete: remove,\n };\n return {\n createBrowserCookieHelper: () => helper,\n createCookieHelper: async () => helper,\n createPlaceholderCookieHelper: async () => helper,\n deleteCookie: async (name: string) => remove(name),\n deleteCookieClient: remove,\n getCookieClient: (name: string) => serverCookieState.values.get(name) ?? null,\n isSecure: async () => true,\n saveVerifierAndState: async () => {\n throw new Error(\"saveVerifierAndState is not used in this test\");\n },\n setOrDeleteCookie: async (name: string, value: string | null) => setOrDelete(name, value),\n setOrDeleteCookieClient: setOrDelete,\n };\n});\n\ndescribe(\"StackClientApp custom refresh cookie updates\", () => {\n it(\"preserves the existing custom and default cookies without a server hostname\", async () => {\n expect(getTrustedParentDomain(\"_.example.com\", [\"https://example.com\", \"https://**.example.com\"])).toBe(\"example.com\");\n const projectId = \"00000000-0000-4000-8000-000000000000\";\n const customCookieName = `hexclave-refresh-${projectId}--custom-${encodeBase32(new TextEncoder().encode(\"example.com\"))}`;\n const defaultCookieName = `__Host-hexclave-refresh-${projectId}--default`;\n serverCookieState.values.clear();\n serverCookieState.values.set(defaultCookieName, JSON.stringify({ refresh_token: \"old-refresh\", updated_at_millis: 1 }));\n serverCookieState.values.set(customCookieName, JSON.stringify({ refresh_token: \"old-refresh\", updated_at_millis: 1 }));\n\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId,\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"none\",\n noAutomaticPrefetch: true,\n devTool: false,\n });\n const trustedParentLookups: string[] = [];\n Reflect.set(clientApp, \"_getTrustedParentDomain\", async (domain: string) => {\n trustedParentLookups.push(domain);\n return domain === \"_.example.com\" ? \"example.com\" : null;\n });\n const getOrCreateTokenStore = Reflect.get(clientApp, \"_getOrCreateTokenStore\");\n const cookieHelper: CookieHelper = {\n identity: {},\n get: (name: string) => serverCookieState.values.get(name) ?? null,\n getAll: () => Object.fromEntries(serverCookieState.values),\n set: (name: string, value: string) => serverCookieState.values.set(name, value),\n setOrDelete: (name: string, value: string | null) => {\n if (value === null) {\n serverCookieState.values.delete(name);\n } else {\n serverCookieState.values.set(name, value);\n }\n },\n delete: (name: string) => serverCookieState.values.delete(name),\n };\n const tokenStore = getOrCreateTokenStore.call(clientApp, cookieHelper, \"nextjs-cookie\");\n const warnSpy = vi.spyOn(console, \"warn\").mockImplementation(() => {});\n\n tokenStore.set({ accessToken: \"new-access\", refreshToken: \"new-refresh\" });\n await new Promise((resolve) => setTimeout(resolve, 0));\n\n expect.soft(warnSpy).not.toHaveBeenCalled();\n const customCookieValue = serverCookieState.values.get(customCookieName);\n expect.soft(customCookieValue).toBeDefined();\n if (customCookieValue != null) {\n expect.soft(JSON.parse(customCookieValue)).toEqual({\n refresh_token: \"new-refresh\",\n updated_at_millis: expect.any(Number),\n });\n }\n expect.soft(serverCookieState.values.has(defaultCookieName)).toBe(true);\n expect.soft(trustedParentLookups).toEqual([\"_.example.com\"]);\n warnSpy.mockRestore();\n });\n\n it(\"recovers the custom cookie after overlapping server updates\", async () => {\n const projectId = \"00000000-0000-4000-8000-000000000001\";\n const customCookieName = `hexclave-refresh-${projectId}--custom-${encodeBase32(new TextEncoder().encode(\"example.com\"))}`;\n const defaultCookieName = `__Host-hexclave-refresh-${projectId}--default`;\n serverCookieState.values.clear();\n serverCookieState.values.set(defaultCookieName, JSON.stringify({ refresh_token: \"old-refresh\", updated_at_millis: 1 }));\n serverCookieState.values.set(customCookieName, JSON.stringify({ refresh_token: \"old-refresh\", updated_at_millis: 1 }));\n\n const clientApp = new StackClientApp({\n baseUrl: \"http://localhost:12345\",\n projectId,\n publishableClientKey: \"stack-pk-test\",\n tokenStore: \"memory\",\n redirectMethod: \"none\",\n noAutomaticPrefetch: true,\n devTool: false,\n });\n let releaseTrustedParentLookup: (() => void) | undefined;\n let shouldBlockTrustedParentLookup = true;\n Reflect.set(clientApp, \"_getTrustedParentDomain\", async (domain: string) => {\n if (shouldBlockTrustedParentLookup) {\n shouldBlockTrustedParentLookup = false;\n await new Promise<void>((resolve) => {\n releaseTrustedParentLookup = resolve;\n });\n }\n return domain === \"_.example.com\" ? \"example.com\" : null;\n });\n const getOrCreateTokenStore = Reflect.get(clientApp, \"_getOrCreateTokenStore\");\n const cookieHelper: CookieHelper = {\n identity: {},\n get: (name: string) => serverCookieState.values.get(name) ?? null,\n getAll: () => Object.fromEntries(serverCookieState.values),\n set: (name: string, value: string) => serverCookieState.values.set(name, value),\n setOrDelete: (name: string, value: string | null) => {\n if (value === null) {\n serverCookieState.values.delete(name);\n } else {\n serverCookieState.values.set(name, value);\n }\n },\n delete: (name: string) => serverCookieState.values.delete(name),\n };\n const tokenStore = getOrCreateTokenStore.call(clientApp, cookieHelper, \"nextjs-cookie\");\n\n tokenStore.set({ accessToken: \"first-access\", refreshToken: \"first-refresh\" });\n await new Promise((resolve) => setTimeout(resolve, 0));\n if (releaseTrustedParentLookup == null) {\n throw new Error(\"Expected the first custom cookie recovery lookup to be pending.\");\n }\n tokenStore.set({ accessToken: \"second-access\", refreshToken: \"second-refresh\" });\n releaseTrustedParentLookup();\n await new Promise((resolve) => setTimeout(resolve, 0));\n\n const customCookieValue = serverCookieState.values.get(customCookieName);\n expect(customCookieValue).toBeDefined();\n if (customCookieValue == null) {\n throw new Error(\"Expected the custom refresh cookie to be recovered.\");\n }\n expect(JSON.parse(customCookieValue)).toMatchObject({\n refresh_token: \"second-refresh\",\n updated_at_millis: expect.any(Number),\n });\n expect(serverCookieState.values.has(defaultCookieName)).toBe(true);\n });\n});\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as stripBrowserActionQueryParam, r as _HexclaveClientAppImplIncomplete } from "../../../../admin-app-impl-
|
|
1
|
+
import { i as stripBrowserActionQueryParam, r as _HexclaveClientAppImplIncomplete } from "../../../../admin-app-impl-C6zvB2sD.js";
|
|
2
2
|
export { _HexclaveClientAppImplIncomplete, stripBrowserActionQueryParam };
|
|
@@ -443,6 +443,7 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
443
443
|
});
|
|
444
444
|
this._convexPartialUserCache = (0, __common_js.createCache)(async ([ctx]) => await this._getPartialUserFromConvex(ctx));
|
|
445
445
|
this._trustedParentDomainCache = (0, __common_js.createCache)(async ([domain]) => await this._getTrustedParentDomain(domain));
|
|
446
|
+
this._knownCustomRefreshCookieDomains = /* @__PURE__ */ new Set();
|
|
446
447
|
this._anonymousSignUpInProgress = null;
|
|
447
448
|
this._prefetchedCrossDomainHandoffParams = null;
|
|
448
449
|
this._prefetchedCrossDomainHandoffParamsFetchedAt = 0;
|
|
@@ -944,18 +945,13 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
944
945
|
});
|
|
945
946
|
});
|
|
946
947
|
}
|
|
947
|
-
_queueCustomRefreshCookieUpdate(refreshToken, updatedAt, context) {
|
|
948
|
+
_queueCustomRefreshCookieUpdate(refreshToken, updatedAt, context, previousCustomDomains) {
|
|
948
949
|
(0, _hexclave_shared_dist_utils_promises.runAsynchronously)(async () => {
|
|
949
950
|
this._mostRecentQueuedCookieRefreshIndex++;
|
|
950
951
|
const updateIndex = this._mostRecentQueuedCookieRefreshIndex;
|
|
951
952
|
let hostname;
|
|
952
953
|
if ((0, _hexclave_shared_dist_utils_env.isBrowserLike)()) hostname = window.location.hostname;
|
|
953
954
|
else hostname = await getServerRequestHost();
|
|
954
|
-
if (!hostname) {
|
|
955
|
-
console.warn("No hostname found when queueing custom refresh cookie update");
|
|
956
|
-
return;
|
|
957
|
-
}
|
|
958
|
-
const domain = await this._trustedParentDomainCache.getOrWait([hostname], "read-write");
|
|
959
955
|
const cookieOptions = {
|
|
960
956
|
maxAge: 3600 * 24 * 365,
|
|
961
957
|
noOpIfServerComponent: true
|
|
@@ -969,9 +965,22 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
969
965
|
if (context === "browser") (0, _________cookie_js.setOrDeleteCookieClient)(name, value, options);
|
|
970
966
|
else await (0, _________cookie_js.setOrDeleteCookie)(name, value, options);
|
|
971
967
|
};
|
|
972
|
-
if (domain.status === "error" || !domain.data || updateIndex !== this._mostRecentQueuedCookieRefreshIndex) return;
|
|
973
968
|
const value = refreshToken && updatedAt ? this._formatRefreshCookieValue(refreshToken, updatedAt) : null;
|
|
969
|
+
if (!hostname) {
|
|
970
|
+
const domains = /* @__PURE__ */ new Set();
|
|
971
|
+
for (const previousDomain of new Set(previousCustomDomains)) {
|
|
972
|
+
const domain = await this._trustedParentDomainCache.getOrWait([`_.${previousDomain}`], "read-write");
|
|
973
|
+
if (updateIndex !== this._mostRecentQueuedCookieRefreshIndex) return;
|
|
974
|
+
if (domain.status !== "error" && domain.data != null) domains.add(domain.data);
|
|
975
|
+
}
|
|
976
|
+
if (updateIndex !== this._mostRecentQueuedCookieRefreshIndex) return;
|
|
977
|
+
await Promise.all([...domains].map((domain) => setCookie(domain, value)));
|
|
978
|
+
return;
|
|
979
|
+
}
|
|
980
|
+
const domain = await this._trustedParentDomainCache.getOrWait([hostname], "read-write");
|
|
981
|
+
if (domain.status === "error" || !domain.data || updateIndex !== this._mostRecentQueuedCookieRefreshIndex) return;
|
|
974
982
|
await setCookie(domain.data, value);
|
|
983
|
+
this._knownCustomRefreshCookieDomains.add(domain.data);
|
|
975
984
|
const isSecure = await (0, _________cookie_js.isSecure)();
|
|
976
985
|
const defaultName = this._getRefreshTokenDefaultCookieNameForSecure(isSecure);
|
|
977
986
|
if (context === "browser") (0, _________cookie_js.setOrDeleteCookieClient)(defaultName, null, cookieOptions);
|
|
@@ -1023,7 +1032,8 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
1023
1032
|
const domain = this._getDomainFromCustomRefreshCookieName(name);
|
|
1024
1033
|
(0, _________cookie_js.deleteCookieClient)(name, domain ? { domain } : {});
|
|
1025
1034
|
});
|
|
1026
|
-
this.
|
|
1035
|
+
cookieNamesToDelete.map((name) => this._getDomainFromCustomRefreshCookieName(name)).filter((domain) => domain !== null).forEach((domain) => this._knownCustomRefreshCookieDomains.add(domain));
|
|
1036
|
+
this._queueCustomRefreshCookieUpdate(refreshToken, updatedAt, "browser", [...this._knownCustomRefreshCookieDomains]);
|
|
1027
1037
|
hasSucceededInWriting = true;
|
|
1028
1038
|
} catch (e) {
|
|
1029
1039
|
if (!(0, _hexclave_shared_dist_utils_env.isBrowserLike)()) hasSucceededInWriting = false;
|
|
@@ -1064,7 +1074,8 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
1064
1074
|
...domain ? { domain } : {}
|
|
1065
1075
|
});
|
|
1066
1076
|
}));
|
|
1067
|
-
this.
|
|
1077
|
+
cookieNamesToDelete.map((name) => this._getDomainFromCustomRefreshCookieName(name)).filter((domain) => domain !== null).forEach((domain) => this._knownCustomRefreshCookieDomains.add(domain));
|
|
1078
|
+
this._queueCustomRefreshCookieUpdate(refreshToken, updatedAt, "server", [...this._knownCustomRefreshCookieDomains]);
|
|
1068
1079
|
});
|
|
1069
1080
|
});
|
|
1070
1081
|
return store;
|