@cosmicdrift/kumiko-dev-server 0.329.0 → 0.330.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.
Files changed (125) hide show
  1. package/README.md +17 -0
  2. package/bin/kumiko-build.ts +3 -2
  3. package/bin/kumiko-dev.ts +1 -1
  4. package/bin/kumiko-init-deploy.ts +1 -1
  5. package/bin/kumiko-schema-check.ts +4 -1
  6. package/dist/build-server-bundle.d.ts +31 -0
  7. package/dist/build-server-bundle.js +282 -0
  8. package/dist/build.d.ts +2 -0
  9. package/dist/build.js +5 -0
  10. package/dist/cli.d.ts +5 -0
  11. package/dist/cli.js +9 -0
  12. package/dist/codegen/index.d.ts +4 -0
  13. package/dist/codegen/index.js +4 -0
  14. package/dist/codegen/render.d.ts +55 -0
  15. package/dist/codegen/render.js +273 -0
  16. package/dist/codegen/run-codegen.d.ts +20 -0
  17. package/dist/codegen/run-codegen.js +219 -0
  18. package/dist/codegen/scan-events.d.ts +76 -0
  19. package/dist/codegen/scan-events.js +447 -0
  20. package/dist/codegen/watch.d.ts +33 -0
  21. package/dist/codegen/watch.js +112 -0
  22. package/dist/compose-stacks.d.ts +60 -0
  23. package/dist/compose-stacks.js +127 -0
  24. package/dist/crash-tracker.d.ts +17 -0
  25. package/dist/crash-tracker.js +37 -0
  26. package/dist/create-kumiko-server.d.ts +195 -0
  27. package/dist/create-kumiko-server.js +1040 -0
  28. package/dist/env-schema.d.ts +15 -0
  29. package/dist/env-schema.js +60 -0
  30. package/dist/few-shot-corpus.d.ts +72 -0
  31. package/dist/few-shot-corpus.js +262 -0
  32. package/dist/framework-version.d.ts +1 -0
  33. package/dist/framework-version.js +31 -0
  34. package/dist/index.d.ts +22 -0
  35. package/dist/index.js +33 -0
  36. package/dist/init-deploy-cli.d.ts +10 -0
  37. package/dist/init-deploy-cli.js +111 -0
  38. package/dist/kebab.d.ts +1 -0
  39. package/{src/kebab.ts → dist/kebab.js} +2 -3
  40. package/dist/run-dev-app.d.ts +174 -0
  41. package/dist/run-dev-app.js +403 -0
  42. package/dist/scaffold-app-feature.d.ts +16 -0
  43. package/dist/scaffold-app-feature.js +240 -0
  44. package/dist/scaffold-app.d.ts +45 -0
  45. package/dist/scaffold-app.js +852 -0
  46. package/dist/scaffold-demo-tasks.d.ts +8 -0
  47. package/{src/scaffold-demo-tasks.ts → dist/scaffold-demo-tasks.js} +69 -98
  48. package/dist/scaffold-deploy.d.ts +92 -0
  49. package/dist/scaffold-deploy.js +254 -0
  50. package/dist/scaffold-feature.d.ts +26 -0
  51. package/dist/scaffold-feature.js +163 -0
  52. package/dist/schema-apply.d.ts +11 -0
  53. package/dist/schema-apply.js +95 -0
  54. package/dist/schema-check-core.d.ts +2 -0
  55. package/{src/schema-check-core.ts → dist/schema-check-core.js} +8 -10
  56. package/dist/schema-tables-auth-mode.d.ts +2 -0
  57. package/{src/schema-tables-auth-mode.ts → dist/schema-tables-auth-mode.js} +2 -10
  58. package/dist/schema-tables-minimal.d.ts +2 -0
  59. package/{src/schema-tables-minimal.ts → dist/schema-tables-minimal.js} +2 -11
  60. package/dist/setup-test-stack-from-features.d.ts +11 -0
  61. package/dist/setup-test-stack-from-features.js +42 -0
  62. package/dist/welcome-banner.d.ts +15 -0
  63. package/dist/welcome-banner.js +27 -0
  64. package/package.json +71 -24
  65. package/src/changes.json +6 -0
  66. package/src/__tests__/build-prod-bundle.integration.test.ts +0 -282
  67. package/src/__tests__/build-server-bundle.test.ts +0 -228
  68. package/src/__tests__/classify-change.test.ts +0 -87
  69. package/src/__tests__/compose-stacks.test.ts +0 -273
  70. package/src/__tests__/config-resolver-default.integration.test.ts +0 -165
  71. package/src/__tests__/crash-tracker.test.ts +0 -89
  72. package/src/__tests__/create-kumiko-server-errors.test.ts +0 -54
  73. package/src/__tests__/create-kumiko-server-options.test.ts +0 -33
  74. package/src/__tests__/create-kumiko-server.integration.test.ts +0 -1007
  75. package/src/__tests__/discover-format.test.ts +0 -32
  76. package/src/__tests__/env-schema.integration.test.ts +0 -248
  77. package/src/__tests__/env-schema.test.ts +0 -132
  78. package/src/__tests__/few-shot-corpus.test.ts +0 -316
  79. package/src/__tests__/framework-version.test.ts +0 -45
  80. package/src/__tests__/init-deploy-cli.test.ts +0 -113
  81. package/src/__tests__/kumiko-schema-check.test.ts +0 -56
  82. package/src/__tests__/merge-extra-context.test.ts +0 -67
  83. package/src/__tests__/resolve-stylesheet.test.ts +0 -132
  84. package/src/__tests__/run-dev-app-boot-validation.test.ts +0 -38
  85. package/src/__tests__/run-dev-app.integration.test.ts +0 -290
  86. package/src/__tests__/runtime-classification.test.ts +0 -26
  87. package/src/__tests__/saas-identity-wire.integration.test.ts +0 -427
  88. package/src/__tests__/scaffold-app-feature.test.ts +0 -216
  89. package/src/__tests__/scaffold-app.test.ts +0 -630
  90. package/src/__tests__/scaffold-demo-tasks.test.ts +0 -47
  91. package/src/__tests__/scaffold-deploy.test.ts +0 -464
  92. package/src/__tests__/scaffold-dev-cycle.integration.test.ts +0 -109
  93. package/src/__tests__/scaffold-feature.test.ts +0 -143
  94. package/src/__tests__/schema-apply.integration.test.ts +0 -191
  95. package/src/__tests__/setup-test-stack-from-features.integration.test.ts +0 -30
  96. package/src/__tests__/setup-test-stack-job-run-logger.integration.test.ts +0 -72
  97. package/src/__tests__/walkthrough.integration.test.ts +0 -140
  98. package/src/__tests__/welcome-banner.test.ts +0 -42
  99. package/src/build-server-bundle.ts +0 -346
  100. package/src/build.ts +0 -28
  101. package/src/codegen/__tests__/render-codegen.test.ts +0 -100
  102. package/src/codegen/__tests__/run-codegen.test.ts +0 -665
  103. package/src/codegen/__tests__/strict-mode-diagnostics.test.ts +0 -347
  104. package/src/codegen/__tests__/watch.test.ts +0 -222
  105. package/src/codegen/index.ts +0 -19
  106. package/src/codegen/render.ts +0 -305
  107. package/src/codegen/run-codegen.ts +0 -278
  108. package/src/codegen/scan-events.ts +0 -565
  109. package/src/codegen/watch.ts +0 -140
  110. package/src/compose-stacks.ts +0 -193
  111. package/src/crash-tracker.ts +0 -56
  112. package/src/create-kumiko-server.ts +0 -1397
  113. package/src/env-schema.ts +0 -72
  114. package/src/few-shot-corpus.ts +0 -370
  115. package/src/framework-version.ts +0 -39
  116. package/src/index.ts +0 -105
  117. package/src/init-deploy-cli.ts +0 -148
  118. package/src/run-dev-app.ts +0 -694
  119. package/src/scaffold-app-feature.ts +0 -283
  120. package/src/scaffold-app.ts +0 -1033
  121. package/src/scaffold-deploy.ts +0 -393
  122. package/src/scaffold-feature.ts +0 -226
  123. package/src/schema-apply.ts +0 -123
  124. package/src/setup-test-stack-from-features.ts +0 -80
  125. package/src/welcome-banner.ts +0 -43
@@ -0,0 +1,163 @@
1
+ // scaffoldFeature — generate a fresh feature workspace from a name.
2
+ // Used by `bun kumiko create <name>` and (later) by the Designer when
3
+ // a tenant scaffolds a new feature inside their repo. Wraps the
4
+ // canonical-form renderer (feature-ast/render.ts) so every freshly
5
+ // scaffolded feature is born in canonical Object-Form with the
6
+ // schema-version header set.
7
+ //
8
+ // The generated workspace is intentionally minimal: a single entity
9
+ // pattern as a starter, so the user has something to point a "bun
10
+ // kumiko dev" at and immediately see something on screen. Adding more
11
+ // patterns is the user's job (or the Designer's / AI's, on top of this
12
+ // scaffolding).
13
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
14
+ import { join, resolve } from "node:path";
15
+ import { renderFeatureFile, } from "@cosmicdrift/kumiko-framework/engine";
16
+ /**
17
+ * Generate a starter feature workspace at `destination`. Throws when
18
+ * the destination already exists — refuses to overwrite. The caller is
19
+ * expected to run `bun install` afterwards to wire the workspace.
20
+ */
21
+ export function scaffoldFeature(options) {
22
+ const featureName = validateFeatureName(options.name);
23
+ const repoRoot = options.repoRoot ?? process.cwd();
24
+ const kebab = camelToKebab(featureName);
25
+ const destination = resolve(options.destination
26
+ ? resolveDestination(options.destination, repoRoot)
27
+ : join(repoRoot, "samples", "recipes", kebab));
28
+ if (existsSync(destination)) {
29
+ throw new Error(`scaffoldFeature: destination already exists at ${destination} — refusing to overwrite`);
30
+ }
31
+ mkdirSync(join(destination, "src"), { recursive: true });
32
+ const packageName = `@cosmicdrift/kumiko-sample-${kebab}`;
33
+ const packageJson = renderPackageJson(packageName);
34
+ const packageJsonFile = join(destination, "package.json");
35
+ writeFileSync(packageJsonFile, packageJson);
36
+ const tsconfigFile = join(destination, "tsconfig.json");
37
+ writeFileSync(tsconfigFile, renderTsconfig());
38
+ const featureFile = join(destination, "src", "feature.ts");
39
+ const featureSource = renderFeatureFile({
40
+ featureName,
41
+ patterns: starterPatterns(),
42
+ });
43
+ writeFileSync(featureFile, featureSource);
44
+ return {
45
+ destination,
46
+ featureFile,
47
+ packageJsonFile,
48
+ tsconfigFile,
49
+ featureName,
50
+ packageName,
51
+ };
52
+ }
53
+ // =============================================================================
54
+ // Internal — name + path validation
55
+ // =============================================================================
56
+ const RESERVED_WORDS = new Set([
57
+ // Subset of TS reserved words that would be confusing as feature names.
58
+ "default",
59
+ "delete",
60
+ "function",
61
+ "import",
62
+ "export",
63
+ "class",
64
+ "interface",
65
+ "enum",
66
+ "type",
67
+ "module",
68
+ "package",
69
+ "private",
70
+ "protected",
71
+ "public",
72
+ "static",
73
+ "void",
74
+ "null",
75
+ "true",
76
+ "false",
77
+ ]);
78
+ const NAME_RE = /^[a-z][A-Za-z0-9]*$/;
79
+ function validateFeatureName(raw) {
80
+ if (!raw) {
81
+ throw new Error("scaffoldFeature: feature name is required");
82
+ }
83
+ if (!NAME_RE.test(raw)) {
84
+ throw new Error(`scaffoldFeature: "${raw}" is not a valid feature name — use camelCase starting with a lowercase letter (e.g. "todoList")`);
85
+ }
86
+ if (RESERVED_WORDS.has(raw)) {
87
+ throw new Error(`scaffoldFeature: "${raw}" is a reserved word and cannot be a feature name`);
88
+ }
89
+ return raw;
90
+ }
91
+ function camelToKebab(name) {
92
+ return name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
93
+ }
94
+ function resolveDestination(dest, repoRoot) {
95
+ // Allow callers to pass either an absolute path or a repo-relative
96
+ // one — keep both ergonomic. `resolve(repoRoot, dest)` is a no-op for
97
+ // absolute paths.
98
+ return resolve(repoRoot, dest);
99
+ }
100
+ // =============================================================================
101
+ // Internal — content generators
102
+ // =============================================================================
103
+ function renderPackageJson(packageName) {
104
+ return `${JSON.stringify({
105
+ name: packageName,
106
+ description: "Kumiko sample feature — scaffolded by `bun kumiko create`",
107
+ private: true,
108
+ dependencies: {
109
+ "@cosmicdrift/kumiko-framework": "workspace:*",
110
+ },
111
+ }, null, 2)}\n`;
112
+ }
113
+ /**
114
+ * Standard tsconfig matching the rest of the sample workspaces:
115
+ * strict, ESNext, bundler-resolution, no-emit. Without this file
116
+ * `bun install + tsc` immediately complains about missing config —
117
+ * scaffolded features should compile cleanly out of the box.
118
+ */
119
+ function renderTsconfig() {
120
+ return `${JSON.stringify({
121
+ compilerOptions: {
122
+ strict: true,
123
+ noUncheckedIndexedAccess: true,
124
+ noPropertyAccessFromIndexSignature: true,
125
+ forceConsistentCasingInFileNames: true,
126
+ verbatimModuleSyntax: true,
127
+ target: "ESNext",
128
+ module: "ESNext",
129
+ moduleResolution: "bundler",
130
+ esModuleInterop: true,
131
+ skipLibCheck: true,
132
+ lib: ["ESNext"],
133
+ types: ["bun-types"],
134
+ noEmit: true,
135
+ },
136
+ include: ["src/**/*"],
137
+ }, null, 2)}\n`;
138
+ }
139
+ // Synthetic SourceLocation — the renderer reads `.raw` only for opaque
140
+ // (closure-bearing) bodies. Static patterns like `entity` don't touch
141
+ // `source.raw` at render-time, so an empty placeholder is fine.
142
+ const SYNTHETIC_LOC = {
143
+ file: "<scaffold>",
144
+ start: { line: 1, column: 1 },
145
+ end: { line: 1, column: 1 },
146
+ raw: "",
147
+ };
148
+ function starterPatterns() {
149
+ // One entity, one field. Smallest interesting output: parses, renders,
150
+ // can be `bun kumiko dev`'d, and gives the user something to extend.
151
+ return [
152
+ {
153
+ kind: "entity",
154
+ source: SYNTHETIC_LOC,
155
+ entityName: "item",
156
+ definition: {
157
+ fields: {
158
+ title: { type: "text", required: true },
159
+ },
160
+ },
161
+ },
162
+ ];
163
+ }
@@ -0,0 +1,11 @@
1
+ import { type FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
2
+ import { type ComposeFeaturesOptions } from "@cosmicdrift/kumiko-server-runtime/compose-features";
3
+ export type SchemaApplyOptions = ComposeFeaturesOptions & {
4
+ /** App-Features (z.B. APP_FEATURES aus run-config) — composed mit den
5
+ * bundled-Features für den Projection-Rebuild-Registry. */
6
+ readonly features: readonly FeatureDefinition[];
7
+ /** Default INIT_CWD ?? process.cwd(); Migrations unter <appCwd>/kumiko/migrations. */
8
+ readonly appCwd?: string;
9
+ };
10
+ export declare function runSchemaApply(opts: SchemaApplyOptions): Promise<number>;
11
+ export declare function runStandaloneSchemaCli(opts: SchemaApplyOptions): Promise<never>;
@@ -0,0 +1,95 @@
1
+ // Standalone `kumiko schema apply` für Production-Bundles. Apps bündeln ein
2
+ // dünnes bin/kumiko.ts das nur runStandaloneSchemaCli mit den App-Features
3
+ // aufruft — die ganze Orchestrierung (Infra-Bootstrap, Migrations,
4
+ // Projection-Rebuild) lebt hier statt als ~100-Zeilen-Boilerplate pro App.
5
+ //
6
+ // Der Pulumi-migrate-initContainer ruft `bun /app/kumiko.js schema apply`;
7
+ // kumiko-build entdeckt das App-bin via findRepoRoot() und bündelt es.
8
+ import { existsSync } from "node:fs";
9
+ import { join } from "node:path";
10
+ import { createDbConnection, runMigrationsFromDir } from "@cosmicdrift/kumiko-framework/db";
11
+ import { createRegistry } from "@cosmicdrift/kumiko-framework/engine";
12
+ import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
13
+ import { queueRebuildsFromMarkers, runPendingRebuilds, } from "@cosmicdrift/kumiko-framework/migrations";
14
+ import { createEventConsumerStateTable, createProjectionStateTable, } from "@cosmicdrift/kumiko-framework/pipeline";
15
+ import { composeFeatures, } from "@cosmicdrift/kumiko-server-runtime/compose-features";
16
+ export async function runSchemaApply(opts) {
17
+ const dbUrl = process.env["DATABASE_URL"];
18
+ if (!dbUrl) {
19
+ console.error("\n DATABASE_URL not set.\n");
20
+ return 1;
21
+ }
22
+ const appCwd = opts.appCwd ?? process.env["INIT_CWD"] ?? process.cwd();
23
+ const migrationsDir = join(appCwd, "kumiko/migrations");
24
+ if (!existsSync(migrationsDir)) {
25
+ console.error(`\n ${migrationsDir} fehlt — kumiko/migrations/ muss im Image liegen.\n`);
26
+ return 1;
27
+ }
28
+ const { db, close } = createDbConnection(dbUrl);
29
+ try {
30
+ // Infra-Tabellen (event-store + pipeline-state) zuerst, alle
31
+ // tableExists-gated idempotent: auf einer Bestands-DB no-op, auf einer
32
+ // leeren Greenfield-DB legen sie kumiko_events/_consumers/_projections an
33
+ // bevor die App-Migrations dagegen laufen. Ohne das bricht eine leere DB
34
+ // (z.B. cashcolt auf frischem CNPG) an `relation "kumiko_events" does not exist`.
35
+ console.log("\n Lege Framework-Infra-Tabellen an (idempotent)…");
36
+ await createEventsTable(db);
37
+ await createEventConsumerStateTable(db);
38
+ await createProjectionStateTable(db);
39
+ console.log(` Wende kumiko-Migrations an (${migrationsDir})…`);
40
+ const result = await runMigrationsFromDir(db, migrationsDir);
41
+ if (result.applied.length === 0) {
42
+ console.log(`\n ✓ All ${result.skipped.length} migrations already applied.\n`);
43
+ }
44
+ else {
45
+ console.log(`\n ✓ Applied ${result.applied.length}:`);
46
+ for (const id of result.applied)
47
+ console.log(` + ${id}`);
48
+ if (result.skipped.length > 0)
49
+ console.log(` (${result.skipped.length} already applied)`);
50
+ console.log("");
51
+ }
52
+ // Projection rebuild: persistent queue instead of "only this run's
53
+ // result.applied" — otherwise a failed rebuild stays silently stuck
54
+ // forever, since the migration is already tracked applied and gets
55
+ // skipped on the next apply (#2464). queueRebuildsFromMarkers persists
56
+ // the marker tables BEFORE the rebuild; runPendingRebuilds unconditionally
57
+ // also picks up open entries from earlier, failed runs — not just the
58
+ // ones this run freshly applied.
59
+ const thisRunTables = await queueRebuildsFromMarkers(db, {
60
+ migrationsDir,
61
+ appliedIds: result.applied,
62
+ });
63
+ const registry = createRegistry(composeFeatures([...opts.features], opts));
64
+ const rebuildRun = await runPendingRebuilds(db, registry, { thisRunTables });
65
+ if (rebuildRun.rebuilt.length > 0) {
66
+ console.log(` Rebuild ${rebuildRun.rebuilt.length} Projection(s)…`);
67
+ for (const r of rebuildRun.rebuilt) {
68
+ console.log(` ↻ ${r.projection} (${r.eventsProcessed} events)`);
69
+ }
70
+ console.log("");
71
+ }
72
+ if (rebuildRun.failed.length > 0) {
73
+ throw new Error(`Projection rebuild failed for: ${rebuildRun.failed
74
+ .map((f) => `${f.projection} (${f.error})`)
75
+ .join("; ")}. Table(s) stay queued in kumiko_pending_rebuilds — retried on the next apply.`);
76
+ }
77
+ return 0;
78
+ }
79
+ catch (e) {
80
+ console.error(`\n ✗ ${e instanceof Error ? (e.stack ?? e.message) : String(e)}\n`);
81
+ return 1;
82
+ }
83
+ finally {
84
+ await close();
85
+ }
86
+ }
87
+ export async function runStandaloneSchemaCli(opts) {
88
+ const cmd = Bun.argv[2];
89
+ const sub = Bun.argv[3];
90
+ if (cmd === "schema" && sub === "apply") {
91
+ process.exit(await runSchemaApply(opts));
92
+ }
93
+ console.error(`\n Unbekannt: kumiko ${cmd ?? ""} ${sub ?? ""}\n Nur 'kumiko schema apply' im Standalone-Bundle.\n`);
94
+ process.exit(1);
95
+ }
@@ -0,0 +1,2 @@
1
+ export declare function resolveGeneratePath(cwd: string): string;
2
+ export declare function implicitAuthModeFeatureNames(): readonly string[];
@@ -1,26 +1,24 @@
1
1
  // Pure helpers for the `kumiko-schema-check` bin. Kept in src/ (vs. the bin)
2
2
  // so they are part of the tsc project + unit-testable without importing the
3
3
  // auto-running CLI.
4
-
5
4
  import { existsSync } from "node:fs";
6
5
  import { resolve } from "node:path";
7
6
  import { composeFeatures } from "@cosmicdrift/kumiko-server-runtime/compose-features";
8
-
9
7
  // The generate-script lives under different roots across apps: publicstatus
10
8
  // uses `drizzle/generate.ts`, the framework's own sample-apps use
11
9
  // `schema/generate.ts`. Pick whichever exists so a no-arg `bunx
12
10
  // kumiko-schema-check` works in both layouts; default to `drizzle/` for the
13
11
  // error message when neither is present.
14
- export function resolveGeneratePath(cwd: string): string {
15
- const drizzlePath = resolve(cwd, "drizzle/generate.ts");
16
- const schemaPath = resolve(cwd, "schema/generate.ts");
17
- if (!existsSync(drizzlePath) && existsSync(schemaPath)) return schemaPath;
18
- return drizzlePath;
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;
19
18
  }
20
-
21
19
  // The features composeFeatures auto-prepends in auth-mode (config + user +
22
20
  // tenant + auth-email-password). Derived from composeFeatures itself so this
23
21
  // can't drift from the real prepend-list in compose-features.ts.
24
- export function implicitAuthModeFeatureNames(): readonly string[] {
25
- return composeFeatures([], { includeBundled: true }).map((f) => f.name);
22
+ export function implicitAuthModeFeatureNames() {
23
+ return composeFeatures([], { includeBundled: true }).map((f) => f.name);
26
24
  }
@@ -0,0 +1,2 @@
1
+ export { archivedStreamsTable, eventsTable, snapshotsTable, } from "@cosmicdrift/kumiko-framework/event-store";
2
+ export { eventConsumerStateTable, projectionStateTable, } from "@cosmicdrift/kumiko-framework/pipeline";
@@ -19,14 +19,6 @@
19
19
  //
20
20
  // (Datei-Name "auth-mode" ist historisch — heute ist der Inhalt reine
21
21
  // Framework-Infra. Umbenennen ist breaking change für App-Imports.)
22
-
23
22
  // Framework-Infra (immer da, unabhängig von Features)
24
- export {
25
- archivedStreamsTable,
26
- eventsTable,
27
- snapshotsTable,
28
- } from "@cosmicdrift/kumiko-framework/event-store";
29
- export {
30
- eventConsumerStateTable,
31
- projectionStateTable,
32
- } from "@cosmicdrift/kumiko-framework/pipeline";
23
+ export { archivedStreamsTable, eventsTable, snapshotsTable, } from "@cosmicdrift/kumiko-framework/event-store";
24
+ export { eventConsumerStateTable, projectionStateTable, } from "@cosmicdrift/kumiko-framework/pipeline";
@@ -0,0 +1,2 @@
1
+ export { archivedStreamsTable, eventsTable, snapshotsTable, upcasterDeadLetterTable, } from "@cosmicdrift/kumiko-framework/event-store";
2
+ export { eventConsumerStateTable, projectionStateTable, } from "@cosmicdrift/kumiko-framework/pipeline";
@@ -9,14 +9,5 @@
9
9
  //
10
10
  // Wer Auth-Tables will, nutzt drizzle-tables-auth-mode (umfasst Minimal
11
11
  // plus Bundle-Tables für Config, Tenant, User, Sessions).
12
-
13
- export {
14
- archivedStreamsTable,
15
- eventsTable,
16
- snapshotsTable,
17
- upcasterDeadLetterTable,
18
- } from "@cosmicdrift/kumiko-framework/event-store";
19
- export {
20
- eventConsumerStateTable,
21
- projectionStateTable,
22
- } from "@cosmicdrift/kumiko-framework/pipeline";
12
+ export { archivedStreamsTable, eventsTable, snapshotsTable, upcasterDeadLetterTable, } from "@cosmicdrift/kumiko-framework/event-store";
13
+ export { eventConsumerStateTable, projectionStateTable, } from "@cosmicdrift/kumiko-framework/pipeline";
@@ -0,0 +1,11 @@
1
+ import type { FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
2
+ import { type TestStack, type TestStackOptions } from "@cosmicdrift/kumiko-framework/stack";
3
+ import { type ComposeFeaturesOptions } from "@cosmicdrift/kumiko-server-runtime/compose-features";
4
+ export type TestStackPreset = "config" | "template-resolver";
5
+ export type SetupTestStackFromFeaturesOptions = Omit<TestStackOptions, "features"> & {
6
+ readonly includeBundled?: boolean;
7
+ readonly authOptions?: ComposeFeaturesOptions["authOptions"];
8
+ readonly presets?: readonly TestStackPreset[];
9
+ };
10
+ export declare function mergeExtraContext(base: TestStackOptions["extraContext"], presets: readonly TestStackPreset[]): TestStackOptions["extraContext"];
11
+ export declare function setupTestStackFromFeatures(appFeatures: readonly FeatureDefinition[], options?: SetupTestStackFromFeaturesOptions): Promise<TestStack>;
@@ -0,0 +1,42 @@
1
+ // Test helper: composeFeatures + setupTestStack in one call.
2
+ // Apps pass the same feature list as run-config (APP_FEATURES / buildAppFeatures).
3
+ import { createConfigResolver, } from "@cosmicdrift/kumiko-bundled-features/config";
4
+ import { createTemplateResolverApi } from "@cosmicdrift/kumiko-bundled-features/template-resolver";
5
+ import { setupTestStack, } from "@cosmicdrift/kumiko-framework/stack";
6
+ import { jobRunLoggerCallbacks } from "@cosmicdrift/kumiko-server-runtime/boot/job-run-logger";
7
+ import { composeFeatures, } from "@cosmicdrift/kumiko-server-runtime/compose-features";
8
+ import { addConfigAccessorFactory } from "@cosmicdrift/kumiko-server-runtime/run-prod-app";
9
+ export function mergeExtraContext(base, presets) {
10
+ if (presets.length === 0)
11
+ return base;
12
+ return (deps) => {
13
+ const fromBase = typeof base === "function" ? base(deps) : base !== undefined ? { ...base } : {};
14
+ const merged = { ...fromBase };
15
+ if (presets.includes("config")) {
16
+ // Same precedence as mergeConfigResolverDefault (run-dev-app.ts) — a base-supplied resolver wins, factory always derives from it (fw#3313).
17
+ const configResolver = fromBase["configResolver"] ?? createConfigResolver();
18
+ Object.assign(merged, addConfigAccessorFactory({ configResolver }, deps.registry));
19
+ }
20
+ if (presets.includes("template-resolver")) {
21
+ merged["templateResolver"] = createTemplateResolverApi(deps.db);
22
+ }
23
+ return merged;
24
+ };
25
+ }
26
+ export async function setupTestStackFromFeatures(appFeatures, options = {}) {
27
+ const { includeBundled = false, authOptions, presets = [], ...stackOptions } = options;
28
+ const features = composeFeatures(appFeatures, { includeBundled, authOptions });
29
+ const extraContext = mergeExtraContext(stackOptions.extraContext, presets);
30
+ // Same run-logger wiring as prod, so jobs that declare tenantVisibleFailure
31
+ // write their failure rows in tests too.
32
+ const defaultRunLogger = ({ registry, db, }) => jobRunLoggerCallbacks(registry, db);
33
+ const jobs = stackOptions.jobs === undefined
34
+ ? undefined
35
+ : { runLogger: defaultRunLogger, ...stackOptions.jobs };
36
+ return setupTestStack({
37
+ ...stackOptions,
38
+ ...(jobs !== undefined && { jobs }),
39
+ features,
40
+ ...(extraContext !== undefined && { extraContext }),
41
+ });
42
+ }
@@ -0,0 +1,15 @@
1
+ export type WelcomeBannerInput = {
2
+ /** Resolved listen-URL (`http://localhost:3000`). */
3
+ readonly url: string;
4
+ /** Login the seeded admin uses (from runDevApp options.auth.admin). */
5
+ readonly admin?: {
6
+ readonly email: string;
7
+ readonly password: string;
8
+ };
9
+ /** Hot-reload hint shown in the "add a feature" line. Defaults to
10
+ * `src/features/`. */
11
+ readonly featuresDir?: string;
12
+ /** Custom docs URL — defaults to the public docs site. */
13
+ readonly docsUrl?: string;
14
+ };
15
+ export declare function renderWelcomeBanner(input: WelcomeBannerInput): string;
@@ -0,0 +1,27 @@
1
+ // First-run welcome banner for `runDevApp({ welcomeBanner: true })`.
2
+ // Opt-in only — `bun dev` should not normalize this for apps that
3
+ // already log their own startup. Scaffolded apps (create-kumiko-app)
4
+ // flip it on so the first `bun dev` doesn't end on "Server läuft" with
5
+ // the user wondering where to click.
6
+ export function renderWelcomeBanner(input) {
7
+ const featuresDir = input.featuresDir ?? "src/features/";
8
+ const docsUrl = input.docsUrl ?? "https://docs.kumiko.rocks/quickstart";
9
+ const lines = [];
10
+ lines.push(`✓ kumiko-app läuft`);
11
+ lines.push(`→ Browser: ${input.url}`);
12
+ if (input.admin) {
13
+ lines.push(`→ Login als: ${input.admin.email} / ${input.admin.password}`);
14
+ }
15
+ lines.push(`→ Feature add: edit ${featuresDir}`);
16
+ lines.push(`→ Docs: ${docsUrl}`);
17
+ const innerWidth = Math.max(...lines.map((l) => stringWidth(l)));
18
+ const border = "─".repeat(innerWidth + 2);
19
+ const top = `┌${border}┐`;
20
+ const bottom = `└${border}┘`;
21
+ const padded = lines.map((l) => `│ ${l}${" ".repeat(innerWidth - stringWidth(l))} │`);
22
+ return [top, ...padded, bottom].join("\n");
23
+ }
24
+ // ponytail: codepoint width; ok for ASCII + arrows, add a width-lib if CJK ever lands here.
25
+ function stringWidth(s) {
26
+ return [...s].length;
27
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-dev-server",
3
- "version": "0.329.0",
3
+ "version": "0.330.2",
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>",
@@ -19,36 +19,40 @@
19
19
  },
20
20
  "exports": {
21
21
  ".": {
22
- "types": "./src/index.ts",
23
- "default": "./src/index.ts"
22
+ "types": "./dist/index.d.ts",
23
+ "default": "./dist/index.js"
24
24
  },
25
25
  "./build": {
26
- "types": "./src/build.ts",
27
- "default": "./src/build.ts"
26
+ "types": "./dist/build.d.ts",
27
+ "default": "./dist/build.js"
28
28
  },
29
29
  "./compose-stacks": {
30
- "types": "./src/compose-stacks.ts",
31
- "default": "./src/compose-stacks.ts"
30
+ "types": "./dist/compose-stacks.d.ts",
31
+ "default": "./dist/compose-stacks.js"
32
32
  },
33
33
  "./env-schema": {
34
- "types": "./src/env-schema.ts",
35
- "default": "./src/env-schema.ts"
34
+ "types": "./dist/env-schema.d.ts",
35
+ "default": "./dist/env-schema.js"
36
36
  },
37
37
  "./setup-test-stack-from-features": {
38
- "types": "./src/setup-test-stack-from-features.ts",
39
- "default": "./src/setup-test-stack-from-features.ts"
38
+ "types": "./dist/setup-test-stack-from-features.d.ts",
39
+ "default": "./dist/setup-test-stack-from-features.js"
40
40
  },
41
41
  "./schema-apply": {
42
- "types": "./src/schema-apply.ts",
43
- "default": "./src/schema-apply.ts"
42
+ "types": "./dist/schema-apply.d.ts",
43
+ "default": "./dist/schema-apply.js"
44
44
  },
45
45
  "./schema-tables-auth-mode": {
46
- "types": "./src/schema-tables-auth-mode.ts",
47
- "default": "./src/schema-tables-auth-mode.ts"
46
+ "types": "./dist/schema-tables-auth-mode.d.ts",
47
+ "default": "./dist/schema-tables-auth-mode.js"
48
48
  },
49
49
  "./schema-tables-minimal": {
50
- "types": "./src/schema-tables-minimal.ts",
51
- "default": "./src/schema-tables-minimal.ts"
50
+ "types": "./dist/schema-tables-minimal.d.ts",
51
+ "default": "./dist/schema-tables-minimal.js"
52
+ },
53
+ "./cli": {
54
+ "types": "./dist/cli.d.ts",
55
+ "default": "./dist/cli.js"
52
56
  }
53
57
  },
54
58
  "bin": {
@@ -60,19 +64,62 @@
60
64
  "kumiko-upgrade": "./bin/kumiko-upgrade.ts"
61
65
  },
62
66
  "dependencies": {
63
- "@cosmicdrift/kumiko-bundled-features": "0.329.0",
64
- "@cosmicdrift/kumiko-framework": "0.329.0",
65
- "@cosmicdrift/kumiko-headless": "0.329.0",
66
- "@cosmicdrift/kumiko-server-runtime": "0.329.0",
67
- "ts-morph": "^28.0.0"
67
+ "@cosmicdrift/kumiko-bundled-features": "0.330.2",
68
+ "@cosmicdrift/kumiko-framework": "0.330.2",
69
+ "@cosmicdrift/kumiko-headless": "0.330.2",
70
+ "@cosmicdrift/kumiko-renderer-web": "0.330.2",
71
+ "@cosmicdrift/kumiko-server-runtime": "0.330.2",
72
+ "bun-types": "^1.3.13",
73
+ "ts-morph": "^28.0.0",
74
+ "zod": "^4.4.3"
68
75
  },
69
76
  "publishConfig": {
70
77
  "registry": "https://registry.npmjs.org",
71
- "access": "public"
78
+ "access": "public",
79
+ "exports": {
80
+ ".": {
81
+ "types": "./dist/index.d.ts",
82
+ "default": "./dist/index.js"
83
+ },
84
+ "./build": {
85
+ "types": "./dist/build.d.ts",
86
+ "default": "./dist/build.js"
87
+ },
88
+ "./compose-stacks": {
89
+ "types": "./dist/compose-stacks.d.ts",
90
+ "default": "./dist/compose-stacks.js"
91
+ },
92
+ "./env-schema": {
93
+ "types": "./dist/env-schema.d.ts",
94
+ "default": "./dist/env-schema.js"
95
+ },
96
+ "./setup-test-stack-from-features": {
97
+ "types": "./dist/setup-test-stack-from-features.d.ts",
98
+ "default": "./dist/setup-test-stack-from-features.js"
99
+ },
100
+ "./schema-apply": {
101
+ "types": "./dist/schema-apply.d.ts",
102
+ "default": "./dist/schema-apply.js"
103
+ },
104
+ "./schema-tables-auth-mode": {
105
+ "types": "./dist/schema-tables-auth-mode.d.ts",
106
+ "default": "./dist/schema-tables-auth-mode.js"
107
+ },
108
+ "./schema-tables-minimal": {
109
+ "types": "./dist/schema-tables-minimal.d.ts",
110
+ "default": "./dist/schema-tables-minimal.js"
111
+ },
112
+ "./cli": {
113
+ "types": "./dist/cli.d.ts",
114
+ "default": "./dist/cli.js"
115
+ }
116
+ }
72
117
  },
73
118
  "files": [
74
- "src",
119
+ "dist",
120
+ "bin",
75
121
  "templates",
122
+ "src/changes.json",
76
123
  "README.md",
77
124
  "LICENSE"
78
125
  ]
package/src/changes.json CHANGED
@@ -1,4 +1,10 @@
1
1
  [
2
+ {
3
+ "version": "0.330.0",
4
+ "type": "improvement",
5
+ "title": "kumiko-server-runtime and kumiko-dev-server are published as compiled JavaScript plus .d.ts",
6
+ "detail": "Both packages now ship `dist` (`.js` and `.d.ts`) instead of TypeScript source. Export keys are unchanged; only the targets behind them move to `dist`. `kumiko-dev-server` keeps its `bin/*.ts` entrypoints (they still need Bun) and ships them together with `templates`; they now import through the new `@cosmicdrift/kumiko-dev-server/cli` export instead of reaching into `src`. `kumiko-server-runtime` now declares `ioredis` and `kumiko-dev-server` declares `zod` as dependencies, which their code already imported. `ioredis` is imported as a named `{ Redis }` so the class resolves under Node's ESM loader."
7
+ },
2
8
  {
3
9
  "version": "0.328.0",
4
10
  "type": "improvement",