@voltro/database 0.41.0 → 0.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +188 -0
- package/dist/{frameworkLiveTables-BS6FuivX.js → frameworkLiveTables-XPFqj8n3.js} +247 -247
- package/dist/index.d.ts +100 -13
- package/dist/index.js +786 -651
- package/dist/sql.d.ts +46 -6
- package/dist/sql.js +873 -800
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -173,7 +173,7 @@ export declare const attachEagerLoads: (rows: ReadonlyArray<Row_2>, spec: WithSp
|
|
|
173
173
|
* Returns an object with the keys OMITTED rather than set to `undefined`, so an
|
|
174
174
|
* unattributed event is byte-identical to one from before this existed — no
|
|
175
175
|
* `traceId: undefined` appearing in a snapshot, a broadcast payload, or a
|
|
176
|
-
*
|
|
176
|
+
* deployment's `Object.keys`.
|
|
177
177
|
*
|
|
178
178
|
* **Call it where the event is CREATED, not where it is delivered.** A
|
|
179
179
|
* transactional write queues its events and flushes them after commit, by which
|
|
@@ -222,7 +222,7 @@ export declare const auditTableIndexes: (table: Table<string, Record<string, Col
|
|
|
222
222
|
* so an insert need not supply them. Name-based on purpose: a hand-declared
|
|
223
223
|
* `createdAt` with no default reads as optional here (the lenient direction —
|
|
224
224
|
* never rejects valid code), while the mixin-managed ones are always filled.
|
|
225
|
-
* Runtime tuple + the type derived from it, so a
|
|
225
|
+
* Runtime tuple + the type derived from it, so a deployment that must skip these
|
|
226
226
|
* at runtime (e.g. `@voltro/testing`'s `fixtureRow`, which fills only
|
|
227
227
|
* caller-owned required columns) reads the SAME list the insert-row type uses —
|
|
228
228
|
* no second copy to drift. */
|
|
@@ -651,7 +651,7 @@ export declare type ChangeEvent = {
|
|
|
651
651
|
* How the event reached this process. Absent/'inline' = emitted by this
|
|
652
652
|
* process's own write path; 'injected' = delivered over a cross-instance
|
|
653
653
|
* transport (`injectExternalChange` — the broadcast bus or a CDC
|
|
654
|
-
* consumer). A
|
|
654
|
+
* consumer). A deployment that must act exactly once per change
|
|
655
655
|
* FLEET-WIDE combines this with `DataStore.changeScope`: on a
|
|
656
656
|
* `'local'`-scope store, acting on non-injected events covers each
|
|
657
657
|
* change exactly once (on its writer); on a `'fleet'`-scope store every
|
|
@@ -765,6 +765,19 @@ export declare const chunkRowsForInsert: <T extends Record<string, unknown>>(row
|
|
|
765
765
|
*/
|
|
766
766
|
export declare const claimPendingAttribution: (key: string) => WriteAttribution | undefined;
|
|
767
767
|
|
|
768
|
+
/**
|
|
769
|
+
* Classify a driver failure — already flattened by `extractDbCause` — into the
|
|
770
|
+
* safe facts above, or `undefined` when it is not a constraint violation at all
|
|
771
|
+
* (a deadlock, a dead connection, a timeout, a syntax error).
|
|
772
|
+
*
|
|
773
|
+
* `operation` is the write the framework was performing. It is consulted for
|
|
774
|
+
* ONE thing: sqlite reports both FK directions as the same bare
|
|
775
|
+
* `FOREIGN KEY constraint failed` with no name and no column, so a delete that
|
|
776
|
+
* trips it is `foreignKeyInUse` and an insert is `foreignKey`. Every other
|
|
777
|
+
* dialect states the direction itself and the operation is not consulted.
|
|
778
|
+
*/
|
|
779
|
+
export declare const classifyConstraintViolation: (dbCause: Record<string, unknown>, operation?: string) => ConstraintFacts | undefined;
|
|
780
|
+
|
|
768
781
|
/** Wipe — used by tests + the dev-loop hot-reload. */
|
|
769
782
|
export declare const clearEnumRenames: () => void;
|
|
770
783
|
|
|
@@ -1865,6 +1878,48 @@ export declare interface ConnectionIdentityInput {
|
|
|
1865
1878
|
readonly database?: string | undefined;
|
|
1866
1879
|
}
|
|
1867
1880
|
|
|
1881
|
+
/**
|
|
1882
|
+
* The SAFE facts about a constraint violation: which rule, and the NAME of the
|
|
1883
|
+
* constraint / column it fired on. Never a value, and never the driver's
|
|
1884
|
+
* sentence.
|
|
1885
|
+
*
|
|
1886
|
+
* That exclusion is the whole design, and it is measured, not cautious:
|
|
1887
|
+
*
|
|
1888
|
+
* - postgres attaches `detail: "Failing row contains (t4, l1, null, null,
|
|
1889
|
+
* null)."` to a not-null and a check violation — **the entire row**, every
|
|
1890
|
+
* column, including anything a table marked `.sensitive()`.
|
|
1891
|
+
* - mysql/mariadb: `Duplicate entry 's1' for key 'tasks.slug'`.
|
|
1892
|
+
* - mssql: `The duplicate key value is (s1).` and, on truncation,
|
|
1893
|
+
* `Truncated value: '…'`.
|
|
1894
|
+
*
|
|
1895
|
+
* So "just pass the driver message through" is not a smaller version of this —
|
|
1896
|
+
* it is a different feature, one that ships row contents to whoever provoked
|
|
1897
|
+
* the error. A constraint NAME is schema, the same class of fact the framework
|
|
1898
|
+
* already puts on the wire in `TableValidationFailed.table`; a row is data.
|
|
1899
|
+
*
|
|
1900
|
+
* Everything here is captured as an anchored identifier group out of the
|
|
1901
|
+
* driver text — never a slice of it — so a regex that fails to match yields
|
|
1902
|
+
* `undefined` rather than a sentence that happens to contain a value.
|
|
1903
|
+
*/
|
|
1904
|
+
export declare interface ConstraintFacts {
|
|
1905
|
+
readonly kind: ConstraintKind;
|
|
1906
|
+
/** The constraint / index name, when the dialect names one. */
|
|
1907
|
+
readonly constraint?: string;
|
|
1908
|
+
/** The column, when the dialect names one instead of (or beside) a constraint. */
|
|
1909
|
+
readonly column?: string;
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
/**
|
|
1913
|
+
* Which integrity rule the database refused on.
|
|
1914
|
+
*
|
|
1915
|
+
* `foreignKey` and `foreignKeyInUse` are the two DIRECTIONS of one constraint
|
|
1916
|
+
* and mean opposite things to a caller — "the row you pointed at does not
|
|
1917
|
+
* exist" vs "you may not remove this row, others still point at it". A UI
|
|
1918
|
+
* branches differently on each, so they are separate members rather than one
|
|
1919
|
+
* member plus a string a caller would have to grep.
|
|
1920
|
+
*/
|
|
1921
|
+
export declare type ConstraintKind = 'foreignKey' | 'foreignKeyInUse' | 'unique' | 'notNull' | 'check';
|
|
1922
|
+
|
|
1868
1923
|
/** Case-insensitive substring match on a text column. Non-indexable —
|
|
1869
1924
|
* always evaluated as an unindexed leaf (the matcher's pre-filter only
|
|
1870
1925
|
* recognizes eq/in/range). Lowers to `ILIKE '%…%'` on Postgres. */
|
|
@@ -2803,7 +2858,7 @@ declare type EmptyMerge = unknown;
|
|
|
2803
2858
|
*
|
|
2804
2859
|
* It was three. The store wrote `encrypt(JSON.stringify(v))`, the escape hatch
|
|
2805
2860
|
* wrote `encrypt(v)`, and the backfill wrote `encrypt(v)`. All three produce the
|
|
2806
|
-
* `enc:v1:` envelope and NOTHING distinguishes them. A
|
|
2861
|
+
* `enc:v1:` envelope and NOTHING distinguishes them. A deployment wrote session
|
|
2807
2862
|
* rows through the escape hatch and read them through the store, which threw
|
|
2808
2863
|
* `FieldDecryptionError` blaming the key — the key was right; the ENCODING was
|
|
2809
2864
|
* not. Eight of their ten session rows, and the failure looked like a key
|
|
@@ -2970,6 +3025,8 @@ export declare const expires: () => MixinDefinition<{
|
|
|
2970
3025
|
*/
|
|
2971
3026
|
export declare const externalChangeEvent: (event: ChangeEvent, attribution?: Partial<ChangeEventMeta>) => ChangeEvent;
|
|
2972
3027
|
|
|
3028
|
+
export declare const extractDbCause: (err: unknown) => Record<string, unknown>;
|
|
3029
|
+
|
|
2973
3030
|
/** The subset of `@voltro/logger`'s logger this module needs. Structural so
|
|
2974
3031
|
* this package keeps its browser-safe import surface. */
|
|
2975
3032
|
export declare interface FallbackLogger {
|
|
@@ -3499,7 +3556,7 @@ export declare const isBranchNamespace: (namespace: string) => boolean;
|
|
|
3499
3556
|
* `isRelationsSpec` rejects it (registering nothing has no meaning), which is
|
|
3500
3557
|
* right, but the caller then cannot tell it apart from a module with no
|
|
3501
3558
|
* `relations(...)` export at all. `voltro dev` reported both as *"no relations(...)
|
|
3502
|
-
* export found"*, and a
|
|
3559
|
+
* export found"*, and a deployment with 368 relations files got exactly one warning
|
|
3503
3560
|
* pointing at a file that HAS the export:
|
|
3504
3561
|
*
|
|
3505
3562
|
* export const easyProxyIntegrationsRelations = relations(easyProxyIntegrations, ({ one }) => ({
|
|
@@ -3518,6 +3575,15 @@ export declare const isFieldDecryptionError: (e: unknown) => e is FieldDecryptio
|
|
|
3518
3575
|
/** Type-guard for the discovery walker. */
|
|
3519
3576
|
export declare const isFileMigration: (value: unknown) => value is FileMigration;
|
|
3520
3577
|
|
|
3578
|
+
/**
|
|
3579
|
+
* Foreign-key violation, either direction, across every dialect. Derived from
|
|
3580
|
+
* `classifyConstraintViolation` rather than re-listing the codes: this
|
|
3581
|
+
* predicate and the classifier disagreeing is invisible until a tenant-FK
|
|
3582
|
+
* failure quietly stops being typed, and mssql already spent a release in
|
|
3583
|
+
* exactly that state (547 was read off `.code`, where it never appears).
|
|
3584
|
+
*/
|
|
3585
|
+
export declare const isForeignKeyViolation: (dbCause: Record<string, unknown>) => boolean;
|
|
3586
|
+
|
|
3521
3587
|
/** True when `name` is a live table the framework / its runtime engines create
|
|
3522
3588
|
* but no user schema declares — never plan a drop for it. */
|
|
3523
3589
|
export declare const isFrameworkOwnedLiveTable: (name: string) => boolean;
|
|
@@ -3531,6 +3597,18 @@ export declare const isLocalFirst: (table: LocalFirstMarked) => boolean;
|
|
|
3531
3597
|
|
|
3532
3598
|
export declare const isMigrationDefinition: (value: unknown) => value is MigrationDefinition;
|
|
3533
3599
|
|
|
3600
|
+
/**
|
|
3601
|
+
* MySQL and MariaDB. They share a driver, a quoting style and most of a
|
|
3602
|
+
* grammar — and they are NOT interchangeable in DDL.
|
|
3603
|
+
*
|
|
3604
|
+
* The one that has already cost us: **MySQL/InnoDB silently discards a
|
|
3605
|
+
* column-inline `REFERENCES` clause** (parsed, thrown away, no warning, CREATE
|
|
3606
|
+
* succeeds), while MariaDB honours it and creates the constraint. Measured on
|
|
3607
|
+
* mysql 8.4 and mariadb 11. Anything referential that this family emits has to
|
|
3608
|
+
* be table-level to work on both.
|
|
3609
|
+
*/
|
|
3610
|
+
export declare const isMysqlFamily: (dialect: DialectId) => boolean;
|
|
3611
|
+
|
|
3534
3612
|
/**
|
|
3535
3613
|
* True when the connection string points at a Neon serverless-postgres host
|
|
3536
3614
|
* (`*.neon.tech` / `*.neon.build`, including the `-pooler` endpoints). Neon's
|
|
@@ -3546,6 +3624,15 @@ export declare const isNull: <RowOf = Record<string, unknown>, K extends keyof R
|
|
|
3546
3624
|
|
|
3547
3625
|
export declare const isPrimaryKeyConflictError: (err: unknown) => err is PrimaryKeyConflictError;
|
|
3548
3626
|
|
|
3627
|
+
/** A query cancelled for exceeding the `statementTimeoutMs` deadline, across
|
|
3628
|
+
* dialects: pg `57014` (query_canceled — what `statement_timeout` raises),
|
|
3629
|
+
* MySQL `3024` (ER_QUERY_TIMEOUT), MariaDB `1969` (ER_STATEMENT_TIMEOUT), mssql
|
|
3630
|
+
* `ETIMEOUT` (tedious request timeout), sqlite `SQLITE_INTERRUPT`. NOT a
|
|
3631
|
+
* transient error — a re-run just repeats the runaway, so it must not retry
|
|
3632
|
+
* (`servePipeline`'s transient set deliberately excludes it). Lets a deployment /
|
|
3633
|
+
* observability layer name the failure instead of reading an opaque SqlError. */
|
|
3634
|
+
export declare const isQueryTimeout: (dbCause: Record<string, unknown>) => boolean;
|
|
3635
|
+
|
|
3549
3636
|
/** Is this ciphertext in the OLD raw encoding? Used by `voltro db encrypt-column`
|
|
3550
3637
|
* to normalise a column without touching rows that are already current. Answers
|
|
3551
3638
|
* `undefined` when the two forms coincide (a numeric column, or a value that
|
|
@@ -3838,7 +3925,7 @@ export declare interface ManyToManyRelation {
|
|
|
3838
3925
|
* the dangerous one: an empty `IN ()` gets dropped, and a DROPPED predicate does
|
|
3839
3926
|
* not narrow — it WIDENS, to the whole tenant. Here it is safe (the SQL
|
|
3840
3927
|
* compiler emits `FALSE`, the in-memory evaluator returns false, and both are
|
|
3841
|
-
* pinned by tests) but an adopting
|
|
3928
|
+
* pinned by tests) but an adopting project wrote `eq('id', '')` instead, because
|
|
3842
3929
|
* they could not tell from the outside and would not bet a visibility rule on
|
|
3843
3930
|
* it. They were right not to.
|
|
3844
3931
|
*
|
|
@@ -5347,7 +5434,7 @@ export declare const registerPendingAttribution: (key: string, attribution: Writ
|
|
|
5347
5434
|
* Register a single `relations()` spec. Multiple specs on the same
|
|
5348
5435
|
* source MERGE — a second spec adds to the first one. A name
|
|
5349
5436
|
* collision between two DIFFERENT specs throws here so the offending
|
|
5350
|
-
* declaration site is the error scope, not a downstream
|
|
5437
|
+
* declaration site is the error scope, not a downstream deployment.
|
|
5351
5438
|
*
|
|
5352
5439
|
* Re-registering the SAME relation object is a no-op, mirroring
|
|
5353
5440
|
* `registerTable`'s `existing === table` tolerance — and for the same reason:
|
|
@@ -5374,7 +5461,7 @@ export declare const registerRelations: (spec: RelationsSpec) => void;
|
|
|
5374
5461
|
*
|
|
5375
5462
|
* ── Two registrations for one table used to be a silent last-write-wins ─────
|
|
5376
5463
|
*
|
|
5377
|
-
* A
|
|
5464
|
+
* A deployment registered `_voltro_schedule_claims` at 1 hour from a startup, and
|
|
5378
5465
|
* one second later the framework registered its own default for the same table.
|
|
5379
5466
|
* Ours won, nothing said so, and their startup went on logging `bounded to 1h`
|
|
5380
5467
|
* at every boot while the table kept everything younger than the framework's
|
|
@@ -5665,7 +5752,7 @@ export declare interface RetentionSpec {
|
|
|
5665
5752
|
* The environment variable that changes this TTL, for the boot announcement.
|
|
5666
5753
|
*
|
|
5667
5754
|
* A standing DELETE whose only control is a variable you have to already know
|
|
5668
|
-
* the name of is how a
|
|
5755
|
+
* the name of is how a deployment lost 1 944 freshly-migrated rows to a 180-day
|
|
5669
5756
|
* default — and then got it wrong a second time by setting it in a running pod
|
|
5670
5757
|
* rather than in a file, where the next deploy would have reverted it. Naming
|
|
5671
5758
|
* it in the boot line is what turns "you have to know" into "you were told".
|
|
@@ -5859,7 +5946,7 @@ export declare type SchemaChangeSeedHook = (event: SchemaChangeSeedEvent) => Pro
|
|
|
5859
5946
|
* inferred {@link Table} generic pulls its method signatures into the emitted
|
|
5860
5947
|
* `.d.ts`, and those reference the private `ColumnBuilder` class — which
|
|
5861
5948
|
* TypeScript refuses to name across the boundary (TS4094). `SchemaTable`
|
|
5862
|
-
* exposes only the plain-data surface a
|
|
5949
|
+
* exposes only the plain-data surface a deployment of a contributed table
|
|
5863
5950
|
* actually reads (`.tableName`, `.fields`, `.appliedIndexes`), so it names
|
|
5864
5951
|
* cleanly and stays browser-safe (pure interfaces, no builder, no server
|
|
5865
5952
|
* imports). A concrete `Table<...>` is assignable to it.
|
|
@@ -6006,7 +6093,7 @@ export declare interface SeedStore {
|
|
|
6006
6093
|
* The primitive an idempotent restore is actually built on: `upsertByUnique`
|
|
6007
6094
|
* costs a read per row and OVERWRITES what it finds, which is wrong when the
|
|
6008
6095
|
* live row is newer than the snapshot. This is one statement per row and
|
|
6009
|
-
* leaves an existing row alone. Reported
|
|
6096
|
+
* leaves an existing row alone. Reported from a real deployment restoring 1361 rows
|
|
6010
6097
|
* across 167 tables in multiple passes for FK order — with only
|
|
6011
6098
|
* `upsertByUnique` available, every pass re-read and re-wrote everything.
|
|
6012
6099
|
*/
|
|
@@ -6255,7 +6342,7 @@ export declare interface StreamTableOptions {
|
|
|
6255
6342
|
readonly where?: Predicate;
|
|
6256
6343
|
/** Rows per DB page. Larger = fewer round-trips, more per-page memory.
|
|
6257
6344
|
* Default 1000. This is the READ page size; it is independent of any
|
|
6258
|
-
* downstream write/checkpoint chunking a
|
|
6345
|
+
* downstream write/checkpoint chunking a deployment layers on. */
|
|
6259
6346
|
readonly chunkSize?: number;
|
|
6260
6347
|
/** Pass-through of the reactive scope opt-outs. For a faithful physical
|
|
6261
6348
|
* export use the RAW dialect store (no scoping applied at all); these
|
|
@@ -7537,7 +7624,7 @@ export declare interface WindowSpec {
|
|
|
7537
7624
|
* request behind this write", so the result does not look like a defect; it looks
|
|
7538
7625
|
* like a schedule. In a compliance trail that asymmetry is the whole problem.
|
|
7539
7626
|
*
|
|
7540
|
-
* A
|
|
7627
|
+
* A deployment could not reproduce it across 2700 writes at 96-way concurrency with
|
|
7541
7628
|
* every core saturated — which is good evidence the window is narrow at their load
|
|
7542
7629
|
* and no evidence at all that it is closed. Their own framing is why this is being
|
|
7543
7630
|
* closed structurally rather than left: *"impossible beats unlikely when the
|