@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/nav.ts
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import type { AccessRule } from "./handlers";
|
|
2
|
-
import type { NavIconKey } from "./nav-icon";
|
|
3
|
-
import type { TargetRef } from "./target-ref";
|
|
4
|
-
import type { TreeAction } from "./tree-node";
|
|
5
|
-
|
|
6
|
-
export type { IconKey, NavIconKey } from "./nav-icon";
|
|
7
|
-
|
|
8
|
-
// Nav entry declaration. Every feature that wants to appear in the app's
|
|
9
|
-
// navigation tree registers one or more entries via r.nav(). The engine
|
|
10
|
-
// keeps the list flat — ui-core's resolveNavigation assembles the parent/
|
|
11
|
-
// child tree at render time, so changes (toggles, access-gating) don't
|
|
12
|
-
// require re-indexing a tree shape server-side.
|
|
13
|
-
//
|
|
14
|
-
// Cross-feature references are allowed: `screen` may point at any
|
|
15
|
-
// registered screen QN, `parent` at any registered nav QN. The boot
|
|
16
|
-
// validator checks both references exist + rejects parent cycles.
|
|
17
|
-
export type NavDefinition = {
|
|
18
|
-
// Feature author writes the feature-local short id ("catalog"); the
|
|
19
|
-
// registry overwrites `id` with the qualified name ("shop:nav:catalog")
|
|
20
|
-
// in its stored copy. Callers of `registry.getNav(qn)` /
|
|
21
|
-
// `getTopLevelNavs()` / `getNavsByParent(...)` always see the qualified
|
|
22
|
-
// id — no parallel reverse index needed. `feature.navs[shortId]` on the
|
|
23
|
-
// unregistered FeatureDefinition keeps the short form.
|
|
24
|
-
readonly id: string;
|
|
25
|
-
// i18n translation key. Resolved at render time by the renderer's
|
|
26
|
-
// useTranslation hook; engine keeps it opaque.
|
|
27
|
-
readonly label: string;
|
|
28
|
-
// Icon key from the closed NavIconKey vocabulary (see nav-icon.ts). Every
|
|
29
|
-
// renderer's icon map is checked against the same union, so a typo'd key
|
|
30
|
-
// is a compile error here rather than a missing icon at runtime.
|
|
31
|
-
readonly icon?: NavIconKey;
|
|
32
|
-
// Qualified name of a parent nav entry ("<feature>:nav:<id>"). Omit for
|
|
33
|
-
// top-level entries. Boot-validator rejects cycles + dangling refs.
|
|
34
|
-
readonly parent?: string;
|
|
35
|
-
// Sort weight within the parent's children (lower = earlier). Ties are
|
|
36
|
-
// broken by registration order — features registered later appear lower.
|
|
37
|
-
readonly order?: number;
|
|
38
|
-
// Qualified name of the screen this entry navigates to
|
|
39
|
-
// ("<feature>:screen:<id>"). Omit for pure grouping entries (a parent-only
|
|
40
|
-
// nav node that renders a sub-tree but has no target screen itself).
|
|
41
|
-
readonly screen?: string;
|
|
42
|
-
// Polymorphes Klick-Ziel (öffnet die EditorPanel-Maske via Target-
|
|
43
|
-
// Resolver) — Alternative zu `screen`. Ein Knoten trägt screen XOR
|
|
44
|
-
// target; der Renderer dispatcht das target statt einen Route-Link zu
|
|
45
|
-
// rendern. Gespiegelt aus dem alten Visual-Tree (TreeNode.target).
|
|
46
|
-
readonly target?: TargetRef;
|
|
47
|
-
// Hover-Actions rechts in der Zeile (VS-Code-Pattern) — erst bei Hover
|
|
48
|
-
// sichtbar. Reihenfolge wie deklariert.
|
|
49
|
-
readonly actions?: readonly TreeAction[];
|
|
50
|
-
// "+" affordance on the node. Click navigates to createAction.screen or
|
|
51
|
-
// dispatches createAction.target; the provider knows what "create empty"
|
|
52
|
-
// means for it (new page slug, etc.).
|
|
53
|
-
readonly createAction?: TreeAction;
|
|
54
|
-
// Children kommen zur Laufzeit aus einem registrierten nav-provider
|
|
55
|
-
// (lazy beim Ausklappen, SSE-live via treeEntities), keyed auf diese
|
|
56
|
-
// Nav-QN. Macht den Knoten expandable auch ohne statische children.
|
|
57
|
-
readonly provider?: boolean;
|
|
58
|
-
// Role / openToAll gate. The nav resolver hides entries the user can't
|
|
59
|
-
// reach; leave unset to always show (engine stays un-opinionated about
|
|
60
|
-
// who sees what — apps that need default-deny can set { roles: [] }).
|
|
61
|
-
// If `screen` is set and `access` is left unset, the client-side nav
|
|
62
|
-
// builder (buildNavRegistrySliceForApp) fills this in from the target
|
|
63
|
-
// screen's own `access` — a nav entry never invites a role into a 403.
|
|
64
|
-
// An explicit `access` here always wins over the screen's.
|
|
65
|
-
readonly access?: AccessRule;
|
|
66
|
-
// Workspace QNs this entry self-assigns to. Merged at boot with any
|
|
67
|
-
// r.workspace({ nav: [...] }) explicit lists. Omit to leave workspace
|
|
68
|
-
// membership decided solely by the workspace's nav list (or both empty
|
|
69
|
-
// → entry belongs to no workspace).
|
|
70
|
-
readonly workspaces?: readonly string[];
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
// A feature's content collection — a set of template-resources of one `kind`,
|
|
74
|
-
// mounted in the nav next to the feature it belongs to rather than under a
|
|
75
|
-
// central "Content" section. Declared via r.contentCollection(), which
|
|
76
|
-
// registers the nav entry (always `provider: true`, the tree children arrive
|
|
77
|
-
// at runtime) and records the `kind` so the client can build the matching tree
|
|
78
|
-
// provider without the app repeating it.
|
|
79
|
-
//
|
|
80
|
-
// `parent` may point at another feature's nav QN; the boot validator rejects
|
|
81
|
-
// dangling refs, so a collection mounted under a feature that isn't mounted
|
|
82
|
-
// fails boot instead of silently disappearing from the sidebar.
|
|
83
|
-
/** Client editor format for r.contentCollection() — not template body storage formats. */
|
|
84
|
-
export type ContentEditorFormat = "plain" | "rich" | "markdown";
|
|
85
|
-
|
|
86
|
-
export type ContentCollectionDefinition = {
|
|
87
|
-
// Feature-local short id, kebab-case. Also becomes the nav entry's id, so
|
|
88
|
-
// it must not collide with an r.nav()/r.screen() id in the same feature.
|
|
89
|
-
// Handlers take this id, not a kind — a payload can therefore only ever
|
|
90
|
-
// address a declared collection, with the rules that were declared for it.
|
|
91
|
-
readonly id: string;
|
|
92
|
-
// Which template-resource kind this collection lists ("mail-html",
|
|
93
|
-
// "document-pdf", "text-block", ...). The engine keeps it opaque —
|
|
94
|
-
// bundled-features owns the kind vocabulary. Two collections may share a
|
|
95
|
-
// kind and still differ in access and ownership.
|
|
96
|
-
readonly kind: string;
|
|
97
|
-
// Who may read and write this collection's entries. Declared at mount time
|
|
98
|
-
// by the app, because a bundled feature cannot know the host's role
|
|
99
|
-
// vocabulary — same reasoning as the `access` option on tags/folders/ledger.
|
|
100
|
-
// Omitted means the mounting app didn't decide; the feature's own default
|
|
101
|
-
// applies.
|
|
102
|
-
readonly access?: AccessRule;
|
|
103
|
-
// "tenant": one set of entries shared by everyone in the tenant (reply
|
|
104
|
-
// snippets an admin curates). "user": every user keeps their own (mail
|
|
105
|
-
// signatures). Defaults to "tenant".
|
|
106
|
-
readonly ownership?: "tenant" | "user";
|
|
107
|
-
// Which editor the client renders for this collection's entries — not how
|
|
108
|
-
// the content is stored. "rich" still stores HTML, because mail and PDF
|
|
109
|
-
// rendering want HTML either way. "markdown" stores markdown text, not
|
|
110
|
-
// HTML. Defaults to "plain" (textarea).
|
|
111
|
-
readonly contentFormat?: ContentEditorFormat;
|
|
112
|
-
// Fixed variable names the collection's editor offers as insertable chips,
|
|
113
|
-
// mapped to an example value the Preview substitutes in for `{{name}}`
|
|
114
|
-
// (e.g. `{ customerName: "Max Mustermann", orderId: "A-1042" }` for an
|
|
115
|
-
// ai-prompt collection). Declared once per collection, not per entry — a
|
|
116
|
-
// collection-set write always persists an entry's own `variableSchema` as
|
|
117
|
-
// `{}` (collections never let a user redefine the variable set), so this
|
|
118
|
-
// is the only place the client can learn which variables exist and what
|
|
119
|
-
// their preview values are.
|
|
120
|
-
readonly variableSchema?: Readonly<Record<string, string>>;
|
|
121
|
-
readonly nav: {
|
|
122
|
-
readonly label: string;
|
|
123
|
-
readonly icon?: NavIconKey;
|
|
124
|
-
readonly parent?: string;
|
|
125
|
-
readonly order?: number;
|
|
126
|
-
// Visibility of the nav node. Leave unset — it then follows the
|
|
127
|
-
// collection's `access`, so the sidebar never offers a node whose
|
|
128
|
-
// contents the handler will refuse. Set it only to hide the node from
|
|
129
|
-
// someone who may still reach the data another way.
|
|
130
|
-
readonly access?: AccessRule;
|
|
131
|
-
readonly workspaces?: readonly string[];
|
|
132
|
-
// "+" affordance on the node and hover actions on the row — same meaning
|
|
133
|
-
// as on NavDefinition. Without a createAction a collection can only list
|
|
134
|
-
// what already exists; the target is usually the owning feature's
|
|
135
|
-
// r.treeActions create.
|
|
136
|
-
readonly createAction?: TreeAction;
|
|
137
|
-
readonly actions?: readonly TreeAction[];
|
|
138
|
-
};
|
|
139
|
-
};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
// Barrel for observability types. Split into span/metric/provider so each module stays focused.
|
|
2
|
-
|
|
3
|
-
export type {
|
|
4
|
-
Counter,
|
|
5
|
-
Gauge,
|
|
6
|
-
Histogram,
|
|
7
|
-
Meter,
|
|
8
|
-
MetricDefinition,
|
|
9
|
-
MetricLabels,
|
|
10
|
-
MetricsHandle,
|
|
11
|
-
MetricType,
|
|
12
|
-
} from "./metric";
|
|
13
|
-
export type {
|
|
14
|
-
ObservabilityOptions,
|
|
15
|
-
ObservabilityProvider,
|
|
16
|
-
SamplingConfig,
|
|
17
|
-
SensitiveFilterConfig,
|
|
18
|
-
} from "./provider";
|
|
19
|
-
export type {
|
|
20
|
-
SerializedTraceContext,
|
|
21
|
-
Span,
|
|
22
|
-
SpanAttributes,
|
|
23
|
-
SpanAttributeValue,
|
|
24
|
-
SpanKind,
|
|
25
|
-
SpanStatus,
|
|
26
|
-
StartSpanOptions,
|
|
27
|
-
Tracer,
|
|
28
|
-
} from "./span";
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
// Metric + Meter contract. Feature code interacts through ctx.metrics
|
|
2
|
-
// (MetricsHandle); the framework wires Counter/Histogram/Gauge behind that.
|
|
3
|
-
|
|
4
|
-
export type MetricLabels = Record<string, string | number | boolean>;
|
|
5
|
-
|
|
6
|
-
export type MetricType = "counter" | "histogram" | "gauge";
|
|
7
|
-
|
|
8
|
-
export type MetricDefinition = {
|
|
9
|
-
// Fully-qualified name (with kumiko_<feature>_ prefix already applied).
|
|
10
|
-
readonly name: string;
|
|
11
|
-
readonly type: MetricType;
|
|
12
|
-
readonly description?: string;
|
|
13
|
-
// Declared label keys. Inc/observe calls with unknown label keys throw.
|
|
14
|
-
readonly labels?: readonly string[];
|
|
15
|
-
// Buckets only for histogram. If omitted, provider-default is used.
|
|
16
|
-
readonly buckets?: readonly number[];
|
|
17
|
-
readonly unit?: string;
|
|
18
|
-
// If true, the framework auto-injects tenant_id from the active ctx.
|
|
19
|
-
// Default false — adding tenant_id multiplies cardinality by tenant count.
|
|
20
|
-
readonly tenantLabel?: boolean;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
export interface Counter {
|
|
24
|
-
inc(value?: number, labels?: MetricLabels): void;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface Histogram {
|
|
28
|
-
observe(value: number, labels?: MetricLabels): void;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface Gauge {
|
|
32
|
-
set(value: number, labels?: MetricLabels): void;
|
|
33
|
-
inc(value?: number, labels?: MetricLabels): void;
|
|
34
|
-
dec(value?: number, labels?: MetricLabels): void;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface Meter {
|
|
38
|
-
// Called once per metric during boot. Duplicate names throw.
|
|
39
|
-
registerMetric(def: MetricDefinition): void;
|
|
40
|
-
// Lookup by fully-qualified name. Unknown names throw — typed access only.
|
|
41
|
-
counter(name: string): Counter;
|
|
42
|
-
histogram(name: string): Histogram;
|
|
43
|
-
gauge(name: string): Gauge;
|
|
44
|
-
// List of registered definitions — used by ctx.metrics to validate labels.
|
|
45
|
-
definitions(): ReadonlyMap<string, MetricDefinition>;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Public handle for feature code — ctx.metrics.
|
|
49
|
-
// Name resolution uses the fully-qualified name (kumiko_<feature>_<short>).
|
|
50
|
-
// The registrar resolves the short name from the calling feature context
|
|
51
|
-
// at boot time; at handler time the map is ready.
|
|
52
|
-
export interface MetricsHandle {
|
|
53
|
-
inc(name: string, labels?: MetricLabels, value?: number): void;
|
|
54
|
-
observe(name: string, value: number, labels?: MetricLabels): void;
|
|
55
|
-
set(name: string, value: number, labels?: MetricLabels): void;
|
|
56
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
// Observability provider contract — the "plug" that implementations (noop,
|
|
2
|
-
// console, otlp, prometheus) fulfil. Configuration types that consumers
|
|
3
|
-
// (buildServer, setupTestStack) hand in also live here.
|
|
4
|
-
|
|
5
|
-
import type { Meter } from "./metric";
|
|
6
|
-
import type { Tracer } from "./span";
|
|
7
|
-
|
|
8
|
-
export type SamplingConfig = {
|
|
9
|
-
// Base sampling rate 0..1. Default 1 in v1 (sample everything).
|
|
10
|
-
readonly tracing?: number;
|
|
11
|
-
readonly alwaysOnError?: boolean;
|
|
12
|
-
readonly alwaysOnSlow?: { readonly thresholdMs: number };
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export type SensitiveFilterConfig = {
|
|
16
|
-
readonly redactedHeaders: readonly string[];
|
|
17
|
-
readonly redactedQueryParams: readonly string[];
|
|
18
|
-
readonly redactedAttributeKeyPatterns: readonly RegExp[];
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export type ObservabilityOptions = {
|
|
22
|
-
readonly sampling?: SamplingConfig;
|
|
23
|
-
readonly sensitiveFilter?: Partial<SensitiveFilterConfig>;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export interface ObservabilityProvider {
|
|
27
|
-
readonly name: string;
|
|
28
|
-
readonly tracer: Tracer;
|
|
29
|
-
readonly meter: Meter;
|
|
30
|
-
// Graceful flush. Called from framework lifecycle shutdown.
|
|
31
|
-
shutdown(): Promise<void>;
|
|
32
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
// Span + Tracer contract. Provider implementations (noop, recording → console/otlp)
|
|
2
|
-
// all speak this — everything else (middleware, dispatcher, db, redis, jobs)
|
|
3
|
-
// is provider-agnostic.
|
|
4
|
-
|
|
5
|
-
export type SpanAttributeValue = string | number | boolean;
|
|
6
|
-
export type SpanAttributes = Record<string, SpanAttributeValue>;
|
|
7
|
-
|
|
8
|
-
export type SpanStatus = "unset" | "ok" | "error";
|
|
9
|
-
|
|
10
|
-
export type SpanKind = "internal" | "server" | "client" | "producer" | "consumer";
|
|
11
|
-
|
|
12
|
-
// Serialized form of a trace context — what we pass across process boundaries
|
|
13
|
-
// (outbox row, BullMQ job payload). Matches W3C trace-context spec loosely,
|
|
14
|
-
// but staying minimal — a full W3C parser is v2.
|
|
15
|
-
export type SerializedTraceContext = {
|
|
16
|
-
readonly traceId: string;
|
|
17
|
-
readonly spanId: string;
|
|
18
|
-
readonly baggage?: Readonly<Record<string, string>>;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export type StartSpanOptions = {
|
|
22
|
-
// Either a live Span (normal in-process parent) or a serialized trace
|
|
23
|
-
// context (cross-process — outbox row, job payload). Both carry traceId
|
|
24
|
-
// and spanId, so the tracer reads them uniformly. Omitted → fall back to
|
|
25
|
-
// the AsyncLocalStorage active span.
|
|
26
|
-
readonly parent?: Span | SerializedTraceContext;
|
|
27
|
-
readonly attributes?: SpanAttributes;
|
|
28
|
-
readonly kind?: SpanKind;
|
|
29
|
-
readonly startTime?: number;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export interface Span {
|
|
33
|
-
readonly traceId: string;
|
|
34
|
-
readonly spanId: string;
|
|
35
|
-
readonly parentSpanId: string | undefined;
|
|
36
|
-
readonly name: string;
|
|
37
|
-
setAttribute(key: string, value: SpanAttributeValue): void;
|
|
38
|
-
setAttributes(attrs: SpanAttributes): void;
|
|
39
|
-
setStatus(status: SpanStatus, message?: string): void;
|
|
40
|
-
recordException(error: Error): void;
|
|
41
|
-
end(endTime?: number): void;
|
|
42
|
-
// Whether end() has been called. Idempotency guard for auto-wrappers.
|
|
43
|
-
readonly ended: boolean;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface Tracer {
|
|
47
|
-
startSpan(name: string, options?: StartSpanOptions): Span;
|
|
48
|
-
// Runs fn inside the span context (AsyncLocalStorage), ends the span
|
|
49
|
-
// automatically — including on thrown errors, where the error is recorded
|
|
50
|
-
// and status set to "error" before re-throwing.
|
|
51
|
-
withSpan<T>(
|
|
52
|
-
name: string,
|
|
53
|
-
optionsOrFn: StartSpanOptions | ((span: Span) => Promise<T>),
|
|
54
|
-
fn?: (span: Span) => Promise<T>,
|
|
55
|
-
): Promise<T>;
|
|
56
|
-
// Current active span from AsyncLocalStorage, or undefined.
|
|
57
|
-
getActiveSpan(): Span | undefined;
|
|
58
|
-
}
|
package/src/ownership.ts
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
// --- Ownership ---
|
|
2
|
-
// Pure types for the declarative Claims → Access bridge. Runtime (from(),
|
|
3
|
-
// matchesRule(), buildOwnershipClause()) stays in engine/ownership.ts, which
|
|
4
|
-
// re-exports these for backwards compatibility.
|
|
5
|
-
|
|
6
|
-
import type { SessionUser } from "./handlers";
|
|
7
|
-
|
|
8
|
-
// Parameterised SQL fragment — produced by buildOwnershipClause + by the
|
|
9
|
-
// WhereRule escape-hatch. Caller weaves `sqlText` into a larger statement,
|
|
10
|
-
// renumbering placeholders if needed (shiftParams in engine/ownership.ts).
|
|
11
|
-
export type SqlFragment = {
|
|
12
|
-
readonly sqlText: string;
|
|
13
|
-
readonly params: readonly unknown[];
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
// Reference spec supported by `from()`:
|
|
17
|
-
// "user:id" → user.id
|
|
18
|
-
// "user:tenantId" → user.tenantId (rarely needed — TenantDb scopes anyway)
|
|
19
|
-
// "claim:<featureName>:<key>" → user.claims["<featureName>:<key>"]
|
|
20
|
-
//
|
|
21
|
-
// The string form is keyed so the framework can look up the referenced
|
|
22
|
-
// Registry entry at boot (Claim-QN exists? Column type compatible?). A typed
|
|
23
|
-
// object form would force features to import each other's handles — the
|
|
24
|
-
// whole point of H.2's unified path is string-based references, no imports.
|
|
25
|
-
export type OwnershipRef = string;
|
|
26
|
-
|
|
27
|
-
// Resolved during `from()` — the parser eagerly splits the prefix so the
|
|
28
|
-
// runtime evaluator avoids string-parsing on every row. `kind` drives the
|
|
29
|
-
// evaluator branch; the rest is the resolved metadata.
|
|
30
|
-
export type FromRuleKind = "user" | "claim";
|
|
31
|
-
|
|
32
|
-
export type FromRule = {
|
|
33
|
-
readonly kind: "from";
|
|
34
|
-
readonly refKind: FromRuleKind;
|
|
35
|
-
// For "user:id" → "id"; for "user:tenantId" → "tenantId".
|
|
36
|
-
// For "claim:<featureName>:<key>" → "<featureName>:<key>" (the full QN,
|
|
37
|
-
// which is exactly the key under which the JWT stores the value).
|
|
38
|
-
readonly refPath: string;
|
|
39
|
-
// Row-column to match against. For claim rules defaults to the claim's
|
|
40
|
-
// shortName (second segment of the claim QN). For user-rules the column
|
|
41
|
-
// is always explicit.
|
|
42
|
-
readonly column: string;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
// Context passed to a WhereRule escape-hatch. The author returns a SqlFragment
|
|
46
|
-
// whose placeholders start at `paramStart` ($N, $N+1, ...); the framework
|
|
47
|
-
// concatenates the fragment into the larger query.
|
|
48
|
-
export type WhereRuleContext<TTable = unknown> = {
|
|
49
|
-
readonly table: TTable;
|
|
50
|
-
readonly tableName: string;
|
|
51
|
-
readonly paramStart: number;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export type WhereRule<TTable = unknown> = {
|
|
55
|
-
readonly kind: "where";
|
|
56
|
-
readonly where: (user: SessionUser, ctx: WhereRuleContext<TTable>) => SqlFragment;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
// "all" collapses to a primitive so map authors can write `Admin: "all"`
|
|
60
|
-
// without importing a helper.
|
|
61
|
-
export type OwnershipRule = "all" | FromRule | WhereRule;
|
|
62
|
-
|
|
63
|
-
// Per-role map: every key is a role name, value is the rule that role
|
|
64
|
-
// satisfies to pass the access check.
|
|
65
|
-
export type OwnershipMap = Readonly<Record<string, OwnershipRule>>;
|
|
66
|
-
|
|
67
|
-
// Result of buildOwnershipClause. The discriminant lets the caller handle
|
|
68
|
-
// the three outcomes without inspecting SQL internals:
|
|
69
|
-
//
|
|
70
|
-
// "pass" → user is unrestricted. Run the query as-is.
|
|
71
|
-
// "empty" → user has a role mapped but no rule accepts any row (missing
|
|
72
|
-
// claim, empty array, role not in map). Skip the DB call entirely
|
|
73
|
-
// — returning [] is equivalent and avoids a pointless roundtrip.
|
|
74
|
-
// "sql" → apply the parameterised fragment as an AND on the query.
|
|
75
|
-
// Caller is responsible for renumbering placeholders when
|
|
76
|
-
// concatenating with other fragments (see `shiftParams`).
|
|
77
|
-
//
|
|
78
|
-
// "empty" vs. "pass" is the critical distinction for a safe default:
|
|
79
|
-
// undefined/pass = allow, empty = deny-by-construction.
|
|
80
|
-
export type OwnershipClause =
|
|
81
|
-
| { readonly kind: "pass" }
|
|
82
|
-
| { readonly kind: "empty" }
|
|
83
|
-
| { readonly kind: "sql"; readonly sqlText: string; readonly params: readonly unknown[] };
|
package/src/projection.ts
DELETED
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import type { RunIn } from "./config";
|
|
2
|
-
import type { DbRunner } from "./db-connection";
|
|
3
|
-
import type { StoredEvent } from "./event-store-types";
|
|
4
|
-
import type { EntityDefinition } from "./fields";
|
|
5
|
-
import type { MultiStreamApplyContext } from "./multi-stream-apply-context-types";
|
|
6
|
-
import type { SchemaTable } from "./schema-table-types";
|
|
7
|
-
|
|
8
|
-
// Drizzle pgTable shape — projections hand their table through to apply() so
|
|
9
|
-
// user code writes upserts/updates directly instead of going through a
|
|
10
|
-
// framework-managed state reducer. Using the native dialect's `SchemaTable`
|
|
11
|
-
// (drizzle-compat surface) keeps typing honest: typed paths work inside
|
|
12
|
-
// apply(), but the column union is erased so framework code doesn't need
|
|
13
|
-
// to know the schema shape of every user table.
|
|
14
|
-
export type ProjectionTable = SchemaTable;
|
|
15
|
-
|
|
16
|
-
// Single-stream projection apply: runs inline in the write-TX of the event
|
|
17
|
-
// it projects. Gets the event, the TX-scoped DbRunner, and the projection's
|
|
18
|
-
// own `table` (already erased to ProjectionTable). Write through THAT table —
|
|
19
|
-
// it is the only ES-blessed write into a managed projection outside the
|
|
20
|
-
// executor, and it is reachable only here (an arbitrary handler has no such
|
|
21
|
-
// arg), so the write-brand cannot be bypassed by closing over the branded
|
|
22
|
-
// table constant. Inline projections must not spawn further events (no ctx)
|
|
23
|
-
// because they run inside the command's transaction and the framework
|
|
24
|
-
// guarantees a single commit boundary per command.
|
|
25
|
-
//
|
|
26
|
-
// Generic über payload-shape. Default = Record<string, unknown> behält
|
|
27
|
-
// rückwärtskompatibles Verhalten; Konkrete Apply-Handler annotieren
|
|
28
|
-
// `SingleStreamApplyFn<MyPayload>` für typed event.payload-Access. Der
|
|
29
|
-
// `table`-Param ist additiv — 2-arg-Applies (event, tx) bleiben gültig.
|
|
30
|
-
export type SingleStreamApplyFn<TPayload = Record<string, unknown>> = (
|
|
31
|
-
event: StoredEvent<TPayload>,
|
|
32
|
-
tx: DbRunner,
|
|
33
|
-
table: ProjectionTable,
|
|
34
|
-
) => Promise<void>;
|
|
35
|
-
|
|
36
|
-
// Multi-stream projection apply: runs asynchronously via the event-dispatcher
|
|
37
|
-
// with its own cursor. Gets the event, tx, and a ctx surface for emitting
|
|
38
|
-
// follow-up events (saga / process-manager pattern). ctx.appendEvent +
|
|
39
|
-
// ctx.loadAggregate are the Marten-equivalent of IProjectionSession — write
|
|
40
|
-
// cross-aggregate reactions here, not in single-stream projections.
|
|
41
|
-
export type MultiStreamApplyFn<TPayload = Record<string, unknown>> = (
|
|
42
|
-
event: StoredEvent<TPayload>,
|
|
43
|
-
tx: DbRunner,
|
|
44
|
-
ctx: MultiStreamApplyContext,
|
|
45
|
-
) => Promise<void>;
|
|
46
|
-
|
|
47
|
-
export type ProjectionDefinition = {
|
|
48
|
-
readonly name: string;
|
|
49
|
-
// One or more entity names whose events feed this projection. Event-types
|
|
50
|
-
// are matched in `apply` (e.g. "unit.created") — `source` is only used to
|
|
51
|
-
// index projections so the executor doesn't scan all projections on every
|
|
52
|
-
// write.
|
|
53
|
-
readonly source: string | readonly string[];
|
|
54
|
-
// Additional aggregate-types whose events the rebuild replay must include
|
|
55
|
-
// beyond `source`. Fed by r.extendEntityProjection — an extension can react
|
|
56
|
-
// to events on foreign streams (e.g. "field-definition") while `source`
|
|
57
|
-
// keeps meaning "the owning entity" for consumers like soft-delete-cleanup.
|
|
58
|
-
readonly extraSources?: readonly string[];
|
|
59
|
-
// Drizzle-table the projection materializes into. User owns the schema —
|
|
60
|
-
// framework just guarantees the TX and event delivery.
|
|
61
|
-
readonly table: ProjectionTable;
|
|
62
|
-
// Optional: the EntityDefinition the table was built from, for projections
|
|
63
|
-
// without an r.entity registration — lets boot-time GDPR guards see
|
|
64
|
-
// pii/tenantOwned fields that feature.entities (r.entity-only) would miss.
|
|
65
|
-
readonly entity?: EntityDefinition;
|
|
66
|
-
// Keyed by fully-qualified event type ("<aggregate>.<verb>", e.g. "unit.created").
|
|
67
|
-
// Missing keys are silently skipped — a projection declares only the events it
|
|
68
|
-
// cares about.
|
|
69
|
-
readonly apply: Readonly<Record<string, SingleStreamApplyFn>>;
|
|
70
|
-
// Auto-registered projection (one per r.entity) that exists ONLY to
|
|
71
|
-
// make rebuildProjection work for entity-tables. Live writes go through
|
|
72
|
-
// the EventStoreExecutor directly — firing the implicit apply inline
|
|
73
|
-
// would double-write into the same table. The inline-projection-runner
|
|
74
|
-
// skips entries with this flag; rebuildProjection treats them
|
|
75
|
-
// identically to explicit projections.
|
|
76
|
-
readonly isImplicit?: boolean;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
// Extension merged into an entity's implicit projection at registry build.
|
|
80
|
-
// Lets a bundled feature that writes into the HOST entity's table via events
|
|
81
|
-
// (custom-fields pattern) hook those event types into the entity's rebuild
|
|
82
|
-
// replay — without it, a rebuild resets everything the extension wrote.
|
|
83
|
-
// Live delivery stays with the extension's own MSP: implicit projections are
|
|
84
|
-
// skipped by the inline runner, so the apply here runs ONLY during rebuild.
|
|
85
|
-
export type EntityProjectionExtension = {
|
|
86
|
-
// Aggregate-types beyond the entity's own stream whose events the rebuild
|
|
87
|
-
// must scan (e.g. "field-definition"). Omit when all extension events are
|
|
88
|
-
// appended on the host entity's stream.
|
|
89
|
-
readonly sources?: readonly string[];
|
|
90
|
-
// Keyed by fully-qualified event type. Must not collide with the entity's
|
|
91
|
-
// built-in lifecycle applies (<entity>.created/updated/...) or another
|
|
92
|
-
// extension — collisions fail at boot.
|
|
93
|
-
readonly apply: Readonly<Record<string, SingleStreamApplyFn>>;
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
// Per-lifecycle error policy for a MultiStreamProjection. Mirrors Marten's
|
|
97
|
-
// Projections.Errors / Projections.RebuildErrors split — a projection can
|
|
98
|
-
// be lenient during steady-state delivery but strict during rebuild (or
|
|
99
|
-
// vice versa).
|
|
100
|
-
export type MspErrorPolicy = {
|
|
101
|
-
// When the apply handler throws: log the error, advance the cursor past
|
|
102
|
-
// the offending event, and keep delivering. Default false — current
|
|
103
|
-
// strict behaviour: retry up to maxAttempts, then mark the consumer
|
|
104
|
-
// status="dead" and pause delivery. Use for best-effort sinks
|
|
105
|
-
// (notifications, webhooks) where a single bad event should not stall
|
|
106
|
-
// the whole consumer.
|
|
107
|
-
readonly skipApplyErrors?: boolean;
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
export type MspErrorMode = {
|
|
111
|
-
// Applied during steady-state dispatcher delivery.
|
|
112
|
-
readonly continuous?: MspErrorPolicy;
|
|
113
|
-
// Applied during rebuildProjection() / backfill passes. When omitted,
|
|
114
|
-
// rebuild inherits continuous — explicit override common for "strict
|
|
115
|
-
// during rebuild, lenient in production" patterns.
|
|
116
|
-
readonly rebuild?: MspErrorPolicy;
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
// Marten-style MultiStreamProjection: aggregates events from many streams
|
|
120
|
-
// into one cross-cutting read-model. Unlike ProjectionDefinition (single-
|
|
121
|
-
// source, inline in the write-TX), an MSP is ASYNC — the event-dispatcher
|
|
122
|
-
// picks events off the log via its own cursor. Handlers MUST be idempotent
|
|
123
|
-
// because the dispatcher guarantees at-least-once delivery.
|
|
124
|
-
//
|
|
125
|
-
// Use for Sagas / process managers, customer-centric views that span
|
|
126
|
-
// multiple aggregate types, cross-feature aggregations, audit logs. With
|
|
127
|
-
// `table` omitted, the MSP becomes a pure side-effect consumer — sending
|
|
128
|
-
// notifications, posting webhooks, updating an external system. Marten's
|
|
129
|
-
// equivalent of a subscription / event listener, without a separate API.
|
|
130
|
-
export type MultiStreamProjectionDefinition = {
|
|
131
|
-
readonly name: string;
|
|
132
|
-
// Optional: omit for side-effect-only handlers (notifications, external
|
|
133
|
-
// system sync). When present, setupTestStack auto-pushes the table.
|
|
134
|
-
readonly table?: ProjectionTable;
|
|
135
|
-
// Keyed by fully-qualified event type. Unlike a single-stream projection,
|
|
136
|
-
// there is no source-entity hint — the MSP declares the event types it
|
|
137
|
-
// cares about directly. Extract the identity/grouping key inside the
|
|
138
|
-
// apply handler from the event payload.
|
|
139
|
-
readonly apply: Readonly<Record<string, MultiStreamApplyFn>>;
|
|
140
|
-
// How the dispatcher handles apply-throws. Default strict (retry + dead).
|
|
141
|
-
readonly errorMode?: MspErrorMode;
|
|
142
|
-
// Which deploy-lane runs this MSP's dispatcher. Default "worker". MSPs
|
|
143
|
-
// share a single consumer-row per MSP name with SKIP LOCKED, so "both"
|
|
144
|
-
// is safe semantically (API + Worker race for each event; exactly one
|
|
145
|
-
// wins). Use "api" for MSPs that need in-process state on the API
|
|
146
|
-
// (rare); use "both" only when genuinely load-balancing is helpful.
|
|
147
|
-
readonly runIn?: RunIn;
|
|
148
|
-
// Delivery semantics across multi-instance deploys:
|
|
149
|
-
// "shared" (default) — one cursor across all dispatcher instances,
|
|
150
|
-
// SKIP LOCKED serialises; each event delivered exactly
|
|
151
|
-
// once globally. The right choice for side-effects with
|
|
152
|
-
// any downstream state: notifications, external APIs,
|
|
153
|
-
// projection tables, audit rows.
|
|
154
|
-
// "per-instance" — one cursor PER dispatcher instance, so every process
|
|
155
|
-
// delivers every event. Required for push-to-local-
|
|
156
|
-
// subscribers (SSE, in-memory caches): a split-deploy
|
|
157
|
-
// where API instance B emits an event that API instance
|
|
158
|
-
// A's clients also need to see. Handler MUST be
|
|
159
|
-
// side-effect-free relative to the DB — it only reaches
|
|
160
|
-
// in-process structures — otherwise each instance
|
|
161
|
-
// writes duplicate rows. Misuse = duplicated side
|
|
162
|
-
// effects, not a safety property.
|
|
163
|
-
readonly delivery?: "shared" | "per-instance";
|
|
164
|
-
// Where the consumer's cursor starts on its FIRST registration. Default
|
|
165
|
-
// "beginning" replays the full log. "now" seeds the cursor at the current
|
|
166
|
-
// MAX(events.id) so mounting the MSP into an existing app does not
|
|
167
|
-
// retroactively fire side effects for historical events. Only affects the
|
|
168
|
-
// first registration — an existing cursor row is never clobbered.
|
|
169
|
-
readonly startFrom?: "beginning" | "now";
|
|
170
|
-
};
|
package/src/rate-limit-types.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type { Temporal } from "temporal-polyfill";
|
|
2
|
-
|
|
3
|
-
export type RateLimitDecision = {
|
|
4
|
-
readonly allowed: boolean;
|
|
5
|
-
readonly limit: number;
|
|
6
|
-
readonly remaining: number;
|
|
7
|
-
readonly retryAfterSeconds: number;
|
|
8
|
-
readonly windowSeconds: number;
|
|
9
|
-
readonly resetAt: Temporal.Instant;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export type RateLimitConfig = {
|
|
13
|
-
readonly limit: number;
|
|
14
|
-
readonly windowSeconds: number;
|
|
15
|
-
readonly cost?: number;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export type RateLimitResolver = {
|
|
19
|
-
// Atomic check + deduct. Returns the decision and current bucket state
|
|
20
|
-
// — caller decides whether to throw RateLimitError or proceed.
|
|
21
|
-
check(bucket: string, config: RateLimitConfig): Promise<RateLimitDecision>;
|
|
22
|
-
|
|
23
|
-
// Convenience: throws RateLimitError when blocked. Useful inside the
|
|
24
|
-
// dispatcher / middleware code-paths where the failure shape is fixed.
|
|
25
|
-
enforce(bucket: string, config: RateLimitConfig): Promise<RateLimitDecision>;
|
|
26
|
-
|
|
27
|
-
// Read-only inspection: returns the same shape as check() but never
|
|
28
|
-
// mutates the bucket — no token deduction, no refill-timestamp update.
|
|
29
|
-
// Use for ops/status queries (e.g. "kumiko rl status user:42") that
|
|
30
|
-
// must observe the bucket without disturbing it.
|
|
31
|
-
peek(bucket: string, config: Omit<RateLimitConfig, "cost">): Promise<RateLimitDecision>;
|
|
32
|
-
};
|
package/src/relations.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
// Canonical definition — packages/framework/src/engine/constants.ts imports
|
|
2
|
-
// this type and binds its OnDeleteStrategies runtime object to it via
|
|
3
|
-
// `satisfies`, so a drift between the two fails to compile.
|
|
4
|
-
export type OnDeleteStrategy = "cascade" | "restrict" | "setNull" | "nothing";
|
|
5
|
-
|
|
6
|
-
// --- Relations ---
|
|
7
|
-
|
|
8
|
-
export type BelongsToRelation = {
|
|
9
|
-
readonly type: "belongsTo";
|
|
10
|
-
readonly target: string;
|
|
11
|
-
readonly foreignKey: string;
|
|
12
|
-
// onDelete is declared on the parent-side (hasMany / manyToMany) because
|
|
13
|
-
// that's where the "what happens to my children?" decision lives. A
|
|
14
|
-
// belongsTo node just points at a parent — the parent's onDelete drives
|
|
15
|
-
// the cleanup.
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export type HasManyRelation = {
|
|
19
|
-
readonly type: "hasMany";
|
|
20
|
-
readonly target: string;
|
|
21
|
-
readonly foreignKey: string;
|
|
22
|
-
readonly onDelete?: OnDeleteStrategy;
|
|
23
|
-
// When true, a nested payload under this relation's key (e.g.
|
|
24
|
-
// `{ tasks: [{ ... }] }` on a `project:create` write) is auto-expanded
|
|
25
|
-
// into child writes: parent first, then one child-write per entry with
|
|
26
|
-
// the foreign key set to the parent's new id — all in the same TX.
|
|
27
|
-
// Opt-in (default false) so legacy hasMany relations that were declared
|
|
28
|
-
// purely for cascade-delete or UI-nav semantics don't silently gain a
|
|
29
|
-
// client-writable path. Children are never inferred from payload-shape
|
|
30
|
-
// alone; only relations with this flag unlock nested-write.
|
|
31
|
-
//
|
|
32
|
-
// Scope v1: depth=1, create-only, hasMany-only. Update-nested,
|
|
33
|
-
// delete-nested, and belongsTo/m2m auto-expansion are explicit future
|
|
34
|
-
// work — when they arrive, they'll take the same flag so the opt-in
|
|
35
|
-
// stays a single, consistent surface.
|
|
36
|
-
readonly nestedWrite?: boolean;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export type ManyToManyRelation = {
|
|
40
|
-
readonly type: "manyToMany";
|
|
41
|
-
readonly target: string;
|
|
42
|
-
readonly through: {
|
|
43
|
-
readonly table: string;
|
|
44
|
-
readonly sourceKey: string;
|
|
45
|
-
readonly targetKey: string;
|
|
46
|
-
};
|
|
47
|
-
readonly onDelete?: OnDeleteStrategy;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
export type RelationDefinition = BelongsToRelation | HasManyRelation | ManyToManyRelation;
|
|
51
|
-
|
|
52
|
-
export type EntityRelations = Readonly<Record<string, RelationDefinition>>;
|