@cosmicdrift/kumiko-dev-server 0.78.0 → 0.79.2
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-dev-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.79.2",
|
|
4
4
|
"description": "Development server bootstrap for Kumiko apps. Bundles the client, mints dev-JWTs, injects the resolved AppSchema, and seeds an admin. Not for production.",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
"kumiko-schema-check": "./bin/kumiko-schema-check.ts"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@cosmicdrift/kumiko-bundled-features": "0.
|
|
54
|
-
"@cosmicdrift/kumiko-framework": "0.
|
|
53
|
+
"@cosmicdrift/kumiko-bundled-features": "0.79.2",
|
|
54
|
+
"@cosmicdrift/kumiko-framework": "0.79.2",
|
|
55
55
|
"ts-morph": "^28.0.0"
|
|
56
56
|
},
|
|
57
57
|
"publishConfig": {
|
|
@@ -13,6 +13,11 @@ import { composeFeatures } from "../compose-features";
|
|
|
13
13
|
|
|
14
14
|
const noopFeature = defineFeature("noop-app", () => {});
|
|
15
15
|
|
|
16
|
+
// Mirrors what the create-kumiko-app picker hands back when the user
|
|
17
|
+
// ticks an auto-mounted feature: a stub with the same name as a bundled
|
|
18
|
+
// one. The dedupe path drops it and warns.
|
|
19
|
+
const pickerAuthDupe = defineFeature("auth-email-password", () => {});
|
|
20
|
+
|
|
16
21
|
const HMAC_SECRET = "test-secret-with-at-least-32-bytes-aaa";
|
|
17
22
|
|
|
18
23
|
describe("composeFeatures", () => {
|
|
@@ -78,4 +83,29 @@ describe("composeFeatures", () => {
|
|
|
78
83
|
expect(handlerNames).toContain("login");
|
|
79
84
|
expect(handlerNames).toContain("logout");
|
|
80
85
|
});
|
|
86
|
+
|
|
87
|
+
test("app feature duplicating a bundled name is dropped (no createRegistry crash)", () => {
|
|
88
|
+
// Bug discovered during Phase 3 recording: create-kumiko-app's picker
|
|
89
|
+
// hands back createAuthEmailPasswordFeature() because the user ticked
|
|
90
|
+
// it in the recommended set; runDevApp then adds its OWN bundled
|
|
91
|
+
// copy via includeBundled:true, and createRegistry throws "Duplicate
|
|
92
|
+
// feature: auth-email-password". The dedupe path keeps the bundled
|
|
93
|
+
// instance (it carries authOptions wiring) and drops the app stub.
|
|
94
|
+
const features = composeFeatures([pickerAuthDupe, noopFeature], {
|
|
95
|
+
includeBundled: true,
|
|
96
|
+
});
|
|
97
|
+
expect(features.map((f) => f.name)).toEqual([
|
|
98
|
+
"config",
|
|
99
|
+
"user",
|
|
100
|
+
"tenant",
|
|
101
|
+
"auth-email-password",
|
|
102
|
+
"noop-app",
|
|
103
|
+
]);
|
|
104
|
+
// The kept instance is the bundled one — confirmed by the presence of
|
|
105
|
+
// login/logout handlers (the picker stub has none).
|
|
106
|
+
const auth = features.find((f) => f.name === "auth-email-password");
|
|
107
|
+
expect(auth).toBeDefined();
|
|
108
|
+
if (!auth) return;
|
|
109
|
+
expect(Object.keys(auth.writeHandlers)).toContain("login");
|
|
110
|
+
});
|
|
81
111
|
});
|
package/src/compose-features.ts
CHANGED
|
@@ -41,15 +41,33 @@ export function composeFeatures(
|
|
|
41
41
|
appFeatures: readonly FeatureDefinition[],
|
|
42
42
|
options: ComposeFeaturesOptions,
|
|
43
43
|
): FeatureDefinition[] {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
if (!options.includeBundled) return [...appFeatures];
|
|
45
|
+
|
|
46
|
+
// Bundled foundation goes first so its instances carry the runDevApp /
|
|
47
|
+
// runProdApp `authOptions` (passwordReset wiring etc.). App-features that
|
|
48
|
+
// ALSO declare one of these names — e.g. the create-kumiko-app picker
|
|
49
|
+
// hands back `createAuthEmailPasswordFeature()` because the user ticked
|
|
50
|
+
// it — would otherwise crash createRegistry with "Duplicate feature".
|
|
51
|
+
// Drop the app-side duplicates and warn so the user can clean run-config.
|
|
52
|
+
const bundled = [
|
|
53
|
+
createConfigFeature(),
|
|
54
|
+
createUserFeature(),
|
|
55
|
+
createTenantFeature(),
|
|
56
|
+
createAuthEmailPasswordFeature(options.authOptions ?? {}),
|
|
57
|
+
];
|
|
58
|
+
const bundledNames = new Set(bundled.map((f) => f.name));
|
|
59
|
+
const filteredApp: FeatureDefinition[] = [];
|
|
60
|
+
for (const f of appFeatures) {
|
|
61
|
+
if (bundledNames.has(f.name)) {
|
|
62
|
+
// biome-ignore lint/suspicious/noConsole: boot-time UX warning
|
|
63
|
+
console.warn(
|
|
64
|
+
`[composeFeatures] "${f.name}" already auto-mounted via includeBundled — dropping the explicit copy from APP_FEATURES. Remove it from run-config.ts to silence this warning.`,
|
|
65
|
+
);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
filteredApp.push(f);
|
|
69
|
+
}
|
|
70
|
+
return [...bundled, ...filteredApp];
|
|
53
71
|
}
|
|
54
72
|
|
|
55
73
|
/** Shape eines beliebigen run{Prod,Dev}App-Auth-Blocks der eine
|