@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.
- package/package.json +11 -14
- package/src/__tests__/build-prod-bundle.integration.ts +1 -1
- package/src/__tests__/build-prod-bundle.test.ts +1 -1
- package/src/__tests__/cache-headers.test.ts +1 -1
- package/src/__tests__/classify-change.test.ts +1 -1
- package/src/__tests__/compose-features-wiring.integration.ts +10 -9
- package/src/__tests__/compose-features.test.ts +1 -1
- package/src/__tests__/config-seed-boot.integration.ts +5 -4
- package/src/__tests__/crash-tracker.test.ts +1 -1
- package/src/__tests__/create-kumiko-server.integration.ts +5 -5
- package/src/__tests__/env-schema.integration.ts +1 -1
- package/src/__tests__/env-schema.test.ts +1 -1
- package/src/__tests__/few-shot-corpus.test.ts +1 -1
- package/src/__tests__/inject-schema.test.ts +1 -1
- package/src/__tests__/resolve-stylesheet.test.ts +11 -7
- package/src/__tests__/resolve-tailwind-cli.test.ts +1 -1
- package/src/__tests__/run-prod-app-spec.test.ts +1 -1
- package/src/__tests__/run-prod-app.integration.ts +6 -6
- package/src/__tests__/scaffold-app-feature.test.ts +1 -1
- package/src/__tests__/scaffold-app.test.ts +1 -1
- package/src/__tests__/scaffold-deploy.test.ts +1 -1
- package/src/__tests__/scaffold-feature.test.ts +1 -1
- package/src/__tests__/try-hono-first.test.ts +1 -1
- package/src/__tests__/walkthrough.integration.ts +118 -0
- package/src/codegen/__tests__/run-codegen.test.ts +1 -1
- package/src/codegen/__tests__/strict-mode-diagnostics.test.ts +1 -1
- package/src/codegen/__tests__/watch.test.ts +1 -1
- package/src/scaffold-app-feature.ts +2 -1
- package/src/scaffold-app.ts +139 -76
- package/src/{drizzle-tables-auth-mode.ts → schema-tables-auth-mode.ts} +1 -1
- package/templates/deploy/Dockerfile.template +15 -47
- package/CHANGELOG.md +0 -632
- package/src/drizzle-config.ts +0 -44
- /package/src/{drizzle-tables-minimal.ts → schema-tables-minimal.ts} +0 -0
package/src/scaffold-app.ts
CHANGED
|
@@ -6,16 +6,14 @@
|
|
|
6
6
|
// stub, package.json with @cosmicdrift/* deps, tsconfig, .env.example,
|
|
7
7
|
// README.
|
|
8
8
|
//
|
|
9
|
-
//
|
|
10
|
-
// -
|
|
11
|
-
//
|
|
12
|
-
//
|
|
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
|
|
126
|
-
return
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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
|
|
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.
|
|
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
|
-
|
|
30
|
-
|
|
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
|
-
#
|
|
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 (
|
|
39
|
+
# refs. Manifests first for Docker layer cache (bun install only
|
|
47
40
|
# invalidates on dep change).
|
|
48
|
-
COPY package.json
|
|
41
|
+
COPY package.json bun.lock ./
|
|
49
42
|
|
|
50
|
-
|
|
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
|