@cosmicdrift/kumiko-dev-server 0.363.0 → 0.365.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.
@@ -127,7 +127,8 @@ const editScreen: EntityEditScreenDefinition = {
127
127
  const open = {
128
128
  access: {
129
129
  openToAll: {
130
- reason: "scaffolded demo handler: every signed-in user of the demo tenant manages their tasks",
130
+ reason:
131
+ "scaffolded demo handler: every signed-in user of the demo tenant manages their tasks",
131
132
  },
132
133
  },
133
134
  } as const;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-dev-server",
3
- "version": "0.363.0",
3
+ "version": "0.365.0",
4
4
  "description": "Dev-tooling for Kumiko apps: local dev-server bootstrap (runDevApp), scaffolding, codegen. Its compose-stacks/env-schema subpaths are consumed at prod boot too — see @cosmicdrift/kumiko-server-runtime for the prod runner itself.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -60,17 +60,16 @@
60
60
  "kumiko-dev": "./bin/kumiko-dev.ts",
61
61
  "kumiko-init-deploy": "./bin/kumiko-init-deploy.ts",
62
62
  "kumiko-schema": "./bin/kumiko-schema.ts",
63
- "kumiko-schema-check": "./bin/kumiko-schema-check.ts",
64
63
  "kumiko-upgrade": "./bin/kumiko-upgrade.ts"
65
64
  },
66
65
  "dependencies": {
67
- "@cosmicdrift/kumiko-bundled-features": "0.363.0",
68
- "@cosmicdrift/kumiko-framework": "0.363.0",
69
- "@cosmicdrift/kumiko-headless": "0.363.0",
70
- "@cosmicdrift/kumiko-renderer-mail-html": "0.363.0",
71
- "@cosmicdrift/kumiko-renderer-web": "0.363.0",
72
- "@cosmicdrift/kumiko-server-runtime": "0.363.0",
73
- "@cosmicdrift/kumiko-types": "0.363.0",
66
+ "@cosmicdrift/kumiko-bundled-features": "0.365.0",
67
+ "@cosmicdrift/kumiko-framework": "0.365.0",
68
+ "@cosmicdrift/kumiko-headless": "0.365.0",
69
+ "@cosmicdrift/kumiko-renderer-mail-html": "0.365.0",
70
+ "@cosmicdrift/kumiko-renderer-web": "0.365.0",
71
+ "@cosmicdrift/kumiko-server-runtime": "0.365.0",
72
+ "@cosmicdrift/kumiko-types": "0.365.0",
74
73
  "bun-types": "^1.3.13",
75
74
  "ts-morph": "^28.0.0",
76
75
  "zod": "^4.4.3"
package/src/changes.json CHANGED
@@ -1,4 +1,47 @@
1
1
  [
2
+ {
3
+ "version": "0.365.0",
4
+ "type": "fix",
5
+ "title": "New projects read the prod admin password from DEMO_ADMIN_PASSWORD",
6
+ "detail": "The scaffolded bin/main.ts no longer seeds the prod admin with a fixed password. It reads DEMO_ADMIN_PASSWORD (declared in the env schema, min 12 chars), and boot fails without it. Existing apps are untouched; apps from an older scaffold should change bin/main.ts the same way."
7
+ },
8
+ {
9
+ "version": "0.365.0",
10
+ "type": "fix",
11
+ "title": "A freshly scaffolded app passes bun run lint without rework",
12
+ "detail": "New projects now get a .gitignore, an exactly pinned @biomejs/biome and lint-clean generated files (import order, formatting). Existing apps are untouched."
13
+ },
14
+ {
15
+ "version": "0.365.0",
16
+ "type": "improvement",
17
+ "title": "composeRendererStack passes a mail brand suffix resolver",
18
+ "detail": "composeRendererStack({ mailBrandSuffix }) hands the resolver to createRendererMailHtmlFeature as brandSuffix."
19
+ },
20
+ {
21
+ "version": "0.365.0",
22
+ "type": "improvement",
23
+ "title": "composeRendererStack passes a mail footer resolver to the mail renderer",
24
+ "detail": "composeRendererStack({ mailFooter }) hands the resolver to createRendererMailHtmlFeature, so apps on the composed stack set imprint, privacy and platform line in one place."
25
+ },
26
+ {
27
+ "version": "0.365.0",
28
+ "type": "breaking",
29
+ "title": "The kumiko-schema-check bin and the resolveGeneratePath, usesDerivedSchemaLayout and implicitAuthModeFeatureNames exports are removed",
30
+ "detail": "kumiko-schema-check diffed APP_FEATURES against a hand-kept FEATURE_IMPORT_REGISTRY. Apps with kumiko/schema.ts derive their entities from the mounted features and have no registry that could drift, so the check was a no-op there. The helpers resolveGeneratePath, usesDerivedSchemaLayout and implicitAuthModeFeatureNames are no longer exported from @cosmicdrift/kumiko-dev-server/cli.",
31
+ "migration": "Apps with kumiko/schema.ts need nothing. Run kumiko-schema validate to check migrations against the mounted features, and remove kumiko-schema-check from package scripts and CI. Apps that keep a FEATURE_IMPORT_REGISTRY diff it against APP_FEATURES in their own coverage script."
32
+ },
33
+ {
34
+ "version": "0.365.0",
35
+ "type": "fix",
36
+ "title": "buildServerBundle resolves worker and bootstrap entries as .ts or .js; runDevApp stop keeps an explicit blindIndexKey",
37
+ "detail": "An app with bin/main.js and bin/worker.js used to get no dist-server/worker.js without any warning, because only worker.ts and bootstrap.ts were looked up. Siblings now resolve like the server entry, .ts first and then .js. In the ephemeral PII default, stopping runDevApp unset a blindIndexKey that the app passed itself; it now unsets only the key the default generated."
38
+ },
39
+ {
40
+ "version": "0.364.0",
41
+ "type": "fix",
42
+ "title": "runDevApp resolves the masterKey provider before boot validation",
43
+ "detail": "runDevApp validated encrypted fields before building the boot cipher, so an app that supplies masterKey and has no KUMIKO_SECRETS_MASTER_KEY_V1 in the environment booted in production but failed locally with no usable master key. The provider now reaches validateBoot like in runProdApp and runWorkerApp."
44
+ },
2
45
  {
3
46
  "version": "0.363.0",
4
47
  "type": "improvement",
@@ -1,175 +0,0 @@
1
- #!/usr/bin/env bun
2
- // biome-ignore-all lint/suspicious/noConsole: CLI-Script, console ist Feature.
3
- //
4
- // kumiko schema check — Empfehlung 3 aus Sprint-9.8-Retro
5
- // (luminous-watching-moler.md). Diff't APP_FEATURES (runtime, aus
6
- // `src/run-config.ts`) gegen FEATURE_IMPORT_REGISTRY (statisch, aus
7
- // `drizzle/generate.ts`). Catches:
8
- //
9
- // 1. Mount-without-registry: ein neues feature in APP_FEATURES ohne
10
- // Entry in FEATURE_IMPORT_REGISTRY. Resultiert in Schema-Drift:
11
- // Runtime mountet feature, Migration kennt seine Tabellen nicht.
12
- // 2. Stale-registry: ein Entry in FEATURE_IMPORT_REGISTRY ohne
13
- // matching mount in APP_FEATURES. Dead-code; im Schema entsteht
14
- // eine Tabelle ohne Runtime-Konsument.
15
- //
16
- // Studio's 9.8-Drama: FEATURE_IMPORT_REGISTRY war 18 features hinter
17
- // APP_FEATURES. Hätte mit diesem check eine Sekunde Lokal gefangen.
18
- //
19
- // Usage (aus dem app-workspace):
20
- // bunx kumiko-schema-check
21
- // # oder mit explicit pfaden:
22
- // bunx kumiko-schema-check --run-config src/run-config.ts --generate drizzle/generate.ts
23
- //
24
- // Exit 0 wenn alles in sync, exit 1 wenn drift.
25
-
26
- import { existsSync, readFileSync } from "node:fs";
27
- import { resolve } from "node:path";
28
- import {
29
- implicitAuthModeFeatureNames,
30
- resolveGeneratePath,
31
- } from "@cosmicdrift/kumiko-dev-server/cli";
32
-
33
- type Args = {
34
- readonly runConfigPath: string;
35
- readonly generatePath: string;
36
- };
37
-
38
- function parseArgs(argv: readonly string[]): Args {
39
- const cwd = process.cwd();
40
- let runConfigPath = resolve(cwd, "src/run-config.ts");
41
- let generatePath: string | undefined;
42
- for (let i = 0; i < argv.length; i++) {
43
- const flag = argv[i];
44
- const value = argv[i + 1];
45
- if (flag === "--run-config" && value) {
46
- runConfigPath = resolve(cwd, value);
47
- i++;
48
- } else if (flag === "--generate" && value) {
49
- generatePath = resolve(cwd, value);
50
- i++;
51
- }
52
- }
53
- return { runConfigPath, generatePath: generatePath ?? resolveGeneratePath(cwd) };
54
- }
55
-
56
- function readRegistryFeatures(generateSrc: string): Set<string> {
57
- // Match object-keys mit Discriminator `kind: "factory" | "named"`.
58
- // Quoted ("billing-foundation") oder unquoted (config, user) — beides
59
- // ist gültig in JS. Pattern aus use-all-bundled/scripts/check-coverage.ts
60
- // dupliziert hier weil per-app-CLI nicht von sample-script lesen darf.
61
- const re = /(?:"([a-z][a-z0-9-]*)"|([a-z][a-z0-9]*)):\s*\{\s*kind:\s*"(factory|named)"/g;
62
- const out = new Set<string>();
63
- for (const m of generateSrc.matchAll(re)) {
64
- const name = m[1] ?? m[2];
65
- if (name) out.add(name);
66
- }
67
- return out;
68
- }
69
-
70
- async function readMountedFeatures(runConfigPath: string): Promise<Set<string>> {
71
- const mod = (await import(runConfigPath)) as {
72
- APP_FEATURES?: ReadonlyArray<{ name: string }>;
73
- HAS_AUTH?: boolean;
74
- HAS_SIGNUP?: boolean;
75
- };
76
- if (!mod.APP_FEATURES) {
77
- throw new Error(
78
- `kumiko-schema-check: ${runConfigPath} hat kein 'APP_FEATURES' export. ` +
79
- `Convention: 'export const APP_FEATURES = [...] as const'.`,
80
- );
81
- }
82
- const set = new Set<string>();
83
- for (const f of mod.APP_FEATURES) {
84
- set.add(f.name);
85
- }
86
- // HAS_AUTH defaults to true (Studio/use-all-bundled convention). When set,
87
- // include the implicit auth-mode features so the diff doesn't false-positive
88
- // "auth-email-password is mounted but no registry-entry".
89
- if (mod.HAS_AUTH ?? true) {
90
- for (const name of implicitAuthModeFeatureNames()) set.add(name);
91
- }
92
- // auth-self-registration is only prepended when authOptions.signup is set
93
- // (composeFeatures) — opt-in via HAS_SIGNUP so apps without signup don't
94
- // get a stale-registry false positive (#1521).
95
- if (mod.HAS_SIGNUP === true) {
96
- set.add("auth-self-registration");
97
- }
98
- return set;
99
- }
100
-
101
- const USAGE = "Usage: kumiko-schema-check [--run-config <path>] [--generate <path>]";
102
-
103
- async function main(): Promise<void> {
104
- if (process.argv.slice(2).some((arg) => arg === "--help" || arg === "-h")) {
105
- console.log(USAGE);
106
- process.exit(0);
107
- }
108
- const args = parseArgs(process.argv.slice(2));
109
-
110
- if (!existsSync(args.runConfigPath)) {
111
- console.error(`✗ run-config not found: ${args.runConfigPath}`);
112
- process.exit(1);
113
- }
114
- if (!existsSync(args.generatePath)) {
115
- console.error(`✗ generate not found: ${args.generatePath}`);
116
- process.exit(1);
117
- }
118
-
119
- const registry = readRegistryFeatures(readFileSync(args.generatePath, "utf-8"));
120
- const mounted = await readMountedFeatures(args.runConfigPath);
121
-
122
- // Mounted but not in registry → schema-drift (runtime ↔ migration mismatch).
123
- const mountedWithoutEntry: string[] = [];
124
- for (const name of mounted) {
125
- if (!registry.has(name)) mountedWithoutEntry.push(name);
126
- }
127
- // In registry but not mounted → stale entry (dead schema-mapping).
128
- const staleEntries: string[] = [];
129
- for (const name of registry) {
130
- if (!mounted.has(name)) staleEntries.push(name);
131
- }
132
-
133
- let ok = true;
134
-
135
- if (mountedWithoutEntry.length > 0) {
136
- console.error(
137
- `\n✗ ${mountedWithoutEntry.length} feature(s) mounted in APP_FEATURES but NOT in FEATURE_IMPORT_REGISTRY:`,
138
- );
139
- for (const name of mountedWithoutEntry.sort()) {
140
- console.error(` - ${name}`);
141
- }
142
- console.error(
143
- "\n Action: in drizzle/generate.ts FEATURE_IMPORT_REGISTRY den Eintrag ergänzen,",
144
- );
145
- console.error(" damit Schema-Generator + Migration die feature-Tabellen kennt.");
146
- ok = false;
147
- }
148
-
149
- if (staleEntries.length > 0) {
150
- console.error(
151
- `\n✗ ${staleEntries.length} stale FEATURE_IMPORT_REGISTRY entry/entries (kein matching mount):`,
152
- );
153
- for (const name of staleEntries.sort()) {
154
- console.error(` - ${name}`);
155
- }
156
- console.error("\n Action: entry aus drizzle/generate.ts FEATURE_IMPORT_REGISTRY entfernen,");
157
- console.error(" oder das feature in src/run-config.ts mounten.");
158
- ok = false;
159
- }
160
-
161
- if (ok) {
162
- console.log(
163
- `✓ schema check: ${mounted.size} mounted ↔ ${registry.size} registry entries, no drift`,
164
- );
165
- process.exit(0);
166
- } else {
167
- process.exit(1);
168
- }
169
- }
170
-
171
- // Only run when executed as a CLI, not when imported (e.g. from tests that
172
- // exercise the exported pure helpers).
173
- if (import.meta.main) {
174
- await main();
175
- }
@@ -1,2 +0,0 @@
1
- export declare function resolveGeneratePath(cwd: string): string;
2
- export declare function implicitAuthModeFeatureNames(): readonly string[];
@@ -1,24 +0,0 @@
1
- // Pure helpers for the `kumiko-schema-check` bin. Kept in src/ (vs. the bin)
2
- // so they are part of the tsc project + unit-testable without importing the
3
- // auto-running CLI.
4
- import { existsSync } from "node:fs";
5
- import { resolve } from "node:path";
6
- import { composeFeatures } from "@cosmicdrift/kumiko-server-runtime/compose-features";
7
- // The generate-script lives under different roots across apps: publicstatus
8
- // uses `drizzle/generate.ts`, the framework's own sample-apps use
9
- // `schema/generate.ts`. Pick whichever exists so a no-arg `bunx
10
- // kumiko-schema-check` works in both layouts; default to `drizzle/` for the
11
- // error message when neither is present.
12
- export function resolveGeneratePath(cwd) {
13
- const drizzlePath = resolve(cwd, "drizzle/generate.ts");
14
- const schemaPath = resolve(cwd, "schema/generate.ts");
15
- if (!existsSync(drizzlePath) && existsSync(schemaPath))
16
- return schemaPath;
17
- return drizzlePath;
18
- }
19
- // The features composeFeatures auto-prepends in auth-mode (config + user +
20
- // tenant + auth-email-password). Derived from composeFeatures itself so this
21
- // can't drift from the real prepend-list in compose-features.ts.
22
- export function implicitAuthModeFeatureNames() {
23
- return composeFeatures([], { includeBundled: true }).map((f) => f.name);
24
- }