@hexclave/js 1.0.114 → 1.0.116

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/dist/{admin-app-impl-CmLgv1kA.d.ts → admin-app-impl-Ewv2Au7f.d.ts} +2 -1
  2. package/dist/admin-app-impl-Ewv2Au7f.d.ts.map +1 -0
  3. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
  4. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cookie.test.d.ts +1 -0
  5. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cookie.test.js +163 -0
  6. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cookie.test.js.map +1 -0
  7. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -0
  8. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
  9. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js +20 -9
  10. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  11. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.next-server-session.test.js +0 -10
  12. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.next-server-session.test.js.map +1 -1
  13. package/dist/esm/lib/hexclave-app/apps/implementations/common.js +2 -2
  14. package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +1 -1
  15. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cookie.test.d.ts +1 -0
  16. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cookie.test.js +162 -0
  17. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cookie.test.js.map +1 -0
  18. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -1
  19. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js +20 -9
  20. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  21. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.next-server-session.test.js +0 -10
  22. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.next-server-session.test.js.map +1 -1
  23. package/dist/lib/hexclave-app/apps/implementations/common.js +2 -2
  24. package/dist/lib/hexclave-app/apps/implementations/index.d.ts +1 -1
  25. package/dist/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -1
  26. package/package.json +2 -2
  27. package/src/lib/hexclave-app/apps/implementations/client-app-impl.cookie.test.ts +172 -0
  28. package/src/lib/hexclave-app/apps/implementations/client-app-impl.next-server-session.test.ts +1 -12
  29. package/src/lib/hexclave-app/apps/implementations/client-app-impl.ts +35 -10
  30. package/dist/admin-app-impl-CmLgv1kA.d.ts.map +0 -1
@@ -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 it(\"shares one token store and session across cookie helpers from the same request\", () => {\n const clientApp = createClientApp();\n const getTokenStore = Reflect.get(clientApp, \"_getOrCreateTokenStore\");\n const getSession = Reflect.get(clientApp, \"_getSessionFromTokenStore\");\n const requestIdentity = {};\n\n const firstStore = getTokenStore.call(clientApp, createCookieHelper(requestIdentity), \"nextjs-cookie\");\n const secondStore = getTokenStore.call(clientApp, createCookieHelper(requestIdentity), \"nextjs-cookie\");\n\n expect(secondStore).toBe(firstStore);\n expect(getSession.call(clientApp, secondStore)).toBe(getSession.call(clientApp, firstStore));\n });\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;CACvD,GAAG,wFAAwF;EACzF,MAAM,YAAY,gBAAgB;EAClC,MAAM,gBAAgB,QAAQ,IAAI,WAAW,wBAAwB;EACrE,MAAM,aAAa,QAAQ,IAAI,WAAW,2BAA2B;EACrE,MAAM,kBAAkB,CAAC;EAEzB,MAAM,aAAa,cAAc,KAAK,WAAW,mBAAmB,eAAe,GAAG,eAAe;EACrG,MAAM,cAAc,cAAc,KAAK,WAAW,mBAAmB,eAAe,GAAG,eAAe;EAEtG,OAAO,WAAW,CAAC,CAAC,KAAK,UAAU;EACnC,OAAO,WAAW,KAAK,WAAW,WAAW,CAAC,CAAC,CAAC,KAAK,WAAW,KAAK,WAAW,UAAU,CAAC;CAC7F,CAAC;CAED,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"}
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.114";
16
- if ("js @hexclave/js@1.0.114".startsWith("STACK_COMPILE_TIME"));
15
+ const clientVersion = "js @hexclave/js@1.0.116";
16
+ if ("js @hexclave/js@1.0.116".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-CmLgv1kA.js";
1
+ import { t as _HexclaveAdminAppImplIncomplete } from "../../../../admin-app-impl-Ewv2Au7f.js";
2
2
  export { _HexclaveAdminAppImplIncomplete };
@@ -0,0 +1,162 @@
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
+ get: (name) => serverCookieState.values.get(name) ?? null,
19
+ getAll,
20
+ set: (name, value) => setOrDelete(name, value),
21
+ setOrDelete,
22
+ delete: remove
23
+ };
24
+ return {
25
+ createBrowserCookieHelper: () => helper,
26
+ createCookieHelper: async () => helper,
27
+ createPlaceholderCookieHelper: async () => helper,
28
+ deleteCookie: async (name) => remove(name),
29
+ deleteCookieClient: remove,
30
+ getCookieClient: (name) => serverCookieState.values.get(name) ?? null,
31
+ isSecure: async () => true,
32
+ saveVerifierAndState: async () => {
33
+ throw new Error("saveVerifierAndState is not used in this test");
34
+ },
35
+ setOrDeleteCookie: async (name, value) => setOrDelete(name, value),
36
+ setOrDeleteCookieClient: setOrDelete
37
+ };
38
+ });
39
+ (0, vitest.describe)("StackClientApp custom refresh cookie updates", () => {
40
+ (0, vitest.it)("preserves the existing custom and default cookies without a server hostname", async () => {
41
+ (0, vitest.expect)((0, _hexclave_shared_dist_utils_redirect_urls.getTrustedParentDomain)("_.example.com", ["https://example.com", "https://**.example.com"])).toBe("example.com");
42
+ const projectId = "00000000-0000-4000-8000-000000000000";
43
+ const customCookieName = `hexclave-refresh-${projectId}--custom-${(0, _hexclave_shared_dist_utils_bytes.encodeBase32)(new util.TextEncoder().encode("example.com"))}`;
44
+ const defaultCookieName = `__Host-hexclave-refresh-${projectId}--default`;
45
+ serverCookieState.values.clear();
46
+ serverCookieState.values.set(defaultCookieName, JSON.stringify({
47
+ refresh_token: "old-refresh",
48
+ updated_at_millis: 1
49
+ }));
50
+ serverCookieState.values.set(customCookieName, JSON.stringify({
51
+ refresh_token: "old-refresh",
52
+ updated_at_millis: 1
53
+ }));
54
+ const clientApp = new ___interfaces_client_app_js.StackClientApp({
55
+ baseUrl: "http://localhost:12345",
56
+ projectId,
57
+ publishableClientKey: "stack-pk-test",
58
+ tokenStore: "memory",
59
+ redirectMethod: "none",
60
+ noAutomaticPrefetch: true,
61
+ devTool: false
62
+ });
63
+ const trustedParentLookups = [];
64
+ Reflect.set(clientApp, "_getTrustedParentDomain", async (domain) => {
65
+ trustedParentLookups.push(domain);
66
+ return domain === "_.example.com" ? "example.com" : null;
67
+ });
68
+ const tokenStore = Reflect.get(clientApp, "_getOrCreateTokenStore").call(clientApp, {
69
+ get: (name) => serverCookieState.values.get(name) ?? null,
70
+ getAll: () => Object.fromEntries(serverCookieState.values),
71
+ set: (name, value) => serverCookieState.values.set(name, value),
72
+ setOrDelete: (name, value) => {
73
+ if (value === null) serverCookieState.values.delete(name);
74
+ else serverCookieState.values.set(name, value);
75
+ },
76
+ delete: (name) => serverCookieState.values.delete(name)
77
+ }, "nextjs-cookie");
78
+ const warnSpy = vitest.vi.spyOn(console, "warn").mockImplementation(() => {});
79
+ tokenStore.set({
80
+ accessToken: "new-access",
81
+ refreshToken: "new-refresh"
82
+ });
83
+ await new Promise((resolve) => setTimeout(resolve, 0));
84
+ vitest.expect.soft(warnSpy).not.toHaveBeenCalled();
85
+ const customCookieValue = serverCookieState.values.get(customCookieName);
86
+ vitest.expect.soft(customCookieValue).toBeDefined();
87
+ if (customCookieValue != null) vitest.expect.soft(JSON.parse(customCookieValue)).toEqual({
88
+ refresh_token: "new-refresh",
89
+ updated_at_millis: vitest.expect.any(Number)
90
+ });
91
+ vitest.expect.soft(serverCookieState.values.has(defaultCookieName)).toBe(true);
92
+ vitest.expect.soft(trustedParentLookups).toEqual(["_.example.com"]);
93
+ warnSpy.mockRestore();
94
+ });
95
+ (0, vitest.it)("recovers the custom cookie after overlapping server updates", async () => {
96
+ const projectId = "00000000-0000-4000-8000-000000000001";
97
+ const customCookieName = `hexclave-refresh-${projectId}--custom-${(0, _hexclave_shared_dist_utils_bytes.encodeBase32)(new util.TextEncoder().encode("example.com"))}`;
98
+ const defaultCookieName = `__Host-hexclave-refresh-${projectId}--default`;
99
+ serverCookieState.values.clear();
100
+ serverCookieState.values.set(defaultCookieName, JSON.stringify({
101
+ refresh_token: "old-refresh",
102
+ updated_at_millis: 1
103
+ }));
104
+ serverCookieState.values.set(customCookieName, JSON.stringify({
105
+ refresh_token: "old-refresh",
106
+ updated_at_millis: 1
107
+ }));
108
+ const clientApp = new ___interfaces_client_app_js.StackClientApp({
109
+ baseUrl: "http://localhost:12345",
110
+ projectId,
111
+ publishableClientKey: "stack-pk-test",
112
+ tokenStore: "memory",
113
+ redirectMethod: "none",
114
+ noAutomaticPrefetch: true,
115
+ devTool: false
116
+ });
117
+ let releaseTrustedParentLookup;
118
+ let shouldBlockTrustedParentLookup = true;
119
+ Reflect.set(clientApp, "_getTrustedParentDomain", async (domain) => {
120
+ if (shouldBlockTrustedParentLookup) {
121
+ shouldBlockTrustedParentLookup = false;
122
+ await new Promise((resolve) => {
123
+ releaseTrustedParentLookup = resolve;
124
+ });
125
+ }
126
+ return domain === "_.example.com" ? "example.com" : null;
127
+ });
128
+ const tokenStore = Reflect.get(clientApp, "_getOrCreateTokenStore").call(clientApp, {
129
+ get: (name) => serverCookieState.values.get(name) ?? null,
130
+ getAll: () => Object.fromEntries(serverCookieState.values),
131
+ set: (name, value) => serverCookieState.values.set(name, value),
132
+ setOrDelete: (name, value) => {
133
+ if (value === null) serverCookieState.values.delete(name);
134
+ else serverCookieState.values.set(name, value);
135
+ },
136
+ delete: (name) => serverCookieState.values.delete(name)
137
+ }, "nextjs-cookie");
138
+ tokenStore.set({
139
+ accessToken: "first-access",
140
+ refreshToken: "first-refresh"
141
+ });
142
+ await new Promise((resolve) => setTimeout(resolve, 0));
143
+ if (releaseTrustedParentLookup == null) throw new Error("Expected the first custom cookie recovery lookup to be pending.");
144
+ tokenStore.set({
145
+ accessToken: "second-access",
146
+ refreshToken: "second-refresh"
147
+ });
148
+ releaseTrustedParentLookup();
149
+ await new Promise((resolve) => setTimeout(resolve, 0));
150
+ const customCookieValue = serverCookieState.values.get(customCookieName);
151
+ (0, vitest.expect)(customCookieValue).toBeDefined();
152
+ if (customCookieValue == null) throw new Error("Expected the custom refresh cookie to be recovered.");
153
+ (0, vitest.expect)(JSON.parse(customCookieValue)).toMatchObject({
154
+ refresh_token: "second-refresh",
155
+ updated_at_millis: vitest.expect.any(Number)
156
+ });
157
+ (0, vitest.expect)(serverCookieState.values.has(defaultCookieName)).toBe(true);
158
+ });
159
+ });
160
+ //#endregion
161
+
162
+ //# 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 { 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 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 = {\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 = {\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-CmLgv1kA.js";
1
+ import { i as stripBrowserActionQueryParam, r as _HexclaveClientAppImplIncomplete } from "../../../../admin-app-impl-Ewv2Au7f.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._queueCustomRefreshCookieUpdate(refreshToken, updatedAt, "browser");
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._queueCustomRefreshCookieUpdate(refreshToken, updatedAt, "server");
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;