@cosmicdrift/kumiko-framework 0.367.0 → 0.368.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 +1 -7
- package/README.md +1 -1
- package/agents/examples/access-control.md +2 -2
- package/agents/examples/anonymous-access-multitenant.md +2 -2
- package/agents/examples/anonymous-access.md +3 -3
- package/agents/examples/apex-landing.md +1 -1
- package/agents/examples/apex-surface-auth.md +6 -7
- package/agents/examples/api-worker-split.md +7 -8
- package/agents/examples/auth-claims.md +2 -1
- package/agents/examples/auth-foundation-providers.md +3 -3
- package/agents/examples/auth-mfa.md +3 -4
- package/agents/examples/basic-entity.md +3 -4
- package/agents/examples/chat-channels.md +4 -4
- package/agents/examples/compliance-profiles-demo.md +2 -3
- package/agents/examples/cross-feature-events.md +4 -4
- package/agents/examples/crypto-shredding-hr.md +14 -9
- package/agents/examples/currencies-global.md +3 -4
- package/agents/examples/currencies-per-tenant.md +3 -4
- package/agents/examples/custom-fields-basic.md +2 -3
- package/agents/examples/custom-handlers.md +3 -5
- package/agents/examples/dashboard-stats.md +2 -3
- package/agents/examples/delivery-notifications.md +5 -6
- package/agents/examples/e2e-generator.md +1 -1
- package/agents/examples/embedded-entity-form.md +2 -3
- package/agents/examples/embedded.md +2 -3
- package/agents/examples/encrypted-tenant-config.md +5 -6
- package/agents/examples/error-contract.md +3 -4
- package/agents/examples/event-sourcing.md +19 -23
- package/agents/examples/feature-toggles.md +4 -4
- package/agents/examples/field-access.md +3 -4
- package/agents/examples/files-post-processing.md +12 -13
- package/agents/examples/golden-path.md +208 -0
- package/agents/examples/idempotency.md +2 -2
- package/agents/examples/inbound-mail-triage.md +7 -7
- package/agents/examples/lane-routing.md +3 -3
- package/agents/examples/ledger-banking.md +2 -3
- package/agents/examples/ledger-invoicing.md +2 -3
- package/agents/examples/legal-pages.md +1 -1
- package/agents/examples/lifecycle-hooks.md +3 -3
- package/agents/examples/managed-config.md +3 -4
- package/agents/examples/managed-pages.md +2 -2
- package/agents/examples/notes-history-basic.md +4 -5
- package/agents/examples/ownership.md +3 -5
- package/agents/examples/pdf-audit-export.md +2 -3
- package/agents/examples/pipeline-basics.md +2 -2
- package/agents/examples/public-share-token.md +3 -3
- package/agents/examples/rate-limiting.md +2 -1
- package/agents/examples/realtime-sse.md +2 -3
- package/agents/examples/record-detail-layout.md +1 -1
- package/agents/examples/reference-data.md +3 -3
- package/agents/examples/relations.md +2 -2
- package/agents/examples/screens-nav.md +1 -1
- package/agents/examples/search.md +2 -2
- package/agents/examples/secrets-demo.md +8 -8
- package/agents/examples/security-baseline.md +2 -2
- package/agents/examples/session-revocation.md +7 -8
- package/agents/examples/state-machine.md +181 -165
- package/agents/examples/tags-basic.md +2 -3
- package/agents/examples/tenant-isolation.md +2 -3
- package/agents/examples/tenant-settings.md +2 -2
- package/agents/examples/tier-admin.md +3 -4
- package/agents/examples/timezones.md +3 -3
- package/agents/examples/user-data-rights.md +12 -8
- package/agents/examples/user-profile.md +3 -3
- package/agents/examples/webhook-step.md +2 -3
- package/agents/examples/wizard-form.md +4 -5
- package/agents/examples/workflow-engine.md +7 -3
- package/agents/examples/writeform-section.md +1 -1
- package/agents/examples.md +1 -0
- package/dist/consumer-cli.js +2 -3
- package/dist/crypto/index.d.ts +1 -1
- package/dist/crypto/index.js +1 -1
- package/dist/crypto/owner-transition-rekey.js +2 -0
- package/dist/crypto/pg-kms-adapter.js +1 -1
- package/dist/crypto/subject-resolver.d.ts +2 -0
- package/dist/crypto/subject-resolver.js +30 -15
- package/dist/db/bun-db-deprecated.d.ts +10 -0
- package/dist/{bun-db/index.js → db/bun-db-deprecated.js} +4 -3
- package/dist/db/config-seed.js +1 -1
- package/dist/db/connection.d.ts +23 -5
- package/dist/db/connection.js +10 -5
- package/dist/db/dialect.js +1 -1
- package/dist/db/entity-field-encryption.d.ts +5 -0
- package/dist/db/entity-field-encryption.js +29 -0
- package/dist/db/entity-table-meta.js +6 -5
- package/dist/db/event-store-executor-read.js +26 -5
- package/dist/db/index.d.ts +4 -4
- package/dist/db/index.js +1 -1
- package/dist/db/migrate-runner.js +1 -1
- package/dist/db/queries/backfill-pii.js +16 -9
- package/dist/db/queries/ddl.js +1 -1
- package/dist/db/queries/event-store.d.ts +2 -0
- package/dist/db/queries/event-store.js +26 -0
- package/dist/db/queries/test-stack.js +1 -1
- package/dist/db/query.d.ts +105 -1
- package/dist/db/query.js +1450 -3
- package/dist/{stack/table-helpers.d.ts → db/table-push.d.ts} +5 -15
- package/dist/{stack/table-helpers.js → db/table-push.js} +6 -46
- package/dist/db/tenant-db.d.ts +11 -0
- package/dist/db/tenant-db.js +51 -12
- package/dist/derivatives/derivatives-context.d.ts +1 -1
- package/dist/derivatives/derivatives-context.js +1 -1
- package/dist/engine/boot-validator/gdpr-storage.js +3 -3
- package/dist/engine/boot-validator/pii-retention.js +3 -3
- package/dist/engine/boot-validator/record-owned.js +3 -3
- package/dist/engine/boot-validator/screens.js +8 -1
- package/dist/engine/bridge-stub.d.ts +4 -0
- package/dist/engine/bridge-stub.js +62 -0
- package/dist/engine/event-helpers.d.ts +2 -1
- package/dist/engine/event-helpers.js +1 -0
- package/dist/engine/feature-config-events-jobs.js +2 -2
- package/dist/engine/index.d.ts +1 -0
- package/dist/engine/index.js +1 -0
- package/dist/es-ops/operations-schema.js +1 -1
- package/dist/event-store/admin-api.js +1 -1
- package/dist/event-store/archive.js +1 -1
- package/dist/event-store/errors.d.ts +2 -1
- package/dist/event-store/errors.js +6 -2
- package/dist/event-store/event-store.js +17 -9
- package/dist/event-store/events-schema.js +1 -1
- package/dist/event-store/rebuild-dead-letter.js +3 -3
- package/dist/event-store/snapshot.js +1 -1
- package/dist/event-store/upcaster-dead-letter.js +3 -3
- package/dist/files/create-file-ref-from-bytes.js +1 -1
- package/dist/files/file-routes.js +1 -1
- package/dist/internal/stack-support.d.ts +12 -0
- package/dist/internal/stack-support.js +12 -0
- package/dist/internal/testing.d.ts +4 -0
- package/dist/internal/testing.js +5 -0
- package/dist/jobs/job-runner.js +23 -11
- package/dist/migrations/pending-rebuilds.js +1 -1
- package/dist/migrations/pii-event-backfill.js +2 -2
- package/dist/pipeline/dispatch-shared.js +43 -23
- package/dist/pipeline/dispatch-write.js +6 -2
- package/dist/pipeline/dispatcher-utils.js +6 -2
- package/dist/pipeline/event-consumer-state.js +1 -1
- package/dist/pipeline/projection-rebuild.d.ts +1 -0
- package/dist/pipeline/projection-rebuild.js +1 -1
- package/dist/pipeline/projection-state.js +1 -1
- package/dist/pipeline/system-hooks.js +1 -1
- package/dist/schema-cli.js +3 -3
- package/dist/search/purge-subject.js +20 -10
- package/dist/seeding/index.d.ts +1 -0
- package/dist/seeding/index.js +1 -0
- package/dist/stack/index.d.ts +10 -9
- package/dist/stack/index.js +11 -19
- package/dist/testing/e2e-generator.d.ts +5 -49
- package/dist/testing/e2e-generator.js +5 -382
- package/dist/testing/handler-context.d.ts +5 -4
- package/dist/testing/handler-context.js +5 -69
- package/dist/testing/index.d.ts +10 -26
- package/dist/testing/index.js +10 -34
- package/dist/testing/real-providers.d.ts +5 -3
- package/dist/testing/real-providers.js +5 -21
- package/package.json +37 -9
- package/src/changes.json +58 -0
- package/src/scripts/codemod/README.md +43 -0
- package/src/scripts/codemod/codemod-support.ts +276 -0
- package/src/scripts/codemod/db-factory.ts +810 -0
- package/src/scripts/codemod/feature-factory.ts +429 -0
- package/src/scripts/codemod/s3-imports.ts +274 -0
- package/src/scripts/codemod/tenant-db-options.ts +454 -0
- package/src/scripts/codemod/testing-move-targets.ts +161 -0
- package/src/scripts/codemod/testing-move.ts +520 -0
- package/dist/bun-db/connection.d.ts +0 -17
- package/dist/bun-db/connection.js +0 -40
- package/dist/bun-db/index.d.ts +0 -4
- package/dist/bun-db/query.d.ts +0 -106
- package/dist/bun-db/query.js +0 -1457
- package/dist/db/api.d.ts +0 -19
- package/dist/db/api.js +0 -23
- package/dist/db/bun-provider.d.ts +0 -2
- package/dist/db/bun-provider.js +0 -28
- package/dist/db/postgres-provider.d.ts +0 -2
- package/dist/db/postgres-provider.js +0 -21
- package/dist/db/query-api.d.ts +0 -2
- package/dist/db/query-api.js +0 -6
- package/dist/stack/db.d.ts +0 -22
- package/dist/stack/db.js +0 -67
- package/dist/stack/drain-event-consumers.d.ts +0 -4
- package/dist/stack/drain-event-consumers.js +0 -51
- package/dist/stack/drain-jobs.d.ts +0 -22
- package/dist/stack/drain-jobs.js +0 -141
- package/dist/stack/event-collector.d.ts +0 -9
- package/dist/stack/event-collector.js +0 -12
- package/dist/stack/push-entity-projection-tables.d.ts +0 -24
- package/dist/stack/push-entity-projection-tables.js +0 -74
- package/dist/stack/redis.d.ts +0 -17
- package/dist/stack/redis.js +0 -52
- package/dist/stack/request-helper.d.ts +0 -35
- package/dist/stack/request-helper.js +0 -144
- package/dist/stack/test-stack.d.ts +0 -192
- package/dist/stack/test-stack.js +0 -429
- package/dist/testing/access-assertions.d.ts +0 -2
- package/dist/testing/access-assertions.js +0 -13
- package/dist/testing/assertions.d.ts +0 -10
- package/dist/testing/assertions.js +0 -22
- package/dist/testing/boot-validator-fixture.d.ts +0 -3
- package/dist/testing/boot-validator-fixture.js +0 -101
- package/dist/testing/closed-connection-error.d.ts +0 -7
- package/dist/testing/closed-connection-error.js +0 -46
- package/dist/testing/db-cleanup.d.ts +0 -9
- package/dist/testing/db-cleanup.js +0 -31
- package/dist/testing/expect-error.d.ts +0 -2
- package/dist/testing/expect-error.js +0 -22
- package/dist/testing/file-provider-contract.d.ts +0 -2
- package/dist/testing/file-provider-contract.js +0 -102
- package/dist/testing/http-cookies.d.ts +0 -7
- package/dist/testing/http-cookies.js +0 -47
- package/dist/testing/late-bound.d.ts +0 -9
- package/dist/testing/late-bound.js +0 -31
- package/dist/testing/manual-clock.d.ts +0 -14
- package/dist/testing/manual-clock.js +0 -12
- package/dist/testing/multipart-helper.d.ts +0 -22
- package/dist/testing/multipart-helper.js +0 -77
- package/dist/testing/mutable-master-key-provider.d.ts +0 -7
- package/dist/testing/mutable-master-key-provider.js +0 -35
- package/dist/testing/observability-recorder.d.ts +0 -9
- package/dist/testing/observability-recorder.js +0 -29
- package/dist/testing/seed.d.ts +0 -9
- package/dist/testing/seed.js +0 -21
- package/dist/testing/shared-entities.d.ts +0 -286
- package/dist/testing/shared-entities.js +0 -56
- package/dist/testing/utils.d.ts +0 -1
- package/dist/testing/utils.js +0 -1
- package/dist/testing/wait-for.d.ts +0 -20
- package/dist/testing/wait-for.js +0 -47
- package/dist/testing/without-ambient-temporal.d.ts +0 -5
- package/dist/testing/without-ambient-temporal.js +0 -17
- package/dist/testing/zip-fixture.d.ts +0 -1
- package/dist/testing/zip-fixture.js +0 -33
- /package/dist/{stack/test-users.d.ts → seeding/seed-users.d.ts} +0 -0
- /package/dist/{stack/test-users.js → seeding/seed-users.js} +0 -0
|
@@ -4,7 +4,7 @@ import { index, instant, integer, jsonb, table as pgTable, primaryKey, sql, text
|
|
|
4
4
|
import { ensureSnapshotVersionColumn, upsertSnapshot } from "../db/queries/event-store.js";
|
|
5
5
|
import { selectMany } from "../db/query.js";
|
|
6
6
|
import { tableExists } from "../db/schema-inspection.js";
|
|
7
|
-
import { unsafePushTables } from "../
|
|
7
|
+
import { unsafePushTables } from "../db/table-push.js";
|
|
8
8
|
import { isStreamArchived } from "./archive.js";
|
|
9
9
|
import { loadEventsAfterVersion } from "./event-store.js";
|
|
10
10
|
// Marten-aligned snapshot store. A snapshot is a point-in-time materialised
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// separate CLI step — not implemented here, tracked as follow-up.
|
|
14
14
|
import { bigint, index, integer, jsonb, table as pgTable, text, timestamp, uuid, } from "../db/dialect.js";
|
|
15
15
|
import { tableExists } from "../db/schema-inspection.js";
|
|
16
|
-
import { unsafePushTables } from "../
|
|
16
|
+
import { unsafePushTables } from "../db/table-push.js";
|
|
17
17
|
export const upcasterDeadLetterTable = pgTable("kumiko_upcaster_dead_letters", {
|
|
18
18
|
// Surrogate PK. We don't reuse eventId so a single event can land
|
|
19
19
|
// here multiple times (retry attempts across deploys before the fix
|
|
@@ -49,7 +49,7 @@ export async function createUpcasterDeadLetterTable(db) {
|
|
|
49
49
|
// ops tooling uses it for correlate-and-replay flows.
|
|
50
50
|
export async function recordUpcasterDeadLetter(db, args) {
|
|
51
51
|
const message = args.error instanceof Error ? args.error.message : String(args.error);
|
|
52
|
-
const { insertOne } = await import("../
|
|
52
|
+
const { insertOne } = await import("../db/query.js");
|
|
53
53
|
await insertOne(db, upcasterDeadLetterTable, {
|
|
54
54
|
eventId: args.event.id,
|
|
55
55
|
tenantId: args.event.tenantId,
|
|
@@ -65,7 +65,7 @@ export async function recordUpcasterDeadLetter(db, args) {
|
|
|
65
65
|
// Ops-side query. Loads recent failures, optionally scoped by event-type
|
|
66
66
|
// to triage a single broken migration without pulling the full table.
|
|
67
67
|
export async function listDeadLetters(db, options = {}) {
|
|
68
|
-
const { selectMany } = await import("../
|
|
68
|
+
const { selectMany } = await import("../db/query.js");
|
|
69
69
|
const limit = options.limit ?? 100;
|
|
70
70
|
const where = options.eventType !== undefined ? { eventType: options.eventType } : undefined;
|
|
71
71
|
const rows = await selectMany(db, upcasterDeadLetterTable, where, {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { fetchOne } from "../
|
|
1
|
+
import { fetchOne } from "../db/query.js";
|
|
2
2
|
import { FrameworkReasons, InternalError, UnprocessableError, writeFailure, } from "../errors/index.js";
|
|
3
3
|
import { createFileRefRow, DEFAULT_MAX_UPLOAD_SIZE, storeFileAsFileRef, writeAcceptedFileBytes, } from "./create-file-ref.js";
|
|
4
4
|
import { fileRefsTable } from "./file-ref-table.js";
|
|
@@ -2,8 +2,8 @@ import { Hono } from "hono";
|
|
|
2
2
|
import { bodyLimit } from "hono/body-limit";
|
|
3
3
|
import { getUser } from "../api/auth-middleware.js";
|
|
4
4
|
import { requestContext } from "../api/request-context.js";
|
|
5
|
-
import { selectMany } from "../bun-db/index.js";
|
|
6
5
|
import { collectPiiSubjectFields, configuredPiiSubjectKms, decryptPiiFieldValues, isPiiCiphertext, PII_ERASED_SENTINEL, } from "../crypto/index.js";
|
|
6
|
+
import { selectMany } from "../db/query.js";
|
|
7
7
|
import { createProjectingTenantDb } from "../db/tenant-db.js";
|
|
8
8
|
import { createDerivativesContext, resolveFieldVariant, resolveRenderer, } from "../derivatives/index.js";
|
|
9
9
|
import { SYSTEM_USER_ID } from "../engine/system-user.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { createDbConnection } from "../db/connection.js";
|
|
2
|
+
export { createDatabase, databaseExists, dropDatabaseIfExists, truncateTablesRestartIdentity, } from "../db/queries/test-stack.js";
|
|
3
|
+
export { type AnyDb, isClosedConnectionError } from "../db/query.js";
|
|
4
|
+
export { columnNamesOf } from "../db/schema-inspection.js";
|
|
5
|
+
export { schemaTableName } from "../db/table-introspection.js";
|
|
6
|
+
export { addMissingColumns, addMissingIndexes, tableToMeta, unsafeCreateEntityTable, unsafeEnsureEntityTable, unsafePushTables, } from "../db/table-push.js";
|
|
7
|
+
export { SEARCHABLE_FALSE_WHITELIST } from "../engine/boot-validator/entity-list-screens.js";
|
|
8
|
+
export { validateNavBootSubset } from "../engine/boot-validator/index.js";
|
|
9
|
+
export { validateOwnershipBoot } from "../engine/boot-validator/ownership.js";
|
|
10
|
+
export { featureHasI18nSurface, requiredKeysFromFeature } from "../i18n/required-surface-keys.js";
|
|
11
|
+
export type { Lifecycle } from "../lifecycle/index.js";
|
|
12
|
+
export { createRateLimitResolver } from "../rate-limit/index.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// @runtime dev
|
|
2
|
+
export { createDbConnection } from "../db/connection.js";
|
|
3
|
+
export { createDatabase, databaseExists, dropDatabaseIfExists, truncateTablesRestartIdentity, } from "../db/queries/test-stack.js";
|
|
4
|
+
export { isClosedConnectionError } from "../db/query.js";
|
|
5
|
+
export { columnNamesOf } from "../db/schema-inspection.js";
|
|
6
|
+
export { schemaTableName } from "../db/table-introspection.js";
|
|
7
|
+
export { addMissingColumns, addMissingIndexes, tableToMeta, unsafeCreateEntityTable, unsafeEnsureEntityTable, unsafePushTables, } from "../db/table-push.js";
|
|
8
|
+
export { SEARCHABLE_FALSE_WHITELIST } from "../engine/boot-validator/entity-list-screens.js";
|
|
9
|
+
export { validateNavBootSubset } from "../engine/boot-validator/index.js";
|
|
10
|
+
export { validateOwnershipBoot } from "../engine/boot-validator/ownership.js";
|
|
11
|
+
export { featureHasI18nSurface, requiredKeysFromFeature } from "../i18n/required-surface-keys.js";
|
|
12
|
+
export { createRateLimitResolver } from "../rate-limit/index.js";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { resetBlindIndexKeyForTests } from "../crypto/blind-index.js";
|
|
2
|
+
export { resetEventPiiCatalogForTests } from "../crypto/event-pii.js";
|
|
3
|
+
export { resetPiiSubjectKmsForTests } from "../crypto/pii-field-encryption.js";
|
|
4
|
+
export { resetEntityFieldEncryptionCacheForTests } from "../db/entity-field-encryption.js";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// @runtime test
|
|
2
|
+
export { resetBlindIndexKeyForTests } from "../crypto/blind-index.js";
|
|
3
|
+
export { resetEventPiiCatalogForTests } from "../crypto/event-pii.js";
|
|
4
|
+
export { resetPiiSubjectKmsForTests } from "../crypto/pii-field-encryption.js";
|
|
5
|
+
export { resetEntityFieldEncryptionCacheForTests } from "../db/entity-field-encryption.js";
|
package/dist/jobs/job-runner.js
CHANGED
|
@@ -6,6 +6,7 @@ import { Redis } from "ioredis";
|
|
|
6
6
|
import { requestContext } from "../api/request-context.js";
|
|
7
7
|
import { createTenantDb, createUncheckedSystemDb } from "../db/tenant-db.js";
|
|
8
8
|
import { createDerivativesContext } from "../derivatives/derivatives-context.js";
|
|
9
|
+
import { bridgeStub } from "../engine/bridge-stub.js";
|
|
9
10
|
import { qnScope } from "../engine/qualified-name.js";
|
|
10
11
|
import { createSystemUser } from "../engine/system-user.js";
|
|
11
12
|
import { SYSTEM_TENANT_ID, } from "../engine/types/index.js";
|
|
@@ -19,7 +20,6 @@ import { RedisKeys } from "../pipeline/redis-keys.js";
|
|
|
19
20
|
import { createGatedIdentitySwitch } from "../pipeline/system-identity-switch.js";
|
|
20
21
|
import { TENANT_TIMEZONE_CONFIG_KEY } from "../pipeline/tenant-timezone-config-key.js";
|
|
21
22
|
import { buildPersonalDataGate, isPersonalDataGated, parseWriteOrigin, } from "../pipeline/write-origin.js";
|
|
22
|
-
import { bridgeStub } from "../testing/handler-context.js";
|
|
23
23
|
import { createTzContext, isValidIanaTimeZone } from "../time/index.js";
|
|
24
24
|
import { cronRepeatOptions } from "./cron-repeat-options.js";
|
|
25
25
|
import { resolveMaxPerTenant } from "./max-per-tenant.js";
|
|
@@ -429,7 +429,7 @@ export function createJobRunner(options) {
|
|
|
429
429
|
return undefined;
|
|
430
430
|
return async () => {
|
|
431
431
|
const systemUser = createSystemUser(SYSTEM_TENANT_ID);
|
|
432
|
-
const systemModeDb = createTenantDb(db, SYSTEM_TENANT_ID, "system");
|
|
432
|
+
const systemModeDb = createTenantDb({ db, tenantId: SYSTEM_TENANT_ID, mode: "system" });
|
|
433
433
|
const reportEscapeHatch = createEscapeHatchReporter({
|
|
434
434
|
handler: ACTIVE_TENANT_IDS_QUERY_NAME,
|
|
435
435
|
tenantId: SYSTEM_TENANT_ID,
|
|
@@ -922,9 +922,14 @@ export function createJobRunner(options) {
|
|
|
922
922
|
// unchecked cross-tenant escape hatch for such a job. Gated like jobDb so
|
|
923
923
|
// ctx.systemDb, built from it, is gated too.
|
|
924
924
|
const tenantScopedDb = configDb
|
|
925
|
-
? createTenantDb(
|
|
926
|
-
|
|
927
|
-
|
|
925
|
+
? createTenantDb({
|
|
926
|
+
db: configDb,
|
|
927
|
+
tenantId,
|
|
928
|
+
mode: "system",
|
|
929
|
+
grants: {
|
|
930
|
+
projectionRegistry: registry,
|
|
931
|
+
...(jobPersonalDataGate && { personalDataGate: jobPersonalDataGate }),
|
|
932
|
+
},
|
|
928
933
|
})
|
|
929
934
|
: undefined;
|
|
930
935
|
const isSystemJob = registry.isJobSystemScoped(jobName);
|
|
@@ -945,12 +950,19 @@ export function createJobRunner(options) {
|
|
|
945
950
|
? createUncheckedSystemDb(tenantScopedDb, undefined, reportEscapeHatch)
|
|
946
951
|
: undefined;
|
|
947
952
|
const jobDb = configDb
|
|
948
|
-
? createTenantDb(
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
953
|
+
? createTenantDb({
|
|
954
|
+
db: configDb,
|
|
955
|
+
tenantId,
|
|
956
|
+
mode: "tenant",
|
|
957
|
+
tracer: context.tracer,
|
|
958
|
+
meter: context.meter,
|
|
959
|
+
grants: {
|
|
960
|
+
unsafeRaw: escapeHatchFor(jobDef.escapeHatch, "unsafeRaw"),
|
|
961
|
+
globalWrites: escapeHatchFor(jobDef.escapeHatch, "globalWrites"),
|
|
962
|
+
report: reportEscapeHatch,
|
|
963
|
+
projectionRegistry: registry,
|
|
964
|
+
...(jobPersonalDataGate && { personalDataGate: jobPersonalDataGate }),
|
|
965
|
+
},
|
|
954
966
|
})
|
|
955
967
|
: undefined;
|
|
956
968
|
const crossTenantReadsReason = escapeHatchFor(jobDef.escapeHatch, "unsafeRaw")?.reason;
|
|
@@ -14,9 +14,9 @@ import { instant, table as pgTable, sql, text } from "../db/dialect.js";
|
|
|
14
14
|
import { deleteMany, selectMany, upsertOnConflict } from "../db/query.js";
|
|
15
15
|
import { readRebuildMarker } from "../db/rebuild-marker.js";
|
|
16
16
|
import { tableExists } from "../db/schema-inspection.js";
|
|
17
|
+
import { unsafePushTables } from "../db/table-push.js";
|
|
17
18
|
import { createFallbackLogger } from "../logging/utils.js";
|
|
18
19
|
import { rebuildMultiStreamProjection, rebuildProjection, } from "../pipeline/index.js";
|
|
19
|
-
import { unsafePushTables } from "../stack/index.js";
|
|
20
20
|
import { buildProjectionTableIndex } from "./projection-table-index.js";
|
|
21
21
|
export const pendingRebuildsTable = pgTable("kumiko_pending_rebuilds", {
|
|
22
22
|
tableName: text("table_name").primaryKey(),
|
|
@@ -18,8 +18,8 @@ import { alterTableAddColumn } from "../db/queries/ddl.js";
|
|
|
18
18
|
import { persistPiiBackfillState, readPiiBackfillState, } from "../db/queries/pii-backfill-state.js";
|
|
19
19
|
import { upsertOnConflict } from "../db/query.js";
|
|
20
20
|
import { tableExists } from "../db/schema-inspection.js";
|
|
21
|
+
import { unsafePushTables } from "../db/table-push.js";
|
|
21
22
|
import { createFallbackLogger } from "../logging/utils.js";
|
|
22
|
-
import { unsafePushTables } from "../stack/index.js";
|
|
23
23
|
import { clearPendingRebuilds, createPendingRebuildsTable, listPendingRebuildRows, pendingRebuildsTable, rebuildProjectionOrMultiStream, } from "./pending-rebuilds.js";
|
|
24
24
|
import { buildProjectionTableIndex } from "./projection-table-index.js";
|
|
25
25
|
const PII_EVENT_BACKFILL_LOCK_NAMESPACE = 0x70_69_69_62; // 'piib'
|
|
@@ -71,7 +71,7 @@ export function piiAnnotationEntries(registry) {
|
|
|
71
71
|
// Bump when the backfill gains a transform stage: completed states keyed by the
|
|
72
72
|
// old fingerprint must run one more full pass. Kept out of piiAnnotationEntries,
|
|
73
73
|
// whose emptiness gates no_pii.
|
|
74
|
-
const PII_BACKFILL_TRANSFORM_VERSION = "owner-rekey-
|
|
74
|
+
const PII_BACKFILL_TRANSFORM_VERSION = "owner-rekey-v2";
|
|
75
75
|
export function piiAnnotationFingerprint(registry) {
|
|
76
76
|
return createHash("sha256")
|
|
77
77
|
.update([...piiAnnotationEntries(registry), PII_BACKFILL_TRANSFORM_VERSION].join("\n"))
|
|
@@ -289,16 +289,24 @@ readOnlyForTenant = false) {
|
|
|
289
289
|
});
|
|
290
290
|
const identitySwitchGrantReason = identitySwitchEscapeHatch?.reason ??
|
|
291
291
|
(isSystem ? `r.systemScope() feature "${featureName ?? "unknown"}"` : undefined);
|
|
292
|
-
const buildTenantScopedDb = (source, signal, foreignTenantId, denyWrites = false) => createTenantDb(
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
292
|
+
const buildTenantScopedDb = (source, signal, foreignTenantId, denyWrites = false) => createTenantDb({
|
|
293
|
+
db: source,
|
|
294
|
+
tenantId: foreignTenantId ?? user.tenantId,
|
|
295
|
+
mode: isSystem && foreignTenantId === undefined ? "system" : "tenant",
|
|
296
|
+
tracer: context.tracer,
|
|
297
|
+
meter: context.meter,
|
|
298
|
+
signal,
|
|
299
|
+
grants: {
|
|
300
|
+
...(foreignTenantId === undefined && {
|
|
301
|
+
globalWrites: escapeHatchFor(writeEscapeHatch, "globalWrites"),
|
|
302
|
+
unsafeRaw: escapeHatchFor(handlerEscapeHatch, "unsafeRaw"),
|
|
303
|
+
}),
|
|
304
|
+
report: reportEscapeHatch,
|
|
305
|
+
memberReadOnly: isMemberResolutionPrincipal(user),
|
|
306
|
+
personalDataGate: buildPersonalDataGate(registry, origin),
|
|
307
|
+
projectionRegistry: registry,
|
|
308
|
+
...(denyWrites && { writesDeniedReason: "without an open transaction" }),
|
|
309
|
+
},
|
|
302
310
|
});
|
|
303
311
|
// Propagate the request's AbortSignal so every TenantDb query throws when
|
|
304
312
|
// the client has disconnected — handlers with many sequential queries skip
|
|
@@ -410,7 +418,14 @@ readOnlyForTenant = false) {
|
|
|
410
418
|
const targetSystemUser = createSystemUser(targetTenantId);
|
|
411
419
|
return configFactory({
|
|
412
420
|
user: { id: targetSystemUser.id, tenantId: targetTenantId },
|
|
413
|
-
db: createTenantDb(
|
|
421
|
+
db: createTenantDb({
|
|
422
|
+
db: dbSource,
|
|
423
|
+
tenantId: targetTenantId,
|
|
424
|
+
mode: "tenant",
|
|
425
|
+
tracer: context.tracer,
|
|
426
|
+
meter: context.meter,
|
|
427
|
+
grants: { projectionRegistry: registry },
|
|
428
|
+
}),
|
|
414
429
|
secrets: context.secrets,
|
|
415
430
|
});
|
|
416
431
|
}
|
|
@@ -886,9 +901,7 @@ readOnlyForTenant = false) {
|
|
|
886
901
|
// Finger an typo-resistenten ctx.user-Patterns. Identisch zum
|
|
887
902
|
// event.user-Wert; Identity-Switches nutzen weiterhin queryAs/writeAs.
|
|
888
903
|
user,
|
|
889
|
-
_userId: user.id,
|
|
890
904
|
_tenantId: user.tenantId,
|
|
891
|
-
_handlerType: type,
|
|
892
905
|
...(hasLiveCommitSink && { scheduleAfterCommit }),
|
|
893
906
|
...(includeDeleted && { includeDeleted: true }),
|
|
894
907
|
...bridge,
|
|
@@ -1219,16 +1232,23 @@ function buildAuthClaimsContext(ctx, user) {
|
|
|
1219
1232
|
message: "dispatcher.resolveAuthClaims requires a database connection — none is configured.",
|
|
1220
1233
|
});
|
|
1221
1234
|
}
|
|
1222
|
-
const db = createTenantDb(
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1235
|
+
const db = createTenantDb({
|
|
1236
|
+
db: dbSource,
|
|
1237
|
+
tenantId: user.tenantId,
|
|
1238
|
+
mode: "tenant",
|
|
1239
|
+
tracer: context.tracer,
|
|
1240
|
+
meter: context.meter,
|
|
1241
|
+
grants: {
|
|
1242
|
+
report: createEscapeHatchReporter({
|
|
1243
|
+
handler: "r.authClaims hook",
|
|
1244
|
+
tenantId: user.tenantId,
|
|
1245
|
+
actor: user.id,
|
|
1246
|
+
sink: context._escapeHatchAuditSink,
|
|
1247
|
+
log: context.log ?? createFallbackLogger("dispatcher"),
|
|
1248
|
+
window: ctx.escapeHatchReportWindow,
|
|
1249
|
+
}),
|
|
1250
|
+
projectionRegistry: ctx.registry,
|
|
1251
|
+
},
|
|
1232
1252
|
});
|
|
1233
1253
|
const configAccessor = context._configAccessorFactory
|
|
1234
1254
|
? context._configAccessorFactory({
|
|
@@ -163,7 +163,7 @@ async function isParentRowHiddenFromCaller(ctx, parentEntityName, parentId, user
|
|
|
163
163
|
const source = resolveDbSource(ctx, tx);
|
|
164
164
|
if (!table || !source)
|
|
165
165
|
return true;
|
|
166
|
-
const callerDb = createTenantDb(source, user.tenantId, "tenant");
|
|
166
|
+
const callerDb = createTenantDb({ db: source, tenantId: user.tenantId, mode: "tenant" });
|
|
167
167
|
const visibleRow = await callerDb.fetchOne(table, { id: parentId });
|
|
168
168
|
if (visibleRow === undefined)
|
|
169
169
|
return true;
|
|
@@ -181,7 +181,11 @@ async function completeParentRow(ctx, parentEntityName, parentEntity, parentRow,
|
|
|
181
181
|
const source = resolveDbSource(ctx, tx);
|
|
182
182
|
if (!table || !source || typeof parentRow["id"] !== "string")
|
|
183
183
|
return parentRow;
|
|
184
|
-
const stored = await createTenantDb(
|
|
184
|
+
const stored = await createTenantDb({
|
|
185
|
+
db: source,
|
|
186
|
+
tenantId: user.tenantId,
|
|
187
|
+
mode: "tenant",
|
|
188
|
+
}).fetchOne(table, {
|
|
185
189
|
id: parentRow["id"],
|
|
186
190
|
});
|
|
187
191
|
return stored ? { ...stored, ...parentRow } : parentRow;
|
|
@@ -143,10 +143,14 @@ export function resolveType(type) {
|
|
|
143
143
|
// A custom write losing an append race (ctx.appendEvent, stream.append) is a
|
|
144
144
|
// retryable 409 like the CRUD executor's, not an internal error. Mapped here
|
|
145
145
|
// because errors/ is client code and must not import the event store.
|
|
146
|
-
// currentVersion -1 is the
|
|
146
|
+
// currentVersion -1 is the "not looked up" sentinel for a bare 23505 fallback.
|
|
147
147
|
export function wrapToKumiko(e) {
|
|
148
148
|
if (e instanceof EventStoreVersionConflictError) {
|
|
149
|
-
return new VersionConflictError({
|
|
149
|
+
return new VersionConflictError({
|
|
150
|
+
entityId: e.aggregateId,
|
|
151
|
+
expectedVersion: e.expectedVersion,
|
|
152
|
+
currentVersion: e.currentVersion ?? -1,
|
|
153
|
+
}, { cause: e });
|
|
150
154
|
}
|
|
151
155
|
return toKumikoError(e);
|
|
152
156
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { bigint, index, instant, integer, jsonb, table as pgTable, primaryKey, sql, text, } from "../db/dialect.js";
|
|
2
2
|
import { alterTableAddColumn } from "../db/queries/ddl.js";
|
|
3
3
|
import { tableExists } from "../db/schema-inspection.js";
|
|
4
|
-
import { unsafePushTables } from "../
|
|
4
|
+
import { unsafePushTables } from "../db/table-push.js";
|
|
5
5
|
// Reserved sentinel used in the instance_id column for consumers whose
|
|
6
6
|
// delivery is "shared" — i.e. one cursor across all dispatcher instances
|
|
7
7
|
// (the default, pre-Welle-2.7 behaviour). Per-instance consumers store
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import type { DbConnection } from "../db/connection.js";
|
|
3
3
|
import type { Registry } from "../engine/types/index.js";
|
|
4
4
|
import type { Meter } from "../observability/types/metric.js";
|
|
5
|
+
export declare const REBUILD_BATCH_SIZE = 1000;
|
|
5
6
|
export type RebuildResult = {
|
|
6
7
|
readonly projection: string;
|
|
7
8
|
readonly eventsProcessed: number;
|
|
@@ -8,7 +8,7 @@ import { projectionStateTable } from "./projection-state.js";
|
|
|
8
8
|
// Events replayed per catch-up batch. Each batch is a fresh READ COMMITTED
|
|
9
9
|
// SELECT, so a batch shorter than this means the currently-committed tail is
|
|
10
10
|
// drained.
|
|
11
|
-
const REBUILD_BATCH_SIZE = 1000;
|
|
11
|
+
export const REBUILD_BATCH_SIZE = 1000;
|
|
12
12
|
// Cap on UNLOCKED catch-up batches before forcing the cutover fence. Bounds the
|
|
13
13
|
// lock-free phase under sustained writes that never momentarily quiesce; the
|
|
14
14
|
// fenced final drain then always terminates (no new event can commit once the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { bigint, index, instant, table as pgTable, sql, text } from "../db/dialect.js";
|
|
2
2
|
import { tableExists } from "../db/schema-inspection.js";
|
|
3
|
-
import { unsafePushTables } from "../
|
|
3
|
+
import { unsafePushTables } from "../db/table-push.js";
|
|
4
4
|
// Framework-level state for every registered projection. One row per qualified
|
|
5
5
|
// projection name. Written by the rebuild machinery; read by the CLI + any
|
|
6
6
|
// status dashboard. Lives alongside the events table as framework infra —
|
|
@@ -206,7 +206,7 @@ async function readProjectionRowForSearch(ctx, registry, entityName, entity, ten
|
|
|
206
206
|
if (entity.softDelete && table["isDeleted"]) {
|
|
207
207
|
where["isDeleted"] = false;
|
|
208
208
|
}
|
|
209
|
-
const row = await createTenantDb(baseDb, tenantId).fetchOne(table, where);
|
|
209
|
+
const row = await createTenantDb({ db: baseDb, tenantId }).fetchOne(table, where);
|
|
210
210
|
if (!row)
|
|
211
211
|
return undefined;
|
|
212
212
|
const state = rehydrateCompoundTypes(row, entity);
|
package/dist/schema-cli.js
CHANGED
|
@@ -303,7 +303,7 @@ export async function runSchemaCli(argv, appCwd, out, options = {}) {
|
|
|
303
303
|
out.err(` ${migrationsDir} fehlt — erst schema generate <name>.`);
|
|
304
304
|
return 1;
|
|
305
305
|
}
|
|
306
|
-
const { db, close } = createDbConnection(dbUrl);
|
|
306
|
+
const { db, close } = createDbConnection({ url: dbUrl });
|
|
307
307
|
let wiring;
|
|
308
308
|
try {
|
|
309
309
|
const result = await runMigrationsFromDir(db, migrationsDir);
|
|
@@ -386,7 +386,7 @@ export async function runSchemaCli(argv, appCwd, out, options = {}) {
|
|
|
386
386
|
out.err(` ${migrationsDir} fehlt — erst schema generate <name>.`);
|
|
387
387
|
return 1;
|
|
388
388
|
}
|
|
389
|
-
const { db, close } = createDbConnection(dbUrl);
|
|
389
|
+
const { db, close } = createDbConnection({ url: dbUrl });
|
|
390
390
|
try {
|
|
391
391
|
const result = await baselineMigrations(db, loadMigrationsFromDir(migrationsDir));
|
|
392
392
|
out.log("");
|
|
@@ -418,7 +418,7 @@ export async function runSchemaCli(argv, appCwd, out, options = {}) {
|
|
|
418
418
|
return 0;
|
|
419
419
|
}
|
|
420
420
|
const local = loadMigrationsFromDir(migrationsDir);
|
|
421
|
-
const { db, close } = createDbConnection(dbUrl);
|
|
421
|
+
const { db, close } = createDbConnection({ url: dbUrl });
|
|
422
422
|
try {
|
|
423
423
|
// Frische DB ohne je gelaufenes `kumiko schema apply` → tracking-table
|
|
424
424
|
// fehlt = "nichts applied". Connection-/Permission-Fehler dagegen
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// that still carry the subject key in encrypted columns.
|
|
10
10
|
import { quoteIdent, subjectCiphertextLikePattern } from "../crypto/ciphertext-pattern.js";
|
|
11
11
|
import { isSelfPiiField } from "../crypto/is-self-pii-field.js";
|
|
12
|
-
import { collectSearchableSubjectFields } from "../crypto/subject-resolver.js";
|
|
12
|
+
import { collectSearchableSubjectFields, isRecordKeyedField } from "../crypto/subject-resolver.js";
|
|
13
13
|
import { resolveTableName } from "../db/entity-table-meta.js";
|
|
14
14
|
import { executeRawQueryRead } from "../db/queries/raw-sql.js";
|
|
15
15
|
import { columnNamesOf, tableExists } from "../db/schema-inspection.js";
|
|
@@ -63,20 +63,30 @@ function tenantOwnershipPredicates(entity, searchableFields, tenantId, nextParam
|
|
|
63
63
|
return finalizePredicateParts(parts, params);
|
|
64
64
|
}
|
|
65
65
|
function recordOwnershipPredicates(entity, searchableFields, entityName, subjectEntity, subjectId, nextParam) {
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
let recordIdN;
|
|
66
|
+
const ownerlessColumns = new Set();
|
|
67
|
+
let hasRecordOwnedField = false;
|
|
69
68
|
for (const fieldName of searchableFields) {
|
|
70
69
|
const field = entity.fields[fieldName];
|
|
71
|
-
if (!field)
|
|
70
|
+
if (!field || entityName !== subjectEntity || !isRecordKeyedField(field))
|
|
72
71
|
continue;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
72
|
+
if ("recordOwned" in field && field.recordOwned === true) {
|
|
73
|
+
hasRecordOwnedField = true;
|
|
74
|
+
}
|
|
75
|
+
else if ("userOwned" in field && field.userOwned !== undefined) {
|
|
76
|
+
ownerlessColumns.add(toSnakeCase(field.userOwned.ownerField));
|
|
78
77
|
}
|
|
79
78
|
}
|
|
79
|
+
if (!hasRecordOwnedField && ownerlessColumns.size === 0)
|
|
80
|
+
return null;
|
|
81
|
+
const idN = nextParam();
|
|
82
|
+
const parts = [];
|
|
83
|
+
if (hasRecordOwnedField)
|
|
84
|
+
parts.push(`${quoteIdent("id")} = $${idN}`);
|
|
85
|
+
// whenAbsent: "self" keys a row on itself only while its owner is empty
|
|
86
|
+
for (const col of ownerlessColumns) {
|
|
87
|
+
parts.push(`(${quoteIdent("id")} = $${idN} AND (${quoteIdent(col)} IS NULL OR ${quoteIdent(col)}::text = ''))`);
|
|
88
|
+
}
|
|
89
|
+
const params = [subjectId];
|
|
80
90
|
return finalizePredicateParts(parts, params);
|
|
81
91
|
}
|
|
82
92
|
/** Build OR predicates for rows owned by `subject` (id / ownerField / tenant_id). */
|
package/dist/seeding/index.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export { type EventStoreSeedExisting, type RunEventStoreSeedOptions, runEventStoreSeed, } from "./entity-seed.js";
|
|
2
|
+
export { createTestUser, TestUsers, testTenantId, testUserId } from "./seed-users.js";
|
|
2
3
|
export { DEFAULT_SEED_IF_EXISTS, type SeedIfExists } from "./types.js";
|
package/dist/seeding/index.js
CHANGED
package/dist/stack/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated Moved to `@cosmicdrift/kumiko-testing/stack`. Run `bun kumiko-upgrade --apply`
|
|
3
|
+
* to rewrite imports. Removed in the first release after 2026-10-29.
|
|
4
|
+
*/
|
|
5
|
+
export * from "@cosmicdrift/kumiko-testing/stack";
|
|
6
|
+
/**
|
|
7
|
+
* @deprecated Moved to `@cosmicdrift/kumiko-framework/seeding`. Run `bun kumiko-upgrade --apply`
|
|
8
|
+
* to rewrite imports. Removed in the first release after 2026-10-29.
|
|
9
|
+
*/
|
|
10
|
+
export { createTestUser, TestUsers, testTenantId, testUserId } from "../seeding/seed-users.js";
|
package/dist/stack/index.js
CHANGED
|
@@ -1,19 +1,11 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export {
|
|
12
|
-
export { drainEventConsumers } from "./drain-event-consumers.js";
|
|
13
|
-
export { createEventCollector } from "./event-collector.js";
|
|
14
|
-
export { pushEntityProjectionTables } from "./push-entity-projection-tables.js";
|
|
15
|
-
export { createTestRedis } from "./redis.js";
|
|
16
|
-
export { createRequestHelper } from "./request-helper.js";
|
|
17
|
-
export { resetEventStore, unsafeCreateEntityTable, unsafeEnsureEntityTable, unsafePushTables, } from "./table-helpers.js";
|
|
18
|
-
export { setupTestStack } from "./test-stack.js";
|
|
19
|
-
export { createTestUser, TestUsers, testTenantId, testUserId, } from "./test-users.js";
|
|
1
|
+
// @runtime test
|
|
2
|
+
/**
|
|
3
|
+
* @deprecated Moved to `@cosmicdrift/kumiko-testing/stack`. Run `bun kumiko-upgrade --apply`
|
|
4
|
+
* to rewrite imports. Removed in the first release after 2026-10-29.
|
|
5
|
+
*/
|
|
6
|
+
export * from "@cosmicdrift/kumiko-testing/stack";
|
|
7
|
+
/**
|
|
8
|
+
* @deprecated Moved to `@cosmicdrift/kumiko-framework/seeding`. Run `bun kumiko-upgrade --apply`
|
|
9
|
+
* to rewrite imports. Removed in the first release after 2026-10-29.
|
|
10
|
+
*/
|
|
11
|
+
export { createTestUser, TestUsers, testTenantId, testUserId } from "../seeding/seed-users.js";
|
|
@@ -1,49 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
readonly title: string;
|
|
7
|
-
readonly urlPath: string;
|
|
8
|
-
} | {
|
|
9
|
-
readonly kind: "list-has-fixture-row";
|
|
10
|
-
readonly screenQn: string;
|
|
11
|
-
readonly title: string;
|
|
12
|
-
readonly urlPath: string;
|
|
13
|
-
readonly writeHandlerQn: string;
|
|
14
|
-
readonly fixture: Readonly<Record<string, unknown>>;
|
|
15
|
-
readonly identifyingValue: string;
|
|
16
|
-
} | {
|
|
17
|
-
readonly kind: "edit-validates-required";
|
|
18
|
-
readonly screenQn: string;
|
|
19
|
-
readonly title: string;
|
|
20
|
-
readonly urlPath: string;
|
|
21
|
-
readonly requiredFields: readonly string[];
|
|
22
|
-
} | {
|
|
23
|
-
readonly kind: "edit-save-persists";
|
|
24
|
-
readonly screenQn: string;
|
|
25
|
-
readonly title: string;
|
|
26
|
-
readonly urlPath: string;
|
|
27
|
-
readonly listUrlPath?: string;
|
|
28
|
-
readonly fills: readonly EditFillOp[];
|
|
29
|
-
readonly identifyingValue: string;
|
|
30
|
-
readonly identifyingField: string;
|
|
31
|
-
};
|
|
32
|
-
export type EditFillOp = {
|
|
33
|
-
readonly kind: "fill";
|
|
34
|
-
readonly field: string;
|
|
35
|
-
readonly value: string;
|
|
36
|
-
} | {
|
|
37
|
-
readonly kind: "check";
|
|
38
|
-
readonly field: string;
|
|
39
|
-
readonly value: boolean;
|
|
40
|
-
} | {
|
|
41
|
-
readonly kind: "select";
|
|
42
|
-
readonly field: string;
|
|
43
|
-
readonly value: string;
|
|
44
|
-
};
|
|
45
|
-
export type E2EGeneratorOptions = {
|
|
46
|
-
readonly tenantPlaceholder?: string;
|
|
47
|
-
};
|
|
48
|
-
export declare function generateE2ESpec(registry: Registry, options?: E2EGeneratorOptions): readonly E2ETestSpec[];
|
|
49
|
-
export declare function generateZodFixture(schema: z.ZodTypeAny): unknown;
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated Moved to `@cosmicdrift/kumiko-testing/helpers/e2e-generator`. Run
|
|
3
|
+
* `bun kumiko-upgrade --apply` to rewrite imports. Removed in the first release after 2026-10-29.
|
|
4
|
+
*/
|
|
5
|
+
export * from "@cosmicdrift/kumiko-testing/helpers/e2e-generator";
|