@sourceregistry/node-ovsdb 1.0.2 → 1.0.3

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.es ADDED
@@ -0,0 +1,613 @@
1
+ import { existsSync as f } from "node:fs";
2
+ import { createConnection as l } from "node:net";
3
+ import { EventEmitter as w } from "node:events";
4
+ import { connect as g } from "node:tls";
5
+ class E extends Error {
6
+ /**
7
+ * The error payload returned by the server.
8
+ */
9
+ response;
10
+ /**
11
+ * Creates a new RPC error wrapper.
12
+ */
13
+ constructor(t) {
14
+ super(t.details ? `${t.error}: ${t.details}` : t.error), this.name = "OvsdbRpcError", this.response = t;
15
+ }
16
+ }
17
+ class m extends Error {
18
+ /**
19
+ * The raw payload that failed validation.
20
+ */
21
+ payload;
22
+ /**
23
+ * Creates a new protocol error wrapper.
24
+ */
25
+ constructor(t, e) {
26
+ super(t), this.name = "OvsdbProtocolError", this.payload = e;
27
+ }
28
+ }
29
+ class y extends Error {
30
+ /**
31
+ * Zero-based index of the failed operation in the submitted transaction.
32
+ */
33
+ operationIndex;
34
+ /**
35
+ * Operation that produced the error.
36
+ */
37
+ operation;
38
+ /**
39
+ * OVSDB error payload returned for the failed operation.
40
+ */
41
+ result;
42
+ /**
43
+ * Raw transaction results returned by the server.
44
+ */
45
+ results;
46
+ /**
47
+ * Creates a new transaction error wrapper.
48
+ */
49
+ constructor(t) {
50
+ super(`Transaction operation ${t.operationIndex} failed: ${t.result.error}`), this.name = "OvsdbTransactionError", this.operationIndex = t.operationIndex, this.operation = t.operation, this.result = t.result, this.results = t.results;
51
+ }
52
+ }
53
+ class k {
54
+ stagedOperations = [];
55
+ /**
56
+ * Returns the currently staged operations.
57
+ */
58
+ get operations() {
59
+ return this.stagedOperations;
60
+ }
61
+ /**
62
+ * Adds an operation to the transaction.
63
+ */
64
+ add(t) {
65
+ return this.stagedOperations.push(t), t;
66
+ }
67
+ /**
68
+ * Stages an insert operation.
69
+ */
70
+ insert(t) {
71
+ return this.add(t);
72
+ }
73
+ /**
74
+ * Stages a select operation.
75
+ */
76
+ select(t) {
77
+ return this.add(t);
78
+ }
79
+ /**
80
+ * Stages an update operation.
81
+ */
82
+ update(t) {
83
+ return this.add(t);
84
+ }
85
+ /**
86
+ * Stages a mutate operation.
87
+ */
88
+ mutate(t) {
89
+ return this.add(t);
90
+ }
91
+ /**
92
+ * Stages a delete operation.
93
+ */
94
+ delete(t) {
95
+ return this.add(t);
96
+ }
97
+ /**
98
+ * Stages a wait operation.
99
+ */
100
+ wait(t) {
101
+ return this.add(t);
102
+ }
103
+ /**
104
+ * Stages a comment operation.
105
+ */
106
+ comment(t) {
107
+ return this.add({
108
+ op: "comment",
109
+ comment: t
110
+ });
111
+ }
112
+ /**
113
+ * Stages an assert operation.
114
+ */
115
+ assert(t) {
116
+ return this.add({
117
+ op: "assert",
118
+ lock: t
119
+ });
120
+ }
121
+ /**
122
+ * Stages a commit operation.
123
+ */
124
+ commit(t = !1) {
125
+ return this.add({
126
+ op: "commit",
127
+ durable: t
128
+ });
129
+ }
130
+ /**
131
+ * Stages an abort operation.
132
+ */
133
+ abort() {
134
+ return this.add({
135
+ op: "abort"
136
+ });
137
+ }
138
+ }
139
+ class x extends w {
140
+ timeout;
141
+ connectionOptions;
142
+ connectionFactory;
143
+ socket = null;
144
+ requestId = 1;
145
+ receiveBuffer = "";
146
+ pendingRequests = /* @__PURE__ */ new Map();
147
+ connected = !1;
148
+ closeEmitted = !1;
149
+ /**
150
+ * Creates a new OVSDB client instance.
151
+ */
152
+ constructor(t = {}) {
153
+ super(), this.timeout = t.timeout ?? 5e3, this.connectionOptions = q(t), this.connectionFactory = t.connectionFactory;
154
+ }
155
+ /**
156
+ * Returns `true` when the underlying socket is currently connected.
157
+ */
158
+ get isConnected() {
159
+ return this.connected;
160
+ }
161
+ /**
162
+ * Opens the transport connection.
163
+ *
164
+ * @returns The connected client instance for chaining.
165
+ */
166
+ async connect() {
167
+ if (this.connected)
168
+ return this;
169
+ if (!this.connectionFactory && this.connectionOptions.transport === "unix" && !f(this.connectionOptions.socketPath))
170
+ throw new Error(`OVSDB socket not found: ${this.connectionOptions.socketPath}`);
171
+ const t = this.connectionFactory ? this.connectionFactory(this.connectionOptions) : v(this.connectionOptions);
172
+ this.attachSocket(t);
173
+ const e = this.connectionOptions.transport === "tls" ? "secureConnect" : "connect";
174
+ return await new Promise((s, n) => {
175
+ const a = setTimeout(() => {
176
+ i(), this.disposeTransport(new Error(`Connection timeout after ${this.timeout}ms`)), n(new Error(`Connection timeout after ${this.timeout}ms`));
177
+ }, this.timeout), o = () => {
178
+ i(), this.connected = !0, this.closeEmitted = !1, this.emit("connect"), s();
179
+ }, c = (h) => {
180
+ i(), n(h);
181
+ }, i = () => {
182
+ clearTimeout(a), t.off(e, o), t.off("error", c);
183
+ };
184
+ t.once(e, o), t.once("error", c);
185
+ }), this;
186
+ }
187
+ /**
188
+ * Sends a raw JSON-RPC request and resolves with its `result` payload.
189
+ *
190
+ * @param method RPC method name.
191
+ * @param params RPC parameters.
192
+ */
193
+ async request(t, e = []) {
194
+ this.assertConnected();
195
+ const s = this.requestId++, n = {
196
+ method: t,
197
+ params: e,
198
+ id: s
199
+ };
200
+ return await new Promise((a, o) => {
201
+ const c = setTimeout(() => {
202
+ this.pendingRequests.delete(s), o(new Error(`Request timeout for method: ${t}`));
203
+ }, this.timeout);
204
+ this.pendingRequests.set(s, {
205
+ resolve: (i) => a(i),
206
+ reject: o,
207
+ timeoutId: c
208
+ }), this.writeMessage(n).catch((i) => {
209
+ clearTimeout(c), this.pendingRequests.delete(s), o(i);
210
+ });
211
+ });
212
+ }
213
+ /**
214
+ * Sends a JSON-RPC notification without waiting for a response.
215
+ *
216
+ * @param method RPC method name.
217
+ * @param params RPC parameters.
218
+ */
219
+ async notify(t, e = []) {
220
+ this.assertConnected(), await this.writeMessage({ method: t, params: e });
221
+ }
222
+ /**
223
+ * Returns the database names exposed by the connected OVSDB server.
224
+ */
225
+ async listDbs() {
226
+ return await this.request("list_dbs", []);
227
+ }
228
+ /**
229
+ * Returns the schema definition for a database.
230
+ *
231
+ * @param dbName Database name.
232
+ */
233
+ async getSchema(t = "Open_vSwitch") {
234
+ return await this.request("get_schema", [t]);
235
+ }
236
+ /**
237
+ * Executes a single transaction.
238
+ *
239
+ * The response preserves operation ordering, so tuple inputs infer tuple outputs.
240
+ *
241
+ * @param dbName Database name.
242
+ * @param operations Transaction operations.
243
+ */
244
+ async transact(t, e) {
245
+ return await this.request(
246
+ "transact",
247
+ [t, ...e]
248
+ );
249
+ }
250
+ /**
251
+ * Stages a transaction in a callback and submits it only if the callback
252
+ * completes successfully.
253
+ *
254
+ * This helper is convenient when you want a scoped, imperative API while
255
+ * still sending exactly one OVSDB `transact` request.
256
+ *
257
+ * @param dbName Database name.
258
+ * @param callback Callback that stages operations on the transaction object.
259
+ * @param options Auto-commit behavior for the staged transaction.
260
+ */
261
+ async transaction(t, e, s = {}) {
262
+ const n = new k(), a = await e(n), o = [...n.operations], c = s.autoCommit ?? !0, i = o.some((u) => u.op === "commit" || u.op === "abort");
263
+ if (c && !i && o.push({
264
+ op: "commit",
265
+ durable: s.durable ?? !1
266
+ }), o.length === 0)
267
+ return {
268
+ value: a,
269
+ operations: o,
270
+ results: []
271
+ };
272
+ const h = await this.request(
273
+ "transact",
274
+ [t, ...o]
275
+ );
276
+ for (const [u, d] of h.entries())
277
+ if (O(d))
278
+ throw new y({
279
+ operationIndex: u,
280
+ operation: o[u],
281
+ result: d,
282
+ results: h
283
+ });
284
+ return {
285
+ value: a,
286
+ operations: o,
287
+ results: h
288
+ };
289
+ }
290
+ /**
291
+ * Cancels a previously issued request by id.
292
+ *
293
+ * @param requestId JSON-RPC request id to cancel.
294
+ */
295
+ async cancel(t) {
296
+ return await this.request("cancel", [t]);
297
+ }
298
+ /**
299
+ * Starts a standard RFC 7047 monitor.
300
+ *
301
+ * @param dbName Database name.
302
+ * @param monitorId Application-defined monitor id.
303
+ * @param monitorRequests Per-table monitor definitions.
304
+ */
305
+ async monitor(t, e, s) {
306
+ return await this.request("monitor", [
307
+ t,
308
+ e,
309
+ s
310
+ ]);
311
+ }
312
+ /**
313
+ * Starts an Open vSwitch conditional monitor.
314
+ *
315
+ * @param dbName Database name.
316
+ * @param monitorId Application-defined monitor id.
317
+ * @param monitorRequests Per-table conditional monitor definitions.
318
+ */
319
+ async monitorCond(t, e, s) {
320
+ return await this.request("monitor_cond", [
321
+ t,
322
+ e,
323
+ s
324
+ ]);
325
+ }
326
+ /**
327
+ * Starts an Open vSwitch conditional monitor from a known transaction id.
328
+ *
329
+ * @param dbName Database name.
330
+ * @param monitorId Application-defined monitor id.
331
+ * @param monitorRequests Per-table conditional monitor definitions.
332
+ * @param lastTransactionId Last seen transaction id, or `null` for a fresh snapshot.
333
+ */
334
+ async monitorCondSince(t, e, s, n = null) {
335
+ return await this.request("monitor_cond_since", [
336
+ t,
337
+ e,
338
+ s,
339
+ n
340
+ ]);
341
+ }
342
+ /**
343
+ * Cancels a monitor by its monitor id.
344
+ *
345
+ * @param monitorId Monitor id used when the monitor was created.
346
+ */
347
+ async monitorCancel(t) {
348
+ return await this.request("monitor_cancel", [t]);
349
+ }
350
+ /**
351
+ * Acquires a named database lock.
352
+ *
353
+ * @param lockId Lock identifier.
354
+ */
355
+ async lock(t) {
356
+ return await this.request("lock", [t]);
357
+ }
358
+ /**
359
+ * Forces ownership of a named database lock.
360
+ *
361
+ * @param lockId Lock identifier.
362
+ */
363
+ async steal(t) {
364
+ return await this.request("steal", [t]);
365
+ }
366
+ /**
367
+ * Releases a previously acquired named database lock.
368
+ *
369
+ * @param lockId Lock identifier.
370
+ */
371
+ async unlock(t) {
372
+ return await this.request("unlock", [t]);
373
+ }
374
+ /**
375
+ * Sends an echo request to validate transport liveness.
376
+ *
377
+ * @param payload Values to be echoed back by the server.
378
+ */
379
+ async echo(...t) {
380
+ return await this.request("echo", t);
381
+ }
382
+ /**
383
+ * Enables or disables Open vSwitch database change awareness.
384
+ *
385
+ * @param enabled Whether the server should report change awareness metadata.
386
+ */
387
+ async setDbChangeAware(t = !0) {
388
+ return await this.request("set_db_change_aware", [t]);
389
+ }
390
+ /**
391
+ * Closes the connection and rejects all pending requests.
392
+ */
393
+ async close() {
394
+ this.disposeTransport();
395
+ }
396
+ /**
397
+ * Implements `AsyncDisposable`.
398
+ */
399
+ async [Symbol.asyncDispose]() {
400
+ await this.close();
401
+ }
402
+ attachSocket(t) {
403
+ this.socket = t, this.receiveBuffer = "", t.on("data", this.handleData), t.on("error", this.handleSocketError), t.on("close", this.handleSocketClose);
404
+ }
405
+ handleData = (t) => {
406
+ this.receiveBuffer += typeof t == "string" ? t : t.toString("utf8");
407
+ let e = p(this.receiveBuffer);
408
+ for (; e; )
409
+ this.receiveBuffer = e.rest, this.parseFrame(e.frame), e = p(this.receiveBuffer);
410
+ const s = this.receiveBuffer.trimStart();
411
+ s && s[0] !== "{" && s[0] !== "[" && (this.emitProtocolError("Received non-JSON data on the transport", this.receiveBuffer), this.receiveBuffer = "");
412
+ };
413
+ handleSocketError = (t) => {
414
+ this.emit("transportError", t), this.disposeTransport(t);
415
+ };
416
+ handleSocketClose = () => {
417
+ this.disposeTransport();
418
+ };
419
+ parseFrame(t) {
420
+ try {
421
+ const e = JSON.parse(t);
422
+ this.handleMessage(e);
423
+ } catch {
424
+ const s = new m("Failed to parse JSON message", t);
425
+ this.emit("protocolError", s, t);
426
+ }
427
+ }
428
+ handleMessage(t) {
429
+ if (!t || typeof t != "object") {
430
+ this.emitProtocolError("Expected a JSON object message", t);
431
+ return;
432
+ }
433
+ if ("method" in t && typeof t.method == "string") {
434
+ const e = t;
435
+ if (e.id !== void 0 && e.id !== null) {
436
+ this.handleIncomingRequest(e.method, e.params ?? [], e.id);
437
+ return;
438
+ }
439
+ this.handleNotification(t);
440
+ return;
441
+ }
442
+ if ("id" in t) {
443
+ this.handleResponse(t);
444
+ return;
445
+ }
446
+ this.emitProtocolError("Received message without method or id", t);
447
+ }
448
+ handleResponse(t) {
449
+ const e = this.pendingRequests.get(t.id);
450
+ if (!e) {
451
+ this.emitProtocolError("Received response for an unknown request id", t);
452
+ return;
453
+ }
454
+ if (this.pendingRequests.delete(t.id), clearTimeout(e.timeoutId), t.error) {
455
+ e.reject(new E(t.error));
456
+ return;
457
+ }
458
+ e.resolve(t.result);
459
+ }
460
+ async handleIncomingRequest(t, e, s) {
461
+ if (t === "echo") {
462
+ await this.writeMessage({
463
+ id: s,
464
+ result: e,
465
+ error: null
466
+ });
467
+ return;
468
+ }
469
+ await this.writeMessage({
470
+ id: s,
471
+ result: null,
472
+ error: {
473
+ error: "not supported",
474
+ details: `Unsupported server request: ${t}`
475
+ }
476
+ });
477
+ }
478
+ handleNotification(t) {
479
+ switch (this.emit("notification", t), t.method) {
480
+ case "update":
481
+ this.emit("update", t);
482
+ break;
483
+ case "update2":
484
+ this.emit("update2", t);
485
+ break;
486
+ case "update3":
487
+ this.emit("update3", t);
488
+ break;
489
+ case "locked":
490
+ this.emit("locked", t);
491
+ break;
492
+ case "stolen":
493
+ this.emit("stolen", t);
494
+ break;
495
+ default:
496
+ this.emitProtocolError("Received an unknown notification method", t);
497
+ break;
498
+ }
499
+ }
500
+ emitProtocolError(t, e) {
501
+ const s = new m(t, e);
502
+ this.emit("protocolError", s, e);
503
+ }
504
+ async writeMessage(t) {
505
+ this.assertConnected(), await new Promise((e, s) => {
506
+ this.socket?.write(`${JSON.stringify(t)}
507
+ `, (n) => {
508
+ if (n) {
509
+ s(n);
510
+ return;
511
+ }
512
+ e();
513
+ });
514
+ });
515
+ }
516
+ assertConnected() {
517
+ if (!this.connected || !this.socket)
518
+ throw new Error("Not connected to OVSDB");
519
+ }
520
+ disposeTransport(t) {
521
+ const e = this.socket;
522
+ this.socket = null, this.connected = !1, this.receiveBuffer = "", e && (e.off("data", this.handleData), e.off("error", this.handleSocketError), e.off("close", this.handleSocketClose), e.destroyed || e.destroy());
523
+ const s = t ?? new Error("Connection closed");
524
+ for (const n of this.pendingRequests.values())
525
+ clearTimeout(n.timeoutId), n.reject(s);
526
+ this.pendingRequests.clear(), this.closeEmitted || (this.closeEmitted = !0, this.emit("close"));
527
+ }
528
+ }
529
+ function q(r = {}) {
530
+ if (r.host) {
531
+ const t = r.port ?? 6640;
532
+ return r.tls ? {
533
+ transport: "tls",
534
+ host: r.host,
535
+ port: t,
536
+ tlsOptions: {
537
+ host: r.host,
538
+ port: t,
539
+ ...r.tlsOptions
540
+ }
541
+ } : {
542
+ transport: "tcp",
543
+ host: r.host,
544
+ port: t
545
+ };
546
+ }
547
+ return {
548
+ transport: "unix",
549
+ socketPath: r.socketPath ?? "/var/run/openvswitch/db.sock"
550
+ };
551
+ }
552
+ function v(r) {
553
+ switch (r.transport) {
554
+ case "unix":
555
+ return l(r.socketPath);
556
+ case "tcp":
557
+ return l(r.port, r.host);
558
+ case "tls":
559
+ return g(r.tlsOptions);
560
+ }
561
+ }
562
+ function O(r) {
563
+ return typeof r == "object" && r !== null && "error" in r && typeof r.error == "string";
564
+ }
565
+ function p(r) {
566
+ let t = 0;
567
+ for (; t < r.length && /\s/u.test(r[t]); )
568
+ t += 1;
569
+ if (t >= r.length)
570
+ return null;
571
+ const e = r[t];
572
+ if (!(e === "{" ? "}" : e === "[" ? "]" : null))
573
+ return null;
574
+ let n = 0, a = !1, o = !1;
575
+ for (let c = t; c < r.length; c += 1) {
576
+ const i = r[c];
577
+ if (a) {
578
+ if (o) {
579
+ o = !1;
580
+ continue;
581
+ }
582
+ if (i === "\\") {
583
+ o = !0;
584
+ continue;
585
+ }
586
+ i === '"' && (a = !1);
587
+ continue;
588
+ }
589
+ if (i === '"') {
590
+ a = !0;
591
+ continue;
592
+ }
593
+ if (i === "{" || i === "[") {
594
+ n += 1;
595
+ continue;
596
+ }
597
+ if ((i === "}" || i === "]") && (n -= 1, n === 0))
598
+ return {
599
+ frame: r.slice(t, c + 1),
600
+ rest: r.slice(c + 1)
601
+ };
602
+ }
603
+ return null;
604
+ }
605
+ export {
606
+ x as OVSDBClient,
607
+ m as OvsdbProtocolError,
608
+ E as OvsdbRpcError,
609
+ k as OvsdbTransaction,
610
+ y as OvsdbTransactionError,
611
+ q as resolveConnectionOptions
612
+ };
613
+ //# sourceMappingURL=index.es.map