@cosmicdrift/kumiko-dev-server 0.400.0 → 0.402.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.
@@ -19,7 +19,7 @@ export type ManagedAppFacts = {
19
19
  /** Ref used in the workflow templates while `kumiko.deploy.infraRef` is unset. */
20
20
  export declare const DEFAULT_INFRA_REF = "main";
21
21
  /** Infra tag a new app is scaffolded with; Renovate keeps it current via the reusables-v* rule. */
22
- export declare const CURRENT_INFRA_REF = "reusables-v1.2.4";
22
+ export declare const CURRENT_INFRA_REF = "reusables-v2.0.0";
23
23
  /** Byte-compared after the marker lines are stripped. */
24
24
  export type ManagedTemplateFile = {
25
25
  readonly kind: "template";
@@ -16,7 +16,7 @@ export const TSCONFIG_PRESET = "@cosmicdrift/kumiko-framework/tsconfig.app.json"
16
16
  /** Ref used in the workflow templates while `kumiko.deploy.infraRef` is unset. */
17
17
  export const DEFAULT_INFRA_REF = "main";
18
18
  /** Infra tag a new app is scaffolded with; Renovate keeps it current via the reusables-v* rule. */
19
- export const CURRENT_INFRA_REF = "reusables-v1.2.4";
19
+ export const CURRENT_INFRA_REF = "reusables-v2.0.0";
20
20
  function templatesDir() {
21
21
  return join(dirname(fileURLToPath(import.meta.url)), "..", "..", "templates", "managed");
22
22
  }
@@ -142,7 +142,7 @@ export async function runDevAfterSetup(stack, ctx) {
142
142
  // Apply r.config({ seeds }) declared by any registered feature.
143
143
  // Runs before user-supplied seed callbacks so those can read /
144
144
  // override the deploy-defaults.
145
- await applyStandardBootSeeds({
145
+ const { adminUserId } = await applyStandardBootSeeds({
146
146
  db: stack.db,
147
147
  registry: stack.registry,
148
148
  admin: effectiveAuth?.admin,
@@ -150,7 +150,11 @@ export async function runDevAfterSetup(stack, ctx) {
150
150
  cipher: bootCrypto.configCipher,
151
151
  processName: "runDevApp",
152
152
  });
153
+ const firstMembership = effectiveAuth?.admin?.memberships[0];
154
+ const admin = adminUserId !== undefined && firstMembership !== undefined
155
+ ? { id: adminUserId, tenantId: firstMembership.tenantId, roles: firstMembership.roles }
156
+ : undefined;
153
157
  for (const seed of config.stackSeeds) {
154
- await seed(stack);
158
+ await seed(stack, { admin });
155
159
  }
156
160
  }
@@ -2,6 +2,7 @@ import type { SeedAdminOptions } from "@cosmicdrift/kumiko-bundled-features/auth
2
2
  import type { PostAuthLandingResolver } from "@cosmicdrift/kumiko-framework/api";
3
3
  import type { KmsAdapter } from "@cosmicdrift/kumiko-framework/crypto";
4
4
  import type { RowLevelSecurityMode } from "@cosmicdrift/kumiko-framework/db";
5
+ import type { SessionUser } from "@cosmicdrift/kumiko-framework/engine";
5
6
  import { type BundledListsOptions, type FeatureDefinition, type Registry, type ValidateBootOptions } from "@cosmicdrift/kumiko-framework/engine";
6
7
  import type { ComposedEnvSchema } from "@cosmicdrift/kumiko-framework/env";
7
8
  import type { ErrorDocsConfig } from "@cosmicdrift/kumiko-framework/errors";
@@ -66,8 +67,12 @@ export type RunDevAppAuthOptions = {
66
67
  readonly postAuthLanding?: PostAuthLandingResolver;
67
68
  };
68
69
  /** Hook for app-specific seeding (demo data, fixtures). Runs after the
69
- * admin (when auth is active) in declared order. */
70
- export type SeedFn = (stack: TestStack) => Promise<void>;
70
+ * admin (when auth is active) in declared order. `context.admin` is the
71
+ * seeded admin as a session user (first membership), undefined without one. */
72
+ export type SeedFn = (stack: TestStack, context: SeedContext) => Promise<void>;
73
+ export type SeedContext = {
74
+ readonly admin?: SessionUser | undefined;
75
+ };
71
76
  /** Dev counterpart of `ProdSeedsConfig`: the declarative shortcuts plus free seeds that get the test stack. */
72
77
  export type RunDevAppSeedsConfig = Omit<ProdSeedsConfig, "run"> & {
73
78
  readonly run?: readonly SeedFn[];
@@ -158,6 +158,7 @@ function renderPackageJson(name, version, testSetup, infraRef) {
158
158
  "@cosmicdrift/kumiko-bundled-features": version,
159
159
  "@cosmicdrift/kumiko-dev-server": version,
160
160
  "@cosmicdrift/kumiko-framework": version,
161
+ "@cosmicdrift/kumiko-locale-de": version,
161
162
  "@cosmicdrift/kumiko-renderer": version,
162
163
  "@cosmicdrift/kumiko-server-runtime": version,
163
164
  react: "^19.2.6",
@@ -258,9 +259,10 @@ function renderRunConfig(features) {
258
259
  }
259
260
  const imports = [
260
261
  ...[...grouped].map(([specifier, names]) => ({ specifier, names })),
262
+ { specifier: "@cosmicdrift/kumiko-locale-de", names: ["localeDe"] },
261
263
  { specifier: "./features/tasks", names: ["tasksFeature"] },
262
264
  ];
263
- const callExprs = [...effective.map((f) => f.callExpression), "tasksFeature"];
265
+ const callExprs = [...effective.map((f) => f.callExpression), "localeDe()", "tasksFeature"];
264
266
  const oneLineFeatures = `export const APP_FEATURES = [${callExprs.join(", ")}] as const;`;
265
267
  const appFeatures = oneLineFeatures.length <= MAX_LINE_WIDTH
266
268
  ? oneLineFeatures
@@ -318,6 +320,7 @@ ${imports}
318
320
 
319
321
  export default defineAppConfig({
320
322
  features: composeFeatures([...APP_FEATURES], { includeBundled: HAS_AUTH }),
323
+ validateBootOptions: { requireFieldValueTranslations: true },
321
324
  client: { entries: ["src/client.tsx"] },
322
325
  ports: { dev: ${SCAFFOLD_DEV_PORT}, e2e: ${SCAFFOLD_E2E_PORT} },
323
326
  });
@@ -439,12 +442,14 @@ ${authBlock}
439
442
  });
440
443
  `;
441
444
  }
442
- // Tiers mirror how Biome wraps the JSX as the name grows.
445
+ // Tiers mirror how Biome wraps the JSX as the name grows. The user spread
446
+ // is part of every tier so the line-width math covers it.
443
447
  function renderDefaultAppShellElement(appName) {
444
448
  const spanOpen = '<span className="font-semibold tracking-tight">';
449
+ const userSpread = "{...(user !== undefined && { user })}";
445
450
  // html-ok: appName is kebab-validated (a-z/0-9/-); this is generated .tsx source, not runtime HTML.
446
451
  const brandInline = `${spanOpen}${appName}</span>`;
447
- const singleLine = ` <DefaultAppShell brand={${brandInline}} schema={schema}>`;
452
+ const singleLine = ` <DefaultAppShell brand={${brandInline}} schema={schema} ${userSpread}>`;
448
453
  if (singleLine.length <= MAX_LINE_WIDTH)
449
454
  return singleLine;
450
455
  const brandAttrInline = ` brand={${brandInline}}`;
@@ -457,14 +462,21 @@ function renderDefaultAppShellElement(appName) {
457
462
  : [` ${spanOpen}`, ` ${appName}`, " </span>"]),
458
463
  " }",
459
464
  ].join("\n")}`;
460
- return [" <DefaultAppShell", brandAttribute, " schema={schema}", " >"].join("\n");
465
+ return [
466
+ " <DefaultAppShell",
467
+ brandAttribute,
468
+ " schema={schema}",
469
+ ` ${userSpread}`,
470
+ " >",
471
+ ].join("\n");
461
472
  }
462
473
  function renderClient(appName) {
463
474
  const imports = renderSortedImports([
464
475
  {
465
476
  specifier: "@cosmicdrift/kumiko-bundled-features/auth-email-password/web",
466
- names: ["emailPasswordClient"],
477
+ names: ["emailPasswordClient", "useShellUser"],
467
478
  },
479
+ { specifier: "@cosmicdrift/kumiko-locale-de/web", names: ["localeDeClient"] },
468
480
  { specifier: "./features/tasks/web", names: ["tasksClient"] },
469
481
  {
470
482
  specifier: "@cosmicdrift/kumiko-renderer/web",
@@ -489,6 +501,7 @@ function renderClient(appName) {
489
501
  ${imports}
490
502
 
491
503
  function AppShell({ children, schema }: { children: ReactNode; schema: AppSchema }): ReactNode {
504
+ const user = useShellUser();
492
505
  return (
493
506
  ${renderDefaultAppShellElement(appName)}
494
507
  {children}
@@ -498,7 +511,7 @@ ${renderDefaultAppShellElement(appName)}
498
511
 
499
512
  createKumikoApp({
500
513
  shell: AppShell,
501
- clientFeatures: [emailPasswordClient(), tasksClient],
514
+ clientFeatures: [localeDeClient(), emailPasswordClient(), tasksClient],
502
515
  });
503
516
  `;
504
517
  }
@@ -212,15 +212,15 @@ export function renderDemoSeedFile() {
212
212
  return `// Demo seed — a few tasks so \`bun dev\` shows a non-empty list.
213
213
 
214
214
  import type { SeedFn } from "@cosmicdrift/kumiko-dev-server";
215
- import { TestUsers } from "@cosmicdrift/kumiko-framework/seeding";
216
215
 
217
216
  const DEMO_TASKS = [
218
217
  { title: "Welcome to Kumiko", status: "todo", priority: 1, isUrgent: false },
219
218
  { title: "Try editing me", status: "in progress", priority: 2, isUrgent: true },
220
219
  ] as const;
221
220
 
222
- export const seedDemoTasks: SeedFn = async (stack) => {
223
- const admin = TestUsers.admin;
221
+ export const seedDemoTasks: SeedFn = async (stack, { admin }) => {
222
+ // skip: no seeded admin (auth off) — nobody to own the demo tasks
223
+ if (admin === undefined) return;
224
224
  const existing = await stack.http.queryOk<{ rows: unknown[] }>(
225
225
  "tasks:query:task:list",
226
226
  {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-dev-server",
3
- "version": "0.400.0",
3
+ "version": "0.402.0",
4
4
  "description": "Dev-tooling for Kumiko apps: local dev-server bootstrap (runDevApp), scaffolding. 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": "MIT",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -77,15 +77,15 @@
77
77
  "kumiko-upgrade": "./bin/kumiko-upgrade.ts"
78
78
  },
79
79
  "dependencies": {
80
- "@cosmicdrift/kumiko-bundled-features": "0.400.0",
81
- "@cosmicdrift/kumiko-feature-ast": "0.400.0",
82
- "@cosmicdrift/kumiko-framework": "0.400.0",
83
- "@cosmicdrift/kumiko-renderer": "0.400.0",
84
- "@cosmicdrift/kumiko-renderer-mail-html": "0.400.0",
85
- "@cosmicdrift/kumiko-guards": "0.400.0",
86
- "@cosmicdrift/kumiko-server-runtime": "0.400.0",
87
- "@cosmicdrift/kumiko-testing": "0.400.0",
88
- "@cosmicdrift/kumiko-types": "0.400.0",
80
+ "@cosmicdrift/kumiko-bundled-features": "0.402.0",
81
+ "@cosmicdrift/kumiko-feature-ast": "0.402.0",
82
+ "@cosmicdrift/kumiko-framework": "0.402.0",
83
+ "@cosmicdrift/kumiko-renderer": "0.402.0",
84
+ "@cosmicdrift/kumiko-renderer-mail-html": "0.402.0",
85
+ "@cosmicdrift/kumiko-guards": "0.402.0",
86
+ "@cosmicdrift/kumiko-server-runtime": "0.402.0",
87
+ "@cosmicdrift/kumiko-testing": "0.402.0",
88
+ "@cosmicdrift/kumiko-types": "0.402.0",
89
89
  "ts-morph": "^28.0.0",
90
90
  "zod": "^4.6.7"
91
91
  },
package/src/changes.json CHANGED
@@ -1,4 +1,16 @@
1
1
  [
2
+ {
3
+ "version": "0.401.0",
4
+ "type": "improvement",
5
+ "title": "Scaffolded apps show the user, speak German and seed demo data as the real admin",
6
+ "detail": "The scaffolded shell gets the signed-in user, the app mounts the German locale, and its kumiko.config.ts turns on requireFieldValueTranslations. A `SeedFn` receives `(stack, { admin })`: the seeded admin as a session user (first membership), undefined without auth. The scaffolded demo seed uses it instead of TestUsers.admin. `applyStandardBootSeeds` returns `{ adminUserId? }`."
7
+ },
8
+ {
9
+ "version": "0.401.0",
10
+ "type": "improvement",
11
+ "title": "New apps start on infra reusables v2.0.0",
12
+ "detail": "The managed ci.yml gives the test job `contents: read`, `packages: read` and `pull-requests: read`, which the v2 reusable test workflow asks for, and kumiko-create writes kumiko.deploy.infraRef reusables-v2.0.0. Existing apps set infraRef to reusables-v2.0.0 and run kumiko sync-managed --write."
13
+ },
2
14
  {
3
15
  "version": "0.395.0",
4
16
  "type": "fix",
@@ -19,6 +19,10 @@ env:
19
19
 
20
20
  jobs:
21
21
  test:
22
+ permissions:
23
+ contents: read
24
+ packages: read
25
+ pull-requests: read
22
26
  uses: cosmicdriftgamestudio/infra/.github/workflows/_app-test.yml@{{infraRef}}
23
27
  with:
24
28
  ui-guards: {{uiGuards}}