@cosmicdrift/kumiko-dev-server 0.344.0 → 0.346.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.
@@ -200,6 +200,7 @@ export type KumikoServerHandle = {
200
200
  export declare const STYLESHEET_WATCH_ENV = "KUMIKO_DEV_STYLESHEET_WATCH";
201
201
  export declare const PROD_BUNDLES_ENV = "KUMIKO_DEV_PROD_BUNDLES";
202
202
  export declare function classifyChange(filename: string): "restart" | "hot-reload" | "ignore";
203
+ export declare function classifyWatchedChange(watchedDir: string, filename: string, entrySourceFiles: ReadonlySet<string>): ReturnType<typeof classifyChange>;
203
204
  export declare function resolveStylesheet(options: CreateKumikoServerOptions): string | undefined;
204
205
  export declare function resolveStylesheetWatch(options: Pick<CreateKumikoServerOptions, "stylesheetWatch">, env?: Readonly<Record<string, string | undefined>>): boolean;
205
206
  export declare function createKumikoServer(options: CreateKumikoServerOptions): Promise<KumikoServerHandle>;
@@ -345,6 +345,14 @@ export function classifyChange(filename) {
345
345
  }
346
346
  return "restart";
347
347
  }
348
+ // The watcher reports paths relative to the watched directory, so an entry arrives as a bare
349
+ // "client.tsx" (or a custom name like "client-admin.tsx") that classifyChange alone reads as a
350
+ // server file and answers with a restart.
351
+ export function classifyWatchedChange(watchedDir, filename, entrySourceFiles) {
352
+ return entrySourceFiles.has(resolve(watchedDir, filename))
353
+ ? "hot-reload"
354
+ : classifyChange(filename);
355
+ }
348
356
  // Expandiert watchDirs-Patterns auf konkrete Verzeichnisse. Ein Eintrag
349
357
  // ohne `*` wird als gewöhnlicher Pfad resolved; mit `*` wird er per
350
358
  // glob expanded und alle Treffer die Verzeichnisse sind übernommen.
@@ -683,8 +691,9 @@ export async function createKumikoServer(options) {
683
691
  // RELOAD_SNIPPET oben.
684
692
  const bootId = String(Date.now());
685
693
  const reloadClients = new Set();
686
- const broadcastReload = () => {
687
- const payload = "event: reload\ndata: now\n\n";
694
+ // JSON-encoded so a filename can never break the SSE framing.
695
+ const broadcastReload = (changedFile) => {
696
+ const payload = `event: reload\ndata: ${JSON.stringify(changedFile)}\n\n`;
688
697
  for (const client of reloadClients) {
689
698
  if (client.closed)
690
699
  continue;
@@ -973,10 +982,11 @@ export async function createKumikoServer(options) {
973
982
  const entryDirs = new Set();
974
983
  for (const e of entries)
975
984
  entryDirs.add(resolve(e.sourceFile, ".."));
985
+ const entrySourceFiles = new Set(entries.map((e) => resolve(e.sourceFile)));
976
986
  const dirs = [...entryDirs, ...expandWatchPatterns(options.watchDirs ?? [])];
977
987
  for (const dir of dirs) {
978
988
  void watchDir(dir, async (filename) => {
979
- const action = classifyChange(filename);
989
+ const action = classifyWatchedChange(dir, filename, entrySourceFiles);
980
990
  // skip: file change classified as ignore (test/css/json), nothing to rebuild
981
991
  if (action === "ignore")
982
992
  return;
@@ -998,7 +1008,7 @@ export async function createKumikoServer(options) {
998
1008
  clientBundles.set(e.name, rebuilt);
999
1009
  }
1000
1010
  logInfo(`[kumiko-server] rebuilt on ${filename}, broadcasting reload`);
1001
- broadcastReload();
1011
+ broadcastReload(filename);
1002
1012
  }
1003
1013
  catch {
1004
1014
  // buildClient already logged the failure; keep serving the
@@ -269,6 +269,7 @@ export async function runDevApp(options) {
269
269
  ...patAuthFragment,
270
270
  ...(mfaFeature && {
271
271
  mfaVerifyHandler: AuthMfaHandlers.verify,
272
+ switchTenantMfaGateHandler: AuthHandlers.switchTenantMfaGate,
272
273
  mfaPreauthEnableStartHandler: AuthMfaHandlers.enableStartPreauth,
273
274
  mfaPreauthConfirmHandler: AuthMfaHandlers.enableConfirmPreauth,
274
275
  }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-dev-server",
3
- "version": "0.344.0",
3
+ "version": "0.346.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.344.0",
68
- "@cosmicdrift/kumiko-framework": "0.344.0",
69
- "@cosmicdrift/kumiko-headless": "0.344.0",
70
- "@cosmicdrift/kumiko-renderer-web": "0.344.0",
71
- "@cosmicdrift/kumiko-server-runtime": "0.344.0",
67
+ "@cosmicdrift/kumiko-bundled-features": "0.346.0",
68
+ "@cosmicdrift/kumiko-framework": "0.346.0",
69
+ "@cosmicdrift/kumiko-headless": "0.346.0",
70
+ "@cosmicdrift/kumiko-renderer-web": "0.346.0",
71
+ "@cosmicdrift/kumiko-server-runtime": "0.346.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,16 @@
1
1
  [
2
+ {
3
+ "version": "0.345.0",
4
+ "type": "fix",
5
+ "title": "generated migrate-step.sh honours COMPOSE_PROJECT_NAME from .env",
6
+ "detail": "The `migrate-step.sh` that `kumiko-init-deploy` generates now reads `.env` before it picks the stack network. Before, a `COMPOSE_PROJECT_NAME` set only in `.env` was ignored and the script fell back to the directory name, so on a shared host it could run the migration against another app's network and Postgres. The project name, from `.env` or the directory, is lowercased and stripped to `[a-z0-9_-]` as Compose does, and the script still stops when the network does not exist. Regenerate the script in existing apps to pick this up."
7
+ },
8
+ {
9
+ "version": "0.345.0",
10
+ "type": "fix",
11
+ "title": "Client entry edits hot-reload instead of restarting",
12
+ "detail": "Editing a client entry file hot-reloads instead of restarting the dev server\nOn macOS the recursive file watcher reports paths relative to the watched directory. A change to a client entry such as `client.tsx` or a custom-named entry was therefore classified as a server change and restarted the process. The watcher now resolves the path and treats every configured entry source file as hot-reload."
13
+ },
2
14
  {
3
15
  "version": "0.341.0",
4
16
  "type": "improvement",
@@ -15,14 +15,6 @@
15
15
 
16
16
  set -euo pipefail
17
17
 
18
- # Compose lowercases the project name and drops characters outside [a-z0-9_-].
19
- COMPOSE_PROJECT="${COMPOSE_PROJECT_NAME:-$(basename "$PWD" | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9_-')}"
20
- STACK_NETWORK="${COMPOSE_PROJECT}_stack"
21
- if ! docker network inspect "$STACK_NETWORK" >/dev/null 2>&1; then
22
- echo "Stack network '$STACK_NETWORK' not found (derived from COMPOSE_PROJECT_NAME or the directory name '$(basename "$PWD")') — compose project not running?" >&2
23
- exit 1
24
- fi
25
-
26
18
  # Import .env as bash env. `set -a` marks subsequent variable assignments
27
19
  # as auto-export. Bash's built-in parser respects quotes/escapes like
28
20
  # compose does, without depending on compose-profile features.
@@ -30,6 +22,15 @@ set -a
30
22
  . ./.env
31
23
  set +a
32
24
 
25
+ # After the .env import, so a COMPOSE_PROJECT_NAME set there picks the network.
26
+ # Compose lowercases the project name and drops characters outside [a-z0-9_-].
27
+ COMPOSE_PROJECT="$(printf '%s' "${COMPOSE_PROJECT_NAME:-$(basename "$PWD")}" | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9_-')"
28
+ STACK_NETWORK="${COMPOSE_PROJECT}_stack"
29
+ if ! docker network inspect "$STACK_NETWORK" >/dev/null 2>&1; then
30
+ echo "Stack network '$STACK_NETWORK' not found (derived from COMPOSE_PROJECT_NAME or the directory name '$(basename "$PWD")') — compose project not running?" >&2
31
+ exit 1
32
+ fi
33
+
33
34
  # Percent-encode so '@', ':', '/', '#', '%' in the password cannot change how
34
35
  # the URL is parsed. LC_ALL=C makes the loop walk bytes, not characters;
35
36
  # bash sign-extends bytes >= 0x80 in "'$c", hence the & 255.