@happyvertical/smrt-core 0.49.3 → 0.49.5
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/README.md +20 -0
- package/agents/change-feed.md +19 -0
- package/agents/collection-reads.md +21 -0
- package/agents/generators.md +5 -0
- package/agents/memory.md +23 -3
- package/agents/null-equal-indexes.md +88 -0
- package/agents/object-runtime.md +85 -0
- package/agents/schema-paths.md +7 -7
- package/dist/browser.js +2 -2
- package/dist/cascade.d.ts.map +1 -1
- package/dist/cascade.js +13 -10
- package/dist/cascade.js.map +1 -1
- package/dist/change-feed.d.ts +22 -0
- package/dist/change-feed.d.ts.map +1 -1
- package/dist/change-feed.js +147 -6
- package/dist/change-feed.js.map +1 -1
- package/dist/class.js +1 -1
- package/dist/collection-cache.d.ts +10 -1
- package/dist/collection-cache.d.ts.map +1 -1
- package/dist/collection-cache.js +65 -10
- package/dist/collection-cache.js.map +1 -1
- package/dist/collection.d.ts +69 -2
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +142 -9
- package/dist/collection.js.map +1 -1
- package/dist/consumer-plugin/artifact-publication.d.ts +27 -0
- package/dist/consumer-plugin/artifact-publication.d.ts.map +1 -0
- package/dist/consumer-plugin/artifact-publication.js +80 -0
- package/dist/consumer-plugin/artifact-publication.js.map +1 -0
- package/dist/consumer-plugin/index.d.ts.map +1 -1
- package/dist/consumer-plugin/index.js +44 -6
- package/dist/consumer-plugin/index.js.map +1 -1
- package/dist/db-errors.js +1 -1
- package/dist/db-errors.js.map +1 -1
- package/dist/embedded-write-queue.d.ts +1 -1
- package/dist/embedded-write-queue.d.ts.map +1 -1
- package/dist/embedded-write-queue.js +16 -6
- package/dist/embedded-write-queue.js.map +1 -1
- package/dist/embeddings/storage.d.ts +16 -0
- package/dist/embeddings/storage.d.ts.map +1 -1
- package/dist/embeddings/storage.js +40 -0
- package/dist/embeddings/storage.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/interceptors.d.ts +22 -0
- package/dist/interceptors.d.ts.map +1 -1
- package/dist/interceptors.js +12 -0
- package/dist/interceptors.js.map +1 -1
- package/dist/junction.d.ts +12 -3
- package/dist/junction.d.ts.map +1 -1
- package/dist/junction.js +34 -4
- package/dist/junction.js.map +1 -1
- package/dist/knowledge-config.d.ts +6 -0
- package/dist/knowledge-config.d.ts.map +1 -0
- package/dist/knowledge-config.js +48 -0
- package/dist/knowledge-config.js.map +1 -0
- package/dist/manifest/static-manifest.d.ts.map +1 -1
- package/dist/manifest/static-manifest.js +91 -1
- package/dist/manifest/static-manifest.js.map +1 -1
- package/dist/manifest/store.js +1 -1
- package/dist/manifest/store.js.map +1 -1
- package/dist/manifest.json +104 -1
- package/dist/migrations/differ.d.ts.map +1 -1
- package/dist/migrations/differ.js +2 -0
- package/dist/migrations/differ.js.map +1 -1
- package/dist/migrations/generator.d.ts.map +1 -1
- package/dist/migrations/generator.js +2 -0
- package/dist/migrations/generator.js.map +1 -1
- package/dist/migrations/index.d.ts +1 -0
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +2 -1
- package/dist/migrations/null-equal-indexes.d.ts +37 -0
- package/dist/migrations/null-equal-indexes.d.ts.map +1 -0
- package/dist/migrations/null-equal-indexes.js +133 -0
- package/dist/migrations/null-equal-indexes.js.map +1 -0
- package/dist/migrations/tracker.d.ts.map +1 -1
- package/dist/migrations/tracker.js +6 -0
- package/dist/migrations/tracker.js.map +1 -1
- package/dist/migrations.js +2 -1
- package/dist/object.d.ts +33 -0
- package/dist/object.d.ts.map +1 -1
- package/dist/object.js +316 -46
- package/dist/object.js.map +1 -1
- package/dist/plain-json.d.ts +6 -0
- package/dist/plain-json.d.ts.map +1 -0
- package/dist/plain-json.js +41 -0
- package/dist/plain-json.js.map +1 -0
- package/dist/postgres-permissions.d.ts.map +1 -1
- package/dist/postgres-permissions.js +6 -2
- package/dist/postgres-permissions.js.map +1 -1
- package/dist/prebuild/index.d.ts.map +1 -1
- package/dist/prebuild/index.js +3 -3
- package/dist/prebuild/index.js.map +1 -1
- package/dist/registry/class-registration.d.ts.map +1 -1
- package/dist/registry/class-registration.js +4 -1
- package/dist/registry/class-registration.js.map +1 -1
- package/dist/registry/schema-builder.d.ts.map +1 -1
- package/dist/registry/schema-builder.js +4 -3
- package/dist/registry/schema-builder.js.map +1 -1
- package/dist/registry/validator.d.ts +1 -0
- package/dist/registry/validator.d.ts.map +1 -1
- package/dist/registry/validator.js +8 -1
- package/dist/registry/validator.js.map +1 -1
- package/dist/registry.js +1 -1
- package/dist/scanner/manifest-generator.d.ts.map +1 -1
- package/dist/scanner/manifest-generator.js +21 -0
- package/dist/scanner/manifest-generator.js.map +1 -1
- package/dist/scanner/types.d.ts +2 -0
- package/dist/scanner/types.d.ts.map +1 -1
- package/dist/scanner/types.js.map +1 -1
- package/dist/schema/conflict-target.d.ts +8 -2
- package/dist/schema/conflict-target.d.ts.map +1 -1
- package/dist/schema/conflict-target.js +11 -3
- package/dist/schema/conflict-target.js.map +1 -1
- package/dist/schema/ddl/null-equal-index.d.ts +5 -0
- package/dist/schema/ddl/null-equal-index.d.ts.map +1 -0
- package/dist/schema/ddl/null-equal-index.js +17 -0
- package/dist/schema/ddl/null-equal-index.js.map +1 -0
- package/dist/schema/ddl/postgres-strategy.d.ts +2 -1
- package/dist/schema/ddl/postgres-strategy.d.ts.map +1 -1
- package/dist/schema/ddl/postgres-strategy.js +7 -0
- package/dist/schema/ddl/postgres-strategy.js.map +1 -1
- package/dist/schema/generator.d.ts.map +1 -1
- package/dist/schema/generator.js +8 -3
- package/dist/schema/generator.js.map +1 -1
- package/dist/schema/manifest-schema.d.ts +2 -1
- package/dist/schema/manifest-schema.d.ts.map +1 -1
- package/dist/schema/manifest-schema.js +12 -4
- package/dist/schema/manifest-schema.js.map +1 -1
- package/dist/schema/schema-manager.d.ts.map +1 -1
- package/dist/schema/schema-manager.js +1 -1
- package/dist/schema/schema-manager.js.map +1 -1
- package/dist/schema/types.d.ts +2 -0
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/scripts/browser-plain-json-regression.mjs +85 -0
- package/dist/smrt-knowledge.json +73 -15
- package/dist/system/schema.d.ts +14 -3
- package/dist/system/schema.d.ts.map +1 -1
- package/dist/system/schema.js +120 -2
- package/dist/system/schema.js.map +1 -1
- package/dist/vite-plugin/api-client-entries.d.ts.map +1 -1
- package/dist/vite-plugin/api-client-entries.js +9 -7
- package/dist/vite-plugin/api-client-entries.js.map +1 -1
- package/dist/vite-plugin/index.d.ts +24 -0
- package/dist/vite-plugin/index.d.ts.map +1 -1
- package/dist/vite-plugin/index.js +48 -115
- package/dist/vite-plugin/index.js.map +1 -1
- package/dist/vite-plugin/sveltekit-generator.d.ts.map +1 -1
- package/dist/vite-plugin/sveltekit-generator.js +2 -2
- package/dist/vite-plugin/sveltekit-generator.js.map +1 -1
- package/dist/vite-plugin/web-collections.d.ts +18 -0
- package/dist/vite-plugin/web-collections.d.ts.map +1 -1
- package/dist/vite-plugin/web-collections.js +55 -2
- package/dist/vite-plugin/web-collections.js.map +1 -1
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -191,6 +191,22 @@ generates routes, types, registration, and virtual modules, but it disables
|
|
|
191
191
|
source/package scans, watch rescans, and manifest writes. Omit
|
|
192
192
|
`generationSnapshot` for normal local development.
|
|
193
193
|
|
|
194
|
+
#### Consumer web collection definitions
|
|
195
|
+
|
|
196
|
+
`smrtConsumer()` also resolves `@smrt/web` for browser collection consumers:
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
import { collectionDefinitions, getCollectionDefinition } from '@smrt/web';
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
The module projects the consumer's aggregated dependency manifest through the
|
|
203
|
+
same web-definition generator as `smrtPlugin()`. Each definition retains its
|
|
204
|
+
provider-qualified `objectRef` (for example, `@acme/widgets:Widget`) and its
|
|
205
|
+
manifest-derived fields, actions, relationships, WebMCP descriptors, and
|
|
206
|
+
`manifestHash`. Consumer snapshots select the dependency view, so local project
|
|
207
|
+
objects are not included. During declaration generation the matching
|
|
208
|
+
`smrt-web.d.ts` module is written alongside the other consumer virtual modules.
|
|
209
|
+
|
|
194
210
|
### Generated SvelteKit routes
|
|
195
211
|
|
|
196
212
|
Enable SvelteKit route generation with `svelteKit: { enabled: true }`. Its
|
|
@@ -267,6 +283,10 @@ Because s-m-r-t owns every mutation path (`save()`, `delete()`,
|
|
|
267
283
|
automatically invalidates the affected table's cached entries in-process —
|
|
268
284
|
including STI siblings sharing the table. Cached values are raw rows:
|
|
269
285
|
hydration and read interceptors (tenancy, audit) still run on every call.
|
|
286
|
+
Concurrent identical misses coalesce only on the same concrete database
|
|
287
|
+
interface. Distinct connection or transaction interfaces never share pending
|
|
288
|
+
reads or completed rows, even with the same URL; invalidation still clears
|
|
289
|
+
all interfaces for that URL and table.
|
|
270
290
|
|
|
271
291
|
Caches are per-process. For multi-replica deployments, add
|
|
272
292
|
`crossProcess: true` to broadcast invalidations over the database adapter's
|
package/agents/change-feed.md
CHANGED
|
@@ -15,3 +15,22 @@ Adapter-agnostic change-observation spine (`src/change-feed.ts`) — the server
|
|
|
15
15
|
- `getTableVersion(db, table) → number`: the per-table change version (`MAX(seq)` for the table **plus that table's staged-but-undrained count**, so a staged write still moves the ETag and cannot false-304 a client; the sum is monotonic because draining `n` staged rows raises the table's `MAX(seq)` by at least `n`, and both terms are read in ONE statement — separate reads let a drain be counted twice, minting a version a later write re-mints; replica-stable, with no per-process divergence), the ETag source for zero-query conditional GETs (#1765). Advances on any framework write to the table (CRUD and sync-apply, which all `save()`/`delete()`). A table with no retained entry of its own falls back to the global horizon (never a resettable low value) so an all-pruned table cannot false-304 a stale client; only 0 when the feed is empty.
|
|
16
16
|
- Generated `_changes` routes: REST (`GET {basePath}/_changes`, requires `authMiddleware`, otherwise 401 — per-model `api.public` does NOT apply) and SvelteKit (`{routesDir}/_changes/+server.ts`, requires an authenticated principal on `locals`; opt out via `sveltekit.changesRoute.enabled: false`). Query params: `since`, `tables` (comma-separated), `limit`. Responses stay HTTP 200 in the resync state — `resyncRequired` is protocol state, not an error, and `resyncCursor` is the resume cursor after the client completes a full refetch.
|
|
17
17
|
- Retention: `pruneChangeFeed(db, { maxAgeMs?, maxRows?, dryRun? })` — scheduled since #2375 by `runRetentionSweep()` (30-day default), so nothing needs to call it directly; `dryRun` counts the same predicate instead of deleting. Pruning deletes oldest-first and always retains the newest entry (a non-empty feed is never emptied), which is what makes pruned-cursor detection provable. The age bound is a **prefix** bound — everything below the oldest entry still inside the window — because `created_at` and `seq` are not co-monotonic (writer clocks skew, and a staged entry carries its stage-time stamp into a later-assigned sequence); deleting by timestamp alone could punch a hole in the middle of the retained run, where `since < floor - 1` cannot see it and keeps caught-up consumers polling normally. Raw-SQL writes are invisible to the feed (same documented gap as the #1499 cache); `bumpChangeFeed(db, { table, rowId? })` is the manual escape hatch.
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## Compatible bulk mutations (#2818)
|
|
21
|
+
|
|
22
|
+
`appendChanges(db, entries)` validates all inputs before writing and returns one
|
|
23
|
+
sequence (or PostgreSQL staged `null`) per entry in input order. A nonempty batch
|
|
24
|
+
uses one client SQL statement and one set-based insert. The PostgreSQL
|
|
25
|
+
`_smrt_append_changes(jsonb)` helper chooses the staged/direct path once before
|
|
26
|
+
its own writes assign a transaction ID, and retains the same exception isolation
|
|
27
|
+
as the single-row helper. Bootstrap refreshes its body marker and runtime grants
|
|
28
|
+
include this exact helper signature.
|
|
29
|
+
|
|
30
|
+
The registered feed interceptor explicitly supports grouped lifecycle completion.
|
|
31
|
+
`recordInstanceChanges()` retains observable-table filtering, row/tenant IDs,
|
|
32
|
+
per-row operations, and best-effort failure handling. It publishes each direct
|
|
33
|
+
sequence in order; staged entries publish through the existing committed drain.
|
|
34
|
+
A batch is never replaced with a table-level bump or a single aggregate event.
|
|
35
|
+
The junction caller bounds its batch; the low-level append API does not split
|
|
36
|
+
one logical append into partially committed chunks.
|
|
@@ -68,3 +68,24 @@ the first error.
|
|
|
68
68
|
`=`, `>`, `<`, `>=`, `<=`, `!=`, `in`, `not in`, and `like`. Arrays imply `IN`,
|
|
69
69
|
and null values render `IS NULL`/`IS NOT NULL`. `contains` and dot-notation JSON
|
|
70
70
|
paths are intentionally rejected until the SQL layer supports them.
|
|
71
|
+
|
|
72
|
+
For subclass-owned bounded SQL, `resolveListReadPredicate()` provides SQL scope
|
|
73
|
+
plus `finish(instances)`. Call `finish` exactly once on the final hydrated page
|
|
74
|
+
(including empty pages), after raw-query hooks and annotations, outside provider
|
|
75
|
+
fallback catches. It invokes normal `afterList` using the original `beforeList`
|
|
76
|
+
context and model identity. It does not fetch replacement rows after filtering.
|
|
77
|
+
ID-only consumers have no hydrated page and do not call this completion step.
|
|
78
|
+
|
|
79
|
+
`semanticSearchIdsWithAvailability()` is the protected fallback-aware boundary:
|
|
80
|
+
only absent embedding configuration or a failed `provider.embed()` returns
|
|
81
|
+
`available: false`. Invalid options, authorization, ranking, query, and caller
|
|
82
|
+
override failures propagate regardless of their error class. Public
|
|
83
|
+
`semanticSearchIds()` keeps its array/throw contract by throwing the returned
|
|
84
|
+
provider error. Consumers must branch on availability, never classify thrown
|
|
85
|
+
`EmbeddingUnavailableError` values from an entire search as provider failures.
|
|
86
|
+
|
|
87
|
+
Semantic ID eligibility binds its complete beforeList/STI/where predicate once
|
|
88
|
+
in a CTE per candidate chunk. Only the scalar eligibility mask leaves the
|
|
89
|
+
application database. Candidate chunks use the remaining conservative 999-bind
|
|
90
|
+
budget (minimum 1); a predicate already larger than that budget retains the
|
|
91
|
+
adapter’s existing capacity instead of being rejected by a new API limit.
|
package/agents/generators.md
CHANGED
|
@@ -26,6 +26,11 @@ collection class and its populated model share an endpoint, the model owns the
|
|
|
26
26
|
canonical collection key and row payload schema; the collection class remains
|
|
27
27
|
available under a deterministic class-derived secondary key. Selection and
|
|
28
28
|
collision suffixes must not depend on manifest insertion order (#2027).
|
|
29
|
+
Route emission iterates manifest objects in the same deterministic
|
|
30
|
+
qualified-identity order (`orderedManifestObjectEntries`), so when two models
|
|
31
|
+
share one collection the last writer of each route file — and therefore the
|
|
32
|
+
CRUD method set `resolveGeneratedEndpointCrudMethods` mirrors into
|
|
33
|
+
`smrt-client.d.ts` — is stable across scan orders (#2754).
|
|
29
34
|
For aggregated manifests, inheritance and item-type references resolve exact
|
|
30
35
|
qualified names first, then package-local simple names, then a stable identity
|
|
31
36
|
fallback so duplicate class names across packages cannot reintroduce ordering.
|
package/agents/memory.md
CHANGED
|
@@ -11,10 +11,30 @@ filtering; object/collection recall does not update them.
|
|
|
11
11
|
|
|
12
12
|
Semantic search uses `_smrt_embeddings` and cosine ranking over fields declared
|
|
13
13
|
by `@smrt({ embeddings })`, with native pgvector/HNSW or an in-memory fallback.
|
|
14
|
-
|
|
15
|
-
applies. Keep injected search behind the
|
|
16
|
-
|
|
14
|
+
Legacy `semanticSearch` results hydrate through `list({ 'id in': … })`, so normal
|
|
15
|
+
tenant isolation still applies. Keep injected search behind the public
|
|
16
|
+
`SmrtCollection.semanticSearch` / `semanticSearchIds` boundaries.
|
|
17
17
|
|
|
18
18
|
`LearningMemory.capture()` reinforces successes and decays failures while
|
|
19
19
|
updating outcome counters. Its tenant-isolated `recall()` applies confidence,
|
|
20
20
|
expiry, time-decay, and hierarchical-scope filters and refreshes `last_used_at`.
|
|
21
|
+
|
|
22
|
+
`semanticSearchIds(query, options)` and `findSimilarIdsToEmbedding(vector, options)`
|
|
23
|
+
return `{ id, similarity }` without object hydration. They apply caller `where`,
|
|
24
|
+
normal `beforeList` tenancy predicates, and child STI scope **before** exact
|
|
25
|
+
cosine top-K (legacy `semanticSearch` applies caller `where` after ranking).
|
|
26
|
+
Equal scores sort by object ID. Search scans JSON embedding vectors in keyset
|
|
27
|
+
batches of 64, including when native vector storage is enabled (JSON is always
|
|
28
|
+
persisted); each batch checks application eligibility using a fixed-size scalar
|
|
29
|
+
SQL mask of primary-key `EXISTS` probes. This supports separate system/app
|
|
30
|
+
databases without fetching all tenant IDs or application rows. Memory is
|
|
31
|
+
O(limit + 64); the exact fallback still scans all matching stored embeddings.
|
|
32
|
+
The embedding primary key supports the cursor and application primary keys
|
|
33
|
+
support eligibility probes; no new application index is needed. Pagination
|
|
34
|
+
callers can request offset + limit scored IDs, then hydrate only their page.
|
|
35
|
+
|
|
36
|
+
`semanticSearchIds` reports missing embedding configuration/provider failure as
|
|
37
|
+
`EmbeddingUnavailableError`; authorization/interceptor and application SQL errors
|
|
38
|
+
remain distinct and must not be caught as text-fallback signals. Subclass SQL
|
|
39
|
+
readers can compile normal beforeList + STI predicates with the protected
|
|
40
|
+
`resolveListReadPredicate()` (ordered values and portable `?` placeholders).
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Nullable framework conflict identities
|
|
2
|
+
|
|
3
|
+
`SmrtObject.save()` and the SDK upsert already treat NULL conflict values as
|
|
4
|
+
identical. On PostgreSQL 15+, a matching full `UNIQUE NULLS NOT DISTINCT` index
|
|
5
|
+
allows a warm nullable upsert to execute one native statement. This statement
|
|
6
|
+
bound excludes the first server/index capability probes and object lifecycle
|
|
7
|
+
work. PostgreSQL version alone does not establish readiness.
|
|
8
|
+
|
|
9
|
+
SMRT marks only its generated **runtime conflict identity** indexes with
|
|
10
|
+
`nullsNotDistinct: true`, and only when a key column is nullable. This includes
|
|
11
|
+
CTI/STI defaults and explicitly configured conflict columns. Primary-key targets
|
|
12
|
+
need no additional index. Optional business-field and declared composite unique
|
|
13
|
+
indexes remain ordinary NULLS DISTINCT; multiple NULL business values continue
|
|
14
|
+
to be legal. The marker survives manifest, registry and migration schema paths.
|
|
15
|
+
|
|
16
|
+
Fresh PostgreSQL DDL uses a version-gated dynamic `DO` block: PostgreSQL 15+
|
|
17
|
+
executes NND, while older servers execute ordinary UNIQUE without parsing the
|
|
18
|
+
unsupported syntax. SQLite/DuckDB DDL and their existing upsert paths do not
|
|
19
|
+
change. The PostgreSQL statement planner preserves the complete block and
|
|
20
|
+
**rejects `--postgres-safe`** when such a block is present, before executing the
|
|
21
|
+
plan. Schedule an atomic maintenance window and retry ordinary `db:migrate`
|
|
22
|
+
without that flag. No conditional blocking index build runs in concurrent mode.
|
|
23
|
+
|
|
24
|
+
## Existing deployment procedure
|
|
25
|
+
|
|
26
|
+
1. Generate current manifests and run ordinary schema migration to establish
|
|
27
|
+
the current tables/conflict column shapes. Ordinary parity does not replace
|
|
28
|
+
an existing index merely because its NULL semantics differ.
|
|
29
|
+
2. Run `smrt db:migrate-null-equal-indexes --dry-run` against the intended
|
|
30
|
+
database. The command discovers framework schema markers, checks server
|
|
31
|
+
version and exact public-schema index catalogs, and prints readiness and
|
|
32
|
+
replacement SQL. It performs no DDL or data writes in dry-run mode.
|
|
33
|
+
3. Resolve blocked findings explicitly. Duplicate NULL-equal groups are counted
|
|
34
|
+
without printing their values; the report supplies a quoted detector SELECT.
|
|
35
|
+
Decide correct identities with the data owner. This command never deletes or
|
|
36
|
+
merges rows. Missing/drifted indexes require explicit schema repair first. PostgreSQL's
|
|
37
|
+
physical truncation of a generated name is recognized using its server
|
|
38
|
+
`name` type, including multibyte names. A differently renamed equivalent is
|
|
39
|
+
never adopted automatically: ordinary `db:migrate` may already consider it
|
|
40
|
+
satisfied and emit no repair. Inspect `pg_indexes`, verify framework ownership,
|
|
41
|
+
exact ordered keys, uniqueness and dependencies, then in a separate maintenance
|
|
42
|
+
transaction rename that verified owned index with `ALTER INDEX ... RENAME TO`
|
|
43
|
+
the expected name, or create the expected index from generated schema. Never
|
|
44
|
+
rename an unrelated business index. Repeat preflight after the repair.
|
|
45
|
+
4. Schedule a maintenance window and run `smrt db:migrate-null-equal-indexes`.
|
|
46
|
+
It acquires ACCESS EXCLUSIVE table locks in deterministic order, repeats
|
|
47
|
+
catalog and duplicate checks under those locks, and replaces pending indexes
|
|
48
|
+
in one transaction. Writers wait while the locks are held. Lock/statement
|
|
49
|
+
timeouts use `migrations.postgres` settings (30s/60s defaults, 0 disables).
|
|
50
|
+
5. Refresh database connections in **every application process**, or restart
|
|
51
|
+
them. The SDK caches negative capability probes per adapter. Use the public
|
|
52
|
+
`getDatabase({ ...sameOptions, clearCache: true })` API and replace consumer
|
|
53
|
+
references to the old adapter; merely refreshing the CLI process cannot
|
|
54
|
+
refresh running applications. Until refresh, the existing fallback remains
|
|
55
|
+
correct, but retains its additional statements.
|
|
56
|
+
6. Repeat dry-run to verify current indexes. A repeated apply skips current
|
|
57
|
+
indexes. PostgreSQL <15 and other engines report unsupported and change
|
|
58
|
+
nothing; upgrading PostgreSQL does not itself replace an ordinary index.
|
|
59
|
+
|
|
60
|
+
The migration refuses constraint-owned indexes, reverse dependencies (including
|
|
61
|
+
foreign keys), extension/internal ownership, partitioned tables, predicates,
|
|
62
|
+
expressions, INCLUDE columns, nondefault ordering/operator classes/collation or
|
|
63
|
+
storage, and changed key order. These require a separate dependency-aware
|
|
64
|
+
migration. It never uses CASCADE or drops foreign keys. A failed locked recheck,
|
|
65
|
+
DDL statement or timeout rolls back every replacement and retains the original
|
|
66
|
+
indexes; resolve the reported cause and retry. Catalog state supplies the
|
|
67
|
+
idempotency/readiness record, rather than an audit marker that could falsely
|
|
68
|
+
claim readiness after later DDL drift. Keep the command output in the operator's
|
|
69
|
+
change record. No runtime object operation creates or upgrades application DDL.
|
|
70
|
+
|
|
71
|
+
Implementation: `schema/conflict-target.ts`, `schema/ddl/null-equal-index.ts`,
|
|
72
|
+
`migrations/null-equal-indexes.ts`, and CLI `db-migrate-null-equal-indexes.ts`.
|
|
73
|
+
|
|
74
|
+
Checked-in `src/manifest/manifest.json` files are supported source-only fallbacks,
|
|
75
|
+
including packages imported before their first build. Regenerate them through
|
|
76
|
+
`ManifestBuilder.generate({ outputDir: 'src/manifest', outputName: 'manifest.json',
|
|
77
|
+
loadViteConfig: false, include: ['src/**/*.ts'], exclude: ['**/*.test.ts',
|
|
78
|
+
'**/*.spec.ts', '**/__tests__/**'], discoverExternalPackages: true,
|
|
79
|
+
injectPackageInfo: true })` from each package directory when schema generation
|
|
80
|
+
changes. This is the canonical source and build writer, not a marker-only JSON
|
|
81
|
+
patch. Same-name collected indexes must have compatible ordered columns,
|
|
82
|
+
uniqueness, predicates and expressions; otherwise collection fails with a
|
|
83
|
+
regeneration diagnostic. A compatible optional ownership marker survives either
|
|
84
|
+
contributor order; explicitly contradictory markers also fail closed.
|
|
85
|
+
|
|
86
|
+
Collection access classes retain schema metadata copied from their resolved item
|
|
87
|
+
model after model generation completes. They never generate an independent
|
|
88
|
+
conflict identity; indirect collection subclasses inherit the same item schema.
|
package/agents/object-runtime.md
CHANGED
|
@@ -19,6 +19,19 @@
|
|
|
19
19
|
persisted rows must use `getCanonicalPersistedRow()` so UUID identities are
|
|
20
20
|
cast in the same coherent read before reuse.
|
|
21
21
|
- `is(criteria)` / `do(instructions)` / `describe()`: AI operations via function calling. They inject the object's own `toPublicJSON()` (sensitive fields stripped) as a "content body" so the model reasons over the instance. Options: `includeData: false` skips injection (for callers that already curate the relevant fields into the instruction); `maxDataLength` overrides the truncation budget. Neither key is forwarded to `ai.message()`. (#1567)
|
|
22
|
+
- `normalizePersistenceData(data)` is the synchronous final derived-column hook:
|
|
23
|
+
shared save preparation passes read-only snake-case row data after the complete polymorphic
|
|
24
|
+
`toJSON()` / `transformJSON()` chain and UUID coercion, then merges the returned
|
|
25
|
+
columns before every insert/update/upsert branch. Declare permitted snake-case
|
|
26
|
+
columns with `getPersistenceDerivedColumns()`, preserving super declarations.
|
|
27
|
+
Declarations must name registered schema fields; framework identity, tenant,
|
|
28
|
+
revision, STI metadata and natural conflict columns are always rejected.
|
|
29
|
+
Undeclared return keys reject before persistence. The hook receives a frozen
|
|
30
|
+
shallow row copy. Derive only the declared columns; do not perform I/O.
|
|
31
|
+
Preserve `super` results. It does not alter plain/public serialization;
|
|
32
|
+
use `transformJSON()` for that existing contract. Ordinary saves and eligible
|
|
33
|
+
junction batches share this preparation. A custom normalization override makes
|
|
34
|
+
a junction ineligible for batching, preserving its virtual per-row save path.
|
|
22
35
|
- `save()` error contract (#2366): unique/PK violation → `ValidationError` `VALIDATION_UNIQUE_CONSTRAINT`, NOT NULL → `VALIDATION_REQUIRED_FIELD`, both on the first attempt on every adapter; any other database failure → `DatabaseError` with the driver error on `cause`
|
|
23
36
|
- `getSlug()`: auto-generates from name → title → label → id
|
|
24
37
|
- `loadRelated(fieldName)`: lazy-loads relationships (cached in `_loadedRelationships` Map)
|
|
@@ -31,6 +44,25 @@ legacy external string targets retain manifest discovery. Junction column naming
|
|
|
31
44
|
conventions still use display names. Cached reads retain their tenant rechecks.
|
|
32
45
|
|
|
33
46
|
|
|
47
|
+
## Plain-object serialization
|
|
48
|
+
|
|
49
|
+
`toPlainObject()` materializes the `toJSON()` / `transformJSON()` result directly,
|
|
50
|
+
without an intermediate JSON string for ordinary payloads. Native `JSON.rawJSON()`
|
|
51
|
+
literals are decoded once with `JSON.parse()`. Nested hooks and JSON omission/coercion
|
|
52
|
+
rules still apply. The active ancestor stack rejects cycles while allowing
|
|
53
|
+
shared siblings, which become independent plain copies. Arrays skip boxed-value
|
|
54
|
+
brand checks; other objects use intrinsic brand checks without reading user
|
|
55
|
+
`Symbol.toStringTag` getters. Customize the payload through `transformJSON()`.
|
|
56
|
+
The focused `to-plain-object.test.ts` suite compares legacy output and reports
|
|
57
|
+
warmed, interleaved per-row timings without a flaky timing assertion.
|
|
58
|
+
|
|
59
|
+
`pnpm --filter @happyvertical/smrt-core test:browser` bundles the production
|
|
60
|
+
`src/plain-json.ts` helper and executes it in Chromium with `process` and
|
|
61
|
+
`JSON.isRawJSON` unavailable. It is an opt-in local/browser release gate rather
|
|
62
|
+
than part of the default core suite: it requires the repository's
|
|
63
|
+
`playwright-core` dependency and an installed Chromium binary. The normal test
|
|
64
|
+
suite covers the same helper through `toPlainObject()` on Node.
|
|
65
|
+
|
|
34
66
|
## SmrtCollection Query
|
|
35
67
|
|
|
36
68
|
Projection, latest-related, facets, counts, and bounded read plans are
|
|
@@ -62,6 +94,59 @@ explicit wildcards. Adding operators requires SQL support first.
|
|
|
62
94
|
STI child collections auto-filter by `_meta_type`. Query bounds — `LIMIT 1` on `get()`, the `limit`/`offset` parser, the `orderBy` whitelist and sensitive/permission refusals, and the deterministic generated-list ordering (#2367) — are in [query-bounds.md](query-bounds.md).
|
|
63
95
|
|
|
64
96
|
|
|
97
|
+
## Junction reads and compatible writes
|
|
98
|
+
|
|
99
|
+
`byLeft(id, { relationship: 'attachment', limit: 20, offset: 40 })` and
|
|
100
|
+
`byRight()` forward `limit`/`offset` to the collection's existing bounds parser;
|
|
101
|
+
other options remain field filters. Pagination is read-only: `detach()` still
|
|
102
|
+
requires field filters and never deletes a page. Cursor pagination is not part
|
|
103
|
+
of this API; callers can use deterministic limit/offset pages.
|
|
104
|
+
|
|
105
|
+
`setLinks()` preserves replacement semantics: even retained right IDs get new
|
|
106
|
+
junction IDs/timestamps and delete/create change entries. `detach()` and
|
|
107
|
+
`setLinks()` batch compatible models automatically. Within 100 removed + added
|
|
108
|
+
rows and 900 inserted bind values, a warm SQLite/DuckDB/PostgreSQL operation uses
|
|
109
|
+
constant framework SQL: one snapshot, grouped owned-memory cleanup and delete,
|
|
110
|
+
one multi-row natural-key upsert, and one feed append per nonempty mutation
|
|
111
|
+
phase. Bootstrap, retries, and caller-defined work are excluded. The read
|
|
112
|
+
snapshot and in-memory work remain proportional to link count.
|
|
113
|
+
|
|
114
|
+
Eligibility is deliberately conservative and rechecked each call: base runtime
|
|
115
|
+
methods/accessors and collection create/attach behavior, one non-STI table,
|
|
116
|
+
compiler-owned declarative validators, no validated cross-package references,
|
|
117
|
+
no embedding generation, no incoming typed references, non-NULL unique
|
|
118
|
+
conflict values with no duplicate input conflict keys, and explicit consent
|
|
119
|
+
from every mutation interceptor. Otherwise the original virtual per-row path
|
|
120
|
+
runs. Larger sets retain that fallback; there is no truncated replacement.
|
|
121
|
+
Polymorphic association cleanup remains grouped through the owning cascade API
|
|
122
|
+
and invalidates every affected table. JSON export adapters retain their ordinary
|
|
123
|
+
lifecycle; unrecognized transaction-only DuckDB handles also fall back.
|
|
124
|
+
The tenancy interceptor consents only without directory dispatch/custom error
|
|
125
|
+
callbacks. Tenant checks and auto-population still run per row. The change-feed
|
|
126
|
+
interceptor appends every row and preserves tenant IDs and tombstones.
|
|
127
|
+
|
|
128
|
+
Bulk lifecycle preparation and completion are owned by `SmrtObject`; collection
|
|
129
|
+
initialization shares `createUnsaved()` with `create()`. Additional interceptors
|
|
130
|
+
may supply `bulkMutation.compatible()` only if grouped before/persist/after
|
|
131
|
+
phases preserve their behavior and before hooks have no side effects beyond
|
|
132
|
+
instance/context mutation. Preparation can discover an unsupported shape and
|
|
133
|
+
fall back; before hooks must tolerate that rehearsal. Unknown interceptors never
|
|
134
|
+
opt in implicitly.
|
|
135
|
+
The compiler marks its own callback-free validators by function identity.
|
|
136
|
+
|
|
137
|
+
The whole replacement remains nontransactional unless the caller supplies a
|
|
138
|
+
transaction. A delete group is atomic with its owned-memory cleanup and each
|
|
139
|
+
multi-row insert is atomic, so database failure can leave the deletion phase
|
|
140
|
+
committed without new links. No per-row prefix is promised for a failed batch.
|
|
141
|
+
The batch delete reuses an existing DuckDB transaction when the SDK explicitly
|
|
142
|
+
refuses savepoint nesting before running any work; it never replays a callback.
|
|
143
|
+
The legacy fallback retains its existing detectable nested-transaction refusal
|
|
144
|
+
for ordinary deletes inside caller-owned DuckDB transactions
|
|
145
|
+
([#2824](https://github.com/happyvertical/smrt/issues/2824)).
|
|
146
|
+
Public ordinary `save()` still owns revision CAS; batches only create new
|
|
147
|
+
instances and never use this path to overwrite a loaded revision.
|
|
148
|
+
|
|
149
|
+
|
|
65
150
|
## DispatchBus
|
|
66
151
|
|
|
67
152
|
- `emit(signalType, payload, metadata)` → creates persistent Dispatch record
|
package/agents/schema-paths.md
CHANGED
|
@@ -74,13 +74,13 @@ divergence is a bug in the generator, not an exception to add to the test.
|
|
|
74
74
|
migration replaces a same-name global unique with tenant-led columns. That
|
|
75
75
|
prefix serves tenant and tenant-scoped slug reads; a legacy standalone tenant
|
|
76
76
|
index is dropped only with `--drop-indexes`.
|
|
77
|
-
- **Optional NULL tenants**
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
77
|
+
- **Optional NULL tenants** retain the SDK's NULL-equal upsert identity. Generated
|
|
78
|
+
framework conflict indexes with nullable keys carry `nullsNotDistinct: true`;
|
|
79
|
+
PostgreSQL 15+ creates `UNIQUE NULLS NOT DISTINCT`, enabling warm single-statement
|
|
80
|
+
native upserts. Earlier PostgreSQL, SQLite and DuckDB retain adapter fallback
|
|
81
|
+
semantics. Existing ordinary indexes are upgraded only through the explicit
|
|
82
|
+
[NULL-equal maintenance migration](null-equal-indexes.md). Optional business
|
|
83
|
+
unique fields remain NULLS DISTINCT; this marker is not inferred from them.
|
|
84
84
|
- **Tenant-key rollout requires a maintenance window.** Old code/new indexes
|
|
85
85
|
and new code/old indexes both fail new-object saves because conflict column
|
|
86
86
|
sets must match exactly; persisted ID-based saves still work. Backfill legacy
|
package/dist/browser.js
CHANGED
|
@@ -17,7 +17,7 @@ import { SmrtObject } from "./object.js";
|
|
|
17
17
|
import { isFrameworkBaseClass } from "./registry/framework-base-classes.js";
|
|
18
18
|
import { SMRT_COLLECTION_BASE_NAMES, isSmrtCollectionExtendsName } from "./registry/collection-resolution.js";
|
|
19
19
|
import { ObjectRegistry, smrt } from "./registry.js";
|
|
20
|
-
import { DEFAULT_FACET_LIMIT, MAX_FACET_FIELDS, MAX_FACET_LIMIT, MAX_STI_READ_SCOPE_TYPES, SmrtCollection } from "./collection.js";
|
|
20
|
+
import { DEFAULT_FACET_LIMIT, EmbeddingUnavailableError, MAX_FACET_FIELDS, MAX_FACET_LIMIT, MAX_STI_READ_SCOPE_TYPES, SmrtCollection } from "./collection.js";
|
|
21
21
|
import { SmrtHierarchical } from "./hierarchical.js";
|
|
22
22
|
import { SmrtJunction } from "./junction.js";
|
|
23
23
|
import { SmrtPolymorphicAssociation } from "./polymorphic-association.js";
|
|
@@ -27,4 +27,4 @@ import { BOOTED_PROVENANCE, assertPlainJson, sanitizeMessagePaths, snapshotRegis
|
|
|
27
27
|
import { DEFAULT_RETENTION_POLICY, clearRetentionTasks, getRetentionTasks, pruneAiUsage, pruneExpiredContexts, registerRetentionTask, runRetentionSweep, unregisterRetentionTask } from "./system/retention.js";
|
|
28
28
|
import "./system/index.js";
|
|
29
29
|
import "./tools/index.js";
|
|
30
|
-
export { AIError, AiUsageCollector, AiUsagePersistenceHandler, BOOTED_PROVENANCE, ConfigurationError, DEFAULT_AI_COST_RATES, DEFAULT_FACET_LIMIT, DEFAULT_RETENTION_POLICY, DIAGNOSTICS_DEFAULT_LIMIT, DatabaseError, ErrorUtils, FilesystemError, MAX_FACET_FIELDS, MAX_FACET_LIMIT, MAX_STI_READ_SCOPE_TYPES, MetricsAdapter, NetworkError, ObjectRegistry, PubSubAdapter, RuntimeError, SMRT_COLLECTION_BASE_NAMES, SYSTEM_DIAGNOSTICS_TABLES, SignalBus, SignalSanitizer, SmrtClass, SmrtCollection, SmrtError, SmrtHierarchical, SmrtJunction, SmrtObject, SmrtPolymorphicAssociation, TenantIsolationError, ValidationError, ValidationReport, ValidationUtils, assertPlainJson, assertPostgresSystemTimestampsCurrent, classifyDatabaseError, classifyDialectMessage, clearRetentionTasks, config, convertTypeToJsonSchema, ensureBootstrapSystemTableCompatibility, ensureDeferredSystemTableCompatibility, ensureDispatchSubscriptionsSystemTableCompatibility, ensureDispatchSystemTableCompatibility, ensureJobEventsSystemTableCompatibility, ensureJobsSystemTableCompatibility, ensureLegacySystemTableCompatibility, ensureSystemTables, estimateAiUsageCost, executeToolCall, executeToolCalls, formatToolResults, generateToolFromMethod, generateToolManifest, getDatabaseEngine, getRetentionTasks, isAbortedTransactionError, isDeterministicDatabaseError, isFrameworkBaseClass, isNotNullViolationError, isSmrtCollectionExtendsName, isTransientDatabaseError, isUniqueViolationError, migratePostgresSystemTimestamps, planPostgresSystemTimestampMigrations, pruneAiUsage, pruneExpiredContexts, readDispatchHealth, readJobHealth, readMigrationStatus, readRecentChanges, readRegistryDrift, readScheduleHealth, readSystemDiagnostics, registerRetentionTask, runRetentionSweep, sanitizeMessagePaths, shouldIncludeMethod, smrt, smrt as smrtRegistry, snapshotRegistry, tableExists, unregisterRetentionTask, validateToolCall };
|
|
30
|
+
export { AIError, AiUsageCollector, AiUsagePersistenceHandler, BOOTED_PROVENANCE, ConfigurationError, DEFAULT_AI_COST_RATES, DEFAULT_FACET_LIMIT, DEFAULT_RETENTION_POLICY, DIAGNOSTICS_DEFAULT_LIMIT, DatabaseError, EmbeddingUnavailableError, ErrorUtils, FilesystemError, MAX_FACET_FIELDS, MAX_FACET_LIMIT, MAX_STI_READ_SCOPE_TYPES, MetricsAdapter, NetworkError, ObjectRegistry, PubSubAdapter, RuntimeError, SMRT_COLLECTION_BASE_NAMES, SYSTEM_DIAGNOSTICS_TABLES, SignalBus, SignalSanitizer, SmrtClass, SmrtCollection, SmrtError, SmrtHierarchical, SmrtJunction, SmrtObject, SmrtPolymorphicAssociation, TenantIsolationError, ValidationError, ValidationReport, ValidationUtils, assertPlainJson, assertPostgresSystemTimestampsCurrent, classifyDatabaseError, classifyDialectMessage, clearRetentionTasks, config, convertTypeToJsonSchema, ensureBootstrapSystemTableCompatibility, ensureDeferredSystemTableCompatibility, ensureDispatchSubscriptionsSystemTableCompatibility, ensureDispatchSystemTableCompatibility, ensureJobEventsSystemTableCompatibility, ensureJobsSystemTableCompatibility, ensureLegacySystemTableCompatibility, ensureSystemTables, estimateAiUsageCost, executeToolCall, executeToolCalls, formatToolResults, generateToolFromMethod, generateToolManifest, getDatabaseEngine, getRetentionTasks, isAbortedTransactionError, isDeterministicDatabaseError, isFrameworkBaseClass, isNotNullViolationError, isSmrtCollectionExtendsName, isTransientDatabaseError, isUniqueViolationError, migratePostgresSystemTimestamps, planPostgresSystemTimestampMigrations, pruneAiUsage, pruneExpiredContexts, readDispatchHealth, readJobHealth, readMigrationStatus, readRecentChanges, readRegistryDrift, readScheduleHealth, readSystemDiagnostics, registerRetentionTask, runRetentionSweep, sanitizeMessagePaths, shouldIncludeMethod, smrt, smrt as smrtRegistry, snapshotRegistry, tableExists, unregisterRetentionTask, validateToolCall };
|
package/dist/cascade.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cascade.d.ts","sourceRoot":"","sources":["../src/cascade.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAK5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAKpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAM1D;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,gBAAgB,CAAC;AAsB9C,gFAAgF;AAChF,MAAM,WAAW,gBAAgB;IAC/B,mEAAmE;IACnE,SAAS,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,SAAS,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,MAAM,EAAE,cAAc,CAAC;IACvB,4EAA4E;IAC5E,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,mEAAmE;AACnE,MAAM,WAAW,2BAA2B;IAC1C,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,2EAA2E;AAC3E,MAAM,WAAW,WAAW;IAC1B,4EAA4E;IAC5E,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,mEAAmE;IACnE,WAAW,EAAE,2BAA2B,EAAE,CAAC;IAC3C,yEAAyE;IACzE,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,+EAA+E;IAC/E,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,mBAAmB,GAAG,IAAI,CACpC,OAAO,cAAc,EACnB,oBAAoB,GACpB,WAAW,GACX,oBAAoB,GACpB,cAAc,GACd,uBAAuB,GACvB,UAAU,GACV,YAAY,GACZ,gBAAgB,CACnB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,GAAG,SAAS,CAE5E;AASD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,mBAAmB,EAC7B,SAAS,EAAE,MAAM,GAChB,WAAW,CAyIb;
|
|
1
|
+
{"version":3,"file":"cascade.d.ts","sourceRoot":"","sources":["../src/cascade.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAK5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAKpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAM1D;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,gBAAgB,CAAC;AAsB9C,gFAAgF;AAChF,MAAM,WAAW,gBAAgB;IAC/B,mEAAmE;IACnE,SAAS,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,SAAS,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,MAAM,EAAE,cAAc,CAAC;IACvB,4EAA4E;IAC5E,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,mEAAmE;AACnE,MAAM,WAAW,2BAA2B;IAC1C,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,2EAA2E;AAC3E,MAAM,WAAW,WAAW;IAC1B,4EAA4E;IAC5E,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,mEAAmE;IACnE,WAAW,EAAE,2BAA2B,EAAE,CAAC;IAC3C,yEAAyE;IACzE,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,+EAA+E;IAC/E,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,mBAAmB,GAAG,IAAI,CACpC,OAAO,cAAc,EACnB,oBAAoB,GACpB,WAAW,GACX,oBAAoB,GACpB,cAAc,GACd,uBAAuB,GACvB,UAAU,GACV,YAAY,GACZ,gBAAgB,CACnB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,GAAG,SAAS,CAE5E;AASD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,mBAAmB,EAC7B,SAAS,EAAE,MAAM,GAChB,WAAW,CAyIb;AAqZD,8EAA8E;AAC9E,MAAM,WAAW,aAAa;IAC5B,4EAA4E;IAC5E,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B;;;;OAIG;IACH,oBAAoB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3C;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,iBAAiB,EACrB,QAAQ,EAAE,mBAAmB,EAC7B,MAAM,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,EAAE,CAAA;CAAE,GAC9D,OAAO,CAAC,aAAa,CAAC,CAwBxB;AASD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,iBAAiB,EACrB,QAAQ,EAAE,mBAAmB,EAC7B,MAAM,EAAE;IACN,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CAC/B,EACD,UAAU,EAAE,CAAC,EAAE,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,GACnD,OAAO,CAAC,aAAa,CAAC,CAuDxB"}
|
package/dist/cascade.js
CHANGED
|
@@ -382,16 +382,19 @@ async function resolveReferences(ctx, className, tableName, ids, depth) {
|
|
|
382
382
|
ctx.affectedTables.add(reference.tableName);
|
|
383
383
|
ctx.affectedTableClasses.set(reference.tableName, toQualifiedClassName(ctx.registry, reference.className));
|
|
384
384
|
}
|
|
385
|
-
for (const association of plan.polymorphic)
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
385
|
+
for (const association of plan.polymorphic) {
|
|
386
|
+
if (!await ctx.db.tableExists(association.tableName)) continue;
|
|
387
|
+
for (const batch of chunkArray(pending, 900)) {
|
|
388
|
+
const where = { ...idPredicate("meta_id", batch) };
|
|
389
|
+
if (plan.metaTypes.length === 1) where.meta_type = plan.metaTypes[0];
|
|
390
|
+
else where["meta_type in"] = plan.metaTypes;
|
|
391
|
+
if (((await tolerateMissingTable(() => ctx.db.delete(association.tableName, where), void 0, {
|
|
392
|
+
table: association.tableName,
|
|
393
|
+
action: "polymorphic association cleanup"
|
|
394
|
+
}))?.affected ?? 0) > 0) {
|
|
395
|
+
ctx.affectedTables.add(association.tableName);
|
|
396
|
+
ctx.affectedTableClasses.set(association.tableName, toQualifiedClassName(ctx.registry, association.className));
|
|
397
|
+
}
|
|
395
398
|
}
|
|
396
399
|
}
|
|
397
400
|
}
|