@rstmdb/client 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1332 @@
1
+ 'use strict';
2
+
3
+ var events = require('events');
4
+ var net = require('net');
5
+ var tls = require('tls');
6
+
7
+ function _interopNamespace(e) {
8
+ if (e && e.__esModule) return e;
9
+ var n = Object.create(null);
10
+ if (e) {
11
+ Object.keys(e).forEach(function (k) {
12
+ if (k !== 'default') {
13
+ var d = Object.getOwnPropertyDescriptor(e, k);
14
+ Object.defineProperty(n, k, d.get ? d : {
15
+ enumerable: true,
16
+ get: function () { return e[k]; }
17
+ });
18
+ }
19
+ });
20
+ }
21
+ n.default = e;
22
+ return Object.freeze(n);
23
+ }
24
+
25
+ var net__namespace = /*#__PURE__*/_interopNamespace(net);
26
+ var tls__namespace = /*#__PURE__*/_interopNamespace(tls);
27
+
28
+ // src/client.ts
29
+
30
+ // src/protocol/crc32c.ts
31
+ var CRC32C_TABLE = new Uint32Array(256);
32
+ (function initTable() {
33
+ const POLYNOMIAL = 2197175160;
34
+ for (let i = 0; i < 256; i++) {
35
+ let crc = i;
36
+ for (let j = 0; j < 8; j++) {
37
+ if (crc & 1) {
38
+ crc = crc >>> 1 ^ POLYNOMIAL;
39
+ } else {
40
+ crc = crc >>> 1;
41
+ }
42
+ }
43
+ CRC32C_TABLE[i] = crc >>> 0;
44
+ }
45
+ })();
46
+ function crc32c(data) {
47
+ let crc = 4294967295;
48
+ for (let i = 0; i < data.length; i++) {
49
+ const byte = data[i];
50
+ const tableIndex = (crc ^ byte) & 255;
51
+ crc = crc >>> 8 ^ CRC32C_TABLE[tableIndex];
52
+ }
53
+ return (crc ^ 4294967295) >>> 0;
54
+ }
55
+ function verifyCrc32c(data, expected) {
56
+ return crc32c(data) === expected;
57
+ }
58
+
59
+ // src/errors/codes.ts
60
+ var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
61
+ ErrorCode2["UNSUPPORTED_PROTOCOL"] = "UNSUPPORTED_PROTOCOL";
62
+ ErrorCode2["BAD_REQUEST"] = "BAD_REQUEST";
63
+ ErrorCode2["UNAUTHORIZED"] = "UNAUTHORIZED";
64
+ ErrorCode2["AUTH_FAILED"] = "AUTH_FAILED";
65
+ ErrorCode2["NOT_FOUND"] = "NOT_FOUND";
66
+ ErrorCode2["MACHINE_NOT_FOUND"] = "MACHINE_NOT_FOUND";
67
+ ErrorCode2["MACHINE_VERSION_EXISTS"] = "MACHINE_VERSION_EXISTS";
68
+ ErrorCode2["INSTANCE_NOT_FOUND"] = "INSTANCE_NOT_FOUND";
69
+ ErrorCode2["INSTANCE_EXISTS"] = "INSTANCE_EXISTS";
70
+ ErrorCode2["INVALID_TRANSITION"] = "INVALID_TRANSITION";
71
+ ErrorCode2["GUARD_FAILED"] = "GUARD_FAILED";
72
+ ErrorCode2["CONFLICT"] = "CONFLICT";
73
+ ErrorCode2["WAL_IO_ERROR"] = "WAL_IO_ERROR";
74
+ ErrorCode2["INTERNAL_ERROR"] = "INTERNAL_ERROR";
75
+ ErrorCode2["RATE_LIMITED"] = "RATE_LIMITED";
76
+ ErrorCode2["CONNECTION_FAILED"] = "CONNECTION_FAILED";
77
+ ErrorCode2["CONNECTION_CLOSED"] = "CONNECTION_CLOSED";
78
+ ErrorCode2["TIMEOUT"] = "TIMEOUT";
79
+ return ErrorCode2;
80
+ })(ErrorCode || {});
81
+ function isRetryableCode(code) {
82
+ switch (code) {
83
+ case "CONNECTION_FAILED" /* CONNECTION_FAILED */:
84
+ case "CONNECTION_CLOSED" /* CONNECTION_CLOSED */:
85
+ case "TIMEOUT" /* TIMEOUT */:
86
+ case "RATE_LIMITED" /* RATE_LIMITED */:
87
+ case "WAL_IO_ERROR" /* WAL_IO_ERROR */:
88
+ case "INTERNAL_ERROR" /* INTERNAL_ERROR */:
89
+ return true;
90
+ default:
91
+ return false;
92
+ }
93
+ }
94
+
95
+ // src/errors/base.ts
96
+ var RstmdbError = class _RstmdbError extends Error {
97
+ /** Error code */
98
+ code;
99
+ /** Whether the operation can be retried */
100
+ retryable;
101
+ /** Additional error details */
102
+ details;
103
+ constructor(message, code, options) {
104
+ super(message, { cause: options?.cause });
105
+ this.name = "RstmdbError";
106
+ this.code = code;
107
+ this.retryable = options?.retryable ?? isRetryableCode(code);
108
+ this.details = options?.details;
109
+ Object.setPrototypeOf(this, new.target.prototype);
110
+ }
111
+ /**
112
+ * Create an error from a server response.
113
+ */
114
+ static fromResponse(response) {
115
+ const code = response.code || "INTERNAL_ERROR" /* INTERNAL_ERROR */;
116
+ return new _RstmdbError(response.message, code, {
117
+ details: response.details
118
+ });
119
+ }
120
+ };
121
+
122
+ // src/errors/classes.ts
123
+ var ConnectionError = class extends RstmdbError {
124
+ constructor(message, options) {
125
+ super(message, "CONNECTION_FAILED" /* CONNECTION_FAILED */, {
126
+ retryable: true,
127
+ ...options
128
+ });
129
+ this.name = "ConnectionError";
130
+ }
131
+ };
132
+ var TimeoutError = class extends RstmdbError {
133
+ constructor(message, options) {
134
+ super(message, "TIMEOUT" /* TIMEOUT */, {
135
+ retryable: true,
136
+ ...options
137
+ });
138
+ this.name = "TimeoutError";
139
+ }
140
+ };
141
+ var ProtocolError = class extends RstmdbError {
142
+ constructor(message, code = "BAD_REQUEST" /* BAD_REQUEST */, options) {
143
+ super(message, code, {
144
+ retryable: false,
145
+ ...options
146
+ });
147
+ this.name = "ProtocolError";
148
+ }
149
+ };
150
+ var ServerError = class _ServerError extends RstmdbError {
151
+ constructor(message, code, options) {
152
+ super(message, code, options);
153
+ this.name = "ServerError";
154
+ }
155
+ /**
156
+ * Create a ServerError from a server response.
157
+ */
158
+ static fromResponse(response) {
159
+ const code = response.code || "INTERNAL_ERROR" /* INTERNAL_ERROR */;
160
+ const message = response.message || "Unknown server error";
161
+ switch (code) {
162
+ case "NOT_FOUND" /* NOT_FOUND */:
163
+ case "MACHINE_NOT_FOUND" /* MACHINE_NOT_FOUND */:
164
+ case "INSTANCE_NOT_FOUND" /* INSTANCE_NOT_FOUND */:
165
+ return new NotFoundError(message, code, { details: response.details });
166
+ case "CONFLICT" /* CONFLICT */:
167
+ case "INSTANCE_EXISTS" /* INSTANCE_EXISTS */:
168
+ case "MACHINE_VERSION_EXISTS" /* MACHINE_VERSION_EXISTS */:
169
+ return new ConflictError(message, code, { details: response.details });
170
+ case "UNAUTHORIZED" /* UNAUTHORIZED */:
171
+ case "AUTH_FAILED" /* AUTH_FAILED */:
172
+ return new AuthenticationError(message, code, { details: response.details });
173
+ case "INVALID_TRANSITION" /* INVALID_TRANSITION */:
174
+ return new InvalidTransitionError(message, { details: response.details });
175
+ case "GUARD_FAILED" /* GUARD_FAILED */:
176
+ return new GuardFailedError(message, { details: response.details });
177
+ default:
178
+ return new _ServerError(message, code, { details: response.details });
179
+ }
180
+ }
181
+ };
182
+ var NotFoundError = class extends ServerError {
183
+ constructor(message, code = "NOT_FOUND" /* NOT_FOUND */, options) {
184
+ super(message, code, { retryable: false, ...options });
185
+ this.name = "NotFoundError";
186
+ }
187
+ };
188
+ var ConflictError = class extends ServerError {
189
+ constructor(message, code = "CONFLICT" /* CONFLICT */, options) {
190
+ super(message, code, { retryable: false, ...options });
191
+ this.name = "ConflictError";
192
+ }
193
+ };
194
+ var AuthenticationError = class extends ServerError {
195
+ constructor(message, code = "UNAUTHORIZED" /* UNAUTHORIZED */, options) {
196
+ super(message, code, { retryable: false, ...options });
197
+ this.name = "AuthenticationError";
198
+ }
199
+ };
200
+ var InvalidTransitionError = class extends ServerError {
201
+ constructor(message, options) {
202
+ super(message, "INVALID_TRANSITION" /* INVALID_TRANSITION */, { retryable: false, ...options });
203
+ this.name = "InvalidTransitionError";
204
+ }
205
+ };
206
+ var GuardFailedError = class extends ServerError {
207
+ constructor(message, options) {
208
+ super(message, "GUARD_FAILED" /* GUARD_FAILED */, { retryable: false, ...options });
209
+ this.name = "GuardFailedError";
210
+ }
211
+ };
212
+
213
+ // src/protocol/frame.ts
214
+ var FRAME_MAGIC = 1380143192;
215
+ var PROTOCOL_VERSION = 1;
216
+ var HEADER_SIZE = 18;
217
+ var FrameFlags = /* @__PURE__ */ ((FrameFlags2) => {
218
+ FrameFlags2[FrameFlags2["NONE"] = 0] = "NONE";
219
+ FrameFlags2[FrameFlags2["CRC_PRESENT"] = 1] = "CRC_PRESENT";
220
+ FrameFlags2[FrameFlags2["COMPRESSED"] = 2] = "COMPRESSED";
221
+ FrameFlags2[FrameFlags2["STREAM"] = 4] = "STREAM";
222
+ FrameFlags2[FrameFlags2["END_STREAM"] = 8] = "END_STREAM";
223
+ return FrameFlags2;
224
+ })(FrameFlags || {});
225
+ var FrameEncoder = class {
226
+ useCrc;
227
+ constructor(options) {
228
+ this.useCrc = options?.useCrc ?? true;
229
+ }
230
+ /**
231
+ * Encode an object into an RCP frame.
232
+ */
233
+ encode(payload) {
234
+ const payloadJson = JSON.stringify(payload);
235
+ const payloadBuffer = Buffer.from(payloadJson, "utf8");
236
+ const flags = this.useCrc ? 1 /* CRC_PRESENT */ : 0 /* NONE */;
237
+ const crcValue = this.useCrc ? crc32c(payloadBuffer) : 0;
238
+ return this.encodeRaw(payloadBuffer, flags, crcValue);
239
+ }
240
+ /**
241
+ * Encode a stream frame.
242
+ */
243
+ encodeStream(payload, endStream = false) {
244
+ const payloadJson = JSON.stringify(payload);
245
+ const payloadBuffer = Buffer.from(payloadJson, "utf8");
246
+ let flags = 4 /* STREAM */;
247
+ if (this.useCrc) flags |= 1 /* CRC_PRESENT */;
248
+ if (endStream) flags |= 8 /* END_STREAM */;
249
+ const crcValue = this.useCrc ? crc32c(payloadBuffer) : 0;
250
+ return this.encodeRaw(payloadBuffer, flags, crcValue);
251
+ }
252
+ /**
253
+ * Encode raw payload with specified flags.
254
+ */
255
+ encodeRaw(payload, flags, crcValue) {
256
+ const headerExtLen = 0;
257
+ const payloadLen = payload.length;
258
+ const frame = Buffer.allocUnsafe(HEADER_SIZE + headerExtLen + payloadLen);
259
+ frame.writeUInt32BE(FRAME_MAGIC, 0);
260
+ frame.writeUInt16BE(PROTOCOL_VERSION, 4);
261
+ frame.writeUInt16BE(flags, 6);
262
+ frame.writeUInt16BE(headerExtLen, 8);
263
+ frame.writeUInt32BE(payloadLen, 10);
264
+ frame.writeUInt32BE(crcValue, 14);
265
+ payload.copy(frame, HEADER_SIZE);
266
+ return frame;
267
+ }
268
+ };
269
+ var FrameDecoder = class {
270
+ buffer = Buffer.alloc(0);
271
+ verifyCrc;
272
+ constructor(options) {
273
+ this.verifyCrc = options?.verifyCrc ?? true;
274
+ }
275
+ /**
276
+ * Append data to the internal buffer.
277
+ */
278
+ append(data) {
279
+ this.buffer = Buffer.concat([this.buffer, data]);
280
+ }
281
+ /**
282
+ * Try to decode a frame from the buffer.
283
+ * Returns null if not enough data is available.
284
+ */
285
+ decode() {
286
+ if (this.buffer.length < HEADER_SIZE) {
287
+ return null;
288
+ }
289
+ const magic = this.buffer.readUInt32BE(0);
290
+ if (magic !== FRAME_MAGIC) {
291
+ throw new ProtocolError(
292
+ `Invalid frame magic: expected 0x${FRAME_MAGIC.toString(16)} (RCPX), got 0x${magic.toString(16)}`,
293
+ "BAD_REQUEST" /* BAD_REQUEST */
294
+ );
295
+ }
296
+ const version = this.buffer.readUInt16BE(4);
297
+ if (version !== PROTOCOL_VERSION) {
298
+ throw new ProtocolError(
299
+ `Unsupported protocol version: ${version}`,
300
+ "UNSUPPORTED_PROTOCOL" /* UNSUPPORTED_PROTOCOL */
301
+ );
302
+ }
303
+ const flags = this.buffer.readUInt16BE(6);
304
+ const headerExtLen = this.buffer.readUInt16BE(8);
305
+ const payloadLen = this.buffer.readUInt32BE(10);
306
+ const crcValue = this.buffer.readUInt32BE(14);
307
+ const totalLen = HEADER_SIZE + headerExtLen + payloadLen;
308
+ if (this.buffer.length < totalLen) {
309
+ return null;
310
+ }
311
+ const payloadStart = HEADER_SIZE + headerExtLen;
312
+ const payload = this.buffer.subarray(payloadStart, payloadStart + payloadLen);
313
+ if (this.verifyCrc && flags & 1 /* CRC_PRESENT */) {
314
+ if (!verifyCrc32c(payload, crcValue)) {
315
+ throw new ProtocolError("CRC32C checksum mismatch", "BAD_REQUEST" /* BAD_REQUEST */);
316
+ }
317
+ }
318
+ this.buffer = this.buffer.subarray(totalLen);
319
+ return { flags, payload: Buffer.from(payload) };
320
+ }
321
+ /**
322
+ * Reset the decoder state.
323
+ */
324
+ reset() {
325
+ this.buffer = Buffer.alloc(0);
326
+ }
327
+ /**
328
+ * Get the current buffer length.
329
+ */
330
+ get bufferedLength() {
331
+ return this.buffer.length;
332
+ }
333
+ };
334
+
335
+ // src/protocol/operations.ts
336
+ var Operation = /* @__PURE__ */ ((Operation2) => {
337
+ Operation2["HELLO"] = "HELLO";
338
+ Operation2["AUTH"] = "AUTH";
339
+ Operation2["PING"] = "PING";
340
+ Operation2["INFO"] = "INFO";
341
+ Operation2["PUT_MACHINE"] = "PUT_MACHINE";
342
+ Operation2["GET_MACHINE"] = "GET_MACHINE";
343
+ Operation2["LIST_MACHINES"] = "LIST_MACHINES";
344
+ Operation2["CREATE_INSTANCE"] = "CREATE_INSTANCE";
345
+ Operation2["GET_INSTANCE"] = "GET_INSTANCE";
346
+ Operation2["DELETE_INSTANCE"] = "DELETE_INSTANCE";
347
+ Operation2["APPLY_EVENT"] = "APPLY_EVENT";
348
+ Operation2["BATCH"] = "BATCH";
349
+ Operation2["WAL_READ"] = "WAL_READ";
350
+ Operation2["SNAPSHOT_INSTANCE"] = "SNAPSHOT_INSTANCE";
351
+ Operation2["COMPACT"] = "COMPACT";
352
+ Operation2["WATCH_INSTANCE"] = "WATCH_INSTANCE";
353
+ Operation2["WATCH_ALL"] = "WATCH_ALL";
354
+ Operation2["UNWATCH"] = "UNWATCH";
355
+ return Operation2;
356
+ })(Operation || {});
357
+ Object.values(Operation);
358
+
359
+ // src/protocol/messages.ts
360
+ function isResponseMessage(msg) {
361
+ return msg.type === "response";
362
+ }
363
+ function isStreamEventMessage(msg) {
364
+ return msg.type === "event";
365
+ }
366
+ function isStreamEndMessage(msg) {
367
+ return msg.type === "end";
368
+ }
369
+ function parseBigIntFields(obj, fields) {
370
+ const result = { ...obj };
371
+ for (const field of fields) {
372
+ const value = result[field];
373
+ if (typeof value === "string") {
374
+ result[field] = BigInt(value);
375
+ }
376
+ }
377
+ return result;
378
+ }
379
+
380
+ // src/connection.ts
381
+ var Connection = class extends events.EventEmitter {
382
+ config;
383
+ socket = null;
384
+ state = "DISCONNECTED" /* DISCONNECTED */;
385
+ encoder;
386
+ decoder;
387
+ pending = /* @__PURE__ */ new Map();
388
+ nextId = 1;
389
+ subscriptions;
390
+ reconnectAttempt = 0;
391
+ reconnectTimer = null;
392
+ closing = false;
393
+ constructor(config, subscriptions) {
394
+ super();
395
+ this.config = config;
396
+ this.subscriptions = subscriptions;
397
+ this.encoder = new FrameEncoder({ useCrc: true });
398
+ this.decoder = new FrameDecoder({ verifyCrc: true });
399
+ }
400
+ /**
401
+ * Get the current connection state.
402
+ */
403
+ getState() {
404
+ return this.state;
405
+ }
406
+ /**
407
+ * Check if connected.
408
+ */
409
+ isConnected() {
410
+ return this.state === "CONNECTED" /* CONNECTED */;
411
+ }
412
+ /**
413
+ * Connect to the server.
414
+ */
415
+ async connect() {
416
+ if (this.state !== "DISCONNECTED" /* DISCONNECTED */) {
417
+ throw new ConnectionError("Already connected or connecting");
418
+ }
419
+ this.closing = false;
420
+ this.state = "CONNECTING" /* CONNECTING */;
421
+ try {
422
+ await this.createSocket();
423
+ this.state = "HANDSHAKING" /* HANDSHAKING */;
424
+ await this.handshake();
425
+ this.state = "CONNECTED" /* CONNECTED */;
426
+ this.reconnectAttempt = 0;
427
+ this.emit("connect");
428
+ } catch (error) {
429
+ this.state = "DISCONNECTED" /* DISCONNECTED */;
430
+ this.cleanup();
431
+ throw error;
432
+ }
433
+ }
434
+ /**
435
+ * Close the connection.
436
+ */
437
+ async close() {
438
+ this.closing = true;
439
+ if (this.reconnectTimer) {
440
+ clearTimeout(this.reconnectTimer);
441
+ this.reconnectTimer = null;
442
+ }
443
+ if (this.socket) {
444
+ this.state = "CLOSING" /* CLOSING */;
445
+ const error = new ConnectionError("Connection closed");
446
+ for (const pending of this.pending.values()) {
447
+ clearTimeout(pending.timeout);
448
+ pending.reject(error);
449
+ }
450
+ this.pending.clear();
451
+ this.subscriptions.closeAll(error);
452
+ await new Promise((resolve) => {
453
+ if (this.socket) {
454
+ this.socket.once("close", () => resolve());
455
+ this.socket.end();
456
+ setTimeout(() => {
457
+ if (this.socket) {
458
+ this.socket.destroy();
459
+ }
460
+ resolve();
461
+ }, 1e3);
462
+ } else {
463
+ resolve();
464
+ }
465
+ });
466
+ this.cleanup();
467
+ }
468
+ this.state = "DISCONNECTED" /* DISCONNECTED */;
469
+ }
470
+ /**
471
+ * Send a request and wait for response.
472
+ */
473
+ async request(op, params) {
474
+ if (this.state !== "CONNECTED" /* CONNECTED */ && this.state !== "HANDSHAKING" /* HANDSHAKING */) {
475
+ throw new ConnectionError("Not connected");
476
+ }
477
+ const socket = this.socket;
478
+ if (!socket) {
479
+ throw new ConnectionError("Socket not available");
480
+ }
481
+ const id = String(this.nextId++);
482
+ const message = { type: "request", id, op, params };
483
+ const frame = this.encoder.encode(message);
484
+ return new Promise((resolve, reject) => {
485
+ const timeout = setTimeout(() => {
486
+ this.pending.delete(id);
487
+ reject(new TimeoutError(`Request ${op} timed out after ${this.config.requestTimeout}ms`));
488
+ }, this.config.requestTimeout);
489
+ this.pending.set(id, {
490
+ id,
491
+ resolve: (response) => {
492
+ clearTimeout(timeout);
493
+ this.pending.delete(id);
494
+ if (response.status !== "ok") {
495
+ reject(
496
+ ServerError.fromResponse(
497
+ response.error || { code: "INTERNAL_ERROR" /* INTERNAL_ERROR */, message: "Unknown error" }
498
+ )
499
+ );
500
+ } else {
501
+ resolve(response.result);
502
+ }
503
+ },
504
+ reject: (error) => {
505
+ clearTimeout(timeout);
506
+ this.pending.delete(id);
507
+ reject(error);
508
+ },
509
+ timeout
510
+ });
511
+ socket.write(frame, (err) => {
512
+ if (err) {
513
+ const pending = this.pending.get(id);
514
+ if (pending) {
515
+ clearTimeout(pending.timeout);
516
+ this.pending.delete(id);
517
+ reject(new ConnectionError(`Failed to send request: ${err.message}`, { cause: err }));
518
+ }
519
+ }
520
+ });
521
+ });
522
+ }
523
+ /**
524
+ * Create the TCP/TLS socket.
525
+ */
526
+ async createSocket() {
527
+ return new Promise((resolve, reject) => {
528
+ const connectTimeout = setTimeout(() => {
529
+ if (this.socket) {
530
+ this.socket.destroy();
531
+ this.socket = null;
532
+ }
533
+ reject(new TimeoutError(`Connection timeout after ${this.config.connectTimeout}ms`));
534
+ }, this.config.connectTimeout);
535
+ const options = {
536
+ host: this.config.host,
537
+ port: this.config.port
538
+ };
539
+ const onConnect = () => {
540
+ clearTimeout(connectTimeout);
541
+ this.setupSocket();
542
+ resolve();
543
+ };
544
+ const onError = (err) => {
545
+ clearTimeout(connectTimeout);
546
+ reject(new ConnectionError(`Failed to connect: ${err.message}`, { cause: err }));
547
+ };
548
+ if (this.config.tls) {
549
+ const tlsOptions = {
550
+ ...options,
551
+ ...this.config.tls
552
+ };
553
+ this.socket = tls__namespace.connect(tlsOptions);
554
+ this.socket.once("secureConnect", onConnect);
555
+ } else {
556
+ this.socket = net__namespace.connect(options);
557
+ this.socket.once("connect", onConnect);
558
+ }
559
+ this.socket.once("error", onError);
560
+ });
561
+ }
562
+ /**
563
+ * Set up socket event handlers.
564
+ */
565
+ setupSocket() {
566
+ if (!this.socket) return;
567
+ this.socket.on("data", (data) => this.handleData(data));
568
+ this.socket.on("close", () => {
569
+ const wasConnected = this.state === "CONNECTED" /* CONNECTED */;
570
+ this.cleanup();
571
+ this.state = "DISCONNECTED" /* DISCONNECTED */;
572
+ if (!this.closing && wasConnected) {
573
+ this.emit("disconnect");
574
+ this.scheduleReconnect();
575
+ }
576
+ });
577
+ this.socket.on("error", (err) => {
578
+ this.emit("error", new ConnectionError(err.message, { cause: err }));
579
+ });
580
+ }
581
+ /**
582
+ * Handle incoming data.
583
+ */
584
+ handleData(data) {
585
+ this.decoder.append(data);
586
+ let frame;
587
+ try {
588
+ while ((frame = this.decoder.decode()) !== null) {
589
+ this.handleFrame(frame);
590
+ }
591
+ } catch (error) {
592
+ this.emit("error", error);
593
+ this.socket?.destroy();
594
+ }
595
+ }
596
+ /**
597
+ * Handle a decoded frame.
598
+ */
599
+ handleFrame(frame) {
600
+ let message;
601
+ try {
602
+ message = JSON.parse(frame.payload.toString("utf8"));
603
+ } catch {
604
+ throw new ProtocolError("Invalid JSON payload");
605
+ }
606
+ if (isResponseMessage(message)) {
607
+ const pending = this.pending.get(message.id);
608
+ if (pending) {
609
+ pending.resolve(message);
610
+ }
611
+ } else if (isStreamEventMessage(message)) {
612
+ this.subscriptions.dispatch(message);
613
+ } else if (isStreamEndMessage(message)) {
614
+ this.subscriptions.end(message.subscription_id);
615
+ }
616
+ }
617
+ /**
618
+ * Perform the handshake (HELLO + AUTH).
619
+ */
620
+ async handshake() {
621
+ const helloParams = {
622
+ protocol_version: 1,
623
+ wire_modes: ["binary_json"],
624
+ features: ["idempotency", "batch"]
625
+ };
626
+ if (this.config.clientName) {
627
+ helloParams["client_name"] = this.config.clientName;
628
+ }
629
+ const helloResult = await this.request(
630
+ "HELLO" /* HELLO */,
631
+ helloParams
632
+ );
633
+ if (helloResult.protocol_version !== 1) {
634
+ throw new ProtocolError(
635
+ `Unsupported protocol version: ${helloResult.protocol_version}`,
636
+ "UNSUPPORTED_PROTOCOL" /* UNSUPPORTED_PROTOCOL */
637
+ );
638
+ }
639
+ if (this.config.authToken) {
640
+ await this.request("AUTH" /* AUTH */, {
641
+ method: "bearer",
642
+ token: this.config.authToken
643
+ });
644
+ }
645
+ }
646
+ /**
647
+ * Schedule a reconnection attempt.
648
+ */
649
+ scheduleReconnect() {
650
+ if (this.closing || !this.config.reconnect) {
651
+ return;
652
+ }
653
+ if (this.reconnectAttempt >= this.config.reconnectMaxAttempts) {
654
+ this.emit(
655
+ "error",
656
+ new ConnectionError(
657
+ `Max reconnection attempts (${this.config.reconnectMaxAttempts}) reached`
658
+ )
659
+ );
660
+ return;
661
+ }
662
+ this.reconnectAttempt++;
663
+ const delay = this.config.reconnectInterval * Math.min(this.reconnectAttempt, 5);
664
+ this.reconnectTimer = setTimeout(() => {
665
+ this.reconnectTimer = null;
666
+ this.emit("reconnect", this.reconnectAttempt);
667
+ this.connect().catch(() => {
668
+ });
669
+ }, delay);
670
+ }
671
+ /**
672
+ * Clean up resources.
673
+ */
674
+ cleanup() {
675
+ this.decoder.reset();
676
+ if (this.socket) {
677
+ this.socket.removeAllListeners();
678
+ this.socket = null;
679
+ }
680
+ }
681
+ };
682
+ var SubscriptionHandler = class extends events.EventEmitter {
683
+ subscriptionId;
684
+ events = [];
685
+ waiters = [];
686
+ closed = false;
687
+ closeError;
688
+ unsubscribeFn;
689
+ constructor(subscriptionId, unsubscribeFn) {
690
+ super();
691
+ this.subscriptionId = subscriptionId;
692
+ this.unsubscribeFn = unsubscribeFn;
693
+ }
694
+ /**
695
+ * Push an event to the subscription.
696
+ */
697
+ push(event) {
698
+ if (this.closed) return;
699
+ const waiter = this.waiters.shift();
700
+ if (waiter) {
701
+ waiter.resolve({ value: event, done: false });
702
+ } else {
703
+ this.events.push(event);
704
+ }
705
+ this.emit("event", event);
706
+ }
707
+ /**
708
+ * Close the subscription with an optional error.
709
+ */
710
+ close(error) {
711
+ if (this.closed) return;
712
+ this.closed = true;
713
+ this.closeError = error;
714
+ for (const waiter of this.waiters) {
715
+ if (error) {
716
+ waiter.reject(error);
717
+ } else {
718
+ waiter.resolve({ value: void 0, done: true });
719
+ }
720
+ }
721
+ this.waiters = [];
722
+ if (error) {
723
+ this.emit("error", error);
724
+ }
725
+ this.emit("end");
726
+ }
727
+ /**
728
+ * AsyncIterator implementation.
729
+ */
730
+ async *[Symbol.asyncIterator]() {
731
+ while (true) {
732
+ if (this.closed) {
733
+ if (this.closeError) {
734
+ throw this.closeError;
735
+ }
736
+ while (this.events.length > 0) {
737
+ yield this.events.shift();
738
+ }
739
+ return;
740
+ }
741
+ if (this.events.length > 0) {
742
+ yield this.events.shift();
743
+ continue;
744
+ }
745
+ const result = await new Promise((resolve, reject) => {
746
+ this.waiters.push({ resolve, reject });
747
+ });
748
+ if (result.done) {
749
+ return;
750
+ }
751
+ yield result.value;
752
+ }
753
+ }
754
+ /**
755
+ * Cancel the subscription.
756
+ */
757
+ async unsubscribe() {
758
+ if (!this.closed) {
759
+ await this.unsubscribeFn();
760
+ this.close();
761
+ }
762
+ }
763
+ /**
764
+ * Check if the subscription is closed.
765
+ */
766
+ get isClosed() {
767
+ return this.closed;
768
+ }
769
+ };
770
+
771
+ // src/streaming/manager.ts
772
+ var SubscriptionManager = class {
773
+ subscriptions = /* @__PURE__ */ new Map();
774
+ /**
775
+ * Register a new subscription.
776
+ */
777
+ register(subscriptionId, handler) {
778
+ this.subscriptions.set(subscriptionId, handler);
779
+ }
780
+ /**
781
+ * Unregister a subscription.
782
+ */
783
+ unregister(subscriptionId) {
784
+ const handler = this.subscriptions.get(subscriptionId);
785
+ if (handler) {
786
+ handler.close();
787
+ this.subscriptions.delete(subscriptionId);
788
+ }
789
+ }
790
+ /**
791
+ * Get a subscription handler.
792
+ */
793
+ get(subscriptionId) {
794
+ return this.subscriptions.get(subscriptionId);
795
+ }
796
+ /**
797
+ * Check if a subscription exists.
798
+ */
799
+ has(subscriptionId) {
800
+ return this.subscriptions.has(subscriptionId);
801
+ }
802
+ /**
803
+ * Dispatch an event to the appropriate subscription.
804
+ */
805
+ dispatch(message) {
806
+ const handler = this.subscriptions.get(message.subscription_id);
807
+ if (!handler) {
808
+ return;
809
+ }
810
+ const event = {
811
+ subscriptionId: message.subscription_id,
812
+ instanceId: message.instance_id,
813
+ machine: message.machine,
814
+ version: message.version,
815
+ walOffset: BigInt(message.wal_offset),
816
+ fromState: message.from_state,
817
+ toState: message.to_state,
818
+ event: message.event,
819
+ payload: message.payload,
820
+ ctx: message.ctx
821
+ };
822
+ handler.push(event);
823
+ }
824
+ /**
825
+ * End a subscription (e.g., when server sends end message).
826
+ */
827
+ end(subscriptionId, error) {
828
+ const handler = this.subscriptions.get(subscriptionId);
829
+ if (handler) {
830
+ handler.close(error);
831
+ this.subscriptions.delete(subscriptionId);
832
+ }
833
+ }
834
+ /**
835
+ * Close all subscriptions (e.g., on disconnect).
836
+ */
837
+ closeAll(error) {
838
+ for (const handler of this.subscriptions.values()) {
839
+ handler.close(error);
840
+ }
841
+ this.subscriptions.clear();
842
+ }
843
+ /**
844
+ * Get the number of active subscriptions.
845
+ */
846
+ get size() {
847
+ return this.subscriptions.size;
848
+ }
849
+ };
850
+
851
+ // src/types/config.ts
852
+ var DEFAULT_CONFIG = {
853
+ port: 7401,
854
+ connectTimeout: 1e4,
855
+ requestTimeout: 3e4,
856
+ reconnect: true,
857
+ reconnectInterval: 1e3,
858
+ reconnectMaxAttempts: 10
859
+ };
860
+ function resolveConfig(config) {
861
+ let tlsConfig;
862
+ if (config.tls === true) {
863
+ tlsConfig = { rejectUnauthorized: true };
864
+ } else if (config.tls && typeof config.tls === "object") {
865
+ tlsConfig = config.tls;
866
+ }
867
+ return {
868
+ host: config.host,
869
+ port: config.port ?? DEFAULT_CONFIG.port,
870
+ connectTimeout: config.connectTimeout ?? DEFAULT_CONFIG.connectTimeout,
871
+ requestTimeout: config.requestTimeout ?? DEFAULT_CONFIG.requestTimeout,
872
+ authToken: config.authToken,
873
+ tls: tlsConfig,
874
+ reconnect: config.reconnect ?? DEFAULT_CONFIG.reconnect,
875
+ reconnectInterval: config.reconnectInterval ?? DEFAULT_CONFIG.reconnectInterval,
876
+ reconnectMaxAttempts: config.reconnectMaxAttempts ?? DEFAULT_CONFIG.reconnectMaxAttempts,
877
+ clientName: config.clientName
878
+ };
879
+ }
880
+ var ClientOptions = class _ClientOptions {
881
+ config;
882
+ constructor(host) {
883
+ this.config = { host };
884
+ }
885
+ /**
886
+ * Create a new options builder with the given host.
887
+ */
888
+ static create(host) {
889
+ return new _ClientOptions(host);
890
+ }
891
+ /**
892
+ * Set the server port.
893
+ * @default 7401
894
+ */
895
+ port(port) {
896
+ this.config.port = port;
897
+ return this;
898
+ }
899
+ /**
900
+ * Set the authentication token.
901
+ */
902
+ auth(token) {
903
+ this.config.authToken = token;
904
+ return this;
905
+ }
906
+ /**
907
+ * Configure TLS settings.
908
+ *
909
+ * @param config - TLS configuration, or `true` to enable with system CA
910
+ *
911
+ * @example
912
+ * ```typescript
913
+ * // Enable TLS with system CA
914
+ * options.tls(true)
915
+ *
916
+ * // Custom CA certificate
917
+ * options.tls({ ca: fs.readFileSync('ca.pem') })
918
+ *
919
+ * // mTLS with client certificate
920
+ * options.tls({
921
+ * ca: fs.readFileSync('ca.pem'),
922
+ * cert: fs.readFileSync('client.pem'),
923
+ * key: fs.readFileSync('client-key.pem'),
924
+ * })
925
+ * ```
926
+ */
927
+ tls(config) {
928
+ this.config.tls = config;
929
+ return this;
930
+ }
931
+ /**
932
+ * Set timeout values.
933
+ */
934
+ timeout(options) {
935
+ if (options.connect !== void 0) {
936
+ this.config.connectTimeout = options.connect;
937
+ }
938
+ if (options.request !== void 0) {
939
+ this.config.requestTimeout = options.request;
940
+ }
941
+ return this;
942
+ }
943
+ /**
944
+ * Configure reconnection behavior.
945
+ */
946
+ reconnect(options) {
947
+ if (options.enabled !== void 0) {
948
+ this.config.reconnect = options.enabled;
949
+ }
950
+ if (options.interval !== void 0) {
951
+ this.config.reconnectInterval = options.interval;
952
+ }
953
+ if (options.maxAttempts !== void 0) {
954
+ this.config.reconnectMaxAttempts = options.maxAttempts;
955
+ }
956
+ return this;
957
+ }
958
+ /**
959
+ * Set the client name (sent in HELLO handshake).
960
+ */
961
+ clientName(name) {
962
+ this.config.clientName = name;
963
+ return this;
964
+ }
965
+ /**
966
+ * Build the configuration object.
967
+ */
968
+ build() {
969
+ return { ...this.config };
970
+ }
971
+ };
972
+
973
+ // src/client.ts
974
+ var Client = class _Client extends events.EventEmitter {
975
+ connection;
976
+ subscriptions;
977
+ config;
978
+ constructor(config) {
979
+ super();
980
+ this.config = config;
981
+ const resolvedConfig = resolveConfig(config);
982
+ this.subscriptions = new SubscriptionManager();
983
+ this.connection = new Connection(resolvedConfig, this.subscriptions);
984
+ this.connection.on("connect", () => this.emit("connect"));
985
+ this.connection.on("disconnect", (error) => this.emit("disconnect", error));
986
+ this.connection.on("error", (error) => this.emit("error", error));
987
+ this.connection.on("reconnect", (attempt) => this.emit("reconnect", attempt));
988
+ }
989
+ /**
990
+ * Create a client and connect to the server.
991
+ *
992
+ * @param host - Server hostname
993
+ * @param port - Server port (default: 7401)
994
+ * @param options - Additional options
995
+ * @returns Connected client instance
996
+ *
997
+ * @example
998
+ * ```typescript
999
+ * const client = await Client.connect('localhost');
1000
+ * const client = await Client.connect('localhost', 7401);
1001
+ * const client = await Client.connect('localhost', 7401, { auth: 'token' });
1002
+ * ```
1003
+ */
1004
+ static async connect(host, port = 7401, options) {
1005
+ const client = new _Client({
1006
+ host,
1007
+ port,
1008
+ authToken: options?.auth,
1009
+ tls: options?.tls,
1010
+ clientName: options?.clientName
1011
+ });
1012
+ await client.connect();
1013
+ return client;
1014
+ }
1015
+ /**
1016
+ * Get the current configuration.
1017
+ */
1018
+ getConfig() {
1019
+ return this.config;
1020
+ }
1021
+ // ─────────────────────────────────────────────────────────────────────────
1022
+ // Connection Lifecycle
1023
+ // ─────────────────────────────────────────────────────────────────────────
1024
+ /**
1025
+ * Connect to the server.
1026
+ */
1027
+ async connect() {
1028
+ await this.connection.connect();
1029
+ }
1030
+ /**
1031
+ * Close the connection.
1032
+ */
1033
+ async close() {
1034
+ await this.connection.close();
1035
+ }
1036
+ /**
1037
+ * Check if connected to the server.
1038
+ */
1039
+ isConnected() {
1040
+ return this.connection.getState() === "CONNECTED" /* CONNECTED */;
1041
+ }
1042
+ // ─────────────────────────────────────────────────────────────────────────
1043
+ // System Operations
1044
+ // ─────────────────────────────────────────────────────────────────────────
1045
+ /**
1046
+ * Ping the server.
1047
+ */
1048
+ async ping() {
1049
+ await this.connection.request("PING" /* PING */);
1050
+ }
1051
+ /**
1052
+ * Get server information.
1053
+ */
1054
+ async info() {
1055
+ const result = await this.connection.request("INFO" /* INFO */);
1056
+ return {
1057
+ serverName: result.server_name,
1058
+ serverVersion: result.server_version,
1059
+ protocolVersion: result.protocol_version,
1060
+ maxPayloadBytes: result.max_payload_bytes,
1061
+ maxBatchOps: result.max_batch_ops,
1062
+ walSegmentSize: result.wal_segment_size,
1063
+ authRequired: result.auth_required,
1064
+ features: result.features
1065
+ };
1066
+ }
1067
+ // ─────────────────────────────────────────────────────────────────────────
1068
+ // Machine Operations
1069
+ // ─────────────────────────────────────────────────────────────────────────
1070
+ /**
1071
+ * Create or update a state machine definition.
1072
+ */
1073
+ async putMachine(machine, version, definition) {
1074
+ const result = await this.connection.request("PUT_MACHINE" /* PUT_MACHINE */, {
1075
+ machine,
1076
+ version,
1077
+ definition
1078
+ });
1079
+ return {
1080
+ machine: result.machine,
1081
+ version: result.version,
1082
+ storedChecksum: result.stored_checksum,
1083
+ created: result.created
1084
+ };
1085
+ }
1086
+ /**
1087
+ * Get a state machine definition.
1088
+ */
1089
+ async getMachine(machine, version) {
1090
+ const result = await this.connection.request("GET_MACHINE" /* GET_MACHINE */, {
1091
+ machine,
1092
+ version
1093
+ });
1094
+ return result;
1095
+ }
1096
+ /**
1097
+ * List all state machines.
1098
+ */
1099
+ async listMachines(options) {
1100
+ const result = await this.connection.request(
1101
+ "LIST_MACHINES" /* LIST_MACHINES */,
1102
+ options
1103
+ );
1104
+ return result;
1105
+ }
1106
+ // ─────────────────────────────────────────────────────────────────────────
1107
+ // Instance Operations
1108
+ // ─────────────────────────────────────────────────────────────────────────
1109
+ /**
1110
+ * Create a new state machine instance.
1111
+ */
1112
+ async createInstance(machine, version, options) {
1113
+ const params = { machine, version };
1114
+ if (options?.instanceId) params["instance_id"] = options.instanceId;
1115
+ if (options?.initialCtx) params["initial_ctx"] = options.initialCtx;
1116
+ if (options?.idempotencyKey) params["idempotency_key"] = options.idempotencyKey;
1117
+ const result = await this.connection.request("CREATE_INSTANCE" /* CREATE_INSTANCE */, params);
1118
+ return {
1119
+ instanceId: result.instance_id,
1120
+ state: result.state,
1121
+ walOffset: BigInt(result.wal_offset)
1122
+ };
1123
+ }
1124
+ /**
1125
+ * Get instance state and context.
1126
+ */
1127
+ async getInstance(instanceId) {
1128
+ const result = await this.connection.request("GET_INSTANCE" /* GET_INSTANCE */, { instance_id: instanceId });
1129
+ return {
1130
+ machine: result.machine,
1131
+ version: result.version,
1132
+ state: result.state,
1133
+ ctx: result.ctx,
1134
+ lastEventId: result.last_event_id,
1135
+ lastWalOffset: BigInt(result.last_wal_offset)
1136
+ };
1137
+ }
1138
+ /**
1139
+ * Delete an instance.
1140
+ */
1141
+ async deleteInstance(instanceId, options) {
1142
+ const params = { instance_id: instanceId };
1143
+ if (options?.idempotencyKey) params["idempotency_key"] = options.idempotencyKey;
1144
+ await this.connection.request("DELETE_INSTANCE" /* DELETE_INSTANCE */, params);
1145
+ }
1146
+ // ─────────────────────────────────────────────────────────────────────────
1147
+ // Event Operations
1148
+ // ─────────────────────────────────────────────────────────────────────────
1149
+ /**
1150
+ * Apply an event to an instance.
1151
+ */
1152
+ async applyEvent(instanceId, event, options) {
1153
+ const params = {
1154
+ instance_id: instanceId,
1155
+ event
1156
+ };
1157
+ if (options?.payload) params["payload"] = options.payload;
1158
+ if (options?.expectedState) params["expected_state"] = options.expectedState;
1159
+ if (options?.expectedWalOffset !== void 0) {
1160
+ params["expected_wal_offset"] = Number(options.expectedWalOffset);
1161
+ }
1162
+ if (options?.eventId) params["event_id"] = options.eventId;
1163
+ if (options?.idempotencyKey) params["idempotency_key"] = options.idempotencyKey;
1164
+ const result = await this.connection.request("APPLY_EVENT" /* APPLY_EVENT */, params);
1165
+ return {
1166
+ fromState: result.from_state,
1167
+ toState: result.to_state,
1168
+ ctx: result.ctx,
1169
+ walOffset: BigInt(result.wal_offset),
1170
+ applied: result.applied,
1171
+ eventId: result.event_id
1172
+ };
1173
+ }
1174
+ /**
1175
+ * Execute multiple operations in a batch.
1176
+ */
1177
+ async batch(operations, options) {
1178
+ const serializedOps = operations.map((op) => {
1179
+ const params = {};
1180
+ for (const [key, value] of Object.entries(op.params)) {
1181
+ const snakeKey = key.replace(/([A-Z])/g, "_$1").toLowerCase();
1182
+ params[snakeKey] = value;
1183
+ }
1184
+ return { op: op.op, params };
1185
+ });
1186
+ const result = await this.connection.request("BATCH" /* BATCH */, {
1187
+ ops: serializedOps,
1188
+ ...options
1189
+ });
1190
+ return {
1191
+ results: result.results.map((r) => ({
1192
+ status: r.status,
1193
+ result: r.result ? parseBigIntFields(r.result, ["wal_offset"]) : void 0,
1194
+ error: r.error ? ServerError.fromResponse(r.error) : void 0
1195
+ })),
1196
+ walOffset: result.wal_offset ? BigInt(result.wal_offset) : void 0
1197
+ };
1198
+ }
1199
+ // ─────────────────────────────────────────────────────────────────────────
1200
+ // WAL Operations
1201
+ // ─────────────────────────────────────────────────────────────────────────
1202
+ /**
1203
+ * Read entries from the write-ahead log.
1204
+ */
1205
+ async walRead(fromOffset, options) {
1206
+ const result = await this.connection.request("WAL_READ" /* WAL_READ */, {
1207
+ fromOffset: fromOffset.toString(),
1208
+ ...options
1209
+ });
1210
+ return {
1211
+ entries: result.entries.map((e) => ({
1212
+ ...e,
1213
+ offset: BigInt(e.offset)
1214
+ })),
1215
+ hasMore: result.hasMore,
1216
+ nextOffset: result.nextOffset ? BigInt(result.nextOffset) : void 0
1217
+ };
1218
+ }
1219
+ /**
1220
+ * Create a snapshot of an instance.
1221
+ */
1222
+ async snapshotInstance(instanceId) {
1223
+ const result = await this.connection.request("SNAPSHOT_INSTANCE" /* SNAPSHOT_INSTANCE */, { instance_id: instanceId });
1224
+ return {
1225
+ instanceId,
1226
+ walOffset: BigInt(result.wal_offset),
1227
+ sizeBytes: 0
1228
+ // Not provided by server
1229
+ };
1230
+ }
1231
+ /**
1232
+ * Trigger WAL compaction.
1233
+ */
1234
+ async compact(options) {
1235
+ const params = {};
1236
+ if (options?.force) params["force_snapshot"] = options.force;
1237
+ const result = await this.connection.request("COMPACT" /* COMPACT */, params);
1238
+ return {
1239
+ snapshotsCreated: result.snapshots_created,
1240
+ segmentsDeleted: result.segments_deleted,
1241
+ bytesReclaimed: BigInt(result.bytes_reclaimed)
1242
+ };
1243
+ }
1244
+ // ─────────────────────────────────────────────────────────────────────────
1245
+ // Watch/Streaming Operations
1246
+ // ─────────────────────────────────────────────────────────────────────────
1247
+ /**
1248
+ * Watch a specific instance for state changes.
1249
+ */
1250
+ async watchInstance(instanceId, options) {
1251
+ const params = {
1252
+ instance_id: instanceId
1253
+ };
1254
+ if (options?.includeCtx !== void 0) params["include_ctx"] = options.includeCtx;
1255
+ if (options?.fromOffset !== void 0) params["from_offset"] = Number(options.fromOffset);
1256
+ const result = await this.connection.request(
1257
+ "WATCH_INSTANCE" /* WATCH_INSTANCE */,
1258
+ params
1259
+ );
1260
+ const handler = new SubscriptionHandler(
1261
+ result.subscription_id,
1262
+ () => this.unwatch(result.subscription_id)
1263
+ );
1264
+ this.subscriptions.register(result.subscription_id, handler);
1265
+ return handler;
1266
+ }
1267
+ /**
1268
+ * Watch all instances matching the filter.
1269
+ */
1270
+ async watchAll(options) {
1271
+ const params = {};
1272
+ if (options?.includeCtx !== void 0) params["include_ctx"] = options.includeCtx;
1273
+ if (options?.fromOffset !== void 0) params["from_offset"] = Number(options.fromOffset);
1274
+ if (options?.machines) params["machines"] = options.machines;
1275
+ if (options?.fromStates) params["from_states"] = options.fromStates;
1276
+ if (options?.toStates) params["to_states"] = options.toStates;
1277
+ if (options?.events) params["events"] = options.events;
1278
+ const result = await this.connection.request(
1279
+ "WATCH_ALL" /* WATCH_ALL */,
1280
+ params
1281
+ );
1282
+ const handler = new SubscriptionHandler(
1283
+ result.subscription_id,
1284
+ () => this.unwatch(result.subscription_id)
1285
+ );
1286
+ this.subscriptions.register(result.subscription_id, handler);
1287
+ return handler;
1288
+ }
1289
+ /**
1290
+ * Cancel a watch subscription.
1291
+ */
1292
+ async unwatch(subscriptionId) {
1293
+ await this.connection.request("UNWATCH" /* UNWATCH */, { subscription_id: subscriptionId });
1294
+ this.subscriptions.unregister(subscriptionId);
1295
+ }
1296
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1297
+ on(event, listener) {
1298
+ return super.on(event, listener);
1299
+ }
1300
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1301
+ once(event, listener) {
1302
+ return super.once(event, listener);
1303
+ }
1304
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1305
+ off(event, listener) {
1306
+ return super.off(event, listener);
1307
+ }
1308
+ };
1309
+
1310
+ exports.AuthenticationError = AuthenticationError;
1311
+ exports.Client = Client;
1312
+ exports.ClientOptions = ClientOptions;
1313
+ exports.ConflictError = ConflictError;
1314
+ exports.ConnectionError = ConnectionError;
1315
+ exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
1316
+ exports.ErrorCode = ErrorCode;
1317
+ exports.FRAME_MAGIC = FRAME_MAGIC;
1318
+ exports.FrameDecoder = FrameDecoder;
1319
+ exports.FrameEncoder = FrameEncoder;
1320
+ exports.FrameFlags = FrameFlags;
1321
+ exports.GuardFailedError = GuardFailedError;
1322
+ exports.HEADER_SIZE = HEADER_SIZE;
1323
+ exports.InvalidTransitionError = InvalidTransitionError;
1324
+ exports.NotFoundError = NotFoundError;
1325
+ exports.Operation = Operation;
1326
+ exports.PROTOCOL_VERSION = PROTOCOL_VERSION;
1327
+ exports.ProtocolError = ProtocolError;
1328
+ exports.RstmdbError = RstmdbError;
1329
+ exports.ServerError = ServerError;
1330
+ exports.TimeoutError = TimeoutError;
1331
+ //# sourceMappingURL=index.js.map
1332
+ //# sourceMappingURL=index.js.map