@cosmicdrift/kumiko-dev-server 0.289.0 → 0.291.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-dev-server",
3
- "version": "0.289.0",
3
+ "version": "0.291.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>",
@@ -59,10 +59,10 @@
59
59
  "kumiko-upgrade": "./bin/kumiko-upgrade.ts"
60
60
  },
61
61
  "dependencies": {
62
- "@cosmicdrift/kumiko-bundled-features": "0.289.0",
63
- "@cosmicdrift/kumiko-framework": "0.289.0",
64
- "@cosmicdrift/kumiko-headless": "0.289.0",
65
- "@cosmicdrift/kumiko-server-runtime": "0.289.0",
62
+ "@cosmicdrift/kumiko-bundled-features": "0.291.0",
63
+ "@cosmicdrift/kumiko-framework": "0.291.0",
64
+ "@cosmicdrift/kumiko-headless": "0.291.0",
65
+ "@cosmicdrift/kumiko-server-runtime": "0.291.0",
66
66
  "ts-morph": "^28.0.0"
67
67
  },
68
68
  "publishConfig": {
package/src/changes.json CHANGED
@@ -1,4 +1,10 @@
1
1
  [
2
+ {
3
+ "version": "0.291.0",
4
+ "type": "fix",
5
+ "title": "renderWriteHandlerTypes emits the WriteHandlerQn union in stable order",
6
+ "detail": "`renderWriteHandlerTypes` now sorts `handlerQns` before rendering, like its sibling renderers in the same file. The dev-server passes registration order (`collectWriteHandlerQns`) while the CLI/build path passes manifest order, so the same feature set produced a differently ordered `WriteHandlerQn` union in `.kumiko/define.ts` and `.kumiko/types.generated.d.ts` depending on which one ran last. Consumer apps that commit those generated files no longer get order-only diffs after a local `bun dev`."
7
+ },
2
8
  {
3
9
  "version": "0.289.0",
4
10
  "type": "improvement",
@@ -90,4 +90,11 @@ describe("renderWriteHandlerTypes", () => {
90
90
  expect(out).toContain("export type WriteHandlerQn =");
91
91
  expect(out).toContain('| "tenant:write:create"');
92
92
  });
93
+
94
+ test("output does not depend on input order", () => {
95
+ const out = renderWriteHandlerTypes(["a:write:x", "b:write:y"]);
96
+
97
+ expect(renderWriteHandlerTypes(["b:write:y", "a:write:x"])).toBe(out);
98
+ expect(out.indexOf('| "a:write:x"')).toBeLessThan(out.indexOf('| "b:write:y"'));
99
+ });
93
100
  });
@@ -296,7 +296,9 @@ export function renderDefineFile(handlerQns: readonly string[] = []): string {
296
296
  export function renderWriteHandlerTypes(handlerQns: readonly string[]): string {
297
297
  if (handlerQns.length === 0) return "";
298
298
 
299
- const lines = handlerQns.map((qn) => ` | "${qn}"`);
299
+ // Stable order — callers pass registration order (dev-server) or manifest
300
+ // order (CLI); bare sort keeps both byte-identical.
301
+ const lines = [...handlerQns].sort().map((qn) => ` | "${qn}"`);
300
302
  return ["", WRITE_HANDLER_QN_MARKER, `export type WriteHandlerQn =`, ...lines, ";", ""].join(
301
303
  "\n",
302
304
  );
@@ -45,10 +45,6 @@ import {
45
45
  SESSIONS_FEATURE,
46
46
  } from "@cosmicdrift/kumiko-bundled-features/sessions";
47
47
  import { TenantQueries } from "@cosmicdrift/kumiko-bundled-features/tenant";
48
- import {
49
- resolveTenantLifecycleGate,
50
- TENANT_LIFECYCLE_FEATURE,
51
- } from "@cosmicdrift/kumiko-bundled-features/tenant-lifecycle";
52
48
  import type { SessionMetadata, TokenVerifier } from "@cosmicdrift/kumiko-framework/api";
53
49
  import { createInMemoryLoginRateLimiter } from "@cosmicdrift/kumiko-framework/api";
54
50
  import {
@@ -56,7 +52,6 @@ import {
56
52
  configurePiiSubjectKms,
57
53
  type KmsAdapter,
58
54
  } from "@cosmicdrift/kumiko-framework/crypto";
59
- import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
60
55
  import { configureEntityFieldEncryption } from "@cosmicdrift/kumiko-framework/db";
61
56
  import {
62
57
  collectWriteHandlerQns,
@@ -68,6 +63,7 @@ import {
68
63
  type SessionUser,
69
64
  type TenantId,
70
65
  type TierResolverPlugin,
66
+ type ValidateBootOptions,
71
67
  validateAppCustomScreenWriteQns,
72
68
  validateBoot,
73
69
  } from "@cosmicdrift/kumiko-framework/engine";
@@ -176,6 +172,8 @@ export type RunDevAppOptions = {
176
172
  * auth-email-password automatisch dazu gemischt — KEIN doppeltes
177
173
  * manuelles Hinzufügen nötig. */
178
174
  readonly features: readonly FeatureDefinition[];
175
+ /** Opt-in boot-validator warnings — see ValidateBootOptions. */
176
+ readonly validateBootOptions?: ValidateBootOptions;
179
177
  /** Pfad zum Browser-Entry-Modul. Bun.build bündelt es zu /client.js.
180
178
  * Mutually exclusive mit `clientEntries`. */
181
179
  readonly clientEntry?: string;
@@ -302,7 +300,7 @@ export async function runDevApp(options: RunDevAppOptions): Promise<KumikoServer
302
300
  // CrashLoopBackOff sterben ließ (#359). Wirft synchron, bevor ein
303
301
  // Socket oder Watcher (codegen-Write) aufgeht.
304
302
  try {
305
- validateBoot(features);
303
+ validateBoot(features, options.validateBootOptions);
306
304
  } finally {
307
305
  if (setFileStorageProviderEnv) delete process.env["FILE_STORAGE_PROVIDER"];
308
306
  }
@@ -437,10 +435,8 @@ export async function runDevApp(options: RunDevAppOptions): Promise<KumikoServer
437
435
  // needs the real db+registry (only concrete after setupTestStack). Wired
438
436
  // whenever a provider feature (personal-access-tokens today) is mounted.
439
437
  let tokenVerifier: TokenVerifier | undefined;
440
- let lifecycleDb: DbConnection | undefined;
441
438
  const patFeature = features.find((f) => f.name === PAT_FEATURE);
442
439
  const mfaFeature = features.find((f) => f.name === AUTH_MFA_FEATURE);
443
- const tenantLifecycleFeature = features.find((f) => f.name === TENANT_LIFECYCLE_FEATURE);
444
440
  const patAuthFragment = patFeature
445
441
  ? {
446
442
  tokenVerifier: (rawToken: string) => {
@@ -456,18 +452,6 @@ export async function runDevApp(options: RunDevAppOptions): Promise<KumikoServer
456
452
  }
457
453
  : {};
458
454
 
459
- const tenantLifecycleAuthFragment = tenantLifecycleFeature
460
- ? {
461
- resolveTenantLifecycleStatus: async (tenantId: string) => {
462
- if (!lifecycleDb) {
463
- throw new Error("[runDevApp] tenant-lifecycle gate accessed before onAfterSetup");
464
- }
465
- const gate = await resolveTenantLifecycleGate(lifecycleDb, tenantId);
466
- return gate ? { status: gate.status } : null;
467
- },
468
- }
469
- : {};
470
-
471
455
  // Parity with runProdApp (#1372 review): gate on sessionStore provider, not
472
456
  // the sessions feature name — a custom provider must also wire auth
473
457
  // callbacks. sessionStoreProviderMounted computed above via the registry
@@ -525,7 +509,6 @@ export async function runDevApp(options: RunDevAppOptions): Promise<KumikoServer
525
509
  }),
526
510
  ...sessionAuthFragment,
527
511
  ...patAuthFragment,
528
- ...tenantLifecycleAuthFragment,
529
512
  ...(mfaFeature && {
530
513
  mfaVerifyHandler: AuthMfaHandlers.verify,
531
514
  mfaPreauthEnableStartHandler: AuthMfaHandlers.enableStartPreauth,
@@ -565,7 +548,6 @@ export async function runDevApp(options: RunDevAppOptions): Promise<KumikoServer
565
548
  },
566
549
  }),
567
550
  onAfterSetup: async (stack) => {
568
- lifecycleDb = stack.db;
569
551
  // Sprint-8a: build tier-resolver BEFORE any seeds so seeds can rely
570
552
  // on the resolver being live (e.g. seed that writes a SystemAdmin's
571
553
  // tier-assignment can immediately read tier-cuts).