@cosmicdrift/kumiko-framework 0.353.0 → 0.354.1
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/dist/api/index.d.ts +1 -1
- package/dist/api/index.js +1 -1
- package/dist/api/redis-sse-broker.d.ts +1 -0
- package/dist/api/redis-sse-broker.js +16 -10
- package/dist/api/request-context.d.ts +1 -0
- package/dist/api/request-context.js +5 -0
- package/dist/api/routes.js +4 -2
- package/dist/api/server.js +28 -3
- package/dist/api/sse-broker.d.ts +7 -3
- package/dist/api/sse-route.js +2 -6
- package/dist/api/token-expiry-timer.d.ts +1 -0
- package/dist/api/token-expiry-timer.js +10 -0
- package/dist/bun-db/query.js +29 -2
- package/dist/crypto/event-pii.js +4 -2
- package/dist/crypto/kms-wiring.js +31 -5
- package/dist/db/eagerload.d.ts +8 -3
- package/dist/db/eagerload.js +85 -81
- package/dist/db/event-store-executor-context.d.ts +12 -0
- package/dist/db/event-store-executor-context.js +59 -18
- package/dist/db/event-store-executor-read.js +81 -31
- package/dist/db/event-store-executor-write.js +54 -3
- package/dist/db/index.d.ts +1 -1
- package/dist/db/migrate-generator.js +1 -1
- package/dist/db/queries/backfill-pii.d.ts +1 -0
- package/dist/db/queries/backfill-pii.js +11 -6
- package/dist/db/queries/event-consumer.d.ts +2 -3
- package/dist/db/queries/event-consumer.js +54 -43
- package/dist/db/queries/event-store.d.ts +5 -0
- package/dist/db/queries/event-store.js +51 -3
- package/dist/db/queries/pii-backfill-state.d.ts +8 -1
- package/dist/db/queries/pii-backfill-state.js +16 -5
- package/dist/db/queries/shadow-swap.js +32 -3
- package/dist/db/render-ddl.js +6 -6
- package/dist/db/table-builder.js +6 -7
- package/dist/db/tenant-db.d.ts +5 -2
- package/dist/db/tenant-db.js +47 -7
- package/dist/derivatives/variant-key.d.ts +1 -0
- package/dist/derivatives/variant-key.js +3 -0
- package/dist/engine/boot-validator/access-declarations.js +5 -0
- package/dist/engine/boot-validator/config-deps.js +3 -0
- package/dist/engine/boot-validator/entity-handler.d.ts +1 -0
- package/dist/engine/boot-validator/entity-handler.js +40 -0
- package/dist/engine/boot-validator/handler-field-references.d.ts +2 -0
- package/dist/engine/boot-validator/handler-field-references.js +25 -0
- package/dist/engine/boot-validator/index.js +6 -1
- package/dist/engine/boot-validator/nav.js +3 -1
- package/dist/engine/boot-validator/ownership.d.ts +2 -1
- package/dist/engine/boot-validator/ownership.js +32 -1
- package/dist/engine/boot-validator/pii-retention.js +8 -1
- package/dist/engine/boot-validator/query-output-columns.js +9 -9
- package/dist/engine/boot-validator/screens.js +98 -7
- package/dist/engine/boot-validator/transfer-graph.d.ts +2 -1
- package/dist/engine/boot-validator/transfer-graph.js +8 -63
- package/dist/engine/boot-validator/url-prefill-fields.d.ts +1 -0
- package/dist/engine/boot-validator/url-prefill-fields.js +35 -0
- package/dist/engine/build-app-schema.js +3 -0
- package/dist/engine/changeset-changes.d.ts +1 -0
- package/dist/engine/changeset-changes.js +49 -33
- package/dist/engine/define-feature.js +11 -0
- package/dist/engine/entity-handlers.d.ts +3 -3
- package/dist/engine/entity-handlers.js +55 -34
- package/dist/engine/escape-hatch-reason.d.ts +2 -0
- package/dist/engine/escape-hatch-reason.js +8 -0
- package/dist/engine/extension-names.d.ts +8 -9
- package/dist/engine/extension-names.js +8 -9
- package/dist/engine/extensions/tenant-data.d.ts +3 -1
- package/dist/engine/extensions/tenant-resource.d.ts +9 -1
- package/dist/engine/factories.d.ts +1 -1
- package/dist/engine/feature-changelog.d.ts +2 -0
- package/dist/engine/feature-changelog.js +6 -0
- package/dist/engine/feature-config-events-jobs.js +41 -4
- package/dist/engine/handler-field-references.d.ts +3 -0
- package/dist/engine/handler-field-references.js +31 -0
- package/dist/engine/i18n-key.js +2 -3
- package/dist/engine/index.d.ts +8 -2
- package/dist/engine/index.js +6 -1
- package/dist/engine/ownership.js +3 -4
- package/dist/engine/project-app-schema-for-roles.js +3 -1
- package/dist/engine/registry-ingest.d.ts +1 -0
- package/dist/engine/registry-ingest.js +8 -3
- package/dist/engine/run-pipeline.js +12 -1
- package/dist/engine/schema-builder.js +35 -2
- package/dist/engine/screen-helpers.d.ts +13 -0
- package/dist/engine/screen-helpers.js +31 -0
- package/dist/engine/soft-delete-cleanup.js +3 -2
- package/dist/engine/steps/_read-source.d.ts +4 -0
- package/dist/engine/steps/_read-source.js +22 -0
- package/dist/engine/steps/describe-workflow-step-error.js +3 -1
- package/dist/engine/steps/read-find-many.js +2 -1
- package/dist/engine/steps/read-find-one.js +2 -1
- package/dist/engine/steps/workflow-step-error.d.ts +5 -0
- package/dist/engine/steps/workflow-step-error.js +13 -0
- package/dist/engine/transfer-adjacency.d.ts +24 -0
- package/dist/engine/transfer-adjacency.js +107 -0
- package/dist/entrypoint/index.d.ts +2 -0
- package/dist/entrypoint/index.js +2 -0
- package/dist/env/index.js +45 -23
- package/dist/errors/classes.d.ts +8 -0
- package/dist/errors/classes.js +13 -0
- package/dist/errors/index.d.ts +2 -1
- package/dist/errors/index.js +2 -1
- package/dist/errors/reasons.d.ts +1 -0
- package/dist/errors/reasons.js +3 -0
- package/dist/errors/subject-erased.d.ts +2 -0
- package/dist/errors/subject-erased.js +9 -0
- package/dist/event-store/admin-api.js +14 -10
- package/dist/event-store/event-store.d.ts +1 -0
- package/dist/event-store/event-store.js +14 -9
- package/dist/event-store/events-schema.js +2 -1
- package/dist/event-store/index.d.ts +1 -1
- package/dist/event-store/index.js +1 -1
- package/dist/files/file-handle.d.ts +1 -1
- package/dist/files/file-handle.js +30 -6
- package/dist/files/file-routes.js +10 -4
- package/dist/files/resolve-content-type.d.ts +2 -0
- package/dist/files/resolve-content-type.js +8 -0
- package/dist/i18n/required-surface-keys.d.ts +2 -0
- package/dist/i18n/required-surface-keys.js +8 -0
- package/dist/jobs/index.d.ts +1 -1
- package/dist/jobs/job-runner.d.ts +13 -0
- package/dist/jobs/job-runner.js +128 -22
- package/dist/migrations/pii-event-backfill.js +46 -25
- package/dist/observability/index.d.ts +1 -1
- package/dist/observability/index.js +1 -1
- package/dist/observability/standard-metrics.d.ts +4 -0
- package/dist/observability/standard-metrics.js +12 -0
- package/dist/pipeline/dispatch-shared.d.ts +2 -0
- package/dist/pipeline/dispatch-shared.js +74 -9
- package/dist/pipeline/dispatch-stream.d.ts +5 -1
- package/dist/pipeline/dispatch-stream.js +19 -12
- package/dist/pipeline/dispatcher.d.ts +3 -1
- package/dist/pipeline/dispatcher.js +10 -15
- package/dist/pipeline/event-consumer-state.js +0 -26
- package/dist/pipeline/event-dispatcher-admin.js +17 -11
- package/dist/pipeline/event-dispatcher-delivery.d.ts +1 -1
- package/dist/pipeline/event-dispatcher-delivery.js +3 -2
- package/dist/pipeline/event-dispatcher.js +48 -7
- package/dist/pipeline/index.d.ts +2 -0
- package/dist/pipeline/index.js +1 -0
- package/dist/pipeline/member-read-only-transaction.js +25 -5
- package/dist/pipeline/msp-rebuild.js +3 -3
- package/dist/pipeline/pending-gap-ranges.d.ts +1 -0
- package/dist/pipeline/pending-gap-ranges.js +22 -0
- package/dist/pipeline/system-hooks.js +4 -4
- package/dist/pipeline/system-identity-switch.d.ts +1 -1
- package/dist/pipeline/system-identity-switch.js +5 -4
- package/dist/pipeline/tenant-timezone-cache.js +5 -3
- package/dist/redis/cache-sync-topics.d.ts +1 -0
- package/dist/redis/cache-sync-topics.js +1 -0
- package/dist/redis/client.d.ts +1 -0
- package/dist/redis/client.js +7 -0
- package/dist/redis/index.d.ts +1 -1
- package/dist/redis/index.js +1 -1
- package/dist/redis/pubsub-signal.d.ts +1 -0
- package/dist/redis/pubsub-signal.js +3 -0
- package/dist/search/meilisearch-adapter.js +34 -4
- package/dist/stack/test-stack.d.ts +4 -1
- package/dist/stack/test-stack.js +9 -2
- package/dist/testing/e2e-generator.js +7 -2
- package/dist/ui-types/index.d.ts +3 -3
- package/dist/ui-types/index.js +2 -2
- package/dist/upgrade-cli.js +7 -2
- package/package.json +12 -4
- package/src/changes.json +209 -0
- package/src/scripts/codemod/migrate-cross-tenant.ts +2 -1
package/src/changes.json
CHANGED
|
@@ -1,4 +1,213 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.354.1",
|
|
4
|
+
"type": "fix",
|
|
5
|
+
"title": "Executor list returns the stream version, so updates built on list rows no longer fail with version_conflict after ctx.appendEvent"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"version": "0.354.1",
|
|
9
|
+
"type": "fix",
|
|
10
|
+
"title": "Update schema accepts null on optional fields, so a preSave hook or client can clear a stored optional value",
|
|
11
|
+
"detail": "Update schema accepts null on optional fields, so a preSave hook or client can clear a stored optional value without presave_hook_invalid_output or a validation error"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"version": "0.354.0",
|
|
15
|
+
"type": "fix",
|
|
16
|
+
"title": "detail() no longer pairs an old row with a newer stream version, so update({ version: detail.version }) cannot overwrite a concurrent write",
|
|
17
|
+
"detail": "`detail()` reads the row and the stream version in one statement and validates entity-cache hits against the stream version\nBefore, a concurrent update between the row read and the version read handed out the old row with the new version, so `update({ version: detail.version })` passed the optimistic lock and overwrote the newer write. A cached row whose version differs from the stream version now counts as a cache miss."
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"version": "0.354.0",
|
|
21
|
+
"type": "fix",
|
|
22
|
+
"title": "_refs respect access.read, the parentRef gate and field-level read of the referenced entity; unreadable refs are omitted and the renderer falls back to the UUID",
|
|
23
|
+
"detail": "`_refs` only carry what the caller may read on the referenced entity\nEagerload used to resolve every referenced row of the tenant, so a reference field pointing at a team- or row-scoped entity leaked rows the caller could not read themselves. It now applies the target entity's `access.read` (row/team scope), its parentRef gate and its field-level read access, still with one batched lookup per reference field. A reference the caller may not read is omitted exactly like a missing one (no existence oracle); the renderer falls back to the UUID. The handler-level `access` of the target's detail handler is not evaluated, the declarative `access.read` of the target entity is authoritative (same model as reference search and sort).\n`enrichWithReferences` and `enrichRowWithReferences` take a required fifth argument `viewer: { user, parentVisibility }`. The old strip of PII/encrypted fields on ownership-scoped targets is gone: readable rows are decrypted, unreadable rows are not returned at all."
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"version": "0.354.0",
|
|
27
|
+
"type": "breaking",
|
|
28
|
+
"title": "enrichWithReferences and enrichRowWithReferences require a viewer { user, parentVisibility }",
|
|
29
|
+
"migration": "Custom handlers pass `{ user: query.user, parentVisibility: { entities: ctx.registry.getAllEntities() } }` as the fifth argument. No direct callers are known in the workspace apps. Apps can now point reference fields at team- or row-scoped entities (for example solon unitId/propertyId)."
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"version": "0.354.0",
|
|
33
|
+
"type": "breaking",
|
|
34
|
+
"title": "crossTenant removed from entity convention handlers; write handlers with escapeHatch need SystemAdmin-only access",
|
|
35
|
+
"migration": "Replace crossTenant: true with escapeHatch: { reason } (run bun node_modules/@cosmicdrift/kumiko-framework/src/scripts/codemod/migrate-cross-tenant.ts, then replace its placeholder reason, which is rejected otherwise). A create/update/delete/restore handler with escapeHatch must declare access: { roles: [\"SystemAdmin\"] }; list and detail handlers keep their access."
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"version": "0.354.0",
|
|
39
|
+
"type": "fix",
|
|
40
|
+
"title": "ctx.queryAsMember read-only context now allowlists searchAdapter (search), redis (read commands) and entityCache (get, mget); other methods are denied"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"version": "0.354.0",
|
|
44
|
+
"type": "improvement",
|
|
45
|
+
"title": "ctx.queryAsMember reads run under a statement timeout (DispatcherOptions.memberReadTimeoutMs, default 10000) and fail with member_read_timeout"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"version": "0.354.0",
|
|
49
|
+
"type": "fix",
|
|
50
|
+
"title": "ctx.queryProjection with unsafeAllTenants no longer demands a grant on projections without a tenant column"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"version": "0.354.0",
|
|
54
|
+
"type": "improvement",
|
|
55
|
+
"title": "defineProjectionQueryHandler accepts unsafeAllTenants: { reason } as grant and audit reason"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"version": "0.354.0",
|
|
59
|
+
"type": "fix",
|
|
60
|
+
"title": "Event append without a transaction is atomic; ctx.outsideTransaction; pending-gap ranges merge and are exported as a gauge; seed scan starts at the highest consumer cursor"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"version": "0.354.0",
|
|
64
|
+
"type": "improvement",
|
|
65
|
+
"title": "Failed job attempts are logged via the runner logger (job, jobId, attempt, final, error)"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"version": "0.354.0",
|
|
69
|
+
"type": "breaking",
|
|
70
|
+
"title": "Field-level access.read with a where-rule now fails the boot (also on embedded sub-fields)",
|
|
71
|
+
"migration": "Replace the where-rule on the field with a from()-rule (e.g. from(\"user:id\", \"ownerId\")) or move the where-rule to entity access.read. Field read access is evaluated in memory and could never grant a where-rule, so it only hid the field."
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"version": "0.354.0",
|
|
75
|
+
"type": "improvement",
|
|
76
|
+
"title": "kumiko_events gets a partial index over payload tenantId for tenant-membership streams",
|
|
77
|
+
"detail": "The forget-cleanup membership-history queries filter on payload->>'tenantId' and scanned all of kumiko_events. createEventsTable now also ensures events_membership_payload_tenant_idx ON kumiko_events ((payload->>'tenantId')) WHERE aggregate_type = 'tenant-membership', built CONCURRENTLY with the same INVALID-rebuild and race handling as the idempotency index. No migration: the index is created on the next boot or schema apply. On a large event history the first build takes a while but does not block appends."
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"version": "0.354.0",
|
|
81
|
+
"type": "improvement",
|
|
82
|
+
"title": "changes.json entries can set manualAfterCodemod to stay pending manual after the codemod ran",
|
|
83
|
+
"detail": "A codemod entry with `manualAfterCodemod: true` is recorded in `pendingManual` of `.kumiko/upgrade-state.json` in addition to the codemod run. Set it with `kumiko changes add --codemod <path> --manual-after-codemod`."
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"version": "0.354.0",
|
|
87
|
+
"type": "improvement",
|
|
88
|
+
"title": "read.findOne and read.findMany log a warning when a foreign where.tenantId is narrowed to the caller's tenant scope"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"version": "0.354.0",
|
|
92
|
+
"type": "breaking",
|
|
93
|
+
"title": "requestContext.run and runAsDirectCallEntry removed from the public /api barrel; requestContext there is read-only",
|
|
94
|
+
"migration": "Import run and runAsDirectCallEntry from @cosmicdrift/kumiko-framework/internal/request-context; reserved for agent-tools and server runtime wiring, do not use to lift a handler past the risk floor. requestContext.get() from /api is unchanged."
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"version": "0.354.0",
|
|
98
|
+
"type": "fix",
|
|
99
|
+
"title": "SSE broadcasts, toggle sync, stream expiry, page-head abort, PII backfill failures and preSave output are now handled strictly instead of failing silently",
|
|
100
|
+
"detail": "Review hardening: confirmed SSE publish awaited by consumers, feature-toggle cache invalidation over the cache-sync bus, stream expiry timer, page-head resolver abort signal, PII backfill `failed_event_ids`, preSave output validation, read-only proxy `then`/symbol guard, no orphan-row delete in event-consumer state, exported `DEFAULT_HTML` of dev-server and server-runtime"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"version": "0.354.0",
|
|
104
|
+
"type": "breaking",
|
|
105
|
+
"title": "TenantDestroyHookResult: done:false now requires processed",
|
|
106
|
+
"migration": "Tenant destroy hooks that return { done: false } must also return processed (number of items handled this tick). A tick with processed 0 now counts as a failed stage attempt."
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"version": "0.354.0",
|
|
110
|
+
"type": "improvement",
|
|
111
|
+
"title": "Handler titles and field labels as i18n keys, plus the references Zod meta",
|
|
112
|
+
"detail": "`handlerTitleKey(qn)` (`<qn>:title`) and `handlerFieldLabelKey(qn, field)` (`<qn>:field:<field>`) define where a handler's title and input labels live; a feature declares the full keys (e.g. `channel-texts:write:generate:title`, built with `handlerTitleKey(qn)`) in `r.translations`, because the client resolves keys without a feature prefix. Mark a handler input field that points at an entity with `vehicleId: z.string().meta({ references: \"vehicle\" })` (or `\"feature:entity\"`); boot throws when the entity is unknown and `handlerFieldReference(schema, field)` reads it. `findHandlerTranslationGaps` reports agent-exposed write handlers without an entity or actionForm screen and without these keys as `handler-without-translation`. `kumiko agent lint` lists them as warnings without affecting the exit code, and the boot prints one summary line. `findAgentDocGaps` stays unchanged on purpose, since the agent-manifest guard fails on every gap it returns."
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"version": "0.354.0",
|
|
116
|
+
"type": "fix",
|
|
117
|
+
"title": "list search no longer drops hits beyond the 50th candidate",
|
|
118
|
+
"detail": "event-store-executor list: the search path now asks the SearchAdapter for up to 1000 candidate ids instead of the adapter's default 50, so hits beyond the 50th are no longer silently dropped. When the adapter returns the full 1000 (Meilisearch's maxTotalHits cap), the list result carries `searchTruncated: true` (new optional field on `CursorResult`) so clients can tell the match set may be incomplete."
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"version": "0.354.0",
|
|
122
|
+
"type": "fix",
|
|
123
|
+
"title": "The blockDelete-without-anonymize boot warning names the retention-cron risk instead of a Forget error",
|
|
124
|
+
"detail": "The boot warning for `retention.strategy: \"blockDelete\"` without a field `anonymize` now names the real risk: once keepFor expires, the data-retention cron anonymizes nothing and the row keeps its PII"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"version": "0.354.0",
|
|
128
|
+
"type": "breaking",
|
|
129
|
+
"title": "db.global(table) writes on executor-managed entity tables are rejected",
|
|
130
|
+
"detail": "Database, event-store consumer, search and Redis review fixes\n`db.global(table)` writes are rejected on executor-managed entity tables, and `unsafeRaw` handles derived through `begin`, `transaction` or `reserve` keep the personal-data gate. Reference sorting and search re-check label and read access plus ownership, and a stale search index can no longer surface another tenant's row. A cross-tenant convention handler reports one audit event per touched row with that row as target.\nA failing dispatcher pass no longer records its error on a consumer whose cursor moved in the meantime and skips a row another pass holds locked. A projection rebuild aborts when the configured blind-index key differs from the one used to build the live table. An array `ne` filter on a jsonb column means \"does not contain all of these\", matching the entity list filter. `date` columns that still hold a timestamptz log a warning once per column.\n`kumiko_event_dispatcher_listen_connected` only drops to 0 on a real connection-loss error and is restored when the pre-check recovers. A consumer logs once when it tracks more than 1000 pending gap ranges. The lazy Meilisearch default config no longer overwrites settings stored by an earlier `configure()` after a restart.\nAccess invalidation publishes through `PubSubSignal.publishConfirmed`, so a Redis failure fails the consumer and the event is redelivered instead of being dropped (`SseBroker.publishAccessInvalidation` may return a promise). `KUMIKO_REDIS_CHANNEL_PREFIX` namespaces the SSE and feature-toggle Pub/Sub channels for apps sharing one Redis; `createRedisToggleSyncSignal` takes the prefix as an optional third argument. Types that mention `Temporal` now carry the `temporal-polyfill/global` reference into their `.d.ts` files.",
|
|
131
|
+
"migration": "Write entities through the entity executor and keep db.global for hand-written unmanaged tables."
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"version": "0.354.0",
|
|
135
|
+
"type": "fix",
|
|
136
|
+
"title": "unsafeRaw handles derived through begin, transaction or reserve keep the personal-data gate"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"version": "0.354.0",
|
|
140
|
+
"type": "fix",
|
|
141
|
+
"title": "A stale search index can no longer surface another tenant's row"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"version": "0.354.0",
|
|
145
|
+
"type": "fix",
|
|
146
|
+
"title": "A projection rebuild aborts when the blind-index key differs from the one used to build the live table"
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"version": "0.354.0",
|
|
150
|
+
"type": "fix",
|
|
151
|
+
"title": "An array ne filter on a jsonb column means \"does not contain all of these\""
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"version": "0.354.0",
|
|
155
|
+
"type": "fix",
|
|
156
|
+
"title": "Access invalidation publishes with confirmation so a Redis failure redelivers the event"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"version": "0.354.0",
|
|
160
|
+
"type": "breaking",
|
|
161
|
+
"title": "defineFeature throws when dedupeOptions holds a nested object",
|
|
162
|
+
"migration": "Flatten dedupeOptions to primitive values."
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"version": "0.354.0",
|
|
166
|
+
"type": "breaking",
|
|
167
|
+
"title": "Boot validation rejects an object-form redirect with idFrom on a screen that has no id",
|
|
168
|
+
"migration": "Point the redirect at a screen with an id or drop idFrom."
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"version": "0.354.0",
|
|
172
|
+
"type": "breaking",
|
|
173
|
+
"title": "A list column absent from the query output schema must set virtual: true",
|
|
174
|
+
"migration": "Add virtual: true to computed columns that are not part of the query output."
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"version": "0.354.0",
|
|
178
|
+
"type": "fix",
|
|
179
|
+
"title": "Session-only httpRoutes now pass the global IP rate limit"
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"version": "0.354.0",
|
|
183
|
+
"type": "breaking",
|
|
184
|
+
"title": "Boot validator rejects inert sortable, authored urlPrefillFields and an unknown listScreenId",
|
|
185
|
+
"migration": "Remove sortable from entityList columns and sortable true from projectionList columns (declare sorting on the entity field), remove urlPrefillFields from form screens (buildAppSchema derives it from navigate params), and point listScreenId at a mounted screen short id."
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"version": "0.354.0",
|
|
189
|
+
"type": "breaking",
|
|
190
|
+
"title": "TreeAction is screen XOR target at the type level",
|
|
191
|
+
"migration": "Give every createAction and actions[] entry either screen or target, not both and not neither; the boot validator already rejected the other forms."
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"version": "0.354.0",
|
|
195
|
+
"type": "improvement",
|
|
196
|
+
"title": "Row actions can open a secretMint or actionForm that submits without edits",
|
|
197
|
+
"detail": "actionForm and secretMint screens gain `submitPrefilled`: a row action that navigates in with `params` can submit the form right away, with the record id carried in a hidden or read-only field."
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"version": "0.354.0",
|
|
201
|
+
"type": "improvement",
|
|
202
|
+
"title": "Select field options can depend on another field",
|
|
203
|
+
"detail": "Select fields gain `conditionalOptions`: options that are only available while a condition on a sibling field holds, filtered in the form and enforced on write."
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"version": "0.354.0",
|
|
207
|
+
"type": "improvement",
|
|
208
|
+
"title": "setupTestStack accepts rateLimitNowMs to freeze the rate-limit clock in tests",
|
|
209
|
+
"detail": "setupTestStack accepts `rateLimitNowMs`, the time source of the stack's rate-limit resolver, so tests can freeze the token-bucket clock instead of racing the refill window"
|
|
210
|
+
},
|
|
2
211
|
{
|
|
3
212
|
"version": "0.353.0",
|
|
4
213
|
"type": "improvement",
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
type PropertyAssignment,
|
|
16
16
|
SyntaxKind,
|
|
17
17
|
} from "ts-morph";
|
|
18
|
+
import { CODEMOD_PLACEHOLDER_REASON_MARKER } from "../../engine/escape-hatch-reason.js";
|
|
18
19
|
import { collectSourceFiles } from "./collect-source-files.js";
|
|
19
20
|
|
|
20
21
|
export interface Rewrite {
|
|
@@ -151,7 +152,7 @@ function deriveBestEffortHandlerName(assignment: PropertyAssignment): string | u
|
|
|
151
152
|
|
|
152
153
|
function buildEscapeHatchReason(target: AutoRewriteTarget): string {
|
|
153
154
|
const verbKind = READ_VERBS.has(target.verb) ? "reads" : "writes";
|
|
154
|
-
return `${target.handlerName} ${verbKind} ${target.entityName} rows across every tenant (migrated from crossTenant: true;
|
|
155
|
+
return `${target.handlerName} ${verbKind} ${target.entityName} rows across every tenant (migrated from crossTenant: true; ${CODEMOD_PLACEHOLDER_REASON_MARKER})`;
|
|
155
156
|
}
|
|
156
157
|
|
|
157
158
|
export function migrateCrossTenantSource(
|