@cosmicdrift/kumiko-server-runtime 0.197.0 → 0.198.0
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-server-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.198.0",
|
|
4
4
|
"description": "Production server-boot runtime for Kumiko apps: connections, schema-drift-gate, seeds, lifecycle, graceful shutdown. Symmetric to kumiko-dev-server's runDevApp, without dev/scaffold/codegen tooling.",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -42,6 +42,10 @@
|
|
|
42
42
|
"types": "./src/pii-boot-gate.ts",
|
|
43
43
|
"default": "./src/pii-boot-gate.ts"
|
|
44
44
|
},
|
|
45
|
+
"./session-boot-gate": {
|
|
46
|
+
"types": "./src/session-boot-gate.ts",
|
|
47
|
+
"default": "./src/session-boot-gate.ts"
|
|
48
|
+
},
|
|
45
49
|
"./boot/apply-boot-seeds": {
|
|
46
50
|
"types": "./src/boot/apply-boot-seeds.ts",
|
|
47
51
|
"default": "./src/boot/apply-boot-seeds.ts"
|
|
@@ -76,8 +80,8 @@
|
|
|
76
80
|
}
|
|
77
81
|
},
|
|
78
82
|
"dependencies": {
|
|
79
|
-
"@cosmicdrift/kumiko-bundled-features": "0.
|
|
80
|
-
"@cosmicdrift/kumiko-framework": "0.
|
|
83
|
+
"@cosmicdrift/kumiko-bundled-features": "0.198.0",
|
|
84
|
+
"@cosmicdrift/kumiko-framework": "0.198.0",
|
|
81
85
|
"temporal-polyfill": "^0.3.2"
|
|
82
86
|
},
|
|
83
87
|
"publishConfig": {
|
|
@@ -1,22 +1,70 @@
|
|
|
1
|
-
import { describe, expect, test } from "bun:test";
|
|
1
|
+
import { describe, expect, spyOn, test } from "bun:test";
|
|
2
2
|
import { assertSessionBootInvariants } from "../session-boot-gate";
|
|
3
3
|
|
|
4
4
|
describe("assertSessionBootInvariants (#1372)", () => {
|
|
5
5
|
test("no auth → no throw", () => {
|
|
6
6
|
expect(() =>
|
|
7
|
-
assertSessionBootInvariants({
|
|
7
|
+
assertSessionBootInvariants({
|
|
8
|
+
hasAuth: false,
|
|
9
|
+
sessionStoreProviderMounted: false,
|
|
10
|
+
mode: "prod",
|
|
11
|
+
}),
|
|
8
12
|
).not.toThrow();
|
|
9
13
|
});
|
|
10
14
|
|
|
11
15
|
test("auth + sessionStore → no throw", () => {
|
|
12
16
|
expect(() =>
|
|
13
|
-
assertSessionBootInvariants({
|
|
17
|
+
assertSessionBootInvariants({
|
|
18
|
+
hasAuth: true,
|
|
19
|
+
sessionStoreProviderMounted: true,
|
|
20
|
+
mode: "prod",
|
|
21
|
+
}),
|
|
14
22
|
).not.toThrow();
|
|
15
23
|
});
|
|
16
24
|
|
|
17
|
-
test("auth without sessionStore →
|
|
25
|
+
test("prod: auth without sessionStore → BOOT ABORTED throw", () => {
|
|
18
26
|
expect(() =>
|
|
19
|
-
assertSessionBootInvariants({
|
|
27
|
+
assertSessionBootInvariants({
|
|
28
|
+
hasAuth: true,
|
|
29
|
+
sessionStoreProviderMounted: false,
|
|
30
|
+
mode: "prod",
|
|
31
|
+
}),
|
|
20
32
|
).toThrow(/BOOT ABORTED/);
|
|
21
33
|
});
|
|
22
34
|
});
|
|
35
|
+
|
|
36
|
+
// dev/prod split (#2027) — dev-server had no equivalent gate at all before
|
|
37
|
+
// this: a forgotten sessions mount silently left session-list empty with no
|
|
38
|
+
// signal. Mirrors assertPiiBootInvariants' dev/prod split (warn vs abort).
|
|
39
|
+
describe("assertSessionBootInvariants — dev mode (#2027)", () => {
|
|
40
|
+
test("dev: auth without sessionStore → warns, does NOT throw", () => {
|
|
41
|
+
const warnSpy = spyOn(console, "warn").mockImplementation(() => {});
|
|
42
|
+
try {
|
|
43
|
+
expect(() =>
|
|
44
|
+
assertSessionBootInvariants({
|
|
45
|
+
hasAuth: true,
|
|
46
|
+
sessionStoreProviderMounted: false,
|
|
47
|
+
mode: "dev",
|
|
48
|
+
}),
|
|
49
|
+
).not.toThrow();
|
|
50
|
+
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining("sessionStore"));
|
|
51
|
+
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining("[runDevApp]"));
|
|
52
|
+
} finally {
|
|
53
|
+
warnSpy.mockRestore();
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("dev: auth + sessionStore → no throw, no warn", () => {
|
|
58
|
+
const warnSpy = spyOn(console, "warn").mockImplementation(() => {});
|
|
59
|
+
try {
|
|
60
|
+
assertSessionBootInvariants({
|
|
61
|
+
hasAuth: true,
|
|
62
|
+
sessionStoreProviderMounted: true,
|
|
63
|
+
mode: "dev",
|
|
64
|
+
});
|
|
65
|
+
expect(warnSpy).not.toHaveBeenCalled();
|
|
66
|
+
} finally {
|
|
67
|
+
warnSpy.mockRestore();
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
package/src/run-prod-app.ts
CHANGED
|
@@ -799,6 +799,7 @@ export async function runProdApp(options: RunProdAppOptions): Promise<ProdAppHan
|
|
|
799
799
|
assertSessionBootInvariants({
|
|
800
800
|
hasAuth: Boolean(effectiveAuth),
|
|
801
801
|
sessionStoreProviderMounted: registry.getExtensionUsages(EXT_SESSION_STORE).length > 0,
|
|
802
|
+
mode: "prod",
|
|
802
803
|
});
|
|
803
804
|
|
|
804
805
|
// C1 boot-mode exit: validators ran + registry built; no DB/Redis client
|
package/src/session-boot-gate.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
export type SessionBootGateOptions = {
|
|
2
2
|
readonly hasAuth: boolean;
|
|
3
3
|
readonly sessionStoreProviderMounted: boolean;
|
|
4
|
+
/** prod fails hard on a missing sessionStore provider (stateless JWTs would
|
|
5
|
+
* silently skip server-side revocation and any session-list UI stays
|
|
6
|
+
* empty); dev only warns — a forgotten sessions mount in a local sample
|
|
7
|
+
* app shouldn't crash the dev-server boot, but it must not stay silent
|
|
8
|
+
* either (#2027 — dev previously had no gate here at all). */
|
|
9
|
+
readonly mode: "prod" | "dev";
|
|
4
10
|
};
|
|
5
11
|
|
|
6
12
|
// Catch a forgotten sessions mount at boot instead of silently degrading
|
|
@@ -12,9 +18,17 @@ export function assertSessionBootInvariants(opts: SessionBootGateOptions): void
|
|
|
12
18
|
// skip: sessionStore provider is wired (sessions feature).
|
|
13
19
|
if (opts.sessionStoreProviderMounted) return;
|
|
14
20
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
const tag = opts.mode === "prod" ? "runProdApp" : "runDevApp";
|
|
22
|
+
const message =
|
|
23
|
+
"auth is mounted but no sessionStore provider is registered. JWTs would be stateless " +
|
|
24
|
+
"(no server-side revocation) and any session-list screen stays empty. Mount " +
|
|
25
|
+
"createSessionsFeature() (@cosmicdrift/kumiko-bundled-features/sessions) alongside auth-foundation.";
|
|
26
|
+
|
|
27
|
+
if (opts.mode === "dev") {
|
|
28
|
+
// biome-ignore lint/suspicious/noConsole: boot-time ops warning, no logger configured this early
|
|
29
|
+
console.warn(`[${tag}] ${message}`);
|
|
30
|
+
// skip: dev mode, warning already logged above — never abort dev boot.
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
throw new Error(`[${tag}] BOOT ABORTED — ${message}`);
|
|
20
34
|
}
|