@cosmicdrift/kumiko-framework 0.158.2 → 0.160.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.
Files changed (168) hide show
  1. package/package.json +7 -2
  2. package/src/__tests__/consumer-cli.integration.test.ts +110 -0
  3. package/src/api/__tests__/api.test.ts +65 -0
  4. package/src/api/__tests__/auth-routes-cookie.test.ts +17 -1
  5. package/src/api/__tests__/auth-routes-invalid-body-invite.test.ts +237 -0
  6. package/src/api/__tests__/auth-routes-mfa-verify.test.ts +1 -0
  7. package/src/api/__tests__/csrf-constants-sync.test.ts +20 -0
  8. package/src/api/__tests__/dispatcher-live.integration.test.ts +74 -0
  9. package/src/api/__tests__/jwt.test.ts +150 -1
  10. package/src/api/__tests__/login-rate-limiter-sweep.test.ts +41 -0
  11. package/src/api/__tests__/server-boot-guards.test.ts +71 -0
  12. package/src/api/__tests__/server-jwt-ttl.test.ts +58 -0
  13. package/src/api/api-constants.ts +5 -0
  14. package/src/api/auth-middleware.ts +48 -59
  15. package/src/api/auth-routes.ts +51 -17
  16. package/src/api/index.ts +3 -3
  17. package/src/api/jwt.ts +148 -7
  18. package/src/api/pii-leak-guard.ts +5 -2
  19. package/src/api/routes.ts +57 -0
  20. package/src/api/server.ts +19 -5
  21. package/src/bun-db/__tests__/select-many-retry.test.ts +79 -0
  22. package/src/bun-db/query.ts +46 -27
  23. package/src/consumer-cli.ts +87 -0
  24. package/src/crypto/__tests__/pii-field-encryption.test.ts +69 -13
  25. package/src/crypto/blind-index.ts +8 -4
  26. package/src/crypto/event-pii.ts +1 -0
  27. package/src/crypto/kms-adapter.ts +2 -118
  28. package/src/crypto/pii-field-encryption.ts +49 -15
  29. package/src/db/__tests__/build-filter-where.test.ts +34 -0
  30. package/src/db/__tests__/event-store-executor-context.pii-roundtrip.test.ts +67 -0
  31. package/src/db/__tests__/event-store-executor-write-verbs.integration.test.ts +396 -0
  32. package/src/db/__tests__/event-store-executor.integration.test.ts +5 -5
  33. package/src/db/blind-index-cleanup.ts +3 -1
  34. package/src/db/connection.ts +3 -11
  35. package/src/db/cursor.ts +1 -18
  36. package/src/db/dialect.ts +8 -19
  37. package/src/db/encryption.ts +2 -3
  38. package/src/db/entity-table-meta-types.ts +2 -0
  39. package/src/db/entity-table-meta.ts +16 -90
  40. package/src/db/event-store-executor.ts +4 -96
  41. package/src/db/queries/backfill-pii.ts +1 -0
  42. package/src/db/queries/event-consumer.ts +35 -2
  43. package/src/db/table-builder.ts +2 -19
  44. package/src/db/tenant-db.ts +6 -55
  45. package/src/engine/__tests__/boot-validator-boot-check.test.ts +99 -0
  46. package/src/engine/__tests__/boot-validator-gdpr-storage.test.ts +7 -233
  47. package/src/engine/__tests__/boot-validator.test.ts +46 -0
  48. package/src/engine/__tests__/codemod-pipeline.test.ts +139 -10
  49. package/src/engine/__tests__/define-roles.test.ts +21 -0
  50. package/src/engine/__tests__/engine.test.ts +28 -0
  51. package/src/engine/__tests__/event-type-map-augmentation.test.ts +24 -0
  52. package/src/engine/__tests__/registry-facade-sweep.test.ts +80 -0
  53. package/src/engine/__tests__/registry.test.ts +40 -0
  54. package/src/engine/__tests__/store-table.test.ts +12 -0
  55. package/src/engine/__tests__/tier-resolver-extension.test.ts +19 -1
  56. package/src/engine/boot-validator/action-wiring.ts +1 -1
  57. package/src/engine/boot-validator/boot-check.ts +21 -0
  58. package/src/engine/boot-validator/entity-handler.ts +10 -1
  59. package/src/engine/boot-validator/entity-list-screens.ts +1 -1
  60. package/src/engine/boot-validator/gdpr-storage.ts +0 -112
  61. package/src/engine/boot-validator/index.ts +3 -9
  62. package/src/engine/boot-validator/screens.ts +1 -1
  63. package/src/engine/define-feature.ts +2 -0
  64. package/src/engine/define-handler.ts +11 -91
  65. package/src/engine/entity-handlers.ts +15 -27
  66. package/src/engine/feature-ast/__tests__/canonical-form.test.ts +11 -1
  67. package/src/engine/feature-ast/__tests__/parse.test.ts +983 -3
  68. package/src/engine/feature-ast/__tests__/patch.test.ts +168 -0
  69. package/src/engine/feature-ast/__tests__/patcher.test.ts +7 -0
  70. package/src/engine/feature-ast/__tests__/render-roundtrip.test.ts +9 -0
  71. package/src/engine/feature-ast/extractors/handlers.ts +19 -2
  72. package/src/engine/feature-ast/extractors/index.ts +1 -0
  73. package/src/engine/feature-ast/index.ts +2 -0
  74. package/src/engine/feature-ast/parse.ts +3 -0
  75. package/src/engine/feature-ast/patch.ts +2 -0
  76. package/src/engine/feature-ast/patcher.ts +21 -0
  77. package/src/engine/feature-ast/patterns.ts +16 -0
  78. package/src/engine/feature-ast/render.ts +15 -0
  79. package/src/engine/feature-builder-state.ts +6 -0
  80. package/src/engine/feature-config-events-jobs.ts +1 -1
  81. package/src/engine/feature-entity-handlers.ts +36 -2
  82. package/src/engine/feature-ui-extensions.ts +5 -1
  83. package/src/engine/field-helpers.ts +31 -0
  84. package/src/engine/handler-helpers.ts +26 -0
  85. package/src/engine/hook-helpers.ts +14 -0
  86. package/src/engine/index.ts +5 -2
  87. package/src/engine/ownership.ts +22 -76
  88. package/src/engine/pattern-library/__tests__/library.test.ts +9 -0
  89. package/src/engine/pattern-library/library.ts +2 -0
  90. package/src/engine/pattern-library/mixed-schemas.ts +37 -0
  91. package/src/engine/registry-facade.ts +9 -0
  92. package/src/engine/registry-ingest.ts +10 -0
  93. package/src/engine/registry-state.ts +3 -0
  94. package/src/engine/registry-validate.ts +1 -1
  95. package/src/engine/screen-helpers.ts +54 -0
  96. package/src/engine/tier-resolver-extension.ts +3 -2
  97. package/src/engine/types/config.ts +2 -497
  98. package/src/engine/types/define-handler.ts +2 -0
  99. package/src/engine/types/entity-handlers.ts +2 -0
  100. package/src/engine/types/event-type-map.ts +1 -37
  101. package/src/engine/types/feature.ts +2 -976
  102. package/src/engine/types/fields.ts +2 -697
  103. package/src/engine/types/handlers.ts +2 -839
  104. package/src/engine/types/hooks.ts +2 -184
  105. package/src/engine/types/http-route.ts +1 -72
  106. package/src/engine/types/identifiers.ts +1 -47
  107. package/src/engine/types/index.ts +66 -33
  108. package/src/engine/types/nav.ts +2 -67
  109. package/src/engine/types/ownership.ts +2 -0
  110. package/src/engine/types/projection.ts +2 -165
  111. package/src/engine/types/relations.ts +1 -51
  112. package/src/engine/types/screen.ts +2 -793
  113. package/src/engine/types/step.ts +2 -334
  114. package/src/engine/types/target-ref.ts +1 -21
  115. package/src/engine/types/tree-node.ts +1 -129
  116. package/src/engine/types/workspace.ts +2 -42
  117. package/src/entrypoint/index.ts +2 -2
  118. package/src/errors/write-error-info.ts +6 -22
  119. package/src/event-store/__tests__/event-store.integration.test.ts +31 -0
  120. package/src/event-store/__tests__/unscoped-stream-primitives.guard.test.ts +43 -0
  121. package/src/event-store/errors.ts +2 -35
  122. package/src/event-store/event-store.ts +28 -51
  123. package/src/event-store/events-schema.ts +1 -10
  124. package/src/event-store/index.ts +3 -2
  125. package/src/event-store/snapshot.ts +11 -35
  126. package/src/event-store/types.ts +2 -0
  127. package/src/files/__tests__/in-memory-provider.contract.test.ts +4 -0
  128. package/src/files/file-handle.ts +2 -19
  129. package/src/files/provider-resolver.ts +3 -5
  130. package/src/files/types.ts +5 -54
  131. package/src/i18n/required-surface-keys.ts +1 -1
  132. package/src/jobs/__tests__/jobs.integration.test.ts +102 -1
  133. package/src/logging/types.ts +1 -7
  134. package/src/observability/types/index.ts +1 -29
  135. package/src/observability/types/metric.ts +1 -56
  136. package/src/observability/types/provider.ts +1 -32
  137. package/src/observability/types/span.ts +1 -58
  138. package/src/pipeline/__tests__/dispatcher.test.ts +134 -1
  139. package/src/pipeline/__tests__/event-dispatcher-delivery-max-attempts.test.ts +126 -0
  140. package/src/pipeline/__tests__/event-dispatcher-rearm.integration.test.ts +180 -0
  141. package/src/pipeline/__tests__/lifecycle-pipeline.test.ts +208 -0
  142. package/src/pipeline/dispatch-shared.ts +51 -3
  143. package/src/pipeline/dispatch-stream.ts +74 -0
  144. package/src/pipeline/dispatcher-utils.ts +1 -1
  145. package/src/pipeline/dispatcher.ts +7 -0
  146. package/src/pipeline/entity-cache.ts +2 -33
  147. package/src/pipeline/event-consumer-state.ts +28 -3
  148. package/src/pipeline/event-dispatcher-admin.ts +4 -0
  149. package/src/pipeline/event-dispatcher-delivery.ts +29 -3
  150. package/src/pipeline/event-dispatcher.ts +27 -1
  151. package/src/pipeline/multi-stream-apply-context.ts +4 -42
  152. package/src/pipeline/system-hooks.ts +7 -0
  153. package/src/rate-limit/resolver.ts +10 -30
  154. package/src/search/types.ts +1 -39
  155. package/src/secrets/__tests__/envelope-cipher.test.ts +2 -30
  156. package/src/secrets/__tests__/envelope.test.ts +1 -1
  157. package/src/secrets/envelope-cipher.ts +17 -45
  158. package/src/secrets/types.ts +2 -177
  159. package/src/stack/__tests__/event-collector.test.ts +42 -0
  160. package/src/testing/__tests__/late-bound.test.ts +25 -0
  161. package/src/testing/__tests__/wait-for.test.ts +53 -0
  162. package/src/testing/boot-validator-fixture.ts +1 -1
  163. package/src/testing/file-provider-contract.ts +84 -0
  164. package/src/testing/handler-context.ts +1 -1
  165. package/src/testing/index.ts +1 -0
  166. package/src/time/geo-tz.ts +1 -32
  167. package/src/time/tz-context.ts +9 -56
  168. package/src/ui-types/index.ts +7 -7
@@ -1,165 +1,2 @@
1
- import type { DbRunner } from "../../db/connection";
2
- import type { TableColumns } from "../../db/dialect";
3
- import type { StoredEvent } from "../../event-store/event-store";
4
- import type { MultiStreamApplyContext } from "../../pipeline/multi-stream-apply-context";
5
- import type { RunIn } from "./config";
6
- import type { EntityDefinition } from "./fields";
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 Drizzle's own `PgTableWithColumns<any>`
11
- // (re-exported as TableColumns) keeps typing honest: drizzle's typed paths work
12
- // inside apply(), but the column union is erased so framework code doesn't need
13
- // to know the schema shape of every user table.
14
- // biome-ignore lint/suspicious/noExplicitAny: Drizzle's PgTable generic needs a concrete row shape; we erase it on purpose because the framework does not know user-defined column types.
15
- export type ProjectionTable = TableColumns<any>;
16
-
17
- // Single-stream projection apply: runs inline in the write-TX of the event
18
- // it projects. Gets the event, the TX-scoped DbRunner, and the projection's
19
- // own `table` (already erased to ProjectionTable). Write through THAT table —
20
- // it is the only ES-blessed write into a managed projection outside the
21
- // executor, and it is reachable only here (an arbitrary handler has no such
22
- // arg), so the write-brand cannot be bypassed by closing over the branded
23
- // table constant. Inline projections must not spawn further events (no ctx)
24
- // because they run inside the command's transaction and the framework
25
- // guarantees a single commit boundary per command.
26
- //
27
- // Generic über payload-shape. Default = Record<string, unknown> behält
28
- // rückwärtskompatibles Verhalten; Konkrete Apply-Handler annotieren
29
- // `SingleStreamApplyFn<MyPayload>` für typed event.payload-Access. Der
30
- // `table`-Param ist additiv — 2-arg-Applies (event, tx) bleiben gültig.
31
- export type SingleStreamApplyFn<TPayload = Record<string, unknown>> = (
32
- event: StoredEvent<TPayload>,
33
- tx: DbRunner,
34
- table: ProjectionTable,
35
- ) => Promise<void>;
36
-
37
- // Multi-stream projection apply: runs asynchronously via the event-dispatcher
38
- // with its own cursor. Gets the event, tx, and a ctx surface for emitting
39
- // follow-up events (saga / process-manager pattern). ctx.appendEvent +
40
- // ctx.loadAggregate are the Marten-equivalent of IProjectionSession — write
41
- // cross-aggregate reactions here, not in single-stream projections.
42
- export type MultiStreamApplyFn<TPayload = Record<string, unknown>> = (
43
- event: StoredEvent<TPayload>,
44
- tx: DbRunner,
45
- ctx: MultiStreamApplyContext,
46
- ) => Promise<void>;
47
-
48
- export type ProjectionDefinition = {
49
- readonly name: string;
50
- // One or more entity names whose events feed this projection. Event-types
51
- // are matched in `apply` (e.g. "unit.created") — `source` is only used to
52
- // index projections so the executor doesn't scan all projections on every
53
- // write.
54
- readonly source: string | readonly string[];
55
- // Additional aggregate-types whose events the rebuild replay must include
56
- // beyond `source`. Fed by r.extendEntityProjection — an extension can react
57
- // to events on foreign streams (e.g. "field-definition") while `source`
58
- // keeps meaning "the owning entity" for consumers like soft-delete-cleanup.
59
- readonly extraSources?: readonly string[];
60
- // Drizzle-table the projection materializes into. User owns the schema —
61
- // framework just guarantees the TX and event delivery.
62
- readonly table: ProjectionTable;
63
- // Optional: the EntityDefinition the table was built from, for projections
64
- // without an r.entity registration — lets boot-time GDPR guards see
65
- // pii/tenantOwned fields that feature.entities (r.entity-only) would miss.
66
- readonly entity?: EntityDefinition;
67
- // Keyed by fully-qualified event type ("<aggregate>.<verb>", e.g. "unit.created").
68
- // Missing keys are silently skipped — a projection declares only the events it
69
- // cares about.
70
- readonly apply: Readonly<Record<string, SingleStreamApplyFn>>;
71
- // Auto-registered projection (one per r.entity) that exists ONLY to
72
- // make rebuildProjection work for entity-tables. Live writes go through
73
- // the EventStoreExecutor directly — firing the implicit apply inline
74
- // would double-write into the same table. The inline-projection-runner
75
- // skips entries with this flag; rebuildProjection treats them
76
- // identically to explicit projections.
77
- readonly isImplicit?: boolean;
78
- };
79
-
80
- // Extension merged into an entity's implicit projection at registry build.
81
- // Lets a bundled feature that writes into the HOST entity's table via events
82
- // (custom-fields pattern) hook those event types into the entity's rebuild
83
- // replay — without it, a rebuild resets everything the extension wrote.
84
- // Live delivery stays with the extension's own MSP: implicit projections are
85
- // skipped by the inline runner, so the apply here runs ONLY during rebuild.
86
- export type EntityProjectionExtension = {
87
- // Aggregate-types beyond the entity's own stream whose events the rebuild
88
- // must scan (e.g. "field-definition"). Omit when all extension events are
89
- // appended on the host entity's stream.
90
- readonly sources?: readonly string[];
91
- // Keyed by fully-qualified event type. Must not collide with the entity's
92
- // built-in lifecycle applies (<entity>.created/updated/...) or another
93
- // extension — collisions fail at boot.
94
- readonly apply: Readonly<Record<string, SingleStreamApplyFn>>;
95
- };
96
-
97
- // Per-lifecycle error policy for a MultiStreamProjection. Mirrors Marten's
98
- // Projections.Errors / Projections.RebuildErrors split — a projection can
99
- // be lenient during steady-state delivery but strict during rebuild (or
100
- // vice versa).
101
- export type MspErrorPolicy = {
102
- // When the apply handler throws: log the error, advance the cursor past
103
- // the offending event, and keep delivering. Default false — current
104
- // strict behaviour: retry up to maxAttempts, then mark the consumer
105
- // status="dead" and pause delivery. Use for best-effort sinks
106
- // (notifications, webhooks) where a single bad event should not stall
107
- // the whole consumer.
108
- readonly skipApplyErrors?: boolean;
109
- };
110
-
111
- export type MspErrorMode = {
112
- // Applied during steady-state dispatcher delivery.
113
- readonly continuous?: MspErrorPolicy;
114
- // Applied during rebuildProjection() / backfill passes. When omitted,
115
- // rebuild inherits continuous — explicit override common for "strict
116
- // during rebuild, lenient in production" patterns.
117
- readonly rebuild?: MspErrorPolicy;
118
- };
119
-
120
- // Marten-style MultiStreamProjection: aggregates events from many streams
121
- // into one cross-cutting read-model. Unlike ProjectionDefinition (single-
122
- // source, inline in the write-TX), an MSP is ASYNC — the event-dispatcher
123
- // picks events off the log via its own cursor. Handlers MUST be idempotent
124
- // because the dispatcher guarantees at-least-once delivery.
125
- //
126
- // Use for Sagas / process managers, customer-centric views that span
127
- // multiple aggregate types, cross-feature aggregations, audit logs. With
128
- // `table` omitted, the MSP becomes a pure side-effect consumer — sending
129
- // notifications, posting webhooks, updating an external system. Marten's
130
- // equivalent of a subscription / event listener, without a separate API.
131
- export type MultiStreamProjectionDefinition = {
132
- readonly name: string;
133
- // Optional: omit for side-effect-only handlers (notifications, external
134
- // system sync). When present, setupTestStack auto-pushes the table.
135
- readonly table?: ProjectionTable;
136
- // Keyed by fully-qualified event type. Unlike a single-stream projection,
137
- // there is no source-entity hint — the MSP declares the event types it
138
- // cares about directly. Extract the identity/grouping key inside the
139
- // apply handler from the event payload.
140
- readonly apply: Readonly<Record<string, MultiStreamApplyFn>>;
141
- // How the dispatcher handles apply-throws. Default strict (retry + dead).
142
- readonly errorMode?: MspErrorMode;
143
- // Which deploy-lane runs this MSP's dispatcher. Default "worker". MSPs
144
- // share a single consumer-row per MSP name with SKIP LOCKED, so "both"
145
- // is safe semantically (API + Worker race for each event; exactly one
146
- // wins). Use "api" for MSPs that need in-process state on the API
147
- // (rare); use "both" only when genuinely load-balancing is helpful.
148
- readonly runIn?: RunIn;
149
- // Delivery semantics across multi-instance deploys:
150
- // "shared" (default) — one cursor across all dispatcher instances,
151
- // SKIP LOCKED serialises; each event delivered exactly
152
- // once globally. The right choice for side-effects with
153
- // any downstream state: notifications, external APIs,
154
- // projection tables, audit rows.
155
- // "per-instance" — one cursor PER dispatcher instance, so every process
156
- // delivers every event. Required for push-to-local-
157
- // subscribers (SSE, in-memory caches): a split-deploy
158
- // where API instance B emits an event that API instance
159
- // A's clients also need to see. Handler MUST be
160
- // side-effect-free relative to the DB — it only reaches
161
- // in-process structures — otherwise each instance
162
- // writes duplicate rows. Misuse = duplicated side
163
- // effects, not a safety property.
164
- readonly delivery?: "shared" | "per-instance";
165
- };
1
+ // Legacy path re-exported for callers still importing this module directly.
2
+ export * from "@cosmicdrift/kumiko-types/projection";
@@ -1,51 +1 @@
1
- import type { OnDeleteStrategy } from "../constants";
2
-
3
- // --- Relations ---
4
-
5
- export type BelongsToRelation = {
6
- readonly type: "belongsTo";
7
- readonly target: string;
8
- readonly foreignKey: string;
9
- readonly searchInclude?: readonly string[];
10
- // onDelete is declared on the parent-side (hasMany / manyToMany) because
11
- // that's where the "what happens to my children?" decision lives. A
12
- // belongsTo node just points at a parent — the parent's onDelete drives
13
- // the cleanup.
14
- };
15
-
16
- export type HasManyRelation = {
17
- readonly type: "hasMany";
18
- readonly target: string;
19
- readonly foreignKey: string;
20
- readonly onDelete?: OnDeleteStrategy;
21
- // When true, a nested payload under this relation's key (e.g.
22
- // `{ tasks: [{ ... }] }` on a `project:create` write) is auto-expanded
23
- // into child writes: parent first, then one child-write per entry with
24
- // the foreign key set to the parent's new id — all in the same TX.
25
- // Opt-in (default false) so legacy hasMany relations that were declared
26
- // purely for cascade-delete or UI-nav semantics don't silently gain a
27
- // client-writable path. Children are never inferred from payload-shape
28
- // alone; only relations with this flag unlock nested-write.
29
- //
30
- // Scope v1: depth=1, create-only, hasMany-only. Update-nested,
31
- // delete-nested, and belongsTo/m2m auto-expansion are explicit future
32
- // work — when they arrive, they'll take the same flag so the opt-in
33
- // stays a single, consistent surface.
34
- readonly nestedWrite?: boolean;
35
- };
36
-
37
- export type ManyToManyRelation = {
38
- readonly type: "manyToMany";
39
- readonly target: string;
40
- readonly through: {
41
- readonly table: string;
42
- readonly sourceKey: string;
43
- readonly targetKey: string;
44
- };
45
- readonly searchInclude?: readonly string[];
46
- readonly onDelete?: OnDeleteStrategy;
47
- };
48
-
49
- export type RelationDefinition = BelongsToRelation | HasManyRelation | ManyToManyRelation;
50
-
51
- export type EntityRelations = Readonly<Record<string, RelationDefinition>>;
1
+ export * from "@cosmicdrift/kumiko-types/relations";