@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,317 @@
1
+ import { a as OperationRegistry, D as DatabaseOperations } from './operation-registry-CGhNT-Sn.js';
2
+ import { R as ReplicationBatch, C as ConflictResolver, A as ApplyResult } from './types-DqODKeOq.js';
3
+ import { N as NodeHealth, T as Transaction, H as ClusterStatusInfo } from './types-Dc8oWlxj.js';
4
+ import { P as Params, Q as QueryOptions, E as ExecuteResult } from './query-types-5B02ixH0.js';
5
+
6
+ /**
7
+ * Describes one migration that a database has applied, as the migrations table records it.
8
+ *
9
+ * @public
10
+ */
11
+ interface AppliedMigrationRow {
12
+ /** The migration's version number. */
13
+ version: number;
14
+ /** The migration's name. */
15
+ name: string;
16
+ /** The hash of the migration's `up` SQL, or `null` when a function applied the migration or the row predates checksums. */
17
+ checksum: string | null;
18
+ }
19
+
20
+ /** The request details that the server passes to the authenticate hook.
21
+ * @public
22
+ */
23
+ interface RequestContext {
24
+ /** The request headers, with every name in lower case. */
25
+ headers: Record<string, string>;
26
+ /** The HTTP method of the request, or of the WebSocket upgrade request. */
27
+ method: string;
28
+ /** The URL path of the request. */
29
+ path: string;
30
+ /** The identifier of the database that the route names. */
31
+ databaseId?: string;
32
+ /** The network address of the client that sent the request. */
33
+ remoteAddress: string;
34
+ }
35
+ /**
36
+ * Identifies the caller behind a request. Return the identity, which the
37
+ * server passes to the other hooks and uses to fill the `fromIdentity`
38
+ * arguments of registered operations, or throw a {@link RequestDeniedError} to
39
+ * reject the request with a status of your own.
40
+ *
41
+ * @public
42
+ */
43
+ type AuthenticateHook<Identity = unknown> = (ctx: RequestContext) => Identity | undefined | Promise<Identity | undefined>;
44
+ /** Returns whether a caller may read the addresses of every node in the group.
45
+ * @public
46
+ */
47
+ type ClusterStatusAuthorizer = (ctx: RequestContext) => boolean | Promise<boolean>;
48
+ /**
49
+ * The synchronous level during a bulk load. At 'off', SQLite documents that a
50
+ * power loss or an operating-system crash can corrupt the database, so 'off'
51
+ * suits only a load that the operator can re-run from scratch. At 'normal', a
52
+ * WAL-mode database stays safe from corruption, which suits a load into a
53
+ * database whose existing data the operator must keep.
54
+ *
55
+ * @public
56
+ */
57
+ type BulkLoadDurability = 'off' | 'normal';
58
+ /** The settings for one bulk load.
59
+ * @public
60
+ */
61
+ interface BulkLoadOptions {
62
+ /** The synchronous level during the load; the default is 'off'. */
63
+ durability?: BulkLoadDurability;
64
+ /**
65
+ * Whether this load ends with a WAL checkpoint; the default is true. Set it
66
+ * to false on every load except the last of a multi-batch import, so that the
67
+ * import pays for one fsyncing checkpoint at the end. Sirannon still restores
68
+ * the configured level after each load, so an abandoned import leaves the
69
+ * writer at that level.
70
+ */
71
+ checkpoint?: boolean;
72
+ }
73
+ /** The totals for a bulk load, which Sirannon sums across rows so that a large load keeps no per-row results in memory.
74
+ * @public
75
+ */
76
+ interface BulkLoadResult {
77
+ /** The number of parameter sets that the load applied. */
78
+ rowsLoaded: number;
79
+ /** The number of rows that the load inserted, updated, or deleted. */
80
+ changes: number;
81
+ }
82
+ /**
83
+ * The object that the server executes one database's statements against. A
84
+ * local `Database` fits this interface, and so does a proxy that forwards
85
+ * statements to another node.
86
+ *
87
+ * @public
88
+ */
89
+ interface ServerExecutionTarget {
90
+ /** Executes a read and returns the rows. */
91
+ query<T = Record<string, unknown>>(sql: string, params?: Params, options?: QueryOptions): Promise<T[]>;
92
+ /**
93
+ * Executes a read and returns rows already encoded for the wire, with
94
+ * safe-range integers as plain numbers and larger integers and BLOBs as
95
+ * tagged envelopes. When the target has this method, the server calls it and
96
+ * encodes nothing itself; otherwise the server calls
97
+ * {@link ServerExecutionTarget.query} and encodes the rows in a second pass.
98
+ */
99
+ queryForWire?(sql: string, params?: Params, options?: QueryOptions): Promise<unknown[]>;
100
+ /** Executes one write and returns the change count and the row id of the last inserted row. */
101
+ execute(sql: string, params?: Params, options?: QueryOptions): Promise<ExecuteResult>;
102
+ /** Calls a function inside one transaction. */
103
+ transaction<T>(fn: (tx: Transaction) => Promise<T>, options?: QueryOptions): Promise<T>;
104
+ /**
105
+ * Executes a transaction whose statements are all known before it starts,
106
+ * which lets concurrent transactions share one commit. When the target has no
107
+ * such method, the server calls {@link ServerExecutionTarget.transaction} and
108
+ * executes the statements one at a time.
109
+ */
110
+ executeTransaction?(statements: readonly {
111
+ sql: string;
112
+ params?: Params;
113
+ }[], options?: QueryOptions): Promise<ExecuteResult[]>;
114
+ /**
115
+ * Executes a bulk load. A target that proxies to a remote primary can omit
116
+ * this method, and the server then rejects bulk-load requests for that target
117
+ * with `BULK_LOAD_UNSUPPORTED`.
118
+ */
119
+ bulkLoad?(sql: string, paramsBatch: Params[], options?: BulkLoadOptions): Promise<BulkLoadResult>;
120
+ /** Applies a batch of changes that a device pushed; when the target has no such method, the server rejects device pushes with `SYNC_UNSUPPORTED`. */
121
+ applyChanges?(batch: ReplicationBatch, resolver?: ConflictResolver | ((table: string) => ConflictResolver)): Promise<ApplyResult>;
122
+ /** Lists the migrations that this database has applied. */
123
+ appliedMigrations?(): Promise<AppliedMigrationRow[]>;
124
+ }
125
+ /**
126
+ * Returns the target that the server executes a database's statements
127
+ * against, or null or undefined, to which the server responds with
128
+ * `DATABASE_NOT_FOUND`.
129
+ *
130
+ * @public
131
+ */
132
+ type ServerExecutionTargetResolver = (databaseId: string) => ServerExecutionTarget | null | undefined | Promise<ServerExecutionTarget | null | undefined>;
133
+ /** The options for the standalone HTTP and WebSocket server.
134
+ * @public
135
+ */
136
+ interface ServerOptions<Identity = unknown> {
137
+ /** The address that the server binds to; the default is '127.0.0.1'. */
138
+ host?: string;
139
+ /** The port that the server binds to; the default is 9876. */
140
+ port?: number;
141
+ /** The cross-origin rules that the server applies to browser requests. */
142
+ cors?: boolean | CorsOptions;
143
+ /**
144
+ * The largest HTTP request body and WebSocket message, in bytes, which the
145
+ * server applies to both transports. The value must be a positive integer no
146
+ * larger than 4_294_967_295, the largest limit that uWebSockets.js stores in
147
+ * its unsigned 32-bit field; the server throws `INVALID_MAX_BODY_BYTES` for
148
+ * any other value. The default is 1_048_576 (1 MB), which caps the
149
+ * memory that the server spends on one request.
150
+ */
151
+ maxBodyBytes?: number;
152
+ /**
153
+ * The most bytes that the server buffers for one WebSocket connection before
154
+ * it closes the connection, so that the client learns of the overflow and
155
+ * reconnects. The value must lie between `maxBodyBytes`, so that one frame
156
+ * fits, and 4_294_967_295; the server throws `INVALID_WS_BACKPRESSURE` for
157
+ * any other value. The default is the larger of 16 MB and `maxBodyBytes`.
158
+ */
159
+ maxWebSocketBackpressureBytes?: number;
160
+ /**
161
+ * How long, in milliseconds, Sirannon keeps change events for WebSocket change
162
+ * subscriptions. The retention limits both the size of the change log on disk
163
+ * and how far back a reconnecting subscriber can resume. The default is
164
+ * 3_600_000, one hour.
165
+ */
166
+ cdcRetentionMs?: number;
167
+ /**
168
+ * How long, in milliseconds, Sirannon keeps the changes that a device's sync
169
+ * cursor still needs before it drops the cursor; a database opened with its
170
+ * own `deviceCursorRetention` uses that value. The default is 2_592_000_000,
171
+ * 30 days.
172
+ */
173
+ deviceCursorRetentionMs?: number;
174
+ /**
175
+ * The most changes that Sirannon keeps for one device's cursor before it
176
+ * drops the cursor; a database opened with its own `maxChangesHeldForDevice`
177
+ * uses that value. 0 sets no limit, and the default is 0.
178
+ */
179
+ maxChangesHeldForDevice?: number;
180
+ /** The number of changes that a device may leave unacknowledged before the server pauses sending more; the default is 1_000. */
181
+ maxUnacknowledgedChanges?: number;
182
+ /** The server calls this before every database route and every WebSocket upgrade, to identify the caller. */
183
+ authenticate?: AuthenticateHook<Identity>;
184
+ /** The statements that callers may invoke by name on one database, keyed by database identifier; with neither this nor `sharedOperations` set, only the SQL routes serve reads and writes. */
185
+ operations?: OperationRegistry<Identity>;
186
+ /**
187
+ * The statements that callers may invoke by name on every database that this
188
+ * server serves, including a database that the registry opens after the
189
+ * server starts. When `operations` has an entry of the same name for that
190
+ * database, the server executes that entry.
191
+ */
192
+ sharedOperations?: DatabaseOperations<Identity>;
193
+ /** Enables the five statement routes and their WebSocket messages, and WebSocket subscriptions to a table's changes on a registry without an `onBeforeSubscribe` hook; the default is false. */
194
+ acceptSql?: boolean;
195
+ /**
196
+ * Enables the route that rebuilds a database from its backups; the default is
197
+ * false. A restore replaces a database that is serving traffic, so the server
198
+ * keeps the route closed until you enable it here, and the server constructor
199
+ * throws `INVALID_BACKUP_RESTORE` when you enable it without an `authenticate`
200
+ * hook.
201
+ */
202
+ acceptBackupRestore?: boolean;
203
+ /** Enables device sync, which covers the push, snapshot, and migration-list routes, device subscriptions, and acknowledgements; the default is false. The server constructor throws `INVALID_DEVICE_SYNC` when you enable it without an `authenticate` hook. */
204
+ acceptDeviceSync?: boolean;
205
+ /** Returns the target that the server executes a database's statements against; without it, the server uses the databases in its own registry. */
206
+ resolveExecutionTarget?: ServerExecutionTargetResolver;
207
+ /** Returns the replication figures that the readiness endpoint reports. */
208
+ getReplicationStatus?: () => ReplicationStatusInfo | null;
209
+ /** Returns the status that `GET /db/{id}/cluster` reports for one database. */
210
+ getClusterStatus?: (databaseId: string) => ClusterStatusInfo | null;
211
+ /** Returns whether a caller may read the addresses of every node in the group. */
212
+ authorizeClusterStatus?: ClusterStatusAuthorizer;
213
+ }
214
+ /** The replication figures that one node reports through its readiness endpoint.
215
+ * @public
216
+ */
217
+ interface ReplicationStatusInfo {
218
+ /** The node's role in the replication group, which sets whether it accepts writes or serves reads. */
219
+ role: string;
220
+ /** Whether this node forwards writes to the primary. */
221
+ writeForwarding: boolean;
222
+ /** The number of peers that the node is connected to. */
223
+ peers: number;
224
+ /** The highest change-log position that this node has recorded locally. */
225
+ localSeq: bigint;
226
+ /** What the node can do now, and the reason for that state. */
227
+ health: NodeHealth;
228
+ /** The identifier of the node's replication group. */
229
+ replicationGroupId?: string;
230
+ /** The primary term that this node reports as current. */
231
+ primaryTerm?: bigint;
232
+ /** The identifier of the primary that this node reports as current. */
233
+ currentPrimary?: string;
234
+ /** Whether the node is connected to its cluster coordinator, and whether it holds write authority. */
235
+ coordinator?: {
236
+ connected: boolean;
237
+ authority: boolean;
238
+ };
239
+ /** The state of this node's controller loop for the group. */
240
+ controller?: {
241
+ state: 'disabled' | 'standby' | 'active' | 'lost';
242
+ };
243
+ /** The identifiers of the replicas that the group counts as in sync. */
244
+ inSyncReplicas?: string[];
245
+ /** The identifiers of the replicas that are behind the primary. */
246
+ laggingReplicas?: string[];
247
+ /** The node's progress through its first sync. */
248
+ syncState?: string;
249
+ }
250
+ /** The cross-origin (CORS) settings for the server.
251
+ * @public
252
+ */
253
+ interface CorsOptions {
254
+ /** The origins that the server allows. */
255
+ origin?: string | string[];
256
+ /** The methods that the server allows. */
257
+ methods?: string[];
258
+ /** The request headers that the server allows. */
259
+ headers?: string[];
260
+ }
261
+ /**
262
+ * The options for the mountable WebSocket handler.
263
+ *
264
+ * @internal
265
+ */
266
+ interface WSHandlerOptions<Identity = unknown> {
267
+ /** The largest message, in bytes; the default is 1_048_576 (1 MB). */
268
+ maxPayloadLength?: number;
269
+ /** The outbound bytes that a socket may buffer before the server pauses a device stream; the default is 16 MB. */
270
+ maxBackpressureBytes?: number;
271
+ /** The change-log retention for change subscriptions, in milliseconds; the default is 3_600_000. */
272
+ cdcRetentionMs?: number;
273
+ deviceCursorRetentionMs?: number;
274
+ maxChangesHeldForDevice?: number;
275
+ maxUnacknowledgedChanges?: number;
276
+ acceptSql?: boolean;
277
+ acceptDeviceSync?: boolean;
278
+ operations?: OperationRegistry<Identity>;
279
+ sharedOperations?: DatabaseOperations<Identity>;
280
+ resolveExecutionTarget?: ServerExecutionTargetResolver;
281
+ }
282
+ /** The options for the client SDK.
283
+ * @public
284
+ */
285
+ interface ClientOptions {
286
+ /** The transport to use; the default is 'websocket'. */
287
+ transport?: 'websocket' | 'http';
288
+ /**
289
+ * Custom headers for HTTP requests, and for the WebSocket upgrade in a
290
+ * runtime whose WebSocket client can send handshake headers, as Node and Bun
291
+ * can and a browser cannot. In a runtime without that ability, constructing a
292
+ * WebSocket-transport client with headers and no
293
+ * {@link ClientOptions.webSocketProtocols} fails with `INVALID_ARGUMENT`. A
294
+ * browser client can pass both, and the client still sends the headers on
295
+ * every HTTP request.
296
+ */
297
+ headers?: Record<string, string>;
298
+ /**
299
+ * The WebSocket subprotocols that the client offers during the handshake,
300
+ * which let a browser send a short-lived credential. The client also offers
301
+ * the `sirannon.v1` identifier, and the server selects that identifier, so the
302
+ * handshake response names `sirannon.v1` and leaves the credential out.
303
+ */
304
+ webSocketProtocols?: string | string[];
305
+ /** Whether the client reconnects when the WebSocket disconnects; the default is true. */
306
+ autoReconnect?: boolean;
307
+ /** The delay before each reconnection attempt, in milliseconds; the default is 1000. */
308
+ reconnectInterval?: number;
309
+ /**
310
+ * The timeout for each request on the WebSocket transport, in milliseconds;
311
+ * the default is 30000, and 0 waits with no limit. Raise it for a bulk load or
312
+ * a batch large enough to take longer than the timeout.
313
+ */
314
+ requestTimeout?: number;
315
+ }
316
+
317
+ export type { AppliedMigrationRow as A, BulkLoadDurability as B, ClientOptions as C, RequestContext as R, ServerOptions as S, WSHandlerOptions as W, BulkLoadResult as a, AuthenticateHook as b, BulkLoadOptions as c, ClusterStatusAuthorizer as d, CorsOptions as e, ReplicationStatusInfo as f, ServerExecutionTarget as g, ServerExecutionTargetResolver as h };
@@ -0,0 +1,254 @@
1
+ import { SERVICE_NAME } from './chunk-BVMZJOVM.mjs';
2
+ import { ReplicationService, buildServerCreds } from './chunk-4KASJKKK.mjs';
3
+ import { registerPeer, removePeer } from './chunk-HR7K3GZW.mjs';
4
+ import { fromForwardRequest, fromBatchPayload, fromAckPayload, fromSyncRequestPayload, fromSyncBatchPayload, fromSyncCompletePayload, fromSyncAckPayload } from './chunk-ADNWEHGZ.mjs';
5
+ import { TransportError } from './chunk-KU32OT4H.mjs';
6
+ import './chunk-BLMRNSUG.mjs';
7
+ import { SirannonError } from './chunk-KINDFBQP.mjs';
8
+ import { Server, status } from '@grpc/grpc-js';
9
+ import { HealthImplementation } from 'grpc-health-check';
10
+
11
+ async function startServer(t) {
12
+ const server = new Server();
13
+ t.server = server;
14
+ const healthImpl = new HealthImplementation({
15
+ [SERVICE_NAME]: "SERVING",
16
+ "": "SERVING"
17
+ });
18
+ healthImpl.addToServer(server);
19
+ t.healthImpl = healthImpl;
20
+ server.addService(ReplicationService, {
21
+ replicate: (call) => {
22
+ handleServerReplicateStream(t, call);
23
+ },
24
+ sync: (call) => {
25
+ handleServerSyncStream(t, call);
26
+ },
27
+ forward: (call, callback) => {
28
+ handleForwardCall(t, call, callback);
29
+ }
30
+ });
31
+ const host = t.options.host ?? "0.0.0.0";
32
+ const port = t.options.port ?? 0;
33
+ const bindAddress = `${host}:${port}`;
34
+ const serverCreds = buildServerCreds(t.options);
35
+ await new Promise((resolve, reject) => {
36
+ server.bindAsync(bindAddress, serverCreds, (err, assignedPort) => {
37
+ if (err) {
38
+ reject(new TransportError(`Failed to bind gRPC server: ${err.message}`));
39
+ return;
40
+ }
41
+ t.boundPort = assignedPort;
42
+ resolve();
43
+ });
44
+ });
45
+ }
46
+ function handleServerReplicateStream(t, call) {
47
+ let peerId = null;
48
+ let helloSent = false;
49
+ call.on("data", (msg) => {
50
+ if (peerId === null) {
51
+ if (!msg.hello) {
52
+ call.destroy(new Error("First message must be Hello"));
53
+ return;
54
+ }
55
+ if (!t.validateTlsIdentity(call, msg.hello.nodeId)) {
56
+ call.destroy(new Error(`TLS certificate CN does not match claimed nodeId '${msg.hello.nodeId}'`));
57
+ return;
58
+ }
59
+ peerId = msg.hello.nodeId;
60
+ const peerRole = msg.hello.role;
61
+ const existing = t.serverPeerStreams.get(peerId);
62
+ if (existing?.replicateStream) {
63
+ existing.replicateStream.end();
64
+ }
65
+ const ps = t.serverPeerStreams.get(peerId) ?? {
66
+ replicateStream: null,
67
+ syncStream: null
68
+ };
69
+ ps.replicateStream = call;
70
+ t.serverPeerStreams.set(peerId, ps);
71
+ if (!helloSent) {
72
+ call.write({
73
+ hello: {
74
+ nodeId: t.localNodeId,
75
+ role: t.localRole,
76
+ groupId: t.localGroupId ?? "",
77
+ primaryTerm: t.localPrimaryTerm ?? 0n,
78
+ protocolVersion: t.localProtocolVersion ?? ""
79
+ }
80
+ });
81
+ helloSent = true;
82
+ }
83
+ registerPeer(t.connectedPeers, t.peerConnectedHandler, peerId, peerRole, {
84
+ groupId: msg.hello.groupId || void 0,
85
+ primaryTerm: msg.hello.primaryTerm === 0n ? void 0 : msg.hello.primaryTerm,
86
+ protocolVersion: msg.hello.protocolVersion || void 0
87
+ });
88
+ return;
89
+ }
90
+ if (msg.batch) {
91
+ const batch = fromBatchPayload(msg.batch);
92
+ t.batchHandler?.(batch, peerId).catch(() => {
93
+ });
94
+ } else if (msg.ack) {
95
+ const ack = fromAckPayload(msg.ack);
96
+ t.ackHandler?.(ack, peerId);
97
+ }
98
+ });
99
+ call.on("end", () => {
100
+ call.end();
101
+ if (peerId) {
102
+ const ps = t.serverPeerStreams.get(peerId);
103
+ if (ps?.replicateStream === call) {
104
+ ps.replicateStream = null;
105
+ }
106
+ if (!ps?.syncStream) {
107
+ removePeer(t.connectedPeers, t.serverPeerStreams, t.peerDisconnectedHandler, peerId);
108
+ }
109
+ }
110
+ });
111
+ call.on("error", () => {
112
+ if (peerId) {
113
+ const ps = t.serverPeerStreams.get(peerId);
114
+ if (ps?.replicateStream === call) {
115
+ ps.replicateStream = null;
116
+ }
117
+ if (!ps?.syncStream) {
118
+ removePeer(t.connectedPeers, t.serverPeerStreams, t.peerDisconnectedHandler, peerId);
119
+ }
120
+ }
121
+ });
122
+ }
123
+ function handleServerSyncStream(t, call) {
124
+ let peerId = null;
125
+ let helloSent = false;
126
+ call.on("data", (msg) => {
127
+ if (peerId === null) {
128
+ if (!msg.hello) {
129
+ call.destroy(new Error("First message must be Hello"));
130
+ return;
131
+ }
132
+ if (!t.validateTlsIdentity(call, msg.hello.nodeId)) {
133
+ call.destroy(new Error(`TLS certificate CN does not match claimed nodeId '${msg.hello.nodeId}'`));
134
+ return;
135
+ }
136
+ peerId = msg.hello.nodeId;
137
+ const peerRole = msg.hello.role;
138
+ const existing = t.serverPeerStreams.get(peerId);
139
+ if (existing?.syncStream) {
140
+ existing.syncStream.end();
141
+ }
142
+ const ps = t.serverPeerStreams.get(peerId) ?? {
143
+ replicateStream: null,
144
+ syncStream: null
145
+ };
146
+ ps.syncStream = call;
147
+ t.serverPeerStreams.set(peerId, ps);
148
+ if (!helloSent) {
149
+ call.write({
150
+ hello: {
151
+ nodeId: t.localNodeId,
152
+ role: t.localRole,
153
+ groupId: t.localGroupId ?? "",
154
+ primaryTerm: t.localPrimaryTerm ?? 0n,
155
+ protocolVersion: t.localProtocolVersion ?? ""
156
+ }
157
+ });
158
+ helloSent = true;
159
+ }
160
+ registerPeer(t.connectedPeers, t.peerConnectedHandler, peerId, peerRole, {
161
+ groupId: msg.hello.groupId || void 0,
162
+ primaryTerm: msg.hello.primaryTerm === 0n ? void 0 : msg.hello.primaryTerm,
163
+ protocolVersion: msg.hello.protocolVersion || void 0
164
+ });
165
+ return;
166
+ }
167
+ if (msg.syncRequest) {
168
+ t.syncRequestHandler?.(fromSyncRequestPayload(msg.syncRequest), peerId).catch(() => {
169
+ });
170
+ } else if (msg.syncBatch) {
171
+ t.syncBatchHandler?.(fromSyncBatchPayload(msg.syncBatch), peerId).catch(() => {
172
+ });
173
+ } else if (msg.syncComplete) {
174
+ t.syncCompleteHandler?.(fromSyncCompletePayload(msg.syncComplete), peerId).catch(() => {
175
+ });
176
+ } else if (msg.syncAck) {
177
+ t.syncAckHandler?.(fromSyncAckPayload(msg.syncAck), peerId);
178
+ }
179
+ });
180
+ call.on("end", () => {
181
+ call.end();
182
+ if (peerId) {
183
+ const ps = t.serverPeerStreams.get(peerId);
184
+ if (ps?.syncStream === call) {
185
+ ps.syncStream = null;
186
+ }
187
+ if (!ps?.replicateStream) {
188
+ removePeer(t.connectedPeers, t.serverPeerStreams, t.peerDisconnectedHandler, peerId);
189
+ }
190
+ }
191
+ });
192
+ call.on("error", () => {
193
+ if (peerId) {
194
+ const ps = t.serverPeerStreams.get(peerId);
195
+ if (ps?.syncStream === call) {
196
+ ps.syncStream = null;
197
+ }
198
+ if (!ps?.replicateStream) {
199
+ removePeer(t.connectedPeers, t.serverPeerStreams, t.peerDisconnectedHandler, peerId);
200
+ }
201
+ }
202
+ });
203
+ }
204
+ function handleForwardCall(t, call, callback) {
205
+ if (!t.forwardHandler) {
206
+ callback({
207
+ code: status.UNIMPLEMENTED,
208
+ message: "Forward handler not registered"
209
+ });
210
+ return;
211
+ }
212
+ const peerId = t.resolveForwardPeerId(call);
213
+ if (!peerId) {
214
+ callback({
215
+ code: status.UNAUTHENTICATED,
216
+ message: "Forward request from unidentified peer"
217
+ });
218
+ return;
219
+ }
220
+ let appReq;
221
+ try {
222
+ appReq = fromForwardRequest(call.request);
223
+ } catch (err) {
224
+ callback({
225
+ code: status.INVALID_ARGUMENT,
226
+ message: err instanceof Error ? err.message : String(err)
227
+ });
228
+ return;
229
+ }
230
+ t.forwardHandler(appReq, peerId).then((result) => {
231
+ callback(null, {
232
+ requestId: result.requestId,
233
+ results: result.results.map((r) => ({
234
+ changes: r.changes,
235
+ lastInsertRowId: BigInt(typeof r.lastInsertRowId === "string" ? r.lastInsertRowId : r.lastInsertRowId)
236
+ })),
237
+ error: "",
238
+ errorCode: "",
239
+ groupId: result.groupId ?? "",
240
+ primaryTerm: result.primaryTerm ?? 0n
241
+ });
242
+ }).catch((err) => {
243
+ callback(null, {
244
+ requestId: call.request.requestId,
245
+ results: [],
246
+ error: err.message,
247
+ errorCode: err instanceof SirannonError ? err.code : "",
248
+ groupId: call.request.groupId ?? "",
249
+ primaryTerm: call.request.primaryTerm ?? 0n
250
+ });
251
+ });
252
+ }
253
+
254
+ export { handleForwardCall, handleServerReplicateStream, handleServerSyncStream, startServer };