@hexclave/next 1.0.51 → 1.0.52

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 (158) hide show
  1. package/dist/{admin-app-impl-BGNL1KyZ.d.ts → admin-app-impl-Bga0o6cL.d.ts} +11 -8
  2. package/dist/{admin-app-impl-BGNL1KyZ.d.ts.map → admin-app-impl-Bga0o6cL.d.ts.map} +1 -1
  3. package/dist/clickmap/clickmap-core.d.ts +1 -1
  4. package/dist/clickmap/index.d.ts +1 -1
  5. package/dist/{client-app-Majjw8Xp.d.ts → client-app-B0kBC67Z.d.ts} +2 -1
  6. package/dist/{client-app-Majjw8Xp.d.ts.map → client-app-B0kBC67Z.d.ts.map} +1 -1
  7. package/dist/common-BK_sydxF.d.ts.map +1 -1
  8. package/dist/components/selected-team-switcher.d.ts +1 -1
  9. package/dist/components/team-icon.d.ts +1 -1
  10. package/dist/components/team-switcher.d.ts +1 -1
  11. package/dist/components-page/account-settings/payments/payments-page.d.ts +1 -1
  12. package/dist/components-page/account-settings/teams/leave-team-section.d.ts +1 -1
  13. package/dist/components-page/account-settings/teams/team-api-keys-section.d.ts +1 -1
  14. package/dist/components-page/account-settings/teams/team-display-name-section.d.ts +1 -1
  15. package/dist/components-page/account-settings/teams/team-member-invitation-section.d.ts +1 -1
  16. package/dist/components-page/account-settings/teams/team-member-list-section.d.ts +1 -1
  17. package/dist/components-page/account-settings/teams/team-page.d.ts +1 -1
  18. package/dist/components-page/account-settings/teams/team-profile-image-section.d.ts +1 -1
  19. package/dist/components-page/account-settings/teams/team-profile-user-section.d.ts +1 -1
  20. package/dist/components-page/hexclave-handler-client.d.ts +1 -1
  21. package/dist/components-page/hexclave-handler.d.ts +1 -1
  22. package/dist/components-page/sign-out.js +11 -2
  23. package/dist/components-page/sign-out.js.map +1 -1
  24. package/dist/components-page/sign-out.test.d.ts +1 -0
  25. package/dist/components-page/sign-out.test.js +157 -0
  26. package/dist/components-page/sign-out.test.js.map +1 -0
  27. package/dist/dev-tool/dev-tool-core.d.ts +1 -1
  28. package/dist/dev-tool/dev-tool-core.d.ts.map +1 -1
  29. package/dist/dev-tool/dev-tool-core.js +58 -28
  30. package/dist/dev-tool/dev-tool-core.js.map +1 -1
  31. package/dist/dev-tool/dev-tool-styles.js +35 -0
  32. package/dist/dev-tool/dev-tool-styles.js.map +1 -1
  33. package/dist/dev-tool/index.d.ts +1 -1
  34. package/dist/esm/components-page/sign-out.d.ts.map +1 -1
  35. package/dist/esm/components-page/sign-out.js +12 -3
  36. package/dist/esm/components-page/sign-out.js.map +1 -1
  37. package/dist/esm/components-page/sign-out.test.d.ts +1 -0
  38. package/dist/esm/components-page/sign-out.test.js +156 -0
  39. package/dist/esm/components-page/sign-out.test.js.map +1 -0
  40. package/dist/esm/dev-tool/dev-tool-core.d.ts.map +1 -1
  41. package/dist/esm/dev-tool/dev-tool-core.js +58 -28
  42. package/dist/esm/dev-tool/dev-tool-core.js.map +1 -1
  43. package/dist/esm/dev-tool/dev-tool-styles.js +35 -0
  44. package/dist/esm/dev-tool/dev-tool-styles.js.map +1 -1
  45. package/dist/esm/generated/global-css.d.ts +1 -1
  46. package/dist/esm/generated/global-css.js +1 -1
  47. package/dist/esm/generated/global-css.js.map +1 -1
  48. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +5 -4
  49. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
  50. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +97 -0
  51. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
  52. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +3 -2
  53. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
  54. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js +26 -1
  55. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  56. package/dist/esm/lib/hexclave-app/apps/implementations/common.d.ts.map +1 -1
  57. package/dist/esm/lib/hexclave-app/apps/implementations/common.js +21 -4
  58. package/dist/esm/lib/hexclave-app/apps/implementations/common.js.map +1 -1
  59. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.d.ts +37 -0
  60. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.d.ts.map +1 -0
  61. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.js +89 -0
  62. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.js.map +1 -0
  63. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.test.d.ts +1 -0
  64. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.test.js +134 -0
  65. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.test.js.map +1 -0
  66. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.d.ts +8 -0
  67. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.d.ts.map +1 -0
  68. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.js +73 -0
  69. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.js.map +1 -0
  70. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.d.ts +1 -0
  71. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.js +92 -0
  72. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.js.map +1 -0
  73. package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -0
  74. package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.d.ts.map +1 -1
  75. package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.js +27 -6
  76. package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.js.map +1 -1
  77. package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.d.ts +1 -0
  78. package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.d.ts.map +1 -1
  79. package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.js.map +1 -1
  80. package/dist/esm/pushed-config-error-overlay/index.js +1 -1
  81. package/dist/esm/pushed-config-error-overlay/index.js.map +1 -1
  82. package/dist/esm/utils/session-storage.d.ts +12 -0
  83. package/dist/esm/utils/session-storage.d.ts.map +1 -0
  84. package/dist/esm/utils/session-storage.js +30 -0
  85. package/dist/esm/utils/session-storage.js.map +1 -0
  86. package/dist/generated/global-css.d.ts +1 -1
  87. package/dist/generated/global-css.js +1 -1
  88. package/dist/generated/global-css.js.map +1 -1
  89. package/dist/{hexclave-provider-IAd7nlbi.d.ts → hexclave-provider-BQ9wrtBt.d.ts} +2 -2
  90. package/dist/{hexclave-provider-IAd7nlbi.d.ts.map → hexclave-provider-BQ9wrtBt.d.ts.map} +1 -1
  91. package/dist/{hooks-BKXOF6jh.d.ts → hooks-ykQ7Wsco.d.ts} +2 -2
  92. package/dist/{hooks-BKXOF6jh.d.ts.map → hooks-ykQ7Wsco.d.ts.map} +1 -1
  93. package/dist/{index-Ck1qKoin.d.ts → index-DwE1cNLH.d.ts} +2 -2
  94. package/dist/{index-Ck1qKoin.d.ts.map → index-DwE1cNLH.d.ts.map} +1 -1
  95. package/dist/index.d.ts +4 -4
  96. package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +1 -1
  97. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +97 -0
  98. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
  99. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -1
  100. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js +26 -1
  101. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  102. package/dist/lib/hexclave-app/apps/implementations/common.js +21 -4
  103. package/dist/lib/hexclave-app/apps/implementations/common.js.map +1 -1
  104. package/dist/lib/hexclave-app/apps/implementations/index.d.ts +1 -1
  105. package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.d.ts +37 -0
  106. package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.d.ts.map +1 -0
  107. package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.js +92 -0
  108. package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.js.map +1 -0
  109. package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.test.d.ts +1 -0
  110. package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.test.js +133 -0
  111. package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.test.js.map +1 -0
  112. package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.d.ts +8 -0
  113. package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.d.ts.map +1 -0
  114. package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.js +74 -0
  115. package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.js.map +1 -0
  116. package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.d.ts +1 -0
  117. package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.js +91 -0
  118. package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.js.map +1 -0
  119. package/dist/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -1
  120. package/dist/lib/hexclave-app/apps/implementations/server-app-impl.js +27 -6
  121. package/dist/lib/hexclave-app/apps/implementations/server-app-impl.js.map +1 -1
  122. package/dist/lib/hexclave-app/apps/index.d.ts +1 -1
  123. package/dist/lib/hexclave-app/apps/interfaces/admin-app.d.ts +1 -1
  124. package/dist/lib/hexclave-app/apps/interfaces/client-app.d.ts +1 -1
  125. package/dist/lib/hexclave-app/apps/interfaces/client-app.js.map +1 -1
  126. package/dist/lib/hexclave-app/apps/interfaces/server-app.d.ts +1 -1
  127. package/dist/lib/hexclave-app/index.d.ts +1 -1
  128. package/dist/lib/hexclave-app/projects/index.d.ts +1 -1
  129. package/dist/lib/hexclave-app/teams/index.d.ts +1 -1
  130. package/dist/lib/hexclave-app/users/index.d.ts +1 -1
  131. package/dist/lib/hooks.d.ts +1 -1
  132. package/dist/providers/hexclave-context.d.ts +1 -1
  133. package/dist/providers/hexclave-provider-client.d.ts +1 -1
  134. package/dist/providers/hexclave-provider.d.ts +1 -1
  135. package/dist/pushed-config-error-overlay/index.d.ts +1 -1
  136. package/dist/pushed-config-error-overlay/index.js +1 -1
  137. package/dist/pushed-config-error-overlay/index.js.map +1 -1
  138. package/dist/sign-out-DBnSkfDz.d.ts.map +1 -1
  139. package/dist/utils/session-storage.d.ts +12 -0
  140. package/dist/utils/session-storage.d.ts.map +1 -0
  141. package/dist/utils/session-storage.js +33 -0
  142. package/dist/utils/session-storage.js.map +1 -0
  143. package/package.json +4 -4
  144. package/src/components-page/sign-out.test.tsx +190 -0
  145. package/src/components-page/sign-out.tsx +22 -3
  146. package/src/dev-tool/dev-tool-core.ts +100 -35
  147. package/src/dev-tool/dev-tool-styles.ts +35 -0
  148. package/src/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.ts +127 -0
  149. package/src/lib/hexclave-app/apps/implementations/client-app-impl.ts +34 -1
  150. package/src/lib/hexclave-app/apps/implementations/common.ts +18 -1
  151. package/src/lib/hexclave-app/apps/implementations/redirect-back-state.test.ts +134 -0
  152. package/src/lib/hexclave-app/apps/implementations/redirect-back-state.ts +140 -0
  153. package/src/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.ts +127 -0
  154. package/src/lib/hexclave-app/apps/implementations/redirect-loop-breaker.ts +117 -0
  155. package/src/lib/hexclave-app/apps/implementations/server-app-impl.ts +31 -5
  156. package/src/lib/hexclave-app/apps/interfaces/client-app.ts +1 -0
  157. package/src/pushed-config-error-overlay/index.ts +1 -1
  158. package/src/utils/session-storage.ts +45 -0
@@ -0,0 +1,91 @@
1
+ let vitest = require("vitest");
2
+ let __redirect_loop_breaker_js = require("./redirect-loop-breaker.js");
3
+ //#region src/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.ts
4
+ function createMockSessionStorage() {
5
+ const map = /* @__PURE__ */ new Map();
6
+ return {
7
+ getItem: (key) => map.get(key) ?? null,
8
+ setItem: (key, value) => {
9
+ map.set(key, value);
10
+ },
11
+ removeItem: (key) => {
12
+ map.delete(key);
13
+ }
14
+ };
15
+ }
16
+ const previousWindow = Reflect.get(globalThis, "window");
17
+ const hadPreviousWindow = Reflect.has(globalThis, "window");
18
+ function record(from, to) {
19
+ (0, __redirect_loop_breaker_js.recordRedirectAndThrowIfLoopDetected)({
20
+ currentUrl: new URL(from),
21
+ targetUrl: new URL(to)
22
+ });
23
+ }
24
+ (0, vitest.describe)("recordRedirectAndThrowIfLoopDetected", () => {
25
+ (0, vitest.beforeEach)(() => {
26
+ Reflect.set(globalThis, "window", { sessionStorage: createMockSessionStorage() });
27
+ vitest.vi.useFakeTimers();
28
+ vitest.vi.setSystemTime(/* @__PURE__ */ new Date("2026-01-01T00:00:00Z"));
29
+ });
30
+ (0, vitest.afterEach)(() => {
31
+ vitest.vi.useRealTimers();
32
+ if (hadPreviousWindow) Reflect.set(globalThis, "window", previousWindow);
33
+ else Reflect.deleteProperty(globalThis, "window");
34
+ });
35
+ (0, vitest.it)("allows distinct redirects in quick succession", () => {
36
+ for (let i = 0; i < 20; i++) record(`https://app.example.test/page-${i}`, `https://app.example.test/page-${i + 1}`);
37
+ });
38
+ (0, vitest.it)("throws once the same redirect repeats 5 times within the window", () => {
39
+ for (let i = 0; i < 4; i++) {
40
+ record("https://app.example.test/dashboard", "https://hosted.example.test/handler/sign-in");
41
+ vitest.vi.advanceTimersByTime(1e3);
42
+ }
43
+ (0, vitest.expect)(() => {
44
+ record("https://app.example.test/dashboard", "https://hosted.example.test/handler/sign-in");
45
+ }).toThrowError(/Redirect loop detected/);
46
+ });
47
+ (0, vitest.it)("treats redirects that differ only in query params or hash as identical", () => {
48
+ for (let i = 0; i < 4; i++) record(`https://app.example.test/dashboard?code=code-${i}`, `https://hosted.example.test/handler/sign-in?state=state-${i}#frag-${i}`);
49
+ (0, vitest.expect)(() => {
50
+ record("https://app.example.test/dashboard?code=final", "https://hosted.example.test/handler/sign-in?state=final");
51
+ }).toThrowError(/Redirect loop detected/);
52
+ });
53
+ (0, vitest.it)("does not throw when the identical redirects are spread out beyond the window", () => {
54
+ for (let i = 0; i < 20; i++) {
55
+ record("https://app.example.test/dashboard", "https://hosted.example.test/handler/sign-in");
56
+ vitest.vi.advanceTimersByTime(31e3);
57
+ }
58
+ });
59
+ (0, vitest.it)("allows the same redirect again after a loop was broken", () => {
60
+ for (let i = 0; i < 4; i++) record("https://app.example.test/dashboard", "https://hosted.example.test/handler/sign-in");
61
+ (0, vitest.expect)(() => {
62
+ record("https://app.example.test/dashboard", "https://hosted.example.test/handler/sign-in");
63
+ }).toThrowError(/Redirect loop detected/);
64
+ record("https://app.example.test/dashboard", "https://hosted.example.test/handler/sign-in");
65
+ });
66
+ (0, vitest.it)("counts self-redirects (same origin and path) towards loops", () => {
67
+ for (let i = 0; i < 4; i++) record(`https://hosted.example.test/handler/sign-in?attempt=${i}`, "https://hosted.example.test/handler/sign-in");
68
+ (0, vitest.expect)(() => {
69
+ record("https://hosted.example.test/handler/sign-in?attempt=final", "https://hosted.example.test/handler/sign-in");
70
+ }).toThrowError(/Redirect loop detected/);
71
+ });
72
+ (0, vitest.it)("degrades to a no-op when sessionStorage is unavailable", () => {
73
+ Reflect.set(globalThis, "window", { get sessionStorage() {
74
+ throw new Error("Storage is disabled");
75
+ } });
76
+ for (let i = 0; i < 20; i++) record("https://app.example.test/dashboard", "https://hosted.example.test/handler/sign-in");
77
+ });
78
+ (0, vitest.it)("recovers from corrupted breadcrumb storage", () => {
79
+ const storage = createMockSessionStorage();
80
+ storage.setItem("hexclave-redirect-loop-breadcrumbs", "{not json");
81
+ Reflect.set(globalThis, "window", { sessionStorage: storage });
82
+ record("https://app.example.test/dashboard", "https://hosted.example.test/handler/sign-in");
83
+ for (let i = 0; i < 3; i++) record("https://app.example.test/dashboard", "https://hosted.example.test/handler/sign-in");
84
+ (0, vitest.expect)(() => {
85
+ record("https://app.example.test/dashboard", "https://hosted.example.test/handler/sign-in");
86
+ }).toThrowError(/Redirect loop detected/);
87
+ });
88
+ });
89
+ //#endregion
90
+
91
+ //# sourceMappingURL=redirect-loop-breaker.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redirect-loop-breaker.test.js","names":[],"sources":["../../../../../src/lib/hexclave-app/apps/implementations/redirect-loop-breaker.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, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { recordRedirectAndThrowIfLoopDetected } from \"./redirect-loop-breaker\";\n\nfunction createMockSessionStorage() {\n const map = new Map<string, string>();\n return {\n getItem: (key: string) => map.get(key) ?? null,\n setItem: (key: string, value: string) => {\n map.set(key, value);\n },\n removeItem: (key: string) => {\n map.delete(key);\n },\n };\n}\n\nconst previousWindow = Reflect.get(globalThis, \"window\");\nconst hadPreviousWindow = Reflect.has(globalThis, \"window\");\n\nfunction record(from: string, to: string) {\n recordRedirectAndThrowIfLoopDetected({\n currentUrl: new URL(from),\n targetUrl: new URL(to),\n });\n}\n\ndescribe(\"recordRedirectAndThrowIfLoopDetected\", () => {\n beforeEach(() => {\n Reflect.set(globalThis, \"window\", { sessionStorage: createMockSessionStorage() });\n vi.useFakeTimers();\n vi.setSystemTime(new Date(\"2026-01-01T00:00:00Z\"));\n });\n\n afterEach(() => {\n vi.useRealTimers();\n if (hadPreviousWindow) {\n Reflect.set(globalThis, \"window\", previousWindow);\n } else {\n Reflect.deleteProperty(globalThis, \"window\");\n }\n });\n\n it(\"allows distinct redirects in quick succession\", () => {\n for (let i = 0; i < 20; i++) {\n record(`https://app.example.test/page-${i}`, `https://app.example.test/page-${i + 1}`);\n }\n });\n\n it(\"throws once the same redirect repeats 5 times within the window\", () => {\n for (let i = 0; i < 4; i++) {\n record(\"https://app.example.test/dashboard\", \"https://hosted.example.test/handler/sign-in\");\n vi.advanceTimersByTime(1000);\n }\n expect(() => {\n record(\"https://app.example.test/dashboard\", \"https://hosted.example.test/handler/sign-in\");\n }).toThrowError(/Redirect loop detected/);\n });\n\n it(\"treats redirects that differ only in query params or hash as identical\", () => {\n // Real loops usually rotate nonce-style params (code, state, after_auth_return_to) each cycle.\n for (let i = 0; i < 4; i++) {\n record(\n `https://app.example.test/dashboard?code=code-${i}`,\n `https://hosted.example.test/handler/sign-in?state=state-${i}#frag-${i}`,\n );\n }\n expect(() => {\n record(\"https://app.example.test/dashboard?code=final\", \"https://hosted.example.test/handler/sign-in?state=final\");\n }).toThrowError(/Redirect loop detected/);\n });\n\n it(\"does not throw when the identical redirects are spread out beyond the window\", () => {\n for (let i = 0; i < 20; i++) {\n record(\"https://app.example.test/dashboard\", \"https://hosted.example.test/handler/sign-in\");\n vi.advanceTimersByTime(31_000);\n }\n });\n\n it(\"allows the same redirect again after a loop was broken\", () => {\n for (let i = 0; i < 4; i++) {\n record(\"https://app.example.test/dashboard\", \"https://hosted.example.test/handler/sign-in\");\n }\n expect(() => {\n record(\"https://app.example.test/dashboard\", \"https://hosted.example.test/handler/sign-in\");\n }).toThrowError(/Redirect loop detected/);\n // The breadcrumbs for the broken loop are dropped, so a manual retry isn't instantly blocked.\n record(\"https://app.example.test/dashboard\", \"https://hosted.example.test/handler/sign-in\");\n });\n\n it(\"counts self-redirects (same origin and path) towards loops\", () => {\n for (let i = 0; i < 4; i++) {\n record(`https://hosted.example.test/handler/sign-in?attempt=${i}`, \"https://hosted.example.test/handler/sign-in\");\n }\n expect(() => {\n record(\"https://hosted.example.test/handler/sign-in?attempt=final\", \"https://hosted.example.test/handler/sign-in\");\n }).toThrowError(/Redirect loop detected/);\n });\n\n it(\"degrades to a no-op when sessionStorage is unavailable\", () => {\n Reflect.set(globalThis, \"window\", {\n get sessionStorage(): Storage {\n throw new Error(\"Storage is disabled\");\n },\n });\n for (let i = 0; i < 20; i++) {\n record(\"https://app.example.test/dashboard\", \"https://hosted.example.test/handler/sign-in\");\n }\n });\n\n it(\"recovers from corrupted breadcrumb storage\", () => {\n const storage = createMockSessionStorage();\n storage.setItem(\"hexclave-redirect-loop-breadcrumbs\", \"{not json\");\n Reflect.set(globalThis, \"window\", { sessionStorage: storage });\n record(\"https://app.example.test/dashboard\", \"https://hosted.example.test/handler/sign-in\");\n // After recovery, loop detection works again.\n for (let i = 0; i < 3; i++) {\n record(\"https://app.example.test/dashboard\", \"https://hosted.example.test/handler/sign-in\");\n }\n expect(() => {\n record(\"https://app.example.test/dashboard\", \"https://hosted.example.test/handler/sign-in\");\n }).toThrowError(/Redirect loop detected/);\n });\n});\n"],"mappings":";;;AAOA,SAAS,2BAA2B;CAClC,MAAM,sBAAM,IAAI,IAAoB;CACpC,OAAO;EACL,UAAU,QAAgB,IAAI,IAAI,GAAG,KAAK;EAC1C,UAAU,KAAa,UAAkB;GACvC,IAAI,IAAI,KAAK,KAAK;EACpB;EACA,aAAa,QAAgB;GAC3B,IAAI,OAAO,GAAG;EAChB;CACF;AACF;AAEA,MAAM,iBAAiB,QAAQ,IAAI,YAAY,QAAQ;AACvD,MAAM,oBAAoB,QAAQ,IAAI,YAAY,QAAQ;AAE1D,SAAS,OAAO,MAAc,IAAY;CACxC,CAAA,GAAA,2BAAA,qCAAA,CAAqC;EACnC,YAAY,IAAI,IAAI,IAAI;EACxB,WAAW,IAAI,IAAI,EAAE;CACvB,CAAC;AACH;qBAES,8CAA8C;CACrD,CAAA,GAAA,OAAA,WAAA,OAAiB;EACf,QAAQ,IAAI,YAAY,UAAU,EAAE,gBAAgB,yBAAyB,EAAE,CAAC;EAChF,OAAA,GAAG,cAAc;EACjB,OAAA,GAAG,8BAAc,IAAI,KAAK,sBAAsB,CAAC;CACnD,CAAC;CAED,CAAA,GAAA,OAAA,UAAA,OAAgB;EACd,OAAA,GAAG,cAAc;EACjB,IAAI,mBACF,QAAQ,IAAI,YAAY,UAAU,cAAc;OAEhD,QAAQ,eAAe,YAAY,QAAQ;CAE/C,CAAC;CAED,CAAA,GAAA,OAAA,GAAA,CAAG,uDAAuD;EACxD,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KACtB,OAAO,iCAAiC,KAAK,iCAAiC,IAAI,GAAG;CAEzF,CAAC;CAED,CAAA,GAAA,OAAA,GAAA,CAAG,yEAAyE;EAC1E,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;GAC1B,OAAO,sCAAsC,6CAA6C;GAC1F,OAAA,GAAG,oBAAoB,GAAI;EAC7B;EACA,CAAA,GAAA,OAAA,OAAA,OAAa;GACX,OAAO,sCAAsC,6CAA6C;EAC5F,CAAC,CAAC,CAAC,aAAa,wBAAwB;CAC1C,CAAC;CAED,CAAA,GAAA,OAAA,GAAA,CAAG,gFAAgF;EAEjF,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KACrB,OACE,gDAAgD,KAChD,2DAA2D,EAAE,QAAQ,GACvE;EAEF,CAAA,GAAA,OAAA,OAAA,OAAa;GACX,OAAO,iDAAiD,yDAAyD;EACnH,CAAC,CAAC,CAAC,aAAa,wBAAwB;CAC1C,CAAC;CAED,CAAA,GAAA,OAAA,GAAA,CAAG,sFAAsF;EACvF,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;GAC3B,OAAO,sCAAsC,6CAA6C;GAC1F,OAAA,GAAG,oBAAoB,IAAM;EAC/B;CACF,CAAC;CAED,CAAA,GAAA,OAAA,GAAA,CAAG,gEAAgE;EACjE,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KACrB,OAAO,sCAAsC,6CAA6C;EAE5F,CAAA,GAAA,OAAA,OAAA,OAAa;GACX,OAAO,sCAAsC,6CAA6C;EAC5F,CAAC,CAAC,CAAC,aAAa,wBAAwB;EAExC,OAAO,sCAAsC,6CAA6C;CAC5F,CAAC;CAED,CAAA,GAAA,OAAA,GAAA,CAAG,oEAAoE;EACrE,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KACrB,OAAO,uDAAuD,KAAK,6CAA6C;EAElH,CAAA,GAAA,OAAA,OAAA,OAAa;GACX,OAAO,6DAA6D,6CAA6C;EACnH,CAAC,CAAC,CAAC,aAAa,wBAAwB;CAC1C,CAAC;CAED,CAAA,GAAA,OAAA,GAAA,CAAG,gEAAgE;EACjE,QAAQ,IAAI,YAAY,UAAU,EAChC,IAAI,iBAA0B;GAC5B,MAAM,IAAI,MAAM,qBAAqB;EACvC,EACF,CAAC;EACD,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KACtB,OAAO,sCAAsC,6CAA6C;CAE9F,CAAC;CAED,CAAA,GAAA,OAAA,GAAA,CAAG,oDAAoD;EACrD,MAAM,UAAU,yBAAyB;EACzC,QAAQ,QAAQ,sCAAsC,WAAW;EACjE,QAAQ,IAAI,YAAY,UAAU,EAAE,gBAAgB,QAAQ,CAAC;EAC7D,OAAO,sCAAsC,6CAA6C;EAE1F,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KACrB,OAAO,sCAAsC,6CAA6C;EAE5F,CAAA,GAAA,OAAA,OAAA,OAAa;GACX,OAAO,sCAAsC,6CAA6C;EAC5F,CAAC,CAAC,CAAC,aAAa,wBAAwB;CAC1C,CAAC;AACH,CAAC"}
@@ -1,2 +1,2 @@
1
- import { n as _HexclaveServerAppImplIncomplete } from "../../../../admin-app-impl-BGNL1KyZ.js";
1
+ import { n as _HexclaveServerAppImplIncomplete } from "../../../../admin-app-impl-Bga0o6cL.js";
2
2
  export { _HexclaveServerAppImplIncomplete };
@@ -7,6 +7,7 @@ let _hexclave_shared_dist_utils_react = require("@hexclave/shared/dist/utils/rea
7
7
  let _hexclave_shared_dist_utils_results = require("@hexclave/shared/dist/utils/results");
8
8
  let __common_js = require("./common.js");
9
9
  let _hexclave_shared_dist_sessions = require("@hexclave/shared/dist/sessions");
10
+ let _hexclave_shared_dist_utils_uuids = require("@hexclave/shared/dist/utils/uuids");
10
11
  let _simplewebauthn_browser = require("@simplewebauthn/browser");
11
12
  let ____________utils_url_js = require("../../../../utils/url.js");
12
13
  let ______api_keys_index_js = require("../../api-keys/index.js");
@@ -226,6 +227,15 @@ var _HexclaveServerAppImplIncomplete = class extends __client_app_impl_js._Hexcl
226
227
  query
227
228
  });
228
229
  });
230
+ this._serverTeamCache = (0, __common_js.createCache)(async ([teamId]) => {
231
+ if (!(0, _hexclave_shared_dist_utils_uuids.isUuid)(teamId)) return null;
232
+ try {
233
+ return await this._interface.getServerTeam(teamId);
234
+ } catch (error) {
235
+ if (_hexclave_shared.KnownErrors.TeamNotFound.isInstance(error)) return null;
236
+ throw error;
237
+ }
238
+ });
229
239
  this._serverUserTeamInvitationsCache = (0, __common_js.createCache)(async ([userId]) => {
230
240
  return await this._interface.listServerUserTeamInvitations(userId);
231
241
  });
@@ -832,11 +842,19 @@ var _HexclaveServerAppImplIncomplete = class extends __client_app_impl_js._Hexcl
832
842
  serverMetadata: crud.server_metadata,
833
843
  async update(update) {
834
844
  await app._interface.updateServerTeam(crud.id, (0, ______teams_index_js.serverTeamUpdateOptionsToCrud)(update));
835
- await Promise.all([app._serverTeamsCache.refreshWhere(() => true), app._serverUsersCache.refreshWhere(() => true)]);
845
+ await Promise.all([
846
+ app._serverTeamCache.refresh([crud.id]),
847
+ app._serverTeamsCache.refreshWhere(() => true),
848
+ app._serverUsersCache.refreshWhere(() => true)
849
+ ]);
836
850
  },
837
851
  async delete() {
838
852
  await app._interface.deleteServerTeam(crud.id);
839
- await Promise.all([app._serverTeamsCache.refreshWhere(() => true), app._serverUsersCache.refreshWhere(() => true)]);
853
+ await Promise.all([
854
+ app._serverTeamCache.refresh([crud.id]),
855
+ app._serverTeamsCache.refreshWhere(() => true),
856
+ app._serverUsersCache.refreshWhere(() => true)
857
+ ]);
840
858
  },
841
859
  async listUsers() {
842
860
  return _hexclave_shared_dist_utils_results.Result.orThrow(await app._serverTeamMemberProfilesCache.getOrWait([crud.id], "write-only")).map((u) => app._serverTeamUserFromCrud(u));
@@ -1255,6 +1273,7 @@ var _HexclaveServerAppImplIncomplete = class extends __client_app_impl_js._Hexcl
1255
1273
  }
1256
1274
  async createTeam(data) {
1257
1275
  const team = await this._interface.createServerTeam((0, ______teams_index_js.serverTeamCreateOptionsToCrud)(data));
1276
+ await this._serverTeamCache.refresh([team.id]);
1258
1277
  await this._serverTeamsCache.refreshWhere(() => true);
1259
1278
  return this._serverTeamFromCrud(team);
1260
1279
  }
@@ -1305,17 +1324,19 @@ var _HexclaveServerAppImplIncomplete = class extends __client_app_impl_js._Hexcl
1305
1324
  if (typeof options === "object" && "apiKey" in options) return await this._getTeamByApiKey(options.apiKey);
1306
1325
  else {
1307
1326
  const teamId = options;
1308
- return (await this.listTeams()).find((t) => t.id === teamId) ?? null;
1327
+ if (teamId == null) return null;
1328
+ const team = _hexclave_shared_dist_utils_results.Result.orThrow(await this._serverTeamCache.getOrWait([teamId], "write-only"));
1329
+ return team == null ? null : this._serverTeamFromCrud(team);
1309
1330
  }
1310
1331
  }
1311
1332
  useTeam(options) {
1312
1333
  if (typeof options === "object" && "apiKey" in options) return this._useTeamByApiKey(options.apiKey);
1313
1334
  else {
1314
1335
  const teamId = options;
1315
- const teams = this.useTeams();
1336
+ const team = (0, __common_js.useAsyncCache)(this._serverTeamCache, [teamId ?? ""], "serverApp.useTeam()");
1316
1337
  return (0, react.useMemo)(() => {
1317
- return teams.find((t) => t.id === teamId) ?? null;
1318
- }, [teams, teamId]);
1338
+ return team == null ? null : this._serverTeamFromCrud(team);
1339
+ }, [team]);
1319
1340
  }
1320
1341
  }
1321
1342
  _createServerDataVaultStore(id) {