@cosmicdrift/kumiko-dev-server 0.14.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 +8 -12
- 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 +1 -1
- 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/{drizzle-tables-auth-mode.ts → schema-tables-auth-mode.ts} +1 -1
- package/templates/deploy/Dockerfile.template +15 -47
- package/CHANGELOG.md +0 -656
- package/src/drizzle-config.ts +0 -44
- /package/src/{drizzle-tables-minimal.ts → schema-tables-minimal.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-dev-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
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>",
|
|
@@ -30,17 +30,13 @@
|
|
|
30
30
|
"types": "./src/compose-features.ts",
|
|
31
31
|
"default": "./src/compose-features.ts"
|
|
32
32
|
},
|
|
33
|
-
"./
|
|
34
|
-
"types": "./src/
|
|
35
|
-
"default": "./src/
|
|
33
|
+
"./schema-tables-auth-mode": {
|
|
34
|
+
"types": "./src/schema-tables-auth-mode.ts",
|
|
35
|
+
"default": "./src/schema-tables-auth-mode.ts"
|
|
36
36
|
},
|
|
37
|
-
"./
|
|
38
|
-
"types": "./src/
|
|
39
|
-
"default": "./src/
|
|
40
|
-
},
|
|
41
|
-
"./drizzle-tables-minimal": {
|
|
42
|
-
"types": "./src/drizzle-tables-minimal.ts",
|
|
43
|
-
"default": "./src/drizzle-tables-minimal.ts"
|
|
37
|
+
"./schema-tables-minimal": {
|
|
38
|
+
"types": "./src/schema-tables-minimal.ts",
|
|
39
|
+
"default": "./src/schema-tables-minimal.ts"
|
|
44
40
|
}
|
|
45
41
|
},
|
|
46
42
|
"bin": {
|
|
@@ -63,4 +59,4 @@
|
|
|
63
59
|
"README.md",
|
|
64
60
|
"LICENSE"
|
|
65
61
|
]
|
|
66
|
-
}
|
|
62
|
+
}
|
|
@@ -12,13 +12,13 @@
|
|
|
12
12
|
// braucht Bun. Spawnen kumiko-build als subprocess via PATH.
|
|
13
13
|
// Skipped wenn `bun` nicht erreichbar — selten, aber sauber.
|
|
14
14
|
|
|
15
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
15
16
|
import { execFileSync } from "node:child_process";
|
|
16
17
|
import { existsSync } from "node:fs";
|
|
17
18
|
import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
18
19
|
import { tmpdir } from "node:os";
|
|
19
20
|
import { dirname, join, resolve } from "node:path";
|
|
20
21
|
import { fileURLToPath } from "node:url";
|
|
21
|
-
import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
|
22
22
|
import { buildProdBundle } from "../build-prod-bundle";
|
|
23
23
|
|
|
24
24
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
// laufen im CI als `yarn build` auf der Showcase-App; das ist der
|
|
7
7
|
// ehrlichere Smoke-Test.
|
|
8
8
|
|
|
9
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
9
10
|
import { existsSync } from "node:fs";
|
|
10
11
|
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
11
12
|
import { tmpdir } from "node:os";
|
|
12
13
|
import { join } from "node:path";
|
|
13
|
-
import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
|
14
14
|
import {
|
|
15
15
|
type ClientEntry,
|
|
16
16
|
discoverClientEntries,
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// /manifest.json, /sw.js → no-cache
|
|
8
8
|
// alles andere → kein expliziter Header
|
|
9
9
|
|
|
10
|
-
import { describe, expect, test } from "
|
|
10
|
+
import { describe, expect, test } from "bun:test";
|
|
11
11
|
import { cacheHeadersFor } from "../run-prod-app";
|
|
12
12
|
|
|
13
13
|
describe("cacheHeadersFor", () => {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// Restarts (DX schlecht) oder echte Schema-Änderungen schlagen
|
|
6
6
|
// nicht durch (UX broken). Beide sind teuer — daher pinnen wir.
|
|
7
7
|
|
|
8
|
-
import { describe, expect, test } from "
|
|
8
|
+
import { describe, expect, test } from "bun:test";
|
|
9
9
|
import { classifyChange } from "../create-kumiko-server";
|
|
10
10
|
|
|
11
11
|
describe("classifyChange", () => {
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
// schreibt in ein lokales Array — gewollter Capture-Spy ohne vitest-
|
|
22
22
|
// Mock-API (CLAUDE.md "Kein Mock in *.integration.ts").
|
|
23
23
|
|
|
24
|
+
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
24
25
|
import { randomBytes } from "node:crypto";
|
|
25
26
|
import {
|
|
26
27
|
AuthErrors,
|
|
@@ -34,6 +35,7 @@ import {
|
|
|
34
35
|
import { tenantEntity, tenantMembershipsTable } from "@cosmicdrift/kumiko-bundled-features/tenant";
|
|
35
36
|
import { seedTenantMembership } from "@cosmicdrift/kumiko-bundled-features/tenant/testing";
|
|
36
37
|
import { UserHandlers, userEntity, userTable } from "@cosmicdrift/kumiko-bundled-features/user";
|
|
38
|
+
import { deleteMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
37
39
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
38
40
|
import {
|
|
39
41
|
setupTestStack,
|
|
@@ -42,7 +44,6 @@ import {
|
|
|
42
44
|
unsafeCreateEntityTable,
|
|
43
45
|
unsafePushTables,
|
|
44
46
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
45
|
-
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
46
47
|
import { composeFeatures } from "../compose-features";
|
|
47
48
|
|
|
48
49
|
const RESET_HMAC = randomBytes(32).toString("base64");
|
|
@@ -151,8 +152,8 @@ describe("composeFeatures wiring — passwordReset", () => {
|
|
|
151
152
|
});
|
|
152
153
|
|
|
153
154
|
beforeEach(async () => {
|
|
154
|
-
await suite.stack.db
|
|
155
|
-
await suite.stack.db
|
|
155
|
+
await deleteMany(suite.stack.db, userTable, {});
|
|
156
|
+
await deleteMany(suite.stack.db, tenantMembershipsTable, {});
|
|
156
157
|
suite.resetEmails.length = 0;
|
|
157
158
|
suite.verifyEmails.length = 0;
|
|
158
159
|
});
|
|
@@ -225,8 +226,8 @@ describe("composeFeatures wiring — emailVerification", () => {
|
|
|
225
226
|
});
|
|
226
227
|
|
|
227
228
|
beforeEach(async () => {
|
|
228
|
-
await suite.stack.db
|
|
229
|
-
await suite.stack.db
|
|
229
|
+
await deleteMany(suite.stack.db, userTable, {});
|
|
230
|
+
await deleteMany(suite.stack.db, tenantMembershipsTable, {});
|
|
230
231
|
suite.resetEmails.length = 0;
|
|
231
232
|
suite.verifyEmails.length = 0;
|
|
232
233
|
});
|
|
@@ -271,8 +272,8 @@ describe("composeFeatures wiring — asymmetric activation", () => {
|
|
|
271
272
|
});
|
|
272
273
|
|
|
273
274
|
beforeEach(async () => {
|
|
274
|
-
await suite.stack.db
|
|
275
|
-
await suite.stack.db
|
|
275
|
+
await deleteMany(suite.stack.db, userTable, {});
|
|
276
|
+
await deleteMany(suite.stack.db, tenantMembershipsTable, {});
|
|
276
277
|
suite.resetEmails.length = 0;
|
|
277
278
|
suite.verifyEmails.length = 0;
|
|
278
279
|
});
|
|
@@ -325,8 +326,8 @@ describe("composeFeatures wiring — fail-closed ohne authOptions", () => {
|
|
|
325
326
|
});
|
|
326
327
|
|
|
327
328
|
afterEach(async () => {
|
|
328
|
-
await suite.stack.db
|
|
329
|
-
await suite.stack.db
|
|
329
|
+
await deleteMany(suite.stack.db, userTable, {});
|
|
330
|
+
await deleteMany(suite.stack.db, tenantMembershipsTable, {});
|
|
330
331
|
suite.resetEmails.length = 0;
|
|
331
332
|
});
|
|
332
333
|
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
// aber die Handler fehlen → POST /api/auth/request-password-reset
|
|
8
8
|
// dispatched ins Leere → 500.
|
|
9
9
|
|
|
10
|
+
import { describe, expect, test } from "bun:test";
|
|
10
11
|
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
11
|
-
import { describe, expect, test } from "vitest";
|
|
12
12
|
import { composeFeatures } from "../compose-features";
|
|
13
13
|
|
|
14
14
|
const noopFeature = defineFeature("noop-app", () => {});
|
|
@@ -12,12 +12,14 @@
|
|
|
12
12
|
// 3. an admin set on top of a seed wins the resolver cascade; coexistence
|
|
13
13
|
// vs. override semantics depend on the admin user's tenantId.
|
|
14
14
|
|
|
15
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
15
16
|
import {
|
|
16
17
|
configValuesTable,
|
|
17
18
|
createConfigAccessorFactory,
|
|
18
19
|
createConfigFeature,
|
|
19
20
|
createConfigResolver,
|
|
20
21
|
} from "@cosmicdrift/kumiko-bundled-features/config";
|
|
22
|
+
import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
21
23
|
import {
|
|
22
24
|
access,
|
|
23
25
|
createSystemConfig,
|
|
@@ -32,7 +34,6 @@ import {
|
|
|
32
34
|
TestUsers,
|
|
33
35
|
unsafePushTables,
|
|
34
36
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
35
|
-
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
36
37
|
import { applyBootSeeds } from "../boot/apply-boot-seeds";
|
|
37
38
|
|
|
38
39
|
const bootSeedsFeature = defineFeature("boot-seeds-test", (r) => {
|
|
@@ -82,7 +83,7 @@ describe("config-seed boot wiring", () => {
|
|
|
82
83
|
test("first boot: applyBootSeeds writes one row per seed", async () => {
|
|
83
84
|
await applyBootSeeds({ registry: stack.registry, db: stack.db });
|
|
84
85
|
|
|
85
|
-
const rows = await stack.db
|
|
86
|
+
const rows = await selectMany(stack.db, configValuesTable);
|
|
86
87
|
expect(rows.length).toBe(2);
|
|
87
88
|
|
|
88
89
|
const siteKeyDef = stack.registry.getConfigKey(SITE_KEY);
|
|
@@ -111,7 +112,7 @@ describe("config-seed boot wiring", () => {
|
|
|
111
112
|
test("re-boot: idempotent — every seed already on disk → no extra rows", async () => {
|
|
112
113
|
await applyBootSeeds({ registry: stack.registry, db: stack.db });
|
|
113
114
|
|
|
114
|
-
const rows = await stack.db
|
|
115
|
+
const rows = await selectMany(stack.db, configValuesTable);
|
|
115
116
|
expect(rows.length).toBe(2);
|
|
116
117
|
});
|
|
117
118
|
|
|
@@ -151,7 +152,7 @@ describe("config-seed boot wiring", () => {
|
|
|
151
152
|
// - 3 rows = coexistence path (admin tenantId !== SYSTEM_TENANT_ID,
|
|
152
153
|
// new specific-tenant row sits next to the seed system-row).
|
|
153
154
|
// Either is correct as long as the resolver picks the admin value.
|
|
154
|
-
const rows = await stack.db
|
|
155
|
+
const rows = await selectMany(stack.db, configValuesTable);
|
|
155
156
|
expect([2, 3]).toContain(rows.length);
|
|
156
157
|
});
|
|
157
158
|
});
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Wrapper aufgibt oder noch eine Runde respawnt; off-by-one am Fenster-
|
|
4
4
|
// Rand würde im Bin-Skript schlecht auffallen.
|
|
5
5
|
|
|
6
|
-
import { describe, expect, test } from "
|
|
6
|
+
import { describe, expect, test } from "bun:test";
|
|
7
7
|
import { createCrashTracker } from "../crash-tracker";
|
|
8
8
|
|
|
9
9
|
describe("createCrashTracker", () => {
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
+
import { afterEach, describe, expect, test } from "bun:test";
|
|
1
2
|
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
2
3
|
import { tmpdir } from "node:os";
|
|
3
4
|
import { join } from "node:path";
|
|
5
|
+
import { asRawClient } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
4
6
|
import {
|
|
5
7
|
createBooleanField,
|
|
6
8
|
createEntity,
|
|
7
9
|
createTextField,
|
|
8
10
|
defineFeature,
|
|
9
11
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
10
|
-
import { sql } from "drizzle-orm";
|
|
11
|
-
import { afterEach, describe, expect, test } from "vitest";
|
|
12
12
|
import { createKumikoServer, type KumikoServerHandle } from "../create-kumiko-server";
|
|
13
13
|
|
|
14
14
|
// Integration-Test: bootet createKumikoServer mit echtem Postgres,
|
|
@@ -50,10 +50,10 @@ async function boot(): Promise<KumikoServerHandle> {
|
|
|
50
50
|
describe("createKumikoServer", () => {
|
|
51
51
|
test("bootet den Kumiko-Stack + legt die Feature-Tables an", async () => {
|
|
52
52
|
const h = await boot();
|
|
53
|
-
const rows = await h.stack.db.
|
|
54
|
-
|
|
53
|
+
const rows = await asRawClient(h.stack.db).unsafe(
|
|
54
|
+
`SELECT to_regclass('public.kumiko_server_probe') IS NOT NULL AS "exists"`,
|
|
55
55
|
);
|
|
56
|
-
expect(rows[0]?.exists).toBe(true);
|
|
56
|
+
expect((rows as Array<Record<string, unknown>>)[0]?.["exists"]).toBe(true);
|
|
57
57
|
});
|
|
58
58
|
|
|
59
59
|
test("GET / → HTML + kumiko_auth/kumiko_csrf Set-Cookie", async () => {
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
// throws (via bootErrorReporter override) and KUMIKO_DRY_RUN_ENV
|
|
5
5
|
// returns the dry-run handle without booting.
|
|
6
6
|
|
|
7
|
+
import { describe, expect, it } from "bun:test";
|
|
7
8
|
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
8
9
|
import { composeEnvSchema, KumikoBootError } from "@cosmicdrift/kumiko-framework/env";
|
|
9
|
-
import { describe, expect, it } from "vitest";
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
import { frameworkCoreEnvSchema } from "../env-schema";
|
|
12
12
|
import * as devServerPublicApi from "../index";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
1
2
|
import { composeEnvSchema, KumikoBootError, parseEnv } from "@cosmicdrift/kumiko-framework/env";
|
|
2
|
-
import { describe, expect, it } from "vitest";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { type FrameworkCoreEnv, frameworkCoreEnvSchema } from "../env-schema";
|
|
5
5
|
|
|
@@ -13,11 +13,11 @@
|
|
|
13
13
|
// because the corpus JSON now lives there — framework is public and must
|
|
14
14
|
// not carry the eval baseline.
|
|
15
15
|
|
|
16
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
16
17
|
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
17
18
|
import { tmpdir } from "node:os";
|
|
18
19
|
import { join } from "node:path";
|
|
19
20
|
import { buildFewShotCorpus, pathToId } from "@cosmicdrift/kumiko-dev-server";
|
|
20
|
-
import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
|
21
21
|
|
|
22
22
|
let workdir: string;
|
|
23
23
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// nicht und mountet leer. Tests pinnen die Idempotenz + die zwei
|
|
5
5
|
// Insertion-Punkte (vor /client.js-Tag oder vor </body>).
|
|
6
6
|
|
|
7
|
-
import { describe, expect, test } from "
|
|
7
|
+
import { describe, expect, test } from "bun:test";
|
|
8
8
|
import { injectSchema } from "../inject-schema";
|
|
9
9
|
|
|
10
10
|
const SCHEMA = '{"features":[]}';
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
// die anderen Tests dort booten ein TestStack (DB + Redis), das brauchen
|
|
8
8
|
// wir für reine Resolver-Logik nicht.
|
|
9
9
|
|
|
10
|
+
import { describe, expect, test } from "bun:test";
|
|
10
11
|
import { mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
11
12
|
import { tmpdir } from "node:os";
|
|
12
13
|
import { join } from "node:path";
|
|
13
|
-
import { describe, expect, test } from "vitest";
|
|
14
14
|
import { resolveStylesheet } from "../create-kumiko-server";
|
|
15
15
|
|
|
16
16
|
describe("resolveStylesheet", () => {
|
|
@@ -48,16 +48,20 @@ describe("resolveStylesheet", () => {
|
|
|
48
48
|
expect(out).toBeUndefined();
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
-
test("undefined + clientEntry
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
51
|
+
test("undefined + clientEntry: undefined (silent skip)", () => {
|
|
52
|
+
// Bun resolveSync findet packages/renderer-web/src/styles.css im
|
|
53
|
+
// Repo. Das ist der prod-Pfad — unter Bun (real oder CI) ist der
|
|
54
|
+
// Wert ein absoluter path; unter Node (von wo der Test portiert
|
|
55
|
+
// wurde) wäre es undefined. Wir akzeptieren beides.
|
|
56
56
|
const out = resolveStylesheet({
|
|
57
57
|
features: [],
|
|
58
58
|
clientEntry: "./entry.tsx",
|
|
59
59
|
});
|
|
60
|
-
|
|
60
|
+
if (typeof Bun === "undefined") {
|
|
61
|
+
expect(out).toBeUndefined();
|
|
62
|
+
} else {
|
|
63
|
+
expect(out).toMatch(/renderer-web\/src\/styles\.css$/);
|
|
64
|
+
}
|
|
61
65
|
});
|
|
62
66
|
|
|
63
67
|
test("undefined + clientEntry + src/styles.css existiert → returns App-Theme-Override", () => {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// genau das, was den dev-server-Crash bei flakigem Netz verhindert:
|
|
3
3
|
// kein Bun → undefined, Package nicht installiert → undefined.
|
|
4
4
|
|
|
5
|
-
import { describe, expect, test } from "
|
|
5
|
+
import { describe, expect, test } from "bun:test";
|
|
6
6
|
import { resolveTailwindCli } from "../resolve-tailwind-cli";
|
|
7
7
|
|
|
8
8
|
describe("resolveTailwindCli", () => {
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
// "looks like a leak"-Reverts oder "bisschen rauf, sollte reichen"-
|
|
5
5
|
// Tweaks.
|
|
6
6
|
|
|
7
|
+
import { describe, expect, test } from "bun:test";
|
|
7
8
|
import { SSE_HEARTBEAT_INTERVAL_MS } from "@cosmicdrift/kumiko-framework/api";
|
|
8
|
-
import { describe, expect, test } from "vitest";
|
|
9
9
|
import { buildBunServeOptions } from "../run-prod-app";
|
|
10
10
|
|
|
11
11
|
describe("Bun.serve options for production", () => {
|
|
@@ -9,9 +9,11 @@
|
|
|
9
9
|
// fetch direkt. Bun.serve-Wiring ist in Production-Coolify selbst
|
|
10
10
|
// getestet wenn der Container hochfährt.
|
|
11
11
|
|
|
12
|
+
import { afterEach, beforeAll, describe, expect, test } from "bun:test";
|
|
12
13
|
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
13
14
|
import { tmpdir } from "node:os";
|
|
14
15
|
import { dirname, join } from "node:path";
|
|
16
|
+
import { asRawClient } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
15
17
|
import { createDbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
16
18
|
import {
|
|
17
19
|
createBooleanField,
|
|
@@ -28,9 +30,7 @@ import {
|
|
|
28
30
|
createProjectionStateTable,
|
|
29
31
|
} from "@cosmicdrift/kumiko-framework/pipeline";
|
|
30
32
|
import { unsafeEnsureEntityTable } from "@cosmicdrift/kumiko-framework/stack";
|
|
31
|
-
import { sql } from "drizzle-orm";
|
|
32
33
|
import postgres from "postgres";
|
|
33
|
-
import { afterEach, beforeAll, describe, expect, test } from "vitest";
|
|
34
34
|
import { z } from "zod";
|
|
35
35
|
import { type ProdAppHandle, runProdApp } from "../run-prod-app";
|
|
36
36
|
|
|
@@ -448,7 +448,7 @@ describe("runProdApp", () => {
|
|
|
448
448
|
});
|
|
449
449
|
|
|
450
450
|
expect(invocations).toBe(1);
|
|
451
|
-
expect(factoryDeps).toEqual({ db: true, redis: true, registry: true });
|
|
451
|
+
expect(factoryDeps!).toEqual({ db: true, redis: true, registry: true });
|
|
452
452
|
// Smoke: handle is functional (boot completed without error).
|
|
453
453
|
expect(handle.entrypoint).toBeDefined();
|
|
454
454
|
});
|
|
@@ -465,9 +465,9 @@ describe("runProdApp", () => {
|
|
|
465
465
|
seedInvocations++;
|
|
466
466
|
// Seed-side idempotence: check before inserting. runProdApp doesn't
|
|
467
467
|
// gate seeds — the seed itself is responsible.
|
|
468
|
-
const existing = await db.
|
|
469
|
-
if (existing.length > 0) return;
|
|
470
|
-
await db.
|
|
468
|
+
const existing = await asRawClient(db).unsafe(`SELECT 1 FROM prod_widgets LIMIT 1`);
|
|
469
|
+
if ((existing as Array<Record<string, unknown>>).length > 0) return;
|
|
470
|
+
await asRawClient(db).unsafe(`INSERT INTO prod_widgets (id, tenant_id, name) VALUES
|
|
471
471
|
(gen_random_uuid(), '00000000-0000-4000-8000-000000000001', 'seeded')`);
|
|
472
472
|
inserted = true;
|
|
473
473
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// scaffoldAppFeature unit-tests (DX-2).
|
|
2
2
|
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
3
4
|
import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
4
5
|
import { tmpdir } from "node:os";
|
|
5
6
|
import { join } from "node:path";
|
|
6
|
-
import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
|
7
7
|
import { scaffoldApp } from "../scaffold-app";
|
|
8
8
|
import { scaffoldAppFeature } from "../scaffold-app-feature";
|
|
9
9
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// scaffoldApp unit-tests (DX-1.0).
|
|
2
2
|
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
3
4
|
import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
4
5
|
import { tmpdir } from "node:os";
|
|
5
6
|
import { join } from "node:path";
|
|
6
|
-
import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
|
7
7
|
import { scaffoldApp } from "../scaffold-app";
|
|
8
8
|
|
|
9
9
|
describe("scaffoldApp", () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from "bun:test";
|
|
1
2
|
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
3
|
import { tmpdir } from "node:os";
|
|
3
4
|
import { join } from "node:path";
|
|
4
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
5
5
|
import { scaffoldDeploy } from "../scaffold-deploy";
|
|
6
6
|
|
|
7
7
|
describe("scaffoldDeploy", () => {
|
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
// 4. Validation: bad names fail loudly, existing destination refuses
|
|
9
9
|
// to overwrite
|
|
10
10
|
|
|
11
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
11
12
|
import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
12
13
|
import { tmpdir } from "node:os";
|
|
13
14
|
import { join } from "node:path";
|
|
14
15
|
import { parseSourceFile, VERSION_HEADER } from "@cosmicdrift/kumiko-framework/engine";
|
|
15
16
|
import { Project } from "ts-morph";
|
|
16
|
-
import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
|
17
17
|
import { scaffoldFeature } from "../scaffold-feature";
|
|
18
18
|
|
|
19
19
|
let workdir: string;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// sich ändert (z.B. "matched" auch für 4xx anders als 404), MÜSSEN
|
|
6
6
|
// beide Pfade synchron updaten.
|
|
7
7
|
|
|
8
|
-
import { describe, expect, test } from "
|
|
8
|
+
import { describe, expect, test } from "bun:test";
|
|
9
9
|
import { type HonoLikeApp, tryHonoFirst } from "../try-hono-first";
|
|
10
10
|
|
|
11
11
|
function makeApp(response: Response): HonoLikeApp {
|
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
// - composeFeatures(includeBundled:true) yields the exact feature-count
|
|
10
10
|
// the walkthrough advertises in "Expected output"
|
|
11
11
|
|
|
12
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
12
13
|
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
13
14
|
import { tmpdir } from "node:os";
|
|
14
15
|
import { join } from "node:path";
|
|
15
16
|
import { createSecretsFeature } from "@cosmicdrift/kumiko-bundled-features/secrets";
|
|
16
17
|
import { createSessionsFeature } from "@cosmicdrift/kumiko-bundled-features/sessions";
|
|
17
18
|
import { createRegistry, defineFeature, validateBoot } from "@cosmicdrift/kumiko-framework/engine";
|
|
18
|
-
import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
|
19
19
|
import { composeFeatures } from "../compose-features";
|
|
20
20
|
import { scaffoldApp } from "../scaffold-app";
|
|
21
21
|
import { scaffoldAppFeature } from "../scaffold-app-feature";
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
// - skipped-Flag wenn 0 Events UND kein .kumiko/ schon existiert
|
|
17
17
|
// - schemas.generated.ts wird erzeugt wenn inline-Schemas, sonst nicht
|
|
18
18
|
|
|
19
|
+
import { describe, expect, test } from "bun:test";
|
|
19
20
|
import { existsSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs";
|
|
20
21
|
import { tmpdir } from "node:os";
|
|
21
22
|
import { join } from "node:path";
|
|
22
|
-
import { describe, expect, test } from "vitest";
|
|
23
23
|
import { runCodegen } from "../run-codegen";
|
|
24
24
|
|
|
25
25
|
function makeAppDir(): string {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
1
2
|
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
2
3
|
import { dirname, join } from "node:path";
|
|
3
4
|
import * as ts from "typescript";
|
|
4
|
-
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
5
5
|
import { runCodegen } from "../run-codegen";
|
|
6
6
|
|
|
7
7
|
const REPO_ROOT = join(__dirname, "../../../../..");
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
// 'zod' nicht direct nutzen, runCodegen scant feature-files die
|
|
9
9
|
// `import { z } from "zod"` haben.
|
|
10
10
|
|
|
11
|
+
import { afterAll, describe, expect, test } from "bun:test";
|
|
11
12
|
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
12
13
|
import { dirname, join } from "node:path";
|
|
13
|
-
import { afterAll, describe, expect, test } from "vitest";
|
|
14
14
|
import type { CodegenResult } from "../run-codegen";
|
|
15
15
|
import { watchAndRegenerate } from "../watch";
|
|
16
16
|
|
|
@@ -114,7 +114,8 @@ function mountInRunConfig(runConfigPath: string, name: string): boolean {
|
|
|
114
114
|
|
|
115
115
|
// 1. Prepend import after the last existing import.
|
|
116
116
|
const imports = sf.getImportDeclarations();
|
|
117
|
-
const insertIndex =
|
|
117
|
+
const insertIndex =
|
|
118
|
+
imports.length > 0 ? (imports[imports.length - 1]?.getChildIndex() ?? 0) + 1 : 0;
|
|
118
119
|
sf.insertImportDeclaration(insertIndex, {
|
|
119
120
|
moduleSpecifier: `./features/${name}`,
|
|
120
121
|
namedImports: [`${camel}Feature`],
|
|
@@ -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
|