@zvndev/powdb-client 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * A tiny connection pool for the PowDB TypeScript client.
3
+ *
4
+ * const pool = new Pool({ host, port, max: 8 });
5
+ *
6
+ * // manual acquire/release
7
+ * const c = await pool.acquire();
8
+ * try {
9
+ * await c.query("...");
10
+ * pool.release(c);
11
+ * } catch (err) {
12
+ * // a broken client should NOT be returned to the pool
13
+ * pool.destroy(c);
14
+ * throw err;
15
+ * }
16
+ *
17
+ * // ...or, preferred, use the scoped helper:
18
+ * const users = await pool.withClient((c) => c.query("Users"));
19
+ *
20
+ * await pool.close();
21
+ */
22
+ import { Client, type ClientOptions, type QueryResult, type ScriptStatementOutcome } from "./index.js";
23
+ export interface PoolOptions extends ClientOptions {
24
+ /** Maximum concurrent clients. Default 10. */
25
+ max?: number;
26
+ /** Acquire timeout in ms. Default 30_000. */
27
+ acquireTimeoutMs?: number;
28
+ /**
29
+ * How many times to retry `Client.connect` on transient errors
30
+ * (connect_failed / timeout). Auth failures and other non-transient
31
+ * errors are never retried. Default 3. Set to 0 to disable.
32
+ */
33
+ connectRetries?: number;
34
+ /**
35
+ * Initial backoff (ms) between connect retries. Each subsequent retry
36
+ * doubles the delay up to `connectMaxBackoffMs`. Default 100.
37
+ */
38
+ connectBackoffMs?: number;
39
+ /** Maximum backoff (ms) between connect retries. Default 2_000. */
40
+ connectMaxBackoffMs?: number;
41
+ }
42
+ /**
43
+ * Lazy, FIFO connection pool.
44
+ *
45
+ * Semantics:
46
+ * - `acquire` returns an idle client if one exists; otherwise creates a new
47
+ * one up to `max`; otherwise waits until `release`/`destroy` frees a slot
48
+ * (subject to `acquireTimeoutMs`).
49
+ * - `release(c)` puts `c` back in the idle queue unconditionally. **If the
50
+ * caller observed a socket/connection error on `c`, they MUST call
51
+ * `destroy(c)` instead** — the pool cannot safely detect dead sockets.
52
+ * - `destroy(c)` closes `c` and decrements the live count, freeing a slot
53
+ * for a new client to be created.
54
+ * - `withClient(fn)` acquires, runs `fn`, and always destroys on error or
55
+ * releases on success. This is the safe default for most call sites.
56
+ * - `close()` rejects any pending waiters and awaits `close()` on every
57
+ * idle client. Subsequent calls to `acquire` reject immediately.
58
+ */
59
+ export declare class Pool {
60
+ private readonly opts;
61
+ private readonly max;
62
+ private readonly acquireTimeoutMs;
63
+ private readonly connectRetries;
64
+ private readonly connectBackoffMs;
65
+ private readonly connectMaxBackoffMs;
66
+ private readonly idleClients;
67
+ private readonly waiters;
68
+ /** Clients owned by this pool (idle + checked-out). Used to reject
69
+ * foreign/double-destroyed clients from corrupting the slot accounting. */
70
+ private readonly owned;
71
+ private live;
72
+ private _closed;
73
+ constructor(opts: PoolOptions);
74
+ /**
75
+ * Wraps Client.connect with the pool's configured retry policy. Used by
76
+ * `acquire` and `drainWaiters`.
77
+ */
78
+ private connect;
79
+ /** Live client count (idle + checked out). */
80
+ get size(): number;
81
+ /** Clients currently sitting in the idle queue. */
82
+ get idle(): number;
83
+ /** `true` once {@link close} has been called. */
84
+ get closed(): boolean;
85
+ /**
86
+ * Acquire a client from the pool.
87
+ *
88
+ * Resolves with an idle client if one is available, creates a new one if
89
+ * `live < max`, or waits in a FIFO queue. Rejects if `acquireTimeoutMs`
90
+ * elapses, or if the pool is closed.
91
+ */
92
+ acquire(): Promise<Client>;
93
+ /**
94
+ * Return `c` to the idle queue so subsequent `acquire` calls can hand it
95
+ * out. If the pool is closed, `c` is closed instead.
96
+ *
97
+ * **Do not call this if `c` has experienced a connection error** — use
98
+ * {@link destroy} for that case.
99
+ */
100
+ release(c: Client): void;
101
+ /**
102
+ * Close `c` and free its slot so a new client can be created on the next
103
+ * `acquire`. Use this when `c` has hit a socket error or is otherwise
104
+ * known-bad.
105
+ */
106
+ destroy(c: Client): void;
107
+ /**
108
+ * Acquire a client, run `fn`, and either release (on success) or destroy
109
+ * (on error). This is the recommended call site — it makes it impossible
110
+ * to leak a client on an unhandled exception.
111
+ */
112
+ withClient<T>(fn: (c: Client) => Promise<T>): Promise<T>;
113
+ /**
114
+ * Run a multi-statement PowQL script on ONE pooled connection, pipelined.
115
+ *
116
+ * Checks out a single client for the whole script (statement order —
117
+ * and `transactional: true` — therefore holds), delegates to
118
+ * {@link Client.execScript}, and releases the client on success or
119
+ * destroys it on error — same lifecycle as {@link withClient}.
120
+ */
121
+ execScript(script: string, opts?: {
122
+ continueOnError?: false;
123
+ transactional?: boolean;
124
+ signal?: AbortSignal;
125
+ }): Promise<QueryResult[]>;
126
+ execScript(script: string, opts: {
127
+ continueOnError: true;
128
+ signal?: AbortSignal;
129
+ }): Promise<ScriptStatementOutcome[]>;
130
+ /**
131
+ * Close the pool. Rejects all pending waiters, awaits `close()` on every
132
+ * idle client, and marks the pool closed. Subsequent `acquire` calls
133
+ * reject immediately.
134
+ *
135
+ * Checked-out clients are NOT tracked — callers that still hold one when
136
+ * `close()` is called are responsible for closing it themselves.
137
+ */
138
+ close(): Promise<void>;
139
+ private drainWaiters;
140
+ }
@@ -0,0 +1,335 @@
1
+ "use strict";
2
+ /**
3
+ * A tiny connection pool for the PowDB TypeScript client.
4
+ *
5
+ * const pool = new Pool({ host, port, max: 8 });
6
+ *
7
+ * // manual acquire/release
8
+ * const c = await pool.acquire();
9
+ * try {
10
+ * await c.query("...");
11
+ * pool.release(c);
12
+ * } catch (err) {
13
+ * // a broken client should NOT be returned to the pool
14
+ * pool.destroy(c);
15
+ * throw err;
16
+ * }
17
+ *
18
+ * // ...or, preferred, use the scoped helper:
19
+ * const users = await pool.withClient((c) => c.query("Users"));
20
+ *
21
+ * await pool.close();
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.Pool = void 0;
25
+ const index_js_1 = require("./index.js");
26
+ const errors_js_1 = require("./errors.js");
27
+ /**
28
+ * Is this error worth retrying? Only the transient connect-phase errors
29
+ * are retryable. Auth failures, size violations, aborts, and protocol
30
+ * errors are not — retrying would just fail the same way.
31
+ */
32
+ function isRetryable(err) {
33
+ if (!(0, errors_js_1.isPowDBError)(err)) {
34
+ // Raw socket errors surface as generic Error before we wrap them in
35
+ // connect_failed. In practice connect() wraps them, but be defensive.
36
+ return err instanceof Error;
37
+ }
38
+ return err.code === "connect_failed" || err.code === "timeout";
39
+ }
40
+ function sleep(ms) {
41
+ return new Promise((resolve) => {
42
+ const t = setTimeout(resolve, ms);
43
+ if (typeof t.unref === "function")
44
+ t.unref();
45
+ });
46
+ }
47
+ /**
48
+ * Connect to the server with bounded retry + exponential backoff. Throws
49
+ * the last error if every attempt fails, or the first error unchanged if
50
+ * it was not retryable.
51
+ */
52
+ async function connectWithRetry(opts, retries, initialBackoffMs, maxBackoffMs) {
53
+ let lastErr;
54
+ let delay = initialBackoffMs;
55
+ for (let attempt = 0; attempt <= retries; attempt++) {
56
+ try {
57
+ return await index_js_1.Client.connect(opts);
58
+ }
59
+ catch (err) {
60
+ lastErr = err;
61
+ if (!isRetryable(err) || attempt === retries)
62
+ break;
63
+ await sleep(delay);
64
+ delay = Math.min(delay * 2, maxBackoffMs);
65
+ }
66
+ }
67
+ throw lastErr;
68
+ }
69
+ /**
70
+ * Lazy, FIFO connection pool.
71
+ *
72
+ * Semantics:
73
+ * - `acquire` returns an idle client if one exists; otherwise creates a new
74
+ * one up to `max`; otherwise waits until `release`/`destroy` frees a slot
75
+ * (subject to `acquireTimeoutMs`).
76
+ * - `release(c)` puts `c` back in the idle queue unconditionally. **If the
77
+ * caller observed a socket/connection error on `c`, they MUST call
78
+ * `destroy(c)` instead** — the pool cannot safely detect dead sockets.
79
+ * - `destroy(c)` closes `c` and decrements the live count, freeing a slot
80
+ * for a new client to be created.
81
+ * - `withClient(fn)` acquires, runs `fn`, and always destroys on error or
82
+ * releases on success. This is the safe default for most call sites.
83
+ * - `close()` rejects any pending waiters and awaits `close()` on every
84
+ * idle client. Subsequent calls to `acquire` reject immediately.
85
+ */
86
+ class Pool {
87
+ opts;
88
+ max;
89
+ acquireTimeoutMs;
90
+ connectRetries;
91
+ connectBackoffMs;
92
+ connectMaxBackoffMs;
93
+ idleClients = [];
94
+ waiters = [];
95
+ /** Clients owned by this pool (idle + checked-out). Used to reject
96
+ * foreign/double-destroyed clients from corrupting the slot accounting. */
97
+ owned = new Set();
98
+ live = 0;
99
+ _closed = false;
100
+ constructor(opts) {
101
+ const { max = 10, acquireTimeoutMs = 30_000, connectRetries = 3, connectBackoffMs = 100, connectMaxBackoffMs = 2_000, ...clientOpts } = opts;
102
+ if (!Number.isFinite(max) || max < 1) {
103
+ throw new TypeError(`Pool: max must be a positive integer, got ${max}`);
104
+ }
105
+ if (!Number.isFinite(acquireTimeoutMs) || acquireTimeoutMs < 0) {
106
+ throw new TypeError(`Pool: acquireTimeoutMs must be a non-negative number, got ${acquireTimeoutMs}`);
107
+ }
108
+ if (!Number.isFinite(connectRetries) || connectRetries < 0) {
109
+ throw new TypeError(`Pool: connectRetries must be a non-negative integer, got ${connectRetries}`);
110
+ }
111
+ this.opts = clientOpts;
112
+ this.max = max;
113
+ this.acquireTimeoutMs = acquireTimeoutMs;
114
+ this.connectRetries = connectRetries;
115
+ this.connectBackoffMs = connectBackoffMs;
116
+ this.connectMaxBackoffMs = connectMaxBackoffMs;
117
+ }
118
+ /**
119
+ * Wraps Client.connect with the pool's configured retry policy. Used by
120
+ * `acquire` and `drainWaiters`.
121
+ */
122
+ connect() {
123
+ return connectWithRetry(this.opts, this.connectRetries, this.connectBackoffMs, this.connectMaxBackoffMs);
124
+ }
125
+ /** Live client count (idle + checked out). */
126
+ get size() {
127
+ return this.live;
128
+ }
129
+ /** Clients currently sitting in the idle queue. */
130
+ get idle() {
131
+ return this.idleClients.length;
132
+ }
133
+ /** `true` once {@link close} has been called. */
134
+ get closed() {
135
+ return this._closed;
136
+ }
137
+ /**
138
+ * Acquire a client from the pool.
139
+ *
140
+ * Resolves with an idle client if one is available, creates a new one if
141
+ * `live < max`, or waits in a FIFO queue. Rejects if `acquireTimeoutMs`
142
+ * elapses, or if the pool is closed.
143
+ */
144
+ async acquire() {
145
+ if (this._closed) {
146
+ throw new Error("pool closed");
147
+ }
148
+ const existing = this.idleClients.shift();
149
+ if (existing !== undefined) {
150
+ return existing;
151
+ }
152
+ if (this.live < this.max) {
153
+ this.live++;
154
+ try {
155
+ const c = await this.connect();
156
+ this.owned.add(c);
157
+ return c;
158
+ }
159
+ catch (err) {
160
+ // Creation failed — we never had a live client, so give the slot
161
+ // back and propagate.
162
+ this.live--;
163
+ // A newly-freed slot may let a pending waiter try again... but only
164
+ // via a future release/destroy. To be fair to waiters, schedule a
165
+ // drain here.
166
+ this.drainWaiters();
167
+ throw err;
168
+ }
169
+ }
170
+ return new Promise((resolve, reject) => {
171
+ const waiter = {
172
+ resolve,
173
+ reject,
174
+ timer: null,
175
+ };
176
+ if (this.acquireTimeoutMs > 0) {
177
+ waiter.timer = setTimeout(() => {
178
+ const idx = this.waiters.indexOf(waiter);
179
+ if (idx !== -1)
180
+ this.waiters.splice(idx, 1);
181
+ reject(new Error("pool acquire timeout"));
182
+ }, this.acquireTimeoutMs);
183
+ // Don't keep the event loop alive just for the timeout.
184
+ if (typeof waiter.timer.unref === "function")
185
+ waiter.timer.unref();
186
+ }
187
+ this.waiters.push(waiter);
188
+ });
189
+ }
190
+ /**
191
+ * Return `c` to the idle queue so subsequent `acquire` calls can hand it
192
+ * out. If the pool is closed, `c` is closed instead.
193
+ *
194
+ * **Do not call this if `c` has experienced a connection error** — use
195
+ * {@link destroy} for that case.
196
+ */
197
+ release(c) {
198
+ if (!this.owned.has(c)) {
199
+ // Foreign client or already-destroyed — refuse to touch accounting.
200
+ return;
201
+ }
202
+ if (this._closed) {
203
+ // Pool is gone — just close the client, fire-and-forget.
204
+ this.owned.delete(c);
205
+ if (this.live > 0)
206
+ this.live--;
207
+ void c.close().catch(() => { });
208
+ return;
209
+ }
210
+ const waiter = this.waiters.shift();
211
+ if (waiter !== undefined) {
212
+ if (waiter.timer !== null)
213
+ clearTimeout(waiter.timer);
214
+ waiter.resolve(c);
215
+ return;
216
+ }
217
+ this.idleClients.push(c);
218
+ }
219
+ /**
220
+ * Close `c` and free its slot so a new client can be created on the next
221
+ * `acquire`. Use this when `c` has hit a socket error or is otherwise
222
+ * known-bad.
223
+ */
224
+ destroy(c) {
225
+ if (!this.owned.has(c)) {
226
+ // Foreign client or already destroyed — don't touch slot accounting.
227
+ return;
228
+ }
229
+ this.owned.delete(c);
230
+ // Decrement first so any waiter we hand off to can create a fresh one.
231
+ if (this.live > 0)
232
+ this.live--;
233
+ void c.close().catch(() => { });
234
+ if (this._closed)
235
+ return;
236
+ // Drain one waiter if possible — the freed slot lets them create a new
237
+ // connection.
238
+ this.drainWaiters();
239
+ }
240
+ /**
241
+ * Acquire a client, run `fn`, and either release (on success) or destroy
242
+ * (on error). This is the recommended call site — it makes it impossible
243
+ * to leak a client on an unhandled exception.
244
+ */
245
+ async withClient(fn) {
246
+ const c = await this.acquire();
247
+ try {
248
+ const out = await fn(c);
249
+ this.release(c);
250
+ return out;
251
+ }
252
+ catch (err) {
253
+ this.destroy(c);
254
+ throw err;
255
+ }
256
+ }
257
+ async execScript(script, opts) {
258
+ if (opts?.continueOnError === true) {
259
+ return this.withClient((c) => c.execScript(script, {
260
+ continueOnError: true,
261
+ ...(opts.transactional !== undefined
262
+ ? { transactional: opts.transactional }
263
+ : {}),
264
+ ...(opts.signal ? { signal: opts.signal } : {}),
265
+ }));
266
+ }
267
+ return this.withClient((c) => c.execScript(script, {
268
+ ...(opts?.transactional !== undefined
269
+ ? { transactional: opts.transactional }
270
+ : {}),
271
+ ...(opts?.signal ? { signal: opts.signal } : {}),
272
+ }));
273
+ }
274
+ /**
275
+ * Close the pool. Rejects all pending waiters, awaits `close()` on every
276
+ * idle client, and marks the pool closed. Subsequent `acquire` calls
277
+ * reject immediately.
278
+ *
279
+ * Checked-out clients are NOT tracked — callers that still hold one when
280
+ * `close()` is called are responsible for closing it themselves.
281
+ */
282
+ async close() {
283
+ if (this._closed)
284
+ return;
285
+ this._closed = true;
286
+ // Reject every pending waiter.
287
+ while (this.waiters.length > 0) {
288
+ const w = this.waiters.shift();
289
+ if (w.timer !== null)
290
+ clearTimeout(w.timer);
291
+ w.reject(new Error("pool closed"));
292
+ }
293
+ // Close every idle client.
294
+ const idle = this.idleClients.splice(0, this.idleClients.length);
295
+ for (const c of idle)
296
+ this.owned.delete(c);
297
+ this.live -= idle.length;
298
+ await Promise.all(idle.map((c) => c.close().catch(() => { })));
299
+ }
300
+ // ──────────────────────────────────────────────────────────
301
+ // internals
302
+ // ──────────────────────────────────────────────────────────
303
+ drainWaiters() {
304
+ // If we have headroom AND a waiter, try to create a client for them.
305
+ // (Handles the "acquire failed → slot freed" path cleanly without
306
+ // forcing the caller to re-poll.)
307
+ if (this._closed)
308
+ return;
309
+ while (this.waiters.length > 0 && this.live < this.max) {
310
+ const waiter = this.waiters.shift();
311
+ if (waiter.timer !== null)
312
+ clearTimeout(waiter.timer);
313
+ this.live++;
314
+ this.connect().then((c) => {
315
+ // Pool may have been closed while the connect was in flight.
316
+ // If so, close the freshly-opened client instead of handing it
317
+ // to a waiter that's already been rejected.
318
+ if (this._closed) {
319
+ if (this.live > 0)
320
+ this.live--;
321
+ void c.close().catch(() => { });
322
+ return;
323
+ }
324
+ this.owned.add(c);
325
+ waiter.resolve(c);
326
+ }, (err) => {
327
+ this.live--;
328
+ waiter.reject(err);
329
+ // Keep trying for the next waiter, if any.
330
+ this.drainWaiters();
331
+ });
332
+ }
333
+ }
334
+ }
335
+ exports.Pool = Pool;
@@ -0,0 +1,185 @@
1
+ /**
2
+ * PowDB wire protocol.
3
+ *
4
+ * Frame format: [type(1)][flags(1)][len(4 LE)][payload]
5
+ * Strings are encoded as [len(4 LE)][utf-8 bytes].
6
+ *
7
+ * This mirrors crates/server/src/protocol.rs — keep them in sync.
8
+ */
9
+ export declare const MSG_CONNECT = 1;
10
+ export declare const MSG_CONNECT_OK = 2;
11
+ export declare const MSG_QUERY = 3;
12
+ /**
13
+ * Query carrying positional `$N` parameters. Pure protocol addition: old
14
+ * servers reject it with the existing "unknown message type" error, and the
15
+ * plain `MSG_QUERY` frame is unchanged. Requires powdb-server ≥ 0.4.7.
16
+ */
17
+ export declare const MSG_QUERY_PARAMS = 4;
18
+ /** SQL query frame. Plain Query remains PowQL for backward compatibility. */
19
+ export declare const MSG_QUERY_SQL = 5;
20
+ /** Private embedded-sync control frames. Requires authenticated server support. */
21
+ export declare const MSG_SYNC_STATUS = 32;
22
+ export declare const MSG_SYNC_PULL = 33;
23
+ export declare const MSG_SYNC_ACK = 34;
24
+ export declare const MSG_SYNC_STATUS_RESULT = 35;
25
+ export declare const MSG_SYNC_PULL_RESULT = 36;
26
+ export declare const MSG_SYNC_ACK_RESULT = 37;
27
+ export declare const MSG_RESULT_ROWS = 7;
28
+ export declare const MSG_RESULT_SCALAR = 8;
29
+ export declare const MSG_RESULT_OK = 9;
30
+ export declare const MSG_ERROR = 10;
31
+ export declare const MSG_RESULT_MSG = 11;
32
+ export declare const MSG_DISCONNECT = 16;
33
+ export declare const MSG_PING = 17;
34
+ export declare const MSG_PONG = 18;
35
+ /** Maximum payload size accepted from the wire (64 MB). */
36
+ export declare const MAX_PAYLOAD_SIZE: number;
37
+ /** Maximum number of rows allowed in a single result message. */
38
+ export declare const MAX_ROWS = 10000000;
39
+ /** Maximum number of columns allowed in a result set. */
40
+ export declare const MAX_COLUMNS = 4096;
41
+ /** Maximum number of bound parameters in a QueryWithParams message. */
42
+ export declare const MAX_PARAMS = 4096;
43
+ /** Maximum retained units accepted in one sync pull result. */
44
+ export declare const MAX_SYNC_UNITS = 4096;
45
+ /** Maximum retained units accepted by the server for one sync pull request. */
46
+ export declare const MAX_SYNC_PULL_UNITS = 4096;
47
+ /** Maximum retained-unit payload budget accepted by the server for one sync pull. */
48
+ export declare const MAX_SYNC_PULL_BYTES: number;
49
+ /**
50
+ * A positional parameter value for {@link MSG_QUERY_PARAMS}. Wire encoding
51
+ * per param: a 1-byte tag followed by the body —
52
+ * `0` null (no body), `1` int (8B LE i64), `2` float (8B LE f64),
53
+ * `3` bool (1B), `4` str (length-prefixed UTF-8).
54
+ *
55
+ * Integral numbers are sent as ints, non-integral numbers as floats; `null`
56
+ * binds PowQL `null`. `bigint` is always an int.
57
+ */
58
+ export type WireParam = {
59
+ tag: "null";
60
+ } | {
61
+ tag: "int";
62
+ value: bigint;
63
+ } | {
64
+ tag: "float";
65
+ value: number;
66
+ } | {
67
+ tag: "bool";
68
+ value: boolean;
69
+ } | {
70
+ tag: "str";
71
+ value: string;
72
+ };
73
+ export type SyncRepairAction = "none" | "pull" | "awaitArchive" | "rebootstrap";
74
+ export interface WireSyncStatus {
75
+ replicaId: string;
76
+ active: boolean;
77
+ lastAppliedLsn: bigint | null;
78
+ remoteLsn: bigint;
79
+ servableLsn: bigint | null;
80
+ unarchivedLsn: bigint | null;
81
+ lagLsn: bigint | null;
82
+ lagBytes: bigint | null;
83
+ lagMs: bigint | null;
84
+ stale: boolean;
85
+ repairAction: SyncRepairAction;
86
+ lastSyncError: string | null;
87
+ }
88
+ export interface WireRetainedUnit {
89
+ txId: bigint;
90
+ recordType: number;
91
+ lsn: bigint;
92
+ data: Buffer;
93
+ }
94
+ export type Message = {
95
+ type: "Connect";
96
+ dbName: string;
97
+ password: string | null;
98
+ /**
99
+ * Optional user name for multi-user authentication (server ≥0.4.6
100
+ * enforces roles). Encoded as a length-prefixed string appended AFTER
101
+ * the password field. When `null` the field is omitted entirely, so the
102
+ * frame is byte-identical to the pre-username (0.3.x) shape and old
103
+ * servers accept it unchanged.
104
+ */
105
+ username: string | null;
106
+ } | {
107
+ type: "ConnectOk";
108
+ version: string;
109
+ } | {
110
+ type: "Query";
111
+ query: string;
112
+ } | {
113
+ type: "QuerySql";
114
+ query: string;
115
+ } | {
116
+ type: "QueryWithParams";
117
+ query: string;
118
+ params: WireParam[];
119
+ } | {
120
+ type: "SyncStatus";
121
+ replicaId: string;
122
+ } | {
123
+ type: "SyncPull";
124
+ replicaId: string;
125
+ sinceLsn: bigint;
126
+ maxUnits: number;
127
+ maxBytes: bigint;
128
+ databaseId: Buffer;
129
+ primaryGeneration: bigint;
130
+ walFormatVersion: number;
131
+ catalogVersion: number;
132
+ segmentFormatVersion: number;
133
+ } | {
134
+ type: "SyncAck";
135
+ replicaId: string;
136
+ appliedLsn: bigint;
137
+ remoteLsn: bigint;
138
+ } | {
139
+ type: "SyncStatusResult";
140
+ status: WireSyncStatus;
141
+ } | {
142
+ type: "SyncPullResult";
143
+ status: WireSyncStatus;
144
+ units: WireRetainedUnit[];
145
+ hasMore: boolean;
146
+ } | {
147
+ type: "SyncAckResult";
148
+ previousAppliedLsn: bigint;
149
+ appliedLsn: bigint;
150
+ remoteLsn: bigint;
151
+ advanced: boolean;
152
+ status: WireSyncStatus;
153
+ } | {
154
+ type: "ResultRows";
155
+ columns: string[];
156
+ rows: string[][];
157
+ } | {
158
+ type: "ResultScalar";
159
+ value: string;
160
+ } | {
161
+ type: "ResultOk";
162
+ affected: bigint;
163
+ } | {
164
+ type: "ResultMessage";
165
+ message: string;
166
+ } | {
167
+ type: "Error";
168
+ message: string;
169
+ } | {
170
+ type: "Disconnect";
171
+ } | {
172
+ type: "Ping";
173
+ } | {
174
+ type: "Pong";
175
+ };
176
+ export declare function encode(msg: Message): Buffer;
177
+ /**
178
+ * Attempts to parse a single frame from the start of `buf`. Returns the parsed
179
+ * message and the number of bytes consumed, or `null` if the buffer does not
180
+ * yet contain a complete frame.
181
+ */
182
+ export declare function tryDecode(buf: Buffer): {
183
+ msg: Message;
184
+ consumed: number;
185
+ } | null;