@cosmicdrift/kumiko-framework 0.2.2 → 0.3.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/CHANGELOG.md +54 -0
- package/package.json +124 -38
- package/src/__tests__/full-stack.integration.ts +2 -2
- package/src/api/auth-routes.ts +5 -5
- package/src/api/jwt.ts +2 -2
- package/src/api/route-registrars.ts +1 -1
- package/src/api/routes.ts +3 -3
- package/src/api/server.ts +6 -7
- package/src/auth/__tests__/roles.test.ts +24 -0
- package/src/auth/index.ts +7 -0
- package/src/auth/roles.ts +42 -0
- package/src/compliance/__tests__/duration-spec.test.ts +72 -0
- package/src/compliance/__tests__/profiles.test.ts +308 -0
- package/src/compliance/__tests__/sub-processors.test.ts +139 -0
- package/src/compliance/duration-spec.ts +44 -0
- package/src/compliance/index.ts +31 -0
- package/src/compliance/override-schema.ts +136 -0
- package/src/compliance/profiles.ts +427 -0
- package/src/compliance/sub-processors.ts +152 -0
- package/src/db/__tests__/big-int-field.test.ts +131 -0
- package/src/db/assert-exists-in.ts +2 -2
- package/src/db/cursor.ts +3 -3
- package/src/db/event-store-executor.ts +19 -13
- package/src/db/located-timestamp.ts +1 -1
- package/src/db/money.ts +12 -2
- package/src/db/pg-error.ts +1 -1
- package/src/db/row-helpers.ts +1 -1
- package/src/db/table-builder.ts +20 -5
- package/src/db/tenant-db.ts +9 -9
- package/src/engine/__tests__/_pipeline-test-utils.ts +23 -0
- package/src/engine/__tests__/boot-validator-api-exposure.test.ts +142 -0
- package/src/engine/__tests__/boot-validator-pii-retention.test.ts +570 -0
- package/src/engine/__tests__/boot-validator-s0-integration.test.ts +160 -0
- package/src/engine/__tests__/build-target.test.ts +135 -0
- package/src/engine/__tests__/codemod-pipeline.test.ts +551 -0
- package/src/engine/__tests__/entity-handlers.test.ts +3 -3
- package/src/engine/__tests__/event-helpers.test.ts +4 -4
- package/src/engine/__tests__/pipeline-engine.test.ts +215 -0
- package/src/engine/__tests__/pipeline-handler.integration.ts +894 -0
- package/src/engine/__tests__/pipeline-observability.integration.ts +142 -0
- package/src/engine/__tests__/pipeline-performance.integration.ts +152 -0
- package/src/engine/__tests__/pipeline-sub-pipelines.test.ts +288 -0
- package/src/engine/__tests__/raw-table.test.ts +2 -2
- package/src/engine/__tests__/steps-aggregate-append-event.test.ts +115 -0
- package/src/engine/__tests__/steps-aggregate-create.test.ts +92 -0
- package/src/engine/__tests__/steps-aggregate-update.test.ts +127 -0
- package/src/engine/__tests__/steps-call-feature.test.ts +123 -0
- package/src/engine/__tests__/steps-mail-send.test.ts +136 -0
- package/src/engine/__tests__/steps-read.test.ts +142 -0
- package/src/engine/__tests__/steps-resolver-utils.test.ts +50 -0
- package/src/engine/__tests__/steps-unsafe-projection-delete.test.ts +69 -0
- package/src/engine/__tests__/steps-unsafe-projection-upsert.test.ts +117 -0
- package/src/engine/__tests__/steps-webhook-send.test.ts +135 -0
- package/src/engine/__tests__/steps-workflow.test.ts +198 -0
- package/src/engine/__tests__/validate-projection-allowlist.test.ts +491 -0
- package/src/engine/__tests__/visual-tree-patterns.test.ts +251 -0
- package/src/engine/boot-validator/api-ext.ts +77 -0
- package/src/engine/boot-validator/config-deps.ts +163 -0
- package/src/engine/boot-validator/entity-handler.ts +466 -0
- package/src/engine/boot-validator/index.ts +159 -0
- package/src/engine/boot-validator/ownership.ts +198 -0
- package/src/engine/boot-validator/pii-retention.ts +155 -0
- package/src/engine/boot-validator/screens-nav.ts +624 -0
- package/src/engine/boot-validator.ts +1 -1528
- package/src/engine/build-app-schema.ts +1 -1
- package/src/engine/build-target.ts +99 -0
- package/src/engine/codemod/index.ts +15 -0
- package/src/engine/codemod/pipeline-codemod.ts +641 -0
- package/src/engine/config-helpers.ts +9 -19
- package/src/engine/constants.ts +1 -1
- package/src/engine/define-feature.ts +127 -9
- package/src/engine/define-handler.ts +89 -3
- package/src/engine/define-roles.ts +2 -2
- package/src/engine/define-step.ts +28 -0
- package/src/engine/define-workflow.ts +110 -0
- package/src/engine/entity-handlers.ts +10 -9
- package/src/engine/event-helpers.ts +4 -4
- package/src/engine/extension-names.ts +105 -0
- package/src/engine/extensions/user-data.ts +106 -0
- package/src/engine/factories.ts +26 -16
- package/src/engine/feature-ast/__tests__/visual-tree-parse.test.ts +184 -0
- package/src/engine/feature-ast/extractors/index.ts +74 -0
- package/src/engine/feature-ast/extractors/round1.ts +110 -0
- package/src/engine/feature-ast/extractors/round2.ts +253 -0
- package/src/engine/feature-ast/extractors/round3.ts +471 -0
- package/src/engine/feature-ast/extractors/round4.ts +1365 -0
- package/src/engine/feature-ast/extractors/round5.ts +72 -0
- package/src/engine/feature-ast/extractors/round6.ts +66 -0
- package/src/engine/feature-ast/extractors/shared.ts +177 -0
- package/src/engine/feature-ast/parse.ts +13 -0
- package/src/engine/feature-ast/patch.ts +9 -1
- package/src/engine/feature-ast/patcher.ts +10 -3
- package/src/engine/feature-ast/patterns.ts +71 -1
- package/src/engine/feature-ast/render.ts +31 -1
- package/src/engine/index.ts +66 -2
- package/src/engine/pattern-library/__tests__/library.test.ts +11 -0
- package/src/engine/pattern-library/library.ts +78 -2
- package/src/engine/pipeline.ts +88 -0
- package/src/engine/projection-helpers.ts +1 -1
- package/src/engine/read-claim.ts +1 -1
- package/src/engine/registry.ts +30 -2
- package/src/engine/resolve-config-or-param.ts +4 -0
- package/src/engine/run-pipeline.ts +162 -0
- package/src/engine/schema-builder.ts +10 -4
- package/src/engine/state-machine.ts +1 -1
- package/src/engine/steps/_drizzle-boundary.ts +19 -0
- package/src/engine/steps/_duration-utils.ts +33 -0
- package/src/engine/steps/_no-return-guard.ts +21 -0
- package/src/engine/steps/_resolver-utils.ts +42 -0
- package/src/engine/steps/_step-dispatch-constants.ts +38 -0
- package/src/engine/steps/aggregate-append-event.ts +56 -0
- package/src/engine/steps/aggregate-create.ts +56 -0
- package/src/engine/steps/aggregate-update.ts +68 -0
- package/src/engine/steps/branch.ts +84 -0
- package/src/engine/steps/call-feature.ts +49 -0
- package/src/engine/steps/compute.ts +41 -0
- package/src/engine/steps/for-each.ts +111 -0
- package/src/engine/steps/mail-send.ts +44 -0
- package/src/engine/steps/read-find-many.ts +51 -0
- package/src/engine/steps/read-find-one.ts +58 -0
- package/src/engine/steps/retry.ts +87 -0
- package/src/engine/steps/return.ts +34 -0
- package/src/engine/steps/unsafe-projection-delete.ts +46 -0
- package/src/engine/steps/unsafe-projection-upsert.ts +69 -0
- package/src/engine/steps/wait-for-event.ts +71 -0
- package/src/engine/steps/wait.ts +69 -0
- package/src/engine/steps/webhook-send.ts +71 -0
- package/src/engine/system-user.ts +1 -1
- package/src/engine/types/feature.ts +143 -1
- package/src/engine/types/fields.ts +134 -10
- package/src/engine/types/handlers.ts +18 -10
- package/src/engine/types/identifiers.ts +1 -0
- package/src/engine/types/index.ts +15 -1
- package/src/engine/types/step.ts +334 -0
- package/src/engine/types/target-ref.ts +21 -0
- package/src/engine/types/tree-node.ts +130 -0
- package/src/engine/types/workspace.ts +7 -0
- package/src/engine/validate-projection-allowlist.ts +161 -0
- package/src/event-store/snapshot.ts +1 -1
- package/src/event-store/upcaster-dead-letter.ts +1 -1
- package/src/event-store/upcaster.ts +1 -1
- package/src/files/__tests__/read-stream.test.ts +105 -0
- package/src/files/__tests__/write-stream.test.ts +233 -0
- package/src/files/__tests__/zip-stream.test.ts +357 -0
- package/src/files/file-routes.ts +1 -1
- package/src/files/in-memory-provider.ts +38 -0
- package/src/files/index.ts +3 -0
- package/src/files/local-provider.ts +58 -1
- package/src/files/types.ts +36 -8
- package/src/files/zip-stream.ts +251 -0
- package/src/jobs/job-runner.ts +10 -10
- package/src/lifecycle/lifecycle.ts +0 -3
- package/src/logging/index.ts +1 -0
- package/src/logging/pino-logger.ts +11 -7
- package/src/logging/utils.ts +24 -0
- package/src/observability/prometheus-meter.ts +7 -5
- package/src/pipeline/__tests__/archive-stream.integration.ts +1 -1
- package/src/pipeline/__tests__/causation-chain.integration.ts +1 -1
- package/src/pipeline/__tests__/domain-events-projections.integration.ts +3 -3
- package/src/pipeline/__tests__/event-define-event-strict.integration.ts +4 -4
- package/src/pipeline/__tests__/load-aggregate-query.integration.ts +1 -1
- package/src/pipeline/__tests__/msp-multi-hop.integration.ts +3 -3
- package/src/pipeline/__tests__/msp-rebuild.integration.ts +3 -3
- package/src/pipeline/__tests__/multi-stream-projection.integration.ts +2 -2
- package/src/pipeline/__tests__/query-projection.integration.ts +5 -5
- package/src/pipeline/append-event-core.ts +22 -6
- package/src/pipeline/dispatcher-utils.ts +188 -0
- package/src/pipeline/dispatcher.ts +63 -283
- package/src/pipeline/distributed-lock.ts +1 -1
- package/src/pipeline/entity-cache.ts +2 -2
- package/src/pipeline/event-consumer-state.ts +0 -13
- package/src/pipeline/event-dispatcher.ts +4 -4
- package/src/pipeline/index.ts +0 -2
- package/src/pipeline/lifecycle-pipeline.ts +6 -12
- package/src/pipeline/msp-rebuild.ts +5 -5
- package/src/pipeline/multi-stream-apply-context.ts +6 -7
- package/src/pipeline/projection-rebuild.ts +2 -2
- package/src/pipeline/projection-state.ts +0 -12
- package/src/rate-limit/__tests__/resolver.integration.ts +8 -4
- package/src/rate-limit/resolver.ts +1 -1
- package/src/search/in-memory-adapter.ts +1 -1
- package/src/search/meilisearch-adapter.ts +3 -3
- package/src/search/types.ts +1 -1
- package/src/secrets/leak-guard.ts +2 -2
- package/src/stack/request-helper.ts +9 -5
- package/src/stack/test-stack.ts +1 -1
- package/src/testing/handler-context.ts +4 -4
- package/src/testing/http-cookies.ts +1 -1
- package/src/time/tz-context.ts +1 -2
- package/src/ui-types/index.ts +4 -0
- package/src/engine/feature-ast/extractors.ts +0 -2562
|
@@ -54,6 +54,7 @@ import type { NavDefinition } from "./nav";
|
|
|
54
54
|
import type { MultiStreamProjectionDefinition, ProjectionDefinition } from "./projection";
|
|
55
55
|
import type { EntityRelations, RelationDefinition } from "./relations";
|
|
56
56
|
import type { ScreenDefinition } from "./screen";
|
|
57
|
+
import type { TreeActionDef, TreeActionsHandle, TreeChildrenSubscribe } from "./tree-node";
|
|
57
58
|
import type { WorkspaceDefinition } from "./workspace";
|
|
58
59
|
|
|
59
60
|
// --- Metrics (declared by features via r.metric()) ---
|
|
@@ -148,6 +149,14 @@ export type FeatureDefinition = {
|
|
|
148
149
|
readonly exports?: unknown;
|
|
149
150
|
readonly requires: readonly string[];
|
|
150
151
|
readonly optionalRequires: readonly string[];
|
|
152
|
+
// Read-side projection-tables this feature is allowed to write via
|
|
153
|
+
// r.step.unsafeProjectionUpsert / unsafeProjectionDelete. Declared via
|
|
154
|
+
// r.requires.projection("table_name"). Hard requirement — boot-error
|
|
155
|
+
// if a step targets a non-listed table or one that's already an
|
|
156
|
+
// r.entity-registered aggregate-table. See step-vocabulary.md Q10.
|
|
157
|
+
readonly requiredProjections: ReadonlySet<string>;
|
|
158
|
+
// Tier-2 step kinds opted-in via r.requires.step("webhook.send"). Q9.
|
|
159
|
+
readonly requiredSteps: ReadonlySet<string>;
|
|
151
160
|
// Declared via r.toggleable({ default }). Presence makes the feature
|
|
152
161
|
// operator-switchable via the feature-toggles bundled feature; absence
|
|
153
162
|
// means the feature is always-on (e.g. auth, tenant, user — core infra
|
|
@@ -164,6 +173,21 @@ export type FeatureDefinition = {
|
|
|
164
173
|
readonly jobs: Readonly<Record<string, JobDefinition>>;
|
|
165
174
|
readonly registrarExtensions: Readonly<Record<string, RegistrarExtensionDef>>;
|
|
166
175
|
readonly extensionUsages: readonly RegistrarExtensionRegistration[];
|
|
176
|
+
/**
|
|
177
|
+
* Cross-feature API names this feature exposes via `r.exposesApi(name)`.
|
|
178
|
+
* Pure Marker-Deklaration — die echte Implementation wird als
|
|
179
|
+
* Query-/Write-Handler unter dem QN-Pattern registriert (z.B.
|
|
180
|
+
* `compliance-profiles:query:effective-profile`). Boot-Validator prüft
|
|
181
|
+
* dass jedes `r.usesApi(name)` einen passenden Exposer hier findet —
|
|
182
|
+
* Tippfehler oder Drop-Refactorings werden zu Boot-Fail statt Runtime-Crash.
|
|
183
|
+
*/
|
|
184
|
+
readonly exposedApis: ReadonlySet<string>;
|
|
185
|
+
/**
|
|
186
|
+
* Cross-feature API names this feature calls. Pflicht-Boot-Check:
|
|
187
|
+
* jeder Eintrag muss in `exposedApis` irgendeines Features auftauchen
|
|
188
|
+
* UND das Provider-Feature muss in requires/optionalRequires sein.
|
|
189
|
+
*/
|
|
190
|
+
readonly usedApis: ReadonlySet<string>;
|
|
167
191
|
readonly referenceData: readonly ReferenceDataDef[];
|
|
168
192
|
readonly notifications: Readonly<Record<string, NotificationDefinition>>;
|
|
169
193
|
readonly events: Readonly<Record<string, EventDef>>;
|
|
@@ -209,6 +233,21 @@ export type FeatureDefinition = {
|
|
|
209
233
|
// shellWorkspaces consumes the resolved per-workspace nav list at mount
|
|
210
234
|
// time; engine validates roles + nav refs at boot.
|
|
211
235
|
readonly workspaces: Readonly<Record<string, WorkspaceDefinition>>;
|
|
236
|
+
// Tree-Actions-Map declared via r.treeActions(). At-most-one per feature
|
|
237
|
+
// (only-once-guard at registration). Erased to `Record<string,
|
|
238
|
+
// TreeActionDef>` for runtime registry-lookup (Visual-Tree-Component
|
|
239
|
+
// dispatching, Pattern-AST consumers). The compile-time-typed surface
|
|
240
|
+
// is the registrar's return value (TreeActionsHandle) which the
|
|
241
|
+
// feature exports via setup-return — buildTarget consumes the handle,
|
|
242
|
+
// not this slot. See visual-tree.md A5 + A7.
|
|
243
|
+
readonly treeActions?: Readonly<Record<string, TreeActionDef>>;
|
|
244
|
+
// Tree-Provider declared via r.tree(). At-most-one per feature.
|
|
245
|
+
// Provider liefert die Top-Level-Knoten dieses Features im Visual-
|
|
246
|
+
// Workspace (navigation: "tree"). Subscribe-Form mit lazy-Eval: erst
|
|
247
|
+
// beim Mount des Workspaces aufgerufen, kann Updates emittieren.
|
|
248
|
+
// Feature ohne treeProvider ist im Visual-Workspace unsichtbar
|
|
249
|
+
// (Zero-Whitelist-Filter aus visual-tree.md A2).
|
|
250
|
+
readonly treeProvider?: TreeChildrenSubscribe;
|
|
212
251
|
// HTTP-Routes declared via r.httpRoute(). Index is "METHOD path"
|
|
213
252
|
// (z.B. "GET /feed.xml") — eindeutig pro Feature. Die App-Server-
|
|
214
253
|
// Boot-Stage iteriert getAllHttpRoutes() und mountet jede Route auf
|
|
@@ -235,9 +274,22 @@ type RefOrRefs = NameOrRef | readonly NameOrRef[];
|
|
|
235
274
|
* keeping strict-mode alive even when handlers route via `eventDef.name`
|
|
236
275
|
* instead of hand-typed string literals.
|
|
237
276
|
*/
|
|
277
|
+
/**
|
|
278
|
+
* `r.requires` is a callable+namespace: existing call form takes feature
|
|
279
|
+
* names (`r.requires("auth", "tenant")`), the `.projection` extension
|
|
280
|
+
* declares read-side projection tables that this feature's pipeline
|
|
281
|
+
* steps are allowed to write via `r.step.unsafeProjectionUpsert`.
|
|
282
|
+
* Hard-required for any unsafeProjection-* step usage (see Q10).
|
|
283
|
+
*/
|
|
284
|
+
export type RequiresApi = ((...featureNames: string[]) => void) & {
|
|
285
|
+
readonly projection: (tableName: string) => void;
|
|
286
|
+
// Tier-2 step opt-in (Q9). Tier-1 implicit, Tier-2 must be declared.
|
|
287
|
+
readonly step: (stepKind: string) => void;
|
|
288
|
+
};
|
|
289
|
+
|
|
238
290
|
export type FeatureRegistrar<TFeature extends string = string> = {
|
|
239
291
|
systemScope(): void;
|
|
240
|
-
requires
|
|
292
|
+
requires: RequiresApi;
|
|
241
293
|
optionalRequires(...featureNames: string[]): void;
|
|
242
294
|
// Declare the feature as operator-togglable. `default` is the effective
|
|
243
295
|
// state when no global-toggle row exists. Must be called at most once per
|
|
@@ -360,6 +412,42 @@ export type FeatureRegistrar<TFeature extends string = string> = {
|
|
|
360
412
|
|
|
361
413
|
useExtension(extensionName: string, entity: NameOrRef, options?: Record<string, unknown>): void;
|
|
362
414
|
|
|
415
|
+
/**
|
|
416
|
+
* Marker-Deklaration: dieses Feature stellt eine Cross-Feature-API
|
|
417
|
+
* unter dem genannten Namen bereit. Die eigentliche Implementation
|
|
418
|
+
* wird separat als Query- oder Write-Handler unter dem QN-Pattern
|
|
419
|
+
* registriert; `r.exposesApi` ist reine Boot-Check-Surface.
|
|
420
|
+
*
|
|
421
|
+
* Boot-Validator prüft, dass jedes `r.usesApi(name)` einen passenden
|
|
422
|
+
* Exposer findet, dass das Exposer-Feature in requires/optionalRequires
|
|
423
|
+
* gelisted ist und dass kein API-Name doppelt exposed wird.
|
|
424
|
+
*
|
|
425
|
+
* ```ts
|
|
426
|
+
* defineFeature("compliance-profiles", (r) => {
|
|
427
|
+
* r.exposesApi("compliance.forTenant");
|
|
428
|
+
* r.queryHandler({
|
|
429
|
+
* name: "compliance:query:for-tenant",
|
|
430
|
+
* // ... echte Implementation
|
|
431
|
+
* });
|
|
432
|
+
* });
|
|
433
|
+
* ```
|
|
434
|
+
*/
|
|
435
|
+
exposesApi(apiName: string): void;
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Declares that this feature calls a cross-feature API. Boot-Validator
|
|
439
|
+
* checkt dass irgendein anderes Feature `r.exposesApi(apiName)` macht
|
|
440
|
+
* und dass dieses Feature `r.requires/optionalRequires` darauf hat.
|
|
441
|
+
*
|
|
442
|
+
* ```ts
|
|
443
|
+
* defineFeature("user-data-rights", (r) => {
|
|
444
|
+
* r.requires("compliance-profiles");
|
|
445
|
+
* r.usesApi("compliance.forTenant");
|
|
446
|
+
* });
|
|
447
|
+
* ```
|
|
448
|
+
*/
|
|
449
|
+
usesApi(apiName: string): void;
|
|
450
|
+
|
|
363
451
|
// Declare a metric. Short name (without kumiko_<feature>_ prefix) — Framework
|
|
364
452
|
// qualifies it on boot. Validation (snake_case + typ-suffix) runs at boot.
|
|
365
453
|
// Usage at runtime: ctx.metrics.inc("created_total", { status: "new" }).
|
|
@@ -455,6 +543,44 @@ export type FeatureRegistrar<TFeature extends string = string> = {
|
|
|
455
543
|
// a non-empty string is the contract. If you can't write a reason,
|
|
456
544
|
// declare data via `r.entity()` instead.
|
|
457
545
|
rawTable(name: string, table: PgTable, options: RawTableOptions): void;
|
|
546
|
+
|
|
547
|
+
// Register the tree-actions schema for this feature — a map of
|
|
548
|
+
// action-name → action-definition (with optional typed args). At-most-
|
|
549
|
+
// one call per feature.
|
|
550
|
+
//
|
|
551
|
+
// Returns a TreeActionsHandle that the feature exports via setup-return
|
|
552
|
+
// (Memory `[EventDef-Exports-Pattern]`). The handle carries the
|
|
553
|
+
// literal-typed action-map that `buildTarget` consumes for compile-
|
|
554
|
+
// time validation:
|
|
555
|
+
//
|
|
556
|
+
// const handle = r.treeActions({
|
|
557
|
+
// edit: { args: { slug: "" as string } },
|
|
558
|
+
// list: {},
|
|
559
|
+
// });
|
|
560
|
+
// return { handle };
|
|
561
|
+
//
|
|
562
|
+
// Without this typed return, the action-map collapses to
|
|
563
|
+
// `Record<string, TreeActionDef>` at the buildTarget call-site and
|
|
564
|
+
// every action becomes accept-anything-string. See visual-tree.md A5.
|
|
565
|
+
//
|
|
566
|
+
// The runtime FeatureDefinition.treeActions slot stores the same map
|
|
567
|
+
// as erased Record (registry lookup, Pattern-AST consumers).
|
|
568
|
+
treeActions<const TActions extends Record<string, TreeActionDef>>(
|
|
569
|
+
actions: TActions,
|
|
570
|
+
): TreeActionsHandle<TFeature, TActions>;
|
|
571
|
+
|
|
572
|
+
// Register the tree-provider for this feature — the Subscribe-Function
|
|
573
|
+
// that emits the top-level Tree-Knoten when the Visual-Workspace
|
|
574
|
+
// (navigation: "tree") mounts. At-most-one call per feature.
|
|
575
|
+
//
|
|
576
|
+
// Provider receives a TreeContext (Phase-0-stub, opaque) and an
|
|
577
|
+
// emit-function; returns an unsubscribe-function. Initial-emit synchron
|
|
578
|
+
// oder async, weitere Emits beliebig oft (e.g. on entity-update SSE).
|
|
579
|
+
//
|
|
580
|
+
// A feature without r.tree() is invisible in `navigation: "tree"`-
|
|
581
|
+
// workspaces — that's the Zero-Whitelist-Filter from visual-tree.md A2:
|
|
582
|
+
// provider-Vorhandensein ist der Filter, kein Workspace-Mapping.
|
|
583
|
+
tree(provider: TreeChildrenSubscribe): void;
|
|
458
584
|
};
|
|
459
585
|
|
|
460
586
|
// --- Registry (created from features) ---
|
|
@@ -626,4 +752,20 @@ export type Registry = {
|
|
|
626
752
|
// validator rejects more than one. Apps without a default fall back to
|
|
627
753
|
// the first workspace the user has access to.
|
|
628
754
|
getDefaultWorkspace(): WorkspaceDefinition | undefined;
|
|
755
|
+
|
|
756
|
+
// Tree-Providers declared via r.tree() across all features. Keyed by
|
|
757
|
+
// declaring feature name (NOT qualified — Provider sind feature-bound,
|
|
758
|
+
// ein Feature liefert genau eine Provider-Function). The Visual-Tree
|
|
759
|
+
// component (renderer-web) iteriert getTreeProviders() beim Mount des
|
|
760
|
+
// navigation: "tree"-Workspaces, ruft jeden Provider mit ctx auf,
|
|
761
|
+
// sammelt die emitted TreeNode[] und merged sie zur Top-Level-Liste.
|
|
762
|
+
// See visual-tree.md A2 (Zero-Whitelist) + A4 (Subscribe-Form).
|
|
763
|
+
getTreeProviders(): ReadonlyMap<string, TreeChildrenSubscribe>;
|
|
764
|
+
|
|
765
|
+
// Tree-Actions-Map des Features. Returns the erased Record (compile-
|
|
766
|
+
// time-typed handle wandert über setup-export, nicht hier). Visual-
|
|
767
|
+
// Tree-Component nutzt das für Runtime-Action-Lookup beim Klick auf
|
|
768
|
+
// einen TreeNode.target — der Resolver findet das Feature via
|
|
769
|
+
// TargetRef.featureId und holt sich die zugehörige Action-Definition.
|
|
770
|
+
getTreeActions(featureName: string): Readonly<Record<string, TreeActionDef>> | undefined;
|
|
629
771
|
};
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// accepted at the type layer during migration: features that pass an
|
|
6
6
|
// array are auto-normalized to { [role]: "all" } at registry build.
|
|
7
7
|
// Long-term: string[] disappears.
|
|
8
|
+
import type { SQL } from "drizzle-orm";
|
|
8
9
|
import type { OwnershipMap } from "../ownership";
|
|
9
10
|
|
|
10
11
|
export type FieldAccess = {
|
|
@@ -20,6 +21,76 @@ export type FieldAccess = {
|
|
|
20
21
|
// custom projections cannot read sensitive field values. See
|
|
21
22
|
// docs/plans/architecture/projections.md.
|
|
22
23
|
|
|
24
|
+
// --- PII / Subject-Key Annotations (DSGVO Art. 17 — Crypto-Shredding) ---
|
|
25
|
+
//
|
|
26
|
+
// Felder die PII enthalten werden in Sprint 3 (crypto-shredding) mit einem
|
|
27
|
+
// Subject-Schluessel encrypted gespeichert. Subject = die natuerliche Person
|
|
28
|
+
// oder der Tenant der die Daten "besitzt". Loeschung erfolgt durch Vernichten
|
|
29
|
+
// des Subject-Keys ("Crypto-Shredding") — der Datensatz bleibt physisch
|
|
30
|
+
// (Audit-Trail bewahrt), ist aber nicht mehr entschluesselbar. Sprint 0
|
|
31
|
+
// fuegt nur die Schema-Marker + Boot-Validation ein; Encrypt/Decrypt-Mechanik
|
|
32
|
+
// kommt in Sprint 3.
|
|
33
|
+
//
|
|
34
|
+
// Drei orthogonale Markierungen:
|
|
35
|
+
// - `pii: true` — Subject = die Entity selbst.
|
|
36
|
+
// Beispiel: user.email gehoert User Marc.
|
|
37
|
+
// - `userOwned: { ownerField }` — Subject = der User der im genannten
|
|
38
|
+
// Field referenziert ist.
|
|
39
|
+
// Beispiel: comment.body gehoert
|
|
40
|
+
// comment.authorId.
|
|
41
|
+
// - `tenantOwned: true` — Subject = der aktuelle Tenant
|
|
42
|
+
// (ctx.tenantId zur Schreibzeit).
|
|
43
|
+
// Beispiel: tenantBranding.brandColor.
|
|
44
|
+
//
|
|
45
|
+
// `anonymize` ist die Pro-Feld-Funktion die der retention-Cleanup-Job
|
|
46
|
+
// (Sprint 2) aufruft wenn die Entity-Strategy "anonymize" lautet oder die
|
|
47
|
+
// `blockDelete`-Frist abgelaufen ist. Beispiel: `() => "[ANONYMIZED]"` oder
|
|
48
|
+
// `() => null`.
|
|
49
|
+
//
|
|
50
|
+
// `allowPlaintext` unterdrueckt PII-Heuristik-Boot-Warnings fuer Felder die
|
|
51
|
+
// zwar PII-Naming haben (email, name, body) aber bewusst Klartext bleiben
|
|
52
|
+
// sollen — z.B. ticket.title als Geschaeftsdaten. Wert ist eine Begruendung
|
|
53
|
+
// wie "is-business-data".
|
|
54
|
+
//
|
|
55
|
+
// `anonymize` darf sync oder async sein — der Cleanup-Job (Sprint 2)
|
|
56
|
+
// awaited den Return. Async-Funktionen sind sinnvoll wenn die Anonymisierung
|
|
57
|
+
// einen Lookup braucht (z.B. konsistente Pseudonyme aus separater Tabelle).
|
|
58
|
+
//
|
|
59
|
+
// Siehe docs/plans/datenschutz/crypto-shredding.md und docs/plans/datenschutz/roadmap.md.
|
|
60
|
+
export type PiiAnnotations = {
|
|
61
|
+
readonly pii?: boolean;
|
|
62
|
+
readonly userOwned?: { readonly ownerField: string };
|
|
63
|
+
readonly tenantOwned?: boolean;
|
|
64
|
+
readonly anonymize?: () => unknown | Promise<unknown>;
|
|
65
|
+
readonly allowPlaintext?: string;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// --- Retention (DSGVO Art. 5(1)(e) + HGB/AO Aufbewahrungspflichten) ---
|
|
69
|
+
//
|
|
70
|
+
// Pro Entity definiert der Author eine Default-Retention-Policy. Tenant-
|
|
71
|
+
// Admin uebersteuert sie via Compliance-Profile + Tenant-Override (Sprint 2).
|
|
72
|
+
// Vier Strategien:
|
|
73
|
+
//
|
|
74
|
+
// - "hardDelete" — Row physisch weg nach `keepFor`. Logs, Sessions.
|
|
75
|
+
// - "softDelete" — `deletedAt = now()`. Erlaubt spaetere Restore.
|
|
76
|
+
// - "anonymize" — Felder mit `anonymize`-Funktion ueberschrieben,
|
|
77
|
+
// Row bleibt. Order/Invoice mit gemischter PII +
|
|
78
|
+
// Geschaeftsdaten.
|
|
79
|
+
// - "blockDelete" — Cleanup-Job ignoriert; User-Forget loest stattdessen
|
|
80
|
+
// `anonymize` aus. Buchhaltung, Mandate, Patientenakten.
|
|
81
|
+
//
|
|
82
|
+
// `keepFor` ist eine Duration-String wie "30d", "10y", "6m". Parser
|
|
83
|
+
// kommt im Cleanup-Job (Sprint 2). `reference` ist das Field das den
|
|
84
|
+
// Lebenszeit-Anker liefert (Default: `createdAt`). Sessions z.B. nutzen
|
|
85
|
+
// `lastSeenAt` damit aktive Sessions nicht weggemueht werden.
|
|
86
|
+
//
|
|
87
|
+
// Siehe docs/plans/features/core-data-retention.md und Sprint 2 in roadmap.md.
|
|
88
|
+
export type RetentionDef = {
|
|
89
|
+
readonly keepFor: string;
|
|
90
|
+
readonly strategy: "hardDelete" | "softDelete" | "anonymize" | "blockDelete";
|
|
91
|
+
readonly reference?: string;
|
|
92
|
+
};
|
|
93
|
+
|
|
23
94
|
export type TextFieldDef = {
|
|
24
95
|
readonly type: "text";
|
|
25
96
|
readonly maxLength?: number;
|
|
@@ -40,7 +111,7 @@ export type TextFieldDef = {
|
|
|
40
111
|
* explizite Höhe. Search/sort/encrypt verhalten sich unverändert
|
|
41
112
|
* identisch zu single-line — nur die Render-Surface wechselt. */
|
|
42
113
|
readonly multiline?: boolean | { readonly rows?: number };
|
|
43
|
-
};
|
|
114
|
+
} & PiiAnnotations;
|
|
44
115
|
|
|
45
116
|
/**
|
|
46
117
|
* Long-form text content — source-code, markdown, blog-posts, email-
|
|
@@ -74,7 +145,7 @@ export type LongTextFieldDef = {
|
|
|
74
145
|
readonly default?: string;
|
|
75
146
|
readonly access?: FieldAccess;
|
|
76
147
|
readonly multiline?: boolean | { readonly rows?: number };
|
|
77
|
-
};
|
|
148
|
+
} & PiiAnnotations;
|
|
78
149
|
|
|
79
150
|
export type BooleanFieldDef = {
|
|
80
151
|
readonly type: "boolean";
|
|
@@ -95,7 +166,7 @@ export type SelectFieldDef<TOptions extends readonly string[] = readonly string[
|
|
|
95
166
|
readonly sensitive?: boolean;
|
|
96
167
|
readonly default?: TOptions[number];
|
|
97
168
|
readonly access?: FieldAccess;
|
|
98
|
-
};
|
|
169
|
+
} & PiiAnnotations;
|
|
99
170
|
|
|
100
171
|
// Mehrere Werte aus einer festen Options-Liste — UI rendert als
|
|
101
172
|
// Checkbox-/Multi-Select-Kontrolle. Storage: jsonb-Array<string>;
|
|
@@ -119,7 +190,7 @@ export type MultiSelectFieldDef<TOptions extends readonly string[] = readonly st
|
|
|
119
190
|
/** Default-Auswahl. Jeder Eintrag muss in `options` sein (Boot-Validator). */
|
|
120
191
|
readonly default?: readonly TOptions[number][];
|
|
121
192
|
readonly access?: FieldAccess;
|
|
122
|
-
};
|
|
193
|
+
} & PiiAnnotations;
|
|
123
194
|
|
|
124
195
|
export type NumberFieldDef = {
|
|
125
196
|
readonly type: "number";
|
|
@@ -129,7 +200,29 @@ export type NumberFieldDef = {
|
|
|
129
200
|
readonly sensitive?: boolean;
|
|
130
201
|
readonly default?: number;
|
|
131
202
|
readonly access?: FieldAccess;
|
|
132
|
-
};
|
|
203
|
+
} & PiiAnnotations;
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* 64-bit-Integer-Spalte fuer Audit-Counter, Byte-Sizes, Event-IDs und
|
|
207
|
+
* andere Werte die >2^31 (~2.1 Mrd) wandern koennen. Storage als
|
|
208
|
+
* Postgres `bigint`, JS-Round-trip als `number` (mode:"number" — sicher
|
|
209
|
+
* bis 2^53 ≈ 9 PB, JSON-serialisierbar). Wer >2^53 braucht (rare),
|
|
210
|
+
* nutzt einen `text`-Field mit eigenem Codec.
|
|
211
|
+
*
|
|
212
|
+
* Vorrang vor `NumberFieldDef`-(integer 32-bit-Cap, ~2.1 GB) immer dann
|
|
213
|
+
* wenn der Wert physisch ueber dieses Limit klettern kann: Bytes,
|
|
214
|
+
* Events, Counters in High-Throughput-Apps, Cumulative-Sums. Money
|
|
215
|
+
* hat dafuer den eigenen `MoneyFieldDef` (mit Currency-Spalte).
|
|
216
|
+
*/
|
|
217
|
+
export type BigIntFieldDef = {
|
|
218
|
+
readonly type: "bigInt";
|
|
219
|
+
readonly required?: boolean;
|
|
220
|
+
readonly sortable?: boolean;
|
|
221
|
+
readonly filterable?: boolean;
|
|
222
|
+
readonly sensitive?: boolean;
|
|
223
|
+
readonly default?: number;
|
|
224
|
+
readonly access?: FieldAccess;
|
|
225
|
+
} & PiiAnnotations;
|
|
133
226
|
|
|
134
227
|
export type MoneyFieldDef = {
|
|
135
228
|
readonly type: "money";
|
|
@@ -207,7 +300,7 @@ export type EmbeddedFieldDef = {
|
|
|
207
300
|
readonly sensitive?: boolean;
|
|
208
301
|
readonly schema: Readonly<Record<string, EmbeddedSubFieldDef>>;
|
|
209
302
|
readonly access?: FieldAccess;
|
|
210
|
-
};
|
|
303
|
+
} & PiiAnnotations;
|
|
211
304
|
|
|
212
305
|
// Legacy "date" — JS-Date-Object, semantisch unklar (Wall-Clock vs Instant).
|
|
213
306
|
// Für neue Felder bevorzuge:
|
|
@@ -223,7 +316,7 @@ export type DateFieldDef = {
|
|
|
223
316
|
readonly filterable?: boolean;
|
|
224
317
|
readonly sensitive?: boolean;
|
|
225
318
|
readonly access?: FieldAccess;
|
|
226
|
-
};
|
|
319
|
+
} & PiiAnnotations;
|
|
227
320
|
|
|
228
321
|
// UTC-Instant (Temporal.Instant). Für Ereignisse die zu einem bestimmten
|
|
229
322
|
// Augenblick passieren, ohne Location-Bezug: createdAt, loginAt, actualPickupAt.
|
|
@@ -251,7 +344,7 @@ export type TimestampFieldDef = {
|
|
|
251
344
|
* { pickupAt: { type: "timestamp", locatedBy: "pickupTz" }, pickupTz: { type: "tz" } }
|
|
252
345
|
*/
|
|
253
346
|
readonly locatedBy?: string;
|
|
254
|
-
};
|
|
347
|
+
} & PiiAnnotations;
|
|
255
348
|
|
|
256
349
|
// IANA-Zonenname (z.B. "Europe/Berlin", "America/Los_Angeles").
|
|
257
350
|
// Wird via `Intl.supportedValuesOf("timeZone")` validiert (kommt im
|
|
@@ -262,7 +355,7 @@ export type TzFieldDef = {
|
|
|
262
355
|
readonly required?: boolean;
|
|
263
356
|
readonly sensitive?: boolean;
|
|
264
357
|
readonly access?: FieldAccess;
|
|
265
|
-
};
|
|
358
|
+
} & PiiAnnotations;
|
|
266
359
|
|
|
267
360
|
// Wall-Clock-Termin an einem Ort als ATOMARES Konzept.
|
|
268
361
|
// EIN Feld in der Schema-Definition, ZWEI Spalten in der DB
|
|
@@ -289,7 +382,7 @@ export type LocatedTimestampFieldDef = {
|
|
|
289
382
|
readonly filterable?: boolean;
|
|
290
383
|
readonly sensitive?: boolean;
|
|
291
384
|
readonly access?: FieldAccess;
|
|
292
|
-
};
|
|
385
|
+
} & PiiAnnotations;
|
|
293
386
|
|
|
294
387
|
export type FileFieldDef = {
|
|
295
388
|
readonly type: "file";
|
|
@@ -332,6 +425,7 @@ export type FieldDefinition =
|
|
|
332
425
|
| SelectFieldDef
|
|
333
426
|
| MultiSelectFieldDef
|
|
334
427
|
| NumberFieldDef
|
|
428
|
+
| BigIntFieldDef
|
|
335
429
|
| MoneyFieldDef
|
|
336
430
|
| ReferenceFieldDef
|
|
337
431
|
| EmbeddedFieldDef
|
|
@@ -380,6 +474,20 @@ export type EntityIndexDef = {
|
|
|
380
474
|
readonly columns: readonly [string, ...string[]];
|
|
381
475
|
readonly unique?: boolean;
|
|
382
476
|
readonly name?: string;
|
|
477
|
+
/**
|
|
478
|
+
* Optional SQL-Fragment fuer Partial-Index — `CREATE [UNIQUE] INDEX
|
|
479
|
+
* ... WHERE <condition>`. Postgres-Pattern fuer "Index nur unter
|
|
480
|
+
* bestimmten Bedingungen", typisches Beispiel: ExportJob-Idempotency
|
|
481
|
+
* `UNIQUE(userId) WHERE status IN ('pending', 'running')`.
|
|
482
|
+
*
|
|
483
|
+
* Caller baut das Fragment via drizzle-orm `sql\`...\``-Tagged-
|
|
484
|
+
* Template. table-builder.ts emittiert `.where(def.where)` auf den
|
|
485
|
+
* Drizzle-IndexBuilder — wirkt sowohl fuer unique- als auch fuer
|
|
486
|
+
* non-unique-Indexes (PG erlaubt beides; non-unique partial nutzt
|
|
487
|
+
* man z.B. fuer scharfe BTREE-Indexes nur auf einer Status-Teilmenge
|
|
488
|
+
* statt voller Tabelle).
|
|
489
|
+
*/
|
|
490
|
+
readonly where?: SQL;
|
|
383
491
|
};
|
|
384
492
|
|
|
385
493
|
export type FieldsMap = Readonly<Record<string, FieldDefinition>>;
|
|
@@ -419,4 +527,20 @@ export type EntityDefinition<F extends FieldsMap = FieldsMap> = {
|
|
|
419
527
|
readonly read?: OwnershipMap;
|
|
420
528
|
readonly write?: OwnershipMap;
|
|
421
529
|
};
|
|
530
|
+
/**
|
|
531
|
+
* Default-Retention-Policy fuer diese Entity. Tenant-Admin kann via
|
|
532
|
+
* Compliance-Profile + Tenant-Override (Sprint 2) uebersteuern.
|
|
533
|
+
* Cleanup-Job (Sprint 2) verarbeitet die Strategy:
|
|
534
|
+
*
|
|
535
|
+
* - "hardDelete" → Row physisch weg nach keepFor
|
|
536
|
+
* - "softDelete" → deletedAt = now() (mit core-soft-delete-Feature)
|
|
537
|
+
* - "anonymize" → Felder mit `anonymize`-Funktion ueberschrieben,
|
|
538
|
+
* Row bleibt
|
|
539
|
+
* - "blockDelete" → Cleanup-Job ignoriert; User-Forget loest
|
|
540
|
+
* stattdessen anonymize aus. Buchhaltung, Mandate,
|
|
541
|
+
* Patientenakten.
|
|
542
|
+
*
|
|
543
|
+
* Siehe docs/plans/features/core-data-retention.md.
|
|
544
|
+
*/
|
|
545
|
+
readonly retention?: RetentionDef;
|
|
422
546
|
};
|
|
@@ -175,9 +175,9 @@ export function withResponseData<T>(result: WriteResult<unknown>, data: T): Writ
|
|
|
175
175
|
|
|
176
176
|
// --- Context Types ---
|
|
177
177
|
|
|
178
|
-
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
179
178
|
// Forward import: Registry is in feature.ts (circular type import — fine in TS)
|
|
180
179
|
import type { Registry } from "./feature";
|
|
180
|
+
import type { TenantId } from "./identifiers";
|
|
181
181
|
|
|
182
182
|
// Minimal interface for job event triggers (framework-owned, concrete type in jobs/)
|
|
183
183
|
export type JobRunnerRef = {
|
|
@@ -312,7 +312,7 @@ export type AppContext = SharedContextFields & {
|
|
|
312
312
|
// TMap propagates the strict event-type-map through `appendEvent`. Defaults
|
|
313
313
|
// to the global KumikoEventTypeMap (augmented per app via
|
|
314
314
|
// `declare module "@cosmicdrift/kumiko-framework/engine"`). Code that bypasses the
|
|
315
|
-
// type-map (runtime-pluggable events) uses `
|
|
315
|
+
// type-map (runtime-pluggable events) uses `unsafeAppendEvent`.
|
|
316
316
|
export type HandlerContext<TMap extends object = KumikoEventTypeMap> = SharedContextFields & {
|
|
317
317
|
readonly db: TenantDb;
|
|
318
318
|
readonly registry: Registry;
|
|
@@ -353,11 +353,11 @@ export type HandlerContext<TMap extends object = KumikoEventTypeMap> = SharedCon
|
|
|
353
353
|
readonly appendEvent: AppendEventFn<TMap>;
|
|
354
354
|
|
|
355
355
|
// Escape-hatch for runtime-pluggable features without a compile-time
|
|
356
|
-
// augmentation. See
|
|
356
|
+
// augmentation. See UnsafeAppendEventFn — same runtime as appendEvent,
|
|
357
357
|
// but the type-surface is `payload: unknown`. Use only when the event-
|
|
358
358
|
// type is not knowable at compile-time; otherwise the strict path
|
|
359
359
|
// (appendEvent) is the contract Designer/AI rely on.
|
|
360
|
-
readonly
|
|
360
|
+
readonly unsafeAppendEvent: UnsafeAppendEventFn;
|
|
361
361
|
|
|
362
362
|
// Marten FetchForWriting equivalent: load the current stream, optionally
|
|
363
363
|
// enforce expectedVersion, and get a handle that appends further events
|
|
@@ -428,11 +428,11 @@ export type HandlerContext<TMap extends object = KumikoEventTypeMap> = SharedCon
|
|
|
428
428
|
// name without the feature having to import the drizzle-table directly.
|
|
429
429
|
//
|
|
430
430
|
// Auto-applies tenant_id filter when the projection table has a tenant_id
|
|
431
|
-
// column (or opt out with {
|
|
431
|
+
// column (or opt out with { unsafeAllTenants: true } for system-scoped reads
|
|
432
432
|
// like cross-tenant analytics). Unknown projection name throws.
|
|
433
433
|
readonly queryProjection: <T = Record<string, unknown>>(
|
|
434
434
|
qualifiedName: string,
|
|
435
|
-
options?: { readonly
|
|
435
|
+
options?: { readonly unsafeAllTenants?: boolean },
|
|
436
436
|
) => Promise<readonly T[]>;
|
|
437
437
|
|
|
438
438
|
// Always populated — Noop when no observability provider is configured.
|
|
@@ -601,7 +601,7 @@ export type TypedAppendEventArgs<TMap extends object, K extends keyof TMap> = {
|
|
|
601
601
|
// Strict-only form. Single overload — `<K extends keyof TMap>` against the
|
|
602
602
|
// app's pre-bound TMap. No fallback overload: apps that need runtime-pluggable
|
|
603
603
|
// events (where the type-string isn't known at compile-time) reach for
|
|
604
|
-
// `
|
|
604
|
+
// `unsafeAppendEvent`.
|
|
605
605
|
//
|
|
606
606
|
// Why no fallback overload:
|
|
607
607
|
// A two-overload form (`(args: AppendEventArgs)` as the second sig)
|
|
@@ -619,13 +619,13 @@ export type TypedAppendEventArgs<TMap extends object, K extends keyof TMap> = {
|
|
|
619
619
|
// KumikoEventTypeMap>(...)` wrappers. Handlers inside those wrappers
|
|
620
620
|
// get a strict ctx.appendEvent.
|
|
621
621
|
// - Cross-package callers (e.g. bundled-features's set.write.ts) that
|
|
622
|
-
// can't afford a local wrapper reach for `ctx.
|
|
622
|
+
// can't afford a local wrapper reach for `ctx.unsafeAppendEvent`
|
|
623
623
|
// instead — same runtime, looser type-surface.
|
|
624
624
|
export type AppendEventFn<TMap extends object = KumikoEventTypeMap> = <K extends keyof TMap>(
|
|
625
625
|
args: TypedAppendEventArgs<TMap, K>,
|
|
626
626
|
) => Promise<void>;
|
|
627
627
|
|
|
628
|
-
export type
|
|
628
|
+
export type UnsafeAppendEventFn = (args: AppendEventArgs) => Promise<void>;
|
|
629
629
|
|
|
630
630
|
// Args for ctx.fetchForWriting — Marten FetchForWriting equivalent. Returns
|
|
631
631
|
// the current stream state + a handle that appends without re-specifying
|
|
@@ -737,8 +737,16 @@ export type WriteHandlerDef = {
|
|
|
737
737
|
readonly schema: ZodType;
|
|
738
738
|
readonly handler: WriteHandlerFn;
|
|
739
739
|
readonly access?: AccessRule;
|
|
740
|
-
readonly
|
|
740
|
+
readonly unsafeSkipTransitionGuard?: boolean;
|
|
741
741
|
readonly rateLimit?: RateLimitOption;
|
|
742
|
+
// Set when the author wrote a `perform: pipeline(...)` block. Boot-
|
|
743
|
+
// validators (projection-allowlist) and Designer/AI tooling read this
|
|
744
|
+
// to inspect the step list. Absent on free-form handlers.
|
|
745
|
+
// Inline-import is intentional: step.ts imports HandlerContext from
|
|
746
|
+
// this file, a top-level `import type { PipelineDef } from "./step"`
|
|
747
|
+
// would form a type-only circular import that TS resolves but tooling
|
|
748
|
+
// (incremental compile, IDEs) sometimes mis-handles.
|
|
749
|
+
readonly perform?: import("./step").PipelineDef;
|
|
742
750
|
};
|
|
743
751
|
|
|
744
752
|
export type QueryHandlerDef = {
|
|
@@ -66,6 +66,7 @@ export type {
|
|
|
66
66
|
} from "./feature";
|
|
67
67
|
export type {
|
|
68
68
|
AnyFileFieldDef,
|
|
69
|
+
BigIntFieldDef,
|
|
69
70
|
BooleanFieldDef,
|
|
70
71
|
DateFieldDef,
|
|
71
72
|
DefaultCurrency,
|
|
@@ -85,7 +86,9 @@ export type {
|
|
|
85
86
|
MoneyFieldDef,
|
|
86
87
|
MultiSelectFieldDef,
|
|
87
88
|
NumberFieldDef,
|
|
89
|
+
PiiAnnotations,
|
|
88
90
|
ReferenceFieldDef,
|
|
91
|
+
RetentionDef,
|
|
89
92
|
SelectFieldDef,
|
|
90
93
|
TextFieldDef,
|
|
91
94
|
TimestampFieldDef,
|
|
@@ -99,7 +102,6 @@ export type {
|
|
|
99
102
|
AppContext,
|
|
100
103
|
AppendEventArgs,
|
|
101
104
|
AppendEventFn,
|
|
102
|
-
AppendEventUnsafeFn,
|
|
103
105
|
AuthClaimsContext,
|
|
104
106
|
AuthClaimsFn,
|
|
105
107
|
AuthClaimsHookDef,
|
|
@@ -130,6 +132,7 @@ export type {
|
|
|
130
132
|
RateLimitOption,
|
|
131
133
|
RateLimitPer,
|
|
132
134
|
SessionUser,
|
|
135
|
+
UnsafeAppendEventFn,
|
|
133
136
|
WriteEvent,
|
|
134
137
|
WriteHandlerDef,
|
|
135
138
|
WriteHandlerFn,
|
|
@@ -208,4 +211,15 @@ export type {
|
|
|
208
211
|
ToolbarAction,
|
|
209
212
|
} from "./screen";
|
|
210
213
|
export { normalizeEditField, normalizeListColumn } from "./screen";
|
|
214
|
+
export type { TargetRef } from "./target-ref";
|
|
215
|
+
export type {
|
|
216
|
+
Subscribe,
|
|
217
|
+
TreeAction,
|
|
218
|
+
TreeActionDef,
|
|
219
|
+
TreeActionsHandle,
|
|
220
|
+
TreeChildrenSubscribe,
|
|
221
|
+
TreeContext,
|
|
222
|
+
TreeNode,
|
|
223
|
+
TreeNodeState,
|
|
224
|
+
} from "./tree-node";
|
|
211
225
|
export type { WorkspaceDefinition } from "./workspace";
|