@cosmicdrift/kumiko-framework 0.2.3 → 0.4.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 +93 -0
- package/package.json +124 -39
- 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/compliance/profiles.ts +8 -8
- 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 +3 -5
- package/src/db/tenant-db.ts +9 -9
- package/src/engine/__tests__/_pipeline-test-utils.ts +23 -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 -1804
- 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 +88 -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/factories.ts +12 -12
- 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 +7 -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 +49 -1
- package/src/engine/feature-ast/render.ts +17 -1
- package/src/engine/index.ts +44 -2
- package/src/engine/pattern-library/__tests__/library.test.ts +6 -0
- package/src/engine/pattern-library/library.ts +42 -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 +2 -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 +93 -1
- package/src/engine/types/handlers.ts +18 -10
- package/src/engine/types/index.ts +11 -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 +132 -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/file-routes.ts +1 -1
- package/src/files/types.ts +2 -2
- 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 -2602
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,98 @@
|
|
|
1
1
|
# @cosmicdrift/kumiko-framework
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 825e7d2: Visual-Tree V.1.4 → V.1.6 — Feature-complete Editor + Folder-Hierarchy + Roving-tabindex.
|
|
8
|
+
|
|
9
|
+
**V.1.4** — explicit `folder?: string` Schema-Field auf text-block-entity. Slug bleibt
|
|
10
|
+
kebab-only validiert, Folder explizit gesetzt. Tree gruppiert via `groupBlocksByFolder`
|
|
11
|
+
(ersetzt `groupBlocksBySlugPrefix`). `Subscribe<T>` Signature um optional `emitError`
|
|
12
|
+
erweitert für explicit async-error-Pfade. ProviderBranch zeigt Error-Banner mit
|
|
13
|
+
Retry-Button. Drift-Test pinnt seedTextBlock-vs-set.write Slug-Validation.
|
|
14
|
+
|
|
15
|
+
**V.1.4b** — URL-State-Routing für Editor-Target via `nav.searchParams`. F5 + Back-Button
|
|
16
|
+
stellen den Editor-State wieder her. Format: `?t=text-content:edit&a_slug=...&a_lang=...`.
|
|
17
|
+
Plus `useDispatchTarget` hook ersetzt globalen `dispatchTarget` als empfohlenen Production-
|
|
18
|
+
Pfad (legacy bleibt für Test-Hooks).
|
|
19
|
+
|
|
20
|
+
**V.1.5** — Arrow-Key-Navigation (`<aside role="tree">`, ARIA-tree-Pattern) + SSE-driven
|
|
21
|
+
Tree-Refresh. `ClientFeatureDefinition.treeEntities?: string[]` listet Entity-Namen pro
|
|
22
|
+
Provider; live-events triggern provider-re-mount → Stale-Tree-state="stub"→"filled"
|
|
23
|
+
flippt nach save automatisch.
|
|
24
|
+
|
|
25
|
+
**V.1.5c+d** — Active-Node-Highlight (explicit blue + 2px border-l + scrollIntoView),
|
|
26
|
+
VS-Code-Polish (compact spacing, focus-visible, folder-icon-color text-amber, indent-
|
|
27
|
+
guides per ancestor-depth), Folder-Wrapper für legal-pages ("📁 Legal" + slug-first
|
|
28
|
+
Verschachtelung) und text-content ("📁 Content").
|
|
29
|
+
|
|
30
|
+
**V.1.6** — Multi-level Folder-Splitting (`folder="page/marketing"` → nested folders,
|
|
31
|
+
walk-or-create-pattern, folder/leaf-collision-tolerant). Roving-tabindex (nur focused-
|
|
32
|
+
treeitem hat tabIndex=0, Tab cyclt aus dem Tree raus).
|
|
33
|
+
|
|
34
|
+
35/35 kumiko check PASS, 13/13 group-blocks + 22/22 text-content integration tests grün.
|
|
35
|
+
Browser + Keyboard lokal validated.
|
|
36
|
+
|
|
37
|
+
**Breaking**: `TreeContext` Type entfernt (V.1.2 SR2-Rip — war nie genutzt). Provider sind
|
|
38
|
+
session-bound: `TreeChildrenSubscribe = () => Subscribe<T>` statt `(ctx) => Subscribe<T>`.
|
|
39
|
+
|
|
40
|
+
**V.1.7-Followups**: useEffect-deps in VisualTree-focus-init (Performance), Cancellation-
|
|
41
|
+
Token in TreeProvider's fetch (emit-after-unmount-warning), inline-rename, drag-drop,
|
|
42
|
+
file-icons per slug-extension, parent-jump bei ArrowLeft auf collapsed-item.
|
|
43
|
+
|
|
44
|
+
## 0.3.0
|
|
45
|
+
|
|
46
|
+
### Minor Changes
|
|
47
|
+
|
|
48
|
+
- 0.3.0 bringt zwei neue Subsysteme (Step-Engine Tier-3 + Visual-Tree) plus
|
|
49
|
+
eine AST-Codemod-Pipeline als Vorarbeit für den L2-AI-Layer.
|
|
50
|
+
|
|
51
|
+
### Breaking Changes
|
|
52
|
+
|
|
53
|
+
- `skipTransitionGuard` → `unsafeSkipTransitionGuard` (Rename in
|
|
54
|
+
feature-ast + engine). Der `unsafe`-Prefix macht die Tragweite des
|
|
55
|
+
Casts sichtbar und ist konsistent zur `unsafeProjectionUpsert`- und
|
|
56
|
+
`r.rawTable`-Konvention. Migration: 1:1-Ersetzung, keine Verhaltens-Änderung.
|
|
57
|
+
|
|
58
|
+
### Features
|
|
59
|
+
|
|
60
|
+
- **Step-Engine M.4 — Tier-3 Workflow-Engine.** Neue Step-Vocabulary
|
|
61
|
+
`wait`, `waitForEvent`, `retry` ermöglicht persistierte Long-Running-Flows
|
|
62
|
+
über Job-Boundaries hinweg. Q7 Snapshot-at-Start hängt jedem Step-Run
|
|
63
|
+
einen SHA-256-Fingerprint des Aggregat-Zustands an, sodass Replays
|
|
64
|
+
deterministisch gegen den ursprünglichen Eingangszustand laufen.
|
|
65
|
+
- **Visual-Tree V.1.x — Tree-API + Editor-Panel.** Neue `VisualTree`-
|
|
66
|
+
Component plus TreeProvider-Pattern; erste TreeProviders für
|
|
67
|
+
`text-content` und `legal-pages` (CMS-light + Impressum/Privacy).
|
|
68
|
+
Fundament für den späteren No-Code-Designer (~3000 LOC, 98 Tests).
|
|
69
|
+
- **Codemod-Pipeline.** AST-basierte Patcher-Module für strukturelle
|
|
70
|
+
Feature-Edits — wird vom kommenden L2-AI-Layer als Tool-Surface
|
|
71
|
+
verwendet, ist aber eigenständig nutzbar für ts-morph-style Migrationen.
|
|
72
|
+
- **user-data-rights Sample-Recipe.** DSGVO Art. 15/17/18/20 vollständig
|
|
73
|
+
als Sample-Recipe (`samples/recipes/`) inklusive README — zeigt die
|
|
74
|
+
Export- und Forget-Pipeline gegen den `compliance-profiles`-Default
|
|
75
|
+
(`eu-dsgvo`).
|
|
76
|
+
|
|
77
|
+
### Fixes
|
|
78
|
+
|
|
79
|
+
- `tier-engine`: auto-default-tier-Hook benutzt jetzt `ctx.db.raw` für
|
|
80
|
+
Event-Store-Operationen (#37, vorher: stiller Bug, 22 Tage live).
|
|
81
|
+
- `engine`: unsafe-projection-upsert nutzt `as never` statt `as any` —
|
|
82
|
+
schmaler Cast-Surface, weniger Compiler-Knebel.
|
|
83
|
+
- `visual-tree`: runtime-isolation marker für client-konsumierte Files,
|
|
84
|
+
damit der Multi-Entry-Build den richtigen Bundle-Split bekommt.
|
|
85
|
+
- `feature-ast`: vollständiger `unsafeSkipTransitionGuard`-Rename (war
|
|
86
|
+
in zwei Modulen noch der alte Name).
|
|
87
|
+
- `framework`: Error-Reasons + `noConsole`-Lint + No-Date-API-Guard
|
|
88
|
+
wieder push-ready.
|
|
89
|
+
|
|
90
|
+
### Library-Updates
|
|
91
|
+
|
|
92
|
+
hono 4.12, jose 6.2, stripe 22.1, meilisearch 0.58, marked 18,
|
|
93
|
+
bun-types 1.3.13, lucide-react 1.14, bullmq 5.76, ioredis 5.10,
|
|
94
|
+
i18next 26.0, react + radix-ui-primitives auf aktuelle Minors.
|
|
95
|
+
|
|
3
96
|
## 0.2.3
|
|
4
97
|
|
|
5
98
|
## 0.2.2
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-framework",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Framework core — engine, pipeline, API, DB, and every other bit that makes Kumiko go.",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -28,56 +28,141 @@
|
|
|
28
28
|
"runtime": "runtime"
|
|
29
29
|
},
|
|
30
30
|
"exports": {
|
|
31
|
-
"./compliance":
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"./
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"./
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"./
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"./
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"./
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"./
|
|
56
|
-
|
|
57
|
-
|
|
31
|
+
"./compliance": {
|
|
32
|
+
"types": "./src/compliance/index.ts",
|
|
33
|
+
"default": "./src/compliance/index.ts"
|
|
34
|
+
},
|
|
35
|
+
"./engine": {
|
|
36
|
+
"types": "./src/engine/index.ts",
|
|
37
|
+
"default": "./src/engine/index.ts"
|
|
38
|
+
},
|
|
39
|
+
"./engine/types": {
|
|
40
|
+
"types": "./src/engine/types/index.ts",
|
|
41
|
+
"default": "./src/engine/types/index.ts"
|
|
42
|
+
},
|
|
43
|
+
"./engine/codemod": {
|
|
44
|
+
"types": "./src/engine/codemod/index.ts",
|
|
45
|
+
"default": "./src/engine/codemod/index.ts"
|
|
46
|
+
},
|
|
47
|
+
"./errors": {
|
|
48
|
+
"types": "./src/errors/index.ts",
|
|
49
|
+
"default": "./src/errors/index.ts"
|
|
50
|
+
},
|
|
51
|
+
"./db": {
|
|
52
|
+
"types": "./src/db/index.ts",
|
|
53
|
+
"default": "./src/db/index.ts"
|
|
54
|
+
},
|
|
55
|
+
"./event-store": {
|
|
56
|
+
"types": "./src/event-store/index.ts",
|
|
57
|
+
"default": "./src/event-store/index.ts"
|
|
58
|
+
},
|
|
59
|
+
"./event-store/admin-api": {
|
|
60
|
+
"types": "./src/event-store/admin-api.ts",
|
|
61
|
+
"default": "./src/event-store/admin-api.ts"
|
|
62
|
+
},
|
|
63
|
+
"./pipeline": {
|
|
64
|
+
"types": "./src/pipeline/index.ts",
|
|
65
|
+
"default": "./src/pipeline/index.ts"
|
|
66
|
+
},
|
|
67
|
+
"./api": {
|
|
68
|
+
"types": "./src/api/index.ts",
|
|
69
|
+
"default": "./src/api/index.ts"
|
|
70
|
+
},
|
|
71
|
+
"./i18n": {
|
|
72
|
+
"types": "./src/i18n/index.ts",
|
|
73
|
+
"default": "./src/i18n/index.ts"
|
|
74
|
+
},
|
|
75
|
+
"./auth": {
|
|
76
|
+
"types": "./src/auth/index.ts",
|
|
77
|
+
"default": "./src/auth/index.ts"
|
|
78
|
+
},
|
|
79
|
+
"./files": {
|
|
80
|
+
"types": "./src/files/index.ts",
|
|
81
|
+
"default": "./src/files/index.ts"
|
|
82
|
+
},
|
|
83
|
+
"./jobs": {
|
|
84
|
+
"types": "./src/jobs/index.ts",
|
|
85
|
+
"default": "./src/jobs/index.ts"
|
|
86
|
+
},
|
|
87
|
+
"./migrations": {
|
|
88
|
+
"types": "./src/migrations/index.ts",
|
|
89
|
+
"default": "./src/migrations/index.ts"
|
|
90
|
+
},
|
|
91
|
+
"./entrypoint": {
|
|
92
|
+
"types": "./src/entrypoint/index.ts",
|
|
93
|
+
"default": "./src/entrypoint/index.ts"
|
|
94
|
+
},
|
|
95
|
+
"./random": {
|
|
96
|
+
"types": "./src/random/index.ts",
|
|
97
|
+
"default": "./src/random/index.ts"
|
|
98
|
+
},
|
|
99
|
+
"./redis": {
|
|
100
|
+
"types": "./src/redis/index.ts",
|
|
101
|
+
"default": "./src/redis/index.ts"
|
|
102
|
+
},
|
|
103
|
+
"./search": {
|
|
104
|
+
"types": "./src/search/index.ts",
|
|
105
|
+
"default": "./src/search/index.ts"
|
|
106
|
+
},
|
|
107
|
+
"./search/meilisearch": {
|
|
108
|
+
"types": "./src/search/meilisearch-adapter.ts",
|
|
109
|
+
"default": "./src/search/meilisearch-adapter.ts"
|
|
110
|
+
},
|
|
111
|
+
"./secrets": {
|
|
112
|
+
"types": "./src/secrets/index.ts",
|
|
113
|
+
"default": "./src/secrets/index.ts"
|
|
114
|
+
},
|
|
115
|
+
"./stack": {
|
|
116
|
+
"types": "./src/stack/index.ts",
|
|
117
|
+
"default": "./src/stack/index.ts"
|
|
118
|
+
},
|
|
119
|
+
"./testing": {
|
|
120
|
+
"types": "./src/testing/index.ts",
|
|
121
|
+
"default": "./src/testing/index.ts"
|
|
122
|
+
},
|
|
123
|
+
"./testing/handler-context": {
|
|
124
|
+
"types": "./src/testing/handler-context.ts",
|
|
125
|
+
"default": "./src/testing/handler-context.ts"
|
|
126
|
+
},
|
|
127
|
+
"./testing/e2e-generator": {
|
|
128
|
+
"types": "./src/testing/e2e-generator.ts",
|
|
129
|
+
"default": "./src/testing/e2e-generator.ts"
|
|
130
|
+
},
|
|
131
|
+
"./time": {
|
|
132
|
+
"types": "./src/time/index.ts",
|
|
133
|
+
"default": "./src/time/index.ts"
|
|
134
|
+
},
|
|
135
|
+
"./ui-types": {
|
|
136
|
+
"types": "./src/ui-types/index.ts",
|
|
137
|
+
"default": "./src/ui-types/index.ts"
|
|
138
|
+
},
|
|
139
|
+
"./utils": {
|
|
140
|
+
"types": "./src/utils/index.ts",
|
|
141
|
+
"default": "./src/utils/index.ts"
|
|
142
|
+
}
|
|
58
143
|
},
|
|
59
144
|
"dependencies": {
|
|
60
|
-
"bullmq": "^5.
|
|
61
|
-
"bun-types": "^1.3.
|
|
145
|
+
"bullmq": "^5.76.7",
|
|
146
|
+
"bun-types": "^1.3.13",
|
|
62
147
|
"drizzle-kit": "^0.31.10",
|
|
63
148
|
"drizzle-orm": "^0.45.2",
|
|
64
|
-
"hono": "^4.12.
|
|
65
|
-
"i18next": "^26.0
|
|
66
|
-
"ioredis": "^5.
|
|
67
|
-
"jose": "^6.
|
|
68
|
-
"meilisearch": "^0.
|
|
149
|
+
"hono": "^4.12.18",
|
|
150
|
+
"i18next": "^26.1.0",
|
|
151
|
+
"ioredis": "^5.10.1",
|
|
152
|
+
"jose": "^6.2.3",
|
|
153
|
+
"meilisearch": "^0.58.0",
|
|
69
154
|
"pino": "^10.3.1",
|
|
70
155
|
"postgres": "^3.4.9",
|
|
71
156
|
"temporal-polyfill": "^0.3.2",
|
|
72
157
|
"ts-morph": "^28.0.0",
|
|
73
158
|
"uuid": "^14.0.0",
|
|
74
|
-
"zod": "^4.3
|
|
159
|
+
"zod": "^4.4.3"
|
|
75
160
|
},
|
|
76
161
|
"devDependencies": {
|
|
77
|
-
"@cosmicdrift/kumiko-dispatcher-live": "0.
|
|
162
|
+
"@cosmicdrift/kumiko-dispatcher-live": "0.4.0",
|
|
78
163
|
"@types/uuid": "^11.0.0",
|
|
79
|
-
"bun-types": "^1.
|
|
80
|
-
"drizzle-kit": "^0.31.
|
|
164
|
+
"bun-types": "^1.3.13",
|
|
165
|
+
"drizzle-kit": "^0.31.10",
|
|
81
166
|
"pino-pretty": "^13.1.3"
|
|
82
167
|
},
|
|
83
168
|
"publishConfig": {
|
|
@@ -46,11 +46,11 @@ let USER_CREATED_EVENT: string;
|
|
|
46
46
|
const domainEventSubscriberCalls: Array<{ type: string; payload: unknown }> = [];
|
|
47
47
|
|
|
48
48
|
async function emitUserCreated(
|
|
49
|
-
ctx: Pick<HandlerContext, "
|
|
49
|
+
ctx: Pick<HandlerContext, "unsafeAppendEvent">,
|
|
50
50
|
id: EntityId,
|
|
51
51
|
email: string,
|
|
52
52
|
): Promise<void> {
|
|
53
|
-
await ctx.
|
|
53
|
+
await ctx.unsafeAppendEvent({
|
|
54
54
|
aggregateId: String(id),
|
|
55
55
|
aggregateType: "user",
|
|
56
56
|
type: USER_CREATED_EVENT,
|
package/src/api/auth-routes.ts
CHANGED
|
@@ -650,7 +650,7 @@ export function createAuthRoutes(
|
|
|
650
650
|
}
|
|
651
651
|
const result = await dispatcher.write(inv.acceptWithLoginHandler, parsed.data, GUEST_USER);
|
|
652
652
|
if (!result.isSuccess) {
|
|
653
|
-
const status = result.error.httpStatus as 400 | 401 | 403 | 422 | 500;
|
|
653
|
+
const status = result.error.httpStatus as 400 | 401 | 403 | 422 | 500; // @cast-boundary engine-payload
|
|
654
654
|
return c.json({ isSuccess: false, error: result.error }, status);
|
|
655
655
|
}
|
|
656
656
|
const data = result.data as {
|
|
@@ -658,7 +658,7 @@ export function createAuthRoutes(
|
|
|
658
658
|
session: SessionUser;
|
|
659
659
|
tenantId: TenantId;
|
|
660
660
|
role: string;
|
|
661
|
-
};
|
|
661
|
+
}; // @cast-boundary engine-payload
|
|
662
662
|
let sessionForJwt: SessionUser = data.session;
|
|
663
663
|
if (config.sessionCreator) {
|
|
664
664
|
const sid = await config.sessionCreator(data.session, requestMeta(c));
|
|
@@ -690,7 +690,7 @@ export function createAuthRoutes(
|
|
|
690
690
|
}
|
|
691
691
|
const result = await dispatcher.write(inv.signupCompleteHandler, parsed.data, GUEST_USER);
|
|
692
692
|
if (!result.isSuccess) {
|
|
693
|
-
const status = result.error.httpStatus as 400 | 401 | 403 | 422 | 500;
|
|
693
|
+
const status = result.error.httpStatus as 400 | 401 | 403 | 422 | 500; // @cast-boundary engine-payload
|
|
694
694
|
return c.json({ isSuccess: false, error: result.error }, status);
|
|
695
695
|
}
|
|
696
696
|
const data = result.data as {
|
|
@@ -698,7 +698,7 @@ export function createAuthRoutes(
|
|
|
698
698
|
session: SessionUser;
|
|
699
699
|
tenantId: TenantId;
|
|
700
700
|
role: string;
|
|
701
|
-
};
|
|
701
|
+
}; // @cast-boundary engine-payload
|
|
702
702
|
let sessionForJwt: SessionUser = data.session;
|
|
703
703
|
if (config.sessionCreator) {
|
|
704
704
|
const sid = await config.sessionCreator(data.session, requestMeta(c));
|
|
@@ -967,7 +967,7 @@ function registerTokenConfirmRoute(opts: {
|
|
|
967
967
|
}
|
|
968
968
|
const result = await opts.dispatcher.write(opts.confirmHandler, parsed.data, GUEST_USER);
|
|
969
969
|
if (!result.isSuccess) {
|
|
970
|
-
const status = result.error.httpStatus as 400 | 401 | 403 | 422 | 500;
|
|
970
|
+
const status = result.error.httpStatus as 400 | 401 | 403 | 422 | 500; // @cast-boundary engine-payload
|
|
971
971
|
return c.json({ isSuccess: false, error: result.error }, status);
|
|
972
972
|
}
|
|
973
973
|
return c.json({ isSuccess: true });
|
package/src/api/jwt.ts
CHANGED
|
@@ -50,8 +50,8 @@ export function createJwtHelper(secret: string, issuer = "kumiko"): JwtHelper {
|
|
|
50
50
|
const { payload } = await jose.jwtVerify(token, encodedSecret, { issuer });
|
|
51
51
|
const result: JwtPayload = {
|
|
52
52
|
sub: String(payload.sub),
|
|
53
|
-
tenantId: payload["tenantId"] as string,
|
|
54
|
-
roles: payload["roles"] as string[],
|
|
53
|
+
tenantId: payload["tenantId"] as string, // @cast-boundary dynamic-key
|
|
54
|
+
roles: payload["roles"] as string[], // @cast-boundary dynamic-key
|
|
55
55
|
};
|
|
56
56
|
const claims = payload["claims"];
|
|
57
57
|
if (claims && typeof claims === "object") {
|
|
@@ -68,7 +68,7 @@ function constantTimeEqual(a: string, b: string): boolean {
|
|
|
68
68
|
// Prometheus-compatible meter (future OTLP bridge) works without an
|
|
69
69
|
// explicit union — if it exposes `snapshot()` it's serialisable.
|
|
70
70
|
function isPrometheusMeter(m: Meter): m is PrometheusMeter {
|
|
71
|
-
return typeof (m as { snapshot?: unknown }).snapshot === "function";
|
|
71
|
+
return typeof (m as { snapshot?: unknown }).snapshot === "function"; // @cast-boundary schema-walk
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
// Mount `/metrics` (or the caller-supplied path). Takes just the Meter —
|
package/src/api/routes.ts
CHANGED
|
@@ -73,7 +73,7 @@ export function createApiRoutes(dispatcher: Dispatcher) {
|
|
|
73
73
|
failedIndex: result.failedIndex,
|
|
74
74
|
results: result.results,
|
|
75
75
|
},
|
|
76
|
-
err.httpStatus as ContentfulStatusCode,
|
|
76
|
+
err.httpStatus as ContentfulStatusCode, // @cast-boundary engine-payload
|
|
77
77
|
);
|
|
78
78
|
}
|
|
79
79
|
return c.json(result);
|
|
@@ -121,7 +121,7 @@ function toKumiko(e: unknown): KumikoError {
|
|
|
121
121
|
function writeErrorResponse(c: Context, err: KumikoError, statusOverride?: number) {
|
|
122
122
|
const requestId = requestContext.get()?.requestId;
|
|
123
123
|
const { error } = serializeError(err, requestId);
|
|
124
|
-
const status = (statusOverride ?? err.httpStatus) as ContentfulStatusCode;
|
|
124
|
+
const status = (statusOverride ?? err.httpStatus) as ContentfulStatusCode; // @cast-boundary engine-payload
|
|
125
125
|
return c.json({ isSuccess: false, error }, status);
|
|
126
126
|
}
|
|
127
127
|
|
|
@@ -130,6 +130,6 @@ function writeErrorResponse(c: Context, err: KumikoError, statusOverride?: numbe
|
|
|
130
130
|
function queryErrorResponse(c: Context, err: KumikoError, statusOverride?: number) {
|
|
131
131
|
const requestId = requestContext.get()?.requestId;
|
|
132
132
|
const body = serializeError(err, requestId);
|
|
133
|
-
const status = (statusOverride ?? err.httpStatus) as ContentfulStatusCode;
|
|
133
|
+
const status = (statusOverride ?? err.httpStatus) as ContentfulStatusCode; // @cast-boundary engine-payload
|
|
134
134
|
return c.json(body, status);
|
|
135
135
|
}
|
package/src/api/server.ts
CHANGED
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
globalIpRateLimit,
|
|
43
43
|
} from "../rate-limit";
|
|
44
44
|
import type { SearchAdapter } from "../search/types";
|
|
45
|
-
import { generateId } from "../utils";
|
|
45
|
+
import { assertUnreachable, generateId } from "../utils";
|
|
46
46
|
import { PUBLIC_API_PATHS } from "./api-constants";
|
|
47
47
|
import { type AnonymousAccessConfig, authMiddleware } from "./auth-middleware";
|
|
48
48
|
import { type AuthRoutesConfig, createAuthRoutes } from "./auth-routes";
|
|
@@ -383,7 +383,7 @@ export function buildServer(options: ServerOptions): KumikoServer {
|
|
|
383
383
|
// can pause this consumer when the feature is globally disabled. Events
|
|
384
384
|
// queue up in the store and replay cleanly from the same cursor on resume.
|
|
385
385
|
...(options.registry.getMultiStreamProjectionFeature(msp.name) && {
|
|
386
|
-
featureName: options.registry.getMultiStreamProjectionFeature(msp.name) as string,
|
|
386
|
+
featureName: options.registry.getMultiStreamProjectionFeature(msp.name) as string, // @cast-boundary engine-bridge
|
|
387
387
|
}),
|
|
388
388
|
// Copy the continuous-lifecycle error policy straight onto the consumer.
|
|
389
389
|
// Rebuild uses its own policy (rebuildProjection reads msp.errorMode.rebuild
|
|
@@ -409,10 +409,7 @@ export function buildServer(options: ServerOptions): KumikoServer {
|
|
|
409
409
|
// Hand the raw DbRunner to apply(): MSPs write to their projection
|
|
410
410
|
// table directly, they don't go through the TenantDb wrapper.
|
|
411
411
|
const rawRunner =
|
|
412
|
-
event.tenantId === SYSTEM_TENANT_ID
|
|
413
|
-
? baseDb
|
|
414
|
-
: // @cast-boundary engine-bridge — TenantDb exposes its raw DbRunner via .raw
|
|
415
|
-
(scopedDb as { raw: typeof baseDb }).raw;
|
|
412
|
+
event.tenantId === SYSTEM_TENANT_ID ? baseDb : (scopedDb as { raw: typeof baseDb }).raw; // @cast-boundary engine-bridge
|
|
416
413
|
// Saga/process-manager ctx: apply can call ctx.appendEvent to cascade
|
|
417
414
|
// a follow-up event onto another aggregate. Uses the triggering event's
|
|
418
415
|
// tenantId + userId so the causal chain stays tenant-consistent.
|
|
@@ -563,7 +560,7 @@ export function buildServer(options: ServerOptions): KumikoServer {
|
|
|
563
560
|
app.route("/api", createSseRoute(sseBroker));
|
|
564
561
|
|
|
565
562
|
if (options.files) {
|
|
566
|
-
const fileDb = options.files.db ?? (options.context.db as FileRoutesOptions["db"]);
|
|
563
|
+
const fileDb = options.files.db ?? (options.context.db as FileRoutesOptions["db"]); // @cast-boundary engine-bridge
|
|
567
564
|
if (!fileDb) throw new Error("files option requires db in context or files.db");
|
|
568
565
|
app.route(
|
|
569
566
|
"/api",
|
|
@@ -605,6 +602,8 @@ export function buildServer(options: ServerOptions): KumikoServer {
|
|
|
605
602
|
// Hono-on() für die Methoden ohne Convenience-Method.
|
|
606
603
|
app.on(route.method, route.path, honoHandler);
|
|
607
604
|
break;
|
|
605
|
+
default:
|
|
606
|
+
assertUnreachable(route.method, "http method");
|
|
608
607
|
}
|
|
609
608
|
}
|
|
610
609
|
}
|
|
@@ -243,7 +243,7 @@ const RAW_PROFILES: Readonly<Record<ComplianceProfileKey, ComplianceProfileRaw>>
|
|
|
243
243
|
},
|
|
244
244
|
tenantDestroyGracePeriod: { days: 30 },
|
|
245
245
|
},
|
|
246
|
-
}
|
|
246
|
+
} satisfies Readonly<Record<ComplianceProfileKey, ComplianceProfileRaw>>;
|
|
247
247
|
|
|
248
248
|
// Raw-Profile (vor extends-Resolution) — `extends`-Profile dürfen
|
|
249
249
|
// Required-Felder weglassen, sie kommen vom Base-Profile dazu.
|
|
@@ -262,11 +262,11 @@ type ComplianceProfileRaw = Partial<Omit<ComplianceProfile, "key" | "region" | "
|
|
|
262
262
|
* Default-Fallback fuer "noch keine Wahl getroffen", mit sichtbarer
|
|
263
263
|
* Warning. Production-Tenants sollen ein echtes Profile waehlen.
|
|
264
264
|
*/
|
|
265
|
-
export const SELECTABLE_PROFILE_KEYS
|
|
265
|
+
export const SELECTABLE_PROFILE_KEYS = [
|
|
266
266
|
"eu-dsgvo",
|
|
267
267
|
"swiss-dsg",
|
|
268
268
|
"de-hr-dsgvo-hgb",
|
|
269
|
-
];
|
|
269
|
+
] as const satisfies readonly ComplianceProfileKey[];
|
|
270
270
|
|
|
271
271
|
/**
|
|
272
272
|
* Top-Level-Properties des `ComplianceProfile`-Type, die ein Tenant-
|
|
@@ -339,7 +339,7 @@ function deepMerge<T extends Record<string, unknown>>(
|
|
|
339
339
|
out[k] = v;
|
|
340
340
|
}
|
|
341
341
|
}
|
|
342
|
-
return out as T;
|
|
342
|
+
return out as T; // @cast-boundary generic-record
|
|
343
343
|
}
|
|
344
344
|
|
|
345
345
|
/**
|
|
@@ -355,7 +355,7 @@ function deepMerge<T extends Record<string, unknown>>(
|
|
|
355
355
|
function resolveExtends(key: ComplianceProfileKey): ComplianceProfile {
|
|
356
356
|
const raw = RAW_PROFILES[key];
|
|
357
357
|
if (!raw.extends) {
|
|
358
|
-
return raw as ComplianceProfile;
|
|
358
|
+
return raw as ComplianceProfile; // @cast-boundary schema-walk
|
|
359
359
|
}
|
|
360
360
|
|
|
361
361
|
const base = RAW_PROFILES[raw.extends];
|
|
@@ -366,7 +366,7 @@ function resolveExtends(key: ComplianceProfileKey): ComplianceProfile {
|
|
|
366
366
|
}
|
|
367
367
|
|
|
368
368
|
return deepMerge(
|
|
369
|
-
base as Record<string, unknown>,
|
|
369
|
+
base as Record<string, unknown>, // @cast-boundary generic-record
|
|
370
370
|
raw as unknown as Record<string, unknown>,
|
|
371
371
|
) as unknown as ComplianceProfile;
|
|
372
372
|
}
|
|
@@ -379,7 +379,7 @@ function resolveExtends(key: ComplianceProfileKey): ComplianceProfile {
|
|
|
379
379
|
export const COMPLIANCE_PROFILES: Readonly<Record<ComplianceProfileKey, ComplianceProfile>> =
|
|
380
380
|
Object.fromEntries(
|
|
381
381
|
(Object.keys(RAW_PROFILES) as ComplianceProfileKey[]).map((k) => [k, resolveExtends(k)]),
|
|
382
|
-
) as Readonly<Record<ComplianceProfileKey, ComplianceProfile>>;
|
|
382
|
+
) as Readonly<Record<ComplianceProfileKey, ComplianceProfile>>; // @cast-boundary dynamic-key
|
|
383
383
|
|
|
384
384
|
// --- Effective-Profile-Resolver ---
|
|
385
385
|
|
|
@@ -421,7 +421,7 @@ export function resolveComplianceProfile(args: {
|
|
|
421
421
|
|
|
422
422
|
const merged = deepMerge(
|
|
423
423
|
base as unknown as Record<string, unknown>,
|
|
424
|
-
args.override as Record<string, unknown>,
|
|
424
|
+
args.override as Record<string, unknown>, // @cast-boundary engine-payload
|
|
425
425
|
) as unknown as ComplianceProfile;
|
|
426
426
|
return { profile: merged };
|
|
427
427
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
1
|
import { and, eq, type SQL } from "drizzle-orm";
|
|
2
|
+
import type { TenantId } from "../engine/types/identifiers";
|
|
3
3
|
import { NotFoundError } from "../errors";
|
|
4
4
|
import type { DbConnection } from "./connection";
|
|
5
5
|
import type { TenantDb } from "./tenant-db";
|
|
@@ -43,7 +43,7 @@ export async function assertExistsIn(
|
|
|
43
43
|
const [row] = await db
|
|
44
44
|
.select()
|
|
45
45
|
.from(entity)
|
|
46
|
-
.where(and(...conditions) as SQL);
|
|
46
|
+
.where(and(...conditions) as SQL); // @cast-boundary db-operator
|
|
47
47
|
|
|
48
48
|
if (!row) {
|
|
49
49
|
const entityName = options.entityName ?? String(options.field).replace(/Id$/, "");
|
package/src/db/cursor.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { EntityId, TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
1
|
import { and, asc, desc, eq, gt, inArray, type SQL, sql } from "drizzle-orm";
|
|
2
|
+
import type { EntityId, TenantId } from "../engine/types/identifiers";
|
|
3
3
|
import type { SelectQuery as PgSelect } from "./dialect";
|
|
4
4
|
|
|
5
5
|
export type CursorQueryOptions = {
|
|
@@ -61,7 +61,7 @@ export function applyCursorQuery<T extends PgSelect>(
|
|
|
61
61
|
// werfen.
|
|
62
62
|
conditions.push(sql`false`);
|
|
63
63
|
} else {
|
|
64
|
-
conditions.push(inArray(table.id, options.filterIds as readonly string[]));
|
|
64
|
+
conditions.push(inArray(table.id, options.filterIds as readonly string[])); // @cast-boundary db-operator
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
@@ -79,5 +79,5 @@ export function applyCursorQuery<T extends PgSelect>(
|
|
|
79
79
|
options.sortDirection === "desc" ? result.orderBy(desc(column)) : result.orderBy(asc(column));
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
return result as T;
|
|
82
|
+
return result as T; // @cast-boundary engine-bridge
|
|
83
83
|
}
|