@cosmicdrift/kumiko-dev-server 0.2.0 → 0.2.2

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/CHANGELOG.md ADDED
@@ -0,0 +1,69 @@
1
+ # @cosmicdrift/kumiko-dev-server
2
+
3
+ ## 0.2.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 7a7da3e: Re-publish 0.2.1 → 0.2.2 mit korrekt aufgelösten cross-package-Versionen.
8
+ 0.2.1 hatte `workspace:*` als Wert in den dependencies (npm publish ohne
9
+ yarn-pack rewrite), Konsumenten bekamen "Workspace not found".
10
+
11
+ publish-with-oidc.sh nutzt jetzt `yarn pack` (rewrited workspace:\*) +
12
+ `npm publish <tarball>` (OIDC + provenance).
13
+
14
+ - Updated dependencies [7a7da3e]
15
+ - @cosmicdrift/kumiko-framework@0.2.2
16
+ - @cosmicdrift/kumiko-bundled-features@0.2.2
17
+
18
+ ## 0.2.1
19
+
20
+ ### Patch Changes
21
+
22
+ - 48b7f6a: CI: switch publish to npm-CLI with OIDC Trusted Publishing + provenance.
23
+ No source changes — verifies the new publish path produces a verified-
24
+ provenance attestation on npmjs.com instead of token-based publish.
25
+ - Updated dependencies [48b7f6a]
26
+ - @cosmicdrift/kumiko-framework@0.2.1
27
+ - @cosmicdrift/kumiko-bundled-features@0.2.1
28
+
29
+ ## 0.2.0
30
+
31
+ ### Minor Changes
32
+
33
+ - 6c70b6f: fix(tenant): seedTenant idempotent gegen Event-Store-Projection-Drift.
34
+
35
+ Verhindert version_conflict beim App-Boot wenn Aggregat existiert aber
36
+ Projection-Row fehlt (rebuild-drift, async-lag, manueller DB-Eingriff).
37
+
38
+ ### Patch Changes
39
+
40
+ - Updated dependencies [6c70b6f]
41
+ - @cosmicdrift/kumiko-framework@0.2.0
42
+ - @cosmicdrift/kumiko-bundled-features@0.2.0
43
+
44
+ ## 0.1.0
45
+
46
+ ### Minor Changes
47
+
48
+ - 59ba6d7: Initial public release of Kumiko — AI-native backend builder.
49
+
50
+ What ships in 0.1.0:
51
+
52
+ - **Engine** (`@cosmicdrift/kumiko-framework`): `defineFeature`, `r.entity`, `r.writeHandler`, `r.queryHandler`, `r.projection`, `r.multiStreamProjection`, `r.hook`, `r.translations`, `r.crud`, `r.referenceData`, `r.screen`, `r.nav`, `r.authClaims`, full lifecycle pipeline with field-level access checks
53
+ - **Pipeline** (`@cosmicdrift/kumiko-framework`): `createDispatcher`, JWT auth via jose, Zod schema validation, role-based access checks, command/write/query split
54
+ - **DB** (`@cosmicdrift/kumiko-framework`): Drizzle helpers (`buildDrizzleTable`, `applyCursorQuery`), CRUD executor, Postgres dialect, optimistic locking, soft delete, multi-tenant scoping
55
+ - **Event sourcing** (`@cosmicdrift/kumiko-framework`): aggregate streams, single + multi-stream projections, event upcasters, asOf queries, archive support, AsyncDaemon-pattern dispatcher
56
+ - **Bundled features** (`@cosmicdrift/kumiko-bundled-features`): auth-email-password, sessions, tenants, users, jobs, secrets, file-provider-s3, mail-transport-smtp/inmemory, billing-foundation, cap-counter, channel-in-app, delivery, feature-toggles, legal-pages
57
+ - **Renderer** (`@cosmicdrift/kumiko-renderer`, `@cosmicdrift/kumiko-renderer-web`): schema-driven CRUD UI for React + Expo Web, override paths, list debounce, theme tokens
58
+ - **Headless** (`@cosmicdrift/kumiko-headless`): view-models for list/edit screens, locale-aware
59
+ - **Dev server** (`@cosmicdrift/kumiko-dev-server`): `runDevApp`, `runProdApp`, `kumiko-build` for production bundles (client + server), Docker-ready
60
+ - **Realtime** (`@cosmicdrift/kumiko-dispatcher-live`): SSE broadcast across tenants, Redis Pub/Sub backend
61
+ - **CLI** (`bin/kumiko.ts`): interactive dev menu, test runners, check pipeline (Biome + TypeScript + 18 guards + Vitest)
62
+
63
+ This is a pre-1.0 release — APIs may change between minor versions. Breaking changes will be documented per release.
64
+
65
+ ### Patch Changes
66
+
67
+ - Updated dependencies [59ba6d7]
68
+ - @cosmicdrift/kumiko-framework@0.1.0
69
+ - @cosmicdrift/kumiko-bundled-features@0.1.0
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-dev-server",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Development server bootstrap for Kumiko apps. Bundles the client, mints dev-JWTs, injects the resolved AppSchema, and seeds an admin. Not for production.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "git+https://github.com/cosmicdriftgamestudio/kumiko-framework.git",
9
+ "url": "git+https://github.com/CosmicDriftGameStudio/kumiko-framework.git",
10
10
  "directory": "packages/dev-server"
11
11
  },
12
12
  "bugs": {
13
- "url": "https://github.com/cosmicdriftgamestudio/kumiko-framework/issues"
13
+ "url": "https://github.com/CosmicDriftGameStudio/kumiko-framework/issues"
14
14
  },
15
15
  "homepage": "https://kumiko.so",
16
16
  "type": "module",
@@ -30,8 +30,8 @@
30
30
  "kumiko-dev": "./bin/kumiko-dev.ts"
31
31
  },
32
32
  "dependencies": {
33
- "@cosmicdrift/kumiko-bundled-features": "workspace:*",
34
- "@cosmicdrift/kumiko-framework": "workspace:*"
33
+ "@cosmicdrift/kumiko-bundled-features": "0.2.2",
34
+ "@cosmicdrift/kumiko-framework": "0.2.2"
35
35
  },
36
36
  "publishConfig": {
37
37
  "registry": "https://registry.npmjs.org",
@@ -42,4 +42,4 @@
42
42
  "README.md",
43
43
  "LICENSE"
44
44
  ]
45
- }
45
+ }
@@ -170,6 +170,14 @@ export type CreateKumikoServerOptions = {
170
170
  * Handler `roles: ["anonymous"]` deklariert. Tenant-Resolution per
171
171
  * Header/Cookie/Default; siehe AnonymousAccessConfig. */
172
172
  readonly anonymousAccess?: TestStackOptions["anonymousAccess"];
173
+ /** Feature-toggle resolver — durchgereicht an setupTestStack. Wenn
174
+ * gesetzt, konsultiert der dispatcher-feature-gate, hook-filter, MSP-
175
+ * filter den callback; absent = alle features always-on. Erforderlich
176
+ * für Tier-Composition (Sprint 8) wo per-Tenant unterschiedliche
177
+ * features aktiv sein sollen. Die typische produktive Implementierung
178
+ * ist `() => globalFeatureToggleRuntime.effectiveFeatures` post-boot
179
+ * (createLateBoundHolder-pattern, weil runtime stack.db braucht). */
180
+ readonly effectiveFeatures?: TestStackOptions["effectiveFeatures"];
173
181
  /** Wird nach dem Aufsetzen der Entity-Tabellen aufgerufen. Hook für
174
182
  * non-entity-tables (unsafePushTables) und Seeding (admin user, initial
175
183
  * tenant, …). Muss idempotent sein — im persistent-DB-Modus läuft
@@ -641,6 +649,9 @@ export async function createKumikoServer(
641
649
  ...(options.auth !== undefined && { authConfig: options.auth }),
642
650
  ...(options.extraContext !== undefined && { extraContext: options.extraContext }),
643
651
  ...(options.anonymousAccess !== undefined && { anonymousAccess: options.anonymousAccess }),
652
+ ...(options.effectiveFeatures !== undefined && {
653
+ effectiveFeatures: options.effectiveFeatures,
654
+ }),
644
655
  });
645
656
  await createEventsTable(stack.db);
646
657
  await pushEntityProjectionTables(stack, stack.registry);
@@ -26,7 +26,14 @@ import {
26
26
  import { TenantQueries } from "@cosmicdrift/kumiko-bundled-features/tenant";
27
27
 
28
28
  import type { SessionMetadata } from "@cosmicdrift/kumiko-framework/api";
29
- import type { FeatureDefinition, SessionUser } from "@cosmicdrift/kumiko-framework/engine";
29
+ import {
30
+ type EffectiveFeaturesResolver,
31
+ type FeatureDefinition,
32
+ findTierResolverUsage,
33
+ type SessionUser,
34
+ type TenantId,
35
+ type TierResolverPlugin,
36
+ } from "@cosmicdrift/kumiko-framework/engine";
30
37
  import type { TestStack } from "@cosmicdrift/kumiko-framework/stack";
31
38
 
32
39
  import { watchAndRegenerate } from "./codegen";
@@ -138,6 +145,13 @@ export type RunDevAppOptions = {
138
145
  * Hono-app gehängt, läuft VOR dem static-asset-Pfad. Symmetrisch zur
139
146
  * gleichnamigen Option in runProdApp. */
140
147
  readonly extraRoutes?: CreateKumikoServerOptions["extraRoutes"];
148
+ /** Feature-toggle resolver — durchgereicht an createKumikoServer →
149
+ * setupTestStack. Sprint-8 Tier-Composition: per-Tenant unterschied-
150
+ * liche features aktiv via globalFeatureToggleRuntime. Pattern in
151
+ * bin/server.ts: createLateBoundHolder + post-boot runtime.initialize
152
+ * in einem seed-fn, weil die runtime stack.db braucht und die seed-
153
+ * Funktionen nach setupTestStack laufen. */
154
+ readonly effectiveFeatures?: CreateKumikoServerOptions["effectiveFeatures"];
141
155
  };
142
156
 
143
157
  export async function runDevApp(options: RunDevAppOptions): Promise<KumikoServerHandle> {
@@ -163,6 +177,33 @@ export async function runDevApp(options: RunDevAppOptions): Promise<KumikoServer
163
177
  ...(composeAuthOptions && { authOptions: composeAuthOptions }),
164
178
  });
165
179
 
180
+ // Sprint-8a Tier-Composition auto-wire: scan features for a
181
+ // tenantTierResolver-extension. If found AND user didn't supply own
182
+ // effectiveFeatures, we wire a late-bound wrapper here and fill it
183
+ // in onAfterSetup (where stack.db + stack.registry are available).
184
+ // App-Author sees nothing — `createTierEngineFeature(opts)` mounts +
185
+ // framework auto-wires.
186
+ const tierResolverUsage = options.effectiveFeatures ? undefined : findTierResolverUsage(features);
187
+ const tierResolverHolder: { resolver: EffectiveFeaturesResolver | undefined } = {
188
+ resolver: undefined,
189
+ };
190
+ const finalEffectiveFeatures: EffectiveFeaturesResolver | undefined =
191
+ options.effectiveFeatures ??
192
+ (tierResolverUsage
193
+ ? (tenantId: TenantId) => {
194
+ // Defensive: Server starts AFTER onAfterSetup completes, so the
195
+ // resolver is filled before any request comes in. Throwing here
196
+ // means a programming error (boot order) rather than silent
197
+ // "all-features-on" misbehavior.
198
+ if (!tierResolverHolder.resolver) {
199
+ throw new Error(
200
+ "tier-resolver: extension found but resolver not yet built — boot order issue?",
201
+ );
202
+ }
203
+ return tierResolverHolder.resolver(tenantId);
204
+ }
205
+ : undefined);
206
+
166
207
  // configResolver-default fürs config-feature — im auth-mode immer
167
208
  // hinzufügen, im no-auth-mode dem Caller überlassen. Factory-form
168
209
  // wird gewrap't damit der spread auf das aufgerufene Result greift,
@@ -216,6 +257,9 @@ export async function runDevApp(options: RunDevAppOptions): Promise<KumikoServer
216
257
  ...(extraContext !== undefined && { extraContext }),
217
258
  ...(options.anonymousAccess !== undefined && { anonymousAccess: options.anonymousAccess }),
218
259
  ...(options.extraRoutes !== undefined && { extraRoutes: options.extraRoutes }),
260
+ ...(finalEffectiveFeatures !== undefined && {
261
+ effectiveFeatures: finalEffectiveFeatures,
262
+ }),
219
263
  ...(options.auth && {
220
264
  auth: {
221
265
  membershipQuery: TenantQueries.memberships,
@@ -261,6 +305,16 @@ export async function runDevApp(options: RunDevAppOptions): Promise<KumikoServer
261
305
  },
262
306
  }),
263
307
  onAfterSetup: async (stack) => {
308
+ // Sprint-8a: build tier-resolver BEFORE any seeds so seeds can rely
309
+ // on the resolver being live (e.g. seed that writes a SystemAdmin's
310
+ // tier-assignment can immediately read tier-cuts).
311
+ if (tierResolverUsage) {
312
+ const plugin = tierResolverUsage.options as TierResolverPlugin;
313
+ tierResolverHolder.resolver = await plugin.build({
314
+ db: stack.db,
315
+ registry: stack.registry,
316
+ });
317
+ }
264
318
  if (options.auth?.sessions !== undefined) {
265
319
  const expiresInMs = options.auth.sessions.expiresInMs;
266
320
  sessionCallbacks = createSessionCallbacks({
@@ -46,7 +46,11 @@ import { createDbConnection } from "@cosmicdrift/kumiko-framework/db";
46
46
  import {
47
47
  buildAppSchema,
48
48
  createRegistry,
49
+ type EffectiveFeaturesResolver,
49
50
  type FeatureDefinition,
51
+ findTierResolverUsage,
52
+ type TenantId,
53
+ type TierResolverPlugin,
50
54
  validateBoot,
51
55
  } from "@cosmicdrift/kumiko-framework/engine";
52
56
  import {
@@ -351,6 +355,12 @@ export type RunProdAppOptions = {
351
355
  * the fetch-handler directly (Bun.serve isn't available under vitest +
352
356
  * node), then call handle.listen() manually if needed. */
353
357
  readonly autoListen?: boolean;
358
+ /** Feature-toggle resolver — durchgereicht an createApiEntrypoint's
359
+ * dispatcherOptions. Sprint-8 Tier-Composition: per-Tenant unterschied-
360
+ * liche features aktiv via globalFeatureToggleRuntime. Pattern:
361
+ * createLateBoundHolder + post-boot runtime.initialize in einem
362
+ * seed-fn (db ist erst nach migrations + features ready). */
363
+ readonly effectiveFeatures?: (tenantId: TenantId) => ReadonlySet<string>;
354
364
  };
355
365
 
356
366
  export type ProdAppHandle = {
@@ -403,6 +413,20 @@ export async function runProdApp(options: RunProdAppOptions): Promise<ProdAppHan
403
413
  validateBoot(features);
404
414
  const registry = createRegistry(features);
405
415
 
416
+ // Sprint-8a Tier-Composition auto-wire: scan features for a
417
+ // tenantTierResolver-extension. If found AND user didn't supply own
418
+ // effectiveFeatures, build the resolver here (db + registry are
419
+ // available) before the dispatcher is constructed. App-Author sees
420
+ // nothing — `createTierEngineFeature(opts)` mounts + framework auto-wires.
421
+ let resolvedEffectiveFeatures: EffectiveFeaturesResolver | undefined = options.effectiveFeatures;
422
+ if (resolvedEffectiveFeatures === undefined) {
423
+ const tierResolverUsage = findTierResolverUsage(features);
424
+ if (tierResolverUsage) {
425
+ const plugin = tierResolverUsage.options as TierResolverPlugin;
426
+ resolvedEffectiveFeatures = await plugin.build({ db, registry });
427
+ }
428
+ }
429
+
406
430
  // 5. Schema-Drift-Gate. Drizzle-kit migrate (yarn kumiko migrate apply)
407
431
  // läuft als CI-Step VOR dem Container-Rollout. Boot prüft hier nur:
408
432
  // (a) Alle Migrations aus drizzle/migrations/meta/_journal.json
@@ -486,7 +510,10 @@ export async function runProdApp(options: RunProdAppOptions): Promise<ProdAppHan
486
510
  jwtSecret,
487
511
  ...(jwtIssuer && { jwtIssuer }),
488
512
  ...(instanceId && { instanceId }),
489
- dispatcherOptions: { idempotency },
513
+ dispatcherOptions: {
514
+ idempotency,
515
+ ...(resolvedEffectiveFeatures && { effectiveFeatures: resolvedEffectiveFeatures }),
516
+ },
490
517
  eventDedup,
491
518
  ...(options.auth && {
492
519
  auth: {