@cosmicdrift/kumiko-types 0.265.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 +1 -1
- package/src/handlers.ts +28 -3
- package/src/tenant-db-types.ts +9 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-types",
|
|
3
|
-
"version": "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
|
@@ -16,13 +16,17 @@ import type { TzContext } from "./tz-context";
|
|
|
16
16
|
|
|
17
17
|
// --- Access ---
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
// "tenant-members": signed-in members may write personal data not bound to the caller by an owner rule.
|
|
20
|
+
export type OpenToAllPersonalData = "tenant-members";
|
|
21
|
+
|
|
22
|
+
export type OpenToAllDeclaration = {
|
|
23
|
+
readonly reason: string;
|
|
24
|
+
readonly personalData?: OpenToAllPersonalData;
|
|
25
|
+
};
|
|
20
26
|
|
|
21
27
|
export type OpenToAllAccessRule = {
|
|
22
28
|
// `true` is the deprecated pre-#2855 form, kept until the call-site migration (fw#2854).
|
|
23
29
|
readonly openToAll: OpenToAllDeclaration | true;
|
|
24
|
-
// Write handler intentionally accepts personal data from any authenticated caller (boot-validator gate).
|
|
25
|
-
readonly publicIntake?: true;
|
|
26
30
|
};
|
|
27
31
|
|
|
28
32
|
// AccessRule is DEFAULT-DENY: a handler without an access rule is not reachable.
|
|
@@ -48,6 +52,10 @@ export function isOpenToAllGranted(rule: AccessRule): boolean {
|
|
|
48
52
|
|
|
49
53
|
// --- Pipeline User ---
|
|
50
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
|
+
|
|
51
59
|
export type SessionUser = {
|
|
52
60
|
// UUID-string so user.id threads through the event-store (aggregate-id) and
|
|
53
61
|
// the projection tables (uuid PK) without casts. Auth middleware reads the
|
|
@@ -88,6 +96,7 @@ export type SessionUser = {
|
|
|
88
96
|
readonly scopes: readonly string[];
|
|
89
97
|
readonly allowedQns: readonly string[];
|
|
90
98
|
};
|
|
99
|
+
readonly origin?: SessionUserOrigin;
|
|
91
100
|
};
|
|
92
101
|
|
|
93
102
|
// --- Claim Keys (r.claimKey declarations) ---
|
|
@@ -227,6 +236,9 @@ import type { Registry } from "./feature";
|
|
|
227
236
|
import type { TenantId } from "./identifiers";
|
|
228
237
|
import type { UncheckedSystemDb } from "./tenant-db-types";
|
|
229
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
|
+
|
|
230
242
|
// Minimal interface for job event triggers (framework-owned, concrete type in jobs/)
|
|
231
243
|
export type JobRunnerRef = {
|
|
232
244
|
handleEvent(
|
|
@@ -245,6 +257,9 @@ export type JobRunnerRef = {
|
|
|
245
257
|
export type DispatchWriteRef = {
|
|
246
258
|
readonly write: (user: SessionUser, qn: string, payload: unknown) => Promise<WriteResult>;
|
|
247
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;
|
|
248
263
|
};
|
|
249
264
|
|
|
250
265
|
// Priority levels for notifications
|
|
@@ -351,6 +366,9 @@ type SharedContextFields = {
|
|
|
351
366
|
// hooks synchronously (kumiko-framework#1566). Absent outside a write
|
|
352
367
|
// pipeline — callers fall back to immediate fire (fixture / no-tx paths).
|
|
353
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;
|
|
354
372
|
};
|
|
355
373
|
|
|
356
374
|
// All optional — used at pipeline/system boundaries.
|
|
@@ -636,6 +654,10 @@ export type HandlerContext<TMap extends object = KumikoEventTypeMap> = SharedCon
|
|
|
636
654
|
userId: string,
|
|
637
655
|
tenantId: TenantId,
|
|
638
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;
|
|
639
661
|
};
|
|
640
662
|
|
|
641
663
|
// Job execution: db + registry + systemUser + logging guaranteed, plus a
|
|
@@ -682,6 +704,9 @@ export type JobContext = SharedContextFields & {
|
|
|
682
704
|
readonly write: (qn: string, payload: unknown) => Promise<WriteResult>;
|
|
683
705
|
readonly writeAs: (user: SessionUser, qn: string, payload: unknown) => Promise<WriteResult>;
|
|
684
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;
|
|
685
710
|
// Multi-trigger jobs (`on: [...]`) use this to tell which trigger fired —
|
|
686
711
|
// undefined for cron/manual jobs. Mirrors AppContext.triggerName.
|
|
687
712
|
readonly triggerName?: string;
|
package/src/tenant-db-types.ts
CHANGED
|
@@ -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.
|
|
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>>(
|