@delali/sirannon-db 0.3.4-next.62 → 0.3.4

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 (108) hide show
  1. package/README.md +79 -56
  2. package/dist/backup/index.d.ts +44 -45
  3. package/dist/backup/index.mjs +7 -7
  4. package/dist/backup-scheduler/index.d.ts +42 -41
  5. package/dist/backup-scheduler/index.mjs +4 -4
  6. package/dist/baseline-Co3iIsN_.d.ts +19 -0
  7. package/dist/change-tracker-DqCdeEyx.d.ts +128 -0
  8. package/dist/{chunk-VOSJBZ6Q.mjs → chunk-2ES3DT4A.mjs} +71 -33
  9. package/dist/{chunk-6CMCO7S4.mjs → chunk-2O3PP4CF.mjs} +1 -1
  10. package/dist/{chunk-E7Q7HE46.mjs → chunk-3BZLZ47R.mjs} +26 -26
  11. package/dist/chunk-4KASJKKK.mjs +2501 -0
  12. package/dist/{chunk-MYNI2WFS.mjs → chunk-52XW3Z76.mjs} +40 -8
  13. package/dist/chunk-55YRLSM2.mjs +57 -0
  14. package/dist/{chunk-KDAHYFW7.mjs → chunk-6AOJCNRU.mjs} +5 -5
  15. package/dist/{chunk-KXTYR2OQ.mjs → chunk-A3PHCO6W.mjs} +39 -111
  16. package/dist/chunk-ADNWEHGZ.mjs +299 -0
  17. package/dist/{chunk-2QLXDHAP.mjs → chunk-BLMRNSUG.mjs} +11 -2
  18. package/dist/chunk-BVMZJOVM.mjs +5 -0
  19. package/dist/{chunk-IWGIYDMZ.mjs → chunk-BZWDPF4G.mjs} +1 -1
  20. package/dist/{chunk-YVF2ZJTE.mjs → chunk-CZL4D3BM.mjs} +1 -1
  21. package/dist/{chunk-7SC2TZAS.mjs → chunk-DX4WGJL7.mjs} +2 -2
  22. package/dist/{chunk-45MKELYA.mjs → chunk-ESTZZPT5.mjs} +132 -13
  23. package/dist/{chunk-QP5L5DFJ.mjs → chunk-FJPR2CJX.mjs} +3 -3
  24. package/dist/chunk-HR7K3GZW.mjs +36 -0
  25. package/dist/{chunk-LXCGPZPA.mjs → chunk-IEKIYO4V.mjs} +1 -1
  26. package/dist/{chunk-TUD5CJ76.mjs → chunk-KB4OLJAD.mjs} +26 -19
  27. package/dist/{chunk-PBRXXISQ.mjs → chunk-KINDFBQP.mjs} +3 -2
  28. package/dist/{chunk-E6IMX7RS.mjs → chunk-KJLNYOOL.mjs} +2 -2
  29. package/dist/{chunk-BTTFW4Z4.mjs → chunk-KU32OT4H.mjs} +2 -10
  30. package/dist/{chunk-JQWGHSEH.mjs → chunk-NVSQ2T5Q.mjs} +71 -70
  31. package/dist/{chunk-W4EUTJNT.mjs → chunk-NZGSDALX.mjs} +94 -96
  32. package/dist/{chunk-U445A3C4.mjs → chunk-QGVRRKB2.mjs} +1 -1
  33. package/dist/{chunk-GYCEJNU4.mjs → chunk-R7GBXNTO.mjs} +1 -1
  34. package/dist/{chunk-7C36BCSN.mjs → chunk-VDN6FHU4.mjs} +1 -1
  35. package/dist/{chunk-6IYS4WLH.mjs → chunk-VO3ZWA2G.mjs} +142 -115
  36. package/dist/chunk-WOMADPM4.mjs +12 -0
  37. package/dist/{chunk-OUSWVNWT.mjs → chunk-YCMB6GR4.mjs} +1 -1
  38. package/dist/{chunk-YNTDOFTN.mjs → chunk-YW7IKQ7T.mjs} +1 -1
  39. package/dist/{chunk-M2BEAH5I.mjs → chunk-ZN4HI5FK.mjs} +126 -72
  40. package/dist/{chunk-SBL6GN43.mjs → chunk-ZYWI45EN.mjs} +1 -1
  41. package/dist/client/index.d.ts +135 -137
  42. package/dist/client/index.mjs +177 -82
  43. package/dist/client/topology.d.ts +31 -31
  44. package/dist/client/topology.mjs +42 -23
  45. package/dist/client-base-BxTocU1x.d.ts +398 -0
  46. package/dist/client-streams-YKANXMWO.mjs +112 -0
  47. package/dist/codegen/cli.mjs +4 -4
  48. package/dist/codegen/index.d.ts +36 -29
  49. package/dist/codegen/index.mjs +4 -4
  50. package/dist/core/index.d.ts +130 -115
  51. package/dist/core/index.mjs +387 -297
  52. package/dist/core/writer-worker.mjs +3 -3
  53. package/dist/database-CGDsXW1K.d.ts +959 -0
  54. package/dist/database-backup-DcLhxoa1.d.ts +143 -0
  55. package/dist/driver/better-sqlite3.d.ts +11 -10
  56. package/dist/driver/better-sqlite3.mjs +11 -11
  57. package/dist/driver/bun.d.ts +9 -8
  58. package/dist/driver/expo.d.ts +6 -7
  59. package/dist/driver/node.d.ts +11 -10
  60. package/dist/driver/node.mjs +13 -11
  61. package/dist/driver/wa-sqlite.d.ts +6 -6
  62. package/dist/errors-CJUkQ-KL.d.ts +199 -0
  63. package/dist/file-migrations/index.d.ts +20 -18
  64. package/dist/file-migrations/index.mjs +3 -3
  65. package/dist/forward-rpc-VRWFZXHN.mjs +44 -0
  66. package/dist/operation-registry-CGhNT-Sn.d.ts +96 -0
  67. package/dist/primary-wins-CHNOYuN7.d.ts +81 -0
  68. package/dist/protocol-DFpNNsIT.d.ts +153 -0
  69. package/dist/query-types-5B02ixH0.d.ts +129 -0
  70. package/dist/react/index.d.ts +22 -22
  71. package/dist/replication/coordinator/etcd.d.ts +37 -31
  72. package/dist/replication/coordinator/etcd.mjs +296 -131
  73. package/dist/replication/index.d.ts +201 -161
  74. package/dist/replication/index.mjs +630 -529
  75. package/dist/restore-options-CH8mE-Tb.d.ts +84 -0
  76. package/dist/server/index.d.ts +201 -191
  77. package/dist/server/index.mjs +736 -619
  78. package/dist/server-options-aYtCkefX.d.ts +317 -0
  79. package/dist/server-streams-24XL4T43.mjs +254 -0
  80. package/dist/sirannon-J3EgPVD7.d.ts +179 -0
  81. package/dist/transport/grpc.d.ts +37 -24
  82. package/dist/transport/grpc.mjs +83 -3199
  83. package/dist/transport/memory.d.ts +25 -26
  84. package/dist/transport/memory.mjs +18 -9
  85. package/dist/types-BrAiDGOb.d.ts +505 -0
  86. package/dist/types-CEJG0eFS.d.ts +88 -0
  87. package/dist/types-Dc8oWlxj.d.ts +1580 -0
  88. package/dist/types-DqODKeOq.d.ts +123 -0
  89. package/dist/types-guEKSzMr.d.ts +367 -0
  90. package/package.json +7 -7
  91. package/dist/baseline-D93hcIEE.d.ts +0 -17
  92. package/dist/change-tracker-CjRFuZdB.d.ts +0 -144
  93. package/dist/client-base-Cmd9EVme.d.ts +0 -397
  94. package/dist/database-BLQvqjsw.d.ts +0 -917
  95. package/dist/database-backup-B7oszQ2n.d.ts +0 -141
  96. package/dist/errors-Dei4GdBb.d.ts +0 -196
  97. package/dist/operation-registry-oiPuSYI6.d.ts +0 -94
  98. package/dist/primary-wins-B0np8JS3.d.ts +0 -85
  99. package/dist/protocol-HI-nY8DD.d.ts +0 -152
  100. package/dist/query-types-p1liOP-b.d.ts +0 -127
  101. package/dist/restore-options-CksYsH1l.d.ts +0 -83
  102. package/dist/server-options-Bj5iJnjx.d.ts +0 -292
  103. package/dist/sirannon-BPxC5tC2.d.ts +0 -178
  104. package/dist/types-B0EhgDbr.d.ts +0 -340
  105. package/dist/types-CbjfRwrK.d.ts +0 -499
  106. package/dist/types-CjhxcjhA.d.ts +0 -123
  107. package/dist/types-DPSmjU54.d.ts +0 -1518
  108. package/dist/types-DTO4CYhW.d.ts +0 -88
@@ -0,0 +1,1580 @@
1
+ import { P as Params, W as WriteConcern, R as ReadConcern, b as ChangeOperation, E as ExecuteResult, a as ReadConcernLevel } from './query-types-5B02ixH0.js';
2
+
3
+ /** One piece of a backup file at a destination.
4
+ * @public
5
+ */
6
+ interface BackupPiece {
7
+ /** The position of this piece in the file, counted in whole pieces from zero. */
8
+ index: number;
9
+ /** The size of this piece, in bytes. */
10
+ byteLength: number;
11
+ }
12
+ /**
13
+ * The storage that Sirannon writes backup bytes to and reads them back from.
14
+ * Sirannon includes no storage client, so you supply the three required
15
+ * operations and connect object storage, another machine, or any other store
16
+ * of bytes. Every piece except the last holds the same number of bytes, and
17
+ * Sirannon can write the pieces in any order, because SQLite writes page one
18
+ * last. A backup chain uses several
19
+ * names, since Sirannon stores its full copy, each change piece, and the list
20
+ * of its records under names of their own.
21
+ *
22
+ * @public
23
+ */
24
+ interface BackupDestination {
25
+ /**
26
+ * Stores one piece of a named file. A second write to the same name and index
27
+ * must replace the piece already there, because when Sirannon stops between
28
+ * storing a piece and recording it, it stores that piece again when it
29
+ * resumes.
30
+ */
31
+ writePiece(name: string, index: number, bytes: Uint8Array): Promise<void>;
32
+ /**
33
+ * Stores one piece only where no piece exists at that name and index, and
34
+ * resolves to true when this call stored it. Sirannon claims each index in
35
+ * its list of chains through this method, so that two nodes writing at the
36
+ * same moment keep both of their chains. When you leave it out, Sirannon
37
+ * writes the record and reads it back, which loses a chain when the other
38
+ * node writes between those two calls.
39
+ */
40
+ writePieceIfAbsent?(name: string, index: number, bytes: Uint8Array): Promise<boolean>;
41
+ /** Returns one piece of a named file. */
42
+ readPiece(name: string, index: number): Promise<Uint8Array>;
43
+ /** Returns every piece of a named file, in any order. */
44
+ listPieces(name: string): Promise<BackupPiece[]>;
45
+ }
46
+
47
+ /** The default name that Sirannon stores the list of chains under at a destination.
48
+ * @public
49
+ */
50
+ declare const DEFAULT_CHAIN_NAME = "sirannon-backup-chain";
51
+ /** The range of write-ahead log frames that one change piece holds.
52
+ * @public
53
+ */
54
+ interface BackupChainPosition {
55
+ /** The checkpoint sequence of the log that holds these frames. SQLite adds one to it each time it restarts the log. */
56
+ logSequence: number;
57
+ /** The first salt of that log. Together with `salt2`, it identifies the generation of the log that holds the frames. */
58
+ salt1: number;
59
+ /** The second salt of that log. */
60
+ salt2: number;
61
+ /** The first frame in the piece, counted from one. */
62
+ firstFrame: number;
63
+ /** The last frame in the piece. */
64
+ lastFrame: number;
65
+ }
66
+ /**
67
+ * The full copy at the head of a chain. Sirannon restores from this copy and
68
+ * then applies the change pieces on top of it.
69
+ *
70
+ * @public
71
+ */
72
+ interface BackupChainBase {
73
+ /** The kind of record. */
74
+ kind: 'full';
75
+ /** The chain that this copy begins. */
76
+ chainId: string;
77
+ /** The name that Sirannon stores the pieces of this copy under at the destination. */
78
+ name: string;
79
+ /** The identifier that Sirannon reports the progress of this copy under. */
80
+ runId: string;
81
+ /** The moment, in epoch milliseconds, that the copy finished. A restore to any earlier moment needs an older chain. */
82
+ finishedAt: number;
83
+ /** The number of pieces that Sirannon stores the copy in. */
84
+ pieceCount: number;
85
+ /** The size of one whole piece, in bytes. */
86
+ pieceBytes: number;
87
+ /** The number of bytes that Sirannon stores at the destination. */
88
+ bytesWritten: number;
89
+ /** The SHA-256 of the copy, present while fingerprinting is on. */
90
+ fingerprint?: string;
91
+ }
92
+ /**
93
+ * One change piece, which holds the log frames that a database writes between
94
+ * the previous capture and this one.
95
+ *
96
+ * @public
97
+ */
98
+ interface BackupChainChange {
99
+ /** The kind of record. */
100
+ kind: 'change';
101
+ /** The chain that this piece extends, which identifies the full copy that the piece applies on top of. */
102
+ chainId: string;
103
+ /** The name that Sirannon stores this piece under at the destination. */
104
+ name: string;
105
+ /** The identifier that Sirannon reports the progress of this capture under. */
106
+ runId: string;
107
+ /** The position of this piece in its chain, counted from one. */
108
+ sequence: number;
109
+ /** The range of log frames that this piece holds. */
110
+ position: BackupChainPosition;
111
+ /** The moment, in epoch milliseconds, that Sirannon captured the frames. A restore stops at a capture time such as this one. */
112
+ capturedAt: number;
113
+ /** The number of log frames in this piece. */
114
+ frameCount: number;
115
+ /** The number of destination pieces that Sirannon stores these frames in. */
116
+ pieceCount: number;
117
+ /** The size of one whole piece, in bytes. */
118
+ pieceBytes: number;
119
+ /** The number of bytes that Sirannon stores at the destination. */
120
+ bytesWritten: number;
121
+ /** Whether the checkpoint after this capture emptied the log. */
122
+ checkpointed: boolean;
123
+ /** The SHA-256 of the frames, present while fingerprinting is on. */
124
+ fingerprint?: string;
125
+ }
126
+ /** Either the full copy at the head of a chain or one change piece along it.
127
+ * @public
128
+ */
129
+ type BackupChainRecord = BackupChainBase | BackupChainChange;
130
+ /** One full copy and every change piece that Sirannon captures after it.
131
+ * @public
132
+ */
133
+ interface BackupChain {
134
+ /** The identifier of this chain. */
135
+ chainId: string;
136
+ /** The moment, in epoch milliseconds, that Sirannon started the chain. */
137
+ startedAt: number;
138
+ /** The identifier of the previous chain, where this chain replaces one. */
139
+ previousChainId?: string;
140
+ /**
141
+ * The full copy that the chain starts from. After someone deletes that
142
+ * record, this field is absent, so no restore can use the chain.
143
+ */
144
+ base?: BackupChainBase;
145
+ /** The change pieces, oldest first. */
146
+ changes: BackupChainChange[];
147
+ }
148
+ /**
149
+ * Returns the name that Sirannon stores the records of one chain under. Each
150
+ * chain has a name of its own, so deleting an old chain leaves every other
151
+ * chain in place.
152
+ *
153
+ * @param chainName - The name that Sirannon stores the list of chains under.
154
+ * @param chainId - The identifier of the chain.
155
+ * @returns The name to read and write the records of that chain under.
156
+ *
157
+ * @public
158
+ */
159
+ declare function chainLogName(chainName: string, chainId: string): string;
160
+ /**
161
+ * Returns every chain at a destination, with its full copy and its change
162
+ * pieces. It reads only the destination, so you can call it on a fresh machine
163
+ * before any database exists.
164
+ *
165
+ * @param destination - The destination that holds the backups and their records.
166
+ * @param chainName - The name that Sirannon stores the list of chains under. Defaults to `sirannon-backup-chain`.
167
+ * @returns The chains, newest first, each with its own records oldest first.
168
+ *
169
+ * @public
170
+ */
171
+ declare function readBackupChains(destination: BackupDestination, chainName?: string): Promise<BackupChain[]>;
172
+
173
+ /**
174
+ * The node of a replication group that takes its backups.
175
+ *
176
+ * With `'replica'`, Sirannon picks an eligible replica, and it picks the
177
+ * primary where the group has no eligible replica. With `'primary'`, Sirannon
178
+ * picks the primary, and no node takes backups while the primary is not
179
+ * eligible. An object names one node directly, and each node compares its own
180
+ * identifier against that name without reading the membership.
181
+ *
182
+ * @public
183
+ */
184
+ type BackupNodePreference = 'replica' | 'primary' | {
185
+ nodeId: string;
186
+ };
187
+ /**
188
+ * The primary of a replication group, and the nodes that hold data current
189
+ * enough to back up.
190
+ *
191
+ * @public
192
+ */
193
+ interface BackupGroupMembership {
194
+ /** The identifier of the primary, or null while the group has no primary. */
195
+ primaryNodeId: string | null;
196
+ /** The identifiers of the nodes that are eligible to take the backup. */
197
+ nodeIds: string[];
198
+ }
199
+ /**
200
+ * The source of the identity of this node and the membership of its
201
+ * replication group. Without a group source, the cycle backs up the database on
202
+ * every turn, as a single-node deployment needs.
203
+ *
204
+ * `coordinatorBackupGroup` in the replication entry point builds a group source
205
+ * from a cluster coordinator. Write your own where another system holds the
206
+ * membership.
207
+ *
208
+ * @public
209
+ */
210
+ interface BackupGroupSource {
211
+ /** The identifier of this node within the group. */
212
+ readonly nodeId: string;
213
+ /**
214
+ * Reads the current membership of the group.
215
+ *
216
+ * @returns The primary of the group, and the nodes that are eligible.
217
+ */
218
+ readMembership(): Promise<BackupGroupMembership>;
219
+ }
220
+ /**
221
+ * The reason that one turn of the cycle writes nothing.
222
+ *
223
+ * `'not-preferred'` means that another node, or no node, takes the backups of
224
+ * this group. `'group-unavailable'` means that Sirannon cannot read the
225
+ * membership of the group. `'previous-run-active'` means that the previous turn
226
+ * is still in progress.
227
+ *
228
+ * @public
229
+ */
230
+ type BackupSkipReason = 'not-preferred' | 'group-unavailable' | 'previous-run-active';
231
+ /**
232
+ * One turn that the cycle skips, and the reason for the skip.
233
+ *
234
+ * @public
235
+ */
236
+ interface BackupSkip {
237
+ /** The condition that applies. */
238
+ reason: BackupSkipReason;
239
+ /** A sentence for the log of the operator that describes the skip. */
240
+ message: string;
241
+ /** The identifier of this node, where a group source supplies one. */
242
+ nodeId?: string;
243
+ /** The identifier of the node that takes the backups, where Sirannon picks one. */
244
+ preferredNodeId?: string;
245
+ /**
246
+ * The size in bytes of the write-ahead log on this node at the skip. An alert
247
+ * on this value as it rises warns you that the log on a node is growing, well
248
+ * before `maxUncapturedLogBytes` ends its chain.
249
+ */
250
+ uncapturedLogBytes?: number;
251
+ }
252
+
253
+ /**
254
+ * The position of the write-ahead log of a database at one moment.
255
+ *
256
+ * A full copy records this position, so that you can tell which generation of
257
+ * the log the database was on when the copy finished. SQLite restarts the log
258
+ * after a checkpoint that empties it, and it writes a new pair of salts into
259
+ * the log at each restart.
260
+ *
261
+ * The backup cycle runs a checkpoint after each capture and none between a full
262
+ * copy and the first change piece of its chain, so those two records hold the
263
+ * same salts. A change piece holds later salts than the piece before it
264
+ * whenever the checkpoint between the two empties the log. A reader can keep a
265
+ * checkpoint from emptying the log, which leaves the log on its current
266
+ * generation, so two consecutive change pieces can hold the same salts.
267
+ *
268
+ * @public
269
+ */
270
+ interface BackupLogPosition {
271
+ /** The checkpoint sequence of the log. SQLite adds one to it each time it restarts the log. */
272
+ logSequence: number;
273
+ /** The first salt of that log. Together with `salt2`, it identifies the generation of the log. */
274
+ salt1: number;
275
+ /** The second salt of that log. */
276
+ salt2: number;
277
+ /** The last frame that commits a transaction, counted from one, or zero where the log holds no such frame. */
278
+ lastFrame: number;
279
+ }
280
+ /** The progress of one backup, which Sirannon reports after each step of the copy and after each piece that it stores.
281
+ * @public
282
+ */
283
+ interface BackupProgress {
284
+ /** The identifier of the backup that this progress describes. */
285
+ runId: string;
286
+ /** Whether Sirannon is copying pages or sending pieces. */
287
+ phase: 'copy' | 'transfer';
288
+ /** The total number of pages to copy. For a change piece, this is the number of log frames in the piece. */
289
+ totalPages: number;
290
+ /**
291
+ * The number of pages left to copy. On the staged route, every report of the
292
+ * transfer phase states zero, since the copy finishes before the transfer
293
+ * starts. On the streamed route, the two phases overlap, so a transfer report
294
+ * states the pages left at the latest step.
295
+ */
296
+ remainingPages: number;
297
+ /** The number of times so far that SQLite restarts the copy from page one. A change piece reports zero, since Sirannon reads the log for it and copies no pages. */
298
+ restarts: number;
299
+ /** The number of pieces stored at the destination so far. */
300
+ piecesWritten: number;
301
+ /** The number of bytes stored at the destination so far. */
302
+ bytesWritten: number;
303
+ }
304
+ /** The report of one finished backup to a destination.
305
+ * @public
306
+ */
307
+ interface BackupRunReport {
308
+ /** The identifier that Sirannon reports the progress of this backup under. */
309
+ runId: string;
310
+ /** The identifier of the source database. */
311
+ databaseId: string;
312
+ /** The path of the source database file. */
313
+ sourcePath: string;
314
+ /** Whether the backup holds the whole database or the log frames written since the previous capture. */
315
+ kind: 'full' | 'change';
316
+ /** The chain that this backup is part of. A full copy begins a chain, and every later change piece extends it. */
317
+ chainId: string;
318
+ /** Whether Sirannon sends the bytes through a local file, which is `staged`, or without one, which is `streamed`. */
319
+ route: 'staged' | 'streamed';
320
+ /**
321
+ * The name that Sirannon stores the pieces under at the destination. Sirannon
322
+ * writes only this name at the destination, because the journal that SQLite
323
+ * opens next to a copy stays on local disk.
324
+ */
325
+ destinationName: string;
326
+ /** The moment, in epoch milliseconds, that the backup started. */
327
+ startedAt: number;
328
+ /** The moment, in epoch milliseconds, that the backup finished. */
329
+ finishedAt: number;
330
+ /** The length of the whole backup, in milliseconds. */
331
+ durationMs: number;
332
+ /** The time, in milliseconds, that SQLite spends copying pages. */
333
+ copyMs: number;
334
+ /** The time, in milliseconds, that Sirannon spends storing pieces at the destination. */
335
+ transferMs: number;
336
+ /** The number of pages that SQLite copies. */
337
+ pageCount: number;
338
+ /** The size of one page, in bytes. */
339
+ pageSize: number;
340
+ /** The number of bytes that Sirannon stores at the destination. */
341
+ bytesWritten: number;
342
+ /** The number of pieces that Sirannon stores at the destination. */
343
+ pieceCount: number;
344
+ /** The size of one whole piece, in bytes. */
345
+ pieceBytes: number;
346
+ /** The number of times that SQLite restarts the copy from page one. */
347
+ restarts: number;
348
+ /** The range of log frames that a change piece holds. A full copy leaves this field out. */
349
+ position?: BackupChainPosition;
350
+ /**
351
+ * The position of the write-ahead log when a full copy finishes. Sirannon
352
+ * reads the log after SQLite copies the last page, so if a writer commits
353
+ * between those two steps, this position can include a frame that the copy
354
+ * lacks. A change piece states its range of log frames in
355
+ * {@link BackupRunReport.position}, and a database without a write-ahead log
356
+ * leaves out both fields.
357
+ */
358
+ logPosition?: BackupLogPosition;
359
+ /** The SHA-256 of the copied file, present while fingerprinting is on. */
360
+ fingerprint?: string;
361
+ }
362
+ /** The report of one finished copy to a local file.
363
+ * @public
364
+ */
365
+ interface BackupFileReport {
366
+ /** The identifier of this copy. */
367
+ runId: string;
368
+ /** The identifier of the source database. */
369
+ databaseId: string;
370
+ /** The path of the source database file. */
371
+ sourcePath: string;
372
+ /** The absolute path of the copy. */
373
+ destPath: string;
374
+ /** The moment, in epoch milliseconds, that the copy started. */
375
+ startedAt: number;
376
+ /** The moment, in epoch milliseconds, that the copy finished. */
377
+ finishedAt: number;
378
+ /** The length of the copy, in milliseconds. */
379
+ durationMs: number;
380
+ /** The number of pages that SQLite copies. */
381
+ pageCount: number;
382
+ /** The size of one page, in bytes. */
383
+ pageSize: number;
384
+ /** The size of the copy, in bytes. */
385
+ byteLength: number;
386
+ /** The number of times that SQLite restarts the copy from page one. */
387
+ restarts: number;
388
+ }
389
+ /**
390
+ * The result of one copy to a local file. The controller for the database adds
391
+ * the database identifier and the source path to build a
392
+ * {@link BackupFileReport}.
393
+ *
394
+ * @internal
395
+ */
396
+ type BackupFileCopy = Omit<BackupFileReport, 'databaseId' | 'sourcePath'>;
397
+ /** The settings for one backup to a destination that the caller supplies.
398
+ * @public
399
+ */
400
+ interface BackupToDestinationOptions {
401
+ /** The destination that stores the pieces, and that a restore reads them from. */
402
+ destination: BackupDestination;
403
+ /** The name to store the pieces under. Defaults to a name with a timestamp. */
404
+ name?: string;
405
+ /** The chain that this copy begins. Defaults to a random identifier. */
406
+ chainId?: string;
407
+ /**
408
+ * The size of one whole piece, in bytes. Defaults to 16 MiB. For a streamed
409
+ * copy, the size must divide by 512, because Sirannon passes SQLite whole
410
+ * 512-byte blocks.
411
+ */
412
+ pieceBytes?: number;
413
+ /** The number of pages that SQLite copies in one step. */
414
+ pagesPerStep?: number;
415
+ /** The number of restarts from page one that Sirannon allows before it fails the copy. */
416
+ restartLimit?: number;
417
+ /** The number of milliseconds that can pass without a completed step before Sirannon fails the copy. */
418
+ stallTimeoutMs?: number;
419
+ /** The number of milliseconds that one call to the destination can take before Sirannon fails the backup. Defaults to 10 minutes, and zero removes the deadline. */
420
+ destinationTimeoutMs?: number;
421
+ /** The number of steps that can pass without SQLite copying a new page before Sirannon fails the copy. */
422
+ noProgressStepLimit?: number;
423
+ /** The directory that the staged route writes its local file in. Defaults to the temporary directory of the system. */
424
+ stagingDir?: string;
425
+ /**
426
+ * Whether Sirannon computes the SHA-256 of the backup. Defaults to true. For a
427
+ * streamed copy, Sirannon reads every piece back from the destination to
428
+ * compute it, because it never holds the whole file, so you pay for that
429
+ * extra read from remote storage.
430
+ */
431
+ fingerprint?: boolean;
432
+ /** Called after each step of the copy and after each piece that Sirannon stores. */
433
+ onProgress?: (progress: BackupProgress) => void;
434
+ }
435
+ /** The options of the caller for one backup, plus the details of the source database and the first-step callback.
436
+ * @internal
437
+ */
438
+ interface BackupRunRequest extends BackupToDestinationOptions {
439
+ /** The identifier of the source database. */
440
+ databaseId: string;
441
+ /** The path of the source database file. */
442
+ sourcePath: string;
443
+ /** Called once after the first step of the copy, so that the caller can release the writer. */
444
+ onFirstStep?: () => void;
445
+ }
446
+
447
+ /**
448
+ * The settings for the cycle that captures the write-ahead log of a database
449
+ * and then checkpoints it.
450
+ *
451
+ * When a database has these options, Sirannon turns off the automatic
452
+ * checkpoints of SQLite, because a checkpoint lets SQLite overwrite log frames
453
+ * that Sirannon has yet to capture, and SQLite reports success either way.
454
+ *
455
+ * @public
456
+ */
457
+ interface BackupCycleOptions {
458
+ /** The destination that stores the full copy, the change pieces, and the chain records. */
459
+ destination: BackupDestination;
460
+ /**
461
+ * The interval between captures, in milliseconds. Defaults to 60000. A
462
+ * shorter interval keeps the log smaller and leaves fewer writes outside any
463
+ * backup after an unclean stop. At zero, the cycle takes a turn only when you
464
+ * call `runOnce`.
465
+ */
466
+ intervalMs?: number;
467
+ /**
468
+ * The age of a chain, in milliseconds, at which a new full copy starts a new
469
+ * chain. Defaults to 24 hours. A restore applies every change piece since the
470
+ * full copy, so this interval sets the upper limit on the time that a restore
471
+ * takes.
472
+ */
473
+ fullCopyIntervalMs?: number;
474
+ /** The name to store the list of chains under. Defaults to `sirannon-backup-chain`. */
475
+ chainName?: string;
476
+ /** The prefix of backup names at the destination. Defaults to `sirannon-backup`. */
477
+ namePrefix?: string;
478
+ /** The size of one whole piece, in bytes. Defaults to 16 MiB. */
479
+ pieceBytes?: number;
480
+ /** Whether to compute the SHA-256 of each backup. Defaults to true. */
481
+ fingerprint?: boolean;
482
+ /**
483
+ * The directory that holds a capture before Sirannon sends it. Defaults to a
484
+ * directory next to the database file, so that a capture that Sirannon has
485
+ * yet to send stays on disk across a restart. When you set it, the staged
486
+ * full copy also writes its local file here.
487
+ */
488
+ stagingDir?: string;
489
+ /** The number of pages that SQLite copies in one step of the full copy. */
490
+ pagesPerStep?: number;
491
+ /** The number of restarts from page one that Sirannon allows before it fails the full copy. */
492
+ restartLimit?: number;
493
+ /** The number of milliseconds that can pass without a completed step before Sirannon fails the full copy. */
494
+ stallTimeoutMs?: number;
495
+ /** The number of milliseconds that one call to the destination can take before Sirannon fails it. Defaults to 10 minutes, and zero removes the deadline. */
496
+ destinationTimeoutMs?: number;
497
+ /**
498
+ * The largest size in bytes that the write-ahead log can reach while the
499
+ * cycle captures nothing. By default there is no limit, which keeps the chain
500
+ * whole and lets the log grow for as long as the captures stop.
501
+ *
502
+ * Set it where free disk space matters more than an unbroken chain. Sirannon
503
+ * measures the log after any turn that captures nothing. Once the log passes
504
+ * this size, Sirannon empties it and reports `BACKUP_CHAIN_BROKEN`, so no
505
+ * backup holds the writes from that log, and the next turn that the node takes
506
+ * starts a new chain with a full copy.
507
+ */
508
+ maxUncapturedLogBytes?: number;
509
+ /** The number of steps that can pass without SQLite copying a new page before Sirannon fails the full copy. */
510
+ noProgressStepLimit?: number;
511
+ /**
512
+ * The source of the identity of this node and the membership of its
513
+ * replication group. Every node of a group has the same cycle, and each turn
514
+ * reads this source before it copies anything. Leave it out on a single-node
515
+ * deployment, where that one node takes every turn.
516
+ */
517
+ replicationGroup?: BackupGroupSource;
518
+ /**
519
+ * The node of that group that takes its backups. Defaults to `'replica'`, so
520
+ * that the primary keeps its capacity for writes. When the group has no
521
+ * eligible replica, Sirannon picks the primary.
522
+ */
523
+ preferredNode?: BackupNodePreference;
524
+ /** Called with the report of every backup that the cycle finishes. */
525
+ onRun?: (report: BackupRunReport) => void;
526
+ /**
527
+ * Called after each step of the copy and after each stored piece, with the
528
+ * counters of the turn in progress. The cycle also records the latest
529
+ * counters in its status, so use this callback when you want every step, and
530
+ * read the status when you want the current figure.
531
+ */
532
+ onProgress?: (progress: BackupProgress) => void;
533
+ /**
534
+ * Called with every turn that the cycle skips, and the reason for the skip. A
535
+ * node that takes none of the backups of its group reports a skip on every
536
+ * turn.
537
+ */
538
+ onSkip?: (skip: BackupSkip) => void;
539
+ /**
540
+ * Called when a capture, a transfer, or a checkpoint fails. Set this
541
+ * callback, because when turns keep failing while writes continue, the log
542
+ * grows without limit, and this callback reports each failure as it happens.
543
+ */
544
+ onError?: (error: Error) => void;
545
+ }
546
+ /** The settings of the operator, plus the database details and callbacks that the cycle needs.
547
+ * @internal
548
+ */
549
+ interface BackupCycleRequest extends BackupCycleOptions {
550
+ /** The identifier of the database to capture from. */
551
+ databaseId: string;
552
+ /** The path of its file. */
553
+ sourcePath: string;
554
+ /** Runs an operation while no other operation holds the writer. */
555
+ runExclusive: (op: () => Promise<void>) => Promise<void>;
556
+ /** Returns the writer connection, which is the only connection that may checkpoint. */
557
+ acquireWriter: () => SQLiteConnection;
558
+ /** Copies the whole database to the destination as the full copy that starts each chain. */
559
+ fullCopy: (options: BackupToDestinationOptions) => Promise<BackupRunReport>;
560
+ }
561
+
562
+ /** A failure of one turn of the cycle.
563
+ * @public
564
+ */
565
+ interface BackupCycleError {
566
+ /** The error code, which a caller matches on. */
567
+ code: string;
568
+ /** A sentence for the log of the operator that describes the failure. */
569
+ message: string;
570
+ /** The moment, in epoch milliseconds, that Sirannon recorded the failure. */
571
+ at: number;
572
+ /** The time from the start of the turn to the failure, in milliseconds. */
573
+ durationMs: number;
574
+ /** The chain that the cycle held when the failure occurred, where it held one. */
575
+ chainId?: string;
576
+ /**
577
+ * The progress of the backup at the failure. Sirannon leaves this field out
578
+ * for a failure before the copy begins. For a failure part-way through, it
579
+ * records the backup identifier, the pages left to copy, and the pieces and
580
+ * bytes already stored at the destination.
581
+ */
582
+ progress?: BackupProgress;
583
+ }
584
+ /** What the cycle is doing now, and the outcome of its recent turns.
585
+ * @public
586
+ */
587
+ interface BackupCycleStatus {
588
+ /** Whether a turn is in progress. */
589
+ running: boolean;
590
+ /** The chain that the cycle extends, where it holds one. */
591
+ chainId?: string;
592
+ /** The progress of the current turn, which Sirannon clears between turns. */
593
+ progress?: BackupProgress;
594
+ /** The report of the most recent backup that the cycle finished. */
595
+ lastRun?: BackupRunReport;
596
+ /** The most recent skipped turn, and the reason for the skip. */
597
+ lastSkip?: BackupSkip;
598
+ /** The most recent failure of a turn. */
599
+ lastError?: BackupCycleError;
600
+ }
601
+
602
+ /** The result of reading one stored backup from a destination and checking it against its record.
603
+ * @public
604
+ */
605
+ interface BackupVerifyResult {
606
+ /** The name that Sirannon stores the pieces under. */
607
+ name: string;
608
+ /** The chain that holds this record. */
609
+ chainId: string;
610
+ /** Whether this is the full copy at the head of that chain or one change piece along it. */
611
+ kind: 'full' | 'change';
612
+ /** The number of pieces at the destination. */
613
+ pieceCount: number;
614
+ /** The total size of those pieces, in bytes. */
615
+ bytesRead: number;
616
+ /** The SHA-256 that Sirannon computes over the bytes that it reads, present where the record holds a fingerprint to compare against. */
617
+ fingerprint?: string;
618
+ }
619
+ /**
620
+ * Reads one backup from the destination and checks it against its record in
621
+ * the chain.
622
+ *
623
+ * A restore finds a damaged piece only after it has begun, so call this
624
+ * beforehand to find the damage early. Sirannon fetches every piece in order
625
+ * and computes a SHA-256 over the bytes as it reads them, then compares that
626
+ * fingerprint and the byte count against the record. Sirannon holds one piece
627
+ * in memory at a time and writes nothing to disk, so a check of a large full
628
+ * copy needs no local storage.
629
+ *
630
+ * A missing piece, a byte count that differs from the record, and a
631
+ * fingerprint that differs from the record each throw
632
+ * `BACKUP_DESTINATION_ERROR`. Where fingerprinting was off for the backup,
633
+ * Sirannon compares only the piece listing and the byte count, and the result
634
+ * has no fingerprint. A name that no chain records throws
635
+ * `BACKUP_CHAIN_BROKEN`.
636
+ *
637
+ * @param destination - The destination that holds the pieces.
638
+ * @param chains - The chains at that destination, as {@link readBackupChains} returns them.
639
+ * @param name - The name that Sirannon stores the backup under, which its chain record states.
640
+ * @returns The number of pieces read, their total size in bytes, and the fingerprint where the record holds one.
641
+ *
642
+ * @public
643
+ */
644
+ declare function verifyBackupRecord(destination: BackupDestination, chains: readonly BackupChain[], name: string): Promise<BackupVerifyResult>;
645
+
646
+ /**
647
+ * Captures the write-ahead log of a database and then checkpoints it, on the
648
+ * interval that the operator sets.
649
+ *
650
+ * The capture must come first, because a checkpoint lets SQLite overwrite
651
+ * frames that Sirannon has yet to capture, and SQLite reports success either
652
+ * way. A failed capture therefore also skips the checkpoint after it.
653
+ *
654
+ * Sirannon creates the cycle for a database from its `backups` option.
655
+ *
656
+ * @public
657
+ */
658
+ declare class BackupCycle {
659
+ private readonly chainName;
660
+ private readonly namePrefix;
661
+ private readonly stagingDir;
662
+ private readonly logPath;
663
+ private readonly intervalMs;
664
+ private readonly fullCopyIntervalMs;
665
+ private readonly preferredNode;
666
+ private readonly timer;
667
+ private state;
668
+ private queued;
669
+ private readonly turns;
670
+ private started;
671
+ private verified;
672
+ private busy;
673
+ private captured;
674
+ private sendRefused;
675
+ private stopped;
676
+ private readonly request;
677
+ private readonly turnLog;
678
+ /** @internal */
679
+ constructor(request: BackupCycleRequest);
680
+ /**
681
+ * Resumes the chain that the state file records, or starts a new chain with a
682
+ * full copy, and then repeats the turn on the interval. On a resumed chain,
683
+ * Sirannon takes an ordinary turn straight away, so it sends the frames written
684
+ * while this node was down to the destination before the first interval ends.
685
+ */
686
+ start(): Promise<void>;
687
+ /**
688
+ * Takes one turn now. In a turn, Sirannon sends any staged capture, reads the
689
+ * frames written since the previous turn, and then checkpoints the log.
690
+ *
691
+ * At most one turn waits in the queue. A call during a turn in progress
692
+ * queues one turn after it, and every later call returns that queued turn,
693
+ * which reads the log when it begins and so captures the writes of every one
694
+ * of those callers. Without that limit, repeated calls during a long full
695
+ * copy would build a queue of turns with nothing left to capture.
696
+ *
697
+ * On a node whose replication group takes its backups from another node, a
698
+ * turn writes nothing and reports a skip.
699
+ *
700
+ * @returns The report of what the turn writes, or undefined where it writes nothing.
701
+ */
702
+ runOnce(): Promise<BackupRunReport | undefined>;
703
+ /**
704
+ * Stops the cycle after one final turn, so that Sirannon sends the writes
705
+ * made since the previous turn to the destination before the database closes.
706
+ */
707
+ stop(): Promise<void>;
708
+ /**
709
+ * Returns every chain at the destination.
710
+ *
711
+ * @returns Every chain, newest first, each with its full copy and its change pieces.
712
+ */
713
+ chains(): Promise<BackupChain[]>;
714
+ /**
715
+ * Returns what the cycle is doing now and the outcome of its recent turns.
716
+ *
717
+ * It returns straight away, both during a long full copy and between turns.
718
+ *
719
+ * @returns Whether a turn is in progress, the progress of that turn, and the last run, skip, and failure.
720
+ */
721
+ status(): BackupCycleStatus;
722
+ /**
723
+ * Reads one backup from the destination and checks it against its record in
724
+ * the chains at that destination.
725
+ *
726
+ * @param name - The name that Sirannon stores the backup under.
727
+ * @returns The number of pieces read, their total size in bytes, and the fingerprint where the record holds one.
728
+ */
729
+ verify(name: string): Promise<BackupVerifyResult>;
730
+ /**
731
+ * Runs one turn and reports to the operator any error that stops it. Some
732
+ * deeper steps report a failure themselves before they throw it, so this
733
+ * reports an error only where no step has reported it already, and the
734
+ * operator receives each failure once. When the turn captures nothing and the
735
+ * log has grown past the limit, Sirannon then empties the log, and the
736
+ * resulting report of the writes that no backup holds replaces any failure
737
+ * that the turn recorded.
738
+ */
739
+ private runTurn;
740
+ /** The callbacks and paths that the stand-down code uses to release the chain of this cycle. */
741
+ private get standDownRequest();
742
+ /** Empties the log when this turn captures nothing from it and it has grown past the limit that the operator sets. */
743
+ private releaseLogPastLimit;
744
+ /**
745
+ * Returns whether this node takes the turn that it is starting. Where the
746
+ * replication group takes its backups from another node, this node stands
747
+ * down from its chain and empties its log. Where Sirannon cannot read the
748
+ * group, this node keeps its chain and its log as they are, because no backup
749
+ * holds the frames that it has yet to capture.
750
+ */
751
+ private takesTheTurn;
752
+ /** Reports a skipped turn when the decision carries a reason for it. */
753
+ private reportSkip;
754
+ private tick;
755
+ private verifyChain;
756
+ private discardState;
757
+ /**
758
+ * Runs one turn. When the turn fails with `BACKUP_LOG_REWOUND` or
759
+ * `BACKUP_CHAIN_BROKEN`, no later piece can extend the chain, so this starts a
760
+ * new chain. The caller still receives the error, because no backup holds the
761
+ * lost writes. Where the new chain also fails to start, Sirannon records that
762
+ * second failure against the broken chain, because the cycle holds no chain by
763
+ * then and the operator needs the status to name the chain that they lost.
764
+ */
765
+ private turnOrStartOver;
766
+ private turn;
767
+ /**
768
+ * Reports a failure to the operator and records it as the outcome of the
769
+ * turn, against the chain that the cycle holds now.
770
+ *
771
+ * @param err - The error that stops the turn.
772
+ */
773
+ private report;
774
+ /** Records a failure against a chain that the cycle may already have released. */
775
+ private reportAgainstChain;
776
+ private replaceChain;
777
+ private captureAndCheckpoint;
778
+ /**
779
+ * Sends the capture staged against the chain that this cycle holds. Once the
780
+ * destination refuses a capture, Sirannon skips the send for the rest of the
781
+ * turn, because a second try would wait out the destination deadline again
782
+ * and delay every turn queued after it.
783
+ */
784
+ private sendWaitingCapture;
785
+ }
786
+
787
+ /** The context that Sirannon passes to each query hook.
788
+ * @public
789
+ */
790
+ interface QueryHookContext {
791
+ /** The identifier of the database that the statement executes against. */
792
+ databaseId: string;
793
+ /** The statement that is about to execute, or the one that has finished executing. */
794
+ sql: string;
795
+ /** The parameters bound to the statement. */
796
+ params?: Params;
797
+ /** Values for the hooks to read. */
798
+ metadata?: Record<string, unknown>;
799
+ /** The write concern that the caller set on the statement. */
800
+ writeConcern?: WriteConcern;
801
+ /** The read concern that the caller set on the statement. */
802
+ readConcern?: ReadConcern;
803
+ }
804
+ /** A hook that Sirannon calls synchronously before it executes each statement; throw from it to reject the statement. Sirannon also fails the statement when the hook returns a promise.
805
+ * @public
806
+ */
807
+ type BeforeQueryHook = (ctx: QueryHookContext) => void;
808
+ /** The context that Sirannon passes to each after-query hook, which adds the statement's duration and outcome to the query context.
809
+ * @public
810
+ */
811
+ interface AfterQueryHookContext extends QueryHookContext {
812
+ /** The number of milliseconds from the start of the statement to its return, including any time that it waited for the writer. */
813
+ durationMs: number;
814
+ /** The error that the statement threw, which the caller also receives, or undefined when the statement succeeded. Every statement of a failed transaction receives that transaction's error. */
815
+ error?: unknown;
816
+ }
817
+ /** A hook that Sirannon calls synchronously after each statement returns or throws. Sirannon ignores an error that the hook throws and a promise that it returns, and calls the next hook either way.
818
+ * @public
819
+ */
820
+ type AfterQueryHook = (ctx: AfterQueryHookContext) => void;
821
+ /** The context that Sirannon passes to each connection hook.
822
+ * @public
823
+ */
824
+ interface ConnectionHookContext {
825
+ /** The identifier of the database that Sirannon is opening or closing. */
826
+ databaseId: string;
827
+ /** The file path of the SQLite database. */
828
+ path: string;
829
+ }
830
+ /** A hook that Sirannon calls synchronously before it opens a database; throw from it to stop the open. Sirannon also fails the open when the hook returns a promise.
831
+ * @public
832
+ */
833
+ type BeforeConnectHook = (ctx: ConnectionHookContext) => void;
834
+ /** A hook that Sirannon calls synchronously once a database is open. Sirannon ignores an error that the hook throws and a promise that it returns, and calls the next hook either way.
835
+ * @public
836
+ */
837
+ type DatabaseOpenHook = (ctx: ConnectionHookContext) => void;
838
+ /** A hook that Sirannon calls synchronously once a database is closed. Sirannon ignores an error that the hook throws and a promise that it returns, and calls the next hook either way.
839
+ * @public
840
+ */
841
+ type DatabaseCloseHook = (ctx: ConnectionHookContext) => void;
842
+ /** A hook that the server calls before it creates a change subscription; throw from it to reject the subscription. A server with `acceptSql` off serves a table subscription only when the registry has this hook.
843
+ * @public
844
+ */
845
+ type BeforeSubscribeHook = (ctx: {
846
+ /** The identifier of the database that the subscription is on. */
847
+ databaseId: string;
848
+ /** The table that the subscription is on. */
849
+ table: string;
850
+ /** The column values that a changed row must have for Sirannon to deliver the change to the subscriber. */
851
+ filter?: Record<string, unknown>;
852
+ /** The identity that the `authenticate` hook returned for the connection, or undefined when the hook returned none. */
853
+ identity?: unknown;
854
+ /** The identifier of the device that the subscription syncs, or undefined for a subscription without a device. */
855
+ deviceId?: string;
856
+ }) => void | Promise<void>;
857
+ /** A hook that the server calls before it reads each table into a snapshot; throw from it to reject the snapshot.
858
+ * @public
859
+ */
860
+ type BeforeSnapshotHook = (ctx: {
861
+ /** The identifier of the database that the server copies into the snapshot. */
862
+ databaseId: string;
863
+ /** The table that the server is about to read. */
864
+ table: string;
865
+ /** The identity that the `authenticate` hook returned for the request, or undefined when the hook returned none. */
866
+ identity?: unknown;
867
+ }) => void | Promise<void>;
868
+ /** A hook that the server calls before it writes a batch that a device pushed, once for each table in the batch; throw from it to reject the whole batch.
869
+ * @public
870
+ */
871
+ type BeforePushHook = (ctx: {
872
+ /** The identifier of the database that the server writes the batch to. */
873
+ databaseId: string;
874
+ /** The table that the server writes these changes to. */
875
+ table: string;
876
+ /** The identifier of the device that sent the batch. */
877
+ deviceId: string;
878
+ /** The identity that the `authenticate` hook returned for the request, or undefined when the hook returned none. */
879
+ identity?: unknown;
880
+ }) => void | Promise<void>;
881
+ /** The hooks that Sirannon calls for every database in a registry, keyed by event.
882
+ * @public
883
+ */
884
+ interface HookConfig {
885
+ /** Sirannon calls this before each statement; throw from it to reject the statement. */
886
+ onBeforeQuery?: BeforeQueryHook | BeforeQueryHook[];
887
+ /** Sirannon calls this after each statement, with the statement's duration. */
888
+ onAfterQuery?: AfterQueryHook | AfterQueryHook[];
889
+ /** Sirannon calls this before it opens a database. */
890
+ onBeforeConnect?: BeforeConnectHook | BeforeConnectHook[];
891
+ /** Sirannon calls this once a database is open. */
892
+ onDatabaseOpen?: DatabaseOpenHook | DatabaseOpenHook[];
893
+ /** Sirannon calls this once a database is closed. */
894
+ onDatabaseClose?: DatabaseCloseHook | DatabaseCloseHook[];
895
+ /** The server calls this before it creates a change subscription; throw from it to reject the subscription. */
896
+ onBeforeSubscribe?: BeforeSubscribeHook | BeforeSubscribeHook[];
897
+ /** The server calls this before it reads each table into a snapshot; throw from it to reject the snapshot. */
898
+ onBeforeSnapshot?: BeforeSnapshotHook | BeforeSnapshotHook[];
899
+ /** The server calls this before it writes a batch that a device pushed; throw from it to reject the batch. */
900
+ onBeforePush?: BeforePushHook | BeforePushHook[];
901
+ }
902
+
903
+ /** The metrics that Sirannon reports after each statement finishes.
904
+ * @public
905
+ */
906
+ interface QueryMetrics {
907
+ /** The identifier of the database that the statement executed against. */
908
+ databaseId: string;
909
+ /** The statement that executed. */
910
+ sql: string;
911
+ /** The statement's duration, in milliseconds. */
912
+ durationMs: number;
913
+ /** The number of rows that a read returns, and absent for a write or a failed statement. */
914
+ rowsReturned?: number;
915
+ /** The number of rows that a write changes, and absent for a read or a failed statement. */
916
+ changes?: number;
917
+ /** True when the statement threw. */
918
+ error?: boolean;
919
+ }
920
+ /** The metrics that Sirannon reports when the registry opens or closes a database.
921
+ * @public
922
+ */
923
+ interface ConnectionMetrics {
924
+ /** The identifier of the database that the registry opened or closed. */
925
+ databaseId: string;
926
+ /** The file path of the SQLite database. */
927
+ path: string;
928
+ /** The number of read connections in the database's pool, which is 0 on close. */
929
+ readerCount: number;
930
+ /** Whether the registry opened or closed the database. */
931
+ event: 'open' | 'close';
932
+ }
933
+ /** The metrics for one change event and its delivery to subscribers.
934
+ * @public
935
+ */
936
+ interface CDCMetrics {
937
+ /** The identifier of the database that the change comes from. */
938
+ databaseId: string;
939
+ /** The table that contains the changed row. */
940
+ table: string;
941
+ /** Whether the change inserted, updated, or deleted the row. */
942
+ operation: ChangeOperation;
943
+ /** The number of subscribers whose filter matches the event and that Sirannon delivers it to, which is zero when none matches. */
944
+ subscriberCount: number;
945
+ }
946
+ /** The callbacks that receive Sirannon's metrics.
947
+ * @public
948
+ */
949
+ interface MetricsConfig {
950
+ /** Sirannon calls this once each statement finishes, whether the statement succeeded or threw. */
951
+ onQueryComplete?: (metrics: QueryMetrics) => void;
952
+ /** Sirannon calls this when the registry opens a database. */
953
+ onConnectionOpen?: (metrics: ConnectionMetrics) => void;
954
+ /** Sirannon calls this when the registry closes a database. */
955
+ onConnectionClose?: (metrics: ConnectionMetrics) => void;
956
+ /** The callback for each change event that Sirannon dispatches to a database's subscribers, both those of `Database.on` and those of a server's WebSocket connections. */
957
+ onCDCEvent?: (metrics: CDCMetrics) => void;
958
+ }
959
+
960
+ /**
961
+ * Executes statements inside one transaction; Sirannon passes it to the function that you give {@link Database.transaction}.
962
+ *
963
+ * @public
964
+ */
965
+ declare class Transaction {
966
+ private readonly conn;
967
+ private _lastInsertRowId;
968
+ constructor(conn: SQLiteConnection);
969
+ /**
970
+ * Executes a read inside this transaction.
971
+ *
972
+ * @param sql - The statement to execute.
973
+ * @param params - The values to bind to the statement, named or positional.
974
+ * @returns The rows that the statement returns.
975
+ */
976
+ query<T = Record<string, unknown>>(sql: string, params?: Params): Promise<T[]>;
977
+ /**
978
+ * Executes one write inside this transaction.
979
+ *
980
+ * @param sql - The statement to execute.
981
+ * @param params - The values to bind to the statement, named or positional.
982
+ * @returns The number of rows that the statement changed, and the row id of the last inserted row.
983
+ */
984
+ execute(sql: string, params?: Params): Promise<ExecuteResult>;
985
+ /**
986
+ * Executes one statement once for each parameter set, inside this transaction.
987
+ *
988
+ * @param sql - The statement to execute for each parameter set.
989
+ * @param paramsBatch - One parameter set for each execution.
990
+ * @returns One result per parameter set, in order.
991
+ */
992
+ executeBatch(sql: string, paramsBatch: Params[]): Promise<ExecuteResult[]>;
993
+ /**
994
+ * The row id that SQLite assigned to the last row that this transaction inserted.
995
+ */
996
+ get lastInsertRowId(): number | bigint;
997
+ /** @internal */
998
+ static run<T>(conn: SQLiteConnection, fn: (tx: Transaction) => Promise<T>): Promise<T>;
999
+ }
1000
+
1001
+ /** Matches a valid migration name, which uses only letters, digits, and underscores.
1002
+ * @public
1003
+ */
1004
+ declare const MIGRATION_NAME_RE: RegExp;
1005
+ /**
1006
+ * Marks a migration as a baseline, which a new database runs in place of every
1007
+ * version up to and including `through`. A database that already has migration
1008
+ * history skips the baseline and applies only the versions that it lacks.
1009
+ *
1010
+ * @public
1011
+ */
1012
+ interface MigrationBaseline {
1013
+ /** The highest earlier version that a new database skips in favour of the baseline. */
1014
+ through: number;
1015
+ }
1016
+ /** Describes one schema change, with the statements that apply it and the statements that undo it.
1017
+ * @public
1018
+ */
1019
+ interface Migration {
1020
+ /** The version number, which sets the ascending order in which the runner applies migrations. */
1021
+ version: number;
1022
+ /** The migration's name, which uses only letters, digits, and underscores. */
1023
+ name: string;
1024
+ /** The SQL that applies the change, or a function that applies it inside the migration's transaction. */
1025
+ up: string | ((tx: Transaction) => void | Promise<void>);
1026
+ /** The SQL that undoes the change, or a function that undoes it. Rollback throws a `MIGRATION_NO_DOWN` error for a migration without it. */
1027
+ down?: string | ((tx: Transaction) => void | Promise<void>);
1028
+ /** Marks this migration as a baseline, which a new database runs in place of the earlier versions. */
1029
+ baseline?: MigrationBaseline;
1030
+ }
1031
+ /** The migrations to apply, as an array or as a function that returns one.
1032
+ * @public
1033
+ */
1034
+ type MigrationSource = Migration[] | (() => Migration[] | Promise<Migration[]>);
1035
+ /** Identifies one migration in a migration or rollback result.
1036
+ * @public
1037
+ */
1038
+ interface AppliedMigrationEntry {
1039
+ /** The migration's version number. */
1040
+ version: number;
1041
+ /** The migration's name. */
1042
+ name: string;
1043
+ }
1044
+ /** Describes the outcome of one migrate call.
1045
+ * @public
1046
+ */
1047
+ interface MigrationResult {
1048
+ /** The migrations that this call applied, in the order that it applied them. */
1049
+ applied: AppliedMigrationEntry[];
1050
+ /** The number of input migrations that this call skipped, because the database already had them or a baseline replaces them. */
1051
+ skipped: number;
1052
+ }
1053
+ /** Describes the outcome of one rollback call.
1054
+ * @public
1055
+ */
1056
+ interface RollbackResult {
1057
+ /** The migrations that this call undid, newest first. */
1058
+ rolledBack: AppliedMigrationEntry[];
1059
+ }
1060
+
1061
+ /** One node that a client can read from, and the read concerns that the node meets now.
1062
+ * @public
1063
+ */
1064
+ interface ClusterReadEndpointInfo {
1065
+ /** The identifier of the node at this endpoint. */
1066
+ nodeId: string;
1067
+ /** The address that a client sends its reads to. */
1068
+ endpoint: string;
1069
+ /** The read concerns that this node meets now. */
1070
+ readConcerns: ReadConcernLevel[];
1071
+ }
1072
+ /** Every value that a node can report as its health state.
1073
+ * @public
1074
+ */
1075
+ declare const NODE_HEALTH_STATES: readonly ["healthy", "degraded", "failing_over", "repairing", "syncing", "unavailable"];
1076
+ /** The word that names what a node can do now.
1077
+ * @public
1078
+ */
1079
+ type NodeHealthState = (typeof NODE_HEALTH_STATES)[number];
1080
+ /** The condition behind a {@link NodeHealthState}.
1081
+ * @public
1082
+ */
1083
+ type NodeHealthReason = (typeof NODE_HEALTH_REASONS)[number];
1084
+ /** Every value that a node can report as the reason for its health state.
1085
+ * @public
1086
+ */
1087
+ declare const NODE_HEALTH_REASONS: readonly ["in-sync", "lagging", "coordinator-unreachable", "draining", "repairing", "faulted", "sync-pending", "no-group-state"];
1088
+ /**
1089
+ * The health of the one node that reports it.
1090
+ *
1091
+ * `canRead` and `canWrite` are true when that node accepts reads and writes
1092
+ * now, and `state` and `reason` name the condition behind them.
1093
+ *
1094
+ * @public
1095
+ */
1096
+ interface NodeHealth {
1097
+ /** What the node can do now. */
1098
+ state: NodeHealthState;
1099
+ /** The condition behind that state. */
1100
+ reason: NodeHealthReason;
1101
+ /** Whether the node serves reads now. */
1102
+ canRead: boolean;
1103
+ /** Whether the node accepts writes now. */
1104
+ canWrite: boolean;
1105
+ }
1106
+ /** What one node reports about its replication group, which `GET /db/{id}/cluster` returns.
1107
+ * @public
1108
+ */
1109
+ interface ClusterStatusInfo {
1110
+ /** The identifier of the database that this status describes. */
1111
+ databaseId: string;
1112
+ /** The identifier of the node's replication group. */
1113
+ replicationGroupId?: string;
1114
+ /** Whether this node is the primary, which accepts writes, or a replica, which serves reads. */
1115
+ role?: 'primary' | 'replica';
1116
+ /** The primary that this node reports as current, or null when the node reports none. */
1117
+ currentPrimary?: {
1118
+ nodeId: string;
1119
+ endpoint?: string;
1120
+ } | null;
1121
+ /** The primary term that this node reports as current. */
1122
+ primaryTerm?: bigint;
1123
+ /** Every node that a client can read from, with the read concerns that each one meets. */
1124
+ readEndpoints?: ClusterReadEndpointInfo[];
1125
+ /** What this node can do now. */
1126
+ health: NodeHealthState;
1127
+ /** The condition behind that health state. */
1128
+ healthReason: NodeHealthReason;
1129
+ }
1130
+ /** The settings for opening and closing databases automatically.
1131
+ * @public
1132
+ */
1133
+ interface LifecycleConfig {
1134
+ /** Opens a database the first time that a caller asks {@link Sirannon.resolve} for an identifier that has no open database. */
1135
+ autoOpen?: {
1136
+ resolver: (id: string) => {
1137
+ path: string;
1138
+ options?: DatabaseOptions;
1139
+ } | undefined;
1140
+ };
1141
+ /** The number of idle milliseconds after which the registry closes a database; 0 turns idle closing off. */
1142
+ idleTimeout?: number;
1143
+ /** The most databases open at once before an automatic open evicts the least recently used one; 0 sets no limit. */
1144
+ maxOpen?: number;
1145
+ }
1146
+ /** The options for opening one database.
1147
+ * @public
1148
+ */
1149
+ interface DatabaseOptions {
1150
+ /** Whether to open the database in read-only mode. */
1151
+ readOnly?: boolean;
1152
+ /** The number of read connections in the pool; the default is 4. */
1153
+ readPoolSize?: number;
1154
+ /** Whether to open the database in WAL mode; the default is true. */
1155
+ walMode?: boolean;
1156
+ /**
1157
+ * The writer's `PRAGMA synchronous` level; the default is 'normal'. Sirannon
1158
+ * restores this level after every bulk load.
1159
+ */
1160
+ synchronous?: SynchronousLevel;
1161
+ /** How often Sirannon polls the change log, in milliseconds; the default is 50. */
1162
+ cdcPollInterval?: number;
1163
+ /** How long Sirannon keeps change-log entries, in milliseconds; the default is 3_600_000, one hour. */
1164
+ cdcRetention?: number;
1165
+ /**
1166
+ * How long, in milliseconds, Sirannon keeps changes for a device's cursor.
1167
+ * Sirannon drops the cursor when the cursor goes this long without an update,
1168
+ * or when the oldest change that the device still needs reaches this age. The
1169
+ * default is 2_592_000_000, 30 days.
1170
+ */
1171
+ deviceCursorRetention?: number;
1172
+ /**
1173
+ * The most changes that Sirannon keeps for one device's cursor. Sirannon
1174
+ * drops the cursor of a device that falls further behind than this, and that
1175
+ * device then downloads the database again when it reconnects. 0 sets no
1176
+ * limit, and the default is 0.
1177
+ */
1178
+ maxChangesHeldForDevice?: number;
1179
+ /**
1180
+ * Whether to execute writes on a dedicated worker thread, so that disk
1181
+ * flushes never block the thread that serves connections, while reads stay
1182
+ * on the calling thread. The driver needs a worker entry, which the
1183
+ * `better-sqlite3` and `node` drivers have, and with any other driver the open
1184
+ * throws `WRITER_WORKER_UNSUPPORTED`. The default is off.
1185
+ */
1186
+ writerWorker?: boolean | WriterWorkerOptions;
1187
+ /**
1188
+ * Captures this database's write-ahead log to a destination that you supply,
1189
+ * on an interval. Apart from the full copies, each capture sends only the log
1190
+ * frames written since the previous capture, so its size follows how much
1191
+ * the database changed.
1192
+ *
1193
+ * With this option, Sirannon turns off SQLite's automatic checkpoint and
1194
+ * checkpoints the log itself after each capture, because a checkpoint lets
1195
+ * SQLite overwrite log frames that no capture has read yet. The default is
1196
+ * off.
1197
+ */
1198
+ backups?: BackupCycleOptions;
1199
+ }
1200
+ /** The limits and recovery settings for the writer worker thread.
1201
+ * @public
1202
+ */
1203
+ interface WriterWorkerOptions {
1204
+ /** The number of writes allowed in flight before Sirannon rejects new writes with a `WriteOverloadError`; the default is 1024. */
1205
+ maxPendingWrites?: number;
1206
+ /** The deadline for each operation, in milliseconds; the default is 30000, and 0 turns it off. At the deadline, Sirannon asks the worker to cancel the operation, and when the worker gives no answer within a second deadline, Sirannon rejects the caller's promise while the worker continues, so the outcome of that write is unknown. */
1207
+ writeTimeoutMs?: number;
1208
+ /** How many times Sirannon restarts the worker after the worker crashes on its own, before writes fail permanently; the default is 5. */
1209
+ maxRestarts?: number;
1210
+ }
1211
+ /** The options for a Sirannon database registry.
1212
+ * @public
1213
+ */
1214
+ interface SirannonOptions {
1215
+ /** The SQLite driver that opens every database in this registry. */
1216
+ driver: SQLiteDriver;
1217
+ /** The hooks that Sirannon calls for every database in this registry. */
1218
+ hooks?: HookConfig;
1219
+ /** The callbacks that receive Sirannon's metrics. */
1220
+ metrics?: MetricsConfig;
1221
+ /** The settings for automatic opening, idle closing, and the limit on open databases. */
1222
+ lifecycle?: LifecycleConfig;
1223
+ /** The migrations that Sirannon applies to each writable database in this registry as it opens. */
1224
+ migrations?: MigrationSource;
1225
+ /** The default writer-worker setting for the databases that this registry opens. */
1226
+ writerWorker?: boolean | WriterWorkerOptions;
1227
+ /** The default change-log retention, in milliseconds, for the databases that this registry opens. */
1228
+ cdcRetention?: number;
1229
+ /** The default device-cursor retention, in milliseconds, for the databases that this registry opens. */
1230
+ deviceCursorRetention?: number;
1231
+ /** The default limit on the changes that Sirannon keeps for one device's cursor, for the databases that this registry opens. */
1232
+ maxChangesHeldForDevice?: number;
1233
+ }
1234
+ /** The options for scheduled backups.
1235
+ * @public
1236
+ */
1237
+ interface BackupScheduleOptions {
1238
+ /** The cron expression, such as '0 * * * *' for every hour. */
1239
+ cron: string;
1240
+ /** The directory that Sirannon writes the backup files to. */
1241
+ destDir: string;
1242
+ /** The most backup files that Sirannon keeps; the default is 5. */
1243
+ maxFiles?: number;
1244
+ /**
1245
+ * The IANA time zone, such as 'America/New_York', in which Sirannon evaluates
1246
+ * the cron expression. When you omit it, Sirannon uses the host's local time
1247
+ * zone and its daylight saving rules.
1248
+ */
1249
+ timezone?: string;
1250
+ /**
1251
+ * Sirannon calls this after each copy that the schedule finishes, with the
1252
+ * file that it wrote and the copy's report. Use it to send the file to durable
1253
+ * storage, or to record that the schedule is still working.
1254
+ *
1255
+ * Sirannon awaits the promise that this returns and deletes the older files
1256
+ * only once that promise settles, so that it deletes no copy that your code
1257
+ * is still uploading. Sirannon passes a failure of this callback, like a
1258
+ * failed copy, to {@link BackupScheduleOptions.onError}, and
1259
+ * {@link BackupScheduleOptions.onBackupTimeoutMs} limits the wait.
1260
+ */
1261
+ onBackup?: (report: BackupFileReport) => void | Promise<void>;
1262
+ /**
1263
+ * How many milliseconds {@link BackupScheduleOptions.onBackup} may take
1264
+ * before Sirannon stops waiting for it; the default is 600_000, ten minutes,
1265
+ * and 0 waits with no limit.
1266
+ *
1267
+ * Sirannon deletes the older files and takes the next copy once the callback
1268
+ * settles or this deadline passes, so a callback that hangs on a socket
1269
+ * delays the schedule by this long at most. Past the deadline, Sirannon
1270
+ * reports the timeout through {@link BackupScheduleOptions.onError} and
1271
+ * continues the schedule while your callback keeps working. Sirannon then
1272
+ * counts that copy among the files that it may delete, so set this longer
1273
+ * than your slowest upload.
1274
+ */
1275
+ onBackupTimeoutMs?: number;
1276
+ /** Sirannon calls this when a scheduled backup fails, and discards the error when you omit it. */
1277
+ onError?: (error: Error) => void;
1278
+ }
1279
+
1280
+ /** Runs an operation while no other operation holds the writer, so that the copy has the writer connection to itself.
1281
+ * @public
1282
+ */
1283
+ type RunExclusive = (op: () => Promise<void>) => Promise<void>;
1284
+ /**
1285
+ * The options of one repeating backup, plus the database details that Sirannon
1286
+ * puts in every report of that backup.
1287
+ *
1288
+ * @public
1289
+ */
1290
+ interface BackupScheduleRequest extends BackupScheduleOptions {
1291
+ /** The identifier of the database that Sirannon copies. Defaults to the name of the source file without its extension. */
1292
+ databaseId?: string;
1293
+ /** The file that Sirannon copies. Defaults to the file that SQLite has open on the connection. */
1294
+ sourcePath?: string;
1295
+ /** Runs each copy while no other operation holds the writer. By default, Sirannon runs each copy without a lock. */
1296
+ runExclusive?: RunExclusive;
1297
+ }
1298
+
1299
+ interface WorkerHostOptions {
1300
+ writeTimeoutMs?: number;
1301
+ maxRestarts?: number;
1302
+ }
1303
+
1304
+ /** Describes the result of one write through the driver.
1305
+ * @public
1306
+ */
1307
+ interface RunResult {
1308
+ /** The number of rows that the statement inserted, updated, or deleted. */
1309
+ changes: number;
1310
+ /** The rowid that SQLite assigned to the last inserted row. */
1311
+ lastInsertRowId: number | bigint;
1312
+ }
1313
+ /**
1314
+ * Distinguishes a caller that runs inside the operation holding the writer
1315
+ * from a caller that waits for the writer. A runtime needs async context
1316
+ * tracking to make that distinction, and a wrong answer would run one
1317
+ * caller's writes inside another caller's transaction.
1318
+ */
1319
+ interface WriterContext {
1320
+ /** Runs an operation and marks it as the one that holds the writer. */
1321
+ run<T>(operation: () => T): T;
1322
+ /** Returns `true` when the caller runs inside the operation that holds the writer. */
1323
+ isActive(): boolean;
1324
+ /** Runs an operation outside the held writer's context, so that its writes stay out of that transaction. */
1325
+ exit<T>(operation: () => T): T;
1326
+ }
1327
+ /**
1328
+ * Copies a database to a file or a destination, and schedules repeating copies.
1329
+ *
1330
+ * @internal
1331
+ */
1332
+ interface BackupEngine {
1333
+ /** Copies the connection's database to a destination path. */
1334
+ backup(conn: SQLiteConnection, destPath: string, onFirstStep?: () => void): Promise<BackupFileCopy>;
1335
+ /** Copies the connection's database to a destination that the caller supplies. */
1336
+ copyToDestination(conn: SQLiteConnection, request: BackupRunRequest): Promise<BackupRunReport>;
1337
+ /** Returns `true` when a full copy streams to the destination without a local file. */
1338
+ streamsToDestination(): boolean;
1339
+ /** Returns a backup cycle that captures the write-ahead log and then checkpoints it. */
1340
+ createCycle(request: BackupCycleRequest): BackupCycle;
1341
+ /** Starts a repeating backup and returns a function that stops it. */
1342
+ schedule(conn: SQLiteConnection, request: BackupScheduleRequest): () => void;
1343
+ }
1344
+ /** Describes the progress after one step of a stepped database copy.
1345
+ * @public
1346
+ */
1347
+ interface DatabaseCopyStep {
1348
+ /** The total number of pages to copy. */
1349
+ totalPages: number;
1350
+ /** The number of pages left to copy. */
1351
+ remainingPages: number;
1352
+ }
1353
+ /** Describes the copy that Sirannon requests from a driver, and the number of pages in each step.
1354
+ * @public
1355
+ */
1356
+ interface DatabaseCopyRequest {
1357
+ /** The path of the copy's destination file. */
1358
+ destPath: string;
1359
+ /** The number of pages that the driver copies in one step. */
1360
+ pagesPerStep: number;
1361
+ /**
1362
+ * The driver calls this function after every step with that step's page
1363
+ * counts. The function returns the number of pages for the next step, which
1364
+ * a driver passes on when its runtime accepts a new count for each step. A
1365
+ * return of zero pauses the copy until the caller catches up.
1366
+ */
1367
+ onStep?: (step: DatabaseCopyStep) => number;
1368
+ /**
1369
+ * The number of milliseconds without a step after which the caller stops
1370
+ * waiting for the copy. A driver that steps the copy on another thread waits
1371
+ * this long for that thread, so a longer timeout keeps a slow copy running.
1372
+ * Zero removes the limit.
1373
+ */
1374
+ stallTimeoutMs?: number;
1375
+ }
1376
+ /** Holds the totals for one statement that the driver applies over many parameter sets.
1377
+ * @public
1378
+ */
1379
+ interface BatchSummary {
1380
+ /** The number of parameter sets that the driver applied. */
1381
+ rowsLoaded: number;
1382
+ /** The number of rows that those statements inserted, updated, or deleted. */
1383
+ changes: number;
1384
+ }
1385
+ /** A prepared statement that a driver returns, which you can run many times.
1386
+ * @public
1387
+ */
1388
+ interface SQLiteStatement {
1389
+ /** Runs the statement and returns every row. */
1390
+ all<T = unknown>(...params: unknown[]): Promise<T[]>;
1391
+ /** Runs the statement and returns the first row, or undefined when the result is empty. */
1392
+ get<T = unknown>(...params: unknown[]): Promise<T | undefined>;
1393
+ /** Runs the statement as a write and returns the number of changed rows and the last inserted rowid. */
1394
+ run(...params: unknown[]): Promise<RunResult>;
1395
+ /**
1396
+ * Runs the statement and returns every row with each integer as a `bigint`,
1397
+ * skipping the narrowing that {@link SQLiteStatement.all} applies. The
1398
+ * server's wire encoder narrows and tags integers in one pass, so reading raw
1399
+ * rows saves the server a second pass over the data. When a driver omits this method,
1400
+ * Sirannon calls {@link SQLiteStatement.all}, which gives the same result
1401
+ * with the extra pass.
1402
+ */
1403
+ allRaw?<T = unknown>(...params: unknown[]): Promise<T[]>;
1404
+ }
1405
+ /**
1406
+ * Describes the error from one failed unit of a grouped write.
1407
+ *
1408
+ * @internal
1409
+ */
1410
+ interface GroupRunError {
1411
+ /** The message that SQLite or the driver raised. */
1412
+ message: string;
1413
+ /** The name of the error class. */
1414
+ name?: string;
1415
+ /** The machine-readable code, when the driver supplies one. */
1416
+ code?: string;
1417
+ }
1418
+ /**
1419
+ * Describes the outcome of one unit in a grouped write.
1420
+ *
1421
+ * @internal
1422
+ */
1423
+ type GroupRunOutcome = {
1424
+ ok: true;
1425
+ results: RunResult[];
1426
+ } | {
1427
+ ok: false;
1428
+ error: GroupRunError;
1429
+ };
1430
+ /** One open connection to a SQLite database.
1431
+ * @public
1432
+ */
1433
+ interface SQLiteConnection {
1434
+ /** Runs one or more statements and returns no rows. */
1435
+ exec(sql: string): Promise<void>;
1436
+ /** Compiles a statement, so that the caller can run it many times. */
1437
+ prepare(sql: string): Promise<SQLiteStatement>;
1438
+ /** Runs a function inside one transaction, committing when it returns and rolling back when it throws. */
1439
+ transaction<T>(fn: (conn: SQLiteConnection) => Promise<T>): Promise<T>;
1440
+ /** Closes the connection. */
1441
+ close(): Promise<void>;
1442
+ /**
1443
+ * Loads a compiled SQLite extension into this connection through the
1444
+ * runtime's own loading function, so that queries on this connection can
1445
+ * call the extension's functions. SQLite registers those functions on the
1446
+ * loading connection alone, so load the extension on every connection that
1447
+ * calls them. When the runtime has no loading function, the returned promise
1448
+ * rejects with an error that names the runtime.
1449
+ */
1450
+ loadExtension?(extensionPath: string): Promise<void>;
1451
+ /**
1452
+ * Copies this connection's database to a file through SQLite's stepped
1453
+ * backup interface, so that writes on this connection can run between
1454
+ * steps. SQLite restarts the copy whenever another connection writes to the
1455
+ * source, so call this method on the writer connection. The driver throws a
1456
+ * `BackupError` when a transaction is open on this connection, because
1457
+ * SQLite would copy no pages and still report success. When the runtime has
1458
+ * no stepped backup function, the method should reject with a
1459
+ * `SirannonError` whose code is `BACKUP_UNSUPPORTED` and whose message names
1460
+ * the runtime, as the Node driver does.
1461
+ */
1462
+ copyDatabase?(request: DatabaseCopyRequest): Promise<DatabaseCopyStep>;
1463
+ /**
1464
+ * `true` when the runtime steps this connection's copy on a thread other
1465
+ * than the caller's. A copy on its own thread can pause until the caller
1466
+ * catches up, while a pause on the caller's thread would block the only
1467
+ * thread.
1468
+ */
1469
+ readonly copyRunsOffCallerThread?: boolean;
1470
+ /** Runs one statement once for each parameter set and returns one result for each set. */
1471
+ runBatch?(sql: string, paramsBatch: readonly unknown[][]): Promise<RunResult[]>;
1472
+ /** Runs one statement once for each parameter set and returns only the totals. */
1473
+ runBatchSummary?(sql: string, paramsBatch: readonly unknown[][]): Promise<BatchSummary>;
1474
+ /**
1475
+ * Runs several independent units in one transaction and returns one outcome
1476
+ * for each unit, in order. A unit is one write or one whole transaction. A
1477
+ * failed unit should leave the other units' writes intact.
1478
+ */
1479
+ runGroup?(units: readonly {
1480
+ statements: readonly {
1481
+ sql: string;
1482
+ params?: readonly unknown[];
1483
+ trusted?: boolean;
1484
+ }[];
1485
+ }[]): Promise<GroupRunOutcome[]>;
1486
+ }
1487
+ /**
1488
+ * The SQLite `PRAGMA synchronous` level for a connection. In WAL mode,
1489
+ * `normal` keeps the database free of corruption, but a power loss can lose
1490
+ * the most recent commits. `full` syncs every commit to disk. `extra` also
1491
+ * syncs the directory after SQLite deletes the rollback journal in DELETE
1492
+ * journal mode, and it behaves like `full` in WAL mode. `off` passes writes to
1493
+ * the operating system without syncing, so use it only for a bulk load that
1494
+ * you can run again.
1495
+ *
1496
+ * @public
1497
+ */
1498
+ type SynchronousLevel = 'off' | 'normal' | 'full' | 'extra';
1499
+ /** Settings with which a driver opens one database file.
1500
+ * @public
1501
+ */
1502
+ interface OpenOptions {
1503
+ /** `true` to open the file for reads only. */
1504
+ readonly?: boolean;
1505
+ /** Puts the database in write-ahead logging mode unless set to `false`. */
1506
+ walMode?: boolean;
1507
+ /** The writer durability level for the connection. */
1508
+ synchronous?: SynchronousLevel;
1509
+ /**
1510
+ * The number of frames in the write-ahead log at which SQLite checkpoints it
1511
+ * automatically. Set it to zero when Sirannon captures the database's own
1512
+ * log, because an automatic checkpoint lets SQLite overwrite frames that the
1513
+ * backup has yet to capture.
1514
+ *
1515
+ * SQLite keeps this setting per connection, so a driver applies it on every
1516
+ * open, including after a writer worker restarts.
1517
+ */
1518
+ walAutoCheckpoint?: number;
1519
+ }
1520
+ /** Describes what a driver's runtime supports.
1521
+ * @public
1522
+ */
1523
+ interface DriverCapabilities {
1524
+ /** `true` when the runtime can open more than one connection to the same file. */
1525
+ multipleConnections: boolean;
1526
+ /** `true` when the runtime can load SQLite extensions. */
1527
+ extensions: boolean;
1528
+ /** `true` when the runtime can copy an open database through SQLite's stepped backup interface. */
1529
+ steppedCopy: boolean;
1530
+ }
1531
+ /**
1532
+ * Describes how a worker thread rebuilds the driver, since a function such as
1533
+ * the driver's `open` cannot pass to another thread. The worker imports
1534
+ * `specifier` and calls the factory named `exportName`, or the default export,
1535
+ * with `config`. `specifier` should be importable from the worker, and
1536
+ * `config` should be a value that `structuredClone` accepts.
1537
+ *
1538
+ * @public
1539
+ */
1540
+ interface DriverWorkerEntry {
1541
+ /** The module that the worker imports to rebuild the driver. */
1542
+ specifier: string;
1543
+ /** The name of the factory export that the worker calls, or the default export when unset. */
1544
+ exportName?: string;
1545
+ /** The value that the worker passes to that factory, which has to be a value that `structuredClone` accepts. */
1546
+ config?: unknown;
1547
+ }
1548
+ /** Describes how Sirannon opens SQLite on one runtime.
1549
+ * @public
1550
+ */
1551
+ interface SQLiteDriver {
1552
+ /** The features that this driver's runtime supports. */
1553
+ readonly capabilities: DriverCapabilities;
1554
+ /** Opens a database file and returns a connection to it. */
1555
+ open(path: string, options?: OpenOptions): Promise<SQLiteConnection>;
1556
+ /** The entry through which a worker thread rebuilds this driver. */
1557
+ readonly worker?: DriverWorkerEntry;
1558
+ /**
1559
+ * Starts a worker thread for writes and returns a connection whose calls run
1560
+ * on that thread. Only a driver whose runtime has threads implements this
1561
+ * method, so a bundle for a runtime without threads leaves out the worker code.
1562
+ */
1563
+ startWriterHost?(path: string, options: OpenOptions, hostOptions?: WorkerHostOptions): Promise<SQLiteConnection>;
1564
+ /** Returns the `WriterContext` that distinguishes the caller holding the writer from a caller waiting for it. */
1565
+ createWriterContext?(): WriterContext;
1566
+ /**
1567
+ * Returns the engine that copies a database to a file. Sirannon passes the
1568
+ * driver back in, so that the engine can open its own connection for a
1569
+ * streamed copy, which loads the extension that moves the bytes.
1570
+ */
1571
+ createBackupEngine?(driver: SQLiteDriver): BackupEngine;
1572
+ /**
1573
+ * Returns an extension path in absolute form. When `load_extension` receives
1574
+ * a bare name, the dynamic linker searches its own paths and can open a
1575
+ * different library from the one that the operator named.
1576
+ */
1577
+ resolveExtensionPath?(extensionPath: string): string;
1578
+ }
1579
+
1580
+ export { type BeforePushHook as $, type AfterQueryHook as A, type BackupDestination as B, DEFAULT_CHAIN_NAME as C, type DatabaseOptions as D, chainLogName as E, readBackupChains as F, verifyBackupRecord as G, type ClusterStatusInfo as H, type SQLiteConnection as I, type BackupFileCopy as J, type BackupRunRequest as K, type BackupScheduleRequest as L, type Migration as M, type NodeHealth as N, type BackupScheduleOptions as O, type DriverCapabilities as P, type BackupEngine as Q, type RunExclusive as R, type SQLiteDriver as S, Transaction as T, type SynchronousLevel as U, type LifecycleConfig as V, type MigrationResult as W, type RollbackResult as X, type AfterQueryHookContext as Y, type AppliedMigrationEntry as Z, type BatchSummary as _, type SirannonOptions as a, type BeforeSnapshotHook as a0, type BeforeSubscribeHook as a1, type CDCMetrics as a2, type ClusterReadEndpointInfo as a3, type ConnectionHookContext as a4, type ConnectionMetrics as a5, type DatabaseCopyRequest as a6, type DatabaseCopyStep as a7, type DriverWorkerEntry as a8, type HookConfig as a9, MIGRATION_NAME_RE as aa, type MetricsConfig as ab, type MigrationBaseline as ac, type MigrationSource as ad, NODE_HEALTH_REASONS as ae, NODE_HEALTH_STATES as af, type NodeHealthReason as ag, type NodeHealthState as ah, type OpenOptions as ai, type QueryHookContext as aj, type QueryMetrics as ak, type RunResult as al, type SQLiteStatement as am, type WriterWorkerOptions as an, type WorkerHostOptions as ao, type WriterContext as ap, type BeforeQueryHook as b, type BeforeConnectHook as c, type DatabaseOpenHook as d, type DatabaseCloseHook as e, type BackupRunReport as f, type BackupChain as g, type BackupChainBase as h, type BackupChainChange as i, type BackupChainPosition as j, type BackupChainRecord as k, BackupCycle as l, type BackupCycleError as m, type BackupCycleOptions as n, type BackupCycleStatus as o, type BackupFileReport as p, type BackupGroupMembership as q, type BackupGroupSource as r, type BackupLogPosition as s, type BackupNodePreference as t, type BackupPiece as u, type BackupProgress as v, type BackupSkip as w, type BackupSkipReason as x, type BackupToDestinationOptions as y, type BackupVerifyResult as z };