@voltro/database 0.80.0 → 0.82.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/dist/index.d.ts CHANGED
@@ -767,6 +767,9 @@ export declare type ChangeEvent = {
767
767
  * re-read failed, or the row was already gone). Re-read or resync.
768
768
  */
769
769
  readonly oversized?: 'rehydrated' | 'tombstone' | 'unrecovered';
770
+ /** A net-change feed may coalesce intermediate writes and supply current
771
+ * images or delete keys only. It cannot support exact historical replay. */
772
+ readonly netChange?: true;
770
773
  /**
771
774
  * How the event reached this process. Absent/'inline' = emitted by this
772
775
  * process's own write path; 'injected' = delivered over a cross-instance
@@ -967,7 +970,7 @@ export declare const coercePredicateValue: (columnType: ColumnType | undefined,
967
970
  /** Same, for the array-valued operators (`inSet` / `notInSet`). */
968
971
  export declare const coercePredicateValues: (columnType: ColumnType | undefined, values: ReadonlyArray<unknown>) => ReadonlyArray<unknown>;
969
972
 
970
- /** The value half of {@link coercePredicateForSqlite}. */
973
+ /** Convert scalar/list predicate values to SQLite driver bindings. */
971
974
  export declare const coerceValueForSqlite: (value: unknown) => unknown;
972
975
 
973
976
  /**
@@ -992,7 +995,7 @@ export declare const collectSubqueries: (predicate: Predicate) => Generator<{
992
995
  * database.orders.where(eq('orgId', oid))
993
996
  * .groupBy(['status'])
994
997
  * .aggregate({ status: column<string>('status'), count: count() })
995
- * // rows: { status: string; count: number | Date | null }[]
998
+ * // rows: { status: string; count: number }[]
996
999
  * ```
997
1000
  */
998
1001
  export declare const column: <T = string | number | boolean | Date | null>(columnName: string, alias?: string) => AggregateColumn<T>;
@@ -2174,6 +2177,11 @@ table?: string) => Statement.Fragment;
2174
2177
  */
2175
2178
  export declare const compileRawFragment: <Row extends object = Record<string, unknown>>(fragment: RawSqlFragment, sql: SqlConstructor) => Statement.Statement<Row>;
2176
2179
 
2180
+ /** Preserve declared bigint columns before SQLite drivers convert them to JS numbers.
2181
+ * Shared by SELECT and DML RETURNING; other dialects retain their native projection.
2182
+ */
2183
+ export declare const compileRowProjection: (table: string, sql: SqlConstructor, projection?: ReadonlyArray<string>) => Statement.Fragment;
2184
+
2177
2185
  export declare const compileSelect: <Row extends object>(descriptor: QueryDescriptor, sql: SqlConstructor, namespace?: QueryNamespace) => Statement.Statement<Row>;
2178
2186
 
2179
2187
  /** Compose the durable identity written to `_voltro_cdcout_claims.changeKey`. */
@@ -2390,9 +2398,9 @@ export declare interface CoreTableRegistration {
2390
2398
  readonly tenants?: () => TableLike;
2391
2399
  }
2392
2400
 
2393
- export declare const count: (alias?: string) => AggregateColumn;
2401
+ export declare const count: (alias?: string) => AggregateColumn<number>;
2394
2402
 
2395
- export declare const countDistinct: (column: string, alias?: string) => AggregateColumn;
2403
+ export declare const countDistinct: (column: string, alias?: string) => AggregateColumn<number>;
2396
2404
 
2397
2405
  /**
2398
2406
  * A whole collaborative DOCUMENT as a column — rich text, nested maps/arrays,
@@ -3943,6 +3951,13 @@ export declare interface FieldCipher {
3943
3951
  * feature, and the reader must not fall back to an unbound read.
3944
3952
  */
3945
3953
  readonly decrypt: (ciphertext: string, binding?: FieldBinding) => string;
3954
+ /**
3955
+ * `true` when only a PREVIOUS key opens this value — a cipher built with the
3956
+ * keys a rotation retires (`makeFieldCipher(current, previous)`). What
3957
+ * `voltro db encrypt-column` rewrites, so the previous key can go. Absent on
3958
+ * a cipher with one key.
3959
+ */
3960
+ readonly sealedWithPreviousKey?: (ciphertext: string, binding?: FieldBinding) => boolean;
3946
3961
  }
3947
3962
 
3948
3963
  /**
@@ -5189,7 +5204,10 @@ export declare type MaterializedMixinFields<Input extends FieldsInput> = Resolve
5189
5204
 
5190
5205
  export declare const materializeFields: <F extends FieldsInput>(fields: F) => FieldDefinitions<F>;
5191
5206
 
5192
- export declare const max: (column: string, alias?: string) => AggregateColumn;
5207
+ export declare const max: <C extends string>(column: C, alias?: string) => AggregateColumn & {
5208
+ readonly op: "max";
5209
+ readonly column: C;
5210
+ };
5193
5211
 
5194
5212
  /** Strictest identifier length across supported dialects (Postgres). */
5195
5213
  export declare const MAX_IDENTIFIER_LENGTH = 63;
@@ -5424,7 +5442,10 @@ export declare interface MigrationStepContext {
5424
5442
  readonly progress: (done: number, total: number) => Effect.Effect<void, never, never>;
5425
5443
  }
5426
5444
 
5427
- export declare const min: (column: string, alias?: string) => AggregateColumn;
5445
+ export declare const min: <C extends string>(column: C, alias?: string) => AggregateColumn & {
5446
+ readonly op: "min";
5447
+ readonly column: C;
5448
+ };
5428
5449
 
5429
5450
  /**
5430
5451
  * The `conflictColumns` an upsert names that cannot match its conflict target.
@@ -6120,7 +6141,7 @@ Joins extends JoinsMap = {}> {
6120
6141
  * - grouped (via Q2's `.groupBy()`): one row per group
6121
6142
  */
6122
6143
  aggregate: <Spec extends Record<string, AggregateColumn<unknown>>>(spec: Spec) => Query<{
6123
- [K in keyof Spec]: Spec[K] extends AggregateColumn<infer T> ? T : never;
6144
+ [K in keyof Spec]: ResolveAggregateResult<Spec[K], RowOf, Joins>;
6124
6145
  }, IxNames, Joins>;
6125
6146
  /**
6126
6147
  * Add `GROUP BY` columns. Composes with `.aggregate({...})` to
@@ -6152,8 +6173,16 @@ Joins extends JoinsMap = {}> {
6152
6173
  *
6153
6174
  * Multiple `.matching()` calls override the predicate (FTS is a
6154
6175
  * single-string concept; no AND-merge).
6176
+ *
6177
+ * `{ prefix: true }` matches each query word as a word beginning and
6178
+ * requires every word — `tomato` finds `tomatoes` — on postgres
6179
+ * (`to_tsquery` with `:*`), mysql/mariadb (BOOLEAN MODE `+word*`) and
6180
+ * sqlite (FTS5 `"word"*`); mssql's LIKE and the in-memory store already
6181
+ * match that way.
6155
6182
  */
6156
- matching: (indexName: string, query: string) => Query<RowOf, IxNames, Joins>;
6183
+ matching: (indexName: string, query: string, options?: {
6184
+ readonly prefix?: boolean;
6185
+ }) => Query<RowOf, IxNames, Joins>;
6157
6186
  /**
6158
6187
  * Request a relevance-ranking column for the active `.matching(...)`
6159
6188
  * search and (by default) order results best-match-first. Must be
@@ -6523,6 +6552,16 @@ export declare interface QueryDescriptor<R = Row> {
6523
6552
  readonly alias: string;
6524
6553
  readonly order: boolean;
6525
6554
  };
6555
+ /** Each query word matches as a word BEGINNING (`tomato` finds
6556
+ * `tomatoes`), every word required — `.matching(…, { prefix: true })`. */
6557
+ readonly prefix?: boolean;
6558
+ /**
6559
+ * Set by a store whose engine keeps no full-text index (Turso's MVCC mode
6560
+ * has no FTS5): the match compiles to a case-insensitive LIKE over the
6561
+ * covered columns, ranked by how many of them hit — the same fallback as
6562
+ * mssql. Never set by the query builder.
6563
+ */
6564
+ readonly fallback?: 'like';
6526
6565
  };
6527
6566
  /**
6528
6567
  * Common-Table-Expression definitions (Q4) — `WITH <name> AS (...)`.
@@ -7129,6 +7168,12 @@ declare type Resolve<T> = {
7129
7168
  */
7130
7169
  export declare const resolveActorSnapshot: (store: ActorLookupStore, subjectId: string | null | undefined, subjectType: string) => Promise<AuditActor | undefined>;
7131
7170
 
7171
+ /** Resolve extrema from the source column while retaining explicit projection types. */
7172
+ export declare type ResolveAggregateResult<A, RowOf, Joins extends JoinsMap> = A extends {
7173
+ readonly op: 'min' | 'max';
7174
+ readonly column: infer C extends string;
7175
+ } ? ResolveJoinedSource<C, RowOf, Joins> | null : A extends AggregateColumn<infer T> ? T : never;
7176
+
7132
7177
  /**
7133
7178
  * Pick the branch mechanism. Prioritises the Neon copy-on-write fast-path when
7134
7179
  * the owned DB is Neon AND the branch snapshots parent data (`seed: 'copy'`);
@@ -7236,6 +7281,9 @@ export declare interface RetentionSpec {
7236
7281
  readonly table: string;
7237
7282
  /** Timestamp column compared against the cutoff (rows strictly older are purged). */
7238
7283
  readonly timeColumn: string;
7284
+ /** Additional timestamps that keep a row while any is within the TTL.
7285
+ * Null timestamps do not protect a row. All columns use the same cutoff. */
7286
+ readonly activityColumns?: ReadonlyArray<string>;
7239
7287
  /** Rows whose `timeColumn` is older than `now - ttlMs` are eligible for purge. */
7240
7288
  readonly ttlMs: number;
7241
7289
  /**
@@ -8022,12 +8070,12 @@ export declare const stampGeneratedId: <T extends Record<string, unknown>>(table
8022
8070
  export declare const stampGeneratedIds: <T extends Record<string, unknown>>(table: string, rows: ReadonlyArray<T>) => ReadonlyArray<T>;
8023
8071
 
8024
8072
  /**
8025
- * Prefix match on a text column — `startsWith('key', 'awb_')`.
8073
+ * Prefix match on a text column — `startsWith('key', 'acme_')`.
8026
8074
  *
8027
8075
  * **Case-SENSITIVE**, unlike {@link contains}, and the asymmetry is deliberate
8028
8076
  * rather than an oversight. `contains` is a search primitive (a human typing
8029
8077
  * into a box), so folding case is what they mean. A prefix is a NAMESPACE — a
8030
- * key prefix, a path segment, a tenant-scoped id — where `awb_` and `AWB_` are
8078
+ * key prefix, a path segment, a tenant-scoped id — where `acme_` and `ACME_` are
8031
8079
  * two different namespaces and quietly merging them is a bug. It also matches
8032
8080
  * the semantics of the JS method it is named after.
8033
8081
  *
@@ -9581,22 +9629,6 @@ export declare const _voltroIdempotencyTable: SchemaTable;
9581
9629
 
9582
9630
  export declare const _voltroKvTable: SchemaTable;
9583
9631
 
9584
- /**
9585
- * `_voltro_migration_plans` — one row per declarative-diff plan
9586
- * application. Written by the planner-based applier (Workstream G).
9587
- *
9588
- * Different from `_voltro_migrations` above:
9589
- * - `_voltro_migrations` tracks individual FILE-based migration runs
9590
- * (one row per migration file in `migrations/*.ts`).
9591
- * - `_voltro_migration_plans` tracks DECLARATIVE plan applications
9592
- * (one row per `voltro db apply` invocation — each plan may contain
9593
- * many concrete ops in `operations`).
9594
- *
9595
- * Both coexist while the framework supports both styles. The planner-based
9596
- * system is the canonical "Workstream G Herzstück" path; file-based is
9597
- * the escape-hatch for split/merge/data-move migrations the diff can't
9598
- * infer.
9599
- */
9600
9632
  export declare const _voltroMigrationPlansTable: SchemaTable;
9601
9633
 
9602
9634
  /**
@@ -9609,6 +9641,18 @@ export declare const _voltroMigrationsTable: SchemaTable;
9609
9641
 
9610
9642
  export declare const _voltroMssqlCdcOffsetsTable: TableLike;
9611
9643
 
9644
+ /**
9645
+ * `_voltro_plugin_migrations` — which plugin `extendSchema.migrations` steps ran.
9646
+ *
9647
+ * It was created by a hand-written `id TEXT PRIMARY KEY`, which MariaDB and
9648
+ * MySQL refuse (errno 1170), so a plugin that shipped a migration could not run
9649
+ * it on the MySQL family at all. Declared here, it goes through the same
9650
+ * per-dialect bootstrap as the migration ledgers — and the declared store
9651
+ * charset with them. The snake_case column names are the ones existing ledgers
9652
+ * already carry on postgres and sqlite.
9653
+ */
9654
+ export declare const _voltroPluginMigrationsTable: SchemaTable;
9655
+
9612
9656
  /**
9613
9657
  * The one row a destructive import leaves behind while it is destructive.
9614
9658
  *
@@ -9658,6 +9702,19 @@ export declare const _voltroReplaceInProgressTable: TableLike;
9658
9702
  */
9659
9703
  export declare const _voltroReplicaObservationsTable: SchemaTable;
9660
9704
 
9705
+ /**
9706
+ * `_voltro_schema_owner` — which APP this database's schema belongs to. One row.
9707
+ *
9708
+ * Two apps pointed at one database each diff the schema against their OWN
9709
+ * declarations, so each sees the other's tables as undeclared and plans to drop
9710
+ * them. The row makes the second app refuse to boot before it plans anything —
9711
+ * see `migrations/schemaOwner.ts`.
9712
+ *
9713
+ * Bootstrapped by the migration boot (like the migration ledgers) and NOT part
9714
+ * of the declared set, so adding it moves no app's schema fingerprint.
9715
+ */
9716
+ export declare const _voltroSchemaOwnerTable: SchemaTable;
9717
+
9661
9718
  /**
9662
9719
  * `_voltro_seeds` — one row per registered seed. Written to by the
9663
9720
  * seed runner as each seed's lifecycle changes. Unlike migrations,