@cosmicdrift/kumiko-types 0.266.0 → 0.268.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-types",
3
- "version": "0.266.0",
3
+ "version": "0.268.0",
4
4
  "description": "Framework-Type-Definitions für Kumiko — FeatureDefinition, BootCheck-Types und die reinen Engine-Types. Erlaubt Downstream-Konsumenten, gegen die Type-Contracts zu bauen, ohne das ganze Framework-Package zu importieren. Enthaelt keine identitaets-sensitiven Runtime-Werte mehr (Error-Klassen leben seit #1629 in kumiko-framework, Brand-Symbole nutzen Symbol.for) und ist deshalb eine plain dependency, keine peerDependency.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
package/src/handlers.ts CHANGED
@@ -52,6 +52,10 @@ export function isOpenToAllGranted(rule: AccessRule): boolean {
52
52
 
53
53
  // --- Pipeline User ---
54
54
 
55
+ // Set only on a SessionUser the framework resolved internally for a
56
+ // background read (ctx.queryAsMember) — such a principal never carries `sid`.
57
+ export type SessionUserOrigin = "member-resolution";
58
+
55
59
  export type SessionUser = {
56
60
  // UUID-string so user.id threads through the event-store (aggregate-id) and
57
61
  // the projection tables (uuid PK) without casts. Auth middleware reads the
@@ -92,6 +96,7 @@ export type SessionUser = {
92
96
  readonly scopes: readonly string[];
93
97
  readonly allowedQns: readonly string[];
94
98
  };
99
+ readonly origin?: SessionUserOrigin;
95
100
  };
96
101
 
97
102
  // --- Claim Keys (r.claimKey declarations) ---
@@ -231,6 +236,9 @@ import type { Registry } from "./feature";
231
236
  import type { TenantId } from "./identifiers";
232
237
  import type { UncheckedSystemDb } from "./tenant-db-types";
233
238
 
239
+ // The framework resolves the member internally, so no hand-built SessionUser reaches app code.
240
+ export type MemberReader = (userId: string, qn: string, payload: unknown) => Promise<unknown>;
241
+
234
242
  // Minimal interface for job event triggers (framework-owned, concrete type in jobs/)
235
243
  export type JobRunnerRef = {
236
244
  handleEvent(
@@ -249,6 +257,9 @@ export type JobRunnerRef = {
249
257
  export type DispatchWriteRef = {
250
258
  readonly write: (user: SessionUser, qn: string, payload: unknown) => Promise<WriteResult>;
251
259
  readonly queryAs: (user: SessionUser, qn: string, payload: unknown) => Promise<unknown>;
260
+ // Builds a tenant-scoped MemberReader — one per JobContext.queryAsMember
261
+ // caller (job-runner.ts lazily creates one per job run).
262
+ readonly createMemberReader: (tenantId: TenantId) => MemberReader;
252
263
  };
253
264
 
254
265
  // Priority levels for notifications
@@ -355,6 +366,9 @@ type SharedContextFields = {
355
366
  // hooks synchronously (kumiko-framework#1566). Absent outside a write
356
367
  // pipeline — callers fall back to immediate fire (fixture / no-tx paths).
357
368
  readonly scheduleAfterCommit?: (hook: () => Promise<void>) => void;
369
+ // Present on HandlerContext/JobContext; hooks receive HandlerContext as
370
+ // AppContext, so it's optional here. See HandlerContext.queryAsMember.
371
+ readonly queryAsMember?: MemberReader;
358
372
  };
359
373
 
360
374
  // All optional — used at pipeline/system boundaries.
@@ -640,6 +654,10 @@ export type HandlerContext<TMap extends object = KumikoEventTypeMap> = SharedCon
640
654
  userId: string,
641
655
  tenantId: TenantId,
642
656
  ) => Promise<ActiveMembershipResult>;
657
+
658
+ // Read-only principal without `sid`; needs the same grant as a SYSTEM queryAs
659
+ // (membership is resolved as SYSTEM), cached per handler invocation or job run.
660
+ readonly queryAsMember: MemberReader;
643
661
  };
644
662
 
645
663
  // Job execution: db + registry + systemUser + logging guaranteed, plus a
@@ -686,6 +704,9 @@ export type JobContext = SharedContextFields & {
686
704
  readonly write: (qn: string, payload: unknown) => Promise<WriteResult>;
687
705
  readonly writeAs: (user: SessionUser, qn: string, payload: unknown) => Promise<WriteResult>;
688
706
  readonly queryAs: (user: SessionUser, qn: string, payload: unknown) => Promise<unknown>;
707
+ // Tenant = the job's resolved tenant (may originate from payload.tenantId
708
+ // for tenant-less triggers, see _tenantId below). Ungated, like queryAs.
709
+ readonly queryAsMember: MemberReader;
689
710
  // Multi-trigger jobs (`on: [...]`) use this to tell which trigger fired —
690
711
  // undefined for cron/manual jobs. Mirrors AppContext.triggerName.
691
712
  readonly triggerName?: string;
@@ -57,11 +57,16 @@ export type TenantDb = {
57
57
  * Underlying DbRunner. Framework-internal use (event-store, migrations) —
58
58
  * bypasses tenant-filter. Feature code uses the typed helpers above so the
59
59
  * automatic scoping stays intact.
60
- * @deprecated Use `ctx.systemDb.unsafeRaw(reason)` or `db.global(table)`
61
- * instead — both make the cross-tenant intent an explicit, named
60
+ * @deprecated Use `ctx.db.unsafeRaw(reason)` / `db.global(table)` (method-
61
+ * form) instead — both make the cross-tenant intent an explicit, named
62
62
  * declaration instead of a silent unfiltered escape hatch. Removal fw#2860.
63
63
  */
64
64
  readonly raw: DbRunner;
65
+ /**
66
+ * Unfiltered DbRunner escape hatch for handlers/hooks that declare `escapeHatch: { reason }`.
67
+ * Throws `AccessDeniedError` when ungranted, or `Error` when `reason` is empty.
68
+ */
69
+ unsafeRaw(reason: string): DbRunner;
65
70
  /**
66
71
  * Reach a "global" table with the tenant filter lifted — reads always work; writes
67
72
  * reject unless the write handler declared `escapeHatch: { reason }`. "tenant"-tenancy is a compile error here.
@@ -70,12 +75,12 @@ export type TenantDb = {
70
75
  table: TTable,
71
76
  ): GlobalTableDb<TTable>;
72
77
  selectMany<T = Record<string, unknown>>(
73
- table: SchemaTable,
78
+ table: SchemaTable | EntityTableMeta,
74
79
  where?: WhereObject,
75
80
  options?: SelectOptions,
76
81
  ): Promise<readonly T[]>;
77
82
  fetchOne<T = Record<string, unknown>>(
78
- table: SchemaTable,
83
+ table: SchemaTable | EntityTableMeta,
79
84
  where: WhereObject,
80
85
  ): Promise<T | undefined>;
81
86
  insertOne<T = Record<string, unknown>>(