@hexclave/js 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.
- package/dist/{admin-app-impl-Cz9Ub_C8.d.ts → admin-app-impl-DHs4il4z.d.ts} +11 -8
- package/dist/{admin-app-impl-Cz9Ub_C8.d.ts.map → admin-app-impl-DHs4il4z.d.ts.map} +1 -1
- package/dist/clickmap/clickmap-core.d.ts +1 -1
- package/dist/clickmap/index.d.ts +1 -1
- package/dist/{client-app-BgdvwktS.d.ts → client-app-BoOM8rxo.d.ts} +2 -1
- package/dist/{client-app-BgdvwktS.d.ts.map → client-app-BoOM8rxo.d.ts.map} +1 -1
- package/dist/common-CRu2FsO9.d.ts.map +1 -1
- package/dist/dev-tool/dev-tool-core.d.ts +1 -1
- package/dist/dev-tool/dev-tool-core.d.ts.map +1 -1
- package/dist/dev-tool/dev-tool-core.js +58 -28
- package/dist/dev-tool/dev-tool-core.js.map +1 -1
- package/dist/dev-tool/dev-tool-styles.js +35 -0
- package/dist/dev-tool/dev-tool-styles.js.map +1 -1
- package/dist/dev-tool/index.d.ts +1 -1
- package/dist/esm/dev-tool/dev-tool-core.d.ts.map +1 -1
- package/dist/esm/dev-tool/dev-tool-core.js +58 -28
- package/dist/esm/dev-tool/dev-tool-core.js.map +1 -1
- package/dist/esm/dev-tool/dev-tool-styles.js +35 -0
- package/dist/esm/dev-tool/dev-tool-styles.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +5 -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.cross-domain.test.js +97 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +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 +26 -1
- 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.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/common.js +21 -4
- package/dist/esm/lib/hexclave-app/apps/implementations/common.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.d.ts +37 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.d.ts.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.js +89 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.js.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.test.d.ts +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.test.js +134 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.test.js.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.d.ts +8 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.d.ts.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.js +73 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.js.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.d.ts +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.js +92 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.js.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.js +24 -3
- package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.d.ts +1 -0
- package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.js.map +1 -1
- package/dist/esm/pushed-config-error-overlay/index.js +1 -1
- package/dist/esm/pushed-config-error-overlay/index.js.map +1 -1
- package/dist/esm/pushed-config-error-overlay/index.test.js +1 -1
- package/dist/esm/utils/session-storage.d.ts +12 -0
- package/dist/esm/utils/session-storage.d.ts.map +1 -0
- package/dist/esm/utils/session-storage.js +30 -0
- package/dist/esm/utils/session-storage.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +97 -0
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js +26 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/common.js +21 -4
- package/dist/lib/hexclave-app/apps/implementations/common.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/index.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.d.ts +37 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.d.ts.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.js +92 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.js.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.test.d.ts +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.test.js +133 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.test.js.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.d.ts +8 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.d.ts.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.js +74 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.js.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.d.ts +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.js +91 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.js.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/server-app-impl.js +24 -3
- package/dist/lib/hexclave-app/apps/implementations/server-app-impl.js.map +1 -1
- package/dist/lib/hexclave-app/apps/index.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/interfaces/admin-app.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/interfaces/client-app.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/interfaces/client-app.js.map +1 -1
- package/dist/lib/hexclave-app/apps/interfaces/server-app.d.ts +1 -1
- package/dist/lib/hexclave-app/index.d.ts +1 -1
- package/dist/lib/hexclave-app/projects/index.d.ts +1 -1
- package/dist/lib/hexclave-app/teams/index.d.ts +1 -1
- package/dist/lib/hexclave-app/users/index.d.ts +1 -1
- package/dist/pushed-config-error-overlay/index.d.ts +1 -1
- package/dist/pushed-config-error-overlay/index.js +1 -1
- package/dist/pushed-config-error-overlay/index.js.map +1 -1
- package/dist/pushed-config-error-overlay/index.test.js +1 -1
- package/dist/utils/session-storage.d.ts +12 -0
- package/dist/utils/session-storage.d.ts.map +1 -0
- package/dist/utils/session-storage.js +33 -0
- package/dist/utils/session-storage.js.map +1 -0
- package/package.json +2 -2
- package/src/dev-tool/dev-tool-core.ts +100 -35
- package/src/dev-tool/dev-tool-styles.ts +35 -0
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.ts +127 -0
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.ts +34 -1
- package/src/lib/hexclave-app/apps/implementations/common.ts +18 -1
- package/src/lib/hexclave-app/apps/implementations/redirect-back-state.test.ts +134 -0
- package/src/lib/hexclave-app/apps/implementations/redirect-back-state.ts +140 -0
- package/src/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.ts +127 -0
- package/src/lib/hexclave-app/apps/implementations/redirect-loop-breaker.ts +117 -0
- package/src/lib/hexclave-app/apps/implementations/server-app-impl.ts +27 -2
- package/src/lib/hexclave-app/apps/interfaces/client-app.ts +1 -0
- package/src/pushed-config-error-overlay/index.ts +1 -1
- package/src/utils/session-storage.ts +45 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { recordRedirectAndThrowIfLoopDetected } from "./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
|
+
recordRedirectAndThrowIfLoopDetected({
|
|
20
|
+
currentUrl: new URL(from),
|
|
21
|
+
targetUrl: new URL(to)
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
describe("recordRedirectAndThrowIfLoopDetected", () => {
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
Reflect.set(globalThis, "window", { sessionStorage: createMockSessionStorage() });
|
|
27
|
+
vi.useFakeTimers();
|
|
28
|
+
vi.setSystemTime(/* @__PURE__ */ new Date("2026-01-01T00:00:00Z"));
|
|
29
|
+
});
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
vi.useRealTimers();
|
|
32
|
+
if (hadPreviousWindow) Reflect.set(globalThis, "window", previousWindow);
|
|
33
|
+
else Reflect.deleteProperty(globalThis, "window");
|
|
34
|
+
});
|
|
35
|
+
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
|
+
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
|
+
vi.advanceTimersByTime(1e3);
|
|
42
|
+
}
|
|
43
|
+
expect(() => {
|
|
44
|
+
record("https://app.example.test/dashboard", "https://hosted.example.test/handler/sign-in");
|
|
45
|
+
}).toThrowError(/Redirect loop detected/);
|
|
46
|
+
});
|
|
47
|
+
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
|
+
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
|
+
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
|
+
vi.advanceTimersByTime(31e3);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
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
|
+
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
|
+
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
|
+
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
|
+
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
|
+
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
|
+
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
|
+
export {};
|
|
91
|
+
|
|
92
|
+
//# 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,qCAAqC;EACnC,YAAY,IAAI,IAAI,IAAI;EACxB,WAAW,IAAI,IAAI,EAAE;CACvB,CAAC;AACH;AAEA,SAAS,8CAA8C;CACrD,iBAAiB;EACf,QAAQ,IAAI,YAAY,UAAU,EAAE,gBAAgB,yBAAyB,EAAE,CAAC;EAChF,GAAG,cAAc;EACjB,GAAG,8BAAc,IAAI,KAAK,sBAAsB,CAAC;CACnD,CAAC;CAED,gBAAgB;EACd,GAAG,cAAc;EACjB,IAAI,mBACF,QAAQ,IAAI,YAAY,UAAU,cAAc;OAEhD,QAAQ,eAAe,YAAY,QAAQ;CAE/C,CAAC;CAED,GAAG,uDAAuD;EACxD,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KACtB,OAAO,iCAAiC,KAAK,iCAAiC,IAAI,GAAG;CAEzF,CAAC;CAED,GAAG,yEAAyE;EAC1E,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;GAC1B,OAAO,sCAAsC,6CAA6C;GAC1F,GAAG,oBAAoB,GAAI;EAC7B;EACA,aAAa;GACX,OAAO,sCAAsC,6CAA6C;EAC5F,CAAC,CAAC,CAAC,aAAa,wBAAwB;CAC1C,CAAC;CAED,GAAG,gFAAgF;EAEjF,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KACrB,OACE,gDAAgD,KAChD,2DAA2D,EAAE,QAAQ,GACvE;EAEF,aAAa;GACX,OAAO,iDAAiD,yDAAyD;EACnH,CAAC,CAAC,CAAC,aAAa,wBAAwB;CAC1C,CAAC;CAED,GAAG,sFAAsF;EACvF,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;GAC3B,OAAO,sCAAsC,6CAA6C;GAC1F,GAAG,oBAAoB,IAAM;EAC/B;CACF,CAAC;CAED,GAAG,gEAAgE;EACjE,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KACrB,OAAO,sCAAsC,6CAA6C;EAE5F,aAAa;GACX,OAAO,sCAAsC,6CAA6C;EAC5F,CAAC,CAAC,CAAC,aAAa,wBAAwB;EAExC,OAAO,sCAAsC,6CAA6C;CAC5F,CAAC;CAED,GAAG,oEAAoE;EACrE,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KACrB,OAAO,uDAAuD,KAAK,6CAA6C;EAElH,aAAa;GACX,OAAO,6DAA6D,6CAA6C;EACnH,CAAC,CAAC,CAAC,aAAa,wBAAwB;CAC1C,CAAC;CAED,GAAG,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,GAAG,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,aAAa;GACX,OAAO,sCAAsC,6CAA6C;EAC5F,CAAC,CAAC,CAAC,aAAa,wBAAwB;CAC1C,CAAC;AACH,CAAC"}
|
|
@@ -35,6 +35,7 @@ declare class _HexclaveServerAppImplIncomplete<HasTokenStore extends boolean, Pr
|
|
|
35
35
|
private readonly _serverUsersCache;
|
|
36
36
|
private readonly _serverUserCache;
|
|
37
37
|
private readonly _serverTeamsCache;
|
|
38
|
+
private readonly _serverTeamCache;
|
|
38
39
|
protected _refreshTeamMembership(teamId: string, userId: string): Promise<void>;
|
|
39
40
|
private readonly _serverUserTeamInvitationsCache;
|
|
40
41
|
private readonly _serverTeamUserPermissionsCache;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-app-impl.d.ts","names":[],"sources":["../../../../../../src/lib/hexclave-app/apps/implementations/server-app-impl.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"server-app-impl.d.ts","names":[],"sources":["../../../../../../src/lib/hexclave-app/apps/implementations/server-app-impl.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA6Ca,gCAAA,kEAAkG,gCAAA,CAAiC,aAAA,EAAe,SAAA;EAAA,UAC3I,UAAA,EAAY,uBAAA;EAAA,iBAGb,uBAAA;EAAA,iBAOA,iBAAA;EAAA,iBAqBA,gBAAA;EAAA,iBAIA,iBAAA;EAAA,iBAUA,gBAAA;EAAA,UAeD,sBAAA,CAAuB,MAAA,UAAgB,MAAA,WAAc,OAAA;EAAA,iBAOpD,+BAAA;EAAA,iBAGA,+BAAA;EAAA,iBAUA,oCAAA;EAAA,iBAMA,kCAAA;EAuN6E;EAAA,iBAhN7E,2CAAA;EAmOqF;EAAA,iBArNrF,+BAAA;EAAA,iBAYA,iCAAA;EAAA,iBAMA,oDAAA;EAAA,iBAaA,8BAAA;EAAA,iBAKA,2BAAA;EAAA,iBAKA,2BAAA;EAAA,iBAKA,2BAAA;EAAA,iBAKA,kCAAA;EAAA,iBAKA,+BAAA;EAAA,iBAIA,uBAAA;EAAA,iBAIA,uBAAA;EAAA,iBASA,uBAAA;EAAA,iBASA,2BAAA;EAAA,iBAOA,uBAAA;EAAA,iBAUA,0BAAA;EAAA,iBAMA,qBAAA;EAAA,iBAMA,qBAAA;EAAA,iBAMA,uBAAA;EAAA,iBAMA,wBAAA;EAAA,iBAWA,wBAAA;EAAA,iBAWA,0BAAA;EAAA,UAWP,qBAAA,CAAsB,cAAA,UAAwB,IAAA,oBAAwB,IAAA,CAAK,QAAA;EAAA,QAgCvE,iBAAA;EAAA,UAMJ,kCAAA,CAAmC,IAAA,EAAM,sBAAA,qBAA2C,yBAAA;EAAA,UAmBpF,6BAAA,CAA8B,MAAA,UAAgB,IAAA,EAAM,mBAAA,qBAAwC,oBAAA;EAAA,UA6B5F,mCAAA,CAAoC,MAAA,UAAgB,IAAA,EAAM,0BAAA,qBAA+C,oBAAA;EAAA,UAezG,4BAAA,CAA6B,IAAA,EAAM,iBAAA;;;;;;;;;MAWpB,SAAA;MAAoB,KAAA;MAAgB,WAAA;MAAuB,sBAAA;IAAA,IAAqC,OAAA,CAAQ,MAAA,OAC3H,YAAA,QAAoB,WAAA,CAAY,0CAAA;;;cAgC1B,OAAA,EAAS,gCAAA,CAAiC,aAAA,EAAe,SAAA,GAAY,YAAA;IAAiB,gBAAA;IAA2B,WAAA;IAAsB,SAAA,GAAY,uBAAA;EAAA;EAAA,UAuBrJ,qBAAA,CAAsB,IAAA,EAAM,eAAA,qBAAoC,MAAA;EAAA,UAChE,qBAAA,CAAsB,IAAA,EAAM,eAAA,qBAAoC,MAAA;EAAA,UAChE,qBAAA,CAAsB,IAAA,EAAM,GAAA,CAAI,SAAA,QAAiB,6BAAA,IAAiC,MAAA;EAAA,UAClF,qBAAA,CAAsB,IAAA,EAAM,GAAA,CAAI,SAAA,QAAiB,6BAAA,IAAiC,MAAA;EAAA,UAuBlF,wCAAA,CACR,MAAA,UACA,IAAA;IAAQ,QAAA;IAAkB,mBAAA;EAAA,IACzB,eAAA;EAAA,UAoBO,mBAAA,CAAoB,IAAA,EAAM,SAAA,qBAA8B,UAAA;EAAA,UAiUxD,uBAAA,CAAwB,IAAA,EAAM,sBAAA,qBAA2C,cAAA;EAAA,UAYzE,iCAAA,CAAkC,IAAA,EAAM,kBAAA,qBAAuC,kBAAA;EAAA,UAY/E,qCAAA,CAAsC,MAAA,UAAgB,IAAA,EAAM,kBAAA,qBAAuC,sBAAA;EAAA,UAmB1F,oBAAA,CAAqB,IAAA,EAAM,SAAA,oBAA6B,OAAA,EAAS,eAAA,GAAkB,wBAAA,CAAyB,SAAA;EAAA,UAUrH,mBAAA,CAAoB,IAAA,EAAM,SAAA,qBAA8B,UAAA;EAAA,UAyExD,mBAAA,CAAoB,QAAA;IAAY,IAAA;IAAkC,EAAA;EAAA,GAAc,IAAA,EAAM,QAAA,qBAA6B,UAAA;EAAA,UAkD7G,cAAA,CAAe,OAAA;IAAW,MAAA;EAAA,IAAmB,OAAA,CAAQ,MAAA;EAAA,UAKrD,cAAA,CAAe,OAAA;IAAW,MAAA;EAAA,IAAmB,OAAA,CAAQ,MAAA;EAAA,UAIrD,gBAAA,CAAiB,MAAA,WAAiB,OAAA,CAAQ,UAAA;EAAA,UAQ1C,gBAAA,CAAiB,GAAA,EAAK,SAAA,EAAW,gBAAA,YAA4B,OAAA,CAAQ,UAAA;EAAA,UAYrE,gBAAA,CAAiB,MAAA,WAAiB,OAAA,CAAQ,UAAA;EAQpD,UAAA,CAAW,OAAA,EAAS,uBAAA,GAA0B,OAAA,CAAQ,UAAA;EAMtD,OAAA,CAAQ,OAAA,EAAS,qBAAA,CAAsB,aAAA;IAAmB,EAAA;EAAA,IAAmB,OAAA,CAAQ,wBAAA,CAAyB,SAAA;EAC9G,OAAA,CAAQ,OAAA,EAAS,qBAAA,CAAsB,aAAA;IAAmB,EAAA;EAAA,IAAgB,OAAA,CAAQ,wBAAA,CAAyB,SAAA;EAC3G,OAAA,CAAQ,OAAA,EAAS,qBAAA,CAAsB,aAAA;IAAmB,EAAA;EAAA,IAAoB,OAAA,CAAQ,wBAAA,CAAyB,SAAA;EAC/G,OAAA,CAAQ,OAAA,GAAU,qBAAA,CAAsB,aAAA,IAAiB,OAAA,CAAQ,wBAAA,CAAyB,SAAA;EAC1F,OAAA,CAAQ,EAAA,WAAa,OAAA,CAAQ,UAAA;EAC7B,OAAA,CAAQ,OAAA;IAAW,MAAA;EAAA,IAAmB,OAAA,CAAQ,UAAA;EAC9C,OAAA,CAAQ,OAAA;IAAW,IAAA;IAAgB,GAAA,EAAK,SAAA;IAAW,EAAA;EAAA,IAAqC,OAAA,CAAQ,UAAA;EAqDhG,aAAA,IAAiB,OAAA,CAAQ,wBAAA,CAAyB,SAAA;EAKlD,iBAAA,CAAkB,MAAA,WAAiB,OAAA,CAAQ,UAAA;EAM3C,SAAA,CAAU,OAAA,GAAU,sBAAA,GAAyB,OAAA,CAAQ,UAAA;IAAiB,UAAA;EAAA;EAS5E,yBAAA,CAA0B,IAAA,EAAM,mBAAA,qBAAwC,sBAAA,qBAA2C,mBAAA;EAMnH,uCAAA,CAAwC,IAAA,EAAM,6BAAA,oBAAiD,6BAAA;EAQ/F,0CAAA,CAA2C,IAAA,EAAM,gCAAA,oBAAoD,gCAAA;EAQ/F,OAAA,CAAQ,OAAA;IAAW,MAAA;IAAgB,MAAA;EAAA;IAAqB,MAAA;IAAgB,MAAA;EAAA;IAAqB,MAAA;IAAgB,gBAAA;EAAA,IAA6B,OAAA,CAAQ,UAAA;EAAA,UAaxI,iBAAA,CAAkB,YAAA,8BAA0C,UAAA,UAAoB,MAAA,WAAiB,OAAA;EAU3G,YAAA,CAAa,OAAA,EAAS,8BAAA,GAAiC,OAAA,CAAQ,oBAAA;EAAA,QAY7D,gBAAA;EAYF,YAAA,CAAa,OAAA;IACd,MAAA;EAAA;IAAqB,MAAA;EAAA;IAAqB,gBAAA;EAAA;IAC1C,SAAA;EAAA;IAAwB,OAAA,EAAS,aAAA;EAAA;IAClC,QAAA;EAAA,KACA,OAAA;EAmBE,iBAAA,CAAkB,OAAA;IACnB,MAAA;EAAA;IAAqB,MAAA;EAAA;IAAqB,gBAAA;EAAA;IAC1C,SAAA;EAAA;IAAwB,OAAA,EAAS,aAAA;EAAA;IAClC,SAAA;EAAA,KACA,OAAA;EAOE,UAAA,CAAW,IAAA,EAAM,uBAAA,GAA0B,OAAA,CAAQ,UAAA;EAOnD,SAAA,CAAU,OAAA,GAAU,sBAAA,GAAyB,OAAA,CAAQ,UAAA;IAAiB,UAAA;EAAA;EAQtE,yBAAA,CAA0B,MAAA,UAAgB,OAAA;IAAY,SAAA;EAAA,IAAwB,OAAA;IAAU,MAAA;IAAgB,YAAA;EAAA;EAOxG,OAAA,CAAQ,OAAA;IAAW,MAAA;EAAA,IAAmB,OAAA,CAAQ,UAAA;EAC9C,OAAA,CAAQ,MAAA,WAAiB,OAAA,CAAQ,UAAA;EAAA,UAe7B,2BAAA,CAA4B,EAAA,WAAa,cAAA;EAiB7C,iBAAA,CAAkB,EAAA,WAAa,OAAA,CAAQ,cAAA;EAKvC,SAAA,CAAU,OAAA,EAAS,gBAAA,GAAmB,OAAA;EAKtC,qBAAA,IAAyB,OAAA,CAAQ,iBAAA;EAKjC,0BAAA,IAA8B,OAAA;EAM9B,cAAA,CAAe,OAAA,EAAS,qBAAA,GAAwB,OAAA,CAAQ,sBAAA;EAAA,UAIrC,eAAA,CAAgB,OAAA,EAAS,eAAA,GAAe,OAAA;EAAA,UAOxC,aAAA,IAAa,OAAA;EAWhC,mBAAA,CAAoB,OAAA;IACxB,MAAA;IACA,gBAAA;IACA,SAAA;IACA,KAAA;IACA,WAAA;IACA,sBAAA;EAAA,IACE,OAAA,CAAQ,MAAA,CAAO,mBAAA,EAAqB,YAAA,QAAoB,WAAA,CAAY,0CAAA;AAAA"}
|
|
@@ -3,6 +3,7 @@ import { HexclaveServerInterface, KnownErrors } from "@hexclave/shared";
|
|
|
3
3
|
import { Result } from "@hexclave/shared/dist/utils/results";
|
|
4
4
|
import { clientVersion, createCache, createCacheBySession, getDefaultExtraRequestHeaders, getDefaultProjectId, getDefaultPublishableClientKey, getDefaultSecretServerKey, resolveApiUrls, resolveConstructorOptions } from "./common.js";
|
|
5
5
|
import { InternalSession } from "@hexclave/shared/dist/sessions";
|
|
6
|
+
import { isUuid } from "@hexclave/shared/dist/utils/uuids";
|
|
6
7
|
import { WebAuthnError, startRegistration } from "@simplewebauthn/browser";
|
|
7
8
|
import { constructRedirectUrl } from "../../../../utils/url.js";
|
|
8
9
|
import { apiKeyCreationOptionsToCrud, apiKeyUpdateOptionsToCrud } from "../../api-keys/index.js";
|
|
@@ -216,6 +217,15 @@ var _HexclaveServerAppImplIncomplete = class extends _HexclaveClientAppImplIncom
|
|
|
216
217
|
query
|
|
217
218
|
});
|
|
218
219
|
});
|
|
220
|
+
this._serverTeamCache = createCache(async ([teamId]) => {
|
|
221
|
+
if (!isUuid(teamId)) return null;
|
|
222
|
+
try {
|
|
223
|
+
return await this._interface.getServerTeam(teamId);
|
|
224
|
+
} catch (error) {
|
|
225
|
+
if (KnownErrors.TeamNotFound.isInstance(error)) return null;
|
|
226
|
+
throw error;
|
|
227
|
+
}
|
|
228
|
+
});
|
|
219
229
|
this._serverUserTeamInvitationsCache = createCache(async ([userId]) => {
|
|
220
230
|
return await this._interface.listServerUserTeamInvitations(userId);
|
|
221
231
|
});
|
|
@@ -709,11 +719,19 @@ var _HexclaveServerAppImplIncomplete = class extends _HexclaveClientAppImplIncom
|
|
|
709
719
|
serverMetadata: crud.server_metadata,
|
|
710
720
|
async update(update) {
|
|
711
721
|
await app._interface.updateServerTeam(crud.id, serverTeamUpdateOptionsToCrud(update));
|
|
712
|
-
await Promise.all([
|
|
722
|
+
await Promise.all([
|
|
723
|
+
app._serverTeamCache.refresh([crud.id]),
|
|
724
|
+
app._serverTeamsCache.refreshWhere(() => true),
|
|
725
|
+
app._serverUsersCache.refreshWhere(() => true)
|
|
726
|
+
]);
|
|
713
727
|
},
|
|
714
728
|
async delete() {
|
|
715
729
|
await app._interface.deleteServerTeam(crud.id);
|
|
716
|
-
await Promise.all([
|
|
730
|
+
await Promise.all([
|
|
731
|
+
app._serverTeamCache.refresh([crud.id]),
|
|
732
|
+
app._serverTeamsCache.refreshWhere(() => true),
|
|
733
|
+
app._serverUsersCache.refreshWhere(() => true)
|
|
734
|
+
]);
|
|
717
735
|
},
|
|
718
736
|
async listUsers() {
|
|
719
737
|
return Result.orThrow(await app._serverTeamMemberProfilesCache.getOrWait([crud.id], "write-only")).map((u) => app._serverTeamUserFromCrud(u));
|
|
@@ -1010,6 +1028,7 @@ var _HexclaveServerAppImplIncomplete = class extends _HexclaveClientAppImplIncom
|
|
|
1010
1028
|
}
|
|
1011
1029
|
async createTeam(data) {
|
|
1012
1030
|
const team = await this._interface.createServerTeam(serverTeamCreateOptionsToCrud(data));
|
|
1031
|
+
await this._serverTeamCache.refresh([team.id]);
|
|
1013
1032
|
await this._serverTeamsCache.refreshWhere(() => true);
|
|
1014
1033
|
return this._serverTeamFromCrud(team);
|
|
1015
1034
|
}
|
|
@@ -1037,7 +1056,9 @@ var _HexclaveServerAppImplIncomplete = class extends _HexclaveClientAppImplIncom
|
|
|
1037
1056
|
if (typeof options === "object" && "apiKey" in options) return await this._getTeamByApiKey(options.apiKey);
|
|
1038
1057
|
else {
|
|
1039
1058
|
const teamId = options;
|
|
1040
|
-
|
|
1059
|
+
if (teamId == null) return null;
|
|
1060
|
+
const team = Result.orThrow(await this._serverTeamCache.getOrWait([teamId], "write-only"));
|
|
1061
|
+
return team == null ? null : this._serverTeamFromCrud(team);
|
|
1041
1062
|
}
|
|
1042
1063
|
}
|
|
1043
1064
|
_createServerDataVaultStore(id) {
|