@cosmicdrift/kumiko-dev-server 0.339.0 → 0.341.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.
@@ -15,7 +15,7 @@ export type BuildServerBundleEntry = {
15
15
  };
16
16
  export type BuildServerBundleResult = {
17
17
  readonly outDir: string;
18
- /** Benannte Entry-Files (server.js, ggf. kumiko.js). */
18
+ /** Named entry files (server.js, plus kumiko.js, worker.js and bootstrap.js when present). */
19
19
  readonly entries: readonly BuildServerBundleEntry[];
20
20
  /** Geteilte Framework-Chunks (von splitting). */
21
21
  readonly chunks: readonly BuildServerBundleEntry[];
@@ -8,18 +8,23 @@
8
8
  // bin/main.ts → dist-server/server.js (App-Boot, ruft runProdApp)
9
9
  // <repo>/bin/kumiko.ts → dist-server/kumiko.js (Migrate-CLI: `schema apply`,
10
10
  // gefunden via walk-up bis bin/kumiko.ts)
11
+ // bin/worker.ts → dist-server/worker.js (optional, next to bin/main.ts:
12
+ // background worker as its own process from the same image)
13
+ // bin/bootstrap.ts → dist-server/bootstrap.js (optional, next to bin/main.ts:
14
+ // one-shot runBootstrap provisioning, run as a k8s Job)
11
15
  // dist-server/package.json → runtime-deps mit gepinnten Versionen
12
16
  //
13
- // Beide Entries werden in EINEM Bun.build-Call mit `splitting` gebaut: das
14
- // Framework landet als geteilte chunk-*.js, server.js + kumiko.js sind schlanke
15
- // Entries die sie importieren — statt das Framework pro Entry neu zu inlinen
16
- // (vorher ~14 MB × N separate Bundles).
17
+ // All entries are built in ONE Bun.build call with `splitting`: the framework
18
+ // lands once as shared chunk-*.js and server.js, kumiko.js, worker.js and
19
+ // bootstrap.js are thin entries importing it. Separate bundles would inline ~14 MB per entry.
17
20
  //
18
21
  // Output:
19
22
  //
20
23
  // dist-server/
21
24
  // server.js ← App-Boot-Entry
22
25
  // kumiko.js ← Migrate-CLI-Entry (wenn bin/kumiko.ts gefunden)
26
+ // worker.js ← worker entry (if bin/worker.ts sits next to main.ts)
27
+ // bootstrap.js ← provisioning entry (if bin/bootstrap.ts sits next to main.ts)
23
28
  // chunk-*.js ← geteilte Framework-Chunks
24
29
  // package.json ← runtime-deps mit gepinnten Versionen
25
30
  //
@@ -105,7 +110,10 @@ export async function buildServerBundle(options = {}) {
105
110
  await mkdir(outDir, { recursive: true });
106
111
  // Ein Bun.build-Call mit allen Entries + splitting → das Framework wird
107
112
  // einmal als shared chunk abgelegt statt pro Entry inlined.
108
- const entrypoints = kumikoCli ? [serverEntry, kumikoCli] : [serverEntry];
113
+ const optionalSiblingEntries = ["worker.ts", "bootstrap.ts"]
114
+ .map((file) => join(dirname(serverEntry), file))
115
+ .filter((path) => existsSync(path));
116
+ const entrypoints = [serverEntry, ...(kumikoCli ? [kumikoCli] : []), ...optionalSiblingEntries];
109
117
  const result = await Bun.build({
110
118
  entrypoints,
111
119
  outdir: outDir,
@@ -25,6 +25,11 @@ export type WatchHandle = {
25
25
  /** Beendet den Watcher. Idempotent — mehrfacher Aufruf ist no-op. */
26
26
  readonly close: () => void;
27
27
  };
28
+ /** Whether a change to `filename` (relative to `src/`, posix or windows
29
+ * separators) can affect codegen output: production .ts/.tsx sources
30
+ * outside the skipped dirs, excluding .d.ts (mostly written by codegen
31
+ * itself) and test files. */
32
+ export declare function isCodegenRelevantChange(filename: string): boolean;
28
33
  /**
29
34
  * Startet den Watcher. Beim Boot fährt einmalig `runCodegen` (sodass
30
35
  * die generated Files sofort frisch sind), dann hängt sich an `fs.watch`
@@ -19,6 +19,20 @@ import { runCodegen } from "./run-codegen.js";
19
19
  import { formatScanWarning } from "./scan-events.js";
20
20
  const SKIP_SUBSTRINGS = ["/node_modules/", "/.kumiko/", "/dist/", "/dist-server/", "/__tests__/"];
21
21
  const DEFAULT_DEBOUNCE_MS = 50;
22
+ /** Whether a change to `filename` (relative to `src/`, posix or windows
23
+ * separators) can affect codegen output: production .ts/.tsx sources
24
+ * outside the skipped dirs, excluding .d.ts (mostly written by codegen
25
+ * itself) and test files. */
26
+ export function isCodegenRelevantChange(filename) {
27
+ const normalised = `/${filename.replace(/\\/g, "/")}`;
28
+ if (SKIP_SUBSTRINGS.some((seg) => normalised.includes(seg)))
29
+ return false;
30
+ if (!normalised.endsWith(".ts") && !normalised.endsWith(".tsx"))
31
+ return false;
32
+ if (normalised.endsWith(".d.ts"))
33
+ return false;
34
+ return !normalised.endsWith(".test.ts") && !normalised.endsWith(".test.tsx");
35
+ }
22
36
  /**
23
37
  * Startet den Watcher. Beim Boot fährt einmalig `runCodegen` (sodass
24
38
  * die generated Files sofort frisch sind), dann hängt sich an `fs.watch`
@@ -65,22 +79,8 @@ export function watchAndRegenerate(opts) {
65
79
  // skip: watcher closed or no filename reported, nothing to act on
66
80
  if (closed || !filename)
67
81
  return;
68
- // node liefert filename relativ zu srcDir, kann aber posix oder
69
- // windows-style separators haben. Wir prüfen substring-tolerant.
70
- const normalised = `/${filename.toString().replace(/\\/g, "/")}`;
71
- // skip: path matches an excluded segment (node_modules/dist/etc.)
72
- if (SKIP_SUBSTRINGS.some((seg) => normalised.includes(seg)))
73
- return;
74
- // skip: Nur .ts/.tsx interessieren — alles andere (CSS, MD, JSON) hat
75
- // keinen Einfluss auf r.defineEvent-Calls.
76
- if (!normalised.endsWith(".ts") && !normalised.endsWith(".tsx"))
77
- return;
78
- // skip: .d.ts ausgenommen — die kommen meistens vom codegen selbst.
79
- if (normalised.endsWith(".d.ts"))
80
- return;
81
- // skip: .test.ts/.test.tsx ausgenommen — Tests definieren keine
82
- // Production-Features.
83
- if (normalised.endsWith(".test.ts") || normalised.endsWith(".test.tsx"))
82
+ // skip: change cannot affect r.defineEvent calls
83
+ if (!isCodegenRelevantChange(filename.toString()))
84
84
  return;
85
85
  if (timer)
86
86
  clearTimeout(timer);
@@ -312,6 +312,7 @@ export async function runDevApp(options) {
312
312
  tierResolverHolder.resolver = await plugin.build({
313
313
  db: stack.db,
314
314
  registry: stack.registry,
315
+ cacheSync: stack.cacheSync,
315
316
  });
316
317
  }
317
318
  if (effectiveAuth && stack.registry.getExtensionUsages(EXT_SESSION_STORE).length > 0) {
@@ -41,11 +41,6 @@ export type ScaffoldDeployDetected = {
41
41
  * `package.json#kumiko.deploy.dbUser`, default = appName. The db name
42
42
  * always stays appName regardless of this value. */
43
43
  readonly dbUser: string;
44
- /** How migrate-step.sh locates the compose `_stack` network — from
45
- * `package.json#kumiko.deploy.stackNetwork`. "discover" (default):
46
- * today's `docker network ls` heuristic. "directory": the exact name
47
- * `$(basename "$PWD")_stack`, checked via `docker network inspect`. */
48
- readonly stackNetwork: "discover" | "directory";
49
44
  };
50
45
  export type ScaffoldedFile = {
51
46
  readonly path: string;
@@ -60,8 +60,6 @@ export function renderDeployFiles(options) {
60
60
  hasPrivateGhPackages: detected.hasPrivateGhPackages,
61
61
  installFromFullTree: detected.installFromFullTree,
62
62
  installFromManifests: !detected.installFromFullTree,
63
- stackNetworkDiscover: detected.stackNetwork === "discover",
64
- stackNetworkDirectory: detected.stackNetwork === "directory",
65
63
  customDbUser: detected.dbUser !== options.appName,
66
64
  };
67
65
  const dir = templatesDir();
@@ -140,7 +138,14 @@ const DB_USER_RE = /^[a-zA-Z0-9_][a-zA-Z0-9_-]{0,62}$/;
140
138
  const kumikoDeployConfigSchema = z
141
139
  .object({
142
140
  dbUser: z.string().regex(DB_USER_RE).optional(),
143
- stackNetwork: z.enum(["discover", "directory"]).optional(),
141
+ // "directory" is the only behaviour left; the key stays valid so existing
142
+ // package.json files keep scaffolding.
143
+ stackNetwork: z
144
+ .string()
145
+ .refine((value) => value === "directory", {
146
+ message: 'the stackNetwork option was removed: migrate-step.sh always uses the exact "<dirname>_stack" network (COMPOSE_PROJECT_NAME or directory name). Delete the option or set it to "directory"',
147
+ })
148
+ .optional(),
144
149
  })
145
150
  .strict();
146
151
  /** `package.json#kumiko.deploy` must be well-formed — silently falling back
@@ -175,7 +180,7 @@ function resolveDeployConfig(deployConfigRaw, appName) {
175
180
  }
176
181
  throw new Error(`scaffoldDeploy: invalid package.json#kumiko.deploy.dbUser — effective value "${dbUser}" (defaulted from appName) does not match ${DB_USER_RE}`);
177
182
  }
178
- return { dbUser, stackNetwork: config.stackNetwork ?? "discover" };
183
+ return { dbUser };
179
184
  }
180
185
  function detectOptionalSurfaces(sourceDir, appName) {
181
186
  const hasSeeds = existsSync(join(sourceDir, "seeds"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-dev-server",
3
- "version": "0.339.0",
3
+ "version": "0.341.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.339.0",
68
- "@cosmicdrift/kumiko-framework": "0.339.0",
69
- "@cosmicdrift/kumiko-headless": "0.339.0",
70
- "@cosmicdrift/kumiko-renderer-web": "0.339.0",
71
- "@cosmicdrift/kumiko-server-runtime": "0.339.0",
67
+ "@cosmicdrift/kumiko-bundled-features": "0.341.0",
68
+ "@cosmicdrift/kumiko-framework": "0.341.0",
69
+ "@cosmicdrift/kumiko-headless": "0.341.0",
70
+ "@cosmicdrift/kumiko-renderer-web": "0.341.0",
71
+ "@cosmicdrift/kumiko-server-runtime": "0.341.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,27 @@
1
1
  [
2
+ {
3
+ "version": "0.341.0",
4
+ "type": "improvement",
5
+ "title": "buildServerBundle bundles bin/bootstrap.ts to dist-server/bootstrap.js when present"
6
+ },
7
+ {
8
+ "version": "0.341.0",
9
+ "type": "fix",
10
+ "title": "Codegen watcher change filter is a tested pure predicate"
11
+ },
12
+ {
13
+ "version": "0.341.0",
14
+ "type": "breaking",
15
+ "title": "Deploy migrate-step.sh always uses the exact stack network",
16
+ "detail": "The discover variant (docker network ls | head -1) could pick another compose project's network on a shared host. The script now uses COMPOSE_PROJECT_NAME or the directory name plus _stack.",
17
+ "migration": "Remove package.json kumiko.deploy.stackNetwork (or set it to \"directory\"), then re-run scaffoldDeploy. If the deploy directory name differs from the compose project, set COMPOSE_PROJECT_NAME for migrate-step.sh."
18
+ },
19
+ {
20
+ "version": "0.340.0",
21
+ "type": "improvement",
22
+ "title": "Server bundle includes an optional worker entry",
23
+ "detail": "When `bin/worker.ts` sits next to `bin/main.ts`, `buildServerBundle` builds it in the same split build as `dist-server/worker.js`. Start a separate worker process from the same image with `exec bun run worker.js`."
24
+ },
2
25
  {
3
26
  "version": "0.338.0",
4
27
  "type": "fix",
@@ -10,29 +10,11 @@
10
10
  # changes BEFORE the app container starts — runProdApp's boot gate would
11
11
  # otherwise abort with SchemaDriftError.
12
12
  #
13
- {{#stackNetworkDiscover}}
14
- # Network discovery: the _stack network is named `<dirname>_stack`
15
- # (compose convention). We discover it via `docker network ls` instead
16
- # of hard-coding.
17
- {{/stackNetworkDiscover}}
18
- {{#stackNetworkDirectory}}
19
13
  # Network: the exact `<dirname>_stack` name of the compose project this
20
- # script runs in (package.json#kumiko.deploy.stackNetwork = "directory").
21
- {{/stackNetworkDirectory}}
14
+ # script runs in — never another project's network on a shared host.
22
15
 
23
16
  set -euo pipefail
24
17
 
25
- {{#stackNetworkDiscover}}
26
- # `|| true` keeps `set -e`/`pipefail` from aborting the script when `grep`
27
- # finds no match (exit 1) — the empty-check below owns that case and prints
28
- # the actionable hint instead of a bare pipefail abort.
29
- STACK_NETWORK=$(docker network ls --format "{{.Name}}" | grep -E "_stack$" | head -1 || true)
30
- if [ -z "$STACK_NETWORK" ]; then
31
- echo "No _stack network found — compose project not running?" >&2
32
- exit 1
33
- fi
34
- {{/stackNetworkDiscover}}
35
- {{#stackNetworkDirectory}}
36
18
  # Compose lowercases the project name and drops characters outside [a-z0-9_-].
37
19
  COMPOSE_PROJECT="${COMPOSE_PROJECT_NAME:-$(basename "$PWD" | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9_-')}"
38
20
  STACK_NETWORK="${COMPOSE_PROJECT}_stack"
@@ -40,7 +22,6 @@ if ! docker network inspect "$STACK_NETWORK" >/dev/null 2>&1; then
40
22
  echo "Stack network '$STACK_NETWORK' not found (derived from COMPOSE_PROJECT_NAME or the directory name '$(basename "$PWD")') — compose project not running?" >&2
41
23
  exit 1
42
24
  fi
43
- {{/stackNetworkDirectory}}
44
25
 
45
26
  # Import .env as bash env. `set -a` marks subsequent variable assignments
46
27
  # as auto-export. Bash's built-in parser respects quotes/escapes like