@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
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,59 @@
|
|
|
1
1
|
# @cosmicdrift/kumiko-framework
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 0.3.0 bringt zwei neue Subsysteme (Step-Engine Tier-3 + Visual-Tree) plus
|
|
8
|
+
eine AST-Codemod-Pipeline als Vorarbeit für den L2-AI-Layer.
|
|
9
|
+
|
|
10
|
+
### Breaking Changes
|
|
11
|
+
|
|
12
|
+
- `skipTransitionGuard` → `unsafeSkipTransitionGuard` (Rename in
|
|
13
|
+
feature-ast + engine). Der `unsafe`-Prefix macht die Tragweite des
|
|
14
|
+
Casts sichtbar und ist konsistent zur `unsafeProjectionUpsert`- und
|
|
15
|
+
`r.rawTable`-Konvention. Migration: 1:1-Ersetzung, keine Verhaltens-Änderung.
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
- **Step-Engine M.4 — Tier-3 Workflow-Engine.** Neue Step-Vocabulary
|
|
20
|
+
`wait`, `waitForEvent`, `retry` ermöglicht persistierte Long-Running-Flows
|
|
21
|
+
über Job-Boundaries hinweg. Q7 Snapshot-at-Start hängt jedem Step-Run
|
|
22
|
+
einen SHA-256-Fingerprint des Aggregat-Zustands an, sodass Replays
|
|
23
|
+
deterministisch gegen den ursprünglichen Eingangszustand laufen.
|
|
24
|
+
- **Visual-Tree V.1.x — Tree-API + Editor-Panel.** Neue `VisualTree`-
|
|
25
|
+
Component plus TreeProvider-Pattern; erste TreeProviders für
|
|
26
|
+
`text-content` und `legal-pages` (CMS-light + Impressum/Privacy).
|
|
27
|
+
Fundament für den späteren No-Code-Designer (~3000 LOC, 98 Tests).
|
|
28
|
+
- **Codemod-Pipeline.** AST-basierte Patcher-Module für strukturelle
|
|
29
|
+
Feature-Edits — wird vom kommenden L2-AI-Layer als Tool-Surface
|
|
30
|
+
verwendet, ist aber eigenständig nutzbar für ts-morph-style Migrationen.
|
|
31
|
+
- **user-data-rights Sample-Recipe.** DSGVO Art. 15/17/18/20 vollständig
|
|
32
|
+
als Sample-Recipe (`samples/recipes/`) inklusive README — zeigt die
|
|
33
|
+
Export- und Forget-Pipeline gegen den `compliance-profiles`-Default
|
|
34
|
+
(`eu-dsgvo`).
|
|
35
|
+
|
|
36
|
+
### Fixes
|
|
37
|
+
|
|
38
|
+
- `tier-engine`: auto-default-tier-Hook benutzt jetzt `ctx.db.raw` für
|
|
39
|
+
Event-Store-Operationen (#37, vorher: stiller Bug, 22 Tage live).
|
|
40
|
+
- `engine`: unsafe-projection-upsert nutzt `as never` statt `as any` —
|
|
41
|
+
schmaler Cast-Surface, weniger Compiler-Knebel.
|
|
42
|
+
- `visual-tree`: runtime-isolation marker für client-konsumierte Files,
|
|
43
|
+
damit der Multi-Entry-Build den richtigen Bundle-Split bekommt.
|
|
44
|
+
- `feature-ast`: vollständiger `unsafeSkipTransitionGuard`-Rename (war
|
|
45
|
+
in zwei Modulen noch der alte Name).
|
|
46
|
+
- `framework`: Error-Reasons + `noConsole`-Lint + No-Date-API-Guard
|
|
47
|
+
wieder push-ready.
|
|
48
|
+
|
|
49
|
+
### Library-Updates
|
|
50
|
+
|
|
51
|
+
hono 4.12, jose 6.2, stripe 22.1, meilisearch 0.58, marked 18,
|
|
52
|
+
bun-types 1.3.13, lucide-react 1.14, bullmq 5.76, ioredis 5.10,
|
|
53
|
+
i18next 26.0, react + radix-ui-primitives auf aktuelle Minors.
|
|
54
|
+
|
|
55
|
+
## 0.2.3
|
|
56
|
+
|
|
3
57
|
## 0.2.2
|
|
4
58
|
|
|
5
59
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-framework",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.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,55 +28,141 @@
|
|
|
28
28
|
"runtime": "runtime"
|
|
29
29
|
},
|
|
30
30
|
"exports": {
|
|
31
|
-
"./
|
|
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
|
-
|
|
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
|
+
}
|
|
57
143
|
},
|
|
58
144
|
"dependencies": {
|
|
59
|
-
"bullmq": "^5.
|
|
60
|
-
"bun-types": "^1.3.
|
|
145
|
+
"bullmq": "^5.76.7",
|
|
146
|
+
"bun-types": "^1.3.13",
|
|
61
147
|
"drizzle-kit": "^0.31.10",
|
|
62
148
|
"drizzle-orm": "^0.45.2",
|
|
63
|
-
"hono": "^4.12.
|
|
64
|
-
"i18next": "^26.0
|
|
65
|
-
"ioredis": "^5.
|
|
66
|
-
"jose": "^6.
|
|
67
|
-
"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",
|
|
68
154
|
"pino": "^10.3.1",
|
|
69
155
|
"postgres": "^3.4.9",
|
|
70
156
|
"temporal-polyfill": "^0.3.2",
|
|
71
157
|
"ts-morph": "^28.0.0",
|
|
72
158
|
"uuid": "^14.0.0",
|
|
73
|
-
"zod": "^4.3
|
|
159
|
+
"zod": "^4.4.3"
|
|
74
160
|
},
|
|
75
161
|
"devDependencies": {
|
|
76
|
-
"@cosmicdrift/kumiko-dispatcher-live": "0.
|
|
162
|
+
"@cosmicdrift/kumiko-dispatcher-live": "0.3.0",
|
|
77
163
|
"@types/uuid": "^11.0.0",
|
|
78
|
-
"bun-types": "^1.
|
|
79
|
-
"drizzle-kit": "^0.31.
|
|
164
|
+
"bun-types": "^1.3.13",
|
|
165
|
+
"drizzle-kit": "^0.31.10",
|
|
80
166
|
"pino-pretty": "^13.1.3"
|
|
81
167
|
},
|
|
82
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
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Snapshot-Tests fuer ROLES — faengt stille Drift ab.
|
|
2
|
+
|
|
3
|
+
import { describe, expect, test } from "vitest";
|
|
4
|
+
import { ROLES } from "../roles";
|
|
5
|
+
|
|
6
|
+
describe("ROLES constants", () => {
|
|
7
|
+
test("Snapshot — explizit zu updaten bei Aenderungen", () => {
|
|
8
|
+
expect(ROLES).toMatchInlineSnapshot(`
|
|
9
|
+
{
|
|
10
|
+
"DataProtectionOfficer": "DataProtectionOfficer",
|
|
11
|
+
"Member": "Member",
|
|
12
|
+
"SystemAdmin": "SystemAdmin",
|
|
13
|
+
"TenantAdmin": "TenantAdmin",
|
|
14
|
+
"TenantOwner": "TenantOwner",
|
|
15
|
+
}
|
|
16
|
+
`);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test("ROLES-Werte sind identisch zu den Keys (keine Drift im Mapping)", () => {
|
|
20
|
+
for (const [key, value] of Object.entries(ROLES)) {
|
|
21
|
+
expect(value).toBe(key);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// `@cosmicdrift/kumiko-framework/auth` — Auth-Foundation (Roles, Token-
|
|
2
|
+
// Helpers, Session-Types). Wird von Bundled-Features (auth-email-password,
|
|
3
|
+
// tenant, user) und Datenschutz-Sprints (S1+ user-data-rights, S5 tenant-
|
|
4
|
+
// lifecycle, S6 legal-hold) genutzt.
|
|
5
|
+
|
|
6
|
+
export type { Role } from "./roles";
|
|
7
|
+
export { ROLES } from "./roles";
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Zentrale Role-Konstanten der Plattform.
|
|
2
|
+
//
|
|
3
|
+
// Hintergrund: Bundled-Features driften zwischen "Admin" (text-content,
|
|
4
|
+
// secrets, ai-foundation, file-provider-s3) und "TenantAdmin" (tenant-
|
|
5
|
+
// handler, publicstatus, platform). App-Builder fallen in diese Falle.
|
|
6
|
+
// Diese Datei ist die Single Source of Truth — Bundled-Features
|
|
7
|
+
// migrieren schrittweise auf die ROLES-Constants in den Sprint-
|
|
8
|
+
// Touchpoints, an denen sie ohnehin angefasst werden.
|
|
9
|
+
//
|
|
10
|
+
// Canonical-Names:
|
|
11
|
+
// TenantOwner — Volle Tenant-Hoheit, einzige Rolle die
|
|
12
|
+
// Tenant-Destroy triggern darf.
|
|
13
|
+
// TenantAdmin — Tenant-Konfiguration + User-Management.
|
|
14
|
+
// Bestehender String "Admin" wird hierauf
|
|
15
|
+
// migriert.
|
|
16
|
+
// DataProtectionOfficer — DPO; setzt Legal-Holds, sieht Authority-
|
|
17
|
+
// Audit-Stream auch im silentMode (Sprint 6).
|
|
18
|
+
// SystemAdmin — Plattform-Operator (NICHT Tenant-scoped).
|
|
19
|
+
// Authority-Export, KMS-Recovery, Cross-
|
|
20
|
+
// Tenant-Setup. Matched den bestehenden
|
|
21
|
+
// "SystemAdmin"-String in text-content,
|
|
22
|
+
// secrets, auth-email-password, etc.
|
|
23
|
+
// Member — Standard-Mitglied eines Tenants ohne
|
|
24
|
+
// Admin-Rechte.
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Plattform-weit standardisierte Role-Namen. Alle Datenschutz-Sprints
|
|
28
|
+
* (1+) nutzen ausschliesslich diese Constants statt String-Literale.
|
|
29
|
+
*/
|
|
30
|
+
export const ROLES = {
|
|
31
|
+
TenantOwner: "TenantOwner",
|
|
32
|
+
TenantAdmin: "TenantAdmin",
|
|
33
|
+
DataProtectionOfficer: "DataProtectionOfficer",
|
|
34
|
+
SystemAdmin: "SystemAdmin",
|
|
35
|
+
Member: "Member",
|
|
36
|
+
} as const;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Type-Union aller bekannten Role-Namen (Compile-Time-Check fuer
|
|
40
|
+
* Handler-Access-Rules + Ownership-Maps).
|
|
41
|
+
*/
|
|
42
|
+
export type Role = (typeof ROLES)[keyof typeof ROLES];
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Unit-Tests fuer DurationSpec-Helpers (S2.U5a.fix2).
|
|
2
|
+
//
|
|
3
|
+
// Pinst beide Discriminated-Union-Branches (`{days}` + `{hours}`) plus
|
|
4
|
+
// Edge-Cases die in den Integration-Tests nicht auftauchen (0-Werte,
|
|
5
|
+
// Singular/Plural). Der Bug aus dem U5a-Review (`{hours: 6}` fiel auf
|
|
6
|
+
// 30d-Default) wird hier zentral verhindert.
|
|
7
|
+
|
|
8
|
+
import { ensureTemporalPolyfill, getTemporal } from "@cosmicdrift/kumiko-framework/time";
|
|
9
|
+
import { beforeAll, describe, expect, test } from "vitest";
|
|
10
|
+
import { addDurationSpec, describeDurationSpec, durationSpecToMs } from "../duration-spec";
|
|
11
|
+
|
|
12
|
+
beforeAll(async () => {
|
|
13
|
+
await ensureTemporalPolyfill();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe("durationSpecToMs", () => {
|
|
17
|
+
test("days → days * 86_400_000", () => {
|
|
18
|
+
expect(durationSpecToMs({ days: 30 })).toBe(30 * 24 * 60 * 60 * 1000);
|
|
19
|
+
expect(durationSpecToMs({ days: 1 })).toBe(24 * 60 * 60 * 1000);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("hours → hours * 3_600_000", () => {
|
|
23
|
+
expect(durationSpecToMs({ hours: 6 })).toBe(6 * 60 * 60 * 1000);
|
|
24
|
+
expect(durationSpecToMs({ hours: 72 })).toBe(72 * 60 * 60 * 1000);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("0-Werte ergeben 0", () => {
|
|
28
|
+
expect(durationSpecToMs({ days: 0 })).toBe(0);
|
|
29
|
+
expect(durationSpecToMs({ hours: 0 })).toBe(0);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe("addDurationSpec", () => {
|
|
34
|
+
test("days addiert exakt zu Instant.epochMilliseconds", () => {
|
|
35
|
+
const T = getTemporal();
|
|
36
|
+
const t0 = T.Instant.fromEpochMilliseconds(1_700_000_000_000);
|
|
37
|
+
const t1 = addDurationSpec(t0, { days: 30 });
|
|
38
|
+
expect(t1.epochMilliseconds - t0.epochMilliseconds).toBe(30 * 24 * 60 * 60 * 1000);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("hours addiert exakt zu Instant.epochMilliseconds", () => {
|
|
42
|
+
const T = getTemporal();
|
|
43
|
+
const t0 = T.Instant.fromEpochMilliseconds(1_700_000_000_000);
|
|
44
|
+
const t1 = addDurationSpec(t0, { hours: 6 });
|
|
45
|
+
expect(t1.epochMilliseconds - t0.epochMilliseconds).toBe(6 * 60 * 60 * 1000);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Regression-Guard fuer den U5a-Bug: vorher fiel `{hours: 6}` auf
|
|
49
|
+
// `30 * 86_400_000`-Default zurueck. Wenn jemand den Branch wieder
|
|
50
|
+
// verliert, faellt dieser Test sofort um.
|
|
51
|
+
test("hours-Branch ist NICHT auf days-Default mappable (U5a-Regression)", () => {
|
|
52
|
+
const T = getTemporal();
|
|
53
|
+
const t0 = T.Instant.fromEpochMilliseconds(1_700_000_000_000);
|
|
54
|
+
const tHours = addDurationSpec(t0, { hours: 6 });
|
|
55
|
+
const tDaysDefault = addDurationSpec(t0, { days: 30 });
|
|
56
|
+
expect(tHours.epochMilliseconds).not.toBe(tDaysDefault.epochMilliseconds);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
describe("describeDurationSpec", () => {
|
|
61
|
+
test("days mit Pluralisierung", () => {
|
|
62
|
+
expect(describeDurationSpec({ days: 30 })).toBe("30 days");
|
|
63
|
+
expect(describeDurationSpec({ days: 1 })).toBe("1 day");
|
|
64
|
+
expect(describeDurationSpec({ days: 0 })).toBe("0 days");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("hours mit Pluralisierung", () => {
|
|
68
|
+
expect(describeDurationSpec({ hours: 72 })).toBe("72 hours");
|
|
69
|
+
expect(describeDurationSpec({ hours: 1 })).toBe("1 hour");
|
|
70
|
+
expect(describeDurationSpec({ hours: 0 })).toBe("0 hours");
|
|
71
|
+
});
|
|
72
|
+
});
|