@minnowdb/core 0.3.0 → 0.4.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.
Files changed (276) hide show
  1. package/README.md +4 -2
  2. package/dist/block-format/block.d.ts +32 -13
  3. package/dist/block-format/block.js +179 -55
  4. package/dist/block-format/checksum.d.ts +2 -1
  5. package/dist/block-format/checksum.js +5 -2
  6. package/dist/block-format/codecs.d.ts +7 -2
  7. package/dist/block-format/codecs.js +53 -12
  8. package/dist/block-format/column.d.ts +3 -2
  9. package/dist/block-format/column.js +96 -30
  10. package/dist/block-format/index.d.ts +2 -2
  11. package/dist/block-format/index.js +2 -2
  12. package/dist/block-format/physical.d.ts +8 -2
  13. package/dist/block-format/physical.js +14 -6
  14. package/dist/block-format/types.d.ts +7 -3
  15. package/dist/block-format/types.js +0 -1
  16. package/dist/block-format/unicode.d.ts +11 -0
  17. package/dist/block-format/unicode.js +46 -0
  18. package/dist/date-value.d.ts +15 -0
  19. package/dist/date-value.js +64 -0
  20. package/dist/engine/artifact-cache.d.ts +0 -1
  21. package/dist/engine/artifact-cache.js +0 -1
  22. package/dist/engine/batch.d.ts +5 -2
  23. package/dist/engine/batch.js +0 -1
  24. package/dist/engine/buffered-writer.d.ts +2 -1
  25. package/dist/engine/buffered-writer.js +34 -9
  26. package/dist/engine/cache-limits.d.ts +25 -0
  27. package/dist/engine/cache-limits.js +25 -0
  28. package/dist/engine/catalog.d.ts +5 -6
  29. package/dist/engine/catalog.js +5 -5
  30. package/dist/engine/client.d.ts +27 -7
  31. package/dist/engine/client.js +197 -31
  32. package/dist/engine/database.d.ts +161 -38
  33. package/dist/engine/database.js +4320 -1523
  34. package/dist/engine/defaults.d.ts +0 -1
  35. package/dist/engine/defaults.js +2 -4
  36. package/dist/engine/errors.d.ts +19 -1
  37. package/dist/engine/errors.js +32 -2
  38. package/dist/engine/fts.d.ts +0 -6
  39. package/dist/engine/fts.js +39 -14
  40. package/dist/engine/group-index.d.ts +0 -1
  41. package/dist/engine/group-index.js +6 -11
  42. package/dist/engine/index.d.ts +16 -11
  43. package/dist/engine/index.js +12 -10
  44. package/dist/engine/join-index.d.ts +0 -1
  45. package/dist/engine/join-index.js +2 -2
  46. package/dist/engine/keyed-live.d.ts +57 -0
  47. package/dist/engine/keyed-live.js +226 -0
  48. package/dist/engine/live-api.d.ts +4 -0
  49. package/dist/engine/live-api.js +4 -0
  50. package/dist/engine/live.d.ts +43 -26
  51. package/dist/engine/live.js +499 -129
  52. package/dist/engine/memory.d.ts +2 -1
  53. package/dist/engine/memory.js +3 -2
  54. package/dist/engine/optimizer.d.ts +0 -1
  55. package/dist/engine/optimizer.js +4 -4
  56. package/dist/engine/query-api.d.ts +3 -0
  57. package/dist/engine/query-api.js +3 -0
  58. package/dist/engine/query-cache.d.ts +0 -1
  59. package/dist/engine/query-cache.js +4 -4
  60. package/dist/engine/query.d.ts +4 -7
  61. package/dist/engine/query.js +348 -155
  62. package/dist/engine/result-wire.d.ts +0 -1
  63. package/dist/engine/result-wire.js +2 -2
  64. package/dist/engine/schema-wire.d.ts +1 -2
  65. package/dist/engine/schema-wire.js +0 -1
  66. package/dist/engine/schema.d.ts +3 -8
  67. package/dist/engine/schema.js +41 -24
  68. package/dist/engine/sort-keys.d.ts +0 -1
  69. package/dist/engine/sort-keys.js +2 -2
  70. package/dist/engine/sql-domains.d.ts +6 -1
  71. package/dist/engine/sql-domains.js +209 -45
  72. package/dist/engine/sql-driver.d.ts +2 -2
  73. package/dist/engine/sql-driver.js +0 -1
  74. package/dist/engine/sql-json.d.ts +0 -1
  75. package/dist/engine/sql-json.js +53 -7
  76. package/dist/engine/sql-semantics.d.ts +8 -5
  77. package/dist/engine/sql-semantics.js +427 -65
  78. package/dist/engine/typed-live.d.ts +67 -0
  79. package/dist/engine/typed-live.js +349 -0
  80. package/dist/engine/vector.d.ts +7 -1
  81. package/dist/engine/vector.js +202 -58
  82. package/dist/engine/worker-host.d.ts +8 -2
  83. package/dist/engine/worker-host.js +616 -152
  84. package/dist/engine/worker.d.ts +0 -1
  85. package/dist/engine/worker.js +3 -3
  86. package/dist/engine/write-block-planner.d.ts +18 -0
  87. package/dist/engine/write-block-planner.js +112 -0
  88. package/dist/index.d.ts +0 -1
  89. package/dist/index.js +0 -1
  90. package/dist/plan/index.d.ts +0 -1
  91. package/dist/plan/index.js +0 -1
  92. package/dist/storage/index.d.ts +1 -1
  93. package/dist/storage/index.js +1 -1
  94. package/dist/storage/indexeddb.d.ts +74 -65
  95. package/dist/storage/indexeddb.js +12301 -2076
  96. package/dist/storage/memory.d.ts +56 -66
  97. package/dist/storage/memory.js +1004 -139
  98. package/dist/storage/opfs/files.d.ts +18 -7
  99. package/dist/storage/opfs/files.js +115 -28
  100. package/dist/storage/opfs/index.d.ts +1 -1
  101. package/dist/storage/opfs/index.js +1 -1
  102. package/dist/storage/opfs/leader.d.ts +403 -91
  103. package/dist/storage/opfs/leader.js +4306 -602
  104. package/dist/storage/opfs/rpc.d.ts +15 -3
  105. package/dist/storage/opfs/rpc.js +223 -2
  106. package/dist/storage/opfs/snapshot-ledger.d.ts +40 -0
  107. package/dist/storage/opfs/snapshot-ledger.js +281 -0
  108. package/dist/storage/opfs/store.d.ts +26 -121
  109. package/dist/storage/opfs/store.js +436 -388
  110. package/dist/storage/persistence.d.ts +37 -0
  111. package/dist/storage/persistence.js +78 -0
  112. package/dist/storage/snapshot-stream.d.ts +24 -0
  113. package/dist/storage/snapshot-stream.js +897 -0
  114. package/dist/storage/snapshot.d.ts +9 -99
  115. package/dist/storage/snapshot.js +33 -309
  116. package/dist/storage/toolkit/extents.d.ts +41 -7
  117. package/dist/storage/toolkit/extents.js +402 -39
  118. package/dist/storage/toolkit/index.d.ts +3 -4
  119. package/dist/storage/toolkit/index.js +27 -3
  120. package/dist/storage/toolkit/record-core.d.ts +174 -61
  121. package/dist/storage/toolkit/record-core.js +5401 -849
  122. package/dist/storage/toolkit/sync-file.d.ts +10 -1
  123. package/dist/storage/toolkit/sync-file.js +50 -2
  124. package/dist/storage/toolkit/wal.d.ts +23 -5
  125. package/dist/storage/toolkit/wal.js +89 -27
  126. package/dist/storage/toolkit/wire.d.ts +4 -6
  127. package/dist/storage/toolkit/wire.js +80 -25
  128. package/dist/storage/types.d.ts +1271 -218
  129. package/dist/storage/types.js +1471 -138
  130. package/dist/testing/block-store-conformance.d.ts +0 -1
  131. package/dist/testing/block-store-conformance.js +877 -138
  132. package/dist/testing/index.d.ts +42 -31
  133. package/dist/testing/index.js +100 -68
  134. package/dist/testing/opfs-shim.d.ts +13 -3
  135. package/dist/testing/opfs-shim.js +40 -6
  136. package/dist/testing/simulator.d.ts +0 -1
  137. package/dist/testing/simulator.js +43 -12
  138. package/dist/testing/sqllogictest.d.ts +0 -1
  139. package/dist/testing/sqllogictest.js +0 -1
  140. package/dist/transactions/index.d.ts +81 -20
  141. package/dist/transactions/index.js +1050 -268
  142. package/dist/worker-protocol/index.d.ts +3 -2
  143. package/dist/worker-protocol/index.js +2 -5
  144. package/package.json +49 -1
  145. package/dist/block-format/block.d.ts.map +0 -1
  146. package/dist/block-format/block.js.map +0 -1
  147. package/dist/block-format/checksum.d.ts.map +0 -1
  148. package/dist/block-format/checksum.js.map +0 -1
  149. package/dist/block-format/codecs.d.ts.map +0 -1
  150. package/dist/block-format/codecs.js.map +0 -1
  151. package/dist/block-format/column.d.ts.map +0 -1
  152. package/dist/block-format/column.js.map +0 -1
  153. package/dist/block-format/index.d.ts.map +0 -1
  154. package/dist/block-format/index.js.map +0 -1
  155. package/dist/block-format/physical.d.ts.map +0 -1
  156. package/dist/block-format/physical.js.map +0 -1
  157. package/dist/block-format/types.d.ts.map +0 -1
  158. package/dist/block-format/types.js.map +0 -1
  159. package/dist/engine/artifact-cache.d.ts.map +0 -1
  160. package/dist/engine/artifact-cache.js.map +0 -1
  161. package/dist/engine/batch.d.ts.map +0 -1
  162. package/dist/engine/batch.js.map +0 -1
  163. package/dist/engine/buffered-writer.d.ts.map +0 -1
  164. package/dist/engine/buffered-writer.js.map +0 -1
  165. package/dist/engine/catalog.d.ts.map +0 -1
  166. package/dist/engine/catalog.js.map +0 -1
  167. package/dist/engine/client.d.ts.map +0 -1
  168. package/dist/engine/client.js.map +0 -1
  169. package/dist/engine/coordinator.d.ts +0 -17
  170. package/dist/engine/coordinator.d.ts.map +0 -1
  171. package/dist/engine/coordinator.js +0 -60
  172. package/dist/engine/coordinator.js.map +0 -1
  173. package/dist/engine/database.d.ts.map +0 -1
  174. package/dist/engine/database.js.map +0 -1
  175. package/dist/engine/defaults.d.ts.map +0 -1
  176. package/dist/engine/defaults.js.map +0 -1
  177. package/dist/engine/errors.d.ts.map +0 -1
  178. package/dist/engine/errors.js.map +0 -1
  179. package/dist/engine/fts.d.ts.map +0 -1
  180. package/dist/engine/fts.js.map +0 -1
  181. package/dist/engine/group-index.d.ts.map +0 -1
  182. package/dist/engine/group-index.js.map +0 -1
  183. package/dist/engine/index.d.ts.map +0 -1
  184. package/dist/engine/index.js.map +0 -1
  185. package/dist/engine/join-index.d.ts.map +0 -1
  186. package/dist/engine/join-index.js.map +0 -1
  187. package/dist/engine/live.d.ts.map +0 -1
  188. package/dist/engine/live.js.map +0 -1
  189. package/dist/engine/memory.d.ts.map +0 -1
  190. package/dist/engine/memory.js.map +0 -1
  191. package/dist/engine/optimizer.d.ts.map +0 -1
  192. package/dist/engine/optimizer.js.map +0 -1
  193. package/dist/engine/query-cache.d.ts.map +0 -1
  194. package/dist/engine/query-cache.js.map +0 -1
  195. package/dist/engine/query.d.ts.map +0 -1
  196. package/dist/engine/query.js.map +0 -1
  197. package/dist/engine/result-wire.d.ts.map +0 -1
  198. package/dist/engine/result-wire.js.map +0 -1
  199. package/dist/engine/schema-wire.d.ts.map +0 -1
  200. package/dist/engine/schema-wire.js.map +0 -1
  201. package/dist/engine/schema.d.ts.map +0 -1
  202. package/dist/engine/schema.js.map +0 -1
  203. package/dist/engine/sort-keys.d.ts.map +0 -1
  204. package/dist/engine/sort-keys.js.map +0 -1
  205. package/dist/engine/sql-domains.d.ts.map +0 -1
  206. package/dist/engine/sql-domains.js.map +0 -1
  207. package/dist/engine/sql-driver.d.ts.map +0 -1
  208. package/dist/engine/sql-driver.js.map +0 -1
  209. package/dist/engine/sql-json.d.ts.map +0 -1
  210. package/dist/engine/sql-json.js.map +0 -1
  211. package/dist/engine/sql-semantics.d.ts.map +0 -1
  212. package/dist/engine/sql-semantics.js.map +0 -1
  213. package/dist/engine/vector.d.ts.map +0 -1
  214. package/dist/engine/vector.js.map +0 -1
  215. package/dist/engine/worker-host.d.ts.map +0 -1
  216. package/dist/engine/worker-host.js.map +0 -1
  217. package/dist/engine/worker.d.ts.map +0 -1
  218. package/dist/engine/worker.js.map +0 -1
  219. package/dist/index.d.ts.map +0 -1
  220. package/dist/index.js.map +0 -1
  221. package/dist/plan/index.d.ts.map +0 -1
  222. package/dist/plan/index.js.map +0 -1
  223. package/dist/storage/fixture-shape.d.ts +0 -42
  224. package/dist/storage/fixture-shape.d.ts.map +0 -1
  225. package/dist/storage/fixture-shape.js +0 -146
  226. package/dist/storage/fixture-shape.js.map +0 -1
  227. package/dist/storage/index.d.ts.map +0 -1
  228. package/dist/storage/index.js.map +0 -1
  229. package/dist/storage/indexeddb.d.ts.map +0 -1
  230. package/dist/storage/indexeddb.js.map +0 -1
  231. package/dist/storage/memory.d.ts.map +0 -1
  232. package/dist/storage/memory.js.map +0 -1
  233. package/dist/storage/opfs/files.d.ts.map +0 -1
  234. package/dist/storage/opfs/files.js.map +0 -1
  235. package/dist/storage/opfs/index.d.ts.map +0 -1
  236. package/dist/storage/opfs/index.js.map +0 -1
  237. package/dist/storage/opfs/leader.d.ts.map +0 -1
  238. package/dist/storage/opfs/leader.js.map +0 -1
  239. package/dist/storage/opfs/rpc.d.ts.map +0 -1
  240. package/dist/storage/opfs/rpc.js.map +0 -1
  241. package/dist/storage/opfs/store.d.ts.map +0 -1
  242. package/dist/storage/opfs/store.js.map +0 -1
  243. package/dist/storage/snapshot.d.ts.map +0 -1
  244. package/dist/storage/snapshot.js.map +0 -1
  245. package/dist/storage/toolkit/extents.d.ts.map +0 -1
  246. package/dist/storage/toolkit/extents.js.map +0 -1
  247. package/dist/storage/toolkit/index.d.ts.map +0 -1
  248. package/dist/storage/toolkit/index.js.map +0 -1
  249. package/dist/storage/toolkit/record-core.d.ts.map +0 -1
  250. package/dist/storage/toolkit/record-core.js.map +0 -1
  251. package/dist/storage/toolkit/sync-file.d.ts.map +0 -1
  252. package/dist/storage/toolkit/sync-file.js.map +0 -1
  253. package/dist/storage/toolkit/wal.d.ts.map +0 -1
  254. package/dist/storage/toolkit/wal.js.map +0 -1
  255. package/dist/storage/toolkit/wire.d.ts.map +0 -1
  256. package/dist/storage/toolkit/wire.js.map +0 -1
  257. package/dist/storage/types.d.ts.map +0 -1
  258. package/dist/storage/types.js.map +0 -1
  259. package/dist/testing/block-store-conformance.d.ts.map +0 -1
  260. package/dist/testing/block-store-conformance.js.map +0 -1
  261. package/dist/testing/index.d.ts.map +0 -1
  262. package/dist/testing/index.js.map +0 -1
  263. package/dist/testing/opfs-shim.d.ts.map +0 -1
  264. package/dist/testing/opfs-shim.js.map +0 -1
  265. package/dist/testing/seeds.d.ts +0 -11
  266. package/dist/testing/seeds.d.ts.map +0 -1
  267. package/dist/testing/seeds.js +0 -50
  268. package/dist/testing/seeds.js.map +0 -1
  269. package/dist/testing/simulator.d.ts.map +0 -1
  270. package/dist/testing/simulator.js.map +0 -1
  271. package/dist/testing/sqllogictest.d.ts.map +0 -1
  272. package/dist/testing/sqllogictest.js.map +0 -1
  273. package/dist/transactions/index.d.ts.map +0 -1
  274. package/dist/transactions/index.js.map +0 -1
  275. package/dist/worker-protocol/index.d.ts.map +0 -1
  276. package/dist/worker-protocol/index.js.map +0 -1
@@ -1,16 +1,21 @@
1
- import type { DatabaseSnapshot, SnapshotLoadProgress } from "./snapshot.js";
2
1
  export declare const storeNames: readonly ["catalog", "manifests", "segments", "blocks", "transactions", "leases", "statistics", "temp", "gc"];
3
- /** The manifest fields every commit publishes; `Manifest` adds the resolved block list. */
2
+ export declare const MAX_MANIFEST_CHANGED_TABLE_IDS = 1024;
3
+ export declare function canonicalManifestChangedTableIds(ids: readonly string[]): string[];
4
+ export declare function validateCanonicalManifestChangedTableIds(ids: readonly string[]): string[];
5
+ /**
6
+ * The bounded manifest record every commit publishes. Block membership is paged separately;
7
+ * reading this record must never materialize a database-sized ID array.
8
+ */
4
9
  export interface ManifestSummary {
5
10
  version: number;
6
11
  previousVersion: number | null;
7
12
  createdAt: string;
8
- /**
9
- * Table IDs whose logical content this commit changed; empty means a logical no-change such as
10
- * compaction. Absent on manifests written before change tracking, which readers treat as
11
- * potentially changing every table.
12
- */
13
- changedTableIds?: string[];
13
+ /** Exact live payload membership cardinality at this version. */
14
+ liveBlockCount: number;
15
+ /** Exact sum of stored payload bytes in the live membership at this version. */
16
+ liveBlockBytes: number;
17
+ /** Table IDs whose logical content changed; empty means compaction or another logical no-op. */
18
+ changedTableIds: string[];
14
19
  /** A pruned descriptor remains readable for commit reconciliation but cannot be pinned. */
15
20
  prunedAt?: string;
16
21
  /**
@@ -24,34 +29,80 @@ export interface ManifestSummary {
24
29
  count: number;
25
30
  }>;
26
31
  }
27
- export interface Manifest extends ManifestSummary {
28
- blockIds: string[];
29
- }
32
+ /** Public/cold manifest inspection is bounded metadata only. */
33
+ export type Manifest = ManifestSummary;
30
34
  /**
31
- * The stored manifest shape: a checkpoint carries the complete sorted block list; a delta
32
- * carries only this commit's added and removed ids plus its distance from the checkpoint below
33
- * it. Reads resolve a version by walking back to the nearest checkpoint and applying deltas
34
- * forward, so publishing a commit writes O(changed blocks) instead of rewriting every live
35
- * block id. Pruning first tombstones records; maintenance later deletes only the obsolete prefix
36
- * below the checkpoint that the earliest readable version needs.
35
+ * One payload's bounded manifest-membership interval. The block is visible at version `v` iff
36
+ * `addedVersion <= v && (removedVersion === null || v < removedVersion)`. `byteLength` and the
37
+ * payload bytes are immutable while this record exists; `removedVersion`, when present, is
38
+ * strictly greater than `addedVersion`.
39
+ *
40
+ * A retired ID cannot be added again while this provenance record or a transaction/job that
41
+ * names it is retained. Once every readable/pinned version in the interval and every recovery
42
+ * root is gone, garbage collection removes payload and provenance together; no immortal ID
43
+ * tombstone is required.
37
44
  */
38
- export interface StoredManifestRecord extends ManifestSummary {
39
- blockIds?: string[];
40
- addedBlockIds?: string[];
41
- removedBlockIds?: string[];
42
- /** Deltas since the checkpoint below; 0 on checkpoints. */
43
- deltaDepth?: number;
44
- }
45
- /** Every this-many commits the store writes a full checkpoint instead of a delta. */
46
- export declare const MANIFEST_CHECKPOINT_INTERVAL = 32;
47
- /** Applies one stored record to a running block set (checkpoint replaces, delta mutates). */
48
- export declare function applyManifestRecord(blockIds: Set<string>, record: StoredManifestRecord): void;
49
- export interface PublishManifestInput {
50
- changedTableIds?: readonly string[];
45
+ export interface ManifestBlockRecord {
46
+ readonly blockId: string;
47
+ readonly byteLength: number;
48
+ /** CRC-32 of the exact stored payload, computed once before the first durable write. */
49
+ readonly checksum: number;
50
+ readonly addedVersion: number;
51
+ readonly removedVersion: number | null;
52
+ }
53
+ export interface ListManifestBlockPageInput {
54
+ readonly version: number;
55
+ readonly afterBlockId: string | null;
56
+ readonly limit: number;
57
+ }
58
+ export interface ListRetiredManifestBlockPageInput {
59
+ /** Includes records retired at or before this published version. */
60
+ readonly removedThroughVersion: number;
61
+ readonly afterBlockId: string | null;
62
+ readonly limit: number;
63
+ }
64
+ export interface ManifestBlockPage {
65
+ readonly records: ReadonlyArray<Pick<ManifestBlockRecord, "blockId" | "byteLength" | "checksum">>;
66
+ readonly nextCursor: string | null;
67
+ }
68
+ /** Input for adapter-internal manifest construction; not a public store mutation. */
69
+ export interface CreateManifestInput {
70
+ changedTableIds: readonly string[];
51
71
  expectedVersion: number | null;
52
- blockIds: readonly string[];
72
+ liveBlockCount: number;
73
+ liveBlockBytes: number;
53
74
  createdAt?: string;
54
75
  }
76
+ /**
77
+ * The stored manifest is the same bounded summary returned publicly. Exact block membership is
78
+ * represented once by `ManifestBlockRecord` intervals; checkpoint/delta arrays are deliberately
79
+ * absent from the v1 layout.
80
+ */
81
+ export type StoredManifestRecord = ManifestSummary;
82
+ /**
83
+ * One atomic user-table drop. The store compares both catalog and manifest revisions, derives
84
+ * every block that the table's segments still contribute to that exact manifest, publishes one
85
+ * successor without those blocks, and removes all table-owned metadata in the same durable
86
+ * step. Stored block payloads remain for lease-aware collection.
87
+ */
88
+ export interface DropTableInput {
89
+ tableId: string;
90
+ expectedTableRevision: number;
91
+ expectedManifestVersion: number | null;
92
+ /** Catalog epoch of the complete dependency proof used to authorize this drop. */
93
+ expectedCatalogEpoch: number;
94
+ committedAt: string;
95
+ }
96
+ /** One atomic column retirement; see `CatalogStore.dropTableColumn`. */
97
+ export interface DropTableColumnInput {
98
+ tableId: string;
99
+ columnId: string;
100
+ expectedTableRevision: number;
101
+ expectedManifestVersion: number | null;
102
+ /** Catalog epoch of the complete dependency proof used to authorize this drop. */
103
+ expectedCatalogEpoch: number;
104
+ committedAt: string;
105
+ }
55
106
  export declare const simpleDataTypes: readonly ["boolean", "number", "string", "datetime"];
56
107
  export type SimpleDataType = (typeof simpleDataTypes)[number];
57
108
  /** PostgreSQL logical domains layered over the four stable physical block encodings. */
@@ -124,6 +175,14 @@ export interface TableColumnRecord {
124
175
  /** Engine-generated row-addressing column; stored and indexed, never exposed as SQL schema. */
125
176
  hidden?: true;
126
177
  }
178
+ export declare const MAX_TABLE_COLUMNS = 1024;
179
+ export declare const MAX_ENUM_VALUES = 4096;
180
+ export declare const MAX_SECONDARY_INDEXES = 1024;
181
+ export declare const MAX_TABLE_TRIGGERS = 256;
182
+ export declare const MAX_TRIGGER_STATEMENTS = 256;
183
+ export declare const MAX_TABLE_CONSTRAINTS = 1024;
184
+ export declare const MAX_TABLE_RECORD_CHARACTERS = 1048576;
185
+ export declare const MAX_TABLE_RECORD_ENTRIES = 65536;
127
186
  /**
128
187
  * The single authority on which enum declarations are legal, shared by the schema DSL's
129
188
  * `column.enum()` and the engine's `createTable`: at least one value, every value a non-empty
@@ -178,18 +237,18 @@ export type SecondaryIndexDirection = "asc" | "desc";
178
237
  */
179
238
  export interface SecondaryIndexRecord {
180
239
  name: string;
181
- /** First indexed column, retained so catalogs written by the single-column release stay valid. */
240
+ /** First indexed column, repeated for constant-time scalar catalog access. */
182
241
  columnId: string;
183
- /** Ordered key columns. Missing on legacy records, where `columnId` is the complete key. */
184
- columnIds?: string[];
185
- /** Declared key direction per column. Missing legacy entries are ascending. */
186
- directions?: SecondaryIndexDirection[];
242
+ /** Ordered key columns. */
243
+ columnIds: string[];
244
+ /** Declared key direction per column. */
245
+ directions: SecondaryIndexDirection[];
187
246
  /** SQL UNIQUE: enforced through an atomic, separately namespaced membership set. */
188
247
  unique?: true;
189
248
  /** The membership set has been seeded and must be enforced, independent of postings state. */
190
249
  uniqueEnforced?: true;
191
- /** Legacy scalar terms or the prefix-free composite encoding used by newly created indexes. */
192
- termEncoding?: "tuple-v1";
250
+ /** Prefix-free composite encoding used by every v1 secondary index. */
251
+ termEncoding: "tuple-v1";
193
252
  storage: "postings-v1";
194
253
  storageColumnId: string;
195
254
  locator: "row-id" | "key-hash-v1";
@@ -199,6 +258,12 @@ export interface SecondaryIndexRecord {
199
258
  /** Manifest version the base build covers; commit deltas above it merge at read time. */
200
259
  buildFromVersion: number;
201
260
  }
261
+ /**
262
+ * Whether a secondary-index replacement changes the contract a staged writer must honor.
263
+ * Physical posting-build state is deliberately excluded: postings are only a reverified pruning
264
+ * accelerator. Index identity, key shape, and UNIQUE enforcement are structural.
265
+ */
266
+ export declare function secondaryIndexWriteContractChanged(previous: Readonly<Record<string, SecondaryIndexRecord>> | null | undefined, next: Readonly<Record<string, SecondaryIndexRecord>> | null | undefined): boolean;
202
267
  export interface TableRecord {
203
268
  id: string;
204
269
  name: string;
@@ -211,16 +276,14 @@ export interface TableRecord {
211
276
  ftsColumns?: Record<string, FtsColumnIndexRecord>;
212
277
  /** Durable secondary indexes keyed by stable index ID. */
213
278
  secondaryIndexes?: Record<string, SecondaryIndexRecord>;
214
- /** AFTER triggers on this table, fired by the committing writer inside its transaction. */
279
+ /** BEFORE/AFTER triggers on this table, fired by the committing writer in its transaction. */
215
280
  triggers?: TriggerRecord[];
216
- /** FOREIGN KEY constraints. Missing arrays are legacy single-column records. */
281
+ /** FOREIGN KEY constraints. Column tuples are always explicit, including scalar keys. */
217
282
  foreignKeys?: Array<{
218
283
  name: string;
219
- column: string;
220
- columns?: string[];
284
+ columns: string[];
221
285
  parentTable: string;
222
- parentColumn: string;
223
- parentColumns?: string[];
286
+ parentColumns: string[];
224
287
  onDelete: "restrict" | "cascade" | "set null";
225
288
  }>;
226
289
  /**
@@ -234,12 +297,10 @@ export interface TableRecord {
234
297
  }>;
235
298
  /**
236
299
  * True when `migrate()` created this table from a schema declaration, which makes the schema
237
- * authoritative over it: dropping the declaration may drop the table. A table created with
238
- * `CREATE TABLE`, or one written before this field existed, is absent-or-false and no
239
- * migration removes it — the same rule views follow, and it matters more here because a
240
- * table holds rows.
300
+ * authoritative over it: dropping the declaration may drop the table. `CREATE TABLE` records
301
+ * false explicitly.
241
302
  */
242
- managed?: boolean;
303
+ managed: boolean;
243
304
  /**
244
305
  * A view rather than a table: the query text it stands for, and no segments of its own. The
245
306
  * `columns` are the query's inferred output schema, so a view answers the same catalog
@@ -248,12 +309,10 @@ export interface TableRecord {
248
309
  view?: {
249
310
  sql: string;
250
311
  /**
251
- * True when `migrate()` created this view from a schema declaration, which makes the schema
252
- * authoritative over it: dropping the declaration drops the view. A view created with
253
- * `CREATE VIEW`, or one written before this field existed, is absent-or-false and no
254
- * migration will remove it.
312
+ * True when `migrate()` created this view from a schema declaration. `CREATE VIEW` records
313
+ * false explicitly.
255
314
  */
256
- managed?: boolean;
315
+ managed: boolean;
257
316
  };
258
317
  /** Internal catalog object backing CREATE TYPE ... AS ENUM; never exposed as a table. */
259
318
  enumType?: {
@@ -267,23 +326,36 @@ export interface TableRecord {
267
326
  columnId: string;
268
327
  };
269
328
  createdAt: string;
270
- /** Compare-and-swap revision for catalog evolution; records written before it read as 0. */
271
- revision?: number;
329
+ /** Compare-and-swap revision for catalog evolution. */
330
+ revision: number;
272
331
  }
332
+ /** Exact UTF-8 bytes used when the canonical record-wire JSON codec persists a table record. */
333
+ export declare function catalogRecordRetainedBytes(record: TableRecord): number;
334
+ export declare function manifestRecordRetainedBytes(record: Manifest): number;
335
+ /**
336
+ * Admission charge for one manifest summary, including the exact canonical tombstone bytes that
337
+ * later reclamation may add. Reserving them up front prevents quota deadlock at the byte ceiling.
338
+ */
339
+ export declare function manifestRecordRetainedReservationBytes(record: Manifest): number;
340
+ export declare function segmentRecordRetainedBytes(record: SegmentRecord): number;
341
+ /** Hard catalog cardinality/text bounds shared by engine, adapters, checkpoints, and snapshots. */
342
+ export declare function validateTableRecordBounds(record: TableRecord): void;
273
343
  /** Validates the durable identities and ownership rules of one table's secondary indexes. */
274
344
  export declare function validateSecondaryIndexes(record: TableRecord): void;
275
- /** Ordered catalog column IDs for legacy and current secondary-index records. */
345
+ /** Ordered catalog column IDs for one canonical secondary-index record. */
276
346
  export declare function secondaryIndexColumnIds(index: SecondaryIndexRecord): readonly string[];
277
- /** Declared directions for legacy and current secondary-index records. */
347
+ /** Declared directions for one canonical secondary-index record. */
278
348
  export declare function secondaryIndexDirections(index: SecondaryIndexRecord): readonly SecondaryIndexDirection[];
279
349
  /** Unique-membership namespace owned by one physical secondary index. */
280
350
  export declare function secondaryUniqueKeyNamespace(tableId: string, indexId: string): string;
281
351
  /**
282
- * One AFTER trigger: catalog-persisted on its table record so the catalog epoch makes it
352
+ * One row trigger: catalog-persisted on its table record so the catalog epoch makes it
283
353
  * visible to every tab immediately, and executed by the committing writer inside the same
284
354
  * transaction as the triggering write — the write and its derivations publish atomically.
285
355
  */
286
356
  export interface TriggerRecord {
357
+ /** Immutable durable identity. Names may be reused only after this trigger is gone. */
358
+ id: string;
287
359
  name: string;
288
360
  event: "insert" | "update" | "delete";
289
361
  /**
@@ -312,7 +384,25 @@ export declare class TableRecordConflictError extends Error {
312
384
  readonly name = "TableRecordConflictError";
313
385
  constructor(tableId: string, expectedRevision: number, actualRevision: number | null);
314
386
  }
387
+ /** A catalog drop lost a race with durable work that still owns records for the table. */
388
+ export declare class TableInUseError extends Error {
389
+ readonly tableId: string;
390
+ readonly ownerKind: "transaction" | "compaction job" | "foreign key" | "pending foreign key" | "accelerator build";
391
+ readonly ownerId: string;
392
+ readonly name = "TableInUseError";
393
+ constructor(tableId: string, ownerKind: "transaction" | "compaction job" | "foreign key" | "pending foreign key" | "accelerator build", ownerId: string);
394
+ }
395
+ /** Refuses a commit that would cross the persisted level-zero fragmentation safety ceiling. */
396
+ export declare class CompactionBacklogError extends Error {
397
+ readonly tableName: string;
398
+ readonly levelZeroSegments: number;
399
+ readonly limit: number;
400
+ readonly name = "CompactionBacklogError";
401
+ constructor(tableName: string, levelZeroSegments: number, limit: number);
402
+ }
315
403
  export type SegmentKind = "insert" | "upsert" | "update" | "delete" | "base";
404
+ /** Absolute visible level-zero ceiling; every commit that adds L0 must enforce this or lower. */
405
+ export declare const MAX_LEVEL_ZERO_SEGMENTS = 4096;
316
406
  /** Maps a contiguous segment-row run to its immutable hidden row IDs. */
317
407
  export interface RowIdSpan {
318
408
  readonly rowStart: number;
@@ -327,20 +417,17 @@ export interface SegmentRecord {
327
417
  rowIdStart: bigint;
328
418
  rowIdEndExclusive: bigint;
329
419
  columnBlockIds: Record<string, string[]>;
330
- kind?: SegmentKind;
420
+ kind: SegmentKind;
331
421
  keyColumnId?: string;
332
- /** Missing on legacy records, which are interpreted as level zero. */
333
- level?: number;
334
- /** Missing on legacy records, where commit order supplies the logical order. */
335
- logicalOrder?: number;
422
+ level: number;
423
+ logicalOrder: number;
336
424
  /**
337
425
  * Staging position inside the owning transaction. Orders segments of one commit relative
338
- * to each other (an in-scope update must fold after the in-scope insert it patches);
339
- * missing on legacy records, which never shared a key within one commit.
426
+ * to each other (an in-scope update must fold after the in-scope insert it patches).
340
427
  */
341
- commitOrdinal?: number;
342
- /** Missing on legacy insert/upsert records, which imply one contiguous row-ID span. */
343
- rowIdSpans?: readonly RowIdSpan[];
428
+ commitOrdinal: number;
429
+ /** Empty for a contiguous row-ID envelope; merged bases record every retained range. */
430
+ rowIdSpans: readonly RowIdSpan[];
344
431
  /** Monotone policy ordinal for an immutable append-row-range level-two partition. */
345
432
  readonly partitionOrdinal?: number;
346
433
  createdAt: string;
@@ -349,15 +436,82 @@ export interface RowIdRange {
349
436
  start: bigint;
350
437
  endExclusive: bigint;
351
438
  }
439
+ /** Largest persisted row ID/posting value; the wire format is canonical unsigned 64-bit. */
440
+ export declare const MAX_ROW_ID: bigint;
441
+ /** One past `MAX_ROW_ID`, allowed only for exclusive range/counter ends. */
442
+ export declare const MAX_ROW_ID_EXCLUSIVE_END: bigint;
443
+ /** Auto-increment values are exposed as exact JavaScript numbers and therefore stop here. */
444
+ export declare const MAX_AUTO_INCREMENT_VALUE: bigint;
445
+ export declare const MAX_AUTO_INCREMENT_EXCLUSIVE_END: bigint;
352
446
  export type LeaseKind = "reader" | "backup";
447
+ /** A live owner renews; an abandoned durable pin expires within one hour. */
448
+ export declare const MAX_LEASE_TTL_MS: number;
449
+ /** Durable resource ceilings; adapters sweep expired owners before atomically refusing creation. */
450
+ export declare const MAX_ACTIVE_LEASES = 4096;
451
+ export declare const MAX_ACTIVE_TEMP_OWNERS = 1024;
452
+ export declare const MAX_TEMP_RUNS_PER_OWNER = 1024;
453
+ export declare const MAX_TEMP_PAGES_PER_OWNER = 16384;
454
+ export declare const MAX_TEMP_RUNS_TOTAL = 65536;
455
+ export declare const MAX_TEMP_PAGES_TOTAL = 262144;
456
+ export declare const MAX_TEMP_BYTES_PER_OWNER: number;
457
+ export declare const MAX_TEMP_BYTES_TOTAL: number;
458
+ export declare const MAX_ACTIVE_COMPACTION_JOBS = 1024;
459
+ export declare const MAX_ACTIVE_GARBAGE_COLLECTION_JOBS = 1;
460
+ export declare const MAX_ACTIVE_UNIQUE_KEY_BUILDS = 1024;
461
+ export declare const MAX_ACTIVE_FTS_BASE_BUILDS = 128;
462
+ export declare const MAX_ACTIVE_SECONDARY_INDEX_BUILDS = 128;
463
+ export declare const MAX_ACCELERATOR_BUILD_STAGED_BYTES_TOTAL: number;
464
+ export declare const MAX_ACCELERATOR_BUILD_STAGED_ENTRIES_TOTAL = 16777216;
465
+ export declare const MAX_ACTIVE_TRANSACTIONS = 4096;
466
+ export declare const MAX_GLOBAL_STAGED_ARTIFACT_BYTES: number;
467
+ export declare const MAX_GLOBAL_STAGED_BLOCKS = 65536;
468
+ export declare const MAX_GLOBAL_STAGED_SEGMENTS = 65536;
469
+ /** Catalog enumeration remains bounded even for cold public inspection APIs. */
470
+ export declare const MAX_CATALOG_RECORDS = 4096;
471
+ /** Total canonical UTF-8 record-wire bytes retained by the durable catalog. */
472
+ export declare const MAX_CATALOG_RETAINED_BYTES: number;
473
+ export declare const MAX_MANIFEST_RECORDS = 65536;
474
+ export declare const MAX_MANIFEST_RETAINED_BYTES: number;
475
+ export declare const MAX_SEGMENT_RECORDS = 1048576;
476
+ export declare const MAX_SEGMENT_RETAINED_BYTES: number;
477
+ /** Durable diagnostic/provenance tails are pruned before admitting more terminal records. */
478
+ export declare const MAX_TERMINAL_TRANSACTION_RECORDS = 65536;
479
+ export declare const MAX_TERMINAL_COMPACTION_JOB_RECORDS = 4096;
480
+ export declare const MAX_COMPLETED_GARBAGE_COLLECTION_JOB_RECORDS = 1024;
481
+ /** An old renewable pin may not force unbounded history retention while writes continue. */
482
+ export declare const MAX_PINNED_MANIFEST_VERSION_LAG = 4096;
483
+ export declare const MAX_PINNED_RETIRED_BLOCKS = 65536;
484
+ export declare const MAX_PINNED_RETIRED_BYTES: number;
485
+ /** Total obsolete physical history is refused before it can consume an origin indefinitely. */
486
+ export declare const MAX_RETIRED_HISTORY_BYTES: number;
487
+ /** A durable resource family reached its fixed corruption/growth safety ceiling. */
488
+ export declare class StorageResourceLimitError extends Error {
489
+ readonly resource: "lease" | "temp owner" | "temp run" | "temp page" | "temporary run total" | "temporary page total" | "temp owner byte" | "temporary byte" | "compaction job" | "garbage collection job" | "unique-key build" | "full-text build" | "secondary-index build" | "accelerator build byte" | "accelerator build entry" | "transaction" | "staged artifact byte" | "staged block" | "staged segment" | "catalog record" | "catalog byte" | "manifest record" | "manifest byte" | "segment record" | "segment byte" | "terminal transaction" | "terminal compaction job" | "completed garbage collection job" | "pinned manifest version lag" | "pinned retired block" | "pinned retired byte" | "snapshot accelerator byte" | "snapshot accelerator entry" | "retired history byte";
490
+ readonly count: number;
491
+ readonly limit: number;
492
+ readonly name = "StorageResourceLimitError";
493
+ constructor(resource: "lease" | "temp owner" | "temp run" | "temp page" | "temporary run total" | "temporary page total" | "temp owner byte" | "temporary byte" | "compaction job" | "garbage collection job" | "unique-key build" | "full-text build" | "secondary-index build" | "accelerator build byte" | "accelerator build entry" | "transaction" | "staged artifact byte" | "staged block" | "staged segment" | "catalog record" | "catalog byte" | "manifest record" | "manifest byte" | "segment record" | "segment byte" | "terminal transaction" | "terminal compaction job" | "completed garbage collection job" | "pinned manifest version lag" | "pinned retired block" | "pinned retired byte" | "snapshot accelerator byte" | "snapshot accelerator entry" | "retired history byte", count: number, limit: number);
494
+ }
353
495
  export interface LeaseRecord {
354
496
  id: string;
355
497
  kind: LeaseKind;
356
498
  manifestVersion: number | null;
357
499
  ownerId: string;
500
+ /** Issuance cutoff used to prove the initial expiry is bounded. */
501
+ createdAt: string;
358
502
  expiresAt: string;
359
503
  revision: number;
360
504
  }
505
+ export interface RenewLeaseInput {
506
+ id: string;
507
+ expectedRevision: number;
508
+ /** A persisted expiry at or before this boundary is irrevocably expired. */
509
+ expiresAtCutoff: string;
510
+ expiresAt: string;
511
+ }
512
+ export interface MoveLeaseInput extends RenewLeaseInput {
513
+ manifestVersion: number | null;
514
+ }
361
515
  export declare const compactionJobStates: readonly ["planned", "running", "ready", "published", "cancelled", "aborted"];
362
516
  export type CompactionJobState = (typeof compactionJobStates)[number];
363
517
  export interface CompactionJobCursor {
@@ -501,19 +655,18 @@ export interface CompactionJobRecord {
501
655
  sourceStoredBytes: number;
502
656
  outputStoredBytes: number;
503
657
  logicalBytes: number;
504
- /** Missing on Phase 6A records, which normalize to copy-v1. */
505
- readonly rewritePlan?: CompactionRewritePlan;
658
+ readonly rewritePlan: CompactionRewritePlan;
506
659
  /** Null for copy-v1; points at the next output for rechunk-v1. */
507
- outputCursor?: CompactionOutputCursor | null;
660
+ outputCursor: CompactionOutputCursor | null;
508
661
  /** Immutable execution budget. Zero for copy-v1 jobs. */
509
- readonly memoryBudgetBytes?: number;
662
+ readonly memoryBudgetBytes: number;
510
663
  /** Immutable planner estimate. Zero for copy-v1 jobs. */
511
- readonly minimumMemoryBytes?: number;
512
- /** Immutable stored bytes from newly promoted level-zero sources. Missing on legacy jobs. */
513
- readonly level0SourceStoredBytes?: number;
514
- /** Immutable stored bytes from the retained level-one anchor. Missing on legacy jobs. */
515
- readonly anchorSourceStoredBytes?: number;
516
- /** Output partition assigned by the append-row-range L2 policy. Missing on legacy jobs. */
664
+ readonly minimumMemoryBytes: number;
665
+ /** Immutable stored bytes from newly promoted level-zero sources. */
666
+ readonly level0SourceStoredBytes: number;
667
+ /** Immutable stored bytes from the retained level-one anchor. */
668
+ readonly anchorSourceStoredBytes: number;
669
+ /** Output partition assigned by the append-row-range L2 policy. */
517
670
  readonly outputPartitionOrdinal?: number;
518
671
  /** Immutable maximum compaction output bytes per newly promoted L0 byte. */
519
672
  readonly maxWriteAmplification?: number;
@@ -527,8 +680,8 @@ export interface CompactionJobRecord {
527
680
  * write-amplification budget.
528
681
  */
529
682
  readonly priorAttemptOutputStoredBytes?: number;
530
- peakWorkingBytes?: number;
531
- outputLogicalBytes?: number;
683
+ peakWorkingBytes: number;
684
+ outputLogicalBytes: number;
532
685
  targetLevel: number;
533
686
  state: CompactionJobState;
534
687
  transactionId: string | null;
@@ -556,6 +709,16 @@ export interface CompactionJobRecordUpdate {
556
709
  updatedAt: string;
557
710
  error?: string | null;
558
711
  }
712
+ /** Every segment ID owned by a compaction job, including merge partition outputs. */
713
+ export declare function compactionOutputSegmentIds(job: Pick<CompactionJobRecord, "outputSegmentId" | "rewritePlan">): string[];
714
+ /**
715
+ * Proves that a compaction transaction stages exactly the immutable job output. This is kept in
716
+ * the storage contract (rather than only in the engine) so adapters reject forged, reordered, or
717
+ * partially journaled output before publication and while loading durable state.
718
+ */
719
+ export declare function assertCompactionOutputProvenance(job: CompactionJobRecord, table: TableRecord, transaction: Pick<TransactionRecord, "id" | "pendingBlockIds" | "pendingSegmentIds">, sourceSegments: readonly SegmentRecord[], outputSegments: readonly SegmentRecord[], options?: {
720
+ readonly allowOutputPrefix?: boolean;
721
+ }): void;
559
722
  export declare class CompactionJobConflictError extends Error {
560
723
  readonly jobId: string;
561
724
  readonly expectedRevision: number;
@@ -591,6 +754,52 @@ export interface CreateGarbageCollectionJobInput {
591
754
  /** Fixed cutoff used to decide which persisted leases protect a manifest for this job. */
592
755
  leaseCutoff: string;
593
756
  createdAt: string;
757
+ /** Present while bounded discovery is still paging durable metadata. */
758
+ discovery?: GarbageCollectionDiscovery;
759
+ }
760
+ export type GarbageCollectionDiscoveryPhase = "manifests" | "manifest-blocks" | "segments" | "transactions" | "compactions" | "complete";
761
+ export interface GarbageCollectionDiscovery {
762
+ phase: GarbageCollectionDiscoveryPhase;
763
+ currentManifestVersion: number | null;
764
+ retainAboveVersion: number;
765
+ retainAfter: number;
766
+ maxPlanningItems: number;
767
+ manifestCursor: number | null;
768
+ segmentCursor: string | null;
769
+ transactionCursor: string | null;
770
+ compactionCursor: string | null;
771
+ visitedRecords: number;
772
+ /**
773
+ * When a bounded candidate array fills, reclamation completes this job and the next job
774
+ * resumes this discovery phase instead of restarting at the beginning.
775
+ */
776
+ resumePhase?: Exclude<GarbageCollectionDiscoveryPhase, "complete"> | null;
777
+ /** Older continuation resumed only after this job first discovers newly eligible manifests. */
778
+ postManifestPhase?: Exclude<GarbageCollectionDiscoveryPhase, "complete" | "manifests"> | null;
779
+ /** Exact within-record provenance offset; every named artifact is examined at most once. */
780
+ artifactCursor?: GarbageCollectionArtifactCursor | null;
781
+ }
782
+ export interface GarbageCollectionArtifactCursor {
783
+ family: "manifest" | "transaction" | "compaction";
784
+ /** Decimal manifest version for `manifest`; durable record ID for the other families. */
785
+ recordId: string;
786
+ /** Exact lexical manifest-membership cursor; null for transaction/compaction arrays. */
787
+ blockId: string | null;
788
+ blockIndex: number;
789
+ segmentIndex: number;
790
+ }
791
+ /** Absolute per-call bound for durable maintenance candidate arrays and storage transactions. */
792
+ export declare const MAX_MAINTENANCE_BATCH_ITEMS = 1024;
793
+ export declare function boundedMaintenanceBatchItems(value: number, label: string): number;
794
+ export interface UpdateGarbageCollectionPlanningInput {
795
+ jobId: string;
796
+ expectedRevision: number;
797
+ candidateManifestVersions?: readonly number[];
798
+ candidateSegmentIds?: readonly string[];
799
+ candidateBlockIds?: readonly string[];
800
+ candidateTransactionIds?: readonly string[];
801
+ discovery: GarbageCollectionDiscovery;
802
+ updatedAt: string;
594
803
  }
595
804
  export interface GarbageCollectionJobRecord {
596
805
  id: string;
@@ -618,6 +827,8 @@ export interface GarbageCollectionJobRecord {
618
827
  leaseCutoff: string;
619
828
  createdAt: string;
620
829
  updatedAt: string;
830
+ /** Omitted only for explicitly supplied bounded candidate jobs; no discovery scan is needed. */
831
+ discovery?: GarbageCollectionDiscovery;
621
832
  }
622
833
  export interface RunGarbageCollectionStepInput {
623
834
  jobId: string;
@@ -686,9 +897,29 @@ export declare class LeaseConflictError extends Error {
686
897
  readonly name = "LeaseConflictError";
687
898
  constructor(leaseId: string, expectedRevision: number, actualRevision: number | null);
688
899
  }
900
+ /** A renewal/move cutoff reached the persisted expiry; expiry is irrevocable. */
901
+ export declare class LeaseExpiredError extends Error {
902
+ readonly leaseId: string;
903
+ readonly expiresAt: string;
904
+ readonly expiresAtCutoff: string;
905
+ readonly name = "LeaseExpiredError";
906
+ constructor(leaseId: string, expiresAt: string, expiresAtCutoff: string);
907
+ }
908
+ /** Refuses a lease release from a different durable owner. */
909
+ export declare class LeaseOwnerConflictError extends Error {
910
+ readonly leaseId: string;
911
+ readonly expectedOwnerId: string;
912
+ readonly actualOwnerId: string;
913
+ readonly name = "LeaseOwnerConflictError";
914
+ constructor(leaseId: string, expectedOwnerId: string, actualOwnerId: string);
915
+ }
689
916
  export type TransactionStatus = "active" | "committed" | "aborted";
690
917
  export interface TransactionRecord {
691
918
  id: string;
919
+ /** Stable writer identity; liveness renewals never contend on the data revision. */
920
+ ownerId: string;
921
+ /** Durable writer liveness deadline. Expired active records are atomically aborted by GC. */
922
+ expiresAt: string;
692
923
  snapshotVersion: number | null;
693
924
  pendingBlockIds: string[];
694
925
  pendingSegmentIds: string[];
@@ -697,6 +928,33 @@ export interface TransactionRecord {
697
928
  startedAt: string;
698
929
  updatedAt: string;
699
930
  committedVersion: number | null;
931
+ /**
932
+ * Structural catalog epoch captured atomically with the transaction snapshot. Every active
933
+ * transaction carries this storage-owned guard; commit rejects it if DDL changed the schema
934
+ * used to prepare the staged artifacts. Terminal records drop the guard.
935
+ */
936
+ schemaEpochGuard?: number;
937
+ /**
938
+ * Catalog record owned exclusively by this active transaction. It is invisible to catalog
939
+ * reads until commit; abort/expiry discards the reservation with the transaction.
940
+ */
941
+ pendingTable?: TableRecord;
942
+ /** Next row id for the pending table, advanced atomically as insert artifacts stage. */
943
+ pendingTableNextRowId?: bigint;
944
+ /** Catalog epoch captured atomically when the pending table was admitted. */
945
+ catalogEpochGuard?: number;
946
+ }
947
+ export interface AbortTransactionIfExpiredInput {
948
+ transactionId: string;
949
+ expectedOwnerId: string;
950
+ expiresAtCutoff: string;
951
+ updatedAt: string;
952
+ }
953
+ export interface RenewTransactionInput {
954
+ transactionId: string;
955
+ ownerId: string;
956
+ expiresAtCutoff: string;
957
+ expiresAt: string;
700
958
  }
701
959
  export interface TransactionRecordUpdate {
702
960
  snapshotVersion?: number | null;
@@ -705,10 +963,15 @@ export interface TransactionRecordUpdate {
705
963
  status?: TransactionStatus;
706
964
  updatedAt: string;
707
965
  committedVersion?: number | null;
966
+ /** Storage-owned advancement while staging rows for a pending table. */
967
+ pendingTableNextRowId?: bigint;
708
968
  }
709
969
  export interface BeginTransactionInput {
710
- /** Record to create; the store stamps `snapshotVersion` with the current manifest version. */
711
- record: Omit<TransactionRecord, "snapshotVersion">;
970
+ /**
971
+ * Record to create; the store atomically stamps both `snapshotVersion` and
972
+ * `schemaEpochGuard` from its current state.
973
+ */
974
+ record: Omit<TransactionRecord, "snapshotVersion" | "schemaEpochGuard">;
712
975
  /** Reserve this many row ids for the table in the same atomic step. */
713
976
  reserveRowIds?: {
714
977
  tableId: string;
@@ -724,6 +987,15 @@ export interface BeginTransactionInput {
724
987
  count: number;
725
988
  atLeast?: bigint;
726
989
  };
990
+ /**
991
+ * Reserves one invisible catalog record and its initial row-id state in the same atomic step.
992
+ * The expected epoch closes schema/FK races between planning and begin; commit rechecks it.
993
+ */
994
+ pendingTable?: {
995
+ record: TableRecord;
996
+ nextRowId: bigint;
997
+ expectedCatalogEpoch: number;
998
+ };
727
999
  }
728
1000
  export interface BeginTransactionResult {
729
1001
  record: TransactionRecord;
@@ -737,6 +1009,332 @@ export interface StageTransactionArtifactsInput {
737
1009
  segments: readonly SegmentRecord[];
738
1010
  updatedAt: string;
739
1011
  }
1012
+ /** Maximum immutable payloads accepted by one atomic staging/WAL operation. */
1013
+ export declare const MAX_TRANSACTION_STAGE_BLOCKS = 64;
1014
+ /** Maximum segment records accepted by one atomic staging/WAL operation. */
1015
+ export declare const MAX_TRANSACTION_STAGE_SEGMENTS = 64;
1016
+ /**
1017
+ * Maximum block bytes accepted by one atomic staging/WAL operation. The limit still admits one
1018
+ * maximum-size physical block; callers split collections of smaller blocks into bounded calls.
1019
+ */
1020
+ export declare const MAX_TRANSACTION_STAGE_BYTES: number;
1021
+ /** Durable journal ceilings prevent a forgotten or hostile transaction growing without bound. */
1022
+ export declare const MAX_TRANSACTION_PENDING_BLOCKS = 4096;
1023
+ export declare const MAX_TRANSACTION_PENDING_SEGMENTS = 4096;
1024
+ /** Storage-boundary preflight shared by staging and single-shot write implementations. */
1025
+ export declare function assertTransactionArtifactBatchLimits(blocks: readonly BlockWrite[], segments: readonly SegmentRecord[]): void;
1026
+ /** Preflight for the complete persisted journal after a bounded staging operation. */
1027
+ export declare function assertTransactionArtifactJournalLimits(pendingBlockIds: readonly string[], pendingSegmentIds: readonly string[]): void;
1028
+ /**
1029
+ * Atomically rewinds one active transaction's artifact journal to an earlier set and removes
1030
+ * exactly the artifacts that are no longer reachable. Journals are canonically sorted, so an
1031
+ * adapter validates the retained and removed lists as a duplicate-free, disjoint, exact
1032
+ * partition of its current journal before changing records or bytes.
1033
+ */
1034
+ export interface RollbackTransactionArtifactsInput {
1035
+ transactionId: string;
1036
+ expectedRevision: number;
1037
+ pendingBlockIds: readonly string[];
1038
+ pendingSegmentIds: readonly string[];
1039
+ removeBlockIds: readonly string[];
1040
+ removeSegmentIds: readonly string[];
1041
+ updatedAt: string;
1042
+ }
1043
+ export type StorageIntegrityMode = "metadata" | "full";
1044
+ export interface StorageIntegrityIssue {
1045
+ readonly code: string;
1046
+ readonly location: string;
1047
+ readonly message: string;
1048
+ }
1049
+ export interface StorageIntegrityReport {
1050
+ readonly mode: StorageIntegrityMode;
1051
+ readonly ok: boolean;
1052
+ readonly checkedRecords: number;
1053
+ readonly checkedBlocks: number;
1054
+ readonly checkedBytes: number;
1055
+ /** Total findings; `issues` itself is bounded by `maxIssues`. */
1056
+ readonly issueCount: number;
1057
+ readonly issues: readonly StorageIntegrityIssue[];
1058
+ }
1059
+ export interface StorageStats {
1060
+ readonly backend: string;
1061
+ /** Bytes reachable as current database records or payloads. */
1062
+ readonly logicalBytes: number;
1063
+ /** Actual substrate allocation where available; IndexedDB cannot report this per database. */
1064
+ readonly physicalBytes: number | null;
1065
+ readonly liveBlockCount: number;
1066
+ /** Stored payloads outside the current manifest, including staged and retired bytes. */
1067
+ readonly obsoleteBlockCount: number;
1068
+ readonly liveBlockBytes: number;
1069
+ readonly obsoleteBlockBytes: number;
1070
+ readonly temporaryBytes: number;
1071
+ readonly walBytes: number | null;
1072
+ readonly checkpointBytes: number | null;
1073
+ readonly orphanBytes: number | null;
1074
+ readonly manifestCount: number;
1075
+ readonly transactionCount: number;
1076
+ readonly segmentCount: number;
1077
+ readonly maintenance?: {
1078
+ readonly degraded: boolean;
1079
+ readonly consecutiveFailures: number;
1080
+ readonly lastError: string | null;
1081
+ readonly walLimitBytes: number | null;
1082
+ /** Durable garbage awaiting safe physical deletion, when the substrate separates the two. */
1083
+ readonly cleanupDebtBytes: number | null;
1084
+ /** Refusal/backpressure ceiling for cleanup debt, or null when the substrate has no debt. */
1085
+ readonly cleanupLimitBytes: number | null;
1086
+ };
1087
+ }
1088
+ export interface InterruptedSnapshotImport {
1089
+ readonly identity: string;
1090
+ readonly version: number;
1091
+ readonly createdAt: string;
1092
+ readonly stagedBlockCount: number;
1093
+ readonly stagedBytes: number;
1094
+ }
1095
+ export interface InterruptedSnapshotImportAbortResult {
1096
+ readonly identity: string;
1097
+ readonly removedBlockCount: number;
1098
+ readonly removedBytes: number;
1099
+ }
1100
+ /** A snapshot session is renewable but can never pin storage for more than one hour unattended. */
1101
+ export declare const MAX_SNAPSHOT_SESSION_TTL_MS: number;
1102
+ /** Snapshot v1 is an ordered bounded record stream; no database-sized collection is in header. */
1103
+ export declare const SNAPSHOT_FRAME_KINDS: readonly ["catalog-page", "segment-page", "transaction-page", "unique-page", "posting-page", "block"];
1104
+ export type SnapshotFrameKind = (typeof SNAPSHOT_FRAME_KINDS)[number];
1105
+ export declare const MAX_SNAPSHOT_FRAME_ITEMS = 1024;
1106
+ export declare const MAX_SNAPSHOT_METADATA_FRAME_BYTES: number;
1107
+ export declare const MAX_SNAPSHOT_FRAME_BATCH_ITEMS = 64;
1108
+ export declare const MAX_SNAPSHOT_METADATA_BATCH_BYTES: number;
1109
+ /** One block frame is permitted; metadata frames still use MAX_SNAPSHOT_METADATA_BATCH_BYTES. */
1110
+ export declare const MAX_SNAPSHOT_FRAME_BATCH_BYTES: number;
1111
+ /**
1112
+ * Framed restore builds accelerator generations in a disposable core before one atomic publish.
1113
+ * These aggregate ceilings keep that validation heap bounded until generations become a native
1114
+ * chunk-backed structure rather than one materialized in-memory collection.
1115
+ */
1116
+ export declare const MAX_SNAPSHOT_IMPORT_ACCELERATOR_RETAINED_BYTES: number;
1117
+ export declare const MAX_SNAPSHOT_IMPORT_ACCELERATOR_RETAINED_ENTRIES = 16777216;
1118
+ export interface SnapshotKindSummary {
1119
+ readonly frameCount: number;
1120
+ readonly itemCount: number;
1121
+ readonly storedBytes: number;
1122
+ }
1123
+ /** One table plus its durable allocation counters; memberships/postings are separate pages. */
1124
+ export interface SnapshotCatalogItem {
1125
+ readonly kind: "table";
1126
+ readonly record: TableRecord;
1127
+ readonly nextRowId: bigint;
1128
+ readonly autoIncrement: ReadonlyArray<{
1129
+ readonly columnId: string;
1130
+ readonly next: bigint;
1131
+ }>;
1132
+ }
1133
+ export interface SnapshotSegmentItem {
1134
+ readonly kind: "segment";
1135
+ readonly record: SegmentRecord;
1136
+ }
1137
+ export interface SnapshotTransactionItem {
1138
+ readonly kind: "transaction";
1139
+ readonly record: TransactionRecord;
1140
+ }
1141
+ /** Descriptor precedes this generation's chunks; tokens are globally strict lexical order. */
1142
+ export interface SnapshotUniqueGenerationItem {
1143
+ readonly kind: "unique-generation";
1144
+ readonly tableId: string;
1145
+ readonly indexId: string | null;
1146
+ readonly namespaceId: string;
1147
+ readonly generationId: string;
1148
+ readonly chunkCount: number;
1149
+ readonly tokenCount: number;
1150
+ }
1151
+ export interface SnapshotUniqueChunkItem {
1152
+ readonly kind: "unique-chunk";
1153
+ readonly namespaceId: string;
1154
+ readonly generationId: string;
1155
+ readonly ordinal: number;
1156
+ readonly keyTokens: readonly string[];
1157
+ }
1158
+ export type SnapshotUniqueItem = SnapshotUniqueGenerationItem | SnapshotUniqueChunkItem;
1159
+ /**
1160
+ * Complete canonical postings generation at the captured version. Both full-text and scalar
1161
+ * secondary accelerators use this base format; deltas are merged during bounded export, so a
1162
+ * restore never needs pre-snapshot history.
1163
+ */
1164
+ export interface SnapshotPostingGenerationItem {
1165
+ readonly kind: "posting-generation";
1166
+ readonly tableId: string;
1167
+ readonly ownerKind: "fts-column" | "secondary-index";
1168
+ readonly ownerId: string;
1169
+ readonly storageColumnId: string;
1170
+ readonly generationId: string;
1171
+ readonly coversVersion: number;
1172
+ readonly chunkCount: number;
1173
+ /** Exact safe sum of every posting frequency; secondary-index frequencies are always one. */
1174
+ readonly totalTokens: number;
1175
+ }
1176
+ export interface SnapshotPostingChunkItem {
1177
+ readonly kind: "posting-chunk";
1178
+ readonly storageColumnId: string;
1179
+ readonly generationId: string;
1180
+ readonly ordinal: number;
1181
+ readonly postings: readonly FtsPosting[];
1182
+ }
1183
+ export type SnapshotPostingItem = SnapshotPostingGenerationItem | SnapshotPostingChunkItem;
1184
+ export type SnapshotMetadataItem = SnapshotCatalogItem | SnapshotSegmentItem | SnapshotTransactionItem | SnapshotUniqueItem | SnapshotPostingItem;
1185
+ /** Modeled heap retained by one framed accelerator chunk during atomic snapshot validation. */
1186
+ export declare function snapshotAcceleratorItemRetainedUsage(item: SnapshotUniqueChunkItem | SnapshotPostingChunkItem): {
1187
+ bytes: number;
1188
+ entries: number;
1189
+ };
1190
+ /** Shared arithmetic boundary used by streaming adapters and allocation-free cap tests. */
1191
+ export declare function assertSnapshotImportAcceleratorUsage(bytes: number, entries: number): void;
1192
+ /**
1193
+ * Canonical compressed container header. It remains O(1) with database size: the six entries
1194
+ * below contain counts and byte totals only, never record descriptors, keys, or postings.
1195
+ */
1196
+ export interface SnapshotFrameStreamHeader {
1197
+ readonly formatVersion: 1;
1198
+ readonly databaseVersion: number;
1199
+ readonly createdAt: string;
1200
+ readonly kinds: Readonly<Record<SnapshotFrameKind, SnapshotKindSummary>>;
1201
+ }
1202
+ /**
1203
+ * One exact body frame. Frames are globally contiguous by `sequence` and grouped in
1204
+ * `SNAPSHOT_FRAME_KINDS` order. Within kinds, tables/segments/transactions/blocks order by ID;
1205
+ * UNIQUE generations order by namespace (descriptor, then contiguous chunk ordinals), and
1206
+ * posting generations by storageColumnId using the same descriptor/chunk rule. Metadata
1207
+ * payloads use canonical adapter encoding and contain at
1208
+ * most MAX_SNAPSHOT_FRAME_ITEMS/MAX_SNAPSHOT_METADATA_FRAME_BYTES; a block frame contains one
1209
+ * ID plus one stored block and may use MAX_STORED_BLOCK_BYTE_LENGTH. `checksum` covers the exact
1210
+ * payload. Metadata payloads use the single core-owned snapshot wire codec; adapters must not
1211
+ * substitute substrate encodings. Lost-ack replay must additionally compare the complete
1212
+ * persisted bytes.
1213
+ */
1214
+ export interface SnapshotFrame {
1215
+ readonly sequence: number;
1216
+ readonly kind: SnapshotFrameKind;
1217
+ readonly itemCount: number;
1218
+ /** Block ID for a block frame; null for core-wire-encoded metadata pages. */
1219
+ readonly key: string | null;
1220
+ readonly payload: Uint8Array;
1221
+ readonly checksum: number;
1222
+ }
1223
+ export interface SnapshotFrameFooter {
1224
+ readonly frameCount: number;
1225
+ readonly itemCount: number;
1226
+ readonly storedBytes: number;
1227
+ /** Rolling checksum over every canonical frame header and payload in sequence order. */
1228
+ readonly checksum: number;
1229
+ }
1230
+ export interface BeginSnapshotFrameExportInput {
1231
+ readonly ownerId: string;
1232
+ readonly createdAt: string;
1233
+ readonly expiresAt: string;
1234
+ }
1235
+ /**
1236
+ * Export begin atomically captures a frozen catalog/segment/transaction/accelerator generation
1237
+ * into bounded durable pages and records only an exact manifest version/cursor for blocks (it
1238
+ * must not copy block descriptors). It creates the backup lease in the same operation.
1239
+ * Catalog-only writes after begin cannot change the session.
1240
+ */
1241
+ export interface SnapshotFrameExportSession {
1242
+ readonly sessionId: string;
1243
+ readonly ownerId: string;
1244
+ readonly expiresAt: string;
1245
+ readonly header: SnapshotFrameStreamHeader;
1246
+ }
1247
+ export interface ReadSnapshotExportFrameInput {
1248
+ readonly sessionId: string;
1249
+ readonly ownerId: string;
1250
+ readonly sequence: number;
1251
+ readonly expiresAtCutoff: string;
1252
+ readonly expiresAt: string;
1253
+ }
1254
+ export interface BeginSnapshotFrameImportInput {
1255
+ readonly identity: string;
1256
+ readonly ownerId: string;
1257
+ readonly createdAt: string;
1258
+ readonly expiresAt: string;
1259
+ readonly header: SnapshotFrameStreamHeader;
1260
+ }
1261
+ export interface SnapshotFrameImportSession {
1262
+ readonly identity: string;
1263
+ readonly ownerId: string;
1264
+ readonly version: number;
1265
+ readonly createdAt: string;
1266
+ readonly expiresAt: string;
1267
+ readonly nextSequence: number;
1268
+ readonly stagedBytes: number;
1269
+ }
1270
+ export interface RenewSnapshotFrameImportInput {
1271
+ readonly identity: string;
1272
+ readonly ownerId: string;
1273
+ readonly expiresAtCutoff: string;
1274
+ readonly expiresAt: string;
1275
+ }
1276
+ export interface AppendSnapshotImportFramesInput extends RenewSnapshotFrameImportInput {
1277
+ /** Bounded contiguous frames; replayed sequences compare complete persisted bytes. */
1278
+ readonly frames: readonly SnapshotFrame[];
1279
+ }
1280
+ export interface FinishSnapshotFrameImportInput {
1281
+ readonly identity: string;
1282
+ readonly ownerId: string;
1283
+ readonly expiresAtCutoff: string;
1284
+ readonly footer: SnapshotFrameFooter;
1285
+ }
1286
+ export interface CloseSnapshotExportInput {
1287
+ readonly sessionId: string;
1288
+ readonly ownerId: string;
1289
+ }
1290
+ export interface CancelSnapshotImportInput {
1291
+ readonly identity: string;
1292
+ readonly ownerId: string;
1293
+ }
1294
+ export declare class SnapshotImportConflictError extends Error {
1295
+ readonly identity: string;
1296
+ readonly ownerId: string;
1297
+ readonly name = "SnapshotImportConflictError";
1298
+ constructor(identity: string, ownerId: string, message: string);
1299
+ }
1300
+ /**
1301
+ * Persisted bytes belong to a recognized storage family, but not to the version this reader
1302
+ * supports. This is deliberately distinct from corruption: callers must not infer that repair,
1303
+ * recreation, or deletion is safe merely because versions differ.
1304
+ */
1305
+ export declare class StorageFormatVersionError extends Error {
1306
+ readonly backend: string;
1307
+ readonly location: string;
1308
+ readonly actualVersion: number | null;
1309
+ readonly supportedVersion: number;
1310
+ readonly relation: "older" | "newer";
1311
+ readonly name = "StorageFormatVersionError";
1312
+ constructor(backend: string, location: string, actualVersion: number | null, supportedVersion: number, relation: "older" | "newer");
1313
+ }
1314
+ /** A native IndexedDB schema upgrade is waiting for another connection to close. */
1315
+ export declare class IndexedDbSchemaUpgradeBlockedError extends Error {
1316
+ readonly databaseName: string;
1317
+ readonly oldVersion: number;
1318
+ readonly requestedVersion: number;
1319
+ readonly name = "IndexedDbSchemaUpgradeBlockedError";
1320
+ constructor(databaseName: string, oldVersion: number, requestedVersion: number);
1321
+ }
1322
+ /** Persisted metadata or payload failed an adapter's fail-closed integrity checks. */
1323
+ export declare class StorageCorruptionError extends Error {
1324
+ readonly backend: string;
1325
+ readonly location: string;
1326
+ readonly name = "StorageCorruptionError";
1327
+ constructor(backend: string, location: string, message: string);
1328
+ }
1329
+ /**
1330
+ * A remote OPFS leader may have committed a mutation whose acknowledgement was lost.
1331
+ * Reconcile stable identities or revisions before retrying the named operation.
1332
+ */
1333
+ export declare class OpfsUncertainOutcomeError extends Error {
1334
+ readonly method: string;
1335
+ readonly name = "OpfsUncertainOutcomeError";
1336
+ constructor(method: string);
1337
+ }
740
1338
  /**
741
1339
  * The commit input carries only the change: added blocks are the transaction's journaled pending
742
1340
  * blocks, removals are the superseded ids. The store derives the published manifest from its
@@ -747,7 +1345,22 @@ export interface CommitTransactionInput {
747
1345
  changedTableIds?: readonly string[];
748
1346
  expectedTransactionRevision: number;
749
1347
  expectedManifestVersion: number | null;
1348
+ /**
1349
+ * Required when blocks are retired. The store atomically proves this ready compaction job is
1350
+ * owned by the transaction and that `removedBlockIds` exactly names its still-current,
1351
+ * unaliased source set. Ordinary commits cannot retire visible blocks.
1352
+ */
1353
+ compactionJobId?: string;
750
1354
  removedBlockIds?: readonly string[];
1355
+ /**
1356
+ * Atomic post-commit fragmentation ceilings. Exactly one entry is mandatory for every table
1357
+ * receiving a pending level-zero segment, no unrelated entry is allowed, and no limit may
1358
+ * exceed `MAX_LEVEL_ZERO_SEGMENTS`.
1359
+ */
1360
+ levelZeroSegmentLimits?: ReadonlyArray<{
1361
+ tableId: string;
1362
+ limit: number;
1363
+ }>;
751
1364
  /**
752
1365
  * Per-table unique-key changes, in operation order. Multi-entry commits come from atomic
753
1366
  * write scopes; entries for the same table apply sequentially, so in-scope conflicts
@@ -770,7 +1383,9 @@ export interface WriteTransactionInput extends Omit<CommitTransactionInput, "tra
770
1383
  * auto-increment reservation); its journal is extended and its revision compare-and-swapped
771
1384
  * (`TransactionRecordConflictError`). `{ record }` begins the transaction in the same step —
772
1385
  * a fresh record (revision 0, empty journal) the store pins at `expectedManifestVersion` —
773
- * so a write that needed no reservation costs one round trip in total.
1386
+ * so a write that needed no reservation costs one round trip in total. A fresh record carries
1387
+ * the `schemaEpochGuard` captured with its preparation; the store rejects a stale guard before
1388
+ * persisting any part of the write.
774
1389
  */
775
1390
  transaction: {
776
1391
  id: string;
@@ -787,12 +1402,188 @@ export interface UniqueKeyChanges {
787
1402
  requireAbsent: boolean;
788
1403
  remove?: boolean;
789
1404
  }
1405
+ /** Bounded calls used to seed an arbitrarily large UNIQUE namespace without heap materialization. */
1406
+ export declare const MAX_UNIQUE_KEY_BUILD_TOKENS_PER_CHUNK = 4096;
1407
+ export declare const MAX_UNIQUE_KEY_BUILD_CHUNK_BYTES: number;
1408
+ export declare const MAX_UNIQUE_KEY_BUILD_TTL_MS: number;
1409
+ export declare const MAX_UNIQUE_KEY_BUILD_STAGED_BYTES: number;
1410
+ export declare const MAX_UNIQUE_KEY_BUILD_STAGED_BYTES_TOTAL: number;
1411
+ export interface UniqueKeyBuildRecord {
1412
+ buildId: string;
1413
+ tableId: string;
1414
+ indexId: string;
1415
+ namespaceId: string;
1416
+ ownerId: string;
1417
+ state: "active" | "completed";
1418
+ nextOrdinal: number;
1419
+ tokenCount: number;
1420
+ retainedBytes: number;
1421
+ expiresAt: string;
1422
+ createdAt: string;
1423
+ updatedAt: string;
1424
+ completedAt?: string;
1425
+ }
1426
+ export interface BeginUniqueKeyBuildInput {
1427
+ buildId: string;
1428
+ tableId: string;
1429
+ indexId: string;
1430
+ namespaceId: string;
1431
+ ownerId: string;
1432
+ expiresAt: string;
1433
+ createdAt: string;
1434
+ }
1435
+ export interface AppendUniqueKeyBuildChunkInput {
1436
+ buildId: string;
1437
+ ownerId: string;
1438
+ expiresAtCutoff: string;
1439
+ ordinal: number;
1440
+ keyTokens: readonly string[];
1441
+ updatedAt: string;
1442
+ }
1443
+ export interface FinishUniqueKeyBuildInput {
1444
+ buildId: string;
1445
+ ownerId: string;
1446
+ expiresAtCutoff: string;
1447
+ expectedTableRevision: number;
1448
+ expectedManifestVersion: number | null;
1449
+ chunkCount: number;
1450
+ coversVersion: number;
1451
+ completedAt: string;
1452
+ }
1453
+ export interface RenewUniqueKeyBuildInput {
1454
+ buildId: string;
1455
+ ownerId: string;
1456
+ expiresAtCutoff: string;
1457
+ expiresAt: string;
1458
+ updatedAt: string;
1459
+ }
1460
+ export interface AbortUniqueKeyBuildInput {
1461
+ buildId: string;
1462
+ ownerId: string;
1463
+ expiresAtCutoff: string;
1464
+ }
1465
+ /**
1466
+ * A bounded background fold of one already-enforced UNIQUE namespace. Begin freezes the exact
1467
+ * immutable base generation and delta prefix through `throughVersion`; later commits keep
1468
+ * appending canonical `(namespace, token, version)` add/remove records to a separate ordered
1469
+ * tail. Each step resolves at most one bounded lexical token window
1470
+ * into a new immutable generation. Finish swaps the generation and drops only the frozen tail
1471
+ * prefix atomically, so no commit copies database-sized membership and readers always see an
1472
+ * exact base+tail view.
1473
+ */
1474
+ export interface UniqueKeyFoldRecord {
1475
+ foldId: string;
1476
+ tableId: string;
1477
+ indexId: string | null;
1478
+ namespaceId: string;
1479
+ ownerId: string;
1480
+ state: "active" | "completed";
1481
+ sourceGenerationId: string | null;
1482
+ outputGenerationId: string;
1483
+ throughVersion: number;
1484
+ afterToken: string | null;
1485
+ nextOrdinal: number;
1486
+ tokenCount: number;
1487
+ retainedBytes: number;
1488
+ createdAt: string;
1489
+ updatedAt: string;
1490
+ expiresAt: string;
1491
+ completedAt?: string;
1492
+ }
1493
+ export interface BeginUniqueKeyFoldInput {
1494
+ foldId: string;
1495
+ tableId: string;
1496
+ indexId: string | null;
1497
+ namespaceId: string;
1498
+ ownerId: string;
1499
+ outputGenerationId: string;
1500
+ expectedManifestVersion: number;
1501
+ createdAt: string;
1502
+ expiresAt: string;
1503
+ }
1504
+ export interface RunUniqueKeyFoldStepInput {
1505
+ foldId: string;
1506
+ ownerId: string;
1507
+ expiresAtCutoff: string;
1508
+ expiresAt: string;
1509
+ updatedAt: string;
1510
+ maxTokens: number;
1511
+ }
1512
+ export interface FinishUniqueKeyFoldInput {
1513
+ foldId: string;
1514
+ ownerId: string;
1515
+ expiresAtCutoff: string;
1516
+ expectedSourceGenerationId: string | null;
1517
+ expectedThroughVersion: number;
1518
+ chunkCount: number;
1519
+ completedAt: string;
1520
+ }
1521
+ export interface AbortUniqueKeyFoldInput {
1522
+ foldId: string;
1523
+ ownerId: string;
1524
+ expiresAtCutoff: string;
1525
+ }
1526
+ /** Validates one staged seed call before an adapter opens a transaction or WAL frame. */
1527
+ export declare function uniqueKeyBuildChunkRetainedBytes(keyTokens: readonly string[]): number;
1528
+ export declare class UniqueKeyBuildConflictError extends Error {
1529
+ readonly buildId: string;
1530
+ readonly reason: string;
1531
+ readonly name = "UniqueKeyBuildConflictError";
1532
+ constructor(buildId: string, reason: string);
1533
+ }
790
1534
  /** One term's postings within a commit delta or base chunk: parallel rowId/tf arrays. */
791
1535
  export interface FtsPosting {
792
1536
  term: string;
793
1537
  rowIds: bigint[];
794
1538
  tf: number[];
795
1539
  }
1540
+ export declare const MAX_POSTING_BUILD_TTL_MS: number;
1541
+ export interface BeginPostingBuildInput {
1542
+ tableId: string;
1543
+ columnId: string;
1544
+ buildId: string;
1545
+ ownerId: string;
1546
+ createdAt: string;
1547
+ expiresAt: string;
1548
+ }
1549
+ export interface RenewPostingBuildInput {
1550
+ tableId: string;
1551
+ columnId: string;
1552
+ buildId: string;
1553
+ ownerId: string;
1554
+ expiresAtCutoff: string;
1555
+ expiresAt: string;
1556
+ updatedAt: string;
1557
+ }
1558
+ export interface AppendPostingBuildChunkInput extends RenewPostingBuildInput {
1559
+ ordinal: number;
1560
+ chunk: readonly FtsPosting[];
1561
+ }
1562
+ export interface FinishPostingBuildInput {
1563
+ tableId: string;
1564
+ columnId: string;
1565
+ buildId: string;
1566
+ ownerId: string;
1567
+ expiresAtCutoff: string;
1568
+ coversVersion: number;
1569
+ chunkCount: number;
1570
+ totalTokens: number;
1571
+ completedAt: string;
1572
+ }
1573
+ export interface AbortPostingBuildInput {
1574
+ tableId: string;
1575
+ columnId: string;
1576
+ buildId: string;
1577
+ ownerId: string;
1578
+ expiresAtCutoff: string;
1579
+ }
1580
+ export declare class PostingBuildConflictError extends Error {
1581
+ readonly buildId: string;
1582
+ readonly ownerId: string;
1583
+ readonly reason: string;
1584
+ readonly name = "PostingBuildConflictError";
1585
+ constructor(buildId: string, ownerId: string, reason: string);
1586
+ }
796
1587
  /** One indexed column's contribution from one commit: postings for the commit's new rows. */
797
1588
  export interface FtsColumnDelta {
798
1589
  columnId: string;
@@ -811,11 +1602,37 @@ export interface FtsChanges {
811
1602
  tableId: string;
812
1603
  columns: readonly FtsColumnDelta[];
813
1604
  }
1605
+ /** In-memory and atomic-publish bounds for one transaction's accelerator/key deltas. */
1606
+ export declare const MAX_TRANSACTION_COMMIT_DELTA_BYTES: number;
1607
+ export declare const MAX_TRANSACTION_COMMIT_DELTA_ENTRIES = 1048576;
1608
+ export declare function transactionCommitDeltaRetainedBytes(uniqueKeyChanges: readonly UniqueKeyChanges[], ftsChanges: readonly FtsChanges[]): {
1609
+ bytes: number;
1610
+ entries: number;
1611
+ };
814
1612
  /** The per-term candidate row IDs a full-text index lookup returns, aligned with the query. */
815
1613
  export interface FtsCandidates {
816
1614
  /** Per requested term: ascending unique row IDs whose indexed column contained the term. */
817
1615
  rowIdsByTerm: bigint[][];
818
- }
1616
+ /** The bounded read stopped before collecting every matching row; callers must scan. */
1617
+ overflow: boolean;
1618
+ }
1619
+ /** Aggregate row-id ceiling for one postings candidate read. Overflow falls back to a scan. */
1620
+ export declare const MAX_FTS_CANDIDATE_ROW_IDS = 65536;
1621
+ /** Query-term cardinality shared by the parser and every postings adapter boundary. */
1622
+ export declare const MAX_FTS_QUERY_TERMS = 32;
1623
+ /** Retained metadata/value ceiling for one ordered postings read. Overflow falls back to a scan. */
1624
+ export declare const MAX_FTS_ORDERED_READ_BYTES: number;
1625
+ /** Hard public mutation bounds for one streamed postings-build chunk. */
1626
+ export declare const MAX_FTS_POSTINGS_PER_CHUNK = 65536;
1627
+ export declare const MAX_FTS_POSTING_ROW_IDS_PER_CHUNK = 1048576;
1628
+ export declare const MAX_FTS_POSTING_TERM_CHARACTERS = 65536;
1629
+ /** Indexed string values are bounded; non-indexed block strings retain the physical block cap. */
1630
+ export declare const MAX_INDEXED_STRING_CHARACTERS = 16384;
1631
+ /** Maximum normalized tokens retained from one indexed document. */
1632
+ export declare const MAX_FTS_TOKENS_PER_DOCUMENT = 4096;
1633
+ /** Bounded catalog/TOC cardinality. Oversized accelerators invalidate and queries scan. */
1634
+ export declare const MAX_FTS_BASE_CHUNKS = 4096;
1635
+ export declare const MAX_FTS_DELTA_CHUNKS = 128;
819
1636
  /** One exact/prefix term lookup or a lexicographic term range over a postings index. */
820
1637
  export type FtsPostingQuery = {
821
1638
  term: string;
@@ -826,6 +1643,8 @@ export type FtsPostingQuery = {
826
1643
  upper?: string;
827
1644
  upperInclusive?: boolean;
828
1645
  };
1646
+ /** Strict, bounded runtime validation shared by every adapter before any postings read. */
1647
+ export declare function validateFtsPostingQueries(value: unknown, label?: string): asserts value is readonly FtsPostingQuery[];
829
1648
  /** Whether a stored term belongs to one exact, prefix, or range lookup. */
830
1649
  export declare function ftsPostingQueryMatches(term: string, query: FtsPostingQuery): boolean;
831
1650
  /**
@@ -833,12 +1652,19 @@ export declare function ftsPostingQueryMatches(term: string, query: FtsPostingQu
833
1652
  * term-match rule (exact, or prefix as a term range) and the sorted-unique row-id shape must
834
1653
  * never drift between backends — pruning would silently differ per store.
835
1654
  */
836
- export declare function collectFtsCandidates(chunkLists: Iterable<readonly FtsPosting[]>, terms: readonly FtsPostingQuery[]): FtsCandidates;
1655
+ export declare function collectFtsCandidates(chunkLists: Iterable<readonly FtsPosting[]>, terms: readonly FtsPostingQuery[], maxRowIds?: number): FtsCandidates;
1656
+ /** Validates the fixed memory ceilings accepted by one ordered postings read. */
1657
+ export declare function validateFtsOrderedReadLimits(maxRowIds?: number, maxRetainedBytes?: number): void;
837
1658
  /**
838
1659
  * K-way merges sorted base/delta chunks into canonical term order. Only one term's row map and
839
1660
  * one cursor per chunk stay live beyond the returned postings, avoiding a second index-sized map.
840
1661
  */
841
1662
  export declare function collectFtsPostings(chunkLists: Iterable<readonly FtsPosting[]>): FtsPosting[];
1663
+ /** Bounded ordered merge; overflow deliberately returns no partial authoritative answer. */
1664
+ export declare function collectFtsPostingsBounded(chunkLists: Iterable<readonly FtsPosting[]>, maxRowIds?: number, maxRetainedBytes?: number): {
1665
+ postings: FtsPosting[];
1666
+ overflow: boolean;
1667
+ };
842
1668
  /**
843
1669
  * Shared stale-writer policy for both stores' commit steps: a commit that adds segments to a
844
1670
  * table with active full-text columns but no covering delta flips the uncovered columns to
@@ -873,6 +1699,13 @@ export declare class WriteConflictError extends Error {
873
1699
  readonly name = "WriteConflictError";
874
1700
  constructor(expectedVersion: number | null, actualVersion: number | null);
875
1701
  }
1702
+ /** Staged write artifacts were prepared against a structurally different catalog. */
1703
+ export declare class SchemaConflictError extends Error {
1704
+ readonly expectedEpoch: number;
1705
+ readonly actualEpoch: number;
1706
+ readonly name = "SchemaConflictError";
1707
+ constructor(expectedEpoch: number, actualEpoch: number);
1708
+ }
876
1709
  export declare class TransactionRecordConflictError extends Error {
877
1710
  readonly transactionId: string;
878
1711
  readonly expectedRevision: number;
@@ -890,11 +1723,45 @@ export interface TempRunPage {
890
1723
  pageIndex: number;
891
1724
  bytes: Uint8Array;
892
1725
  }
1726
+ /**
1727
+ * Atomically adopts an unpublished compaction output left by an aborted attempt. The adapter
1728
+ * verifies that `segment` exactly matches the stored immutable record apart from its owner,
1729
+ * that the old owner is the expected aborted revision, and that the replacement is the active
1730
+ * transaction linked to `compactionJobId`. It then retags the segment and moves its journal
1731
+ * membership from the old owner to the replacement while advancing both transaction revisions.
1732
+ */
1733
+ export interface AdoptAbortedSegmentInput {
1734
+ segment: SegmentRecord;
1735
+ expectedAbortedTransactionId: string;
1736
+ expectedAbortedTransactionRevision: number;
1737
+ replacementTransactionId: string;
1738
+ expectedReplacementTransactionRevision: number;
1739
+ compactionJobId: string;
1740
+ updatedAt: string;
1741
+ }
1742
+ /** Hard storage-boundary limits for one scratch-page write. */
1743
+ export declare const MAX_TEMP_RUN_PAGES_PER_BATCH = 64;
1744
+ export declare const MAX_TEMP_RUN_PAGE_BYTES: number;
1745
+ export declare const MAX_TEMP_RUN_BATCH_BYTES: number;
1746
+ /**
1747
+ * Refuses an oversized scratch write before an adapter starts a transaction or appends a WAL
1748
+ * record. Query execution splits pages and batches to these limits, so the limits bound atomic
1749
+ * storage work without limiting the total size of a spill.
1750
+ */
1751
+ export declare function assertTempRunPageBatchLimits(pages: readonly TempRunPage[]): void;
893
1752
  export interface TempOwnerRecord {
894
1753
  ownerId: string;
1754
+ createdAt: string;
895
1755
  expiresAt: string;
896
1756
  revision: number;
897
1757
  }
1758
+ export declare const MAX_TEMP_OWNER_TTL_MS: number;
1759
+ export interface RenewTempOwnerInput {
1760
+ ownerId: string;
1761
+ expectedRevision: number;
1762
+ expiresAtCutoff: string;
1763
+ expiresAt: string;
1764
+ }
898
1765
  export declare class TempOwnerConflictError extends Error {
899
1766
  readonly ownerId: string;
900
1767
  readonly expectedRevision: number;
@@ -910,14 +1777,9 @@ export declare class TempOwnerConflictError extends Error {
910
1777
  */
911
1778
  export interface QueryCatalogState {
912
1779
  manifestVersion: number | null;
913
- /**
914
- * Exact block set of manifestVersion, when resolving it was part of the same atomic read.
915
- * Lets the engine pin that already-resolved snapshot instead of reading a large manifest twice.
916
- */
917
- manifestBlockIds?: string[];
918
1780
  /** Positional per requested name; undefined where the table does not exist. */
919
1781
  tables: Array<TableRecord | undefined>;
920
- /** Current-manifest segments of the found tables, sorted by id like listSegments. */
1782
+ /** Current-manifest segments of the found tables, sorted by id. */
921
1783
  segments: SegmentRecord[];
922
1784
  /** Records for the segments' transaction ids; missing records are omitted. */
923
1785
  transactions: TransactionRecord[];
@@ -929,41 +1791,106 @@ export interface QueryCatalogState {
929
1791
  catalogEpoch?: number;
930
1792
  }
931
1793
  /**
932
- * The two change counters a reader needs to know whether anything it may have cached is
933
- * still current, read together in one atomic storage transaction. `manifestVersion` moves on
1794
+ * The change counters a reader or writer needs, read together in one atomic storage
1795
+ * transaction. `manifestVersion` moves on
934
1796
  * every data commit. `catalogEpoch` moves on every catalog mutation — table creation, table
935
1797
  * record updates (schema migration, full-text index stamps), and every manifest publish —
936
1798
  * so an unchanged epoch proves cached catalog state is byte-identical to a fresh read.
937
1799
  * Physical garbage collection does not move the epoch: it only deletes records that are
938
1800
  * already invisible at every leased version, so cached state stays result-equivalent.
1801
+ * `schemaEpoch` is deliberately narrower: it moves only for structural catalog changes, so
1802
+ * writers can reject old-schema artifacts without making concurrent ordinary writes conflict.
939
1803
  */
940
1804
  export interface CatalogProbe {
941
1805
  manifestVersion: number | null;
942
1806
  catalogEpoch: number;
1807
+ /** Advances only when structural catalog state changes, never for an ordinary data commit. */
1808
+ schemaEpoch: number;
1809
+ }
1810
+ /** Optional serializable guard for a catalog mutation whose proof read multiple records. */
1811
+ export interface CatalogMutationOptions {
1812
+ /** Reject unless the complete catalog is still at this epoch. */
1813
+ expectedCatalogEpoch?: number;
1814
+ }
1815
+ /** Atomic replacement fields for one catalog record. */
1816
+ export interface TableRecordUpdate extends CatalogMutationOptions {
1817
+ columns?: TableColumnRecord[];
1818
+ /** Replaces the full-text index state map; null clears it. */
1819
+ ftsColumns?: Record<string, FtsColumnIndexRecord> | null;
1820
+ /** Replaces the secondary-index state map; null clears it. */
1821
+ secondaryIndexes?: Record<string, SecondaryIndexRecord> | null;
1822
+ /** Additional manifest CAS used when publishing a UNIQUE build from a stable snapshot. */
1823
+ expectedManifestVersion?: {
1824
+ value: number | null;
1825
+ };
1826
+ /** Atomically seeds one secondary UNIQUE membership namespace while activating enforcement. */
1827
+ uniqueKeySeed?: {
1828
+ namespaceId: string;
1829
+ keyTokens: readonly string[];
1830
+ };
1831
+ /** Atomically advances a newly declared auto-increment column's durable counter. */
1832
+ autoIncrementSeed?: {
1833
+ columnId: string;
1834
+ atLeast: bigint;
1835
+ };
1836
+ /** Replaces the trigger list; null clears it. */
1837
+ triggers?: TriggerRecord[] | null;
1838
+ /** Replaces a view definition in place; null converts the record back to a table. */
1839
+ view?: TableRecord["view"] | null;
943
1840
  }
944
1841
  /**
945
1842
  * Bulk payload storage: immutable, opaque byte blobs keyed by structured ids.
946
1843
  *
947
- * Blocks are write-once. `addBlock`/`addBlocks` MUST reject an id that already exists, and a
948
- * batch containing any duplicate MUST write nothing at all. Ids contain `/` separators
1844
+ * Blocks are written only through transaction staging, which creates their durable provenance
1845
+ * in the same atomic step and rejects duplicate ids without a partial write. Ids contain `/` separators
949
1846
  * (`table/<uuid>/segment/<uuid>/part/000001`) and sort lexically; treat them as opaque keys.
950
1847
  * Reads MUST return bytes the caller may mutate freely (a fresh copy or freshly deserialized
951
1848
  * buffer), and writes MUST NOT alias the caller's buffer — the engine may reuse it.
952
1849
  *
953
- * Published blocks are retired by superseding them in a commit, never by `removeBlock`; the
954
- * lease-aware collector deletes the bytes once no reader can be pinned to them.
1850
+ * Published blocks are retired by superseding them in a commit; only the store's atomic
1851
+ * lease-aware collection step can physically delete payloads once no reader can reach them.
955
1852
  */
1853
+ /** Maximum manifest-membership ids accepted by one storage call. */
1854
+ export declare const MAX_MANIFEST_BLOCK_PRESENCE_IDS = 1024;
1855
+ /** Maximum UTF-16 code units in any opaque storage identity. */
1856
+ export declare const MAX_STORAGE_ID_CHARACTERS = 1024;
1857
+ /** Maximum UTF-16 code units in a persisted catalog name. */
1858
+ export declare const MAX_CATALOG_NAME_CHARACTERS = 1024;
1859
+ /** Public adapter database-name bound; names commonly become substrate keys or path segments. */
1860
+ export declare const MAX_STORAGE_DATABASE_NAME_CHARACTERS = 256;
1861
+ /** Maximum positional items accepted by one public bulk-read operation. */
1862
+ export declare const MAX_STORAGE_BULK_READ_ITEMS = 1024;
1863
+ /** Maximum aggregate payload bytes returned by one getBlocks call. */
1864
+ export declare const MAX_BLOCK_READ_BATCH_BYTES: number;
1865
+ export declare class BlockReadBatchTooLargeError extends RangeError {
1866
+ readonly requestedBytes: number;
1867
+ readonly limitBytes: number;
1868
+ readonly name = "BlockReadBatchTooLargeError";
1869
+ constructor(requestedBytes: number, limitBytes?: number);
1870
+ }
1871
+ export declare function assertStorageBulkReadItems(items: readonly unknown[], label: string): void;
1872
+ export declare function validateStorageId(value: unknown, label?: string): string;
1873
+ export declare function validateCatalogName(value: unknown, label?: string): string;
1874
+ export declare function validateStorageDatabaseName(value: unknown): string;
956
1875
  export interface BlockPayloadStore {
957
- addBlock(id: string, bytes: Uint8Array): Promise<void>;
958
- /** All or nothing: an internal or existing duplicate id fails the whole batch unwritten. */
959
- addBlocks(blocks: readonly BlockWrite[]): Promise<void>;
960
1876
  getBlock(id: string): Promise<Uint8Array | undefined>;
961
1877
  /** Positional per requested id; undefined where a block does not exist. */
962
1878
  getBlocks(ids: readonly string[]): Promise<Array<Uint8Array | undefined>>;
963
- /** Deleting a missing block is not an error. */
964
- removeBlock(id: string): Promise<void>;
965
- /** Every stored block id, sorted lexically. A cold path tools and tests, not queries. */
966
- listBlockIds(): Promise<string[]>;
1879
+ /**
1880
+ * Reads one block only when it belongs to the exact readable manifest version. The membership
1881
+ * check and payload read are one storage operation: callers must never fetch a block first and
1882
+ * then race a separate manifest check. A missing/pruned manifest or non-member id returns
1883
+ * undefined. A readable member whose payload is missing or unreadable is corruption and MUST
1884
+ * throw StorageCorruptionError. Reader leases keep a selected version from being pruned while
1885
+ * it is in use.
1886
+ */
1887
+ readManifestBlock(version: number | null, id: string): Promise<Uint8Array | undefined>;
1888
+ /**
1889
+ * Positional membership in the exact readable manifest version. Implementations must bound the
1890
+ * input at MAX_MANIFEST_BLOCK_PRESENCE_IDS; callers window larger sets. A missing/pruned
1891
+ * manifest returns false for every id.
1892
+ */
1893
+ hasManifestBlocks(version: number | null, ids: readonly string[]): Promise<boolean[]>;
967
1894
  }
968
1895
  /**
969
1896
  * The table catalog: schema records, the counters that keep writes collision-free, and
@@ -978,48 +1905,40 @@ export interface BlockPayloadStore {
978
1905
  */
979
1906
  export interface CatalogStore {
980
1907
  /** Fails on a duplicate id or name. Advances the catalog epoch. */
981
- addTable(record: TableRecord): Promise<void>;
1908
+ addTable(record: TableRecord, options?: CatalogMutationOptions): Promise<void>;
982
1909
  getTable(id: string): Promise<TableRecord | undefined>;
983
1910
  getTableByName(name: string): Promise<TableRecord | undefined>;
984
- /** Sorted by table name. */
1911
+ /** Sorted by table name; MAX_CATALOG_RECORDS makes this array globally bounded. */
985
1912
  listTables(): Promise<TableRecord[]>;
986
1913
  /**
987
1914
  * Replaces catalog metadata atomically. When `columns` removes a column, the same operation
988
1915
  * must also discard that column's full-text catalog entry, base chunks, and commit deltas.
989
1916
  */
990
- updateTable(id: string, expectedRevision: number, update: {
991
- columns?: TableColumnRecord[];
992
- /** Replaces the full-text index state map; null clears it. */
993
- ftsColumns?: Record<string, FtsColumnIndexRecord> | null;
994
- /** Replaces the secondary-index state map; null clears it. */
995
- secondaryIndexes?: Record<string, SecondaryIndexRecord> | null;
996
- /** Additional manifest CAS used when publishing a UNIQUE build from a stable snapshot. */
997
- expectedManifestVersion?: {
998
- value: number | null;
999
- };
1000
- /**
1001
- * Atomically seeds one secondary UNIQUE membership namespace while publishing the catalog
1002
- * record that activates enforcement. Duplicate tokens reject the entire operation.
1003
- */
1004
- uniqueKeySeed?: {
1005
- namespaceId: string;
1006
- keyTokens: readonly string[];
1007
- };
1008
- /** Replaces the trigger list; null clears it. */
1009
- triggers?: TriggerRecord[] | null;
1010
- }): Promise<TableRecord>;
1011
- /**
1012
- * Removes a table's catalog record together with everything else keyed to it: its segments,
1013
- * its full-text base chunks and commit deltas, its unique-key membership, and its row-id and
1014
- * autoincrement counters. One step, so a crash cannot leave a segment pointing at a table
1015
- * that no longer exists. Advances the catalog epoch, and fails with a
1016
- * `TableRecordConflictError` on a revision mismatch, like `updateTable`.
1017
- *
1018
- * The table's blocks are the caller's business: they are retired by superseding them in a
1019
- * commit, which leaves the bytes for the lease-aware collector rather than deleting data a
1020
- * pinned reader may still be reading.
1917
+ updateTable(id: string, expectedRevision: number, update: TableRecordUpdate): Promise<TableRecord>;
1918
+ /**
1919
+ * Removes a segment-free catalog object such as a view. Must refuse when any segment names the
1920
+ * record; populated tables use `dropTable`, whose manifest retirement and catalog removal are
1921
+ * inseparable. Advances the catalog epoch and fails with `TableRecordConflictError` on a stale
1922
+ * revision.
1021
1923
  */
1022
- removeTable(id: string, expectedRevision: number): Promise<void>;
1924
+ removeTable(id: string, expectedRevision: number, options?: CatalogMutationOptions): Promise<void>;
1925
+ /**
1926
+ * Atomically retires all live table blocks, removes the catalog/segments/counters/indexes,
1927
+ * and publishes the successor manifest. A table revision mismatch throws
1928
+ * `TableRecordConflictError`; a manifest mismatch throws `WriteConflictError`; an active
1929
+ * transaction or nonterminal compaction owner throws `TableInUseError`. Any rejection leaves
1930
+ * the catalog, manifest, jobs, transaction journals, segments, counters, indexes, and payloads
1931
+ * unchanged. A success returns the one manifest summary it published.
1932
+ */
1933
+ dropTable(input: DropTableInput): Promise<ManifestSummary>;
1934
+ /**
1935
+ * Atomically removes one safe non-key column from catalog metadata and every table segment,
1936
+ * removes its posting accelerator, and publishes a successor retiring only removed column
1937
+ * blocks that no remaining segment reference owns. CAS/busy errors match `dropTable`; any
1938
+ * rejection changes nothing, payload bytes stay available to pinned historical readers, and
1939
+ * success returns the exactly one published manifest summary.
1940
+ */
1941
+ dropTableColumn(input: DropTableColumnInput): Promise<ManifestSummary>;
1023
1942
  reserveRowIds(tableId: string, count: number): Promise<RowIdRange>;
1024
1943
  /**
1025
1944
  * Atomically reserves `count` auto-increment values for the column, first bumping the
@@ -1028,6 +1947,36 @@ export interface CatalogStore {
1028
1947
  reserveAutoIncrement(tableId: string, columnId: string, count: number, atLeast?: bigint): Promise<RowIdRange>;
1029
1948
  /** Which of the given key tokens already exist for the table, deduplicated and sorted. */
1030
1949
  getExistingUniqueKeys(tableId: string, keyTokens: readonly string[]): Promise<string[]>;
1950
+ /**
1951
+ * Starts or takes over the exact catalog-owned UNIQUE builder. One active session per namespace
1952
+ * and MAX_ACTIVE_UNIQUE_KEY_BUILDS globally are enforced atomically. Repeating the same active
1953
+ * owner/header is idempotent; an expired owner is irrevocably replaced with an empty stage.
1954
+ */
1955
+ beginUniqueKeyBuild(input: BeginUniqueKeyBuildInput): Promise<UniqueKeyBuildRecord>;
1956
+ getUniqueKeyBuild(buildId: string): Promise<UniqueKeyBuildRecord | undefined>;
1957
+ /** Refuses at/past the cutoff, so a dead builder can never be resurrected. */
1958
+ renewUniqueKeyBuild(input: RenewUniqueKeyBuildInput): Promise<UniqueKeyBuildRecord>;
1959
+ /**
1960
+ * Appends the exact next ordinal. Same-ordinal lost-ack replay compares the persisted tokens
1961
+ * byte-for-byte; a changed replay or duplicate within/across chunks refuses without mutation.
1962
+ */
1963
+ appendUniqueKeyBuildChunk(input: AppendUniqueKeyBuildChunkInput): Promise<UniqueKeyBuildRecord>;
1964
+ /**
1965
+ * Atomically verifies the exact building catalog owner, table+manifest CAS, completed chunk
1966
+ * count, and then publishes both the durable membership namespace and ready catalog state.
1967
+ * A same-build completed retry is a no-op; no catalog/membership intermediate state exists.
1968
+ */
1969
+ finishUniqueKeyBuild(input: FinishUniqueKeyBuildInput): Promise<TableRecord>;
1970
+ /** Exact owner may abort; after expiry any caller may reclaim. Returns false when absent. */
1971
+ abortUniqueKeyBuild(input: AbortUniqueKeyBuildInput): Promise<boolean>;
1972
+ /** Starts or takes over a bounded base+tail membership fold; see `UniqueKeyFoldRecord`. */
1973
+ beginUniqueKeyFold?(input: BeginUniqueKeyFoldInput): Promise<UniqueKeyFoldRecord>;
1974
+ getUniqueKeyFold?(foldId: string): Promise<UniqueKeyFoldRecord | undefined>;
1975
+ /** Advances at most `maxTokens` lexical keys and renews the exact live owner. */
1976
+ runUniqueKeyFoldStep?(input: RunUniqueKeyFoldStepInput): Promise<UniqueKeyFoldRecord>;
1977
+ /** Atomically promotes the output generation and removes only the frozen delta prefix. */
1978
+ finishUniqueKeyFold?(input: FinishUniqueKeyFoldInput): Promise<UniqueKeyFoldRecord>;
1979
+ abortUniqueKeyFold?(input: AbortUniqueKeyFoldInput): Promise<boolean>;
1031
1980
  }
1032
1981
  /**
1033
1982
  * Versions and visibility: manifests (the set of live block ids at each version), segments
@@ -1036,12 +1985,14 @@ export interface CatalogStore {
1036
1985
  *
1037
1986
  * This is where the whole consistency story lives. `commitTransaction` is THE atomic step of
1038
1987
  * the database: in one durable, all-or-nothing action it validates the transaction record's
1039
- * revision and active status, compare-and-swaps the current manifest version, publishes the
1988
+ * revision and active status, verifies its structural `schemaEpochGuard`, compare-and-swaps the
1989
+ * current manifest version, publishes the
1040
1990
  * next manifest, finalizes the transaction's segments, applies unique-key changes (failing
1041
1991
  * with `UniqueKeyConflictError` on a `requireAbsent` violation), applies full-text deltas,
1042
1992
  * and flips the transaction record to committed. No intermediate state may ever be
1043
- * observable, including after a crash at any moment. Version conflicts MUST be
1044
- * `WriteConflictError` and revision conflicts `TransactionRecordConflictError` the exact
1993
+ * observable, including after a crash at any moment. Schema conflicts MUST be
1994
+ * `SchemaConflictError`, version conflicts `WriteConflictError`, and revision conflicts
1995
+ * `TransactionRecordConflictError` — the exact
1045
1996
  * exported classes; the engine's retry and rebase loops match on them, and the worker client
1046
1997
  * rehydrates them by name across the thread boundary.
1047
1998
  */
@@ -1050,21 +2001,30 @@ export interface TransactionStore {
1050
2001
  /** The current version alone, without materializing the manifest's block list. */
1051
2002
  getCurrentManifestVersion(): Promise<number | null>;
1052
2003
  getManifest(version: number): Promise<Manifest | undefined>;
1053
- listManifests(): Promise<Manifest[]>;
2004
+ /**
2005
+ * Exact ID-ordered membership at one historically published version. Implementations resolve
2006
+ * this from interval provenance without reconstructing or cloning a complete manifest. It must
2007
+ * remain pageable after the summary tombstone is removed so bounded maintenance can drain the
2008
+ * retired payload interval; callers separately use `getManifest`/leases to authorize reads.
2009
+ * A version newer than the current database returns an empty page. `limit` is storage-bounded.
2010
+ */
2011
+ listManifestBlockPage(input: ListManifestBlockPageInput): Promise<ManifestBlockPage>;
2012
+ /**
2013
+ * ID-ordered retired provenance, independent of bounded manifest-summary tombstones. This is
2014
+ * the durable garbage-discovery index: every record whose non-null `removedVersion` is at most
2015
+ * `removedThroughVersion` appears exactly once in a full cursor traversal.
2016
+ */
2017
+ listRetiredManifestBlockPage(input: ListRetiredManifestBlockPageInput): Promise<ManifestBlockPage>;
1054
2018
  listManifestPage(afterVersion: number | null, limit: number): Promise<StoragePage<Manifest, number>>;
1055
2019
  /**
1056
- * Publishes the next version directly from a full block-id list, compare-and-swapping on
1057
- * `expectedVersion` (`WriteConflictError` on a mismatch). Every id must exist. The engine
1058
- * commits through transactions instead; this is the lower-level tool underneath.
2020
+ * Fails on a duplicate id; the record's snapshot version and pending ids must be valid. When
2021
+ * an active record omits `schemaEpochGuard`, the store stamps its current structural epoch in
2022
+ * the same atomic creation step. A supplied stale guard throws `SchemaConflictError`.
1059
2023
  */
1060
- publishManifest(input: PublishManifestInput): Promise<Manifest>;
1061
- /** Fails on a duplicate id; the record's snapshot version and pending ids must be valid. */
1062
2024
  createTransaction(record: TransactionRecord): Promise<void>;
1063
2025
  getTransaction(id: string): Promise<TransactionRecord | undefined>;
1064
2026
  /** Positional per requested id; undefined where a record does not exist. */
1065
2027
  getTransactions(ids: readonly string[]): Promise<Array<TransactionRecord | undefined>>;
1066
- /** Sorted by startedAt, then id. */
1067
- listTransactions(): Promise<TransactionRecord[]>;
1068
2028
  listTransactionPage(afterId: string | null, limit: number): Promise<StoragePage<TransactionRecord, string>>;
1069
2029
  /**
1070
2030
  * Compare-and-swap on `expectedRevision` (`TransactionRecordConflictError` on a mismatch).
@@ -1072,15 +2032,35 @@ export interface TransactionStore {
1072
2032
  * committed.
1073
2033
  */
1074
2034
  updateTransaction(id: string, expectedRevision: number, update: TransactionRecordUpdate): Promise<TransactionRecord>;
2035
+ /**
2036
+ * Extends a matching active writer's durable deadline without changing its data revision.
2037
+ * Returns false after ownership is lost or the transaction becomes terminal.
2038
+ */
2039
+ renewTransaction(input: RenewTransactionInput): Promise<boolean>;
2040
+ /**
2041
+ * Atomically aborts an active transaction only when both its owner still matches and its
2042
+ * durable deadline is at or before the cutoff. A concurrent renewal wins by returning
2043
+ * undefined; a successful abort preserves artifact provenance and advances the data revision.
2044
+ */
2045
+ abortTransactionIfExpired(input: AbortTransactionIfExpiredInput): Promise<TransactionRecord | undefined>;
1075
2046
  /** Publishes the next version; the summary omits the block list, which commits never need. */
1076
2047
  commitTransaction(input: CommitTransactionInput): Promise<ManifestSummary>;
1077
- addSegment(record: SegmentRecord): Promise<void>;
1078
2048
  getSegment(id: string): Promise<SegmentRecord | undefined>;
1079
- /** Sorted by id; `tableId` filters. */
1080
- listSegments(tableId?: string): Promise<SegmentRecord[]>;
1081
2049
  /** Sorted by id, after the exclusive cursor; bounded for maintenance scans. */
1082
2050
  listSegmentPage(afterId: string | null, limit: number): Promise<StoragePage<SegmentRecord, string>>;
1083
- removeSegment(id: string): Promise<void>;
2051
+ /** Table-indexed ID page; query/compaction paths never scan unrelated segment history. */
2052
+ listTableSegmentPage(tableId: string, afterId: string | null, limit: number): Promise<StoragePage<SegmentRecord, string>>;
2053
+ /**
2054
+ * Removes an unpublished segment left by the exact aborted owner and unjournals it from that
2055
+ * transaction in the same atomic step. Returns false when the segment is already absent.
2056
+ * Any owner mismatch, non-aborted/missing owner, readable-manifest block reference, active
2057
+ * transaction pending-segment reference, or nonterminal compaction reference rejects without
2058
+ * mutation. A block alias in another journal is safe: this operation deletes segment metadata,
2059
+ * never payload bytes.
2060
+ */
2061
+ removeAbortedSegment(id: string, expectedTransactionId: string): Promise<boolean>;
2062
+ /** See `AdoptAbortedSegmentInput`; returns the updated replacement transaction journal. */
2063
+ adoptAbortedSegment(input: AdoptAbortedSegmentInput): Promise<TransactionRecord>;
1084
2064
  }
1085
2065
  /**
1086
2066
  * Reader pins. A lease is a stored record with an expiry that protects one manifest version
@@ -1090,15 +2070,28 @@ export interface TransactionStore {
1090
2070
  * tabs safe.
1091
2071
  */
1092
2072
  export interface LeaseStore {
1093
- /** Fails on a duplicate id, or when the pinned version's manifest is unavailable. */
2073
+ /**
2074
+ * Fails on a duplicate id or unavailable manifest. Before enforcing MAX_ACTIVE_LEASES, an
2075
+ * adapter sweeps a bounded expired page; creation and the final count check are atomic.
2076
+ */
1094
2077
  createLease(record: LeaseRecord): Promise<void>;
1095
2078
  getLease(id: string): Promise<LeaseRecord | undefined>;
1096
- /** Sorted by id. */
2079
+ /** Sorted by id; MAX_ACTIVE_LEASES makes this array globally bounded. */
1097
2080
  listLeases(): Promise<LeaseRecord[]>;
1098
- renewLease(id: string, expectedRevision: number, expiresAt: string): Promise<LeaseRecord>;
2081
+ /** Bounded expiry/id-ordered page containing only records expired at the fixed cutoff. */
2082
+ listExpiredLeasePage(expiresAtCutoff: string, afterCursor: string | null, limit: number): Promise<StoragePage<LeaseRecord, string>>;
2083
+ renewLease(input: RenewLeaseInput): Promise<LeaseRecord>;
1099
2084
  /** True when removed; false (without removing) when the lease has not yet expired. */
1100
2085
  removeLeaseIfExpired(id: string, expectedRevision: number, expiresAtCutoff: string): Promise<boolean>;
1101
- removeLease(id: string): Promise<void>;
2086
+ /**
2087
+ * Releases an existing lease only for its durable owner. A concurrent same-owner renewal may
2088
+ * still be removed safely; a different owner throws `LeaseOwnerConflictError` without change.
2089
+ * Returns false when the lease is already absent.
2090
+ */
2091
+ removeLease(input: {
2092
+ id: string;
2093
+ ownerId: string;
2094
+ }): Promise<boolean>;
1102
2095
  }
1103
2096
  /**
1104
2097
  * Background-maintenance bookkeeping: the resumable job records that let compaction and
@@ -1114,9 +2107,16 @@ export interface LeaseStore {
1114
2107
  * needs.
1115
2108
  */
1116
2109
  export interface MaintenanceStore {
2110
+ /**
2111
+ * Atomically enforces one nonterminal job per table and MAX_ACTIVE_COMPACTION_JOBS globally;
2112
+ * terminal history does not count and is pruned separately.
2113
+ */
1117
2114
  createCompactionJob(record: CompactionJobRecord): Promise<void>;
1118
2115
  getCompactionJob(id: string): Promise<CompactionJobRecord | undefined>;
1119
- /** Sorted by createdAt, then id; `tableId` filters. */
2116
+ /**
2117
+ * Sorted by createdAt, then id; `tableId` filters. The returned array is bounded by the
2118
+ * enforced active and terminal compaction-job record quotas above.
2119
+ */
1120
2120
  listCompactionJobs(tableId?: string): Promise<CompactionJobRecord[]>;
1121
2121
  listCompactionJobPage(afterId: string | null, limit: number): Promise<StoragePage<CompactionJobRecord, string>>;
1122
2122
  updateCompactionJob(id: string, expectedRevision: number, update: CompactionJobRecordUpdate): Promise<CompactionJobRecord>;
@@ -1126,19 +2126,33 @@ export interface MaintenanceStore {
1126
2126
  * cancelled and its active transaction aborted — atomically.
1127
2127
  */
1128
2128
  cancelCompactionJob(id: string, expectedRevision: number, cancelledAt: string): Promise<CompactionJobRecord>;
1129
- removeCompactionJob(id: string): Promise<void>;
2129
+ /**
2130
+ * Removes only published, cancelled, or aborted diagnostics. Returns false when missing or
2131
+ * when an existing source/output block or segment would lose its last durable provenance/root;
2132
+ * collection can remove that payload first. Nonterminal removal throws without mutation.
2133
+ */
2134
+ removeCompactionJob(id: string): Promise<boolean>;
1130
2135
  /** Validates candidate provenance against persisted records before accepting the job. */
1131
2136
  createGarbageCollectionJob(input: CreateGarbageCollectionJobInput): Promise<GarbageCollectionJobRecord>;
2137
+ /** CAS-appends one bounded discovery page; no payload or catalog data is changed. */
2138
+ updateGarbageCollectionPlanning(input: UpdateGarbageCollectionPlanningInput): Promise<GarbageCollectionJobRecord>;
1132
2139
  getGarbageCollectionJob(id: string): Promise<GarbageCollectionJobRecord | undefined>;
1133
- /** Sorted by createdAt, then id. */
2140
+ /**
2141
+ * Sorted by createdAt, then id. The returned array is bounded by the enforced active and
2142
+ * completed garbage-collection record quotas above.
2143
+ */
1134
2144
  listGarbageCollectionJobs(): Promise<GarbageCollectionJobRecord[]>;
2145
+ /** Bounded page sorted by id; maintenance paths use this instead of materializing history. */
2146
+ listGarbageCollectionJobPage(afterId: string | null, limit: number): Promise<StoragePage<GarbageCollectionJobRecord, string>>;
1135
2147
  runGarbageCollectionStep(input: RunGarbageCollectionStepInput): Promise<GarbageCollectionStepResult>;
1136
2148
  /**
1137
- * Deletes obsolete tombstones only after their garbage blocks are gone, while retaining the
1138
- * checkpoint prefix readable deltas need. A tombstone is the collector's durable discovery
1139
- * record between bounded passes.
2149
+ * Removes at most `maxItems` obsolete summary tombstones while retaining the checkpoint prefix
2150
+ * readable deltas need. Retired block provenance, not the summary, is durable garbage
2151
+ * discovery; `runGarbageCollectionStep` removes each payload and its provenance atomically, so
2152
+ * deleting a summary cannot strand an undiscoverable block.
1140
2153
  */
1141
- removePrunedManifestRecords(): Promise<number>;
2154
+ removePrunedManifestRecords(maxItems: number): Promise<number>;
2155
+ /** Removes only a completed diagnostic; planned/running collection is refused. */
1142
2156
  removeGarbageCollectionJob(id: string): Promise<void>;
1143
2157
  }
1144
2158
  /**
@@ -1149,6 +2163,10 @@ export interface MaintenanceStore {
1149
2163
  */
1150
2164
  export interface FtsIndexStore {
1151
2165
  /** Removes every base chunk and commit delta owned by one column. */
2166
+ /**
2167
+ * Removes posting storage only when the current catalog no longer owns it as a ready/building
2168
+ * accelerator (absent or invalid is safe). Refusal leaves catalog and postings unchanged.
2169
+ */
1152
2170
  removeFtsColumn(tableId: string, columnId: string): Promise<void>;
1153
2171
  /**
1154
2172
  * Replaces one column's full-text base chunks (term-range partitioned, term-sorted within
@@ -1171,7 +2189,7 @@ export interface FtsIndexStore {
1171
2189
  * needing snapshot-exact statistics must detect `coversVersion > upToVersion` and fall
1172
2190
  * back (candidates stay a safe superset either way).
1173
2191
  */
1174
- readFtsCandidates(tableId: string, columnId: string, terms: readonly FtsPostingQuery[], upToVersion: number): Promise<FtsCandidates & {
2192
+ readFtsCandidates(tableId: string, columnId: string, terms: readonly FtsPostingQuery[], upToVersion: number, maxRowIds?: number): Promise<FtsCandidates & {
1175
2193
  deltaChunkCount: number;
1176
2194
  totalTokens: number;
1177
2195
  coversVersion: number;
@@ -1181,8 +2199,10 @@ export interface FtsIndexStore {
1181
2199
  * Canonical term/posting order from the same snapshot-bounded base-plus-delta view. This is a
1182
2200
  * materialized cold path for ordered and covering scans; callers must not retain the result.
1183
2201
  */
1184
- readFtsPostings(tableId: string, columnId: string, upToVersion: number): Promise<{
2202
+ readFtsPostings(tableId: string, columnId: string, upToVersion: number, maxRowIds?: number, maxRetainedBytes?: number): Promise<{
1185
2203
  postings: FtsPosting[];
2204
+ /** The bounded merge stopped early; callers must scan and may rebuild the accelerator. */
2205
+ overflow: boolean;
1186
2206
  deltaChunkCount: number;
1187
2207
  coversVersion: number;
1188
2208
  hasBase: boolean;
@@ -1195,6 +2215,7 @@ export interface FtsIndexStore {
1195
2215
  * records are real records with the usual compare-and-swap (`TempOwnerConflictError`).
1196
2216
  */
1197
2217
  export interface TempSpillStore {
2218
+ /** Atomically enforces the per-owner run/page ceilings before storing payload bytes. */
1198
2219
  putTempRunPage(page: TempRunPage): Promise<void>;
1199
2220
  /**
1200
2221
  * Optional: writes a batch of pages in one storage round trip. Callers fall back to
@@ -1206,13 +2227,16 @@ export interface TempSpillStore {
1206
2227
  removeTempRun(ownerId: string, runId: string): Promise<void>;
1207
2228
  /** Removes the owner record and every page under the owner. */
1208
2229
  removeTempOwner(ownerId: string): Promise<void>;
2230
+ /** Sweeps a bounded expired page before atomically enforcing MAX_ACTIVE_TEMP_OWNERS. */
1209
2231
  createTempOwner(record: TempOwnerRecord): Promise<void>;
1210
2232
  getTempOwner(ownerId: string): Promise<TempOwnerRecord | undefined>;
1211
- renewTempOwner(ownerId: string, expectedRevision: number, expiresAt: string): Promise<TempOwnerRecord>;
2233
+ renewTempOwner(input: RenewTempOwnerInput): Promise<TempOwnerRecord>;
1212
2234
  /** Sweeps pages too when it removes; owners found only via orphaned pages count as expired. */
1213
2235
  removeTempOwnerIfExpired(ownerId: string, expiresAtCutoff: string): Promise<boolean>;
1214
2236
  /** Owner ids from records and from orphaned pages alike, deduplicated, sorted, paged. */
1215
2237
  listTempOwnerIdsPage(afterOwnerId: string | null, limit: number): Promise<StoragePage<string, string>>;
2238
+ /** Actual expired candidates only, ordered by expiry then owner id. */
2239
+ listExpiredTempOwnerPage(expiresAtCutoff: string, afterCursor: string | null, limit: number): Promise<StoragePage<string, string>>;
1216
2240
  }
1217
2241
  /**
1218
2242
  * The complete storage contract: a database is `MinnowDatabase` plus one implementation of
@@ -1227,8 +2251,10 @@ export interface TempSpillStore {
1227
2251
  *
1228
2252
  * - **Atomicity.** Every method is all-or-nothing, including after a crash at any moment.
1229
2253
  * `commitTransaction` and `runGarbageCollectionStep` mutate several record families in one
1230
- * durable step. A method that resolves has happened; a method that rejects has not
1231
- * (observably) happened.
2254
+ * durable step. A local adapter method that resolves has happened; one that rejects has not
2255
+ * happened. The narrow transport-loss exception is an OPFS follower call that throws
2256
+ * `OpfsUncertainOutcomeError`: its prior leader may have committed the named mutation before
2257
+ * losing the reply, so callers must inspect/reopen instead of blindly repeating it.
1232
2258
  * - **Conflicts are typed, by exact class.** Compare-and-swap failures throw the exported
1233
2259
  * error classes (`WriteConflictError`, `TransactionRecordConflictError`,
1234
2260
  * `TableRecordConflictError`, `LeaseConflictError`, `CompactionJobConflictError`,
@@ -1242,10 +2268,10 @@ export interface TempSpillStore {
1242
2268
  * received records and bytes must be copied or serialized before the call resolves.
1243
2269
  * - **Deterministic ordering.** List methods sort as documented on each capability interface;
1244
2270
  * pagination cursors are stable under concurrent writes.
1245
- * - **Optional means atomic.** The optional methods exist so an adapter that can do something
1246
- * in one atomic step may say so; callers trust a present method completely and fall back to
1247
- * the sequential calls when it is absent. Never implement one as the sequential calls in a
1248
- * trench coat.
2271
+ * - **Optional means atomic.** Optional accelerator methods exist so an adapter that can do
2272
+ * something in one atomic step may say so; callers trust a present method completely and fall
2273
+ * back to safe sequential calls when it is absent. Never implement one as sequential calls in
2274
+ * a trench coat.
1249
2275
  * - **Multiple connections are normal.** Several instances (tabs) may open one database.
1250
2276
  * Readers must never block writers; competing writers must resolve through the typed
1251
2277
  * conflicts. How is the adapter's business — storage transactions, a write-ahead log behind
@@ -1265,46 +2291,51 @@ export interface BlockStore extends BlockPayloadStore, CatalogStore, Transaction
1265
2291
  * generation per retry. Required because an index build must never materialize one
1266
2292
  * database-sized storage value as a fallback.
1267
2293
  */
1268
- beginFtsBaseBuild(tableId: string, columnId: string, buildId: string): Promise<void>;
1269
- writeFtsBaseBuildChunk(tableId: string, columnId: string, buildId: string, ordinal: number, chunk: FtsPosting[]): Promise<void>;
1270
- finishFtsBaseBuild(tableId: string, columnId: string, buildId: string, input: {
1271
- coversVersion: number;
1272
- chunkCount: number;
1273
- totalTokens: number;
1274
- }): Promise<void>;
1275
- abortFtsBaseBuild(tableId: string, columnId: string, buildId: string): Promise<void>;
2294
+ beginFtsBaseBuild(input: BeginPostingBuildInput): Promise<void>;
2295
+ renewFtsBaseBuild(input: RenewPostingBuildInput): Promise<void>;
2296
+ writeFtsBaseBuildChunk(input: AppendPostingBuildChunkInput): Promise<void>;
2297
+ finishFtsBaseBuild(input: FinishPostingBuildInput): Promise<void>;
2298
+ abortFtsBaseBuild(input: AbortPostingBuildInput): Promise<void>;
1276
2299
  /**
1277
- * Optional: the current manifest version and catalog epoch in one atomic read. This is the
1278
- * freshness probe: an unchanged pair proves any cached catalog state is still exactly what
1279
- * a fresh read would return. Callers that find this absent must not cache catalog state.
2300
+ * The current manifest version, catalog epoch, and structural schema epoch in one atomic read.
2301
+ * An unchanged manifest/catalog pair proves cached query state is current; the schema epoch is
2302
+ * the narrower write-serialization guard and does not move for ordinary commits.
1280
2303
  */
1281
- getCatalogProbe?(): Promise<CatalogProbe>;
2304
+ getCatalogProbe(): Promise<CatalogProbe>;
1282
2305
  /**
1283
- * Optional: one atomic catalog read for query preparation. Implementations must return
1284
- * the named table records plus the segments and transactions reachable from the returned
1285
- * current manifest version. Historical records may be omitted: explicit version reads use
1286
- * listSegments/getTransactions instead. Callers fall back to those calls when this is absent.
2306
+ * Optional atomic query-catalog read. The returned tables, segments, transaction owners, and
2307
+ * probe epoch must come from one storage snapshot; engines use the sequential stable-epoch
2308
+ * fallback when an adapter does not provide it.
1287
2309
  */
1288
- getQueryCatalogState?(tableNames: readonly string[]): Promise<QueryCatalogState>;
2310
+ getQueryCatalogState?(names: readonly string[]): Promise<QueryCatalogState>;
1289
2311
  /**
1290
- * Optional: reads the current manifest version, creates the transaction record pinned to it,
1291
- * and optionally reserves row ids, all in one atomic storage transaction one round trip
1292
- * instead of three. Callers fall back to the individual calls when this is absent.
2312
+ * Reads the current manifest and schema epoch, creates the transaction record pinned to both,
2313
+ * and optionally reserves row ids or an invisible pending table in one atomic storage
2314
+ * transaction. Required because these reservations cannot be emulated safely by sequential
2315
+ * calls.
1293
2316
  */
1294
- beginTransaction?(input: BeginTransactionInput): Promise<BeginTransactionResult>;
2317
+ beginTransaction(input: BeginTransactionInput): Promise<BeginTransactionResult>;
1295
2318
  /**
1296
- * Optional: stages blocks and segments and journals them on the transaction record in one
1297
- * atomic storage transaction. Must be equivalent to addBlocks + addSegment(s) + one
1298
- * updateTransaction appending the new ids, with no intermediate state observable after a
1299
- * crash. Callers fall back to those calls when this is absent.
2319
+ * Required atomic staging boundary: saves blocks and segments and appends their ids to the
2320
+ * active transaction journal in one durable operation. It is equivalent to addBlocks +
2321
+ * addSegment(s) + one updateTransaction only when those changes commit atomically; there is no
2322
+ * sequential fallback because a crash could otherwise strand bytes or publish a dangling id.
2323
+ * A local refusal has no effect; the documented OPFS follower uncertain-outcome error means
2324
+ * the complete operation may have happened and must never be converted to an ordinary error.
1300
2325
  */
1301
- stageTransactionArtifacts?(input: StageTransactionArtifactsInput): Promise<TransactionRecord>;
2326
+ stageTransactionArtifacts(input: StageTransactionArtifactsInput): Promise<TransactionRecord>;
2327
+ /**
2328
+ * Required atomic savepoint rewind. Compare-and-swaps the journal, validates retained and
2329
+ * removed ids as its exact duplicate-free partition, and removes only the unreachable removed
2330
+ * artifacts in the same durable operation. A refusal leaves both journal and bytes unchanged.
2331
+ */
2332
+ rollbackTransactionArtifacts(input: RollbackTransactionArtifactsInput): Promise<TransactionRecord>;
1302
2333
  /**
1303
2334
  * Optional: the single-shot write — begin (or continue) a transaction, stage its blocks and
1304
2335
  * segments, and commit, all in one atomic storage transaction. Must be exactly equivalent to
1305
2336
  * `stageTransactionArtifacts` followed by `commitTransaction` (preceded by `createTransaction`
1306
2337
  * at `expectedManifestVersion` when the input carries a fresh record): the same validation,
1307
- * the same typed conflicts (`WriteConflictError`, `TransactionRecordConflictError`,
2338
+ * the same typed conflicts (`SchemaConflictError`, `WriteConflictError`, `TransactionRecordConflictError`,
1308
2339
  * `UniqueKeyConflictError`), the same finalized records afterwards — and nothing at all
1309
2340
  * written when any part refuses, including the fresh record. This is what lets a simple
1310
2341
  * write cost one durable storage commit instead of three; callers fall back to the sequence
@@ -1315,29 +2346,52 @@ export interface BlockStore extends BlockPayloadStore, CatalogStore, Transaction
1315
2346
  * Optional: re-pins a lease to another manifest version and renews it, in one atomic step —
1316
2347
  * `createLease` at the new version plus `removeLease` of the old pin, as one round trip that
1317
2348
  * keeps the record and its id. Compare-and-swap on `expectedRevision` (`LeaseConflictError`);
1318
- * the target version's manifest must be available (`SnapshotManifestMissingError`), and a
1319
- * refused move leaves the lease exactly as it was. The engine uses it to carry its shared
2349
+ * the target version's manifest must be available (`SnapshotManifestMissingError`), and a refused
2350
+ * move leaves the lease exactly as it was. An already-expired pin cannot be moved or renewed,
2351
+ * and the new expiry is capped by `MAX_LEASE_TTL_MS`. The engine uses it to carry its shared
1320
2352
  * reader pin forward after each commit; callers fall back to create + remove when absent.
1321
2353
  */
1322
- moveLease?(id: string, expectedRevision: number, manifestVersion: number | null, expiresAt: string): Promise<LeaseRecord>;
2354
+ moveLease?(input: MoveLeaseInput): Promise<LeaseRecord>;
1323
2355
  /**
1324
- * Optional: one committed version copied out as a portable snapshot — see
1325
- * `/docs/storage/snapshots` for what it carries, drops, and guarantees. A store without it
1326
- * still works; `MinnowDatabase` reports the capability as missing rather than failing.
2356
+ * Native bounded snapshot v1. Built-in adapters implement this complete family together.
2357
+ * Export reads exactly one globally ordered frame at a time from a durable frozen generation;
2358
+ * close releases that generation and its lease. No method returns a database-sized array.
1327
2359
  */
1328
- exportSnapshot?(): Promise<DatabaseSnapshot>;
2360
+ beginSnapshotFrameExport?(input: BeginSnapshotFrameExportInput): Promise<SnapshotFrameExportSession>;
2361
+ readSnapshotExportFrame?(input: ReadSnapshotExportFrameInput): Promise<SnapshotFrame | undefined>;
2362
+ closeSnapshotFrameExport?(input: CloseSnapshotExportInput): Promise<boolean>;
1329
2363
  /**
1330
- * Optional: loads a snapshot into this store, which must be empty. Pairs with
1331
- * `exportSnapshot` implement both or neither.
2364
+ * Native bounded import. Append atomically accepts only contiguous bounded frames and exact
2365
+ * lost-ack replay bytes. Finish validates header/footer counts, order, checksums, complete
2366
+ * catalog/segment/transaction/index cross-references, and atomically promotes all staged
2367
+ * generations; rejection leaves the current database unchanged.
1332
2368
  */
1333
- importSnapshot?(snapshot: DatabaseSnapshot, options?: {
1334
- onProgress?: (progress: SnapshotLoadProgress) => void;
1335
- }): Promise<void>;
2369
+ beginSnapshotFrameImport?(input: BeginSnapshotFrameImportInput): Promise<SnapshotFrameImportSession>;
2370
+ renewSnapshotFrameImport?(input: RenewSnapshotFrameImportInput): Promise<SnapshotFrameImportSession>;
2371
+ appendSnapshotImportFrames?(input: AppendSnapshotImportFramesInput): Promise<SnapshotFrameImportSession>;
2372
+ finishSnapshotFrameImport?(input: FinishSnapshotFrameImportInput): Promise<void>;
2373
+ cancelSnapshotFrameImport?(input: CancelSnapshotImportInput): Promise<InterruptedSnapshotImportAbortResult>;
2374
+ /** Bounded, fail-closed verification of control records and optionally every live block. */
2375
+ checkIntegrity?(options?: {
2376
+ mode?: StorageIntegrityMode;
2377
+ maxIssues?: number;
2378
+ }): Promise<StorageIntegrityReport>;
2379
+ /** Explicit storage accounting; adapters do not run this on query or write hot paths. */
2380
+ getStorageStats?(): Promise<StorageStats>;
2381
+ /** Returns the durable marker for an unpublished snapshot import, if this adapter has one. */
2382
+ inspectInterruptedImport?(): Promise<InterruptedSnapshotImport | null>;
2383
+ /** Atomically abandons the named unpublished import and removes all staged state. */
2384
+ abortInterruptedImport?(identity: string): Promise<InterruptedSnapshotImportAbortResult>;
1336
2385
  /**
1337
2386
  * Optional: what this database's data occupies in its substrate, in bytes — the number an
1338
2387
  * application shows a user next to the quota, and what the benchmarks report.
1339
2388
  */
1340
2389
  getLogicalStorageBytes?(): Promise<number>;
2390
+ /**
2391
+ * Optional deterministic channel for commit hints between connections to the same durable
2392
+ * database. The engine creates the BroadcastChannel; stores only expose identity.
2393
+ */
2394
+ readonly liveQueryChannelName?: string;
1341
2395
  /**
1342
2396
  * Releases whatever the connection holds (open handles, channels, timers) without flushing
1343
2397
  * or deleting anything. Synchronous; safe to call twice. Data durability must never depend
@@ -1345,17 +2399,16 @@ export interface BlockStore extends BlockPayloadStore, CatalogStore, Transaction
1345
2399
  */
1346
2400
  close(): void;
1347
2401
  }
1348
- export declare function createManifest(input: PublishManifestInput): Manifest;
1349
- /**
1350
- * Normalizes the additive L2 partition metadata while preserving legacy segment records verbatim.
1351
- */
2402
+ export declare function createManifest(input: CreateManifestInput): Manifest;
2403
+ /** Strictly clones the one canonical v1 segment shape. */
1352
2404
  export declare function normalizeSegmentRecord(record: SegmentRecord): SegmentRecord;
1353
2405
  export declare function updateTransactionRecord(record: TransactionRecord, update: TransactionRecordUpdate): TransactionRecord;
1354
2406
  export declare function createGarbageCollectionJobRecord(input: CreateGarbageCollectionJobInput): GarbageCollectionJobRecord;
2407
+ export declare function normalizeGarbageCollectionDiscovery(discovery: GarbageCollectionDiscovery): GarbageCollectionDiscovery;
2408
+ export declare function updateGarbageCollectionPlanningRecord(record: GarbageCollectionJobRecord, input: UpdateGarbageCollectionPlanningInput): GarbageCollectionJobRecord;
1355
2409
  export declare function normalizeGarbageCollectionJobRecord(record: GarbageCollectionJobRecord): GarbageCollectionJobRecord;
1356
2410
  export declare function advanceGarbageCollectionJobRecord(record: GarbageCollectionJobRecord, accounting: GarbageCollectionStepAccounting): GarbageCollectionJobRecord;
1357
2411
  export declare function normalizeCompactionJobRecord(record: CompactionJobRecord): CompactionJobRecord;
1358
2412
  export declare function updateCompactionJobRecord(record: CompactionJobRecord, update: CompactionJobRecordUpdate): CompactionJobRecord;
1359
2413
  /** Floors an integer-times-double product without rounding the binary double upward. */
1360
2414
  export declare function floorWholeNumberProduct(left: number, right: number, label: string): number;
1361
- //# sourceMappingURL=types.d.ts.map