@cosmicdrift/kumiko-framework 0.387.0 → 0.388.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/AGENTS.md +6 -1
- package/agents/examples/anonymous-access.md +1 -1
- package/agents/examples/apex-landing.md +204 -0
- package/agents/examples/api-worker-split.md +64 -0
- package/agents/examples/app-config.md +14 -0
- package/agents/examples/auth-mfa.md +115 -0
- package/agents/examples/env-composition.md +28 -1
- package/agents/examples/legal-pages.md +1 -1
- package/agents/examples/prod-boot-options.md +16 -0
- package/agents/examples/rate-limiting.md +48 -0
- package/agents/examples/record-detail-layout.md +692 -0
- package/agents/examples/seed-migration.md +212 -0
- package/agents/examples/wizard-form.md +941 -0
- package/agents/examples/writeform-section.md +548 -0
- package/agents/features.md +19 -2
- package/agents/widgets.md +1 -0
- package/dist/api/client-error-route.js +8 -2
- package/dist/api/index.d.ts +3 -1
- package/dist/api/index.js +3 -1
- package/dist/api/request-context.d.ts +1 -1
- package/dist/api/request-context.js +1 -1
- package/dist/api/server-boot-checks.d.ts +10 -0
- package/dist/api/server-boot-checks.js +157 -0
- package/dist/api/server-event-dispatcher.d.ts +26 -0
- package/dist/api/server-event-dispatcher.js +208 -0
- package/dist/api/server-extra-routes.d.ts +11 -0
- package/dist/api/server-extra-routes.js +203 -0
- package/dist/api/server-middleware.d.ts +20 -0
- package/dist/api/server-middleware.js +211 -0
- package/dist/api/server-routes.d.ts +19 -0
- package/dist/api/server-routes.js +293 -0
- package/dist/api/server-websocket-routes.d.ts +4 -0
- package/dist/api/server-websocket-routes.js +108 -0
- package/dist/api/server-wiring.d.ts +32 -0
- package/dist/api/server-wiring.js +236 -0
- package/dist/api/server.d.ts +10 -15
- package/dist/api/server.js +48 -1251
- package/dist/api/session-cookies.js +4 -4
- package/dist/api/sse-route.js +16 -12
- package/dist/crypto/owner-transition-rekey.d.ts +5 -1
- package/dist/crypto/owner-transition-rekey.js +1 -1
- package/dist/crypto/pii-field-encryption.d.ts +5 -1
- package/dist/crypto/pii-field-encryption.js +3 -1
- package/dist/db/aggregate-sql.d.ts +21 -0
- package/dist/db/aggregate-sql.js +155 -0
- package/dist/db/closed-connection.d.ts +9 -0
- package/dist/db/closed-connection.js +95 -0
- package/dist/db/dialect.js +1 -1
- package/dist/db/distinct-on.d.ts +1 -1
- package/dist/db/driver-row-coercion.d.ts +2 -0
- package/dist/db/driver-row-coercion.js +186 -0
- package/dist/db/driver-value-preparation.d.ts +16 -0
- package/dist/db/driver-value-preparation.js +99 -0
- package/dist/db/entity-field-encryption.d.ts +1 -0
- package/dist/db/entity-field-encryption.js +1 -1
- package/dist/db/entity-table-meta.js +103 -110
- package/dist/db/event-store-executor-context.d.ts +2 -1
- package/dist/db/event-store-executor-read-aggregate.d.ts +8 -0
- package/dist/db/event-store-executor-read-aggregate.js +112 -0
- package/dist/db/event-store-executor-read-filter.d.ts +31 -0
- package/dist/db/event-store-executor-read-filter.js +203 -0
- package/dist/db/event-store-executor-read-paging.d.ts +14 -0
- package/dist/db/event-store-executor-read-paging.js +99 -0
- package/dist/db/event-store-executor-read-rows.d.ts +6 -0
- package/dist/db/event-store-executor-read-rows.js +32 -0
- package/dist/db/event-store-executor-read-search.d.ts +28 -0
- package/dist/db/event-store-executor-read-search.js +221 -0
- package/dist/db/event-store-executor-read-sort.d.ts +41 -0
- package/dist/db/event-store-executor-read-sort.js +130 -0
- package/dist/db/event-store-executor-read-where.d.ts +24 -0
- package/dist/db/event-store-executor-read-where.js +81 -0
- package/dist/db/event-store-executor-read.d.ts +2 -9
- package/dist/db/event-store-executor-read.js +48 -701
- package/dist/db/event-store-executor-write-steps.d.ts +20 -0
- package/dist/db/event-store-executor-write-steps.js +100 -0
- package/dist/db/event-store-executor-write.js +395 -499
- package/dist/db/index.d.ts +6 -2
- package/dist/db/index.js +5 -1
- package/dist/db/list-aggregate-labels.d.ts +14 -0
- package/dist/db/list-aggregate-labels.js +26 -0
- package/dist/db/migrate-generator.js +71 -86
- package/dist/db/migrate-runner.js +4 -1
- package/dist/db/query.d.ts +2 -15
- package/dist/db/query.js +8 -761
- package/dist/db/reference-data.js +6 -1
- package/dist/db/table-builder.js +113 -166
- package/dist/db/table-info.d.ts +10 -0
- package/dist/db/table-info.js +45 -0
- package/dist/db/temporal-value-guards.d.ts +6 -0
- package/dist/db/temporal-value-guards.js +15 -0
- package/dist/db/tenant-db-runner.d.ts +1 -0
- package/dist/db/tenant-db-runner.js +3 -0
- package/dist/db/tenant-db.js +39 -9
- package/dist/db/where-clause.d.ts +6 -0
- package/dist/db/where-clause.js +236 -0
- package/dist/derivatives/delete-stored-file.js +2 -1
- package/dist/engine/boot-validator/boot-check.js +1 -1
- package/dist/engine/boot-validator/detail-screens.js +2 -2
- package/dist/engine/boot-validator/entity-handler.d.ts +1 -0
- package/dist/engine/boot-validator/entity-handler.js +17 -0
- package/dist/engine/boot-validator/form-derivations.js +35 -1
- package/dist/engine/boot-validator/i18n-keys.js +5 -3
- package/dist/engine/boot-validator/index.js +2 -0
- package/dist/engine/boot-validator/pii-retention.js +233 -155
- package/dist/engine/boot-validator/screens-actions.d.ts +1 -0
- package/dist/engine/boot-validator/screens-actions.js +8 -1
- package/dist/engine/boot-validator/screens-dashboard.js +2 -5
- package/dist/engine/boot-validator/screens-forms.js +2 -6
- package/dist/engine/boot-validator/screens-kind-config-edit.d.ts +3 -0
- package/dist/engine/boot-validator/screens-kind-config-edit.js +88 -0
- package/dist/engine/boot-validator/screens-kind-entity-edit.d.ts +3 -0
- package/dist/engine/boot-validator/screens-kind-entity-edit.js +55 -0
- package/dist/engine/boot-validator/screens-kind-entity-list.d.ts +3 -0
- package/dist/engine/boot-validator/screens-kind-entity-list.js +228 -0
- package/dist/engine/boot-validator/screens-kind-projection-detail.d.ts +3 -0
- package/dist/engine/boot-validator/screens-kind-projection-detail.js +235 -0
- package/dist/engine/boot-validator/screens-kind-projection-list.d.ts +3 -0
- package/dist/engine/boot-validator/screens-kind-projection-list.js +52 -0
- package/dist/engine/boot-validator/screens-kind-secret-mint.d.ts +3 -0
- package/dist/engine/boot-validator/screens-kind-secret-mint.js +28 -0
- package/dist/engine/boot-validator/screens-kind-shared.d.ts +37 -0
- package/dist/engine/boot-validator/screens-kind-shared.js +142 -0
- package/dist/engine/boot-validator/screens-lists.d.ts +2 -1
- package/dist/engine/boot-validator/screens-lists.js +12 -9
- package/dist/engine/boot-validator/screens.d.ts +0 -2
- package/dist/engine/boot-validator/screens.js +99 -860
- package/dist/engine/build-app-schema.js +56 -96
- package/dist/engine/define-feature.js +9 -2
- package/dist/engine/define-handler.js +1 -0
- package/dist/engine/entity-handlers.d.ts +13 -0
- package/dist/engine/entity-handlers.js +10 -21
- package/dist/engine/entity-list-runtime-options.d.ts +8 -0
- package/dist/engine/entity-list-runtime-options.js +18 -0
- package/dist/engine/feature-ast/extractors/handlers.js +1 -0
- package/dist/engine/feature-ast/extractors/round2.js +25 -6
- package/dist/engine/feature-ast/patch.js +4 -182
- package/dist/engine/feature-ast/pattern-change-schema.d.ts +3 -0
- package/dist/engine/feature-ast/pattern-change-schema.js +1 -0
- package/dist/engine/feature-ast/pattern-id-matchers.d.ts +7 -0
- package/dist/engine/feature-ast/pattern-id-matchers.js +210 -0
- package/dist/engine/feature-ast/patterns.d.ts +9 -0
- package/dist/engine/feature-ast/patterns.js +43 -51
- package/dist/engine/feature-ast/render.js +48 -87
- package/dist/engine/feature-entity-handlers.js +3 -0
- package/dist/engine/form-derivations.js +18 -7
- package/dist/engine/handler-field-references.js +1 -1
- package/dist/engine/project-app-schema-for-roles.d.ts +2 -0
- package/dist/engine/project-app-schema-for-roles.js +6 -4
- package/dist/engine/registry-ingest.js +1 -1
- package/dist/engine/schema-builder.js +228 -212
- package/dist/engine/screen-helpers.js +1 -1
- package/dist/engine/screen-kind.d.ts +7 -0
- package/dist/engine/screen-kind.js +1 -0
- package/dist/engine/strip-disabled-features-from-app-schema.js +51 -14
- package/dist/engine/validate-projection-allowlist.js +2 -1
- package/dist/entrypoint/index.d.ts +4 -1
- package/dist/entrypoint/index.js +7 -1
- package/dist/errors/docs-url.d.ts +1 -1
- package/dist/errors/docs-url.js +22 -2
- package/dist/es-ops/context.js +1 -1
- package/dist/event-store/admin-api.js +1 -1
- package/dist/event-store/event-store.js +10 -4
- package/dist/files/bind-pending-file-refs.js +3 -3
- package/dist/files/create-file-ref-from-bytes.js +4 -1
- package/dist/files/file-handle.js +2 -3
- package/dist/files/file-routes.js +11 -8
- package/dist/files/resolve-content-type.js +43 -0
- package/dist/files/upload-ledger.js +7 -0
- package/dist/i18n/required-surface-keys.js +182 -206
- package/dist/internal/stack-support.d.ts +2 -1
- package/dist/internal/stack-support.js +1 -1
- package/dist/jobs/job-runner-context.d.ts +32 -0
- package/dist/jobs/job-runner-context.js +305 -0
- package/dist/jobs/job-runner-execution.d.ts +7 -0
- package/dist/jobs/job-runner-execution.js +160 -0
- package/dist/jobs/job-runner-gates.d.ts +19 -0
- package/dist/jobs/job-runner-gates.js +198 -0
- package/dist/jobs/job-runner-helpers.d.ts +17 -3
- package/dist/jobs/job-runner-helpers.js +61 -2
- package/dist/jobs/job-runner-scope.d.ts +44 -0
- package/dist/jobs/job-runner-scope.js +102 -0
- package/dist/jobs/job-runner-types.d.ts +12 -0
- package/dist/jobs/job-runner.d.ts +0 -1
- package/dist/jobs/job-runner.js +47 -657
- package/dist/observability/escape-hatch-report.d.ts +3 -0
- package/dist/observability/escape-hatch-report.js +12 -1
- package/dist/pipeline/cascade-handler.js +165 -138
- package/dist/pipeline/dispatch-query.js +10 -3
- package/dist/pipeline/dispatch-shared.d.ts +13 -3
- package/dist/pipeline/dispatch-shared.js +58 -710
- package/dist/pipeline/dispatch-write.js +296 -189
- package/dist/pipeline/event-dispatcher-admin.js +2 -1
- package/dist/pipeline/event-dispatcher-delivery.js +3 -5
- package/dist/pipeline/handler-context-auth.d.ts +9 -0
- package/dist/pipeline/handler-context-auth.js +54 -0
- package/dist/pipeline/handler-context-config.d.ts +14 -0
- package/dist/pipeline/handler-context-config.js +113 -0
- package/dist/pipeline/handler-context-db.d.ts +24 -0
- package/dist/pipeline/handler-context-db.js +149 -0
- package/dist/pipeline/handler-context-dispatch.d.ts +21 -0
- package/dist/pipeline/handler-context-dispatch.js +89 -0
- package/dist/pipeline/handler-context-events.d.ts +43 -0
- package/dist/pipeline/handler-context-events.js +237 -0
- package/dist/pipeline/handler-context-notify.d.ts +12 -0
- package/dist/pipeline/handler-context-notify.js +55 -0
- package/dist/pipeline/handler-context-observability.d.ts +7 -0
- package/dist/pipeline/handler-context-observability.js +21 -0
- package/dist/pipeline/handler-context-scope.d.ts +48 -0
- package/dist/pipeline/handler-context-scope.js +88 -0
- package/dist/pipeline/notify-scope.js +12 -1
- package/dist/pipeline/pre-handler-gates.js +20 -4
- package/dist/pipeline/pre-transaction-reservations.d.ts +1 -0
- package/dist/pipeline/pre-transaction-reservations.js +9 -3
- package/dist/pipeline/projection-rebuild.js +2 -1
- package/dist/schema-cli/apply-command.d.ts +2 -0
- package/dist/schema-cli/apply-command.js +97 -0
- package/dist/schema-cli/baseline-command.d.ts +2 -0
- package/dist/schema-cli/baseline-command.js +33 -0
- package/dist/schema-cli/generate-command.d.ts +2 -0
- package/dist/schema-cli/generate-command.js +90 -0
- package/dist/schema-cli/shared.d.ts +39 -0
- package/dist/schema-cli/shared.js +95 -0
- package/dist/schema-cli/status-command.d.ts +2 -0
- package/dist/schema-cli/status-command.js +73 -0
- package/dist/schema-cli/validate-boot-input.d.ts +5 -0
- package/dist/schema-cli/validate-boot-input.js +130 -0
- package/dist/schema-cli/validate-command.d.ts +2 -0
- package/dist/schema-cli/validate-command.js +130 -0
- package/dist/schema-cli.d.ts +2 -18
- package/dist/schema-cli.js +47 -604
- package/dist/search/meilisearch-adapter.js +2 -1
- package/dist/upgrade-cli.js +149 -121
- package/package.json +4 -4
- package/src/changes.json +310 -0
- package/src/scripts/codemod/feature-layout.ts +10 -2
- package/src/scripts/codemod/object-form.ts +41 -4
- package/src/scripts/codemod/package-merge.ts +58 -8
- package/src/scripts/codemod/pii-personal-migration.ts +175 -145
- package/src/scripts/codemod/testing-injection.ts +122 -42
- package/src/scripts/codemod/testing-move.ts +29 -7
|
@@ -97,3 +97,215 @@ Wenn eine kaputte Migration den Boot blockiert: setze `skippable: true` im seed-
|
|
|
97
97
|
## See also
|
|
98
98
|
|
|
99
99
|
- **Driver-Use-Case:** `seeds/2026-02-01-fix-admin-roles.ts` in this recipe
|
|
100
|
+
|
|
101
|
+
## Source files
|
|
102
|
+
|
|
103
|
+
### scripts/smoke.ts
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
// biome-ignore-all lint/suspicious/noConsole: CLI tool output
|
|
107
|
+
//
|
|
108
|
+
// Lokaler Smoke-Test für seed-migrations.
|
|
109
|
+
//
|
|
110
|
+
// Was er prüft (offline, ohne Pod-Deploy):
|
|
111
|
+
// 1. Alle seed-files in ./seeds/ können dynamic-import geladen werden
|
|
112
|
+
// → catched syntax-errors + missing default-exports + falsche paths
|
|
113
|
+
// 2. Jeder handler-QN den die seeds referenzieren ist in der echten
|
|
114
|
+
// App-Registry registriert → catched camelCase-typos + drift
|
|
115
|
+
// (Bug-Klasse 3 aus Phase 1 retro)
|
|
116
|
+
// 3. Jeder system-user (mit oder ohne tenantIdOverride) hat Access auf
|
|
117
|
+
// die referenzierten Handler → catched access-rule-Drift
|
|
118
|
+
// (Bug-Klasse 4 aus Phase 1 retro)
|
|
119
|
+
//
|
|
120
|
+
// Schreibt NICHTS in die DB. Reine Read-only Validation.
|
|
121
|
+
//
|
|
122
|
+
// Usage:
|
|
123
|
+
// bun scripts/smoke.ts (gegen ./seeds/)
|
|
124
|
+
// bun scripts/smoke.ts --seeds-dir foo (custom path)
|
|
125
|
+
//
|
|
126
|
+
// In CI: vor `build`-Step laufen lassen — fängt 80% der Phase-1-Bugs
|
|
127
|
+
// lokal in <5 Sekunden statt nach 8-Minuten-Docker-Build im Pod-Boot.
|
|
128
|
+
|
|
129
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
130
|
+
import { resolve } from "node:path";
|
|
131
|
+
// App-spezifisch: nimm die EFFEKTIVEN Features die deine App zur Runtime
|
|
132
|
+
// nutzt. Im typischen Setup mit `runProdApp({ features, auth })`:
|
|
133
|
+
//
|
|
134
|
+
// import { composeFeatures } from "@cosmicdrift/kumiko-dev-server";
|
|
135
|
+
// import { APP_FEATURES } from "../src/run-config";
|
|
136
|
+
// const composed = composeFeatures(APP_FEATURES, { includeBundled: true, ... });
|
|
137
|
+
// const features = composed.features;
|
|
138
|
+
//
|
|
139
|
+
// Bei reiner App-Feature-Setup (kein auth-mode) reicht ein direkter
|
|
140
|
+
// Import der App-Features. Hier im Recipe der minimale set für die
|
|
141
|
+
// referenzierten Recipe-Seeds (tenant + config) — App-Author tauscht
|
|
142
|
+
// gegen sein eigenes Feature-Set.
|
|
143
|
+
import { createConfigFeature } from "@cosmicdrift/kumiko-bundled-features/config";
|
|
144
|
+
import { createTenantFeature } from "@cosmicdrift/kumiko-bundled-features/tenant";
|
|
145
|
+
import {
|
|
146
|
+
createRegistry,
|
|
147
|
+
createSystemUser,
|
|
148
|
+
SYSTEM_TENANT_ID,
|
|
149
|
+
} from "@cosmicdrift/kumiko-framework/engine";
|
|
150
|
+
|
|
151
|
+
const features = [createConfigFeature(), createTenantFeature()];
|
|
152
|
+
|
|
153
|
+
const seedsDir = (() => {
|
|
154
|
+
const idx = process.argv.indexOf("--seeds-dir");
|
|
155
|
+
return idx >= 0 ? resolve(process.argv[idx + 1] ?? "./seeds") : resolve("./seeds");
|
|
156
|
+
})();
|
|
157
|
+
|
|
158
|
+
if (!existsSync(seedsDir)) {
|
|
159
|
+
console.log(`✓ no seeds-dir at ${seedsDir} — nothing to smoke-test`);
|
|
160
|
+
process.exit(0);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const seedFiles = readdirSync(seedsDir)
|
|
164
|
+
.filter((n) => n.endsWith(".ts") && !n.startsWith("_") && !n.startsWith("."))
|
|
165
|
+
.sort();
|
|
166
|
+
|
|
167
|
+
if (seedFiles.length === 0) {
|
|
168
|
+
console.log(`✓ ${seedsDir} is empty — nothing to smoke-test`);
|
|
169
|
+
process.exit(0);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const registry = createRegistry(features);
|
|
173
|
+
|
|
174
|
+
let failed = 0;
|
|
175
|
+
|
|
176
|
+
for (const file of seedFiles) {
|
|
177
|
+
const filePath = resolve(seedsDir, file);
|
|
178
|
+
console.log(`\nseed: ${file}`);
|
|
179
|
+
|
|
180
|
+
// 1. Module-load
|
|
181
|
+
try {
|
|
182
|
+
const mod = await import(filePath);
|
|
183
|
+
if (!mod.default || typeof mod.default.run !== "function") {
|
|
184
|
+
console.error(" ✗ missing valid SeedMigration default-export");
|
|
185
|
+
failed++;
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
console.log(` ✓ loads: "${mod.default.description}"`);
|
|
189
|
+
} catch (err) {
|
|
190
|
+
console.error(` ✗ load fail: ${err instanceof Error ? err.message : String(err)}`);
|
|
191
|
+
failed++;
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// 2 + 3. QN-Resolution + Access (regex-based, gleiche Logik wie runner's
|
|
196
|
+
// dry-run-validator). Pattern matched inline-string-QNs:
|
|
197
|
+
const source = readFileSync(filePath, "utf-8");
|
|
198
|
+
const qnPattern = /systemWriteAs\s*\(\s*["']([^"']+)["']/g;
|
|
199
|
+
const qns = new Set<string>();
|
|
200
|
+
for (const m of source.matchAll(qnPattern)) {
|
|
201
|
+
const qn = m[1];
|
|
202
|
+
if (qn) qns.add(qn);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
for (const qn of qns) {
|
|
206
|
+
const handler = registry.getWriteHandler(qn);
|
|
207
|
+
if (!handler) {
|
|
208
|
+
console.error(` ✗ handler "${qn}" not registered`);
|
|
209
|
+
failed++;
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
const accessRoles = (handler.access as { roles?: readonly string[] }).roles ?? [];
|
|
213
|
+
const systemUserRoles = createSystemUser(SYSTEM_TENANT_ID).roles;
|
|
214
|
+
const hasAccess = systemUserRoles.some((r) => accessRoles.includes(r));
|
|
215
|
+
if (!hasAccess) {
|
|
216
|
+
console.error(
|
|
217
|
+
` ✗ system-user roles=${JSON.stringify([...systemUserRoles])} NOT in access.roles=${JSON.stringify([...accessRoles])} for "${qn}"`,
|
|
218
|
+
);
|
|
219
|
+
failed++;
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
console.log(` ✓ "${qn}" registered + accessible`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (failed > 0) {
|
|
227
|
+
console.error(`\n${failed} issue(s) — fix before push.`);
|
|
228
|
+
process.exit(1);
|
|
229
|
+
}
|
|
230
|
+
console.log(`\n✓ all ${seedFiles.length} seed-file(s) pass smoke.`);
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### seeds/2026-01-01-initial-tenants.ts
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
// Initial-Seed: Demo-Tenants anlegen.
|
|
237
|
+
//
|
|
238
|
+
// Note: in real apps wäre "initial tenants" wahrscheinlich nicht als
|
|
239
|
+
// seed-migration sondern als `r.config({seeds})` oder `auth.admin`-
|
|
240
|
+
// Config umgesetzt — die laufen jedes-Boot idempotent. Hier ist es als
|
|
241
|
+
// seed-migration gezeigt um das Pattern zu demonstrieren.
|
|
242
|
+
//
|
|
243
|
+
// Pattern: jede seed-migration arbeitet write-only via `systemWriteAs`
|
|
244
|
+
// damit alles als Event-Stream persistiert wird. Read-only Lookups
|
|
245
|
+
// (find*) am Context oder direkt via ctx.db.
|
|
246
|
+
|
|
247
|
+
import type { SeedMigration } from "@cosmicdrift/kumiko-framework/es-ops";
|
|
248
|
+
|
|
249
|
+
export default {
|
|
250
|
+
description: "initial demo tenants (alice-corp, beta-inc)",
|
|
251
|
+
run: async (ctx) => {
|
|
252
|
+
// Idempotent-Check: wenn Tenants schon existieren (z.B. via auth.admin-
|
|
253
|
+
// seed), skip diese Migration. Verhindert Konflikt beim re-boot wenn
|
|
254
|
+
// jemand den Marker manuell gelöscht hat.
|
|
255
|
+
const existing = await ctx.findTenants();
|
|
256
|
+
if (existing.some((t) => t.tenantKey === "alice-corp")) return;
|
|
257
|
+
|
|
258
|
+
await ctx.systemWriteAs("tenant:write:create", {
|
|
259
|
+
name: "Alice Corp",
|
|
260
|
+
tenantKey: "alice-corp",
|
|
261
|
+
});
|
|
262
|
+
await ctx.systemWriteAs("tenant:write:create", {
|
|
263
|
+
name: "Beta Inc",
|
|
264
|
+
tenantKey: "beta-inc",
|
|
265
|
+
});
|
|
266
|
+
},
|
|
267
|
+
} satisfies SeedMigration;
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### seeds/2026-02-01-fix-admin-roles.ts
|
|
271
|
+
|
|
272
|
+
```ts
|
|
273
|
+
// Driver-Pattern: ergänze fehlende Rolle auf existierenden Memberships.
|
|
274
|
+
// Spiegelt den realen publicstatus-Bug 2026-05-20 (admin@publicstatus.eu
|
|
275
|
+
// hatte "Admin" aber nicht "TenantAdmin" → text-content + legal-pages
|
|
276
|
+
// access_denied weil bundled-features TenantAdmin erwarten).
|
|
277
|
+
//
|
|
278
|
+
// Funktioniert für jede App mit dem gleichen Pattern: User-Lookup per
|
|
279
|
+
// E-Mail → alle Memberships durchgehen → bei Bedarf via existierendem
|
|
280
|
+
// updateMemberRoles-Handler korrigieren.
|
|
281
|
+
|
|
282
|
+
import type { SeedMigration } from "@cosmicdrift/kumiko-framework/es-ops";
|
|
283
|
+
|
|
284
|
+
export default {
|
|
285
|
+
description: "ergänze TenantAdmin-Rolle für admin@example.com auf allen Memberships",
|
|
286
|
+
run: async (ctx) => {
|
|
287
|
+
const admin = await ctx.findUserByEmail("admin@example.com");
|
|
288
|
+
if (!admin) return; // idempotent: admin nicht (mehr) vorhanden
|
|
289
|
+
|
|
290
|
+
for (const m of await ctx.findMembershipsOfUser(admin.id)) {
|
|
291
|
+
if (m.roles.includes("TenantAdmin")) continue; // bereits korrigiert
|
|
292
|
+
|
|
293
|
+
await ctx.systemWriteAs(
|
|
294
|
+
"tenant:write:update-member-roles", // kebab-case QN — wird vom Dry-Run-Validator gecheckt
|
|
295
|
+
{
|
|
296
|
+
userId: admin.id,
|
|
297
|
+
tenantId: m.tenantId,
|
|
298
|
+
roles: Array.from(new Set([...m.roles, "TenantAdmin"])),
|
|
299
|
+
},
|
|
300
|
+
// tenantIdOverride: stream-tenant aus kumiko_events.v1 — NICHT
|
|
301
|
+
// m.tenantId (payload-tenant). Beide stimmen oft überein, weichen
|
|
302
|
+
// aber ab wenn das Aggregate ursprünglich von einem fremden
|
|
303
|
+
// Executor angelegt wurde (seedTenantMembership by=systemAdmin —
|
|
304
|
+
// publicstatus-Pattern). findMembershipsOfUser liefert beide,
|
|
305
|
+
// kein eigener JOIN nötig.
|
|
306
|
+
m.streamTenantId,
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
} satisfies SeedMigration;
|
|
311
|
+
```
|