@cosmicdrift/kumiko-types 0.327.0 → 0.328.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/dist/action-icon.d.ts +3 -0
- package/dist/action-icon.js +51 -0
- package/{src/agent-exposure.ts → dist/agent-exposure.d.ts} +8 -15
- package/dist/agent-exposure.js +16 -0
- package/dist/concurrency-mode.d.ts +1 -0
- package/dist/config-scope.d.ts +1 -0
- package/dist/config-scope.js +1 -0
- package/dist/config.d.ts +234 -0
- package/dist/config.js +1 -0
- package/dist/cursor-types.d.ts +16 -0
- package/dist/cursor-types.js +1 -0
- package/dist/db-connection.d.ts +14 -0
- package/dist/db-connection.js +1 -0
- package/dist/define-handler.d.ts +58 -0
- package/dist/define-handler.js +1 -0
- package/dist/derivatives-types.d.ts +53 -0
- package/dist/derivatives-types.js +3 -0
- package/dist/entity-cache.d.ts +16 -0
- package/dist/entity-cache.js +1 -0
- package/dist/entity-handlers.d.ts +54 -0
- package/dist/entity-handlers.js +1 -0
- package/dist/entity-table-meta-types.d.ts +44 -0
- package/dist/entity-table-meta-types.js +6 -0
- package/dist/envelope-cipher-types.d.ts +5 -0
- package/dist/envelope-cipher-types.js +1 -0
- package/dist/event-store-executor-types.d.ts +86 -0
- package/dist/event-store-executor-types.js +1 -0
- package/dist/event-store-types.d.ts +37 -0
- package/dist/event-store-types.js +7 -0
- package/dist/event-type-map.d.ts +8 -0
- package/{src/event-type-map.ts → dist/event-type-map.js} +1 -16
- package/dist/executor-brand.d.ts +8 -0
- package/dist/executor-brand.js +1 -0
- package/dist/extension-options-map.d.ts +9 -0
- package/dist/extension-options-map.js +4 -0
- package/dist/feature.d.ts +518 -0
- package/dist/feature.js +1 -0
- package/dist/field-icon.d.ts +1 -0
- package/dist/field-icon.js +1 -0
- package/dist/fields.d.ts +729 -0
- package/dist/fields.js +50 -0
- package/dist/file-handle-types.d.ts +12 -0
- package/dist/file-handle-types.js +1 -0
- package/dist/file-provider-resolver-types.d.ts +3 -0
- package/dist/file-provider-resolver-types.js +1 -0
- package/dist/file-storage-provider-types.d.ts +17 -0
- package/dist/file-storage-provider-types.js +1 -0
- package/dist/geo-tz.d.ts +17 -0
- package/{src/geo-tz.ts → dist/geo-tz.js} +1 -20
- package/dist/handlers.d.ts +493 -0
- package/dist/handlers.js +49 -0
- package/dist/hook-phase.d.ts +1 -0
- package/dist/hook-phase.js +1 -0
- package/dist/hooks.d.ts +75 -0
- package/dist/hooks.js +1 -0
- package/dist/http-route.d.ts +52 -0
- package/dist/http-route.js +13 -0
- package/dist/identifiers.d.ts +8 -0
- package/{src/identifiers.ts → dist/identifiers.js} +7 -24
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/kms-adapter-types.d.ts +68 -0
- package/dist/kms-adapter-types.js +49 -0
- package/dist/logger.d.ts +7 -0
- package/dist/logger.js +1 -0
- package/dist/multi-stream-apply-context-types.d.ts +18 -0
- package/dist/multi-stream-apply-context-types.js +1 -0
- package/dist/nav-icon.d.ts +3 -0
- package/dist/nav-icon.js +100 -0
- package/dist/nav.d.ts +39 -0
- package/dist/nav.js +1 -0
- package/dist/observability/index.d.ts +3 -0
- package/dist/observability/index.js +2 -0
- package/dist/observability/metric.d.ts +34 -0
- package/dist/observability/metric.js +3 -0
- package/dist/observability/provider.d.ts +24 -0
- package/dist/observability/provider.js +4 -0
- package/dist/observability/span.d.ts +32 -0
- package/dist/observability/span.js +4 -0
- package/dist/ownership.d.ts +33 -0
- package/dist/ownership.js +5 -0
- package/dist/projection.d.ts +38 -0
- package/dist/projection.js +1 -0
- package/dist/rate-limit-types.d.ts +19 -0
- package/dist/rate-limit-types.js +1 -0
- package/dist/relations.d.ts +25 -0
- package/dist/relations.js +1 -0
- package/dist/schema-table-types.d.ts +15 -0
- package/{src/schema-table-types.ts → dist/schema-table-types.js} +0 -20
- package/dist/screen.d.ts +1265 -0
- package/dist/screen.js +3 -0
- package/dist/search-adapter.d.ts +32 -0
- package/dist/search-adapter.js +1 -0
- package/dist/secrets-types.d.ts +52 -0
- package/dist/secrets-types.js +30 -0
- package/dist/snapshot-types.d.ts +13 -0
- package/dist/snapshot-types.js +1 -0
- package/dist/step.d.ts +304 -0
- package/dist/step.js +11 -0
- package/dist/target-ref.d.ts +5 -0
- package/{src/target-ref.ts → dist/target-ref.js} +1 -6
- package/dist/tenancy-brand.d.ts +6 -0
- package/dist/tenancy-brand.js +1 -0
- package/dist/tenant-db-types.d.ts +67 -0
- package/dist/tenant-db-types.js +5 -0
- package/dist/tree-node.d.ts +26 -0
- package/dist/tree-node.js +22 -0
- package/dist/tz-context.d.ts +48 -0
- package/dist/tz-context.js +6 -0
- package/dist/websocket-route.d.ts +46 -0
- package/dist/websocket-route.js +10 -0
- package/dist/where-clause-types.d.ts +20 -0
- package/dist/where-clause-types.js +1 -0
- package/dist/workspace.d.ts +10 -0
- package/dist/workspace.js +1 -0
- package/dist/write-error-info-types.d.ts +12 -0
- package/dist/write-error-info-types.js +1 -0
- package/package.json +360 -121
- package/src/changes.json +12 -0
- package/src/__tests__/handlers.test.ts +0 -40
- package/src/__tests__/plural-forms.test.ts +0 -18
- package/src/action-icon.ts +0 -57
- package/src/concurrency-mode.ts +0 -5
- package/src/config-scope.ts +0 -5
- package/src/config.ts +0 -563
- package/src/cursor-types.ts +0 -18
- package/src/db-connection.ts +0 -25
- package/src/define-handler.ts +0 -138
- package/src/derivatives-types.ts +0 -106
- package/src/entity-cache.ts +0 -35
- package/src/entity-handlers.ts +0 -68
- package/src/entity-table-meta-types.ts +0 -101
- package/src/envelope-cipher-types.ts +0 -6
- package/src/event-store-executor-types.ts +0 -163
- package/src/event-store-types.ts +0 -85
- package/src/executor-brand.ts +0 -19
- package/src/extension-options-map.ts +0 -21
- package/src/feature.ts +0 -1141
- package/src/field-icon.ts +0 -23
- package/src/fields.ts +0 -1114
- package/src/file-handle-types.ts +0 -20
- package/src/file-provider-resolver-types.ts +0 -7
- package/src/file-storage-provider-types.ts +0 -54
- package/src/handlers.ts +0 -1246
- package/src/hook-phase.ts +0 -2
- package/src/hooks.ts +0 -170
- package/src/http-route.ts +0 -78
- package/src/kms-adapter-types.ts +0 -128
- package/src/logger.ts +0 -7
- package/src/multi-stream-apply-context-types.ts +0 -52
- package/src/nav-icon.ts +0 -105
- package/src/nav.ts +0 -139
- package/src/observability/index.ts +0 -28
- package/src/observability/metric.ts +0 -56
- package/src/observability/provider.ts +0 -32
- package/src/observability/span.ts +0 -58
- package/src/ownership.ts +0 -83
- package/src/projection.ts +0 -170
- package/src/rate-limit-types.ts +0 -32
- package/src/relations.ts +0 -52
- package/src/screen.ts +0 -1593
- package/src/search-adapter.ts +0 -45
- package/src/secrets-types.ts +0 -182
- package/src/snapshot-types.ts +0 -36
- package/src/step.ts +0 -390
- package/src/tenancy-brand.ts +0 -9
- package/src/tenant-db-types.ts +0 -116
- package/src/tree-node.ts +0 -134
- package/src/tz-context.ts +0 -63
- package/src/websocket-route.ts +0 -68
- package/src/where-clause-types.ts +0 -31
- package/src/workspace.ts +0 -42
- package/src/write-error-info-types.ts +0 -20
- /package/{src/index.ts → dist/concurrency-mode.js} +0 -0
package/src/define-handler.ts
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import type * as z from "zod";
|
|
2
|
-
import type { ZodType } from "zod";
|
|
3
|
-
import type { KumikoEventTypeMap } from "./event-type-map";
|
|
4
|
-
import type {
|
|
5
|
-
AccessRule,
|
|
6
|
-
AgentHandlerHints,
|
|
7
|
-
EscapeHatchDeclaration,
|
|
8
|
-
HandlerContext,
|
|
9
|
-
QueryEvent,
|
|
10
|
-
RateLimitDeclaration,
|
|
11
|
-
WriteEvent,
|
|
12
|
-
WriteResult,
|
|
13
|
-
} from "./handlers";
|
|
14
|
-
import type { PipelineDef } from "./step";
|
|
15
|
-
|
|
16
|
-
// --- Write Handler Definition ---
|
|
17
|
-
//
|
|
18
|
-
// TMap propagates the strict event-type-map through the handler's
|
|
19
|
-
// HandlerContext. CRITICAL: TMap is declared as a generic parameter on the
|
|
20
|
-
// FUNCTION (defineWriteHandler), not just on the type. Generic-functions
|
|
21
|
-
// substitute TMap at the USE-site (the caller's compile context, where
|
|
22
|
-
// the augmentation is visible); generic-type-aliases substitute at the
|
|
23
|
-
// definition-site (framework's compile, where the augmentation isn't
|
|
24
|
-
// visible) and collapse `keyof TMap` to `never`. See the spike-findings
|
|
25
|
-
// memory for the empirical proof.
|
|
26
|
-
//
|
|
27
|
-
// Two authoring forms — `handler` (free-form) or `perform: stepsPipeline(...)`
|
|
28
|
-
// (step-pipeline). A `perform` is compiled to a handler-function at
|
|
29
|
-
// definition time; the dispatcher only ever sees `handler`.
|
|
30
|
-
|
|
31
|
-
export type WriteHandlerDefinition<
|
|
32
|
-
TName extends string = string,
|
|
33
|
-
TSchema extends ZodType = ZodType,
|
|
34
|
-
TData = unknown,
|
|
35
|
-
TMap extends object = KumikoEventTypeMap,
|
|
36
|
-
> = {
|
|
37
|
-
readonly name: TName;
|
|
38
|
-
readonly schema: TSchema;
|
|
39
|
-
readonly access: AccessRule;
|
|
40
|
-
readonly description?: string;
|
|
41
|
-
readonly agent?: AgentHandlerHints;
|
|
42
|
-
readonly unsafeSkipTransitionGuard?: boolean;
|
|
43
|
-
readonly rateLimit?: RateLimitDeclaration;
|
|
44
|
-
readonly escapeHatch?: EscapeHatchDeclaration;
|
|
45
|
-
readonly handler: (
|
|
46
|
-
event: WriteEvent<z.infer<TSchema>>,
|
|
47
|
-
context: HandlerContext<TMap>,
|
|
48
|
-
) => Promise<WriteResult<TData>>;
|
|
49
|
-
// Preserved when the author wrote a `perform` block — the original
|
|
50
|
-
// PipelineDef. Designer/AI/AST tools read this when present; the
|
|
51
|
-
// dispatcher ignores it and just calls `handler`. Absent on free-form
|
|
52
|
-
// handlers.
|
|
53
|
-
readonly perform?: PipelineDef<z.infer<TSchema>, TData>;
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
// Author-facing input — accepts either the free-form `handler` or the
|
|
57
|
-
// pipeline-form `perform`. defineWriteHandler narrows them to the
|
|
58
|
-
// canonical WriteHandlerDefinition shape.
|
|
59
|
-
export type WriteHandlerInput<
|
|
60
|
-
TName extends string = string,
|
|
61
|
-
TSchema extends ZodType = ZodType,
|
|
62
|
-
TData = unknown,
|
|
63
|
-
TMap extends object = KumikoEventTypeMap,
|
|
64
|
-
> = {
|
|
65
|
-
readonly name: TName;
|
|
66
|
-
readonly schema: TSchema;
|
|
67
|
-
readonly access: AccessRule;
|
|
68
|
-
readonly description?: string;
|
|
69
|
-
readonly agent?: AgentHandlerHints;
|
|
70
|
-
readonly unsafeSkipTransitionGuard?: boolean;
|
|
71
|
-
readonly rateLimit?: RateLimitDeclaration;
|
|
72
|
-
readonly escapeHatch?: EscapeHatchDeclaration;
|
|
73
|
-
} & (
|
|
74
|
-
| {
|
|
75
|
-
readonly handler: (
|
|
76
|
-
event: WriteEvent<z.infer<TSchema>>,
|
|
77
|
-
context: HandlerContext<TMap>,
|
|
78
|
-
) => Promise<WriteResult<TData>>;
|
|
79
|
-
readonly perform?: never;
|
|
80
|
-
}
|
|
81
|
-
| {
|
|
82
|
-
readonly perform: PipelineDef<z.infer<TSchema>, TData>;
|
|
83
|
-
readonly handler?: never;
|
|
84
|
-
}
|
|
85
|
-
);
|
|
86
|
-
|
|
87
|
-
// --- Query Handler Definition ---
|
|
88
|
-
|
|
89
|
-
export type QueryHandlerDefinition<
|
|
90
|
-
TName extends string = string,
|
|
91
|
-
TSchema extends ZodType = ZodType,
|
|
92
|
-
TResult = unknown,
|
|
93
|
-
TMap extends object = KumikoEventTypeMap,
|
|
94
|
-
> = {
|
|
95
|
-
readonly name: TName;
|
|
96
|
-
readonly schema: TSchema;
|
|
97
|
-
readonly access: AccessRule;
|
|
98
|
-
readonly description?: string;
|
|
99
|
-
readonly agent?: AgentHandlerHints;
|
|
100
|
-
readonly rateLimit?: RateLimitDeclaration;
|
|
101
|
-
readonly escapeHatch?: EscapeHatchDeclaration;
|
|
102
|
-
readonly handler: (
|
|
103
|
-
query: QueryEvent<z.infer<TSchema>>,
|
|
104
|
-
context: HandlerContext<TMap>,
|
|
105
|
-
) => Promise<TResult>;
|
|
106
|
-
/** Zod schema of `handler`'s actual return value — see QueryHandlerDef's
|
|
107
|
-
* doc (handlers.ts) for the boot-validator checks this unlocks. Not
|
|
108
|
-
* inferred from `TResult`: TResult is a compile-time-only type param
|
|
109
|
-
* (this function never receives a runtime schema for it), so callers
|
|
110
|
-
* that want boot-time column checks declare `outputSchema` explicitly,
|
|
111
|
-
* same as `schema` for the input side. */
|
|
112
|
-
readonly outputSchema?: ZodType;
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
// --- Stream Handler Definition ---
|
|
116
|
-
//
|
|
117
|
-
// Scaffolding only (#1376) — access/rateLimit read by the boot-validator
|
|
118
|
-
// (#1377), dispatch-time consumption (async-generator, SSE) lands in #1378.
|
|
119
|
-
|
|
120
|
-
export type StreamHandlerDefinition<
|
|
121
|
-
TName extends string = string,
|
|
122
|
-
TSchema extends ZodType = ZodType,
|
|
123
|
-
TChunk = unknown,
|
|
124
|
-
TMap extends object = KumikoEventTypeMap,
|
|
125
|
-
> = {
|
|
126
|
-
readonly name: TName;
|
|
127
|
-
readonly schema: TSchema;
|
|
128
|
-
readonly access: AccessRule;
|
|
129
|
-
readonly rateLimit?: RateLimitDeclaration;
|
|
130
|
-
// Stream handlers can't reach db.global() (that gate is write-only), but
|
|
131
|
-
// they can still switch identity to SYSTEM via ctx.queryAs — this opts
|
|
132
|
-
// in, same contract as WriteHandlerDefinition.escapeHatch.
|
|
133
|
-
readonly escapeHatch?: EscapeHatchDeclaration;
|
|
134
|
-
readonly handler: (
|
|
135
|
-
query: QueryEvent<z.infer<TSchema>>,
|
|
136
|
-
context: HandlerContext<TMap>,
|
|
137
|
-
) => AsyncGenerator<TChunk>;
|
|
138
|
-
};
|
package/src/derivatives-types.ts
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
// Derived-file-variants (thumbnails, resized/reformatted images, …) — pure
|
|
2
|
-
// types, no runtime logic. Client-visible package: no `node:*` imports.
|
|
3
|
-
|
|
4
|
-
export type VariantFit = "cover" | "inside" | "contain";
|
|
5
|
-
export type VariantFormat = "webp" | "avif" | "jpeg";
|
|
6
|
-
|
|
7
|
-
// Rectangle in relative coordinates (0…1 of width/height) so it survives a
|
|
8
|
-
// resize. Burning blur into plates/faces needs coordinates that only exist at
|
|
9
|
-
// runtime (detection + user correction), so they ride in the spec instead of a
|
|
10
|
-
// field declaration — the spec hash keys the cache, so corrected regions
|
|
11
|
-
// automatically yield a fresh URL.
|
|
12
|
-
export type BlurRegion = {
|
|
13
|
-
readonly x: number;
|
|
14
|
-
readonly y: number;
|
|
15
|
-
readonly width: number;
|
|
16
|
-
readonly height: number;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export type OverlayGravity = "north-west" | "north-east" | "south-west" | "south-east" | "center";
|
|
20
|
-
|
|
21
|
-
// Placement is relative to the OUTPUT box (after resize), so one declaration
|
|
22
|
-
// covers every aspect ratio the same source is rendered into.
|
|
23
|
-
type OverlayPlacement = {
|
|
24
|
-
// Layer width as a fraction (0…1) of the output width; height follows the
|
|
25
|
-
// layer's own aspect ratio.
|
|
26
|
-
readonly widthPct: number;
|
|
27
|
-
readonly gravity: OverlayGravity;
|
|
28
|
-
// Inset from the edges, fraction of output width. Ignored for "center".
|
|
29
|
-
readonly marginPct?: number;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export type OverlayLayer =
|
|
33
|
-
// `dataToken` is NOT the QR payload — it names a value an
|
|
34
|
-
// EXT_DERIVATIVE_OVERLAY_RESOLVER registration resolves per FileRef. A
|
|
35
|
-
// literal payload is deliberately not expressible: the public variant route
|
|
36
|
-
// is anonymous, so a caller-supplied target would make it an open image
|
|
37
|
-
// generator for arbitrary URLs.
|
|
38
|
-
| ({ readonly kind: "qr"; readonly dataToken: string } & OverlayPlacement)
|
|
39
|
-
// Caller-supplied raster (watermark/badge), base64 in the declaration.
|
|
40
|
-
// Swapping the image changes the spec hash and invalidates every derivative
|
|
41
|
-
// that used it — no extra bookkeeping.
|
|
42
|
-
| ({ readonly kind: "image"; readonly imageBase64: string } & OverlayPlacement);
|
|
43
|
-
|
|
44
|
-
// Renderer-facing counterpart of OverlayLayer once derivatives-context has
|
|
45
|
-
// resolved every `dataToken` — a `qr` layer carries the actual value to
|
|
46
|
-
// encode instead of a name a resolver still has to look up. Keeping this a
|
|
47
|
-
// distinct type (not a value-replacement on OverlayLayer itself) means a
|
|
48
|
-
// renderer's input type structurally cannot hold an unresolved token.
|
|
49
|
-
export type ResolvedOverlayLayer =
|
|
50
|
-
| ({ readonly kind: "qr"; readonly data: string } & OverlayPlacement)
|
|
51
|
-
| Extract<OverlayLayer, { kind: "image" }>;
|
|
52
|
-
|
|
53
|
-
export type VariantSpec = {
|
|
54
|
-
// Default "inside" when omitted (renderer-side default, Schnitt 2).
|
|
55
|
-
readonly fit?: VariantFit;
|
|
56
|
-
readonly size?: { readonly width: number; readonly height: number };
|
|
57
|
-
// Alternative to `size` — longest edge in pixels, aspect preserved.
|
|
58
|
-
readonly maxEdge?: number;
|
|
59
|
-
readonly format?: VariantFormat;
|
|
60
|
-
readonly quality?: number;
|
|
61
|
-
// Whole-image blur radius.
|
|
62
|
-
readonly blur?: number;
|
|
63
|
-
readonly blurRegions?: readonly BlurRegion[];
|
|
64
|
-
// Composited AFTER resize, in array order (last layer on top).
|
|
65
|
-
readonly overlays?: readonly OverlayLayer[];
|
|
66
|
-
// Framework-internal: derivatives-context.ts fills this in from `overlays`
|
|
67
|
-
// once every dataToken is resolved. A renderer reads only this field, so a
|
|
68
|
-
// token can never reach it, even by accident.
|
|
69
|
-
readonly resolvedOverlays?: readonly ResolvedOverlayLayer[];
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
// A renderer turns the original bytes + a spec into the derived bytes for one
|
|
73
|
-
// variant. Registered per MIME-type (exact or `<type>/*` wildcard) via the
|
|
74
|
-
// `derivativeRenderer` extension point — see EXT_DERIVATIVE_RENDERER.
|
|
75
|
-
//
|
|
76
|
-
// The renderer must produce `spec.format` when set, and the source's own
|
|
77
|
-
// format otherwise. It never reports back what it produced: the caller
|
|
78
|
-
// derives the output mimeType from the spec plus the source FileRef's
|
|
79
|
-
// mimeType (see outputMimeType in derivatives-context.ts), because a cache
|
|
80
|
-
// hit has no renderer run to read a mimeType off. When `spec.format` is
|
|
81
|
-
// unset, the source mimeType is client-controlled, so outputMimeType
|
|
82
|
-
// allowlists it against known-safe raster types instead of passing it
|
|
83
|
-
// through verbatim (#2021).
|
|
84
|
-
export type DerivativeRendererPlugin = {
|
|
85
|
-
readonly render: (
|
|
86
|
-
input: Uint8Array,
|
|
87
|
-
spec: VariantSpec,
|
|
88
|
-
sourceMimeType: string,
|
|
89
|
-
) => Promise<Uint8Array>;
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
export type VariantResult = {
|
|
93
|
-
readonly storageKey: string;
|
|
94
|
-
readonly mimeType: string;
|
|
95
|
-
// true = rendered during this call, false = an existing derivative was
|
|
96
|
-
// found and returned unchanged.
|
|
97
|
-
readonly rendered: boolean;
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
// The `ctx.derivatives` service — derive-on-first-use variants of a tracked
|
|
101
|
-
// FileRef. `name` feeds only the readable key-prefix; `spec` determines the
|
|
102
|
-
// content hash, so a spec change always produces a fresh URL instead of
|
|
103
|
-
// silently overwriting what's cached under the old pixels.
|
|
104
|
-
export type DerivativesContext = {
|
|
105
|
-
readonly variant: (fileRefId: string, spec: VariantSpec, name: string) => Promise<VariantResult>;
|
|
106
|
-
};
|
package/src/entity-cache.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { EntityId, TenantId } from "./identifiers";
|
|
2
|
-
|
|
3
|
-
export type EntityCache = {
|
|
4
|
-
/** Get a single cached entity. Returns null on miss. */
|
|
5
|
-
get(
|
|
6
|
-
tenantId: TenantId,
|
|
7
|
-
entityName: string,
|
|
8
|
-
id: EntityId,
|
|
9
|
-
): Promise<Record<string, unknown> | null>;
|
|
10
|
-
|
|
11
|
-
/** Get multiple cached entities. Returns a Map of id → data (misses are absent). */
|
|
12
|
-
mget(
|
|
13
|
-
tenantId: TenantId,
|
|
14
|
-
entityName: string,
|
|
15
|
-
ids: readonly EntityId[],
|
|
16
|
-
): Promise<Map<EntityId, Record<string, unknown>>>;
|
|
17
|
-
|
|
18
|
-
/** Cache a single entity. */
|
|
19
|
-
set(
|
|
20
|
-
tenantId: TenantId,
|
|
21
|
-
entityName: string,
|
|
22
|
-
id: EntityId,
|
|
23
|
-
data: Record<string, unknown>,
|
|
24
|
-
): Promise<void>;
|
|
25
|
-
|
|
26
|
-
/** Cache multiple entities at once. */
|
|
27
|
-
mset(
|
|
28
|
-
tenantId: TenantId,
|
|
29
|
-
entityName: string,
|
|
30
|
-
entries: ReadonlyArray<{ id: EntityId; data: Record<string, unknown> }>,
|
|
31
|
-
): Promise<void>;
|
|
32
|
-
|
|
33
|
-
/** Invalidate a single cached entity. */
|
|
34
|
-
del(tenantId: TenantId, entityName: string, id: EntityId): Promise<void>;
|
|
35
|
-
};
|
package/src/entity-handlers.ts
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import type { EntityDefinition } from "./fields";
|
|
2
|
-
import type {
|
|
3
|
-
AccessRule,
|
|
4
|
-
AgentHandlerHints,
|
|
5
|
-
EscapeHatchDeclaration,
|
|
6
|
-
QueryHandlerDef,
|
|
7
|
-
WriteHandlerDef,
|
|
8
|
-
} from "./handlers";
|
|
9
|
-
|
|
10
|
-
export type EntityHandlerOptions = {
|
|
11
|
-
readonly access: AccessRule;
|
|
12
|
-
readonly description?: string;
|
|
13
|
-
readonly agent?: AgentHandlerHints;
|
|
14
|
-
/** Lifts row filtering for this ONE handler across every tenant instead of
|
|
15
|
-
* the caller's own — for a SystemAdmin-only operator handler over an
|
|
16
|
-
* otherwise tenant-scoped entity. Every use reports an
|
|
17
|
-
* `acknowledge-cross-tenant` escape-hatch audit event. On write handlers
|
|
18
|
-
* update/delete/restore address the target row's own tenant stream.
|
|
19
|
-
* `access` stays the only caller gate. Unlike `escapeHatch` on a
|
|
20
|
-
* hand-written handler this does NOT grant `ctx.db.unsafeRaw`,
|
|
21
|
-
* `db.global()` writes or identity switches. */
|
|
22
|
-
readonly escapeHatch?: EscapeHatchDeclaration;
|
|
23
|
-
/** @deprecated Use `escapeHatch: { reason }` — removed in a future release;
|
|
24
|
-
* run `scripts/codemod/migrate-cross-tenant.ts`. */
|
|
25
|
-
readonly crossTenant?: boolean;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
/** Options for the generic create/update handlers. */
|
|
29
|
-
export type EntityWriteHandlerOptions = EntityHandlerOptions & {
|
|
30
|
-
/** Fields this handler never writes. They leave the payload schema as
|
|
31
|
-
* "must be absent": a payload that still carries one fails validation
|
|
32
|
-
* instead of being stripped silently. create rejects a required field
|
|
33
|
-
* without default here, since the row could never be created. */
|
|
34
|
-
readonly excludeFields?: readonly string[];
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export type EntityQueryHandlerOptions = EntityHandlerOptions;
|
|
38
|
-
|
|
39
|
-
export type EntityCrudVerb = "create" | "update" | "delete" | "restore" | "list" | "detail";
|
|
40
|
-
|
|
41
|
-
// `access` stays optional here — registerEntityCrud resolves it per-verb from `verbAccess`, falling back to this default.
|
|
42
|
-
export type EntityCrudHandlerDefaults = Omit<EntityHandlerOptions, "access"> & {
|
|
43
|
-
readonly access?: AccessRule;
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
export type RegisterEntityCrudOptions = {
|
|
47
|
-
readonly write?: EntityCrudHandlerDefaults;
|
|
48
|
-
readonly read?: EntityCrudHandlerDefaults;
|
|
49
|
-
readonly verbs?: Partial<Record<EntityCrudVerb, boolean>>;
|
|
50
|
-
/** Per-verb access override — falls back to `write.access`/`read.access` when unset for a verb. */
|
|
51
|
-
readonly verbAccess?: Partial<Record<EntityCrudVerb, AccessRule>>;
|
|
52
|
-
/** Per-verb `description` — the author writes one sentence per verb; the AI-agent
|
|
53
|
-
* manifest exposes only the verbs described here (fail-closed, same rule as
|
|
54
|
-
* hand-written handlers). Falls back to `write.description`/`read.description`. */
|
|
55
|
-
readonly descriptions?: Partial<Record<EntityCrudVerb, string>>;
|
|
56
|
-
/** Per-verb `excludeFields` for the generic create/update handlers — see
|
|
57
|
-
* EntityWriteHandlerOptions. */
|
|
58
|
-
readonly excludeFields?: Partial<Record<"create" | "update", readonly string[]>>;
|
|
59
|
-
/** Default true. Set false when the entity was already registered (e.g. before r.relation). */
|
|
60
|
-
readonly registerEntity?: boolean;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
/** Minimal registrar surface — keeps entity-handlers free of define-feature imports. */
|
|
64
|
-
export type EntityCrudRegistrar = {
|
|
65
|
-
entity(name: string, definition: EntityDefinition): unknown;
|
|
66
|
-
writeHandler(def: WriteHandlerDef): unknown;
|
|
67
|
-
queryHandler(def: QueryHandlerDef): unknown;
|
|
68
|
-
};
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
// Plain-data types for EntityTableMeta — split from the runtime
|
|
2
|
-
// (deriveEntityTableMeta, resolveTableName, defineUnmanagedTable) in
|
|
3
|
-
// entity-table-meta.ts. Prep step for the types-only package extraction
|
|
4
|
-
// (#1283) — this file must have ONLY `import type`, no value imports
|
|
5
|
-
// (crypto/DB deps).
|
|
6
|
-
|
|
7
|
-
import type { EntityRelations } from "./relations";
|
|
8
|
-
import type { EntityTenancy } from "./tenancy-brand";
|
|
9
|
-
|
|
10
|
-
// PG type repertoire the read-model tables need. Deliberately narrow — no
|
|
11
|
-
// vendor-specific types (TSVECTOR, HSTORE, etc.). An app-author who needs
|
|
12
|
-
// those reaches into the reviewed SQL migration by hand, not the generator.
|
|
13
|
-
export type PgType =
|
|
14
|
-
| "uuid"
|
|
15
|
-
| "text"
|
|
16
|
-
| "boolean"
|
|
17
|
-
| "integer"
|
|
18
|
-
| "double precision"
|
|
19
|
-
| "bigint"
|
|
20
|
-
| "serial"
|
|
21
|
-
| "bigserial"
|
|
22
|
-
| "jsonb"
|
|
23
|
-
| "timestamptz"
|
|
24
|
-
| "timestamptz(3)"
|
|
25
|
-
// Calendar day, no time-of-day/timezone component — Temporal.PlainDate.
|
|
26
|
-
// Distinct from timestamptz: a `date` field is a pure calendar concept
|
|
27
|
-
// (invoice date, lease term) and must never round-trip through an Instant.
|
|
28
|
-
| "date"
|
|
29
|
-
// Exact decimal — precision/scale are encoded in the type string so the
|
|
30
|
-
// DDL renderer and read-coercion need no side-channel metadata.
|
|
31
|
-
| `numeric(${number},${number})`;
|
|
32
|
-
|
|
33
|
-
export type ColumnMeta = {
|
|
34
|
-
readonly name: string; // snake_case PG column name
|
|
35
|
-
readonly pgType: PgType;
|
|
36
|
-
readonly notNull: boolean;
|
|
37
|
-
// Raw SQL-default-expression (e.g. `now()`, `gen_random_uuid()`,
|
|
38
|
-
// `'[]'::jsonb`). undefined = no DEFAULT clause.
|
|
39
|
-
readonly defaultSql?: string;
|
|
40
|
-
readonly primaryKey?: boolean;
|
|
41
|
-
readonly identity?: boolean;
|
|
42
|
-
// bigint/bigserial only: JS round-trip mode. `number` = createBigIntField /
|
|
43
|
-
// drizzle mode:"number" (safe ≤2^53). `bigint` = money cents, raw unmanaged.
|
|
44
|
-
readonly bigintJsMode?: "number" | "bigint";
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
export type IndexMeta = {
|
|
48
|
-
readonly name: string;
|
|
49
|
-
readonly columns: readonly string[]; // snake_case PG column names
|
|
50
|
-
readonly unique?: boolean;
|
|
51
|
-
// Raw SQL-where-expression for partial indexes. Caller is responsible
|
|
52
|
-
// for safety — emitted verbatim.
|
|
53
|
-
readonly whereSql?: string;
|
|
54
|
-
// Set when the EntityDefinition has a partial index (def.where as a
|
|
55
|
-
// drizzle SQL AST) the generator can't reliably render. The renderer
|
|
56
|
-
// emits the statement COMMENTED OUT with a warning hint — the app-author
|
|
57
|
-
// has to add the WHERE manually in the generated SQL.
|
|
58
|
-
readonly needsManualWhere?: boolean;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
export type CompositePrimaryKeyMeta = {
|
|
62
|
-
readonly name: string;
|
|
63
|
-
readonly columns: readonly string[];
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
export type EntityTableMeta = {
|
|
67
|
-
readonly tableName: string;
|
|
68
|
-
readonly columns: readonly ColumnMeta[];
|
|
69
|
-
readonly indexes: readonly IndexMeta[];
|
|
70
|
-
// For tables with composite PK (no single id column, e.g. snapshots
|
|
71
|
-
// keyed by aggregate_id+version). When set, no column should have
|
|
72
|
-
// primaryKey:true; the constraint is emitted at table-level.
|
|
73
|
-
readonly compositePrimaryKey?: CompositePrimaryKeyMeta;
|
|
74
|
-
// Source hint for diagnostics/tests — not used functionally.
|
|
75
|
-
// "managed" = from EntityDefinition (with base-columns + audit trail).
|
|
76
|
-
// "unmanaged" = via defineUnmanagedTable — no standard audit, the app
|
|
77
|
-
// carries the responsibility. Migration-generator + tooling can use the
|
|
78
|
-
// discriminator to render warnings ("X tables are unmanaged").
|
|
79
|
-
readonly source: "managed" | "unmanaged";
|
|
80
|
-
// PII-subject-annotated field names (pii/userOwned/tenantOwned). Set by
|
|
81
|
-
// deriveEntityTableMeta so the registry can reject r.storeTable stores
|
|
82
|
-
// whose direct writes would skip the executor's encryption (#820).
|
|
83
|
-
readonly piiSubjectFields?: readonly string[];
|
|
84
|
-
// Only present for "global" tables — absent means "tenant" so existing
|
|
85
|
-
// schema snapshots don't drift. See EntityDefinition.tenancy.
|
|
86
|
-
readonly tenancy?: "global";
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
export type BuildEntityTableMetaOptions = {
|
|
90
|
-
readonly featureName?: string;
|
|
91
|
-
readonly relations?: EntityRelations;
|
|
92
|
-
readonly source?: EntityTableMeta["source"];
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
export type UnmanagedTableInput = {
|
|
96
|
-
readonly tableName: string;
|
|
97
|
-
readonly columns: readonly ColumnMeta[];
|
|
98
|
-
readonly indexes?: readonly IndexMeta[];
|
|
99
|
-
readonly compositePrimaryKey?: CompositePrimaryKeyMeta;
|
|
100
|
-
readonly tenancy?: EntityTenancy;
|
|
101
|
-
};
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import type { CursorResult } from "./cursor-types";
|
|
2
|
-
import type { EntityDefinition } from "./fields";
|
|
3
|
-
import type { SessionUser, WriteResult } from "./handlers";
|
|
4
|
-
import type { DeleteContext, SaveContext } from "./hooks";
|
|
5
|
-
import type { EntityId } from "./identifiers";
|
|
6
|
-
import type { SearchAdapter } from "./search-adapter";
|
|
7
|
-
import type { TenantDb } from "./tenant-db-types";
|
|
8
|
-
|
|
9
|
-
// Read-time gate for join-row entities (EntityDefinition.parentRef): the
|
|
10
|
-
// registered-entity map the SQL clause checks host candidates against.
|
|
11
|
-
// Lives here (not in db/parent-ref-clause.ts) because the Registry only
|
|
12
|
-
// exists at request time — the same extension-point shape as
|
|
13
|
-
// referenceSearch/referenceSort below (fw#2660/fw#2741).
|
|
14
|
-
export type ParentVisibilityOption = {
|
|
15
|
-
readonly entities: ReadonlyMap<string, EntityDefinition>;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
// Runs the caller's preSave hooks against changes not yet persisted, for
|
|
19
|
-
// the executor's create()/update() only — restore/delete/forget have no
|
|
20
|
-
// `changes` to shape. See HandlerContext.runPreSave for how this gets bound
|
|
21
|
-
// to a specific handler name + AppContext.
|
|
22
|
-
export type PreSaveRunner = (
|
|
23
|
-
changes: Record<string, unknown>,
|
|
24
|
-
previous: Readonly<Record<string, unknown>>,
|
|
25
|
-
isNew: boolean,
|
|
26
|
-
) => Promise<Record<string, unknown>>;
|
|
27
|
-
|
|
28
|
-
export type EventStoreExecutor = {
|
|
29
|
-
create: (
|
|
30
|
-
payload: Record<string, unknown>,
|
|
31
|
-
user: SessionUser,
|
|
32
|
-
db: TenantDb,
|
|
33
|
-
options?: { preSave?: PreSaveRunner },
|
|
34
|
-
) => Promise<WriteResult<SaveContext>>;
|
|
35
|
-
|
|
36
|
-
update: (
|
|
37
|
-
payload: { id: EntityId; version?: number | undefined; changes: Record<string, unknown> },
|
|
38
|
-
user: SessionUser,
|
|
39
|
-
db: TenantDb,
|
|
40
|
-
options?: {
|
|
41
|
-
skipOptimisticLock?: boolean;
|
|
42
|
-
skipUnchanged?: boolean;
|
|
43
|
-
preSave?: PreSaveRunner;
|
|
44
|
-
// Declarative precondition for a "genau einmal"-transition (kumiko-
|
|
45
|
-
// framework#3024): field/value pairs the row must still hold at write
|
|
46
|
-
// time — a `null` expected value matches a null field. Re-read fresh,
|
|
47
|
-
// atomically with the write's stream version (not the payload's stale
|
|
48
|
-
// `previous`), so a concurrent writer that already moved the row on is
|
|
49
|
-
// caught even when it doesn't collide with the stream-version check.
|
|
50
|
-
// Mismatch fails the whole update with PreconditionFailedError instead
|
|
51
|
-
// of applying it.
|
|
52
|
-
// Scalars only (string/number/boolean/null) — the check is `!==`, so an
|
|
53
|
-
// object/Date/Instant value would compare by reference and silently
|
|
54
|
-
// never match; a timestamp precondition needs its own scalar mirror
|
|
55
|
-
// field to check against, not the compound value itself. Also plain
|
|
56
|
-
// columns only: the check reads raw column values (no decrypt pass),
|
|
57
|
-
// so a pii/encrypted field can't be used here.
|
|
58
|
-
expect?: Readonly<Record<string, string | number | boolean | null>>;
|
|
59
|
-
},
|
|
60
|
-
) => Promise<WriteResult<SaveContext>>;
|
|
61
|
-
|
|
62
|
-
delete: (
|
|
63
|
-
payload: { id: EntityId },
|
|
64
|
-
user: SessionUser,
|
|
65
|
-
db: TenantDb,
|
|
66
|
-
) => Promise<WriteResult<DeleteContext>>;
|
|
67
|
-
|
|
68
|
-
// Hard-purge (Art. 17 erasure). Like delete, but emits `<entity>.forgotten`
|
|
69
|
-
// which hard-deletes the row even for softDelete entities — and, being an
|
|
70
|
-
// auto-verb replayed by the implicit projection, the erasure survives a
|
|
71
|
-
// rebuild (created → forgotten → row gone). Reaches soft-deleted rows too.
|
|
72
|
-
forget: (
|
|
73
|
-
payload: { id: EntityId },
|
|
74
|
-
user: SessionUser,
|
|
75
|
-
db: TenantDb,
|
|
76
|
-
) => Promise<WriteResult<DeleteContext>>;
|
|
77
|
-
|
|
78
|
-
restore: (
|
|
79
|
-
payload: { id: EntityId },
|
|
80
|
-
user: SessionUser,
|
|
81
|
-
db: TenantDb,
|
|
82
|
-
) => Promise<WriteResult<SaveContext>>;
|
|
83
|
-
|
|
84
|
-
list: (
|
|
85
|
-
payload: {
|
|
86
|
-
cursor?: string | undefined;
|
|
87
|
-
limit?: number | undefined;
|
|
88
|
-
search?: string | undefined;
|
|
89
|
-
sort?: string | undefined;
|
|
90
|
-
sortDirection?: "asc" | "desc" | undefined;
|
|
91
|
-
offset?: number | undefined;
|
|
92
|
-
totalCount?: boolean | undefined;
|
|
93
|
-
filter?:
|
|
94
|
-
| {
|
|
95
|
-
readonly field: string;
|
|
96
|
-
readonly op: "eq" | "ne" | "lt" | "gt" | "lte" | "gte" | "in";
|
|
97
|
-
readonly value: unknown;
|
|
98
|
-
}
|
|
99
|
-
| undefined;
|
|
100
|
-
// User-chosen faceted filters (dynamic, additive to the static
|
|
101
|
-
// `filter`). All combined with AND.
|
|
102
|
-
filters?:
|
|
103
|
-
| ReadonlyArray<{
|
|
104
|
-
readonly field: string;
|
|
105
|
-
readonly op: "eq" | "ne" | "lt" | "gt" | "lte" | "gte" | "in";
|
|
106
|
-
readonly value: unknown;
|
|
107
|
-
}>
|
|
108
|
-
| undefined;
|
|
109
|
-
},
|
|
110
|
-
user: SessionUser,
|
|
111
|
-
db: TenantDb,
|
|
112
|
-
/** Tier 2.7e audit fix: per-call SearchAdapter override. When the
|
|
113
|
-
* executor didn't get a SearchAdapter via Options at build time
|
|
114
|
-
* (defaultEntityQueryHandler path), the caller (handler) can pass
|
|
115
|
-
* one from ctx.searchAdapter here at runtime.
|
|
116
|
-
* options.searchAdapter (build-time) wins — the runtime override
|
|
117
|
-
* is the fallback for the default wrapper. */
|
|
118
|
-
runtimeOptions?: {
|
|
119
|
-
readonly searchAdapter?: SearchAdapter;
|
|
120
|
-
// Trash query: skip the implicit `isDeleted = FALSE` filter so soft-
|
|
121
|
-
// deleted rows are returned too. Tenant + ownership clauses still apply
|
|
122
|
-
// — includeDeleted only relaxes the soft-delete predicate, never the
|
|
123
|
-
// visibility ones, so it can ride untrusted query input safely.
|
|
124
|
-
readonly includeDeleted?: boolean;
|
|
125
|
-
// fw#2660 — a text search also matches `searchable: true` reference
|
|
126
|
-
// fields (and the implicit tenantId→tenant.name row-meta reference) by
|
|
127
|
-
// their target row's labelField, not just the raw FK column. Only
|
|
128
|
-
// available at request time (registry access), so it rides the same
|
|
129
|
-
// runtime-override extension point as searchAdapter. `fields` and
|
|
130
|
-
// `resolveEntity` travel together — one without the other silently
|
|
131
|
-
// no-ops, so they're grouped instead of two independent optionals.
|
|
132
|
-
readonly referenceSearch?: {
|
|
133
|
-
readonly fields: ReadonlyArray<{
|
|
134
|
-
readonly fieldName: string;
|
|
135
|
-
readonly targetEntityName: string;
|
|
136
|
-
readonly labelField: string;
|
|
137
|
-
}>;
|
|
138
|
-
readonly resolveEntity: (entityName: string) => EntityDefinition | undefined;
|
|
139
|
-
};
|
|
140
|
-
// fw#2741 — `sortable: true` reference fields order by the target row's
|
|
141
|
-
// labelField instead of the raw FK column. Same request-time registry
|
|
142
|
-
// dependency (and the same fields/resolveEntity pairing) as referenceSearch.
|
|
143
|
-
readonly referenceSort?: {
|
|
144
|
-
readonly fields: ReadonlyArray<{
|
|
145
|
-
readonly fieldName: string;
|
|
146
|
-
readonly targetEntityName: string;
|
|
147
|
-
readonly labelField: string;
|
|
148
|
-
}>;
|
|
149
|
-
readonly resolveEntity: (entityName: string) => EntityDefinition | undefined;
|
|
150
|
-
};
|
|
151
|
-
// Join-row read-gate (EntityDefinition.parentRef) — same request-time
|
|
152
|
-
// registry dependency as referenceSearch/referenceSort above.
|
|
153
|
-
readonly parentVisibility?: ParentVisibilityOption;
|
|
154
|
-
},
|
|
155
|
-
) => Promise<CursorResult<Record<string, unknown>>>;
|
|
156
|
-
|
|
157
|
-
detail: (
|
|
158
|
-
payload: { id: EntityId },
|
|
159
|
-
user: SessionUser,
|
|
160
|
-
db: TenantDb,
|
|
161
|
-
options?: { readonly parentVisibility?: ParentVisibilityOption },
|
|
162
|
-
) => Promise<Record<string, unknown> | null>;
|
|
163
|
-
};
|