@cosmicdrift/kumiko-dev-server 0.13.0 → 0.15.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.
Files changed (34) hide show
  1. package/package.json +11 -14
  2. package/src/__tests__/build-prod-bundle.integration.ts +1 -1
  3. package/src/__tests__/build-prod-bundle.test.ts +1 -1
  4. package/src/__tests__/cache-headers.test.ts +1 -1
  5. package/src/__tests__/classify-change.test.ts +1 -1
  6. package/src/__tests__/compose-features-wiring.integration.ts +10 -9
  7. package/src/__tests__/compose-features.test.ts +1 -1
  8. package/src/__tests__/config-seed-boot.integration.ts +5 -4
  9. package/src/__tests__/crash-tracker.test.ts +1 -1
  10. package/src/__tests__/create-kumiko-server.integration.ts +5 -5
  11. package/src/__tests__/env-schema.integration.ts +1 -1
  12. package/src/__tests__/env-schema.test.ts +1 -1
  13. package/src/__tests__/few-shot-corpus.test.ts +1 -1
  14. package/src/__tests__/inject-schema.test.ts +1 -1
  15. package/src/__tests__/resolve-stylesheet.test.ts +11 -7
  16. package/src/__tests__/resolve-tailwind-cli.test.ts +1 -1
  17. package/src/__tests__/run-prod-app-spec.test.ts +1 -1
  18. package/src/__tests__/run-prod-app.integration.ts +6 -6
  19. package/src/__tests__/scaffold-app-feature.test.ts +1 -1
  20. package/src/__tests__/scaffold-app.test.ts +1 -1
  21. package/src/__tests__/scaffold-deploy.test.ts +1 -1
  22. package/src/__tests__/scaffold-feature.test.ts +1 -1
  23. package/src/__tests__/try-hono-first.test.ts +1 -1
  24. package/src/__tests__/walkthrough.integration.ts +118 -0
  25. package/src/codegen/__tests__/run-codegen.test.ts +1 -1
  26. package/src/codegen/__tests__/strict-mode-diagnostics.test.ts +1 -1
  27. package/src/codegen/__tests__/watch.test.ts +1 -1
  28. package/src/scaffold-app-feature.ts +2 -1
  29. package/src/scaffold-app.ts +139 -76
  30. package/src/{drizzle-tables-auth-mode.ts → schema-tables-auth-mode.ts} +1 -1
  31. package/templates/deploy/Dockerfile.template +15 -47
  32. package/CHANGELOG.md +0 -632
  33. package/src/drizzle-config.ts +0 -44
  34. /package/src/{drizzle-tables-minimal.ts → schema-tables-minimal.ts} +0 -0
@@ -6,16 +6,14 @@
6
6
  // stub, package.json with @cosmicdrift/* deps, tsconfig, .env.example,
7
7
  // README.
8
8
  //
9
- // Intentionally NOT included in DX-1.0:
10
- // - drizzle/ setup (DX-1.1 needs FEATURE_IMPORT_REGISTRY decision from DX-4)
11
- // - deploy/Dockerfile (already covered by scaffoldDeploy separate cmd)
12
- // - first feature scaffold (use scaffoldFeature after this)
13
- //
14
- // The generated app is born "boots cleanly, mounts nothing fancy". User
15
- // runs `kumiko add feature` (DX-2) or hand-edits src/run-config.ts to grow.
9
+ // .ts files are built via ts-morph (same tool [[scaffoldAppFeature]] uses
10
+ // to auto-mount features). Means a single AST representation for both
11
+ // generate + later modify no template-string ts-morph divergence.
12
+ // Static files (package.json, tsconfig, .env, README) stay text-based.
16
13
 
17
14
  import { existsSync, mkdirSync, writeFileSync } from "node:fs";
18
15
  import { join, resolve } from "node:path";
16
+ import { IndentationText, Project, VariableDeclarationKind } from "ts-morph";
19
17
 
20
18
  export type ScaffoldAppOptions = {
21
19
  /** kebab-case app name (e.g. "my-shop"). Becomes package-name + folder. */
@@ -122,72 +120,143 @@ function renderTsconfig(): string {
122
120
  )}\n`;
123
121
  }
124
122
 
125
- function renderRunConfig(): string {
126
- return `// Single source of truth für die Feature-Komposition deiner App.
127
- // Bundled-Foundation: secrets + sessions. config/user/tenant/auth-email-password
128
- // werden via composeFeatures(includeBundled:true) automatisch ergänzt
129
- // wenn runProdApp mit \`auth: {…}\` aufgerufen wird (siehe bin/main.ts).
130
- //
131
- // Neue features hinzufügen:
132
- // - bunx kumiko add feature <name> (DX-2, automatisch)
133
- // - oder: hand-edit + import unten ergänzen
134
-
135
- import { createSecretsFeature } from "@cosmicdrift/kumiko-bundled-features/secrets";
136
- import { createSessionsFeature } from "@cosmicdrift/kumiko-bundled-features/sessions";
123
+ function newTsProject(): Project {
124
+ return new Project({
125
+ useInMemoryFileSystem: true,
126
+ compilerOptions: { target: 99, module: 99, strict: true },
127
+ manipulationSettings: { indentationText: IndentationText.TwoSpaces },
128
+ });
129
+ }
137
130
 
138
- export const APP_FEATURES = [
139
- createSecretsFeature(),
140
- createSessionsFeature(),
141
- ] as const;
142
- `;
131
+ function renderRunConfig(): string {
132
+ const project = newTsProject();
133
+ const sf = project.createSourceFile("run-config.ts", "");
134
+
135
+ sf.addImportDeclaration({
136
+ moduleSpecifier: "@cosmicdrift/kumiko-bundled-features/secrets",
137
+ namedImports: ["createSecretsFeature"],
138
+ });
139
+ sf.addImportDeclaration({
140
+ moduleSpecifier: "@cosmicdrift/kumiko-bundled-features/sessions",
141
+ namedImports: ["createSessionsFeature"],
142
+ });
143
+
144
+ sf.addVariableStatement({
145
+ declarationKind: VariableDeclarationKind.Const,
146
+ isExported: true,
147
+ declarations: [
148
+ {
149
+ name: "APP_FEATURES",
150
+ initializer: "[createSecretsFeature(), createSessionsFeature()] as const",
151
+ },
152
+ ],
153
+ });
154
+
155
+ sf.insertText(
156
+ 0,
157
+ [
158
+ "// Single source of truth für die Feature-Komposition deiner App.",
159
+ "// Bundled-Foundation: secrets + sessions. config/user/tenant/auth-email-password",
160
+ "// werden via composeFeatures(includeBundled:true) automatisch ergänzt",
161
+ "// wenn runProdApp mit `auth: {…}` aufgerufen wird (siehe bin/main.ts).",
162
+ "//",
163
+ "// Neue features hinzufügen:",
164
+ "// - bunx @cosmicdrift/kumiko-cli add feature <name> (DX-2, automatisch)",
165
+ "// - oder: hand-edit + import unten ergänzen",
166
+ "",
167
+ "",
168
+ ].join("\n"),
169
+ );
170
+
171
+ return sf.getFullText();
143
172
  }
144
173
 
145
174
  function renderMain(appName: string): string {
146
- // Deterministic tenant-UUID derived from appName for the seed-admin
147
- // membership. Reproducible across boots; tenants table sees the same
148
- // ID. Format: 8-4-4-4-12 hex chars, version-4 marker at position 14.
149
- // We hash the name into the digits using a tiny PRNG so two apps
150
- // get different IDs without bun's crypto dependency.
151
175
  const tenantId = deriveTenantId(appName);
152
- return `// Production-bootstrap. KUMIKO_DRY_RUN_ENV=boot exits after
153
- // composeFeatures + validateBoot + createRegistry without DB/Redis-connect
154
- // (siehe @cosmicdrift/kumiko-dev-server runProdApp). Echter Dev-Boot
155
- // passiert via \`bunx kumiko dev\` mit Docker-stack — DX-1.0 deckt nur
156
- // den boot-mode-Pfad ab; \`kumiko dev\` kommt in einer späteren DX-Phase.
157
-
158
- import { frameworkCoreEnvSchema, runProdApp } from "@cosmicdrift/kumiko-dev-server";
159
- import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
160
- import { composeEnvSchema } from "@cosmicdrift/kumiko-framework/env";
161
- import { APP_FEATURES } from "../src/run-config";
162
-
163
- const DEFAULT_TENANT_ID = "${tenantId}" as TenantId;
164
-
165
- const envSchema = composeEnvSchema({
166
- core: frameworkCoreEnvSchema,
167
- features: APP_FEATURES,
168
- });
169
-
170
- await runProdApp({
171
- features: APP_FEATURES,
172
- envSchema,
173
- migrations: false,
174
- auth: {
175
- admin: {
176
- email: "admin@${appName}.local",
177
- password: "change-me-on-first-deploy",
178
- displayName: "Admin",
179
- memberships: [
180
- {
181
- tenantId: DEFAULT_TENANT_ID,
182
- tenantKey: "${appName}",
183
- tenantName: "${appName}",
184
- roles: ["TenantAdmin"],
185
- },
186
- ],
187
- },
188
- },
189
- });
190
- `;
176
+ const project = newTsProject();
177
+ const sf = project.createSourceFile("main.ts", "");
178
+
179
+ sf.addImportDeclaration({
180
+ moduleSpecifier: "@cosmicdrift/kumiko-dev-server",
181
+ namedImports: ["frameworkCoreEnvSchema", "runProdApp"],
182
+ });
183
+ sf.addImportDeclaration({
184
+ moduleSpecifier: "@cosmicdrift/kumiko-framework/engine",
185
+ isTypeOnly: true,
186
+ namedImports: ["TenantId"],
187
+ });
188
+ sf.addImportDeclaration({
189
+ moduleSpecifier: "@cosmicdrift/kumiko-framework/env",
190
+ namedImports: ["composeEnvSchema"],
191
+ });
192
+ sf.addImportDeclaration({
193
+ moduleSpecifier: "../src/run-config",
194
+ namedImports: ["APP_FEATURES"],
195
+ });
196
+
197
+ sf.addVariableStatement({
198
+ declarationKind: VariableDeclarationKind.Const,
199
+ declarations: [
200
+ {
201
+ name: "DEFAULT_TENANT_ID",
202
+ initializer: `"${tenantId}" as TenantId`,
203
+ },
204
+ ],
205
+ });
206
+
207
+ sf.addVariableStatement({
208
+ declarationKind: VariableDeclarationKind.Const,
209
+ declarations: [
210
+ {
211
+ name: "envSchema",
212
+ initializer: "composeEnvSchema({ core: frameworkCoreEnvSchema, features: APP_FEATURES })",
213
+ },
214
+ ],
215
+ });
216
+
217
+ sf.addStatements((writer) => {
218
+ writer
219
+ .write("await runProdApp(")
220
+ .inlineBlock(() => {
221
+ writer.writeLine("features: APP_FEATURES,");
222
+ writer.writeLine("envSchema,");
223
+ writer.writeLine("migrations: false,");
224
+ writer.write("auth: ").inlineBlock(() => {
225
+ writer.write("admin: ").inlineBlock(() => {
226
+ writer.writeLine(`email: "admin@${appName}.local",`);
227
+ writer.writeLine(`password: "change-me-on-first-deploy",`);
228
+ writer.writeLine(`displayName: "Admin",`);
229
+ writer.write("memberships: [");
230
+ writer.indent(() => {
231
+ writer.inlineBlock(() => {
232
+ writer.writeLine("tenantId: DEFAULT_TENANT_ID,");
233
+ writer.writeLine(`tenantKey: "${appName}",`);
234
+ writer.writeLine(`tenantName: "${appName}",`);
235
+ writer.writeLine(`roles: ["TenantAdmin"],`);
236
+ });
237
+ writer.write(",");
238
+ });
239
+ writer.write("],");
240
+ });
241
+ });
242
+ })
243
+ .write(");");
244
+ });
245
+
246
+ sf.insertText(
247
+ 0,
248
+ [
249
+ "// Production-bootstrap. KUMIKO_DRY_RUN_ENV=boot exits after",
250
+ "// composeFeatures + validateBoot + createRegistry without DB/Redis-connect",
251
+ "// (siehe @cosmicdrift/kumiko-dev-server runProdApp). Echter Dev-Boot",
252
+ "// passiert via `yarn kumiko dev` (in-repo dev-tool) mit Docker-stack — DX-1.0 deckt nur",
253
+ "// den boot-mode-Pfad ab; `kumiko dev` kommt in einer späteren DX-Phase.",
254
+ "",
255
+ "",
256
+ ].join("\n"),
257
+ );
258
+
259
+ return sf.getFullText();
191
260
  }
192
261
 
193
262
  function renderEnvExample(): string {
@@ -208,7 +277,7 @@ function renderReadme(appName: string): string {
208
277
  return `# ${appName}
209
278
 
210
279
  Scaffolded by \`kumiko new app\`. Boots out-of-the-box with secrets + sessions
211
- mounted (foundation set). Add features with \`bunx kumiko add feature <name>\`.
280
+ mounted (foundation set). Add features with \`bunx @cosmicdrift/kumiko-cli add feature <name>\`.
212
281
 
213
282
  ## First boot
214
283
 
@@ -224,7 +293,7 @@ Expected: \`[runProdApp] boot validation OK (… features, … registry entries)
224
293
  ## Adding features
225
294
 
226
295
  \`\`\`sh
227
- bunx kumiko add feature my-domain
296
+ bunx @cosmicdrift/kumiko-cli add feature my-domain
228
297
  # → editiert src/run-config.ts automatisch + scaffolded src/features/my-domain/
229
298
  \`\`\`
230
299
 
@@ -241,10 +310,6 @@ For full docs see https://docs.kumiko.so.
241
310
  // version-marker at the right spot. NOT cryptographically random —
242
311
  // just a stable per-app default the user can change later.
243
312
  function deriveTenantId(name: string): string {
244
- // Tiny xorshift PRNG seeded from the name's char-codes. Same name →
245
- // same ID. Sufficient for "give every scaffolded app a deterministic
246
- // default tenant" — production sets its own via the create-tenant
247
- // flow anyway.
248
313
  let state = 2166136261;
249
314
  for (const ch of name) {
250
315
  state ^= ch.charCodeAt(0);
@@ -255,11 +320,9 @@ function deriveTenantId(name: string): string {
255
320
  state ^= state << 13;
256
321
  state >>>= 0;
257
322
  const b = hex(state, 4);
258
- // version-4 marker at first char of 3rd group:
259
323
  state ^= state >>> 17;
260
324
  state >>>= 0;
261
325
  const c = `4${hex(state, 3)}`;
262
- // RFC 4122 variant: 10xx (set top two bits of 4th group to 10):
263
326
  state ^= state << 5;
264
327
  state >>>= 0;
265
328
  const d4 = (0x8 | (state & 0x3)).toString(16);
@@ -12,7 +12,7 @@
12
12
  //
13
13
  // Bundle-Entity-Tables (configValuesTable, tenantTable, userTable,
14
14
  // userSessionTable, tenantMembershipsTable etc.) sind bewusst NICHT hier:
15
- // sie kommen über schema.generated.ts via buildDrizzleTable aus den
15
+ // sie kommen über schema.generated.ts via buildEntityTable aus den
16
16
  // r.entity()-Definitionen, das ist seit der entity.indexes-API die
17
17
  // Single-Source-of-Truth. Doppelte Re-Exports würden zwei pgTable-
18
18
  // Instances mit identischem Index-Namen erzeugen — drizzle-kit warnt.
@@ -13,66 +13,34 @@
13
13
  # Size: ~250 MB incl. drizzle-kit for the pre-deploy migrate step.
14
14
  # Build context: repository root (monorepo is used in the build stage).
15
15
 
16
- ARG BUN_VERSION=1.2.20
16
+ ARG BUN_VERSION=1.3.14
17
+ {{#hasPrivateGhPackages}}
18
+ # Private GH-Packages: der CI-Workflow injects GITHUB_TOKEN via --build-arg.
19
+ # Docker's multi-stage ARG scoping braucht die Re-declaration in jeder Stage
20
+ # die sie nutzt; das top-level ARG macht sie per `docker build` setzbar.
21
+ ARG GITHUB_TOKEN=
22
+ {{/hasPrivateGhPackages}}
17
23
  # Build identity — passed in by the CI workflow via --build-arg. Defaults
18
24
  # for local container builds.
19
25
  ARG BUILD_VERSION=dev
20
26
  ARG BUILD_TIME=unknown
21
- {{#hasPrivateGhPackages}}
22
- # Private @cosmicdriftgamestudio/* GH-Packages dep detected — yarn-4
23
- # reads the token via `npmAuthToken: "${GITHUB_TOKEN:-…}"` in .yarnrc.yml.
24
- # Without this build-arg, yarn install aborts with YN0041 anonymous-auth.
25
- ARG GITHUB_TOKEN=
26
- {{/hasPrivateGhPackages}}
27
27
 
28
28
  # ----- build: produces dist/ + dist-server/ ---------------------------------
29
- # Build base is node-alpine (not bun-alpine) because the repo uses yarn 4 as
30
- # its package manager — `link:./.kumiko` (@app/define codegen output) is
31
- # yarn-4's symlink protocol, which bun interprets differently. Node ships
32
- # corepack (yarn 4 via packageManager field); we pull bun via npm for
33
- # `bun run build`. Runtime stage stays pure bun.
34
- FROM node:20-alpine AS build
29
+ FROM oven/bun:${BUN_VERSION}-alpine AS build
30
+ WORKDIR /app
35
31
  {{#hasPrivateGhPackages}}
36
- # Multi-stage ARG inheritance: globals declared before FROM need an
37
- # `ARG <name>` line in every stage that uses them. Without this,
38
- # ${GITHUB_TOKEN} below resolves to empty and yarn install hits YN0041.
32
+ # GITHUB_TOKEN für @cosmicdriftgamestudio/*-Scope beim bun install.
39
33
  ARG GITHUB_TOKEN
34
+ ENV GITHUB_TOKEN=${GITHUB_TOKEN}
35
+ RUN bun config set --scope @cosmicdriftgamestudio token "${GITHUB_TOKEN}"
40
36
  {{/hasPrivateGhPackages}}
41
- WORKDIR /app
42
-
43
- RUN corepack enable && npm install -g bun@${BUN_VERSION}
44
37
 
45
38
  # Standalone-repo layout: @cosmicdrift/* pulled from NPM, no workspace:*
46
- # refs. Manifests first for Docker layer cache (yarn install only
39
+ # refs. Manifests first for Docker layer cache (bun install only
47
40
  # invalidates on dep change).
48
- COPY package.json yarn.lock .yarnrc.yml ./
41
+ COPY package.json bun.lock ./
49
42
 
50
- # YARN_ENABLE_INLINE_BUILDS=true: postinstall stdout/stderr inline in the
51
- # install output. Without this, yarn 4 hides logs in /tmp/xfs-*/build.log
52
- # (invisible in the Docker layer output) and the CI operator guesses why
53
- # the install failed.
54
- #
55
- # `link:./.kumiko` (@app/define in package.json): yarn 4 creates a
56
- # dangling symlink; install does NOT fail. `bun run build` below calls
57
- # `runCodegen` from @cosmicdrift/kumiko-dev-server (see
58
- # bin/kumiko-build.ts), which writes .kumiko/define.ts and turns the
59
- # symlink real before the bundle is built.
60
- ENV YARN_ENABLE_INLINE_BUILDS=true
61
- # Skip postinstall scripts for ALL deps in the build stage. Reason:
62
- # `bun build` bundles JS source only — no native bindings needed at bundle-
63
- # time. msgpackr-extract is the most common offender (ARM/CI native-build
64
- # failures), but the rule applies broadly: any native dep loaded at runtime
65
- # gets re-installed via `bun install --production` in the runtime stage,
66
- # which uses bun's own postinstall handling. Apps that needed per-package
67
- # opt-outs via `dependenciesMeta.<pkg>.built=false` in package.json (e.g.
68
- # studio, enterprise) can remove those entries after adopting this template.
69
- ENV YARN_ENABLE_SCRIPTS=false
70
- {{#hasPrivateGhPackages}}
71
- # Re-export GITHUB_TOKEN as env so yarn-4's `${GITHUB_TOKEN:-…}` expansion
72
- # in .yarnrc.yml finds it during the install step.
73
- ENV GITHUB_TOKEN=${GITHUB_TOKEN}
74
- {{/hasPrivateGhPackages}}
75
- RUN yarn install --immutable
43
+ RUN bun install --frozen-lockfile
76
44
 
77
45
  COPY . .
78
46
  RUN bun run build