@cosmicdrift/kumiko-dev-server 0.352.0 → 0.354.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/bin/kumiko-build.ts +18 -2
- package/dist/codegen/run-codegen.d.ts +3 -0
- package/dist/codegen/run-codegen.js +14 -10
- package/dist/create-kumiko-server.d.ts +1 -0
- package/dist/create-kumiko-server.js +11 -8
- package/dist/run-dev-app.js +1 -0
- package/dist/scaffold-deploy.js +13 -1
- package/dist/scaffold-feature.js +1 -1
- package/package.json +6 -6
- package/src/changes.json +17 -0
package/bin/kumiko-build.ts
CHANGED
|
@@ -33,18 +33,34 @@ import {
|
|
|
33
33
|
|
|
34
34
|
if (process.argv.slice(2).some((arg) => arg === "--help" || arg === "-h")) {
|
|
35
35
|
process.stdout.write(
|
|
36
|
-
"Usage: kumiko-build [app-dir] build client (dist/) and server (dist-server/) bundles
|
|
36
|
+
"Usage: kumiko-build [--check] [app-dir] build client (dist/) and server (dist-server/) bundles;\n" +
|
|
37
|
+
" --check only verifies .kumiko/ is up to date (exit 1 on drift, writes nothing)\n",
|
|
37
38
|
);
|
|
38
39
|
process.exit(0);
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
const
|
|
42
|
+
const checkCodegenOnly = process.argv.includes("--check");
|
|
43
|
+
const explicit = process.argv.slice(2).find((arg) => !arg.startsWith("-"));
|
|
42
44
|
const cwd = explicit ? resolve(process.cwd(), explicit) : process.cwd();
|
|
43
45
|
|
|
44
46
|
const red = "\x1b[31m";
|
|
45
47
|
const yellow = "\x1b[33m";
|
|
46
48
|
const reset = "\x1b[0m";
|
|
47
49
|
|
|
50
|
+
if (checkCodegenOnly) {
|
|
51
|
+
const drift = runCodegen({ appRoot: cwd, checkOnly: true });
|
|
52
|
+
for (const w of drift.warnings) {
|
|
53
|
+
process.stderr.write(`${yellow}!${reset} [codegen] ${formatScanWarning(w)}\n`);
|
|
54
|
+
}
|
|
55
|
+
if (drift.didWriteTypes || drift.didWriteDefine || drift.didWriteSchemas) {
|
|
56
|
+
process.stderr.write(
|
|
57
|
+
`\n ${red}✗${reset} .kumiko/ is stale; run kumiko-build or the dev-server and commit.\n\n`,
|
|
58
|
+
);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
process.exit(0);
|
|
62
|
+
}
|
|
63
|
+
|
|
48
64
|
try {
|
|
49
65
|
// Read once up front — resolveClientEntries can throw (mutual exclusion,
|
|
50
66
|
// malformed declaration, unmigrated legacy client-*.tsx files) and that
|
|
@@ -7,6 +7,9 @@ export type CodegenOptions = {
|
|
|
7
7
|
* Die Dev-Server-Integration übergibt die QNs direkt aus der gebooteten
|
|
8
8
|
* Registry — CLI ruft sie aus dem Manifest. */
|
|
9
9
|
readonly handlerQns?: readonly string[];
|
|
10
|
+
/** Drift check for CI: nothing is written or removed; the `didWrite*` flags
|
|
11
|
+
* report which files would have changed. */
|
|
12
|
+
readonly checkOnly?: boolean;
|
|
10
13
|
};
|
|
11
14
|
export type CodegenResult = {
|
|
12
15
|
readonly outputDir: string;
|
|
@@ -44,7 +44,9 @@ export function runCodegen(opts) {
|
|
|
44
44
|
skipped: true,
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
|
-
|
|
47
|
+
const checkOnly = opts.checkOnly === true;
|
|
48
|
+
if (!checkOnly)
|
|
49
|
+
mkdirSync(outputDir, { recursive: true });
|
|
48
50
|
const typesContent = renderTypesAugmentation(scan.events, outputDir);
|
|
49
51
|
// `opts.handlerQns` undefined means the caller (kumiko-build) has no
|
|
50
52
|
// live feature registry to draw from and relies on the manifest
|
|
@@ -82,12 +84,12 @@ export function runCodegen(opts) {
|
|
|
82
84
|
const finalDefineContent = shouldPreserveStaleBlock
|
|
83
85
|
? withPreservedBlock(defineContent, definePath, TYPED_DISPATCHER_MARKER, LEGACY_TYPED_DISPATCHER_ANCHOR)
|
|
84
86
|
: defineContent;
|
|
85
|
-
const didWriteTypes = writeIfChanged(typesPath, finalTypesContent);
|
|
86
|
-
const didWriteDefine = writeIfChanged(definePath, finalDefineContent);
|
|
87
|
-
writeIfChanged(packageJsonPath, packageJsonContent);
|
|
87
|
+
const didWriteTypes = writeIfChanged(typesPath, finalTypesContent, checkOnly);
|
|
88
|
+
const didWriteDefine = writeIfChanged(definePath, finalDefineContent, checkOnly);
|
|
89
|
+
writeIfChanged(packageJsonPath, packageJsonContent, checkOnly);
|
|
88
90
|
const didWriteSchemas = schemasContent !== undefined
|
|
89
|
-
? writeIfChanged(schemasPath, schemasContent)
|
|
90
|
-
: removeIfExists(schemasPath);
|
|
91
|
+
? writeIfChanged(schemasPath, schemasContent, checkOnly)
|
|
92
|
+
: removeIfExists(schemasPath, checkOnly);
|
|
91
93
|
const warnings = shouldPreserveStaleBlock
|
|
92
94
|
? [
|
|
93
95
|
...scan.warnings,
|
|
@@ -144,11 +146,12 @@ function renderKumikoPackageJson() {
|
|
|
144
146
|
* must NOT trigger a full TS-language-server rebuild (which would
|
|
145
147
|
* happen on every mtime change).
|
|
146
148
|
*/
|
|
147
|
-
function writeIfChanged(path, content) {
|
|
149
|
+
function writeIfChanged(path, content, checkOnly) {
|
|
148
150
|
const existing = readExistingOrUndefined(path);
|
|
149
151
|
if (existing === content)
|
|
150
152
|
return false;
|
|
151
|
-
|
|
153
|
+
if (!checkOnly)
|
|
154
|
+
writeFileSync(path, content, "utf-8");
|
|
152
155
|
return true;
|
|
153
156
|
}
|
|
154
157
|
function readExistingOrUndefined(path) {
|
|
@@ -192,10 +195,11 @@ function extractBlock(content, anchor) {
|
|
|
192
195
|
* produces it (e.g. the last inline-schema was refactored to a named
|
|
193
196
|
* export). Returns true when an actual unlink happened.
|
|
194
197
|
*/
|
|
195
|
-
function removeIfExists(path) {
|
|
198
|
+
function removeIfExists(path, checkOnly) {
|
|
196
199
|
if (!existsSync(path))
|
|
197
200
|
return false;
|
|
198
|
-
|
|
201
|
+
if (!checkOnly)
|
|
202
|
+
rmSync(path, { force: true });
|
|
199
203
|
return true;
|
|
200
204
|
}
|
|
201
205
|
const featureManifestSchema = z.object({
|
|
@@ -201,6 +201,7 @@ export type KumikoServerHandle = {
|
|
|
201
201
|
};
|
|
202
202
|
export declare const STYLESHEET_WATCH_ENV = "KUMIKO_DEV_STYLESHEET_WATCH";
|
|
203
203
|
export declare const PROD_BUNDLES_ENV = "KUMIKO_DEV_PROD_BUNDLES";
|
|
204
|
+
export declare const DEFAULT_HTML = "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width,initial-scale=1,interactive-widget=resizes-content\" />\n <title>Kumiko</title>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/client.js\"></script>\n </body>\n</html>\n";
|
|
204
205
|
type DirectoryWatchEvents = (dir: string, options: {
|
|
205
206
|
readonly recursive: true;
|
|
206
207
|
readonly signal: AbortSignal;
|
|
@@ -20,8 +20,8 @@ import { readFile, realpath, watch } from "node:fs/promises";
|
|
|
20
20
|
import { tmpdir } from "node:os";
|
|
21
21
|
import { join, resolve, sep } from "node:path";
|
|
22
22
|
import { resolveAnonymousAccessFromRegistry } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
|
|
23
|
-
import {
|
|
24
|
-
import { buildAppSchema
|
|
23
|
+
import { createClientIpResolver, generateToken, } from "@cosmicdrift/kumiko-framework/api";
|
|
24
|
+
import { buildAppSchema } from "@cosmicdrift/kumiko-framework/engine";
|
|
25
25
|
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
26
26
|
import { pushEntityProjectionTables, setupTestStack, TestUsers, } from "@cosmicdrift/kumiko-framework/stack";
|
|
27
27
|
import { resolveAndInjectPageHead, } from "@cosmicdrift/kumiko-headless/apex";
|
|
@@ -29,6 +29,7 @@ import { startDevJobRunners } from "@cosmicdrift/kumiko-server-runtime/boot/job-
|
|
|
29
29
|
import { buildBunServeOptions, resolveDerivedMaxRequestBodySize, } from "@cosmicdrift/kumiko-server-runtime/bun-serve-options";
|
|
30
30
|
import { makeDispatchSystemWrite, } from "@cosmicdrift/kumiko-server-runtime/extra-routes-deps";
|
|
31
31
|
import { RENDERER_WEB_FONT_FILE_PATTERN, RENDERER_WEB_FONTS_URL_PREFIX, resolveRendererWebFontsDir, } from "@cosmicdrift/kumiko-server-runtime/renderer-web-fonts";
|
|
32
|
+
import { buildRequestBoundSystemQuery } from "@cosmicdrift/kumiko-server-runtime/request-bound-system-query";
|
|
32
33
|
import { canResolveTailwindStylesheet, resolveTailwindCli, } from "@cosmicdrift/kumiko-server-runtime/resolve-tailwind-cli";
|
|
33
34
|
import { stripNoRouteMatchHeader, tryHonoFirst, } from "@cosmicdrift/kumiko-server-runtime/try-hono-first";
|
|
34
35
|
// Runtime-detection. The dev-server is meant to run under Bun (Kumiko's
|
|
@@ -92,7 +93,7 @@ const RELOAD_SNIPPET = `
|
|
|
92
93
|
// keyboard shrinks only the visual viewport, not the layout viewport that
|
|
93
94
|
// `position: fixed` anchors to — a fixed bottom action bar would stay
|
|
94
95
|
// pinned behind the keyboard instead of above it.
|
|
95
|
-
const DEFAULT_HTML = `<!doctype html>
|
|
96
|
+
export const DEFAULT_HTML = `<!doctype html>
|
|
96
97
|
<html lang="en">
|
|
97
98
|
<head>
|
|
98
99
|
<meta charset="utf-8" />
|
|
@@ -725,11 +726,12 @@ export async function createKumikoServer(options) {
|
|
|
725
726
|
// warn-once flags in dev is an accepted, low-risk gap (dev normally
|
|
726
727
|
// runs unproxied — see CreateKumikoServerOptions.trustedProxyHops).
|
|
727
728
|
const pageHeadClientIpResolver = createClientIpResolver(options.trustedProxyHops ?? 0, "createKumikoServer(pageHead)");
|
|
728
|
-
const buildDevSystemQuery = (req, socketAddress) => (
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
729
|
+
const buildDevSystemQuery = (req, socketAddress) => buildRequestBoundSystemQuery({
|
|
730
|
+
req,
|
|
731
|
+
dispatcher: stack.dispatcher,
|
|
732
|
+
resolver: pageHeadClientIpResolver,
|
|
733
|
+
socketAddress,
|
|
734
|
+
});
|
|
733
735
|
// resolvePageHead goes through the same headless resolveAndInjectPageHead
|
|
734
736
|
// that runProdApp uses, so dev and e2e exercise the one timeout and
|
|
735
737
|
// fallback path instead of a second copy of it (#3026).
|
|
@@ -753,6 +755,7 @@ export async function createKumikoServer(options) {
|
|
|
753
755
|
path: url.pathname,
|
|
754
756
|
host,
|
|
755
757
|
systemQuery: buildDevSystemQuery(req, socketAddress),
|
|
758
|
+
requestSignal: req.signal,
|
|
756
759
|
});
|
|
757
760
|
}
|
|
758
761
|
return new Response(html, { status, headers });
|
package/dist/run-dev-app.js
CHANGED
package/dist/scaffold-deploy.js
CHANGED
|
@@ -47,6 +47,12 @@ export function renderDeployFiles(options) {
|
|
|
47
47
|
// `failed to compute cache key: "/app/seeds": not found`.
|
|
48
48
|
const sourceDir = options.sourceDir ?? destinationRoot;
|
|
49
49
|
const detected = detectOptionalSurfaces(sourceDir, options.appName);
|
|
50
|
+
if (detected.hasPrivateGhPackages && detected.registryConfigFiles.length === 0) {
|
|
51
|
+
// The Dockerfile only forwards the auth build-arg; without a registry
|
|
52
|
+
// config scope entry bun resolves @cosmicdriftgamestudio/* against npmjs
|
|
53
|
+
// and the image build fails late with a 404.
|
|
54
|
+
throw new Error(`renderDeployFiles: private @cosmicdriftgamestudio/* deps need a bunfig.toml or .npmrc in ${sourceDir} with a scope entry for the private registry`);
|
|
55
|
+
}
|
|
50
56
|
const installManifests = ["package.json", "bun.lock", ...detected.registryConfigFiles].join(" ");
|
|
51
57
|
const subs = {
|
|
52
58
|
appName: options.appName,
|
|
@@ -198,8 +204,10 @@ function detectOptionalSurfaces(sourceDir, appName) {
|
|
|
198
204
|
let deployConfigRaw;
|
|
199
205
|
const pkgJsonPath = join(sourceDir, "package.json");
|
|
200
206
|
if (existsSync(pkgJsonPath)) {
|
|
207
|
+
let jsonParsed = false;
|
|
201
208
|
try {
|
|
202
209
|
const raw = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
|
|
210
|
+
jsonParsed = true;
|
|
203
211
|
// Read ahead of packageJsonSchema.parse: an unrelated shape problem in
|
|
204
212
|
// `dependencies`/`workspaces` must not silently discard a valid deploy
|
|
205
213
|
// config along with it (that's caught by the outer catch below).
|
|
@@ -221,8 +229,12 @@ function detectOptionalSurfaces(sourceDir, appName) {
|
|
|
221
229
|
// back to defaults (an invalid deploy config must THROW, but
|
|
222
230
|
// unreadable JSON can't distinguish "no deploy config" from "invalid
|
|
223
231
|
// deploy config" — it already surfaces via this warning).
|
|
232
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
233
|
+
const message = jsonParsed
|
|
234
|
+
? `scaffoldDeploy: package.json at ${pkgJsonPath} has an unexpected dependencies/workspaces shape — private-GH-packages/install-layout detection skipped (${reason})`
|
|
235
|
+
: `scaffoldDeploy: package.json at ${pkgJsonPath} is not valid JSON — private-GH-packages/install-layout detection skipped and kumiko.deploy (dbUser/dbName/stackNetwork) falls back to the defaults (${reason})`;
|
|
224
236
|
// biome-ignore lint/suspicious/noConsole: scaffold visibility for skipped private-package detection
|
|
225
|
-
console.warn(
|
|
237
|
+
console.warn(message);
|
|
226
238
|
}
|
|
227
239
|
}
|
|
228
240
|
const registryConfigFiles = REGISTRY_CONFIG_FILES.filter((f) => existsSync(join(sourceDir, f)));
|
package/dist/scaffold-feature.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-dev-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.354.0",
|
|
4
4
|
"description": "Dev-tooling for Kumiko apps: local dev-server bootstrap (runDevApp), scaffolding, codegen. Its compose-stacks/env-schema subpaths are consumed at prod boot too — see @cosmicdrift/kumiko-server-runtime for the prod runner itself.",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -64,11 +64,11 @@
|
|
|
64
64
|
"kumiko-upgrade": "./bin/kumiko-upgrade.ts"
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@cosmicdrift/kumiko-bundled-features": "0.
|
|
68
|
-
"@cosmicdrift/kumiko-framework": "0.
|
|
69
|
-
"@cosmicdrift/kumiko-headless": "0.
|
|
70
|
-
"@cosmicdrift/kumiko-renderer-web": "0.
|
|
71
|
-
"@cosmicdrift/kumiko-server-runtime": "0.
|
|
67
|
+
"@cosmicdrift/kumiko-bundled-features": "0.354.0",
|
|
68
|
+
"@cosmicdrift/kumiko-framework": "0.354.0",
|
|
69
|
+
"@cosmicdrift/kumiko-headless": "0.354.0",
|
|
70
|
+
"@cosmicdrift/kumiko-renderer-web": "0.354.0",
|
|
71
|
+
"@cosmicdrift/kumiko-server-runtime": "0.354.0",
|
|
72
72
|
"bun-types": "^1.3.13",
|
|
73
73
|
"ts-morph": "^28.0.0",
|
|
74
74
|
"zod": "^4.4.3"
|
package/src/changes.json
CHANGED
|
@@ -1,4 +1,21 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.354.0",
|
|
4
|
+
"type": "fix",
|
|
5
|
+
"title": "Dev boot passes Redis to the delivery service so notify idempotencyKey dedupes",
|
|
6
|
+
"migration": "No action needed."
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"version": "0.353.0",
|
|
10
|
+
"type": "fix",
|
|
11
|
+
"title": "init-deploy fails early when private GitHub packages have no bunfig.toml or .npmrc",
|
|
12
|
+
"detail": "init-deploy rejects private GitHub packages without a registry config\nAn app with `@cosmicdriftgamestudio/*` dependencies but no `bunfig.toml`/`.npmrc` used to get a Dockerfile whose `bun install` failed with a 404 only inside the image build. `scaffoldDeploy`, `renderDeployFiles` and `checkDeployDrift` now throw with a hint to add the scope entry."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"version": "0.353.0",
|
|
16
|
+
"type": "improvement",
|
|
17
|
+
"title": "Deploy scaffold warnings distinguish broken package.json from unexpected dependency shapes"
|
|
18
|
+
},
|
|
2
19
|
{
|
|
3
20
|
"version": "0.351.0",
|
|
4
21
|
"type": "fix",
|