@cosmicdrift/kumiko-server-runtime 0.198.0 → 0.199.1
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.199.1",
|
|
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>",
|
|
@@ -80,8 +80,8 @@
|
|
|
80
80
|
}
|
|
81
81
|
},
|
|
82
82
|
"dependencies": {
|
|
83
|
-
"@cosmicdrift/kumiko-bundled-features": "0.
|
|
84
|
-
"@cosmicdrift/kumiko-framework": "0.
|
|
83
|
+
"@cosmicdrift/kumiko-bundled-features": "0.199.1",
|
|
84
|
+
"@cosmicdrift/kumiko-framework": "0.199.1",
|
|
85
85
|
"temporal-polyfill": "^0.3.2"
|
|
86
86
|
},
|
|
87
87
|
"publishConfig": {
|
|
@@ -532,6 +532,49 @@ describe("runProdApp", () => {
|
|
|
532
532
|
const adminBody = await adminRes.text();
|
|
533
533
|
expect(adminBody).toContain("ADMIN");
|
|
534
534
|
expect(adminBody).toContain("__KUMIKO_SCHEMA__");
|
|
535
|
+
|
|
536
|
+
// #2062: this boot()'s widgetFeature never wires extraContext.searchAdapter,
|
|
537
|
+
// so run-prod-app's `searchAdapterMissing = !(extraContext).searchAdapter`
|
|
538
|
+
// must actually flip true and flow into the injected schema — proving
|
|
539
|
+
// the cast-boundary read isn't silently always-false.
|
|
540
|
+
const schemaMatch = adminBody.match(/window\.__KUMIKO_SCHEMA__=(\{.*?\});<\/script>/s);
|
|
541
|
+
expect(schemaMatch).not.toBeNull();
|
|
542
|
+
const injectedSchema = JSON.parse(schemaMatch?.[1] ?? "{}");
|
|
543
|
+
// Guards against a regex miss silently degrading to `?? "{}"` — an empty
|
|
544
|
+
// features array would make `.every(...)` below vacuously true too.
|
|
545
|
+
expect(injectedSchema.features.length).toBeGreaterThan(0);
|
|
546
|
+
const allFeaturesMissingAdapter = injectedSchema.features.every(
|
|
547
|
+
(f: { searchAdapterMissing?: boolean }) => f.searchAdapterMissing === true,
|
|
548
|
+
);
|
|
549
|
+
expect(allFeaturesMissingAdapter).toBe(true);
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
test("extraContext.searchAdapter wired → injected schema omits searchAdapterMissing (#2062)", async () => {
|
|
553
|
+
const tmpStaticDir = await createTempStaticDir({
|
|
554
|
+
"index.html": "<html><body>ADMIN</body><script src=/client.js></script></html>",
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
const handle = await boot(undefined, {
|
|
558
|
+
staticDir: tmpStaticDir,
|
|
559
|
+
// Presence-only probe — run-prod-app's cast-boundary read only checks
|
|
560
|
+
// truthiness, so a minimal stand-in is enough without pulling in the
|
|
561
|
+
// real SearchAdapter shape.
|
|
562
|
+
extraContext: { searchAdapter: { configure: async () => {}, search: async () => [] } },
|
|
563
|
+
hostDispatch: () => ({ kind: "html", file: "index.html", injectSchema: true }),
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
const res = await handle.fetch(new Request("http://demo.example.test/"));
|
|
567
|
+
const body = await res.text();
|
|
568
|
+
const schemaMatch = body.match(/window\.__KUMIKO_SCHEMA__=(\{.*?\});<\/script>/s);
|
|
569
|
+
expect(schemaMatch).not.toBeNull();
|
|
570
|
+
const injectedSchema = JSON.parse(schemaMatch?.[1] ?? "{}");
|
|
571
|
+
// Guards against a regex miss silently degrading to `?? "{}"` — an empty
|
|
572
|
+
// features array would make `.some(...)` below vacuously false too.
|
|
573
|
+
expect(injectedSchema.features.length).toBeGreaterThan(0);
|
|
574
|
+
const anyFeatureMissingAdapter = injectedSchema.features.some(
|
|
575
|
+
(f: { searchAdapterMissing?: boolean }) => f.searchAdapterMissing === true,
|
|
576
|
+
);
|
|
577
|
+
expect(anyFeatureMissingAdapter).toBe(false);
|
|
535
578
|
});
|
|
536
579
|
|
|
537
580
|
test("hostDispatch: redirect-Modus", async () => {
|
package/src/run-prod-app.ts
CHANGED
|
@@ -930,6 +930,11 @@ export async function runProdApp(options: RunProdAppOptions): Promise<ProdAppHan
|
|
|
930
930
|
{ ...autoExtraContext, ...resolvedExtraContext },
|
|
931
931
|
registry,
|
|
932
932
|
);
|
|
933
|
+
// @cast-boundary engine-bridge — searchAdapter is an optional context-extension
|
|
934
|
+
// (SharedContextFields.searchAdapter), invisible to extraContext's loose
|
|
935
|
+
// Record<string, unknown>-based typing. Presence check only, no need to
|
|
936
|
+
// pull in the SearchAdapter type here.
|
|
937
|
+
const searchAdapterMissing = !(extraContext as { searchAdapter?: unknown }).searchAdapter;
|
|
933
938
|
const baseAnonymousAccess =
|
|
934
939
|
typeof options.anonymousAccess === "function"
|
|
935
940
|
? options.anonymousAccess(deps)
|
|
@@ -1148,7 +1153,7 @@ export async function runProdApp(options: RunProdAppOptions): Promise<ProdAppHan
|
|
|
1148
1153
|
// pro Tenant, Auth-Rolle gated Screens), muss die Injection pro
|
|
1149
1154
|
// Request rendern — staticDir-Fallback einen render(req)-Hook bekommen
|
|
1150
1155
|
// statt eines fixed JSON-Strings. Heute: registry-static, also OK.
|
|
1151
|
-
const appSchemaJson = JSON.stringify(buildAppSchema(registry));
|
|
1156
|
+
const appSchemaJson = JSON.stringify(buildAppSchema(registry, { searchAdapterMissing }));
|
|
1152
1157
|
|
|
1153
1158
|
// App-eigene HTTP-Routes mounten — VOR den Seeds (symmetrisch zum
|
|
1154
1159
|
// dev-server, siehe create-kumiko-server.ts). Ein Seed, der über den
|