@rljson/io 0.0.69 → 0.0.70

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.
@@ -18,7 +18,7 @@ found in the LICENSE file in the root of this package.
18
18
 
19
19
  The central abstraction that defines all database operations:
20
20
 
21
- ```
21
+ ```text
22
22
  ┌─────────────────────────────────────────────┐
23
23
  │ Io Interface │
24
24
  ├─────────────────────────────────────────────┤
@@ -42,7 +42,7 @@ The central abstraction that defines all database operations:
42
42
 
43
43
  In-memory implementation using JavaScript objects.
44
44
 
45
- ```
45
+ ```text
46
46
  ┌─────────────────────┐
47
47
  │ IoMem │
48
48
  ├─────────────────────┤
@@ -61,6 +61,21 @@ In-memory implementation using JavaScript objects.
61
61
  - Uses `@rljson/hash` for data hashing and identity
62
62
  - `IsReady` pattern for initialization tracking
63
63
 
64
+ **Performance internals** (no observable API change):
65
+
66
+ - Rows are indexed per table by content hash — write dedup is O(1) and
67
+ `readRows` with a string `_hash` in the where clause resolves through
68
+ the index instead of scanning the table
69
+ - Table data is kept hash-sorted incrementally (binary-searched insert)
70
+ instead of re-sorting the whole table per write
71
+ - Table and global hashes are updated lazily: writes mark tables dirty,
72
+ hashes are recomputed before they become observable (`dump`,
73
+ `dumpTable`, `createOrExtendTable`, re-`init`) — deterministic hashes
74
+ make the refreshed state identical to eager updates
75
+ - The latest table configuration and column keys are cached per table
76
+ (updated on create/extend), so validation does not re-scan all
77
+ configurations per read/write
78
+
64
79
  **Data Structure:**
65
80
 
66
81
  ```typescript
@@ -76,7 +91,7 @@ _mem = {
76
91
 
77
92
  Remote database connection over sockets (Socket.IO compatible).
78
93
 
79
- ```
94
+ ```text
80
95
  ┌──────────────┐ Socket ┌──────────────┐
81
96
  │ IoPeer │◄───────────────────────►│ IoPeerBridge │
82
97
  │ (Client) │ Events/Acks │ (Server) │
@@ -107,7 +122,7 @@ Remote database connection over sockets (Socket.IO compatible).
107
122
 
108
123
  Server-side handler that bridges socket events to Io operations.
109
124
 
110
- ```
125
+ ```text
111
126
  ┌─────────────────────────────────────┐
112
127
  │ IoPeerBridge │
113
128
  ├─────────────────────────────────────┤
@@ -132,7 +147,7 @@ Server-side handler that bridges socket events to Io operations.
132
147
 
133
148
  Aggregates multiple Io instances with priority-based cascading.
134
149
 
135
- ```
150
+ ```text
136
151
  ┌────────────────────────────────────────────┐
137
152
  │ IoMulti │
138
153
  ├────────────────────────────────────────────┤
@@ -182,7 +197,7 @@ IoMultiIo {
182
197
 
183
198
  Provides name mapping between different table name formats.
184
199
 
185
- ```
200
+ ```text
186
201
  ┌──────────────────────────────────────┐
187
202
  │ IoDbNameMapping │
188
203
  ├──────────────────────────────────────┤
@@ -202,7 +217,7 @@ Provides name mapping between different table name formats.
202
217
 
203
218
  Server implementation that combines Socket.IO with Io backends.
204
219
 
205
- ```
220
+ ```text
206
221
  ┌─────────────────────────────────────┐
207
222
  │ IoServer │
208
223
  ├─────────────────────────────────────┤
@@ -230,7 +245,7 @@ Server implementation that combines Socket.IO with Io backends.
230
245
 
231
246
  ### Write Operation
232
247
 
233
- ```
248
+ ```text
234
249
  Client Code
235
250
 
236
251
 
@@ -248,7 +263,7 @@ io.write(data)
248
263
 
249
264
  ### Read Operation (IoMulti Cascade)
250
265
 
251
- ```
266
+ ```text
252
267
  io.readRows({table: 'users', where: {id: 1}})
253
268
 
254
269
 
@@ -293,7 +308,7 @@ return rljson; // Only after loop completes
293
308
 
294
309
  ### Event-Based Protocol
295
310
 
296
- ```
311
+ ```text
297
312
  Client (IoPeer) Server (IoPeerBridge)
298
313
  │ │
299
314
  ├─── emit('readRows', request) ────►│
@@ -18,7 +18,7 @@ found in the LICENSE file in the root of this package.
18
18
 
19
19
  The central abstraction that defines all database operations:
20
20
 
21
- ```
21
+ ```text
22
22
  ┌─────────────────────────────────────────────┐
23
23
  │ Io Interface │
24
24
  ├─────────────────────────────────────────────┤
@@ -42,7 +42,7 @@ The central abstraction that defines all database operations:
42
42
 
43
43
  In-memory implementation using JavaScript objects.
44
44
 
45
- ```
45
+ ```text
46
46
  ┌─────────────────────┐
47
47
  │ IoMem │
48
48
  ├─────────────────────┤
@@ -61,6 +61,21 @@ In-memory implementation using JavaScript objects.
61
61
  - Uses `@rljson/hash` for data hashing and identity
62
62
  - `IsReady` pattern for initialization tracking
63
63
 
64
+ **Performance internals** (no observable API change):
65
+
66
+ - Rows are indexed per table by content hash — write dedup is O(1) and
67
+ `readRows` with a string `_hash` in the where clause resolves through
68
+ the index instead of scanning the table
69
+ - Table data is kept hash-sorted incrementally (binary-searched insert)
70
+ instead of re-sorting the whole table per write
71
+ - Table and global hashes are updated lazily: writes mark tables dirty,
72
+ hashes are recomputed before they become observable (`dump`,
73
+ `dumpTable`, `createOrExtendTable`, re-`init`) — deterministic hashes
74
+ make the refreshed state identical to eager updates
75
+ - The latest table configuration and column keys are cached per table
76
+ (updated on create/extend), so validation does not re-scan all
77
+ configurations per read/write
78
+
64
79
  **Data Structure:**
65
80
 
66
81
  ```typescript
@@ -76,7 +91,7 @@ _mem = {
76
91
 
77
92
  Remote database connection over sockets (Socket.IO compatible).
78
93
 
79
- ```
94
+ ```text
80
95
  ┌──────────────┐ Socket ┌──────────────┐
81
96
  │ IoPeer │◄───────────────────────►│ IoPeerBridge │
82
97
  │ (Client) │ Events/Acks │ (Server) │
@@ -107,7 +122,7 @@ Remote database connection over sockets (Socket.IO compatible).
107
122
 
108
123
  Server-side handler that bridges socket events to Io operations.
109
124
 
110
- ```
125
+ ```text
111
126
  ┌─────────────────────────────────────┐
112
127
  │ IoPeerBridge │
113
128
  ├─────────────────────────────────────┤
@@ -132,7 +147,7 @@ Server-side handler that bridges socket events to Io operations.
132
147
 
133
148
  Aggregates multiple Io instances with priority-based cascading.
134
149
 
135
- ```
150
+ ```text
136
151
  ┌────────────────────────────────────────────┐
137
152
  │ IoMulti │
138
153
  ├────────────────────────────────────────────┤
@@ -182,7 +197,7 @@ IoMultiIo {
182
197
 
183
198
  Provides name mapping between different table name formats.
184
199
 
185
- ```
200
+ ```text
186
201
  ┌──────────────────────────────────────┐
187
202
  │ IoDbNameMapping │
188
203
  ├──────────────────────────────────────┤
@@ -202,7 +217,7 @@ Provides name mapping between different table name formats.
202
217
 
203
218
  Server implementation that combines Socket.IO with Io backends.
204
219
 
205
- ```
220
+ ```text
206
221
  ┌─────────────────────────────────────┐
207
222
  │ IoServer │
208
223
  ├─────────────────────────────────────┤
@@ -230,7 +245,7 @@ Server implementation that combines Socket.IO with Io backends.
230
245
 
231
246
  ### Write Operation
232
247
 
233
- ```
248
+ ```text
234
249
  Client Code
235
250
 
236
251
 
@@ -248,7 +263,7 @@ io.write(data)
248
263
 
249
264
  ### Read Operation (IoMulti Cascade)
250
265
 
251
- ```
266
+ ```text
252
267
  io.readRows({table: 'users', where: {id: 1}})
253
268
 
254
269
 
@@ -293,7 +308,7 @@ return rljson; // Only after loop completes
293
308
 
294
309
  ### Event-Based Protocol
295
310
 
296
- ```
311
+ ```text
297
312
  Client (IoPeer) Server (IoPeerBridge)
298
313
  │ │
299
314
  ├─── emit('readRows', request) ────►│
package/dist/io-mem.d.ts CHANGED
@@ -36,6 +36,79 @@ export declare class IoMem implements Io {
36
36
  private _isReady;
37
37
  private _isOpen;
38
38
  private _mem;
39
+ /**
40
+ * Latest table configuration per table (the one with the most
41
+ * columns). Kept in sync by _createTable/_extendTable so that reads
42
+ * and writes need no repeated scan over all configurations.
43
+ */
44
+ private readonly _latestCfgs;
45
+ /** Column key sets per table, derived from _latestCfgs */
46
+ private readonly _columnKeys;
47
+ /**
48
+ * Per-table index of rows by content hash. Rows are only ever added,
49
+ * never removed, so the index cannot go stale.
50
+ */
51
+ private readonly _rowIndex;
52
+ /**
53
+ * Tables whose table hash (and thus the global hash) is outdated
54
+ * after writes. Hashes are refreshed lazily before they become
55
+ * observable (dump, dumpTable, create/extend) instead of after every
56
+ * single write — row hashes themselves are always up to date.
57
+ */
58
+ private readonly _dirtyTableHashes;
59
+ /**
60
+ * Recomputes the hashes of all dirty tables and the global hash.
61
+ * Produces exactly the state an eager per-write update would have
62
+ * produced (hashes are deterministic over the same data).
63
+ */
64
+ private _refreshHashes;
65
+ /**
66
+ * Returns the row index of a table, building it lazily from the
67
+ * table data on first access.
68
+ * @param table - The table to index
69
+ */
70
+ private _rowIndexFor;
71
+ /**
72
+ * Inserts a row into hash-sorted table data at its sorted position —
73
+ * preserves the order sortTableDataAndUpdateHash establishes without
74
+ * a full re-sort.
75
+ * @param data - The hash-sorted table data
76
+ * @param row - The row to insert
77
+ */
78
+ private static _insertSortedByHash;
79
+ /**
80
+ * The row filter predicate of readRows. Extracted so that the indexed
81
+ * fast path and the full scan share identical semantics.
82
+ * @param row - The row to check
83
+ * @param where - The where clause
84
+ */
85
+ private static _rowMatchesWhere;
86
+ /**
87
+ * Returns the latest table configuration, filling the cache lazily
88
+ * from IoTools (which picks the config with the most columns).
89
+ * @param table - The table to get the configuration for
90
+ */
91
+ private _latestCfg;
92
+ /**
93
+ * Updates the cached latest configuration of a table
94
+ * @param cfg - The new latest configuration
95
+ */
96
+ private _setLatestCfg;
97
+ /**
98
+ * Throws when one of the given columns does not exist in the table.
99
+ * Mirrors IoTools.throwWhenColumnDoesNotExist but uses the cached
100
+ * configuration.
101
+ * @param table - The table to check
102
+ * @param columns - The columns to check
103
+ */
104
+ private _throwWhenColumnDoesNotExist;
105
+ /**
106
+ * Throws when the data does not match the table configurations.
107
+ * Mirrors IoTools.throwWhenTableDataDoesNotMatchCfg but uses the
108
+ * cached configurations.
109
+ * @param data - The data to validate
110
+ */
111
+ private _throwWhenTableDataDoesNotMatchCfg;
39
112
  private _init;
40
113
  private _initTableCfgs;
41
114
  private _updateGlobalHash;
@@ -48,5 +121,5 @@ export declare class IoMem implements Io {
48
121
  private _contentType;
49
122
  private _write;
50
123
  private _readRows;
51
- _removeNullValues(rljson: Rljson): void;
124
+ _removeNullValues(rljson: Rljson): boolean;
52
125
  }
package/dist/io.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { hip, hsh } from "@rljson/hash";
2
2
  import { IsReady } from "@rljson/is-ready";
3
- import { copy, equals, merge } from "@rljson/json";
3
+ import { equals, copy, merge } from "@rljson/json";
4
4
  import { iterateTables, throwOnInvalidTableCfg, validateRljsonAgainstTableCfg, iterateTablesSync } from "@rljson/rljson";
5
5
  class IoDbNameMapping {
6
6
  // The primary key column is always named '_hash'
@@ -443,8 +443,182 @@ class IoMem {
443
443
  _isReady = new IsReady();
444
444
  _isOpen = false;
445
445
  _mem = hip({});
446
+ /**
447
+ * Latest table configuration per table (the one with the most
448
+ * columns). Kept in sync by _createTable/_extendTable so that reads
449
+ * and writes need no repeated scan over all configurations.
450
+ */
451
+ _latestCfgs = /* @__PURE__ */ new Map();
452
+ /** Column key sets per table, derived from _latestCfgs */
453
+ _columnKeys = /* @__PURE__ */ new Map();
454
+ /**
455
+ * Per-table index of rows by content hash. Rows are only ever added,
456
+ * never removed, so the index cannot go stale.
457
+ */
458
+ _rowIndex = /* @__PURE__ */ new Map();
459
+ /**
460
+ * Tables whose table hash (and thus the global hash) is outdated
461
+ * after writes. Hashes are refreshed lazily before they become
462
+ * observable (dump, dumpTable, create/extend) instead of after every
463
+ * single write — row hashes themselves are always up to date.
464
+ */
465
+ _dirtyTableHashes = /* @__PURE__ */ new Set();
466
+ // ...........................................................................
467
+ /**
468
+ * Recomputes the hashes of all dirty tables and the global hash.
469
+ * Produces exactly the state an eager per-write update would have
470
+ * produced (hashes are deterministic over the same data).
471
+ */
472
+ _refreshHashes() {
473
+ if (this._dirtyTableHashes.size === 0) {
474
+ return;
475
+ }
476
+ for (const tableKey of this._dirtyTableHashes) {
477
+ const table = this._mem[tableKey];
478
+ table._hash = "";
479
+ hip(table, {
480
+ updateExistingHashes: false,
481
+ throwOnWrongHashes: false
482
+ });
483
+ }
484
+ this._dirtyTableHashes.clear();
485
+ this._updateGlobalHash();
486
+ }
487
+ // ...........................................................................
488
+ /**
489
+ * Returns the row index of a table, building it lazily from the
490
+ * table data on first access.
491
+ * @param table - The table to index
492
+ */
493
+ _rowIndexFor(table) {
494
+ let index = this._rowIndex.get(table);
495
+ if (!index) {
496
+ index = /* @__PURE__ */ new Map();
497
+ const tableData = this._mem[table]._data;
498
+ for (const row of tableData) {
499
+ index.set(row._hash, row);
500
+ }
501
+ this._rowIndex.set(table, index);
502
+ }
503
+ return index;
504
+ }
505
+ // ...........................................................................
506
+ /**
507
+ * Inserts a row into hash-sorted table data at its sorted position —
508
+ * preserves the order sortTableDataAndUpdateHash establishes without
509
+ * a full re-sort.
510
+ * @param data - The hash-sorted table data
511
+ * @param row - The row to insert
512
+ */
513
+ static _insertSortedByHash(data, row) {
514
+ const hash = row._hash;
515
+ let lo = 0;
516
+ let hi = data.length;
517
+ while (lo < hi) {
518
+ const mid = lo + hi >> 1;
519
+ if (data[mid]._hash < hash) {
520
+ lo = mid + 1;
521
+ } else {
522
+ hi = mid;
523
+ }
524
+ }
525
+ data.splice(lo, 0, row);
526
+ }
527
+ // ...........................................................................
528
+ /**
529
+ * The row filter predicate of readRows. Extracted so that the indexed
530
+ * fast path and the full scan share identical semantics.
531
+ * @param row - The row to check
532
+ * @param where - The where clause
533
+ */
534
+ static _rowMatchesWhere(row, where) {
535
+ for (const column in where) {
536
+ const a = row[column];
537
+ const b = where[column];
538
+ if (b === null && a === void 0) {
539
+ return true;
540
+ }
541
+ if (!equals(a, b)) {
542
+ return false;
543
+ }
544
+ }
545
+ return true;
546
+ }
547
+ // ...........................................................................
548
+ /**
549
+ * Returns the latest table configuration, filling the cache lazily
550
+ * from IoTools (which picks the config with the most columns).
551
+ * @param table - The table to get the configuration for
552
+ */
553
+ async _latestCfg(table) {
554
+ let cfg = this._latestCfgs.get(table);
555
+ if (!cfg) {
556
+ cfg = await this._ioTools.tableCfg(table);
557
+ this._latestCfgs.set(table, cfg);
558
+ }
559
+ return cfg;
560
+ }
561
+ /**
562
+ * Updates the cached latest configuration of a table
563
+ * @param cfg - The new latest configuration
564
+ */
565
+ _setLatestCfg(cfg) {
566
+ this._latestCfgs.set(cfg.key, cfg);
567
+ this._columnKeys.set(cfg.key, new Set(cfg.columns.map((c) => c.key)));
568
+ }
569
+ /**
570
+ * Throws when one of the given columns does not exist in the table.
571
+ * Mirrors IoTools.throwWhenColumnDoesNotExist but uses the cached
572
+ * configuration.
573
+ * @param table - The table to check
574
+ * @param columns - The columns to check
575
+ */
576
+ async _throwWhenColumnDoesNotExist(table, columns) {
577
+ let columnKeys = this._columnKeys.get(table);
578
+ if (!columnKeys) {
579
+ const cfg = await this._latestCfg(table);
580
+ columnKeys = new Set(cfg.columns.map((c) => c.key));
581
+ this._columnKeys.set(table, columnKeys);
582
+ }
583
+ const missingColumns = columns.filter((column) => !columnKeys.has(column));
584
+ if (missingColumns.length > 0) {
585
+ throw new Error(
586
+ `The following columns do not exist in table "${table}": ${missingColumns.join(
587
+ ", "
588
+ )}.`
589
+ );
590
+ }
591
+ }
592
+ /**
593
+ * Throws when the data does not match the table configurations.
594
+ * Mirrors IoTools.throwWhenTableDataDoesNotMatchCfg but uses the
595
+ * cached configurations.
596
+ * @param data - The data to validate
597
+ */
598
+ async _throwWhenTableDataDoesNotMatchCfg(data) {
599
+ const errors = [];
600
+ for (const tableKey of Object.keys(data)) {
601
+ const table = data[tableKey];
602
+ if (typeof table !== "object" || !Array.isArray(table?._data)) continue;
603
+ if (table._type === "tableCfgs") continue;
604
+ const tableCfg = await this._latestCfg(tableKey);
605
+ errors.push(...validateRljsonAgainstTableCfg(table._data, tableCfg));
606
+ }
607
+ if (errors.length > 0) {
608
+ throw new Error(
609
+ `Table data does not match the configuration.
610
+
611
+ Errors:
612
+ ${errors.map((e) => `- ${e}`).join("\n")}`
613
+ );
614
+ }
615
+ }
446
616
  // ...........................................................................
447
617
  async _init() {
618
+ this._refreshHashes();
619
+ this._rowIndex.clear();
620
+ this._latestCfgs.clear();
621
+ this._columnKeys.clear();
448
622
  this._ioTools = new IoTools(this);
449
623
  this._initTableCfgs();
450
624
  this._updateGlobalHash();
@@ -476,6 +650,7 @@ class IoMem {
476
650
  }
477
651
  // ...........................................................................
478
652
  async _createOrExtendTable(request) {
653
+ this._refreshHashes();
479
654
  const tableCfg = request.tableCfg;
480
655
  await this._ioTools.throwWhenTableIsNotCompatible(tableCfg);
481
656
  const { key } = tableCfg;
@@ -492,6 +667,8 @@ class IoMem {
492
667
  newConfig = hsh(newConfig);
493
668
  this._mem.tableCfgs._data.push(newConfig);
494
669
  this._ioTools.sortTableDataAndUpdateHash(this._mem.tableCfgs);
670
+ this._setLatestCfg(newConfig);
671
+ this._rowIndex.get("tableCfgs")?.set(newConfig._hash, newConfig);
495
672
  const table = {
496
673
  _type: newConfig.type,
497
674
  _data: [],
@@ -509,6 +686,8 @@ class IoMem {
509
686
  newConfig = hsh(newConfig);
510
687
  this._mem.tableCfgs._data.push(newConfig);
511
688
  this._ioTools.sortTableDataAndUpdateHash(this._mem.tableCfgs);
689
+ this._setLatestCfg(newConfig);
690
+ this._rowIndex.get("tableCfgs")?.set(newConfig._hash, newConfig);
512
691
  const table = this._mem[newConfig.key];
513
692
  table._tableCfg = newConfig._hash;
514
693
  this._updateTableHash(newConfig.key);
@@ -516,11 +695,13 @@ class IoMem {
516
695
  }
517
696
  // ...........................................................................
518
697
  async _dump() {
698
+ this._refreshHashes();
519
699
  return copy(this._mem);
520
700
  }
521
701
  // ...........................................................................
522
702
  async _dumpTable(request) {
523
703
  await this._ioTools.throwWhenTableDoesNotExist(request.table);
704
+ this._refreshHashes();
524
705
  const table = this._mem[request.table];
525
706
  return {
526
707
  [request.table]: copy(table)
@@ -534,49 +715,48 @@ class IoMem {
534
715
  // ...........................................................................
535
716
  async _write(request) {
536
717
  const addedData = hsh(request.data);
537
- this._removeNullValues(addedData);
718
+ const removedNullValues = this._removeNullValues(addedData);
538
719
  const tables = Object.keys(addedData);
539
- hsh(addedData);
720
+ if (removedNullValues) {
721
+ hsh(addedData);
722
+ }
540
723
  await this._ioTools.throwWhenTablesDoNotExist(request.data);
541
- await this._ioTools.throwWhenTableDataDoesNotMatchCfg(request.data);
724
+ await this._throwWhenTableDataDoesNotMatchCfg(request.data);
542
725
  for (const table of tables) {
543
726
  if (table.startsWith("_")) {
544
727
  continue;
545
728
  }
546
729
  const oldTable = this._mem[table];
547
730
  const newTable = addedData[table];
731
+ const rowIndex = this._rowIndexFor(table);
548
732
  for (const item of newTable._data) {
549
733
  const hash = item._hash;
550
- const exists = oldTable._data.find((i) => i._hash === hash);
551
- if (!exists) {
552
- oldTable._data.push(item);
734
+ if (!rowIndex.has(hash)) {
735
+ rowIndex.set(hash, item);
736
+ IoMem._insertSortedByHash(oldTable._data, item);
553
737
  }
554
738
  }
555
- this._ioTools.sortTableDataAndUpdateHash(oldTable);
739
+ this._dirtyTableHashes.add(table);
556
740
  }
557
- this._updateGlobalHash();
558
741
  }
559
742
  // ...........................................................................
560
743
  async _readRows(request) {
561
744
  await this._ioTools.throwWhenTableDoesNotExist(request.table);
562
- await this._ioTools.throwWhenColumnDoesNotExist(
745
+ await this._throwWhenColumnDoesNotExist(
563
746
  request.table,
564
747
  Object.keys(request.where)
565
748
  );
566
749
  const table = this._mem[request.table];
567
- const tableDataFiltered = table._data.filter((row) => {
568
- for (const column in request.where) {
569
- const a = row[column];
570
- const b = request.where[column];
571
- if (b === null && a === void 0) {
572
- return true;
573
- }
574
- if (!equals(a, b)) {
575
- return false;
576
- }
577
- }
578
- return true;
579
- });
750
+ const whereHash = request.where["_hash"];
751
+ let tableDataFiltered;
752
+ if (typeof whereHash === "string") {
753
+ const row = this._rowIndexFor(request.table).get(whereHash);
754
+ tableDataFiltered = row && IoMem._rowMatchesWhere(row, request.where) ? [row] : [];
755
+ } else {
756
+ tableDataFiltered = table._data.filter(
757
+ (row) => IoMem._rowMatchesWhere(row, request.where)
758
+ );
759
+ }
580
760
  const tableFiltered = {
581
761
  _type: table._type,
582
762
  _data: tableDataFiltered
@@ -588,16 +768,19 @@ class IoMem {
588
768
  return result;
589
769
  }
590
770
  _removeNullValues(rljson) {
771
+ let removedAny = false;
591
772
  iterateTablesSync(rljson, (table) => {
592
773
  const data = rljson[table]._data;
593
774
  for (const row of data) {
594
775
  for (const key in row) {
595
776
  if (row[key] === null) {
596
777
  delete row[key];
778
+ removedAny = true;
597
779
  }
598
780
  }
599
781
  }
600
782
  });
783
+ return removedAny;
601
784
  }
602
785
  }
603
786
  class PeerSocketMock {
package/dist/io.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"io.js","sources":["/Users/maximilianheller/Documents/Development/rljson-io/src/io-db-name-mapping.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/io-tools.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/io-mem.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/peer-socket-mock.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/io-peer.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/io-multi.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/io-peer-bridge.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/io-server.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/io-test-setup.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/io.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/reverse-ref.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/socket-mock.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/directional-socket-mock.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/socket.ts"],"sourcesContent":["// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nexport class IoDbNameMapping {\n // The primary key column is always named '_hash'\n public primaryKeyColumn: string = '_hash';\n public dataSection: string = '_data';\n public typeColumn: string = 'type';\n public keyColumn: string = 'key';\n\n // Names for the main tables in the database\n public tableNames: { [key: string]: string } = {\n main: 'tableCfgs',\n revision: 'revisions',\n };\n\n /// Suffix handling for the database\n private _suffix: { [key: string]: string } = {\n col: '_col',\n tbl: '_tbl',\n tmp: '_tmp',\n };\n\n // ********************************************************************\n // add and remove suffixes for use in SQL statements\n private _addFix(name: string, fix: string): string {\n return name.endsWith(fix) ? name : name + fix;\n }\n\n public addTableSuffix(name: string): string {\n return this._addFix(name, this._suffix.tbl);\n }\n\n public addColumnSuffix(name: string): string {\n return this._addFix(name, this._suffix.col);\n }\n\n public addTmpSuffix(name: string): string {\n return this._addFix(name, this._suffix.tmp);\n }\n\n private _removeFix(name: string, fix: string): string {\n return name.endsWith(fix) ? name.slice(0, -fix.length) : name;\n }\n\n public removeTableSuffix(name: string): string {\n return this._removeFix(name, this._suffix.tbl);\n }\n\n public removeColumnSuffix(name: string): string {\n return this._removeFix(name, this._suffix.col);\n }\n\n public removeTmpSuffix(name: string): string {\n return this._removeFix(name, this._suffix.tmp);\n }\n}\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { hip } from '@rljson/hash';\nimport {\n iterateTables,\n Rljson,\n TableCfg,\n TableKey,\n TableType,\n throwOnInvalidTableCfg,\n validateRljsonAgainstTableCfg,\n} from '@rljson/rljson';\n\nimport { IoMem } from './io-mem.ts';\nimport { Io } from './io.ts';\n\nexport type IoObserver = (data: Rljson) => void;\n\n/**\n * Provides utility functions for the Io interface.\n */\nexport class IoTools {\n /**\n * Constructor\n * @param io The Io interface to use\n */\n constructor(public readonly io: Io) {}\n\n /**\n * Returns the table configuration of the tableCfgs table.\n */\n static get tableCfgsTableCfg() {\n const tableCfg = hip<TableCfg>({\n _hash: '',\n key: 'tableCfgs',\n type: 'tableCfgs',\n isHead: false,\n isRoot: false,\n isShared: true,\n previous: '',\n\n columns: [\n {\n key: '_hash',\n type: 'string',\n titleShort: 'Hash',\n titleLong: 'Row Hash',\n },\n {\n key: 'key',\n type: 'string',\n titleShort: 'Key',\n titleLong: 'Table Key',\n },\n {\n key: 'type',\n type: 'string',\n titleShort: 'Type',\n titleLong: 'Content Type',\n },\n {\n key: 'isHead',\n type: 'boolean',\n titleShort: 'Is Head',\n titleLong: 'Is Head Table',\n },\n {\n key: 'isRoot',\n type: 'boolean',\n titleShort: 'Is Root',\n titleLong: 'Is Root Table',\n },\n {\n key: 'isShared',\n type: 'boolean',\n titleShort: 'Is Shared',\n titleLong: 'Is Shared Table',\n },\n {\n key: 'previous',\n type: 'string',\n titleShort: 'Previous',\n titleLong: 'Previous Table Configuration Hash',\n },\n {\n key: 'columns',\n type: 'jsonArray',\n titleShort: 'Columns',\n titleLong: 'Column Configurations',\n },\n ],\n });\n\n return tableCfg;\n }\n\n /**\n * Initializes the revisions table.\n */\n initRevisionsTable = async () => {\n const tableCfg: TableCfg = {\n key: 'revisions',\n type: 'revisions',\n isHead: true,\n isRoot: true,\n isShared: false,\n\n columns: [\n {\n key: '_hash',\n type: 'string',\n titleShort: 'Hash',\n titleLong: 'Row Hash',\n },\n {\n key: 'table',\n type: 'string',\n titleShort: 'Table',\n titleLong: 'Table Key',\n },\n {\n key: 'predecessor',\n type: 'string',\n titleShort: 'Predecessor',\n titleLong: 'Predecessor Revision Hash',\n },\n {\n key: 'successor',\n type: 'string',\n titleShort: 'Successor',\n titleLong: 'Successor Revision Hash',\n },\n {\n key: 'timestamp',\n type: 'number',\n titleShort: 'Timestamp',\n titleLong: 'Revision Timestamp',\n },\n {\n key: 'id',\n type: 'string',\n titleShort: 'ID',\n titleLong: 'Revision ID',\n },\n ],\n };\n\n await this.io.createOrExtendTable({ tableCfg });\n };\n\n /**\n * Example object for test purposes\n * @returns An instance of io tools\n */\n static example = async () => {\n const io = await IoMem.example();\n await io.init();\n await io.isReady();\n return new IoTools(io);\n };\n\n /**\n * Throws if the table does not exist\n */\n async throwWhenTableDoesNotExist(table: TableKey): Promise<void> {\n const exists = await this.io.tableExists(table);\n if (!exists) {\n throw new Error(`Table \"${table}\" not found`);\n }\n }\n\n /**\n * Throws if any of the tables in rljson do not exist\n * @param rljson - The Rljson object to check\n */\n async throwWhenTablesDoNotExist(rljson: Rljson): Promise<void> {\n try {\n await iterateTables(rljson, async (tableKey) => {\n const exists = await this.io.tableExists(tableKey);\n if (!exists) {\n throw new Error(`Table \"${tableKey}\" not found`);\n }\n });\n } catch (e) {\n const missingTables = (e as Array<any>).map((e) => e.tableKey);\n\n throw new Error(\n `The following tables do not exist: ${missingTables.join(', ')}`,\n );\n }\n }\n\n /**\n * Returns the current table cfgs of all tables\n * @returns The table configuration of all tables\n */\n async tableCfgs(): Promise<TableCfg[]> {\n const tables = await this.io.rawTableCfgs();\n\n // Take the latest version of each type key\n const newestVersion: Record<TableKey, TableCfg> = {};\n for (let i = tables.length - 1; i >= 0; i--) {\n const table = tables[i];\n const existing = newestVersion[table.key];\n if (!existing || existing.columns.length < table.columns.length) {\n newestVersion[table.key] = table;\n }\n }\n\n // Sort the tables by key\n /* v8 ignore next -- @preserve */\n const resultData = Object.values(newestVersion).sort((a, b) => {\n if (a.key < b.key) {\n return -1;\n }\n if (a.key > b.key) {\n return 1;\n }\n\n return 0;\n });\n return resultData;\n }\n\n /**\n * Returns a list with all table names\n */\n async allTableKeys(): Promise<string[]> {\n const result = (await this.tableCfgs()).map((e) => e.key);\n return result;\n }\n\n /**\n * Returns the configuration of a given table\n */\n async tableCfg(table: TableKey): Promise<TableCfg> {\n const tableCfg = await this.tableCfgOrNull(table);\n if (!tableCfg) {\n throw new Error(`Table \"${table}\" not found`);\n }\n\n return tableCfg!;\n }\n\n /**\n * Returns the configuration of a given table or null if it does not exist.\n\n */\n async tableCfgOrNull(table: TableKey): Promise<TableCfg | null> {\n const tableCfgs = await this.tableCfgs();\n const tableCfg = tableCfgs.find((e) => e.key === table);\n return tableCfg ?? null;\n }\n\n /**\n * Returns a list of all column names of a given table\n */\n async allColumnKeys(table: TableKey): Promise<string[]> {\n const tableCfg = await this.tableCfg(table);\n const result = tableCfg.columns.map((column) => column.key);\n return result;\n }\n\n /**\n * Throws when a column does not exist in a given table\n * @param table - The table to check\n * @param columns - The column to check\n */\n async throwWhenColumnDoesNotExist(\n table: TableKey,\n columns: string[],\n ): Promise<void> {\n const tableCfg = await this.tableCfg(table);\n const columnKeys = tableCfg.columns.map((column) => column.key);\n const missingColumns = columns.filter(\n (column) => !columnKeys.includes(column),\n );\n if (missingColumns.length > 0) {\n throw new Error(\n `The following columns do not exist in table \"${table}\": ${missingColumns.join(\n ', ',\n )}.`,\n );\n }\n }\n\n /**\n * Throws when a table update is not compatible with the current table\n * configuration.\n */\n async throwWhenTableIsNotCompatible(update: TableCfg): Promise<void> {\n const prefix = `Invalid update of table able \"${update.key}\"`;\n\n throwOnInvalidTableCfg(update);\n\n // Check compatibility with existing table\n const existing = await this.tableCfgOrNull(update.key);\n if (existing) {\n // Have columns been deleted?\n if (existing.columns.length > update.columns.length) {\n const deletedColumnKeys = existing.columns\n .map((column) => column.key)\n .filter(\n (key) => !update.columns.some((column) => column.key === key),\n );\n /* v8 ignore next -- @preserve */\n if (deletedColumnKeys.length > 0) {\n const deletedColumns = deletedColumnKeys.join(', ');\n throw new Error(\n `${prefix}: Columns must not be deleted. ` +\n `Deleted columns: ${deletedColumns}}`,\n );\n }\n }\n\n // Have column keys changed?\n for (let i = 0; i < existing.columns.length; i++) {\n const before = existing.columns[i].key;\n const after = update.columns[i].key;\n if (before !== after) {\n throw new Error(\n `${prefix}: ` +\n `Column keys must not change! ` +\n `Column \"${before}\" was renamed into \"${after}\".`,\n );\n }\n }\n\n // Have column types changed?\n for (let i = 0; i < existing.columns.length; i++) {\n const column = existing.columns[i].key;\n const before = existing.columns[i].type;\n const after = update.columns[i].type;\n if (before !== after) {\n throw new Error(\n `${prefix}: ` +\n `Column types must not change! ` +\n `Type of column \"${column}\" was changed from \"${before}\" to ${after}.`,\n );\n }\n }\n }\n }\n\n /**\n * Throws if the data in the table do not match the table configuration\n */\n async throwWhenTableDataDoesNotMatchCfg(data: Rljson) {\n const errors: string[] = [];\n\n await iterateTables(data, async (tableKey) => {\n const tableCfg = await this.tableCfg(tableKey);\n const table = data[tableKey];\n\n // Ignore tableCfgs table\n /* v8 ignore next -- @preserve */\n if (table._type === 'tableCfgs') return;\n\n errors.push(...validateRljsonAgainstTableCfg(table._data, tableCfg));\n });\n\n if (errors.length > 0) {\n throw new Error(\n `Table data does not match the configuration.\\n\\nErrors:\\n${errors\n .map((e) => `- ${e}`)\n .join('\\n')}`,\n );\n }\n }\n\n /**\n * Sorts the data of a table by the hash and updates the table hash in place\n */\n sortTableDataAndUpdateHash(table: TableType): void {\n table._data.sort((a, b) => {\n const hashA = a._hash as string;\n const hashB = b._hash as string;\n /* v8 ignore next -- @preserve */\n if (hashA < hashB) {\n return -1;\n }\n /* v8 ignore next -- @preserve */\n if (hashA > hashB) {\n return 1;\n }\n\n /* v8 ignore next -- @preserve */\n return 0;\n });\n\n table._hash = '';\n hip(table, {\n updateExistingHashes: false,\n throwOnWrongHashes: false,\n });\n }\n}\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { hip, hsh } from '@rljson/hash';\nimport { IsReady } from '@rljson/is-ready';\nimport { copy, equals, JsonValue } from '@rljson/json';\nimport {\n ContentType, iterateTablesSync, Rljson, TableCfg, TableKey, TableType\n} from '@rljson/rljson';\n\nimport { IoTools } from './io-tools.ts';\nimport { Io } from './io.ts';\n\n\n/**\n * In-Memory implementation of the Rljson Io interface.\n */\nexport class IoMem implements Io {\n // ...........................................................................\n // Constructor & example\n\n init(): Promise<void> {\n this._isOpen = true;\n return this._init();\n }\n\n close(): Promise<void> {\n this._isOpen = false;\n return Promise.resolve();\n }\n\n get isOpen(): boolean {\n return this._isOpen;\n }\n\n static example = async () => {\n const io = new IoMem();\n await io.init();\n return io;\n };\n\n // ...........................................................................\n // General\n isReady() {\n return this._isReady.promise;\n }\n\n // ...........................................................................\n // Dump\n\n dump(): Promise<Rljson> {\n return this._dump();\n }\n\n async dumpTable(request: { table: string }): Promise<Rljson> {\n return this._dumpTable(request);\n }\n\n // ...........................................................................\n // Meta Data\n\n async contentType(request: { table: string }): Promise<ContentType> {\n return this._contentType(request);\n }\n\n // ...........................................................................\n // Rows\n\n readRows(request: {\n table: string;\n where: { [column: string]: JsonValue };\n }): Promise<Rljson> {\n return this._readRows(request);\n }\n\n async rowCount(table: string): Promise<number> {\n const tableData = this._mem[table] as TableType;\n if (!tableData) {\n throw new Error(`Table \"${table}\" not found`);\n }\n return Promise.resolve(tableData._data.length);\n }\n\n // ...........................................................................\n // Write\n\n write(request: { data: Rljson }): Promise<void> {\n return this._write(request);\n }\n\n // ...........................................................................\n // Table management\n async tableExists(tableKey: TableKey): Promise<boolean> {\n const table = this._mem[tableKey] as TableType;\n return table ? true : false;\n }\n\n createOrExtendTable(request: { tableCfg: TableCfg }): Promise<void> {\n return this._createOrExtendTable(request);\n }\n\n async rawTableCfgs(): Promise<TableCfg[]> {\n const tables = this._mem.tableCfgs._data as TableCfg[];\n return tables;\n }\n\n // ######################\n // Private\n // ######################\n\n private _ioTools!: IoTools;\n\n private _isReady = new IsReady();\n private _isOpen = false;\n\n private _mem: Rljson = hip({} as Rljson);\n\n // ...........................................................................\n private async _init() {\n this._ioTools = new IoTools(this);\n this._initTableCfgs();\n this._updateGlobalHash();\n await this._ioTools.initRevisionsTable();\n hsh(this._mem);\n\n this._isReady.resolve();\n }\n\n // ...........................................................................\n private _initTableCfgs = () => {\n const tableCfg = IoTools.tableCfgsTableCfg;\n\n this._mem.tableCfgs = hip({\n _type: 'tableCfgs',\n _data: [tableCfg],\n _tableCfg: tableCfg._hash as string,\n });\n };\n\n // ...........................................................................\n private _updateGlobalHash() {\n (this._mem as any)._hash = '';\n hip(this._mem, {\n updateExistingHashes: false,\n });\n }\n\n // ...........................................................................\n private _updateTableHash(tableKey: TableKey) {\n const table = this._mem[tableKey] as TableType;\n table._hash = '';\n hip(table, { updateExistingHashes: false });\n }\n\n // ...........................................................................\n private async _createOrExtendTable(request: {\n tableCfg: TableCfg;\n }): Promise<void> {\n // Make sure that the table config is compatible\n // with an potential existing table\n const tableCfg = request.tableCfg;\n await this._ioTools.throwWhenTableIsNotCompatible(tableCfg);\n\n const { key } = tableCfg;\n\n // Recreate hashes in the case the existing hashes are wrong\n const newConfig = hsh(tableCfg);\n\n // Find an existing table config with the same hash\n const existingConfig = await this._ioTools.tableCfgOrNull(key);\n\n // Write the new config into the database\n if (!existingConfig) {\n this._createTable(newConfig, key);\n } else {\n this._extendTable(existingConfig, newConfig);\n }\n }\n\n // ...........................................................................\n private _createTable(newConfig: TableCfg, tableKey: TableKey) {\n // Write the table config into the database\n newConfig = hsh(newConfig);\n this._mem.tableCfgs._data.push(newConfig);\n this._ioTools.sortTableDataAndUpdateHash(this._mem.tableCfgs);\n\n // Create a table and write it into the database\n const table: TableType = {\n _type: newConfig.type,\n _data: [],\n _tableCfg: newConfig._hash as string,\n };\n\n this._mem[tableKey] ??= hip(table);\n\n // Update hashes\n this._updateTableHash(tableKey);\n this._updateGlobalHash();\n }\n\n // ...........................................................................\n private _extendTable(existingConfig: TableCfg, newConfig: TableCfg) {\n // No columns added? Return.\n if (existingConfig.columns.length === newConfig.columns.length) {\n return;\n }\n\n // Write the new table config into the database\n newConfig = hsh(newConfig);\n this._mem.tableCfgs._data.push(newConfig);\n this._ioTools.sortTableDataAndUpdateHash(this._mem.tableCfgs);\n\n // Update the config of the existing table\n const table = this._mem[newConfig.key] as TableType;\n table._tableCfg = newConfig._hash as string;\n\n // Update the hashes\n this._updateTableHash(newConfig.key);\n this._updateGlobalHash();\n }\n\n // ...........................................................................\n\n private async _dump(): Promise<Rljson> {\n return copy(this._mem);\n }\n\n // ...........................................................................\n private async _dumpTable(request: { table: string }): Promise<Rljson> {\n await this._ioTools.throwWhenTableDoesNotExist(request.table);\n\n const table = this._mem[request.table] as TableType;\n\n return {\n [request.table]: copy(table),\n };\n }\n\n // ...........................................................................\n private async _contentType(request: { table: string }): Promise<ContentType> {\n await this._ioTools.throwWhenTableDoesNotExist(request.table);\n\n return (this._mem[request.table] as TableType)._type;\n }\n\n // ...........................................................................\n private async _write(request: { data: Rljson }): Promise<void> {\n const addedData = hsh(request.data);\n this._removeNullValues(addedData);\n const tables = Object.keys(addedData);\n hsh(addedData);\n\n await this._ioTools.throwWhenTablesDoNotExist(request.data);\n await this._ioTools.throwWhenTableDataDoesNotMatchCfg(request.data);\n\n for (const table of tables) {\n if (table.startsWith('_')) {\n continue;\n }\n\n const oldTable = this._mem[table] as TableType;\n const newTable = addedData[table] as TableType;\n\n // Table exists. Merge data\n for (const item of newTable._data) {\n const hash = item._hash;\n const exists = oldTable._data.find((i) => i._hash === hash);\n if (!exists) {\n oldTable._data.push(item as any);\n }\n }\n\n this._ioTools.sortTableDataAndUpdateHash(oldTable);\n }\n\n // Recalc main hashes\n this._updateGlobalHash();\n }\n\n // ...........................................................................\n private async _readRows(request: {\n table: string;\n where: { [column: string]: JsonValue };\n }): Promise<Rljson> {\n await this._ioTools.throwWhenTableDoesNotExist(request.table);\n await this._ioTools.throwWhenColumnDoesNotExist(\n request.table,\n Object.keys(request.where),\n );\n\n // Read table from data\n const table = this._mem[request.table] as TableType;\n\n // Filter table data\n const tableDataFiltered = table._data.filter((row) => {\n for (const column in request.where) {\n const a = row[column];\n const b = request.where[column];\n if (b === null && a === undefined) {\n return true;\n }\n\n if (!equals(a, b)) {\n return false;\n }\n }\n return true;\n });\n\n // Create an table\n const tableFiltered: TableType = {\n _type: table._type,\n _data: tableDataFiltered,\n };\n\n this._ioTools.sortTableDataAndUpdateHash(tableFiltered);\n\n const result: Rljson = {\n [request.table]: tableFiltered,\n };\n\n return result;\n }\n\n _removeNullValues(rljson: Rljson) {\n iterateTablesSync(rljson, (table) => {\n const data = rljson[table]._data;\n\n for (const row of data) {\n for (const key in row) {\n if (row[key] === null) {\n delete row[key];\n }\n }\n }\n });\n }\n}\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { Io } from './io.ts';\nimport { Socket } from './socket.ts';\n\nexport class PeerSocketMock implements Socket {\n private _listenersMap: Map<string | symbol, Array<(...args: any[]) => void>> =\n new Map();\n\n connected: boolean = false;\n disconnected: boolean = true;\n\n constructor(private _io: Io) {}\n\n // ............................................................................\n /**\n * Removes a specific listener for the specified event.\n * @param eventName - The name of the event.\n * @param listener - The callback function to remove.\n * @returns The PeerSocketMock instance for chaining.\n */\n off(eventName: string | symbol, listener: (...args: any[]) => void): this {\n /* v8 ignore next -- @preserve */\n const listeners = this._listenersMap.get(eventName) || [];\n const index = listeners.indexOf(listener);\n /* v8 ignore else -- @preserve */\n if (index !== -1) {\n listeners.splice(index, 1);\n this._listenersMap.set(eventName, listeners);\n }\n return this;\n }\n\n // ............................................................................\n /**\n * Removes all listeners for the specified event, or all listeners if no event is specified.\n * @param eventName - (Optional) The name of the event.\n * @returns The PeerSocketMock instance for chaining.\n */\n removeAllListeners(eventName?: string | symbol): this {\n if (eventName) {\n this._listenersMap.delete(eventName);\n } else {\n this._listenersMap.clear();\n }\n return this;\n }\n\n // ............................................................................\n /**\n * Registers an event listener for the specified event.\n * @param eventName - The name of the event to listen for.\n * @param listener - The callback function to invoke when the event is emitted.\n * @returns The PeerSocketMock instance for chaining.\n */\n on(eventName: string | symbol, listener: (...args: any[]) => void): this {\n if (!this._listenersMap.has(eventName)) {\n this._listenersMap.set(eventName, []);\n }\n this._listenersMap.get(eventName)!.push(listener);\n return this;\n }\n\n // ...........................................................................\n /**\n * Simulates a connection event.\n *\n * Emits the 'connect' event to all registered listeners.\n */\n connect(): void {\n this.connected = true;\n this.disconnected = false;\n\n const listeners = this._listenersMap.get('connect') || [];\n for (const cb of listeners) {\n cb({});\n }\n }\n\n // ...........................................................................\n /**\n * Simulates a disconnection event.\n *\n * Emits the 'disconnect' event to all registered listeners.\n */\n disconnect(): void {\n this.connected = false;\n this.disconnected = true;\n\n const listeners = this._listenersMap.get('disconnect') || [];\n for (const cb of listeners) {\n cb({});\n }\n }\n\n // ............................................................................\n /**\n * Emits an event, invoking the corresponding method on the Io instance.\n * @param eventName - The name of the event to emit.\n * @param args - The arguments to pass to the event listener.\n * @returns\n */\n emit(eventName: string | symbol, ...args: any[]): boolean {\n const fn = (this._io as any)[eventName] as (...args: any[]) => Promise<any>;\n if (typeof fn !== 'function') {\n throw new Error(`Event ${eventName.toString()} not supported`);\n }\n const cb = args[args.length - 1];\n fn.apply(this._io, args.slice(0, -1))\n .then((result) => {\n cb(result, null);\n })\n .catch((err) => {\n cb(null, err);\n });\n\n return true;\n }\n}\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { JsonValue } from '@rljson/json';\nimport { ContentType, Rljson, TableCfg, TableKey } from '@rljson/rljson';\n\nimport { IoMem } from './io-mem.ts';\nimport { Io } from './io.ts';\nimport { PeerSocketMock } from './peer-socket-mock.ts';\nimport { Socket } from './socket.ts';\n\n\nexport class IoPeer implements Io {\n isOpen: boolean = false;\n\n constructor(\n private _socket: Socket,\n private _requestTimeoutMs: number = 30_000,\n ) {}\n\n // ...........................................................................\n /**\n * Wraps a promise with a timeout. If the promise does not settle within\n * `_requestTimeoutMs`, the returned promise rejects with a timeout error.\n * Clears the timer on settlement to avoid leaks and unhandled rejections.\n */\n private _withTimeout<T>(promise: Promise<T>, operation: string): Promise<T> {\n if (this._requestTimeoutMs <= 0) return promise;\n let timer: ReturnType<typeof setTimeout>;\n const timeoutPromise = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n reject(\n new Error(\n `Timeout after ${this._requestTimeoutMs}ms: ${operation}`,\n ),\n );\n }, this._requestTimeoutMs);\n });\n return Promise.race([promise, timeoutPromise]).finally(() => {\n clearTimeout(timer!);\n });\n }\n\n // ...........................................................................\n /**\n *\n * Initializes the Peer connection.\n * @returns\n */\n async init(): Promise<void> {\n // Update isOpen on connect/disconnect\n this._socket.on('connect', () => {\n this.isOpen = true;\n });\n this._socket.on('disconnect', () => {\n this.isOpen = false;\n });\n\n // Connect the socket\n this._socket.connect();\n\n // Wait for the socket to connect before returning\n return new Promise<void>((resolve) => {\n /* v8 ignore else -- @preserve */\n if (this._socket.connected) {\n this.isOpen = true;\n resolve();\n } else {\n this._socket.on('connect', () => {\n resolve();\n });\n }\n });\n }\n\n // ...........................................................................\n /**\n * Closes the Peer connection.\n * @returns\n */\n\n async close(): Promise<void> {\n // Disconnect the socket and wait for it to complete\n if (!this._socket.connected) return;\n\n return new Promise<void>((resolve) => {\n this._socket.on('disconnect', () => {\n resolve();\n });\n this._socket.disconnect();\n });\n }\n\n // ...........................................................................\n /**\n * Returns a promise that resolves once the Peer connection is ready.\n * @returns\n */\n async isReady(): Promise<void> {\n if (!!this._socket && this._socket.connected === true) this.isOpen = true;\n else this.isOpen = false;\n\n return !!this.isOpen ? Promise.resolve() : Promise.reject();\n }\n\n // ...........................................................................\n /**\n * Dumps the entire database content.\n * @returns A promise that resolves to the dumped database content.\n */\n async dump(): Promise<Rljson> {\n return this._withTimeout(\n new Promise((resolve) => {\n // Request dump, resolve once the data is received (ack)\n this._socket.emit('dump', (data: Rljson) => {\n resolve(data);\n });\n }),\n 'dump',\n );\n }\n\n // ...........................................................................\n /**\n * Dumps a specific table from the database.\n * @param request An object containing the table name to dump.\n * @returns A promise that resolves to the dumped table data.\n */\n dumpTable(request: { table: string }): Promise<Rljson> {\n return this._withTimeout(\n new Promise((resolve, reject) => {\n // Request dumpTable, resolve once the data is received (ack)\n this._socket.emit(\n 'dumpTable',\n request,\n (data: Rljson, error?: Error) => {\n if (error) reject(error);\n resolve(data);\n },\n );\n }),\n 'dumpTable',\n );\n }\n\n // ...........................................................................\n /**\n * Gets the content type of a specific table.\n * @param request An object containing the table name to get the content type for.\n * @returns A promise that resolves to the content type of the specified table.\n */\n contentType(request: { table: string }): Promise<ContentType> {\n return this._withTimeout(\n new Promise((resolve, reject) => {\n // Request contentType, resolve once the data is received (ack)\n this._socket.emit(\n 'contentType',\n request,\n (data: ContentType, error?: Error) => {\n /* v8 ignore next -- @preserve */\n if (error) reject(error);\n resolve(data);\n },\n );\n }),\n 'contentType',\n );\n }\n\n // ...........................................................................\n /**\n * Checks if a specific table exists in the database.\n * @param tableKey The key of the table to check for existence.\n * @returns A promise that resolves to true if the table exists, false otherwise.\n */\n tableExists(tableKey: TableKey): Promise<boolean> {\n return this._withTimeout(\n new Promise((resolve) => {\n // Request tableExists, resolve once the data is received (ack)\n this._socket.emit('tableExists', tableKey, (exists: boolean) => {\n resolve(exists);\n });\n }),\n 'tableExists',\n );\n }\n\n // ...........................................................................\n /**\n * Creates or extends a table with the given configuration.\n * @param request An object containing the table configuration.\n * @returns A promise that resolves once the table is created or extended.\n */\n createOrExtendTable(request: { tableCfg: TableCfg }): Promise<void> {\n return this._withTimeout(\n new Promise((resolve, reject) => {\n // Request createOrExtendTable, resolve once the data is received (ack)\n this._socket.emit(\n 'createOrExtendTable',\n request,\n (_?: boolean, error?: Error) => {\n if (error) reject(error);\n resolve();\n },\n );\n }),\n 'createOrExtendTable',\n );\n }\n\n // ...........................................................................\n /**\n * Retrieves the raw table configurations from the database.\n * @returns A promise that resolves to an array of table configurations.\n */\n rawTableCfgs(): Promise<TableCfg[]> {\n return this._withTimeout(\n new Promise((resolve) => {\n // Request rawTableCfgs, resolve once the data is received (ack)\n this._socket.emit('rawTableCfgs', (data: TableCfg[]) => {\n resolve(data);\n });\n }),\n 'rawTableCfgs',\n );\n }\n\n // ...........................................................................\n /**\n * Writes data to the database.\n * @param request An object containing the data to write.\n * @returns A promise that resolves once the data is written.\n */\n write(request: { data: Rljson }): Promise<void> {\n return this._withTimeout(\n new Promise((resolve, reject) => {\n // Request write, resolve once the data is received (ack)\n this._socket.emit('write', request, (_?: boolean, error?: Error) => {\n if (error) reject(error);\n resolve();\n });\n }),\n 'write',\n );\n }\n\n // ...........................................................................\n /**\n * Reads rows from a specific table that match the given criteria.\n * @param request An object containing the table name and the criteria for selecting rows.\n * @returns A promise that resolves to the selected rows.\n */\n readRows(request: {\n table: string;\n where: { [column: string]: JsonValue | null };\n }): Promise<Rljson> {\n return this._withTimeout(\n new Promise((resolve, reject) => {\n // Request readRows, resolve once the data is received (ack)\n this._socket.emit(\n 'readRows',\n request,\n (result?: Rljson, error?: Error) => {\n if (error) reject(error);\n resolve(result!);\n },\n );\n }),\n 'readRows',\n );\n }\n\n // ...........................................................................\n /**\n * Retrieves the number of rows in a specific table.\n * @param table The name of the table to count rows in.\n * @returns A promise that resolves to the number of rows in the specified table.\n */\n rowCount(table: string): Promise<number> {\n return this._withTimeout(\n new Promise((resolve, reject) => {\n // Request rowCount, resolve once the data is received (ack)\n this._socket.emit(\n 'rowCount',\n table,\n (count?: number, error?: Error) => {\n if (error) reject(error);\n resolve(count!);\n },\n );\n }),\n 'rowCount',\n );\n }\n\n // ...........................................................................\n static example = async () => {\n const ioMem = await IoMem.example();\n const socket = new PeerSocketMock(ioMem);\n const io = new IoPeer(socket);\n await io.init();\n return io;\n };\n}\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { hip } from '@rljson/hash';\nimport { Json, JsonValue, merge } from '@rljson/json';\nimport { ContentType, Rljson, RljsonTable, TableCfg, TableKey, TableType } from '@rljson/rljson';\n\nimport { IoMem } from './io-mem.ts';\nimport { IoPeer } from './io-peer.ts';\nimport { Io } from './io.ts';\nimport { PeerSocketMock } from './peer-socket-mock.ts';\n\n\n// ...........................................................................\n/**\n * Type representing an Io instance along with its capabilities and priority.\n */\nexport type IoMultiIo = {\n io: Io;\n id?: string;\n priority: number;\n read: boolean;\n write: boolean;\n dump: boolean;\n};\n\n// ...........................................................................\n/**\n * Multi Io implementation that combines multiple underlying Io instances\n * with different capabilities (read, write, dump) and priorities.\n */\nexport class IoMulti implements Io {\n isOpen: boolean = false;\n\n constructor(private _ios: Array<IoMultiIo>) {}\n\n // ...........................................................................\n /**\n *\n * Initializes all underlying Io instances.\n * @returns\n */\n async init(): Promise<void> {\n for (let idx = 0; idx < this._ios.length; idx++) {\n const { io } = this._ios[idx];\n if (io.isOpen === false) {\n throw new Error(\n 'All underlying Io instances must be initialized before initializing IoMulti',\n );\n }\n\n this._ios[idx] = { ...this._ios[idx], id: `io-${idx}` };\n }\n\n this.isOpen = true;\n return Promise.resolve();\n }\n\n // ...........................................................................\n /**\n * Closes all underlying Io instances.\n * @returns\n */\n async close(): Promise<void> {\n await Promise.all(this._ios.map((ioMultiIo) => ioMultiIo.io.close()));\n\n this.isOpen = false;\n\n return Promise.resolve();\n }\n\n // ...........................................................................\n /**\n * Returns a promise that resolves once all underlying Io instances are ready.\n * @returns\n */\n isReady(): Promise<void> {\n return Promise.all(\n this._ios.map((ioMultiIo) => ioMultiIo.io.isReady()),\n ).then(() => Promise.resolve());\n }\n\n // ...........................................................................\n /**\n * Dumps the entire database content by merging dumps from all dumpable underlying Io instances.\n * @returns\n */\n async dump(): Promise<Rljson> {\n /* v8 ignore next -- @preserve */\n if (this.dumpables.length === 0) {\n throw new Error('No dumpable Io available');\n }\n\n const dumps = await Promise.all(\n this.dumpables.map(({ io: dumpable }) => dumpable.dump()),\n );\n\n return merge(...dumps) as Rljson;\n }\n\n // ...........................................................................\n /**\n * Dumps a specific table by merging dumps from all dumpable underlying Io instances that contain the table.\n * @param request An object containing the table name to dump.\n * @returns A promise that resolves to the dumped table data.\n */\n async dumpTable(request: { table: string }): Promise<Rljson> {\n /* v8 ignore next -- @preserve */\n if (this.dumpables.length === 0) {\n throw new Error('No dumpable Io available');\n }\n\n const dumps: Rljson[] = [];\n\n for (const { io: dumpable } of this.dumpables) {\n try {\n const dump = await dumpable.dumpTable(request);\n dumps.push(dump);\n } catch {\n continue; // Table does not exist in this dumpable Io\n }\n }\n\n if (dumps.length === 0) {\n throw new Error(`Table \"${request.table}\" not found`);\n }\n\n return merge(...dumps) as Rljson;\n }\n\n // ...........................................................................\n /**\n * Retrieves the content type of a specific table from the first underlying readable Io instance that contains the table.\n * @param request An object containing the table name.\n * @returns A promise that resolves to the content type of the table.\n */\n async contentType(request: { table: string }): Promise<ContentType> {\n /* v8 ignore next -- @preserve */\n if (this.readables.length === 0) {\n throw new Error('No readable Io available');\n }\n\n for (const { io: readable } of this.readables) {\n return readable.contentType(request);\n }\n /* v8 ignore next -- @preserve */\n throw new Error(`Table \"${request.table}\" not found`);\n }\n\n // ...........................................................................\n /**\n * Checks if a specific table exists in any of the underlying readable Io\n * instances. Readables at the same priority level are queried in parallel\n * so that one slow peer does not block others.\n * @param tableKey The key of the table to check.\n * @returns A promise that resolves to true if the table exists in any readable Io, false otherwise.\n */\n async tableExists(tableKey: TableKey): Promise<boolean> {\n /* v8 ignore next -- @preserve */\n if (this.readables.length === 0) {\n throw new Error('No readable Io available');\n }\n\n const groups = IoMulti._groupByPriority(this.readables);\n for (const group of groups) {\n if (group.length === 1) {\n const exists = await group[0].io.tableExists(tableKey);\n if (exists) return true;\n } else {\n const results = await Promise.allSettled(\n group.map((r) => r.io.tableExists(tableKey)),\n );\n for (const result of results) {\n if (result.status === 'fulfilled' && result.value) return true;\n }\n }\n }\n return false;\n }\n\n // ...........................................................................\n /**\n * Creates or extends a table in all underlying writable Io instances.\n * @param request An object containing the table configuration.\n * @returns A promise that resolves once the table has been created or extended in all writable Io instances.\n */\n createOrExtendTable(request: { tableCfg: TableCfg }): Promise<void> {\n /* v8 ignore next -- @preserve */\n if (this.writables.length === 0) {\n throw new Error('No writable Io available');\n }\n //Create or extend table in all writables in parallel and resolve when all have completed\n const creations = this.writables.map(({ io: writable }) =>\n writable.createOrExtendTable(request),\n );\n return Promise.all(creations).then(() => Promise.resolve());\n }\n\n // ...........................................................................\n /**\n * Retrieves the raw table configurations from the highest priority underlying\n * readable Io instance that has any. Stops after the first readable that\n * returns results — this avoids expensive network round-trips to lower-\n * priority peers when the local cache (IoMem, priority 1) already has the\n * answer.\n * @returns A promise that resolves to an array of table configurations.\n */\n async rawTableCfgs(): Promise<TableCfg[]> {\n /* v8 ignore next -- @preserve */\n if (this.readables.length === 0) {\n throw new Error('No readable Io available');\n }\n\n const rawTableCfgs: Map<string, TableCfg> = new Map();\n for (const { io: readable } of this.readables) {\n const cfgs = await readable.rawTableCfgs();\n /* v8 ignore else -- @preserve */\n if (cfgs.length > 0) {\n for (const tableCfg of cfgs) {\n if (!rawTableCfgs.has(tableCfg.key)) {\n rawTableCfgs.set(tableCfg.key, tableCfg);\n }\n }\n break; // Stop after the first readable that has table configs\n }\n }\n return Array.from(rawTableCfgs.values());\n }\n\n // ...........................................................................\n /**\n * Writes data to all underlying writable Io instances.\n * @param request - An object containing the data to write.\n * @returns A promise that resolves once the data has been written to all writable Io instances.\n */\n write(request: { data: Rljson }): Promise<void> {\n /* v8 ignore next -- @preserve */\n if (this.writables.length === 0) {\n throw new Error('No writable Io available');\n }\n\n // Write to all writables in parallel and resolve when all have completed\n const writes = this.writables.map(({ io: writable }) =>\n writable.write(request),\n );\n return Promise.all(writes).then(() => Promise.resolve());\n }\n\n // ...........................................................................\n /**\n * Reads rows from a specific table. Readables are grouped by priority:\n * priorities are tried in ascending order. Within a priority group,\n * all readables are queried **in parallel** — only the first one to\n * return rows wins. This prevents one slow/stale peer from blocking\n * others at the same priority level.\n *\n * @param request An object containing the table name and where clause.\n * @returns A promise that resolves to the read rows.\n */\n async readRows(request: {\n table: string;\n where: { [column: string]: JsonValue | null };\n }): Promise<Rljson> {\n /* v8 ignore next -- @preserve */\n if (this.readables.length === 0) {\n throw new Error('No readable Io available');\n }\n\n let tableExistsAny = false;\n const rows: Map<string, Json> = new Map();\n let type: ContentType | undefined = undefined;\n let readFrom: string = '';\n\n const errors: Error[] = [];\n\n // Group readables by priority (already sorted by priority)\n const groups = IoMulti._groupByPriority(this.readables);\n\n for (const group of groups) {\n if (group.length === 1) {\n // Single readable at this priority — query directly (no race overhead)\n const readable = group[0];\n try {\n const { [request.table]: tableData } = await readable.io.readRows(\n request,\n );\n const tableRows = (tableData as RljsonTable<Json, ContentType>)\n ._data;\n const tableType = (tableData as RljsonTable<Json, ContentType>)\n ._type;\n tableExistsAny = true;\n type ??= tableType;\n\n if (tableRows.length > 0) {\n /* v8 ignore next -- @preserve */\n readFrom = readable.id ?? '';\n /* v8 ignore else -- @preserve */\n for (const tableRow of tableRows) {\n const ref = tableRow._hash as string;\n rows.set(ref, tableRow);\n }\n break; // Got rows — done\n }\n } catch (e) {\n errors.push(e as Error);\n }\n } else {\n // Multiple readables at the same priority — race them in parallel.\n // Collect all settled results and pick the first with rows.\n const results = await Promise.allSettled(\n group.map(async (readable) => {\n const { [request.table]: tableData } = await readable.io.readRows(\n request,\n );\n return {\n readable,\n tableRows: (tableData as RljsonTable<Json, ContentType>)._data,\n tableType: (tableData as RljsonTable<Json, ContentType>)._type,\n };\n }),\n );\n\n let foundRows = false;\n for (const result of results) {\n if (result.status === 'rejected') {\n errors.push(result.reason as Error);\n continue;\n }\n tableExistsAny = true;\n const { readable, tableRows, tableType } = result.value;\n type ??= tableType;\n if (tableRows.length > 0 && !foundRows) {\n foundRows = true;\n readFrom = readable.id ?? '';\n /* v8 ignore else -- @preserve */\n for (const tableRow of tableRows) {\n const ref = tableRow._hash as string;\n rows.set(ref, tableRow);\n }\n }\n }\n\n if (foundRows) break; // Got rows — done\n }\n }\n\n if (!tableExistsAny) {\n /* v8 ignore if -- @preserve */\n if (errors.length === 0) {\n throw new Error(`Table \"${request.table}\" not found`);\n } else {\n const preciseErrors = errors.filter(\n (err) => !err.message.includes(`Table \"${request.table}\" not found`),\n );\n if (preciseErrors.length > 0) {\n throw preciseErrors[0];\n } else {\n throw errors[0];\n }\n }\n } else {\n const rljson = {\n [request.table]: hip({ _data: Array.from(rows.values()), _type: type }),\n } as Rljson;\n\n // Write merged rows back to all writables (hot-swapping cache)\n if (this.writables.length > 0 && rows.size > 0) {\n for (const writeable of this.writables) {\n if (writeable.id === readFrom) {\n continue; // Skip writing back to the source readable Io\n }\n /* v8 ignore next -- @preserve */\n try {\n await writeable.io.write({\n data: rljson,\n });\n } catch {\n continue; // Table does not exist in this writable Io\n }\n }\n }\n\n // Return merged rows\n return rljson;\n }\n }\n\n // ...........................................................................\n /**\n * Retrieves the row count of a specific table by aggregating row counts from all dumpable underlying Io instances.\n * @param table The name of the table.\n * @returns A promise that resolves to the row count of the table.\n */\n async rowCount(table: string): Promise<number> {\n /* v8 ignore next -- @preserve */\n if (this.dumpables.length === 0) {\n throw new Error('No dumpable Io available');\n }\n\n const dumpTable = await this.dumpTable({ table });\n const tableData: TableType = dumpTable[table];\n /* v8 ignore next -- @preserve */\n if (!tableData) {\n throw new Error(`Table \"${table}\" not found`);\n }\n return Promise.resolve(tableData._data.length);\n }\n\n // ...........................................................................\n /**\n * Gets the list of underlying readable Io instances, sorted by priority.\n */\n get readables(): Array<IoMultiIo> {\n return this._ios\n .filter((ioMultiIo) => ioMultiIo.read)\n .sort((a, b) => a.priority - b.priority);\n }\n\n // ...........................................................................\n /**\n * Gets the list of underlying writable Io instances, sorted by priority.\n */\n get writables(): Array<IoMultiIo> {\n return this._ios\n .filter((ioMultiIo) => ioMultiIo.write)\n .sort((a, b) => a.priority - b.priority);\n }\n\n // ...........................................................................\n /**\n * Gets the list of underlying dumpable Io instances, sorted by priority.\n */\n get dumpables(): Array<IoMultiIo> {\n return this._ios\n .filter((ioMultiIo) => ioMultiIo.dump)\n .sort((a, b) => a.priority - b.priority);\n }\n\n // ...........................................................................\n /**\n * Groups IoMultiIo entries by their priority value.\n * Input must already be sorted by priority (ascending).\n * Returns an array of groups, each group containing entries with the same\n * priority.\n */\n static _groupByPriority(ios: Array<IoMultiIo>): Array<Array<IoMultiIo>> {\n const groups: Array<Array<IoMultiIo>> = [];\n let current: Array<IoMultiIo> = [];\n let currentPriority: number | null = null;\n\n for (const io of ios) {\n if (io.priority !== currentPriority) {\n if (current.length > 0) groups.push(current);\n current = [io];\n currentPriority = io.priority;\n } else {\n current.push(io);\n }\n }\n if (current.length > 0) groups.push(current);\n\n return groups;\n }\n\n // ...........................................................................\n static example = async () => {\n const ioPeerMem = await IoMem.example();\n await ioPeerMem.init();\n\n const ioPeerSocket = new PeerSocketMock(ioPeerMem);\n const ioPeer = new IoPeer(ioPeerSocket);\n await ioPeer.init();\n\n const ioMem = await IoMem.example();\n await ioMem.init();\n\n const ios: Array<IoMultiIo> = [\n { io: ioPeer, priority: 1, read: true, write: false, dump: false },\n { io: ioMem, priority: 0, read: true, write: true, dump: true },\n ];\n\n const ioMulti = new IoMulti(ios);\n await ioMulti.init();\n\n return ioMulti;\n };\n}\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { Io } from './io.ts';\nimport { Socket } from './socket.ts';\n\n\n/**\n * Bridges Socket events to Io method calls.\n *\n * This class listens to socket events and translates them into corresponding\n * Io method calls, automatically registering all Io interface methods.\n */\nexport class IoPeerBridge {\n private _eventHandlers: Map<string | symbol, (...args: any[]) => void> =\n new Map();\n\n constructor(private _io: Io, private _socket: Socket) {}\n\n /**\n * Starts the bridge by setting up connection event handlers and\n * automatically registering all Io methods.\n */\n start(): void {\n this._socket.on('connect', () => this._handleConnect());\n this._socket.on('disconnect', () => this._handleDisconnect());\n\n // Automatically register all Io interface methods\n this._registerIoMethods();\n }\n\n /**\n * Stops the bridge by removing all event handlers.\n */\n stop(): void {\n /* v8 ignore next -- @preserve */\n this._socket.off('connect', () => this._handleConnect());\n /* v8 ignore next -- @preserve */\n this._socket.off('disconnect', () => this._handleDisconnect());\n\n for (const [eventName, handler] of this._eventHandlers) {\n this._socket.off(eventName, handler);\n }\n this._eventHandlers.clear();\n }\n\n /**\n * Automatically registers all Io interface methods as socket event handlers.\n */\n private _registerIoMethods(): void {\n // Core Io interface methods\n const ioMethods = [\n 'init',\n 'isReady',\n 'close',\n 'tableExists',\n 'createOrExtendTable',\n 'write',\n 'readRows',\n 'rowCount',\n 'dumpTable',\n 'dump',\n 'contentType',\n 'rawTableCfgs',\n ];\n\n for (const methodName of ioMethods) {\n this.registerEvent(methodName);\n }\n }\n\n /**\n * Registers a socket event to be translated to an Io method call.\n *\n * @param eventName - The socket event name (should match an Io method name)\n * @param ioMethodName - (Optional) The Io method name if different from eventName\n */\n registerEvent(eventName: string, ioMethodName?: string): void {\n const methodName = ioMethodName || eventName;\n\n /* v8 ignore next -- @preserve */\n const handler = (...args: any[]) => {\n // The last argument is expected to be a callback function\n const callback = args[args.length - 1];\n const methodArgs = args.slice(0, -1);\n\n // Get the Io method\n const ioMethod = (this._io as any)[methodName];\n\n /* v8 ignore next -- @preserve */\n if (typeof ioMethod !== 'function') {\n const error = new Error(\n `Method \"${methodName}\" not found on Io instance`,\n );\n if (typeof callback === 'function') {\n callback(null, error);\n }\n return;\n }\n\n // Call the Io method and handle the response\n /* v8 ignore next -- @preserve */\n ioMethod\n .apply(this._io, methodArgs)\n .then((result: any) => {\n if (typeof callback === 'function') {\n // Call callback with just the result (no error parameter when successful)\n callback(result, null); // Two arguments\n }\n })\n .catch((error: any) => {\n if (typeof callback === 'function') {\n // For errors, send null as result and error as second parameter\n callback(null, error); // Two arguments\n }\n });\n };\n\n this._eventHandlers.set(eventName, handler);\n this._socket.on(eventName, handler);\n }\n\n /**\n * Registers multiple socket events at once.\n *\n * @param eventNames - Array of event names to register\n */\n registerEvents(eventNames: string[]): void {\n for (const eventName of eventNames) {\n this.registerEvent(eventName);\n }\n }\n\n /**\n * Unregisters a socket event handler.\n *\n * @param eventName - The event name to unregister\n */\n unregisterEvent(eventName: string | symbol): void {\n const handler = this._eventHandlers.get(eventName);\n if (handler) {\n this._socket.off(eventName, handler);\n this._eventHandlers.delete(eventName);\n }\n }\n\n /**\n * Emits a result back through the socket.\n *\n * @param eventName - The event name to emit\n * @param data - The data to send\n */\n emitToSocket(eventName: string | symbol, ...data: any[]): void {\n this._socket.emit(eventName, ...data);\n }\n\n /**\n * Calls an Io method directly and emits the result through the socket.\n *\n * @param ioMethodName - The Io method to call\n * @param socketEventName - The socket event to emit with the result\n * @param args - Arguments to pass to the Io method\n */\n async callIoAndEmit(\n ioMethodName: string,\n socketEventName: string | symbol,\n ...args: any[]\n ): Promise<void> {\n try {\n const ioMethod = (this._io as any)[ioMethodName];\n\n if (typeof ioMethod !== 'function') {\n throw new Error(`Method \"${ioMethodName}\" not found on Io instance`);\n }\n\n const result = await ioMethod.apply(this._io, args);\n this._socket.emit(socketEventName, result, null);\n } catch (error) {\n this._socket.emit(socketEventName, null, error);\n }\n }\n\n /* v8 ignore next -- @preserve */\n private _handleConnect(): void {\n // Override this method in subclasses to handle connection events\n }\n\n /* v8 ignore next -- @preserve */\n private _handleDisconnect(): void {\n // Override this method in subclasses to handle disconnection events\n }\n\n /**\n * Gets the current socket instance.\n */\n get socket(): Socket {\n return this._socket;\n }\n\n /**\n * Gets the current Io instance.\n */\n get io(): Io {\n return this._io;\n }\n\n /**\n * Returns whether the socket is currently connected.\n */\n get isConnected(): boolean {\n return this._socket.connected;\n }\n}\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { JsonValue } from '@rljson/json';\nimport { Rljson, TableCfg, TableKey } from '@rljson/rljson';\n\nimport { Io } from './io.ts';\nimport { Socket } from './socket.ts';\n\n\nexport class IoServer {\n private _sockets: Socket[] = [];\n\n constructor(private _io: Io) {}\n\n // ...........................................................................\n /**\n * Adds a socket to the IoServer instance.\n * @param socket - The socket to add.\n */\n async addSocket(socket: Socket): Promise<void> {\n // Add transport layer to the socket\n await this._addTransportLayer(socket);\n\n // Add socket to the list of sockets\n this._sockets.push(socket);\n }\n\n // ...........................................................................\n /**\n * Removes a transport layer from the given socket.\n * @param socket - The socket to remove the transport layer from.\n */\n removeSocket(socket: Socket): void {\n this._sockets = this._sockets.filter((s) => s !== socket);\n }\n\n // ...........................................................................\n /**\n * Adds a transport layer to the given socket.\n * @param socket - The socket to add the transport layer to.\n */\n private async _addTransportLayer(socket: Socket): Promise<void> {\n // CRUD operations — use arrow functions that read this._io at call time,\n // so that when _io is replaced (e.g. after _rebuildMultis), existing\n // socket handlers automatically use the latest Io instance.\n const crud = this._generateTransportLayerCRUD();\n for (const [key, fn] of Object.entries(crud)) {\n socket.on(key, (...args: any[]) => {\n const cb = args[args.length - 1];\n\n fn.apply(this, args.slice(0, -1))\n .then((result) => {\n cb(result, null);\n })\n .catch((err) => {\n cb(null, err);\n });\n });\n }\n }\n\n // ...........................................................................\n /**\n * Creates or extends a table with the given configuration.\n * @param request - An object containing the table configuration.\n */\n private async createOrExtendTable(request: {\n tableCfg: TableCfg;\n }): Promise<void> {\n return this._io.createOrExtendTable(request);\n }\n\n // ...........................................................................\n /**\n * Generates a transport layer object that always delegates to the current\n * this._io. Each method is an arrow function reading this._io at call\n * time so that external code can replace _io after construction and all\n * existing socket handlers pick up the new instance.\n */\n private _generateTransportLayerCRUD = () =>\n ({\n init: () => this._io.init(),\n close: () => this._io.close(),\n isOpen: () =>\n new Promise((resolve) => resolve(this._io.isOpen)) as Promise<boolean>,\n isReady: () => this._io.isReady(),\n dump: () => this._io.dump(),\n dumpTable: (request: { table: string }) => this._io.dumpTable(request),\n contentType: (request: { table: string }) =>\n this._io.contentType(request),\n tableExists: (tableKey: TableKey) => this._io.tableExists(tableKey),\n createOrExtendTable: (request: { tableCfg: TableCfg }) =>\n this.createOrExtendTable(request),\n rawTableCfgs: () => this._io.rawTableCfgs(),\n write: (request: { data: Rljson }) => this._io.write(request),\n readRows: (request: {\n table: string;\n where: { [column: string]: JsonValue | null };\n }) => this._io.readRows(request),\n rowCount: (table: string) => this._io.rowCount(table),\n } as { [key: string]: (...args: any[]) => Promise<any> });\n}\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { Io, IoMem } from './index.ts';\n\n// .............................................................................\n/**\n * Io implementation need to implement this interface to be used in\n * conformance tests.\n */\nexport interface IoTestSetup {\n /** setup before the single setups */\n beforeAll: () => Promise<void>;\n\n /**\n * Initializes the io implementation.\n * @returns The io implementation.\n */\n beforeEach: () => Promise<void>;\n\n /**\n * Tears down the io implementation.\n * @returns The io implementation.\n */\n afterEach: () => Promise<void>;\n\n /** cleanup after all tests */\n afterAll: () => Promise<void>;\n\n /**\n * The io implementation to be used in the conformance tests.\n */\n io: Io;\n}\n\n// .............................................................................\n// Example implementation of the IoTestSetup interface\nexport const exampleTestSetup = (): IoTestSetup => {\n return {\n io: new IoMem(),\n beforeAll: async () => {\n // This method can be used for any additional setup required before init.\n // Currently, it does nothing.\n },\n\n beforeEach: async () => {\n // Initialize the io implementation\n },\n afterEach: async () => {\n // Tear down the io implementation\n },\n\n afterAll: async () => {\n // This method can be used for any additional cleanup after tearDown.\n },\n };\n};\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { JsonValue } from '@rljson/json';\nimport { ContentType, Rljson, TableCfg, TableKey } from '@rljson/rljson';\n\n\n// .............................................................................\nexport interface Io {\n // ...........................................................................\n // General\n\n /** Starts the initialization */\n init(): Promise<void>;\n\n /** Closes the io */\n close(): Promise<void>;\n\n /** Returns true if io is opened */\n isOpen: boolean;\n\n /** A promise resolving once the Io interface is ready\n *\n * 💡 Use @rljson/is-ready\n */\n isReady(): Promise<void>;\n\n // ...........................................................................\n // Dump\n\n /** Returns the complete db content as Rljson */\n dump(): Promise<Rljson>;\n\n /** Returns the dump of a complete table */\n dumpTable(request: { table: string }): Promise<Rljson>;\n\n // ...........................................................................\n // Meta Data\n contentType(request: { table: string }): Promise<ContentType>;\n\n // ...........................................................................\n // Tables\n\n /**\n * Returns true if the table exists\n */\n tableExists(tableKey: TableKey): Promise<boolean>;\n\n /**\n * Creates a table with a given config.\n * If the table already exists, new columns are added to the existing table.\n * If the table does not exist, it is created with the given config.\n * If the table exists and columns are removed, an error is thrown.\n * If the table exists and the column type is changed, an error is thrown.\n */\n createOrExtendTable(request: { tableCfg: TableCfg }): Promise<void>;\n\n /**\n * Returns a json structure returning current table configurations\n */\n rawTableCfgs(): Promise<TableCfg[]>;\n\n // ...........................................................................\n // Write\n\n /** Writes Rljson data into the database */\n write(request: { data: Rljson }): Promise<void>;\n\n // ...........................................................................\n // Read rows\n\n /** Queries a list of rows */\n readRows(request: {\n table: string;\n where: { [column: string]: JsonValue | null };\n }): Promise<Rljson>;\n\n /** Returns the number of rows in the given table */\n rowCount(table: string): Promise<number>;\n}\n\n// .............................................................................\nexport const exampleIo =\n 'Checkout @rljson/io-mem for an example implementation';\n","/* v8 ignore file -- @preserve */\n// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { Json } from '@rljson/json';\nimport {\n Buffet,\n Cake,\n iterateTablesSync,\n Layer,\n Ref,\n Rljson,\n TableKey,\n} from '@rljson/rljson';\n\n// .............................................................................\n/**\n * Describes a row that references a child table row\n */\nexport interface ParentRef {\n /**\n * The parent table that references the child table\n */\n [parentTable: TableKey]: {\n /**\n * The parent row that references the child row\n */\n [parentRow: Ref]: {\n /**\n * Details about the reference, e.g. an array index etc.\n */\n details?: Json;\n };\n };\n}\n\n// .............................................................................\n/**\n * Describes the parent table rows referencing a child table row\n */\nexport interface ReverseRefs {\n /**\n * The child table we need the referencing rows for\n */\n [childTable: TableKey]: {\n /**\n * The row hashwe need the referencing rows for\n */\n [childRow: Ref]: ParentRef;\n };\n}\n\n/* v8 ignore start -- @preserve */\n\n// .............................................................................\n/**\n * Calculates the reverse references for a given rljson object\n */\nexport const calcReverseRefs = (rljson: Rljson): ReverseRefs => {\n const result: ReverseRefs = {};\n\n // ......................\n // Prepare data structure\n iterateTablesSync(rljson, (childTableKey, table) => {\n const childTable: { [childRowHash: string]: ParentRef } = {};\n result[childTableKey] = childTable;\n for (const childRow of table._data) {\n childTable[childRow._hash] = {};\n }\n });\n\n // ............................\n // Generate reverse references\n iterateTablesSync(rljson, (parentTableKey, parentTable) => {\n // Iterate all rows of each table\n for (const parentTableRow of parentTable._data) {\n // Find out whe other tables & rows are referenced by this row\n // Write these information intto result\n switch (parentTable._type) {\n case 'components':\n _writeComponentRefs(parentTableKey, parentTableRow, result);\n break;\n\n case 'layers': {\n _writeLayerRefs(parentTableKey, parentTableRow, result);\n break;\n }\n\n case 'sliceIds': {\n // Slice ids do not reference other tables\n break;\n }\n\n case 'cakes': {\n _writeCakeRefs(parentTableKey, parentTableRow, result);\n break;\n }\n\n case 'buffets': {\n _writeBuffetRefs(parentTableKey, parentTableRow, result);\n break;\n }\n }\n }\n });\n\n return result;\n};\n\n/* v8 ignore stop -- @preserve */\n\n// .............................................................................\nconst _writeComponentRefs = (\n parentTableName: TableKey,\n parentRow: Json,\n result: ReverseRefs,\n) => {\n const parentRowHash = parentRow._hash as string;\n\n for (const parentColumnName in parentRow) {\n if (parentColumnName.startsWith('_')) {\n continue;\n }\n\n if (!parentColumnName.endsWith('Ref')) {\n continue;\n }\n\n const childTableName = parentColumnName.slice(0, -3);\n const childRowHash = parentRow[parentColumnName] as string;\n\n _write(\n result,\n childTableName,\n childRowHash,\n parentTableName,\n parentRowHash,\n );\n }\n};\n\n// .............................................................................\nconst _writeLayerRefs = (\n parentTableName: TableKey,\n parentRow: Layer,\n result: ReverseRefs,\n) => {\n const childTableName = parentRow.componentsTable;\n const parentRowHash = parentRow._hash as string;\n\n for (const sliceId in parentRow.add) {\n if (sliceId.startsWith('_')) {\n continue;\n }\n\n const sliceHash = parentRow.add[sliceId] as string;\n\n _write(result, childTableName, sliceHash, parentTableName, parentRowHash);\n }\n};\n\n// .............................................................................\nconst _writeCakeRefs = (\n parentTableName: TableKey,\n parentRow: Cake,\n result: ReverseRefs,\n) => {\n const parentRowHash = parentRow._hash as string;\n\n for (const layer in parentRow.layers) {\n const childTableName = layer;\n const childRowHash = parentRow.layers[layer] as string;\n _write(\n result,\n childTableName,\n childRowHash,\n parentTableName,\n parentRowHash,\n );\n }\n};\n\n// .............................................................................\nconst _writeBuffetRefs = (\n parentTableName: TableKey,\n parentRow: Buffet,\n result: ReverseRefs,\n) => {\n const parentRowHash = parentRow._hash as string;\n\n for (const item of parentRow.items) {\n const childTableName = item.table;\n const childRowHash = item.ref;\n _write(\n result,\n childTableName,\n childRowHash,\n parentTableName,\n parentRowHash,\n );\n }\n};\n\n// .............................................................................\nconst _write = (\n result: ReverseRefs,\n childTableName: string,\n childRowHash: string,\n parentTableName: string,\n parentRowHash: string,\n) => {\n const referencesForChildTable = (result[childTableName] ??= {});\n const referencesForChildTableRow = (referencesForChildTable[childRowHash] ??=\n {});\n\n referencesForChildTableRow[parentTableName] ??= {};\n referencesForChildTableRow[parentTableName][parentRowHash] ??= {};\n};\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n/* v8 ignore file -- @preserve */\nimport { Socket } from './socket.ts';\n\nexport class SocketMock implements Socket {\n public connected: boolean = false;\n public disconnected: boolean = true;\n\n private _listeners: Map<string | symbol, Array<(...args: any[]) => void>> =\n new Map();\n private _onceListeners: Map<\n string | symbol,\n Array<(...args: any[]) => void>\n > = new Map();\n\n connect(): void {\n if (!this.connected) {\n this.connected = true;\n this.disconnected = false;\n this.emit('connect');\n }\n }\n\n disconnect(): void {\n if (this.connected) {\n this.connected = false;\n this.disconnected = true;\n this.emit('disconnect');\n }\n }\n\n on(eventName: string | symbol, listener: (...args: any[]) => void): this {\n if (!this._listeners.has(eventName)) {\n this._listeners.set(eventName, []);\n }\n this._listeners.get(eventName)!.push(listener);\n return this;\n }\n\n once(eventName: string | symbol, listener: (...args: any[]) => void): this {\n if (!this._onceListeners.has(eventName)) {\n this._onceListeners.set(eventName, []);\n }\n this._onceListeners.get(eventName)!.push(listener);\n return this;\n }\n\n off(eventName: string | symbol, listener?: (...args: any[]) => void): this {\n if (listener) {\n // Remove specific listener\n const regularListeners = this._listeners.get(eventName);\n if (regularListeners) {\n const index = regularListeners.indexOf(listener);\n if (index > -1) {\n regularListeners.splice(index, 1);\n }\n }\n\n const onceListeners = this._onceListeners.get(eventName);\n if (onceListeners) {\n const index = onceListeners.indexOf(listener);\n if (index > -1) {\n onceListeners.splice(index, 1);\n }\n }\n } else {\n // Remove all listeners for the event\n this._listeners.delete(eventName);\n this._onceListeners.delete(eventName);\n }\n return this;\n }\n\n emit(eventName: string | symbol, ...args: any[]): boolean {\n let hasListeners = false;\n\n // Emit to regular listeners\n const regularListeners = this._listeners.get(eventName);\n if (regularListeners && regularListeners.length > 0) {\n hasListeners = true;\n // Create a copy to avoid issues if listeners are removed during emission\n [...regularListeners].forEach((listener) => {\n try {\n listener(...args);\n } catch (error) {\n // In a real EventEmitter, this would be handled differently\n console.error(\n `Error in listener for event ${String(eventName)}:`,\n error,\n );\n }\n });\n }\n\n // Emit to once listeners and remove them\n const onceListeners = this._onceListeners.get(eventName);\n if (onceListeners && onceListeners.length > 0) {\n hasListeners = true;\n // Create a copy and clear the original array\n const listenersToCall = [...onceListeners];\n this._onceListeners.delete(eventName);\n\n listenersToCall.forEach((listener) => {\n try {\n listener(...args);\n } catch (error) {\n console.error(\n `Error in once listener for event ${String(eventName)}:`,\n error,\n );\n }\n });\n }\n\n return hasListeners;\n }\n\n removeAllListeners(eventName?: string | symbol): this {\n if (eventName !== undefined) {\n this._listeners.delete(eventName);\n this._onceListeners.delete(eventName);\n } else {\n this._listeners.clear();\n this._onceListeners.clear();\n }\n return this;\n }\n\n listenerCount(eventName: string | symbol): number {\n const regularCount = this._listeners.get(eventName)?.length || 0;\n const onceCount = this._onceListeners.get(eventName)?.length || 0;\n return regularCount + onceCount;\n }\n\n listeners(eventName: string | symbol): Array<(...args: any[]) => void> {\n const regularListeners = this._listeners.get(eventName) || [];\n const onceListeners = this._onceListeners.get(eventName) || [];\n return [...regularListeners, ...onceListeners];\n }\n\n eventNames(): Array<string | symbol> {\n const allEvents = new Set([\n ...this._listeners.keys(),\n ...this._onceListeners.keys(),\n ]);\n return Array.from(allEvents);\n }\n\n // Test helper methods\n reset(): void {\n this.connected = false;\n this.disconnected = true;\n this.removeAllListeners();\n }\n\n simulateError(error: Error): void {\n this.emit('error', error);\n }\n\n simulateMessage(message: any): void {\n this.emit('message', message);\n }\n\n // Get internal state for testing\n getListeners(): Map<string | symbol, Array<(...args: any[]) => void>> {\n return new Map(this._listeners);\n }\n\n getOnceListeners(): Map<string | symbol, Array<(...args: any[]) => void>> {\n return new Map(this._onceListeners);\n }\n}\n\n// ...existing code...\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { Socket } from './socket.ts';\n\n\n/**\n * Creates a pair of connected sockets that properly route messages between them.\n * Unlike SocketMock, this maintains directionality - when socketA emits, only socketB's\n * listeners fire, not socketA's own listeners.\n *\n * This is essential for client-server testing where both use the same socket instance\n * but need separate event handling.\n */\nexport function createSocketPair(): [\n DirectionalSocketMock,\n DirectionalSocketMock,\n] {\n const socketA = new DirectionalSocketMock();\n const socketB = new DirectionalSocketMock();\n\n // Connect them bidirectionally\n socketA._setPeer(socketB);\n socketB._setPeer(socketA);\n\n return [socketA, socketB];\n}\n\nexport class DirectionalSocketMock implements Socket {\n public connected: boolean = false;\n public disconnected: boolean = true;\n\n private _peer?: DirectionalSocketMock;\n private _listeners: Map<string | symbol, Array<(...args: any[]) => void>> =\n new Map();\n private _onceListeners: Map<\n string | symbol,\n Array<(...args: any[]) => void>\n > = new Map();\n\n _setPeer(peer: DirectionalSocketMock): void {\n this._peer = peer;\n }\n\n connect(): void {\n if (!this.connected) {\n this.connected = true;\n this.disconnected = false;\n // Trigger local 'connect' event\n this._triggerLocal('connect');\n // Trigger peer's 'connect' event\n if (this._peer) {\n this._peer._triggerLocal('connect');\n }\n }\n }\n\n disconnect(): void {\n if (this.connected) {\n this.connected = false;\n this.disconnected = true;\n this._triggerLocal('disconnect');\n if (this._peer) {\n this._peer._triggerLocal('disconnect');\n }\n }\n }\n\n on(eventName: string | symbol, listener: (...args: any[]) => void): this {\n if (!this._listeners.has(eventName)) {\n this._listeners.set(eventName, []);\n }\n this._listeners.get(eventName)!.push(listener);\n return this;\n }\n\n once(eventName: string | symbol, listener: (...args: any[]) => void): this {\n if (!this._onceListeners.has(eventName)) {\n this._onceListeners.set(eventName, []);\n }\n this._onceListeners.get(eventName)!.push(listener);\n return this;\n }\n\n off(eventName: string | symbol, listener?: (...args: any[]) => void): this {\n if (listener) {\n const regularListeners = this._listeners.get(eventName);\n if (regularListeners) {\n const index = regularListeners.indexOf(listener);\n if (index > -1) regularListeners.splice(index, 1);\n }\n const onceListeners = this._onceListeners.get(eventName);\n if (onceListeners) {\n const index = onceListeners.indexOf(listener);\n if (index > -1) onceListeners.splice(index, 1);\n }\n } else {\n this._listeners.delete(eventName);\n this._onceListeners.delete(eventName);\n }\n return this;\n }\n\n /**\n * Emits an event to the PEER socket (cross-socket emission).\n * This is the key difference from SocketMock - emit() sends to the other side,\n * not to local listeners.\n *\n * Implements Socket.IO acknowledgement pattern: the last argument can be a callback\n * that the peer will invoke to send a response back.\n */\n emit(eventName: string | symbol, ...args: any[]): boolean {\n if (!this._peer) {\n console.warn(\n `DirectionalSocketMock.emit: No peer connected for event ${String(eventName)}`,\n );\n return false;\n }\n\n // Trigger the event on the PEER socket, not locally\n this._peer._triggerLocal(eventName, ...args);\n return true;\n }\n\n /**\n * Triggers listeners on THIS socket (local emission).\n * Used internally when receiving events from peer.\n */\n private _triggerLocal(eventName: string | symbol, ...args: any[]): void {\n // Trigger regular listeners\n const regularListeners = this._listeners.get(eventName);\n if (regularListeners) {\n [...regularListeners].forEach((listener) => {\n try {\n listener(...args);\n } catch (error) {\n console.error(`Error in listener for ${String(eventName)}:`, error);\n }\n });\n }\n\n // Trigger and remove once listeners\n const onceListeners = this._onceListeners.get(eventName);\n if (onceListeners) {\n const listenersToCall = [...onceListeners];\n this._onceListeners.delete(eventName);\n listenersToCall.forEach((listener) => {\n try {\n listener(...args);\n } catch (error) {\n console.error(\n `Error in once listener for ${String(eventName)}:`,\n error,\n );\n }\n });\n }\n }\n\n removeAllListeners(eventName?: string | symbol): this {\n if (eventName !== undefined) {\n this._listeners.delete(eventName);\n this._onceListeners.delete(eventName);\n } else {\n this._listeners.clear();\n this._onceListeners.clear();\n }\n return this;\n }\n\n listenerCount(eventName: string | symbol): number {\n const regularCount = this._listeners.get(eventName)?.length || 0;\n const onceCount = this._onceListeners.get(eventName)?.length || 0;\n return regularCount + onceCount;\n }\n\n listeners(eventName: string | symbol): Array<(...args: any[]) => void> {\n const regularListeners = this._listeners.get(eventName) || [];\n const onceListeners = this._onceListeners.get(eventName) || [];\n return [...regularListeners, ...onceListeners];\n }\n\n eventNames(): Array<string | symbol> {\n const allEvents = new Set([\n ...this._listeners.keys(),\n ...this._onceListeners.keys(),\n ]);\n return Array.from(allEvents);\n }\n}\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\n//Interface for a generic Socket, similar to Node.js EventEmitter\n//This is a simplified version and may not cover all features of a full EventEmitter\nexport interface Socket {\n connected: boolean;\n disconnected: boolean;\n connect(): void;\n disconnect(): void;\n on(eventName: string | symbol, listener: (...args: any[]) => void): this;\n emit(eventName: string | symbol, ...args: any[]): boolean | this;\n off(eventName: string | symbol, listener?: (...args: any[]) => void): this;\n removeAllListeners(eventName?: string | symbol): this;\n}\n\nexport const socketExample = (): Socket => ({\n connected: false,\n disconnected: true,\n connect() {\n this.connected = true;\n this.disconnected = false;\n this.emit('connect');\n },\n disconnect() {\n this.connected = false;\n this.disconnected = true;\n this.emit('disconnect');\n },\n /* v8 ignore next -- @preserve */\n on() {\n // Implementation of event listener registration\n return this;\n },\n /* v8 ignore next -- @preserve */\n emit() {\n // Implementation of event emission\n return true;\n },\n /* v8 ignore next -- @preserve */\n off() {\n // Implementation of event listener removal\n return this;\n },\n /* v8 ignore next -- @preserve */\n removeAllListeners() {\n // Implementation of removing all listeners\n return this;\n },\n});\n"],"names":["e"],"mappings":";;;;AAMO,MAAM,gBAAgB;AAAA;AAAA,EAEpB,mBAA2B;AAAA,EAC3B,cAAsB;AAAA,EACtB,aAAqB;AAAA,EACrB,YAAoB;AAAA;AAAA,EAGpB,aAAwC;AAAA,IAC7C,MAAM;AAAA,IACN,UAAU;AAAA,EAAA;AAAA;AAAA,EAIJ,UAAqC;AAAA,IAC3C,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,EAAA;AAAA;AAAA;AAAA,EAKC,QAAQ,MAAc,KAAqB;AACjD,WAAO,KAAK,SAAS,GAAG,IAAI,OAAO,OAAO;AAAA,EAC5C;AAAA,EAEO,eAAe,MAAsB;AAC1C,WAAO,KAAK,QAAQ,MAAM,KAAK,QAAQ,GAAG;AAAA,EAC5C;AAAA,EAEO,gBAAgB,MAAsB;AAC3C,WAAO,KAAK,QAAQ,MAAM,KAAK,QAAQ,GAAG;AAAA,EAC5C;AAAA,EAEO,aAAa,MAAsB;AACxC,WAAO,KAAK,QAAQ,MAAM,KAAK,QAAQ,GAAG;AAAA,EAC5C;AAAA,EAEQ,WAAW,MAAc,KAAqB;AACpD,WAAO,KAAK,SAAS,GAAG,IAAI,KAAK,MAAM,GAAG,CAAC,IAAI,MAAM,IAAI;AAAA,EAC3D;AAAA,EAEO,kBAAkB,MAAsB;AAC7C,WAAO,KAAK,WAAW,MAAM,KAAK,QAAQ,GAAG;AAAA,EAC/C;AAAA,EAEO,mBAAmB,MAAsB;AAC9C,WAAO,KAAK,WAAW,MAAM,KAAK,QAAQ,GAAG;AAAA,EAC/C;AAAA,EAEO,gBAAgB,MAAsB;AAC3C,WAAO,KAAK,WAAW,MAAM,KAAK,QAAQ,GAAG;AAAA,EAC/C;AACF;AClCO,MAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,EAKnB,YAA4B,IAAQ;AAAR,SAAA,KAAA;AAAA,EAAS;AAAA;AAAA;AAAA;AAAA,EAKrC,WAAW,oBAAoB;AAC7B,UAAM,WAAW,IAAc;AAAA,MAC7B,OAAO;AAAA,MACP,KAAK;AAAA,MACL,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,MAEV,SAAS;AAAA,QACP;AAAA,UACE,KAAK;AAAA,UACL,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,WAAW;AAAA,QAAA;AAAA,QAEb;AAAA,UACE,KAAK;AAAA,UACL,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,WAAW;AAAA,QAAA;AAAA,QAEb;AAAA,UACE,KAAK;AAAA,UACL,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,WAAW;AAAA,QAAA;AAAA,QAEb;AAAA,UACE,KAAK;AAAA,UACL,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,WAAW;AAAA,QAAA;AAAA,QAEb;AAAA,UACE,KAAK;AAAA,UACL,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,WAAW;AAAA,QAAA;AAAA,QAEb;AAAA,UACE,KAAK;AAAA,UACL,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,WAAW;AAAA,QAAA;AAAA,QAEb;AAAA,UACE,KAAK;AAAA,UACL,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,WAAW;AAAA,QAAA;AAAA,QAEb;AAAA,UACE,KAAK;AAAA,UACL,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,WAAW;AAAA,QAAA;AAAA,MACb;AAAA,IACF,CACD;AAED,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,qBAAqB,YAAY;AAC/B,UAAM,WAAqB;AAAA,MACzB,KAAK;AAAA,MACL,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,UAAU;AAAA,MAEV,SAAS;AAAA,QACP;AAAA,UACE,KAAK;AAAA,UACL,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,WAAW;AAAA,QAAA;AAAA,QAEb;AAAA,UACE,KAAK;AAAA,UACL,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,WAAW;AAAA,QAAA;AAAA,QAEb;AAAA,UACE,KAAK;AAAA,UACL,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,WAAW;AAAA,QAAA;AAAA,QAEb;AAAA,UACE,KAAK;AAAA,UACL,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,WAAW;AAAA,QAAA;AAAA,QAEb;AAAA,UACE,KAAK;AAAA,UACL,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,WAAW;AAAA,QAAA;AAAA,QAEb;AAAA,UACE,KAAK;AAAA,UACL,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,WAAW;AAAA,QAAA;AAAA,MACb;AAAA,IACF;AAGF,UAAM,KAAK,GAAG,oBAAoB,EAAE,UAAU;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,UAAU,YAAY;AAC3B,UAAM,KAAK,MAAM,MAAM,QAAA;AACvB,UAAM,GAAG,KAAA;AACT,UAAM,GAAG,QAAA;AACT,WAAO,IAAI,QAAQ,EAAE;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,2BAA2B,OAAgC;AAC/D,UAAM,SAAS,MAAM,KAAK,GAAG,YAAY,KAAK;AAC9C,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,UAAU,KAAK,aAAa;AAAA,IAC9C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,0BAA0B,QAA+B;AAC7D,QAAI;AACF,YAAM,cAAc,QAAQ,OAAO,aAAa;AAC9C,cAAM,SAAS,MAAM,KAAK,GAAG,YAAY,QAAQ;AACjD,YAAI,CAAC,QAAQ;AACX,gBAAM,IAAI,MAAM,UAAU,QAAQ,aAAa;AAAA,QACjD;AAAA,MACF,CAAC;AAAA,IACH,SAAS,GAAG;AACV,YAAM,gBAAiB,EAAiB,IAAI,CAACA,OAAMA,GAAE,QAAQ;AAE7D,YAAM,IAAI;AAAA,QACR,sCAAsC,cAAc,KAAK,IAAI,CAAC;AAAA,MAAA;AAAA,IAElE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YAAiC;AACrC,UAAM,SAAS,MAAM,KAAK,GAAG,aAAA;AAG7B,UAAM,gBAA4C,CAAA;AAClD,aAAS,IAAI,OAAO,SAAS,GAAG,KAAK,GAAG,KAAK;AAC3C,YAAM,QAAQ,OAAO,CAAC;AACtB,YAAM,WAAW,cAAc,MAAM,GAAG;AACxC,UAAI,CAAC,YAAY,SAAS,QAAQ,SAAS,MAAM,QAAQ,QAAQ;AAC/D,sBAAc,MAAM,GAAG,IAAI;AAAA,MAC7B;AAAA,IACF;AAIA,UAAM,aAAa,OAAO,OAAO,aAAa,EAAE,KAAK,CAAC,GAAG,MAAM;AAC7D,UAAI,EAAE,MAAM,EAAE,KAAK;AACjB,eAAO;AAAA,MACT;AACA,UAAI,EAAE,MAAM,EAAE,KAAK;AACjB,eAAO;AAAA,MACT;AAEA,aAAO;AAAA,IACT,CAAC;AACD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAAkC;AACtC,UAAM,UAAU,MAAM,KAAK,UAAA,GAAa,IAAI,CAAC,MAAM,EAAE,GAAG;AACxD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,OAAoC;AACjD,UAAM,WAAW,MAAM,KAAK,eAAe,KAAK;AAChD,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,MAAM,UAAU,KAAK,aAAa;AAAA,IAC9C;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eAAe,OAA2C;AAC9D,UAAM,YAAY,MAAM,KAAK,UAAA;AAC7B,UAAM,WAAW,UAAU,KAAK,CAAC,MAAM,EAAE,QAAQ,KAAK;AACtD,WAAO,YAAY;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAc,OAAoC;AACtD,UAAM,WAAW,MAAM,KAAK,SAAS,KAAK;AAC1C,UAAM,SAAS,SAAS,QAAQ,IAAI,CAAC,WAAW,OAAO,GAAG;AAC1D,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,4BACJ,OACA,SACe;AACf,UAAM,WAAW,MAAM,KAAK,SAAS,KAAK;AAC1C,UAAM,aAAa,SAAS,QAAQ,IAAI,CAAC,WAAW,OAAO,GAAG;AAC9D,UAAM,iBAAiB,QAAQ;AAAA,MAC7B,CAAC,WAAW,CAAC,WAAW,SAAS,MAAM;AAAA,IAAA;AAEzC,QAAI,eAAe,SAAS,GAAG;AAC7B,YAAM,IAAI;AAAA,QACR,gDAAgD,KAAK,MAAM,eAAe;AAAA,UACxE;AAAA,QAAA,CACD;AAAA,MAAA;AAAA,IAEL;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,8BAA8B,QAAiC;AACnE,UAAM,SAAS,iCAAiC,OAAO,GAAG;AAE1D,2BAAuB,MAAM;AAG7B,UAAM,WAAW,MAAM,KAAK,eAAe,OAAO,GAAG;AACrD,QAAI,UAAU;AAEZ,UAAI,SAAS,QAAQ,SAAS,OAAO,QAAQ,QAAQ;AACnD,cAAM,oBAAoB,SAAS,QAChC,IAAI,CAAC,WAAW,OAAO,GAAG,EAC1B;AAAA,UACC,CAAC,QAAQ,CAAC,OAAO,QAAQ,KAAK,CAAC,WAAW,OAAO,QAAQ,GAAG;AAAA,QAAA;AAGhE,YAAI,kBAAkB,SAAS,GAAG;AAChC,gBAAM,iBAAiB,kBAAkB,KAAK,IAAI;AAClD,gBAAM,IAAI;AAAA,YACR,GAAG,MAAM,mDACa,cAAc;AAAA,UAAA;AAAA,QAExC;AAAA,MACF;AAGA,eAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,QAAQ,KAAK;AAChD,cAAM,SAAS,SAAS,QAAQ,CAAC,EAAE;AACnC,cAAM,QAAQ,OAAO,QAAQ,CAAC,EAAE;AAChC,YAAI,WAAW,OAAO;AACpB,gBAAM,IAAI;AAAA,YACR,GAAG,MAAM,0CAEI,MAAM,uBAAuB,KAAK;AAAA,UAAA;AAAA,QAEnD;AAAA,MACF;AAGA,eAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,QAAQ,KAAK;AAChD,cAAM,SAAS,SAAS,QAAQ,CAAC,EAAE;AACnC,cAAM,SAAS,SAAS,QAAQ,CAAC,EAAE;AACnC,cAAM,QAAQ,OAAO,QAAQ,CAAC,EAAE;AAChC,YAAI,WAAW,OAAO;AACpB,gBAAM,IAAI;AAAA,YACR,GAAG,MAAM,mDAEY,MAAM,uBAAuB,MAAM,QAAQ,KAAK;AAAA,UAAA;AAAA,QAEzE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kCAAkC,MAAc;AACpD,UAAM,SAAmB,CAAA;AAEzB,UAAM,cAAc,MAAM,OAAO,aAAa;AAC5C,YAAM,WAAW,MAAM,KAAK,SAAS,QAAQ;AAC7C,YAAM,QAAQ,KAAK,QAAQ;AAI3B,UAAI,MAAM,UAAU,YAAa;AAEjC,aAAO,KAAK,GAAG,8BAA8B,MAAM,OAAO,QAAQ,CAAC;AAAA,IACrE,CAAC;AAED,QAAI,OAAO,SAAS,GAAG;AACrB,YAAM,IAAI;AAAA,QACR;AAAA;AAAA;AAAA,EAA4D,OACzD,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,EACnB,KAAK,IAAI,CAAC;AAAA,MAAA;AAAA,IAEjB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,2BAA2B,OAAwB;AACjD,UAAM,MAAM,KAAK,CAAC,GAAG,MAAM;AACzB,YAAM,QAAQ,EAAE;AAChB,YAAM,QAAQ,EAAE;AAEhB,UAAI,QAAQ,OAAO;AACjB,eAAO;AAAA,MACT;AAEA,UAAI,QAAQ,OAAO;AACjB,eAAO;AAAA,MACT;AAGA,aAAO;AAAA,IACT,CAAC;AAED,UAAM,QAAQ;AACd,QAAI,OAAO;AAAA,MACT,sBAAsB;AAAA,MACtB,oBAAoB;AAAA,IAAA,CACrB;AAAA,EACH;AACF;AC5XO,MAAM,MAAoB;AAAA;AAAA;AAAA,EAI/B,OAAsB;AACpB,SAAK,UAAU;AACf,WAAO,KAAK,MAAA;AAAA,EACd;AAAA,EAEA,QAAuB;AACrB,SAAK,UAAU;AACf,WAAO,QAAQ,QAAA;AAAA,EACjB;AAAA,EAEA,IAAI,SAAkB;AACpB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,OAAO,UAAU,YAAY;AAC3B,UAAM,KAAK,IAAI,MAAA;AACf,UAAM,GAAG,KAAA;AACT,WAAO;AAAA,EACT;AAAA;AAAA;AAAA,EAIA,UAAU;AACR,WAAO,KAAK,SAAS;AAAA,EACvB;AAAA;AAAA;AAAA,EAKA,OAAwB;AACtB,WAAO,KAAK,MAAA;AAAA,EACd;AAAA,EAEA,MAAM,UAAU,SAA6C;AAC3D,WAAO,KAAK,WAAW,OAAO;AAAA,EAChC;AAAA;AAAA;AAAA,EAKA,MAAM,YAAY,SAAkD;AAClE,WAAO,KAAK,aAAa,OAAO;AAAA,EAClC;AAAA;AAAA;AAAA,EAKA,SAAS,SAGW;AAClB,WAAO,KAAK,UAAU,OAAO;AAAA,EAC/B;AAAA,EAEA,MAAM,SAAS,OAAgC;AAC7C,UAAM,YAAY,KAAK,KAAK,KAAK;AACjC,QAAI,CAAC,WAAW;AACd,YAAM,IAAI,MAAM,UAAU,KAAK,aAAa;AAAA,IAC9C;AACA,WAAO,QAAQ,QAAQ,UAAU,MAAM,MAAM;AAAA,EAC/C;AAAA;AAAA;AAAA,EAKA,MAAM,SAA0C;AAC9C,WAAO,KAAK,OAAO,OAAO;AAAA,EAC5B;AAAA;AAAA;AAAA,EAIA,MAAM,YAAY,UAAsC;AACtD,UAAM,QAAQ,KAAK,KAAK,QAAQ;AAChC,WAAO,QAAQ,OAAO;AAAA,EACxB;AAAA,EAEA,oBAAoB,SAAgD;AAClE,WAAO,KAAK,qBAAqB,OAAO;AAAA,EAC1C;AAAA,EAEA,MAAM,eAAoC;AACxC,UAAM,SAAS,KAAK,KAAK,UAAU;AACnC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMQ;AAAA,EAEA,WAAW,IAAI,QAAA;AAAA,EACf,UAAU;AAAA,EAEV,OAAe,IAAI,EAAY;AAAA;AAAA,EAGvC,MAAc,QAAQ;AACpB,SAAK,WAAW,IAAI,QAAQ,IAAI;AAChC,SAAK,eAAA;AACL,SAAK,kBAAA;AACL,UAAM,KAAK,SAAS,mBAAA;AACpB,QAAI,KAAK,IAAI;AAEb,SAAK,SAAS,QAAA;AAAA,EAChB;AAAA;AAAA,EAGQ,iBAAiB,MAAM;AAC7B,UAAM,WAAW,QAAQ;AAEzB,SAAK,KAAK,YAAY,IAAI;AAAA,MACxB,OAAO;AAAA,MACP,OAAO,CAAC,QAAQ;AAAA,MAChB,WAAW,SAAS;AAAA,IAAA,CACrB;AAAA,EACH;AAAA;AAAA,EAGQ,oBAAoB;AACzB,SAAK,KAAa,QAAQ;AAC3B,QAAI,KAAK,MAAM;AAAA,MACb,sBAAsB;AAAA,IAAA,CACvB;AAAA,EACH;AAAA;AAAA,EAGQ,iBAAiB,UAAoB;AAC3C,UAAM,QAAQ,KAAK,KAAK,QAAQ;AAChC,UAAM,QAAQ;AACd,QAAI,OAAO,EAAE,sBAAsB,MAAA,CAAO;AAAA,EAC5C;AAAA;AAAA,EAGA,MAAc,qBAAqB,SAEjB;AAGhB,UAAM,WAAW,QAAQ;AACzB,UAAM,KAAK,SAAS,8BAA8B,QAAQ;AAE1D,UAAM,EAAE,QAAQ;AAGhB,UAAM,YAAY,IAAI,QAAQ;AAG9B,UAAM,iBAAiB,MAAM,KAAK,SAAS,eAAe,GAAG;AAG7D,QAAI,CAAC,gBAAgB;AACnB,WAAK,aAAa,WAAW,GAAG;AAAA,IAClC,OAAO;AACL,WAAK,aAAa,gBAAgB,SAAS;AAAA,IAC7C;AAAA,EACF;AAAA;AAAA,EAGQ,aAAa,WAAqB,UAAoB;AAE5D,gBAAY,IAAI,SAAS;AACzB,SAAK,KAAK,UAAU,MAAM,KAAK,SAAS;AACxC,SAAK,SAAS,2BAA2B,KAAK,KAAK,SAAS;AAG5D,UAAM,QAAmB;AAAA,MACvB,OAAO,UAAU;AAAA,MACjB,OAAO,CAAA;AAAA,MACP,WAAW,UAAU;AAAA,IAAA;AAGvB,SAAK,KAAK,QAAQ,MAAM,IAAI,KAAK;AAGjC,SAAK,iBAAiB,QAAQ;AAC9B,SAAK,kBAAA;AAAA,EACP;AAAA;AAAA,EAGQ,aAAa,gBAA0B,WAAqB;AAElE,QAAI,eAAe,QAAQ,WAAW,UAAU,QAAQ,QAAQ;AAC9D;AAAA,IACF;AAGA,gBAAY,IAAI,SAAS;AACzB,SAAK,KAAK,UAAU,MAAM,KAAK,SAAS;AACxC,SAAK,SAAS,2BAA2B,KAAK,KAAK,SAAS;AAG5D,UAAM,QAAQ,KAAK,KAAK,UAAU,GAAG;AACrC,UAAM,YAAY,UAAU;AAG5B,SAAK,iBAAiB,UAAU,GAAG;AACnC,SAAK,kBAAA;AAAA,EACP;AAAA;AAAA,EAIA,MAAc,QAAyB;AACrC,WAAO,KAAK,KAAK,IAAI;AAAA,EACvB;AAAA;AAAA,EAGA,MAAc,WAAW,SAA6C;AACpE,UAAM,KAAK,SAAS,2BAA2B,QAAQ,KAAK;AAE5D,UAAM,QAAQ,KAAK,KAAK,QAAQ,KAAK;AAErC,WAAO;AAAA,MACL,CAAC,QAAQ,KAAK,GAAG,KAAK,KAAK;AAAA,IAAA;AAAA,EAE/B;AAAA;AAAA,EAGA,MAAc,aAAa,SAAkD;AAC3E,UAAM,KAAK,SAAS,2BAA2B,QAAQ,KAAK;AAE5D,WAAQ,KAAK,KAAK,QAAQ,KAAK,EAAgB;AAAA,EACjD;AAAA;AAAA,EAGA,MAAc,OAAO,SAA0C;AAC7D,UAAM,YAAY,IAAI,QAAQ,IAAI;AAClC,SAAK,kBAAkB,SAAS;AAChC,UAAM,SAAS,OAAO,KAAK,SAAS;AACpC,QAAI,SAAS;AAEb,UAAM,KAAK,SAAS,0BAA0B,QAAQ,IAAI;AAC1D,UAAM,KAAK,SAAS,kCAAkC,QAAQ,IAAI;AAElE,eAAW,SAAS,QAAQ;AAC1B,UAAI,MAAM,WAAW,GAAG,GAAG;AACzB;AAAA,MACF;AAEA,YAAM,WAAW,KAAK,KAAK,KAAK;AAChC,YAAM,WAAW,UAAU,KAAK;AAGhC,iBAAW,QAAQ,SAAS,OAAO;AACjC,cAAM,OAAO,KAAK;AAClB,cAAM,SAAS,SAAS,MAAM,KAAK,CAAC,MAAM,EAAE,UAAU,IAAI;AAC1D,YAAI,CAAC,QAAQ;AACX,mBAAS,MAAM,KAAK,IAAW;AAAA,QACjC;AAAA,MACF;AAEA,WAAK,SAAS,2BAA2B,QAAQ;AAAA,IACnD;AAGA,SAAK,kBAAA;AAAA,EACP;AAAA;AAAA,EAGA,MAAc,UAAU,SAGJ;AAClB,UAAM,KAAK,SAAS,2BAA2B,QAAQ,KAAK;AAC5D,UAAM,KAAK,SAAS;AAAA,MAClB,QAAQ;AAAA,MACR,OAAO,KAAK,QAAQ,KAAK;AAAA,IAAA;AAI3B,UAAM,QAAQ,KAAK,KAAK,QAAQ,KAAK;AAGrC,UAAM,oBAAoB,MAAM,MAAM,OAAO,CAAC,QAAQ;AACpD,iBAAW,UAAU,QAAQ,OAAO;AAClC,cAAM,IAAI,IAAI,MAAM;AACpB,cAAM,IAAI,QAAQ,MAAM,MAAM;AAC9B,YAAI,MAAM,QAAQ,MAAM,QAAW;AACjC,iBAAO;AAAA,QACT;AAEA,YAAI,CAAC,OAAO,GAAG,CAAC,GAAG;AACjB,iBAAO;AAAA,QACT;AAAA,MACF;AACA,aAAO;AAAA,IACT,CAAC;AAGD,UAAM,gBAA2B;AAAA,MAC/B,OAAO,MAAM;AAAA,MACb,OAAO;AAAA,IAAA;AAGT,SAAK,SAAS,2BAA2B,aAAa;AAEtD,UAAM,SAAiB;AAAA,MACrB,CAAC,QAAQ,KAAK,GAAG;AAAA,IAAA;AAGnB,WAAO;AAAA,EACT;AAAA,EAEA,kBAAkB,QAAgB;AAChC,sBAAkB,QAAQ,CAAC,UAAU;AACnC,YAAM,OAAO,OAAO,KAAK,EAAE;AAE3B,iBAAW,OAAO,MAAM;AACtB,mBAAW,OAAO,KAAK;AACrB,cAAI,IAAI,GAAG,MAAM,MAAM;AACrB,mBAAO,IAAI,GAAG;AAAA,UAChB;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACF;AC3UO,MAAM,eAAiC;AAAA,EAO5C,YAAoB,KAAS;AAAT,SAAA,MAAA;AAAA,EAAU;AAAA,EANtB,oCACF,IAAA;AAAA,EAEN,YAAqB;AAAA,EACrB,eAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWxB,IAAI,WAA4B,UAA0C;AAExE,UAAM,YAAY,KAAK,cAAc,IAAI,SAAS,KAAK,CAAA;AACvD,UAAM,QAAQ,UAAU,QAAQ,QAAQ;AAExC,QAAI,UAAU,IAAI;AAChB,gBAAU,OAAO,OAAO,CAAC;AACzB,WAAK,cAAc,IAAI,WAAW,SAAS;AAAA,IAC7C;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,mBAAmB,WAAmC;AACpD,QAAI,WAAW;AACb,WAAK,cAAc,OAAO,SAAS;AAAA,IACrC,OAAO;AACL,WAAK,cAAc,MAAA;AAAA,IACrB;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,GAAG,WAA4B,UAA0C;AACvE,QAAI,CAAC,KAAK,cAAc,IAAI,SAAS,GAAG;AACtC,WAAK,cAAc,IAAI,WAAW,CAAA,CAAE;AAAA,IACtC;AACA,SAAK,cAAc,IAAI,SAAS,EAAG,KAAK,QAAQ;AAChD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAgB;AACd,SAAK,YAAY;AACjB,SAAK,eAAe;AAEpB,UAAM,YAAY,KAAK,cAAc,IAAI,SAAS,KAAK,CAAA;AACvD,eAAW,MAAM,WAAW;AAC1B,SAAG,CAAA,CAAE;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,aAAmB;AACjB,SAAK,YAAY;AACjB,SAAK,eAAe;AAEpB,UAAM,YAAY,KAAK,cAAc,IAAI,YAAY,KAAK,CAAA;AAC1D,eAAW,MAAM,WAAW;AAC1B,SAAG,CAAA,CAAE;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,KAAK,cAA+B,MAAsB;AACxD,UAAM,KAAM,KAAK,IAAY,SAAS;AACtC,QAAI,OAAO,OAAO,YAAY;AAC5B,YAAM,IAAI,MAAM,SAAS,UAAU,SAAA,CAAU,gBAAgB;AAAA,IAC/D;AACA,UAAM,KAAK,KAAK,KAAK,SAAS,CAAC;AAC/B,OAAG,MAAM,KAAK,KAAK,KAAK,MAAM,GAAG,EAAE,CAAC,EACjC,KAAK,CAAC,WAAW;AAChB,SAAG,QAAQ,IAAI;AAAA,IACjB,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,SAAG,MAAM,GAAG;AAAA,IACd,CAAC;AAEH,WAAO;AAAA,EACT;AACF;AC3GO,MAAM,OAAqB;AAAA,EAGhC,YACU,SACA,oBAA4B,KACpC;AAFQ,SAAA,UAAA;AACA,SAAA,oBAAA;AAAA,EACP;AAAA,EALH,SAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaV,aAAgB,SAAqB,WAA+B;AAC1E,QAAI,KAAK,qBAAqB,EAAG,QAAO;AACxC,QAAI;AACJ,UAAM,iBAAiB,IAAI,QAAe,CAAC,GAAG,WAAW;AACvD,cAAQ,WAAW,MAAM;AACvB;AAAA,UACE,IAAI;AAAA,YACF,iBAAiB,KAAK,iBAAiB,OAAO,SAAS;AAAA,UAAA;AAAA,QACzD;AAAA,MAEJ,GAAG,KAAK,iBAAiB;AAAA,IAC3B,CAAC;AACD,WAAO,QAAQ,KAAK,CAAC,SAAS,cAAc,CAAC,EAAE,QAAQ,MAAM;AAC3D,mBAAa,KAAM;AAAA,IACrB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,OAAsB;AAE1B,SAAK,QAAQ,GAAG,WAAW,MAAM;AAC/B,WAAK,SAAS;AAAA,IAChB,CAAC;AACD,SAAK,QAAQ,GAAG,cAAc,MAAM;AAClC,WAAK,SAAS;AAAA,IAChB,CAAC;AAGD,SAAK,QAAQ,QAAA;AAGb,WAAO,IAAI,QAAc,CAAC,YAAY;AAEpC,UAAI,KAAK,QAAQ,WAAW;AAC1B,aAAK,SAAS;AACd,gBAAA;AAAA,MACF,OAAO;AACL,aAAK,QAAQ,GAAG,WAAW,MAAM;AAC/B,kBAAA;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,QAAuB;AAE3B,QAAI,CAAC,KAAK,QAAQ,UAAW;AAE7B,WAAO,IAAI,QAAc,CAAC,YAAY;AACpC,WAAK,QAAQ,GAAG,cAAc,MAAM;AAClC,gBAAA;AAAA,MACF,CAAC;AACD,WAAK,QAAQ,WAAA;AAAA,IACf,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,UAAyB;AAC7B,QAAI,CAAC,CAAC,KAAK,WAAW,KAAK,QAAQ,cAAc,KAAM,MAAK,SAAS;AAAA,cAC3D,SAAS;AAEnB,WAAO,CAAC,CAAC,KAAK,SAAS,QAAQ,QAAA,IAAY,QAAQ,OAAA;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,OAAwB;AAC5B,WAAO,KAAK;AAAA,MACV,IAAI,QAAQ,CAAC,YAAY;AAEvB,aAAK,QAAQ,KAAK,QAAQ,CAAC,SAAiB;AAC1C,kBAAQ,IAAI;AAAA,QACd,CAAC;AAAA,MACH,CAAC;AAAA,MACD;AAAA,IAAA;AAAA,EAEJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAU,SAA6C;AACrD,WAAO,KAAK;AAAA,MACV,IAAI,QAAQ,CAAC,SAAS,WAAW;AAE/B,aAAK,QAAQ;AAAA,UACX;AAAA,UACA;AAAA,UACA,CAAC,MAAc,UAAkB;AAC/B,gBAAI,cAAc,KAAK;AACvB,oBAAQ,IAAI;AAAA,UACd;AAAA,QAAA;AAAA,MAEJ,CAAC;AAAA,MACD;AAAA,IAAA;AAAA,EAEJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,SAAkD;AAC5D,WAAO,KAAK;AAAA,MACV,IAAI,QAAQ,CAAC,SAAS,WAAW;AAE/B,aAAK,QAAQ;AAAA,UACX;AAAA,UACA;AAAA,UACA,CAAC,MAAmB,UAAkB;AAEpC,gBAAI,cAAc,KAAK;AACvB,oBAAQ,IAAI;AAAA,UACd;AAAA,QAAA;AAAA,MAEJ,CAAC;AAAA,MACD;AAAA,IAAA;AAAA,EAEJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,UAAsC;AAChD,WAAO,KAAK;AAAA,MACV,IAAI,QAAQ,CAAC,YAAY;AAEvB,aAAK,QAAQ,KAAK,eAAe,UAAU,CAAC,WAAoB;AAC9D,kBAAQ,MAAM;AAAA,QAChB,CAAC;AAAA,MACH,CAAC;AAAA,MACD;AAAA,IAAA;AAAA,EAEJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,oBAAoB,SAAgD;AAClE,WAAO,KAAK;AAAA,MACV,IAAI,QAAQ,CAAC,SAAS,WAAW;AAE/B,aAAK,QAAQ;AAAA,UACX;AAAA,UACA;AAAA,UACA,CAAC,GAAa,UAAkB;AAC9B,gBAAI,cAAc,KAAK;AACvB,oBAAA;AAAA,UACF;AAAA,QAAA;AAAA,MAEJ,CAAC;AAAA,MACD;AAAA,IAAA;AAAA,EAEJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAAoC;AAClC,WAAO,KAAK;AAAA,MACV,IAAI,QAAQ,CAAC,YAAY;AAEvB,aAAK,QAAQ,KAAK,gBAAgB,CAAC,SAAqB;AACtD,kBAAQ,IAAI;AAAA,QACd,CAAC;AAAA,MACH,CAAC;AAAA,MACD;AAAA,IAAA;AAAA,EAEJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,SAA0C;AAC9C,WAAO,KAAK;AAAA,MACV,IAAI,QAAQ,CAAC,SAAS,WAAW;AAE/B,aAAK,QAAQ,KAAK,SAAS,SAAS,CAAC,GAAa,UAAkB;AAClE,cAAI,cAAc,KAAK;AACvB,kBAAA;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAAA,MACD;AAAA,IAAA;AAAA,EAEJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS,SAGW;AAClB,WAAO,KAAK;AAAA,MACV,IAAI,QAAQ,CAAC,SAAS,WAAW;AAE/B,aAAK,QAAQ;AAAA,UACX;AAAA,UACA;AAAA,UACA,CAAC,QAAiB,UAAkB;AAClC,gBAAI,cAAc,KAAK;AACvB,oBAAQ,MAAO;AAAA,UACjB;AAAA,QAAA;AAAA,MAEJ,CAAC;AAAA,MACD;AAAA,IAAA;AAAA,EAEJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS,OAAgC;AACvC,WAAO,KAAK;AAAA,MACV,IAAI,QAAQ,CAAC,SAAS,WAAW;AAE/B,aAAK,QAAQ;AAAA,UACX;AAAA,UACA;AAAA,UACA,CAAC,OAAgB,UAAkB;AACjC,gBAAI,cAAc,KAAK;AACvB,oBAAQ,KAAM;AAAA,UAChB;AAAA,QAAA;AAAA,MAEJ,CAAC;AAAA,MACD;AAAA,IAAA;AAAA,EAEJ;AAAA;AAAA,EAGA,OAAO,UAAU,YAAY;AAC3B,UAAM,QAAQ,MAAM,MAAM,QAAA;AAC1B,UAAM,SAAS,IAAI,eAAe,KAAK;AACvC,UAAM,KAAK,IAAI,OAAO,MAAM;AAC5B,UAAM,GAAG,KAAA;AACT,WAAO;AAAA,EACT;AACF;AChRO,MAAM,QAAsB;AAAA,EAGjC,YAAoB,MAAwB;AAAxB,SAAA,OAAA;AAAA,EAAyB;AAAA,EAF7C,SAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUlB,MAAM,OAAsB;AAC1B,aAAS,MAAM,GAAG,MAAM,KAAK,KAAK,QAAQ,OAAO;AAC/C,YAAM,EAAE,GAAA,IAAO,KAAK,KAAK,GAAG;AAC5B,UAAI,GAAG,WAAW,OAAO;AACvB,cAAM,IAAI;AAAA,UACR;AAAA,QAAA;AAAA,MAEJ;AAEA,WAAK,KAAK,GAAG,IAAI,EAAE,GAAG,KAAK,KAAK,GAAG,GAAG,IAAI,MAAM,GAAG,GAAA;AAAA,IACrD;AAEA,SAAK,SAAS;AACd,WAAO,QAAQ,QAAA;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,QAAuB;AAC3B,UAAM,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC,cAAc,UAAU,GAAG,MAAA,CAAO,CAAC;AAEpE,SAAK,SAAS;AAEd,WAAO,QAAQ,QAAA;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAyB;AACvB,WAAO,QAAQ;AAAA,MACb,KAAK,KAAK,IAAI,CAAC,cAAc,UAAU,GAAG,SAAS;AAAA,IAAA,EACnD,KAAK,MAAM,QAAQ,SAAS;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,OAAwB;AAE5B,QAAI,KAAK,UAAU,WAAW,GAAG;AAC/B,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AAEA,UAAM,QAAQ,MAAM,QAAQ;AAAA,MAC1B,KAAK,UAAU,IAAI,CAAC,EAAE,IAAI,SAAA,MAAe,SAAS,KAAA,CAAM;AAAA,IAAA;AAG1D,WAAO,MAAM,GAAG,KAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,UAAU,SAA6C;AAE3D,QAAI,KAAK,UAAU,WAAW,GAAG;AAC/B,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AAEA,UAAM,QAAkB,CAAA;AAExB,eAAW,EAAE,IAAI,SAAA,KAAc,KAAK,WAAW;AAC7C,UAAI;AACF,cAAM,OAAO,MAAM,SAAS,UAAU,OAAO;AAC7C,cAAM,KAAK,IAAI;AAAA,MACjB,QAAQ;AACN;AAAA,MACF;AAAA,IACF;AAEA,QAAI,MAAM,WAAW,GAAG;AACtB,YAAM,IAAI,MAAM,UAAU,QAAQ,KAAK,aAAa;AAAA,IACtD;AAEA,WAAO,MAAM,GAAG,KAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,YAAY,SAAkD;AAElE,QAAI,KAAK,UAAU,WAAW,GAAG;AAC/B,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AAEA,eAAW,EAAE,IAAI,SAAA,KAAc,KAAK,WAAW;AAC7C,aAAO,SAAS,YAAY,OAAO;AAAA,IACrC;AAEA,UAAM,IAAI,MAAM,UAAU,QAAQ,KAAK,aAAa;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,YAAY,UAAsC;AAEtD,QAAI,KAAK,UAAU,WAAW,GAAG;AAC/B,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AAEA,UAAM,SAAS,QAAQ,iBAAiB,KAAK,SAAS;AACtD,eAAW,SAAS,QAAQ;AAC1B,UAAI,MAAM,WAAW,GAAG;AACtB,cAAM,SAAS,MAAM,MAAM,CAAC,EAAE,GAAG,YAAY,QAAQ;AACrD,YAAI,OAAQ,QAAO;AAAA,MACrB,OAAO;AACL,cAAM,UAAU,MAAM,QAAQ;AAAA,UAC5B,MAAM,IAAI,CAAC,MAAM,EAAE,GAAG,YAAY,QAAQ,CAAC;AAAA,QAAA;AAE7C,mBAAW,UAAU,SAAS;AAC5B,cAAI,OAAO,WAAW,eAAe,OAAO,MAAO,QAAO;AAAA,QAC5D;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,oBAAoB,SAAgD;AAElE,QAAI,KAAK,UAAU,WAAW,GAAG;AAC/B,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AAEA,UAAM,YAAY,KAAK,UAAU;AAAA,MAAI,CAAC,EAAE,IAAI,eAC1C,SAAS,oBAAoB,OAAO;AAAA,IAAA;AAEtC,WAAO,QAAQ,IAAI,SAAS,EAAE,KAAK,MAAM,QAAQ,SAAS;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,eAAoC;AAExC,QAAI,KAAK,UAAU,WAAW,GAAG;AAC/B,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AAEA,UAAM,mCAA0C,IAAA;AAChD,eAAW,EAAE,IAAI,SAAA,KAAc,KAAK,WAAW;AAC7C,YAAM,OAAO,MAAM,SAAS,aAAA;AAE5B,UAAI,KAAK,SAAS,GAAG;AACnB,mBAAW,YAAY,MAAM;AAC3B,cAAI,CAAC,aAAa,IAAI,SAAS,GAAG,GAAG;AACnC,yBAAa,IAAI,SAAS,KAAK,QAAQ;AAAA,UACzC;AAAA,QACF;AACA;AAAA,MACF;AAAA,IACF;AACA,WAAO,MAAM,KAAK,aAAa,OAAA,CAAQ;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,SAA0C;AAE9C,QAAI,KAAK,UAAU,WAAW,GAAG;AAC/B,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AAGA,UAAM,SAAS,KAAK,UAAU;AAAA,MAAI,CAAC,EAAE,IAAI,eACvC,SAAS,MAAM,OAAO;AAAA,IAAA;AAExB,WAAO,QAAQ,IAAI,MAAM,EAAE,KAAK,MAAM,QAAQ,SAAS;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,SAAS,SAGK;AAElB,QAAI,KAAK,UAAU,WAAW,GAAG;AAC/B,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AAEA,QAAI,iBAAiB;AACrB,UAAM,2BAA8B,IAAA;AACpC,QAAI,OAAgC;AACpC,QAAI,WAAmB;AAEvB,UAAM,SAAkB,CAAA;AAGxB,UAAM,SAAS,QAAQ,iBAAiB,KAAK,SAAS;AAEtD,eAAW,SAAS,QAAQ;AAC1B,UAAI,MAAM,WAAW,GAAG;AAEtB,cAAM,WAAW,MAAM,CAAC;AACxB,YAAI;AACF,gBAAM,EAAE,CAAC,QAAQ,KAAK,GAAG,UAAA,IAAc,MAAM,SAAS,GAAG;AAAA,YACvD;AAAA,UAAA;AAEF,gBAAM,YAAa,UAChB;AACH,gBAAM,YAAa,UAChB;AACH,2BAAiB;AACjB,mBAAS;AAET,cAAI,UAAU,SAAS,GAAG;AAExB,uBAAW,SAAS,MAAM;AAE1B,uBAAW,YAAY,WAAW;AAChC,oBAAM,MAAM,SAAS;AACrB,mBAAK,IAAI,KAAK,QAAQ;AAAA,YACxB;AACA;AAAA,UACF;AAAA,QACF,SAAS,GAAG;AACV,iBAAO,KAAK,CAAU;AAAA,QACxB;AAAA,MACF,OAAO;AAGL,cAAM,UAAU,MAAM,QAAQ;AAAA,UAC5B,MAAM,IAAI,OAAO,aAAa;AAC5B,kBAAM,EAAE,CAAC,QAAQ,KAAK,GAAG,UAAA,IAAc,MAAM,SAAS,GAAG;AAAA,cACvD;AAAA,YAAA;AAEF,mBAAO;AAAA,cACL;AAAA,cACA,WAAY,UAA6C;AAAA,cACzD,WAAY,UAA6C;AAAA,YAAA;AAAA,UAE7D,CAAC;AAAA,QAAA;AAGH,YAAI,YAAY;AAChB,mBAAW,UAAU,SAAS;AAC5B,cAAI,OAAO,WAAW,YAAY;AAChC,mBAAO,KAAK,OAAO,MAAe;AAClC;AAAA,UACF;AACA,2BAAiB;AACjB,gBAAM,EAAE,UAAU,WAAW,UAAA,IAAc,OAAO;AAClD,mBAAS;AACT,cAAI,UAAU,SAAS,KAAK,CAAC,WAAW;AACtC,wBAAY;AACZ,uBAAW,SAAS,MAAM;AAE1B,uBAAW,YAAY,WAAW;AAChC,oBAAM,MAAM,SAAS;AACrB,mBAAK,IAAI,KAAK,QAAQ;AAAA,YACxB;AAAA,UACF;AAAA,QACF;AAEA,YAAI,UAAW;AAAA,MACjB;AAAA,IACF;AAEA,QAAI,CAAC,gBAAgB;AAEnB,UAAI,OAAO,WAAW,GAAG;AACvB,cAAM,IAAI,MAAM,UAAU,QAAQ,KAAK,aAAa;AAAA,MACtD,OAAO;AACL,cAAM,gBAAgB,OAAO;AAAA,UAC3B,CAAC,QAAQ,CAAC,IAAI,QAAQ,SAAS,UAAU,QAAQ,KAAK,aAAa;AAAA,QAAA;AAErE,YAAI,cAAc,SAAS,GAAG;AAC5B,gBAAM,cAAc,CAAC;AAAA,QACvB,OAAO;AACL,gBAAM,OAAO,CAAC;AAAA,QAChB;AAAA,MACF;AAAA,IACF,OAAO;AACL,YAAM,SAAS;AAAA,QACb,CAAC,QAAQ,KAAK,GAAG,IAAI,EAAE,OAAO,MAAM,KAAK,KAAK,OAAA,CAAQ,GAAG,OAAO,MAAM;AAAA,MAAA;AAIxE,UAAI,KAAK,UAAU,SAAS,KAAK,KAAK,OAAO,GAAG;AAC9C,mBAAW,aAAa,KAAK,WAAW;AACtC,cAAI,UAAU,OAAO,UAAU;AAC7B;AAAA,UACF;AAEA,cAAI;AACF,kBAAM,UAAU,GAAG,MAAM;AAAA,cACvB,MAAM;AAAA,YAAA,CACP;AAAA,UACH,QAAQ;AACN;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAGA,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,SAAS,OAAgC;AAE7C,QAAI,KAAK,UAAU,WAAW,GAAG;AAC/B,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AAEA,UAAM,YAAY,MAAM,KAAK,UAAU,EAAE,OAAO;AAChD,UAAM,YAAuB,UAAU,KAAK;AAE5C,QAAI,CAAC,WAAW;AACd,YAAM,IAAI,MAAM,UAAU,KAAK,aAAa;AAAA,IAC9C;AACA,WAAO,QAAQ,QAAQ,UAAU,MAAM,MAAM;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,YAA8B;AAChC,WAAO,KAAK,KACT,OAAO,CAAC,cAAc,UAAU,IAAI,EACpC,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,YAA8B;AAChC,WAAO,KAAK,KACT,OAAO,CAAC,cAAc,UAAU,KAAK,EACrC,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,YAA8B;AAChC,WAAO,KAAK,KACT,OAAO,CAAC,cAAc,UAAU,IAAI,EACpC,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,iBAAiB,KAAgD;AACtE,UAAM,SAAkC,CAAA;AACxC,QAAI,UAA4B,CAAA;AAChC,QAAI,kBAAiC;AAErC,eAAW,MAAM,KAAK;AACpB,UAAI,GAAG,aAAa,iBAAiB;AACnC,YAAI,QAAQ,SAAS,EAAG,QAAO,KAAK,OAAO;AAC3C,kBAAU,CAAC,EAAE;AACb,0BAAkB,GAAG;AAAA,MACvB,OAAO;AACL,gBAAQ,KAAK,EAAE;AAAA,MACjB;AAAA,IACF;AACA,QAAI,QAAQ,SAAS,EAAG,QAAO,KAAK,OAAO;AAE3C,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,OAAO,UAAU,YAAY;AAC3B,UAAM,YAAY,MAAM,MAAM,QAAA;AAC9B,UAAM,UAAU,KAAA;AAEhB,UAAM,eAAe,IAAI,eAAe,SAAS;AACjD,UAAM,SAAS,IAAI,OAAO,YAAY;AACtC,UAAM,OAAO,KAAA;AAEb,UAAM,QAAQ,MAAM,MAAM,QAAA;AAC1B,UAAM,MAAM,KAAA;AAEZ,UAAM,MAAwB;AAAA,MAC5B,EAAE,IAAI,QAAQ,UAAU,GAAG,MAAM,MAAM,OAAO,OAAO,MAAM,MAAA;AAAA,MAC3D,EAAE,IAAI,OAAO,UAAU,GAAG,MAAM,MAAM,OAAO,MAAM,MAAM,KAAA;AAAA,IAAK;AAGhE,UAAM,UAAU,IAAI,QAAQ,GAAG;AAC/B,UAAM,QAAQ,KAAA;AAEd,WAAO;AAAA,EACT;AACF;ACzdO,MAAM,aAAa;AAAA,EAIxB,YAAoB,KAAiB,SAAiB;AAAlC,SAAA,MAAA;AAAiB,SAAA,UAAA;AAAA,EAAkB;AAAA,EAH/C,qCACF,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQN,QAAc;AACZ,SAAK,QAAQ,GAAG,WAAW,MAAM,KAAK,gBAAgB;AACtD,SAAK,QAAQ,GAAG,cAAc,MAAM,KAAK,mBAAmB;AAG5D,SAAK,mBAAA;AAAA,EACP;AAAA;AAAA;AAAA;AAAA,EAKA,OAAa;AAEX,SAAK,QAAQ,IAAI,WAAW,MAAM,KAAK,gBAAgB;AAEvD,SAAK,QAAQ,IAAI,cAAc,MAAM,KAAK,mBAAmB;AAE7D,eAAW,CAAC,WAAW,OAAO,KAAK,KAAK,gBAAgB;AACtD,WAAK,QAAQ,IAAI,WAAW,OAAO;AAAA,IACrC;AACA,SAAK,eAAe,MAAA;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAA2B;AAEjC,UAAM,YAAY;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAGF,eAAW,cAAc,WAAW;AAClC,WAAK,cAAc,UAAU;AAAA,IAC/B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,cAAc,WAAmB,cAA6B;AAC5D,UAAM,aAAa,gBAAgB;AAGnC,UAAM,UAAU,IAAI,SAAgB;AAElC,YAAM,WAAW,KAAK,KAAK,SAAS,CAAC;AACrC,YAAM,aAAa,KAAK,MAAM,GAAG,EAAE;AAGnC,YAAM,WAAY,KAAK,IAAY,UAAU;AAG7C,UAAI,OAAO,aAAa,YAAY;AAClC,cAAM,QAAQ,IAAI;AAAA,UAChB,WAAW,UAAU;AAAA,QAAA;AAEvB,YAAI,OAAO,aAAa,YAAY;AAClC,mBAAS,MAAM,KAAK;AAAA,QACtB;AACA;AAAA,MACF;AAIA,eACG,MAAM,KAAK,KAAK,UAAU,EAC1B,KAAK,CAAC,WAAgB;AACrB,YAAI,OAAO,aAAa,YAAY;AAElC,mBAAS,QAAQ,IAAI;AAAA,QACvB;AAAA,MACF,CAAC,EACA,MAAM,CAAC,UAAe;AACrB,YAAI,OAAO,aAAa,YAAY;AAElC,mBAAS,MAAM,KAAK;AAAA,QACtB;AAAA,MACF,CAAC;AAAA,IACL;AAEA,SAAK,eAAe,IAAI,WAAW,OAAO;AAC1C,SAAK,QAAQ,GAAG,WAAW,OAAO;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAAe,YAA4B;AACzC,eAAW,aAAa,YAAY;AAClC,WAAK,cAAc,SAAS;AAAA,IAC9B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,gBAAgB,WAAkC;AAChD,UAAM,UAAU,KAAK,eAAe,IAAI,SAAS;AACjD,QAAI,SAAS;AACX,WAAK,QAAQ,IAAI,WAAW,OAAO;AACnC,WAAK,eAAe,OAAO,SAAS;AAAA,IACtC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,aAAa,cAA+B,MAAmB;AAC7D,SAAK,QAAQ,KAAK,WAAW,GAAG,IAAI;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,cACJ,cACA,oBACG,MACY;AACf,QAAI;AACF,YAAM,WAAY,KAAK,IAAY,YAAY;AAE/C,UAAI,OAAO,aAAa,YAAY;AAClC,cAAM,IAAI,MAAM,WAAW,YAAY,4BAA4B;AAAA,MACrE;AAEA,YAAM,SAAS,MAAM,SAAS,MAAM,KAAK,KAAK,IAAI;AAClD,WAAK,QAAQ,KAAK,iBAAiB,QAAQ,IAAI;AAAA,IACjD,SAAS,OAAO;AACd,WAAK,QAAQ,KAAK,iBAAiB,MAAM,KAAK;AAAA,IAChD;AAAA,EACF;AAAA;AAAA,EAGQ,iBAAuB;AAAA,EAE/B;AAAA;AAAA,EAGQ,oBAA0B;AAAA,EAElC;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,SAAiB;AACnB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,KAAS;AACX,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,cAAuB;AACzB,WAAO,KAAK,QAAQ;AAAA,EACtB;AACF;AC1MO,MAAM,SAAS;AAAA,EAGpB,YAAoB,KAAS;AAAT,SAAA,MAAA;AAAA,EAAU;AAAA,EAFtB,WAAqB,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS7B,MAAM,UAAU,QAA+B;AAE7C,UAAM,KAAK,mBAAmB,MAAM;AAGpC,SAAK,SAAS,KAAK,MAAM;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAa,QAAsB;AACjC,SAAK,WAAW,KAAK,SAAS,OAAO,CAAC,MAAM,MAAM,MAAM;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,mBAAmB,QAA+B;AAI9D,UAAM,OAAO,KAAK,4BAAA;AAClB,eAAW,CAAC,KAAK,EAAE,KAAK,OAAO,QAAQ,IAAI,GAAG;AAC5C,aAAO,GAAG,KAAK,IAAI,SAAgB;AACjC,cAAM,KAAK,KAAK,KAAK,SAAS,CAAC;AAE/B,WAAG,MAAM,MAAM,KAAK,MAAM,GAAG,EAAE,CAAC,EAC7B,KAAK,CAAC,WAAW;AAChB,aAAG,QAAQ,IAAI;AAAA,QACjB,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,aAAG,MAAM,GAAG;AAAA,QACd,CAAC;AAAA,MACL,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,oBAAoB,SAEhB;AAChB,WAAO,KAAK,IAAI,oBAAoB,OAAO;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,8BAA8B,OACnC;AAAA,IACC,MAAM,MAAM,KAAK,IAAI,KAAA;AAAA,IACrB,OAAO,MAAM,KAAK,IAAI,MAAA;AAAA,IACtB,QAAQ,MACN,IAAI,QAAQ,CAAC,YAAY,QAAQ,KAAK,IAAI,MAAM,CAAC;AAAA,IACnD,SAAS,MAAM,KAAK,IAAI,QAAA;AAAA,IACxB,MAAM,MAAM,KAAK,IAAI,KAAA;AAAA,IACrB,WAAW,CAAC,YAA+B,KAAK,IAAI,UAAU,OAAO;AAAA,IACrE,aAAa,CAAC,YACZ,KAAK,IAAI,YAAY,OAAO;AAAA,IAC9B,aAAa,CAAC,aAAuB,KAAK,IAAI,YAAY,QAAQ;AAAA,IAClE,qBAAqB,CAAC,YACpB,KAAK,oBAAoB,OAAO;AAAA,IAClC,cAAc,MAAM,KAAK,IAAI,aAAA;AAAA,IAC7B,OAAO,CAAC,YAA8B,KAAK,IAAI,MAAM,OAAO;AAAA,IAC5D,UAAU,CAAC,YAGL,KAAK,IAAI,SAAS,OAAO;AAAA,IAC/B,UAAU,CAAC,UAAkB,KAAK,IAAI,SAAS,KAAK;AAAA,EAAA;AAE1D;ACjEO,MAAM,mBAAmB,MAAmB;AACjD,SAAO;AAAA,IACL,IAAI,IAAI,MAAA;AAAA,IACR,WAAW,YAAY;AAAA,IAGvB;AAAA,IAEA,YAAY,YAAY;AAAA,IAExB;AAAA,IACA,WAAW,YAAY;AAAA,IAEvB;AAAA,IAEA,UAAU,YAAY;AAAA,IAEtB;AAAA,EAAA;AAEJ;AC0BO,MAAM,YACX;ACzBK,MAAM,kBAAkB,CAAC,WAAgC;AAC9D,QAAM,SAAsB,CAAA;AAI5B,oBAAkB,QAAQ,CAAC,eAAe,UAAU;AAClD,UAAM,aAAoD,CAAA;AAC1D,WAAO,aAAa,IAAI;AACxB,eAAW,YAAY,MAAM,OAAO;AAClC,iBAAW,SAAS,KAAK,IAAI,CAAA;AAAA,IAC/B;AAAA,EACF,CAAC;AAID,oBAAkB,QAAQ,CAAC,gBAAgB,gBAAgB;AAEzD,eAAW,kBAAkB,YAAY,OAAO;AAG9C,cAAQ,YAAY,OAAA;AAAA,QAClB,KAAK;AACH,8BAAoB,gBAAgB,gBAAgB,MAAM;AAC1D;AAAA,QAEF,KAAK,UAAU;AACb,0BAAgB,gBAAgB,gBAAgB,MAAM;AACtD;AAAA,QACF;AAAA,QAEA,KAAK,YAAY;AAEf;AAAA,QACF;AAAA,QAEA,KAAK,SAAS;AACZ,yBAAe,gBAAgB,gBAAgB,MAAM;AACrD;AAAA,QACF;AAAA,QAEA,KAAK,WAAW;AACd,2BAAiB,gBAAgB,gBAAgB,MAAM;AACvD;AAAA,QACF;AAAA,MAAA;AAAA,IAEJ;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAKA,MAAM,sBAAsB,CAC1B,iBACA,WACA,WACG;AACH,QAAM,gBAAgB,UAAU;AAEhC,aAAW,oBAAoB,WAAW;AACxC,QAAI,iBAAiB,WAAW,GAAG,GAAG;AACpC;AAAA,IACF;AAEA,QAAI,CAAC,iBAAiB,SAAS,KAAK,GAAG;AACrC;AAAA,IACF;AAEA,UAAM,iBAAiB,iBAAiB,MAAM,GAAG,EAAE;AACnD,UAAM,eAAe,UAAU,gBAAgB;AAE/C;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ;AACF;AAGA,MAAM,kBAAkB,CACtB,iBACA,WACA,WACG;AACH,QAAM,iBAAiB,UAAU;AACjC,QAAM,gBAAgB,UAAU;AAEhC,aAAW,WAAW,UAAU,KAAK;AACnC,QAAI,QAAQ,WAAW,GAAG,GAAG;AAC3B;AAAA,IACF;AAEA,UAAM,YAAY,UAAU,IAAI,OAAO;AAEvC,WAAO,QAAQ,gBAAgB,WAAW,iBAAiB,aAAa;AAAA,EAC1E;AACF;AAGA,MAAM,iBAAiB,CACrB,iBACA,WACA,WACG;AACH,QAAM,gBAAgB,UAAU;AAEhC,aAAW,SAAS,UAAU,QAAQ;AACpC,UAAM,iBAAiB;AACvB,UAAM,eAAe,UAAU,OAAO,KAAK;AAC3C;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ;AACF;AAGA,MAAM,mBAAmB,CACvB,iBACA,WACA,WACG;AACH,QAAM,gBAAgB,UAAU;AAEhC,aAAW,QAAQ,UAAU,OAAO;AAClC,UAAM,iBAAiB,KAAK;AAC5B,UAAM,eAAe,KAAK;AAC1B;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ;AACF;AAGA,MAAM,SAAS,CACb,QACA,gBACA,cACA,iBACA,kBACG;AACH,QAAM,0BAA2B,OAAO,cAAc,MAAM,CAAA;AAC5D,QAAM,6BAA8B,wBAAwB,YAAY,MACtE,CAAA;AAEF,6BAA2B,eAAe,MAAM,CAAA;AAChD,6BAA2B,eAAe,EAAE,aAAa,MAAM,CAAA;AACjE;ACpNO,MAAM,WAA6B;AAAA,EACjC,YAAqB;AAAA,EACrB,eAAwB;AAAA,EAEvB,iCACF,IAAA;AAAA,EACE,qCAGA,IAAA;AAAA,EAER,UAAgB;AACd,QAAI,CAAC,KAAK,WAAW;AACnB,WAAK,YAAY;AACjB,WAAK,eAAe;AACpB,WAAK,KAAK,SAAS;AAAA,IACrB;AAAA,EACF;AAAA,EAEA,aAAmB;AACjB,QAAI,KAAK,WAAW;AAClB,WAAK,YAAY;AACjB,WAAK,eAAe;AACpB,WAAK,KAAK,YAAY;AAAA,IACxB;AAAA,EACF;AAAA,EAEA,GAAG,WAA4B,UAA0C;AACvE,QAAI,CAAC,KAAK,WAAW,IAAI,SAAS,GAAG;AACnC,WAAK,WAAW,IAAI,WAAW,CAAA,CAAE;AAAA,IACnC;AACA,SAAK,WAAW,IAAI,SAAS,EAAG,KAAK,QAAQ;AAC7C,WAAO;AAAA,EACT;AAAA,EAEA,KAAK,WAA4B,UAA0C;AACzE,QAAI,CAAC,KAAK,eAAe,IAAI,SAAS,GAAG;AACvC,WAAK,eAAe,IAAI,WAAW,CAAA,CAAE;AAAA,IACvC;AACA,SAAK,eAAe,IAAI,SAAS,EAAG,KAAK,QAAQ;AACjD,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,WAA4B,UAA2C;AACzE,QAAI,UAAU;AAEZ,YAAM,mBAAmB,KAAK,WAAW,IAAI,SAAS;AACtD,UAAI,kBAAkB;AACpB,cAAM,QAAQ,iBAAiB,QAAQ,QAAQ;AAC/C,YAAI,QAAQ,IAAI;AACd,2BAAiB,OAAO,OAAO,CAAC;AAAA,QAClC;AAAA,MACF;AAEA,YAAM,gBAAgB,KAAK,eAAe,IAAI,SAAS;AACvD,UAAI,eAAe;AACjB,cAAM,QAAQ,cAAc,QAAQ,QAAQ;AAC5C,YAAI,QAAQ,IAAI;AACd,wBAAc,OAAO,OAAO,CAAC;AAAA,QAC/B;AAAA,MACF;AAAA,IACF,OAAO;AAEL,WAAK,WAAW,OAAO,SAAS;AAChC,WAAK,eAAe,OAAO,SAAS;AAAA,IACtC;AACA,WAAO;AAAA,EACT;AAAA,EAEA,KAAK,cAA+B,MAAsB;AACxD,QAAI,eAAe;AAGnB,UAAM,mBAAmB,KAAK,WAAW,IAAI,SAAS;AACtD,QAAI,oBAAoB,iBAAiB,SAAS,GAAG;AACnD,qBAAe;AAEf,OAAC,GAAG,gBAAgB,EAAE,QAAQ,CAAC,aAAa;AAC1C,YAAI;AACF,mBAAS,GAAG,IAAI;AAAA,QAClB,SAAS,OAAO;AAEd,kBAAQ;AAAA,YACN,+BAA+B,OAAO,SAAS,CAAC;AAAA,YAChD;AAAA,UAAA;AAAA,QAEJ;AAAA,MACF,CAAC;AAAA,IACH;AAGA,UAAM,gBAAgB,KAAK,eAAe,IAAI,SAAS;AACvD,QAAI,iBAAiB,cAAc,SAAS,GAAG;AAC7C,qBAAe;AAEf,YAAM,kBAAkB,CAAC,GAAG,aAAa;AACzC,WAAK,eAAe,OAAO,SAAS;AAEpC,sBAAgB,QAAQ,CAAC,aAAa;AACpC,YAAI;AACF,mBAAS,GAAG,IAAI;AAAA,QAClB,SAAS,OAAO;AACd,kBAAQ;AAAA,YACN,oCAAoC,OAAO,SAAS,CAAC;AAAA,YACrD;AAAA,UAAA;AAAA,QAEJ;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,mBAAmB,WAAmC;AACpD,QAAI,cAAc,QAAW;AAC3B,WAAK,WAAW,OAAO,SAAS;AAChC,WAAK,eAAe,OAAO,SAAS;AAAA,IACtC,OAAO;AACL,WAAK,WAAW,MAAA;AAChB,WAAK,eAAe,MAAA;AAAA,IACtB;AACA,WAAO;AAAA,EACT;AAAA,EAEA,cAAc,WAAoC;AAChD,UAAM,eAAe,KAAK,WAAW,IAAI,SAAS,GAAG,UAAU;AAC/D,UAAM,YAAY,KAAK,eAAe,IAAI,SAAS,GAAG,UAAU;AAChE,WAAO,eAAe;AAAA,EACxB;AAAA,EAEA,UAAU,WAA6D;AACrE,UAAM,mBAAmB,KAAK,WAAW,IAAI,SAAS,KAAK,CAAA;AAC3D,UAAM,gBAAgB,KAAK,eAAe,IAAI,SAAS,KAAK,CAAA;AAC5D,WAAO,CAAC,GAAG,kBAAkB,GAAG,aAAa;AAAA,EAC/C;AAAA,EAEA,aAAqC;AACnC,UAAM,gCAAgB,IAAI;AAAA,MACxB,GAAG,KAAK,WAAW,KAAA;AAAA,MACnB,GAAG,KAAK,eAAe,KAAA;AAAA,IAAK,CAC7B;AACD,WAAO,MAAM,KAAK,SAAS;AAAA,EAC7B;AAAA;AAAA,EAGA,QAAc;AACZ,SAAK,YAAY;AACjB,SAAK,eAAe;AACpB,SAAK,mBAAA;AAAA,EACP;AAAA,EAEA,cAAc,OAAoB;AAChC,SAAK,KAAK,SAAS,KAAK;AAAA,EAC1B;AAAA,EAEA,gBAAgB,SAAoB;AAClC,SAAK,KAAK,WAAW,OAAO;AAAA,EAC9B;AAAA;AAAA,EAGA,eAAsE;AACpE,WAAO,IAAI,IAAI,KAAK,UAAU;AAAA,EAChC;AAAA,EAEA,mBAA0E;AACxE,WAAO,IAAI,IAAI,KAAK,cAAc;AAAA,EACpC;AACF;AC9JO,SAAS,mBAGd;AACA,QAAM,UAAU,IAAI,sBAAA;AACpB,QAAM,UAAU,IAAI,sBAAA;AAGpB,UAAQ,SAAS,OAAO;AACxB,UAAQ,SAAS,OAAO;AAExB,SAAO,CAAC,SAAS,OAAO;AAC1B;AAEO,MAAM,sBAAwC;AAAA,EAC5C,YAAqB;AAAA,EACrB,eAAwB;AAAA,EAEvB;AAAA,EACA,iCACF,IAAA;AAAA,EACE,qCAGA,IAAA;AAAA,EAER,SAAS,MAAmC;AAC1C,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,UAAgB;AACd,QAAI,CAAC,KAAK,WAAW;AACnB,WAAK,YAAY;AACjB,WAAK,eAAe;AAEpB,WAAK,cAAc,SAAS;AAE5B,UAAI,KAAK,OAAO;AACd,aAAK,MAAM,cAAc,SAAS;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,aAAmB;AACjB,QAAI,KAAK,WAAW;AAClB,WAAK,YAAY;AACjB,WAAK,eAAe;AACpB,WAAK,cAAc,YAAY;AAC/B,UAAI,KAAK,OAAO;AACd,aAAK,MAAM,cAAc,YAAY;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,GAAG,WAA4B,UAA0C;AACvE,QAAI,CAAC,KAAK,WAAW,IAAI,SAAS,GAAG;AACnC,WAAK,WAAW,IAAI,WAAW,CAAA,CAAE;AAAA,IACnC;AACA,SAAK,WAAW,IAAI,SAAS,EAAG,KAAK,QAAQ;AAC7C,WAAO;AAAA,EACT;AAAA,EAEA,KAAK,WAA4B,UAA0C;AACzE,QAAI,CAAC,KAAK,eAAe,IAAI,SAAS,GAAG;AACvC,WAAK,eAAe,IAAI,WAAW,CAAA,CAAE;AAAA,IACvC;AACA,SAAK,eAAe,IAAI,SAAS,EAAG,KAAK,QAAQ;AACjD,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,WAA4B,UAA2C;AACzE,QAAI,UAAU;AACZ,YAAM,mBAAmB,KAAK,WAAW,IAAI,SAAS;AACtD,UAAI,kBAAkB;AACpB,cAAM,QAAQ,iBAAiB,QAAQ,QAAQ;AAC/C,YAAI,QAAQ,GAAI,kBAAiB,OAAO,OAAO,CAAC;AAAA,MAClD;AACA,YAAM,gBAAgB,KAAK,eAAe,IAAI,SAAS;AACvD,UAAI,eAAe;AACjB,cAAM,QAAQ,cAAc,QAAQ,QAAQ;AAC5C,YAAI,QAAQ,GAAI,eAAc,OAAO,OAAO,CAAC;AAAA,MAC/C;AAAA,IACF,OAAO;AACL,WAAK,WAAW,OAAO,SAAS;AAChC,WAAK,eAAe,OAAO,SAAS;AAAA,IACtC;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,KAAK,cAA+B,MAAsB;AACxD,QAAI,CAAC,KAAK,OAAO;AACf,cAAQ;AAAA,QACN,2DAA2D,OAAO,SAAS,CAAC;AAAA,MAAA;AAE9E,aAAO;AAAA,IACT;AAGA,SAAK,MAAM,cAAc,WAAW,GAAG,IAAI;AAC3C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,cAAc,cAA+B,MAAmB;AAEtE,UAAM,mBAAmB,KAAK,WAAW,IAAI,SAAS;AACtD,QAAI,kBAAkB;AACpB,OAAC,GAAG,gBAAgB,EAAE,QAAQ,CAAC,aAAa;AAC1C,YAAI;AACF,mBAAS,GAAG,IAAI;AAAA,QAClB,SAAS,OAAO;AACd,kBAAQ,MAAM,yBAAyB,OAAO,SAAS,CAAC,KAAK,KAAK;AAAA,QACpE;AAAA,MACF,CAAC;AAAA,IACH;AAGA,UAAM,gBAAgB,KAAK,eAAe,IAAI,SAAS;AACvD,QAAI,eAAe;AACjB,YAAM,kBAAkB,CAAC,GAAG,aAAa;AACzC,WAAK,eAAe,OAAO,SAAS;AACpC,sBAAgB,QAAQ,CAAC,aAAa;AACpC,YAAI;AACF,mBAAS,GAAG,IAAI;AAAA,QAClB,SAAS,OAAO;AACd,kBAAQ;AAAA,YACN,8BAA8B,OAAO,SAAS,CAAC;AAAA,YAC/C;AAAA,UAAA;AAAA,QAEJ;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,mBAAmB,WAAmC;AACpD,QAAI,cAAc,QAAW;AAC3B,WAAK,WAAW,OAAO,SAAS;AAChC,WAAK,eAAe,OAAO,SAAS;AAAA,IACtC,OAAO;AACL,WAAK,WAAW,MAAA;AAChB,WAAK,eAAe,MAAA;AAAA,IACtB;AACA,WAAO;AAAA,EACT;AAAA,EAEA,cAAc,WAAoC;AAChD,UAAM,eAAe,KAAK,WAAW,IAAI,SAAS,GAAG,UAAU;AAC/D,UAAM,YAAY,KAAK,eAAe,IAAI,SAAS,GAAG,UAAU;AAChE,WAAO,eAAe;AAAA,EACxB;AAAA,EAEA,UAAU,WAA6D;AACrE,UAAM,mBAAmB,KAAK,WAAW,IAAI,SAAS,KAAK,CAAA;AAC3D,UAAM,gBAAgB,KAAK,eAAe,IAAI,SAAS,KAAK,CAAA;AAC5D,WAAO,CAAC,GAAG,kBAAkB,GAAG,aAAa;AAAA,EAC/C;AAAA,EAEA,aAAqC;AACnC,UAAM,gCAAgB,IAAI;AAAA,MACxB,GAAG,KAAK,WAAW,KAAA;AAAA,MACnB,GAAG,KAAK,eAAe,KAAA;AAAA,IAAK,CAC7B;AACD,WAAO,MAAM,KAAK,SAAS;AAAA,EAC7B;AACF;AC7KO,MAAM,gBAAgB,OAAe;AAAA,EAC1C,WAAW;AAAA,EACX,cAAc;AAAA,EACd,UAAU;AACR,SAAK,YAAY;AACjB,SAAK,eAAe;AACpB,SAAK,KAAK,SAAS;AAAA,EACrB;AAAA,EACA,aAAa;AACX,SAAK,YAAY;AACjB,SAAK,eAAe;AACpB,SAAK,KAAK,YAAY;AAAA,EACxB;AAAA;AAAA,EAEA,KAAK;AAEH,WAAO;AAAA,EACT;AAAA;AAAA,EAEA,OAAO;AAEL,WAAO;AAAA,EACT;AAAA;AAAA,EAEA,MAAM;AAEJ,WAAO;AAAA,EACT;AAAA;AAAA,EAEA,qBAAqB;AAEnB,WAAO;AAAA,EACT;AACF;"}
1
+ {"version":3,"file":"io.js","sources":["/Users/maximilianheller/Documents/Development/rljson-io/src/io-db-name-mapping.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/io-tools.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/io-mem.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/peer-socket-mock.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/io-peer.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/io-multi.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/io-peer-bridge.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/io-server.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/io-test-setup.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/io.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/reverse-ref.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/socket-mock.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/directional-socket-mock.ts","/Users/maximilianheller/Documents/Development/rljson-io/src/socket.ts"],"sourcesContent":["// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nexport class IoDbNameMapping {\n // The primary key column is always named '_hash'\n public primaryKeyColumn: string = '_hash';\n public dataSection: string = '_data';\n public typeColumn: string = 'type';\n public keyColumn: string = 'key';\n\n // Names for the main tables in the database\n public tableNames: { [key: string]: string } = {\n main: 'tableCfgs',\n revision: 'revisions',\n };\n\n /// Suffix handling for the database\n private _suffix: { [key: string]: string } = {\n col: '_col',\n tbl: '_tbl',\n tmp: '_tmp',\n };\n\n // ********************************************************************\n // add and remove suffixes for use in SQL statements\n private _addFix(name: string, fix: string): string {\n return name.endsWith(fix) ? name : name + fix;\n }\n\n public addTableSuffix(name: string): string {\n return this._addFix(name, this._suffix.tbl);\n }\n\n public addColumnSuffix(name: string): string {\n return this._addFix(name, this._suffix.col);\n }\n\n public addTmpSuffix(name: string): string {\n return this._addFix(name, this._suffix.tmp);\n }\n\n private _removeFix(name: string, fix: string): string {\n return name.endsWith(fix) ? name.slice(0, -fix.length) : name;\n }\n\n public removeTableSuffix(name: string): string {\n return this._removeFix(name, this._suffix.tbl);\n }\n\n public removeColumnSuffix(name: string): string {\n return this._removeFix(name, this._suffix.col);\n }\n\n public removeTmpSuffix(name: string): string {\n return this._removeFix(name, this._suffix.tmp);\n }\n}\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { hip } from '@rljson/hash';\nimport {\n iterateTables,\n Rljson,\n TableCfg,\n TableKey,\n TableType,\n throwOnInvalidTableCfg,\n validateRljsonAgainstTableCfg,\n} from '@rljson/rljson';\n\nimport { IoMem } from './io-mem.ts';\nimport { Io } from './io.ts';\n\nexport type IoObserver = (data: Rljson) => void;\n\n/**\n * Provides utility functions for the Io interface.\n */\nexport class IoTools {\n /**\n * Constructor\n * @param io The Io interface to use\n */\n constructor(public readonly io: Io) {}\n\n /**\n * Returns the table configuration of the tableCfgs table.\n */\n static get tableCfgsTableCfg() {\n const tableCfg = hip<TableCfg>({\n _hash: '',\n key: 'tableCfgs',\n type: 'tableCfgs',\n isHead: false,\n isRoot: false,\n isShared: true,\n previous: '',\n\n columns: [\n {\n key: '_hash',\n type: 'string',\n titleShort: 'Hash',\n titleLong: 'Row Hash',\n },\n {\n key: 'key',\n type: 'string',\n titleShort: 'Key',\n titleLong: 'Table Key',\n },\n {\n key: 'type',\n type: 'string',\n titleShort: 'Type',\n titleLong: 'Content Type',\n },\n {\n key: 'isHead',\n type: 'boolean',\n titleShort: 'Is Head',\n titleLong: 'Is Head Table',\n },\n {\n key: 'isRoot',\n type: 'boolean',\n titleShort: 'Is Root',\n titleLong: 'Is Root Table',\n },\n {\n key: 'isShared',\n type: 'boolean',\n titleShort: 'Is Shared',\n titleLong: 'Is Shared Table',\n },\n {\n key: 'previous',\n type: 'string',\n titleShort: 'Previous',\n titleLong: 'Previous Table Configuration Hash',\n },\n {\n key: 'columns',\n type: 'jsonArray',\n titleShort: 'Columns',\n titleLong: 'Column Configurations',\n },\n ],\n });\n\n return tableCfg;\n }\n\n /**\n * Initializes the revisions table.\n */\n initRevisionsTable = async () => {\n const tableCfg: TableCfg = {\n key: 'revisions',\n type: 'revisions',\n isHead: true,\n isRoot: true,\n isShared: false,\n\n columns: [\n {\n key: '_hash',\n type: 'string',\n titleShort: 'Hash',\n titleLong: 'Row Hash',\n },\n {\n key: 'table',\n type: 'string',\n titleShort: 'Table',\n titleLong: 'Table Key',\n },\n {\n key: 'predecessor',\n type: 'string',\n titleShort: 'Predecessor',\n titleLong: 'Predecessor Revision Hash',\n },\n {\n key: 'successor',\n type: 'string',\n titleShort: 'Successor',\n titleLong: 'Successor Revision Hash',\n },\n {\n key: 'timestamp',\n type: 'number',\n titleShort: 'Timestamp',\n titleLong: 'Revision Timestamp',\n },\n {\n key: 'id',\n type: 'string',\n titleShort: 'ID',\n titleLong: 'Revision ID',\n },\n ],\n };\n\n await this.io.createOrExtendTable({ tableCfg });\n };\n\n /**\n * Example object for test purposes\n * @returns An instance of io tools\n */\n static example = async () => {\n const io = await IoMem.example();\n await io.init();\n await io.isReady();\n return new IoTools(io);\n };\n\n /**\n * Throws if the table does not exist\n */\n async throwWhenTableDoesNotExist(table: TableKey): Promise<void> {\n const exists = await this.io.tableExists(table);\n if (!exists) {\n throw new Error(`Table \"${table}\" not found`);\n }\n }\n\n /**\n * Throws if any of the tables in rljson do not exist\n * @param rljson - The Rljson object to check\n */\n async throwWhenTablesDoNotExist(rljson: Rljson): Promise<void> {\n try {\n await iterateTables(rljson, async (tableKey) => {\n const exists = await this.io.tableExists(tableKey);\n if (!exists) {\n throw new Error(`Table \"${tableKey}\" not found`);\n }\n });\n } catch (e) {\n const missingTables = (e as Array<any>).map((e) => e.tableKey);\n\n throw new Error(\n `The following tables do not exist: ${missingTables.join(', ')}`,\n );\n }\n }\n\n /**\n * Returns the current table cfgs of all tables\n * @returns The table configuration of all tables\n */\n async tableCfgs(): Promise<TableCfg[]> {\n const tables = await this.io.rawTableCfgs();\n\n // Take the latest version of each type key\n const newestVersion: Record<TableKey, TableCfg> = {};\n for (let i = tables.length - 1; i >= 0; i--) {\n const table = tables[i];\n const existing = newestVersion[table.key];\n if (!existing || existing.columns.length < table.columns.length) {\n newestVersion[table.key] = table;\n }\n }\n\n // Sort the tables by key\n /* v8 ignore next -- @preserve */\n const resultData = Object.values(newestVersion).sort((a, b) => {\n if (a.key < b.key) {\n return -1;\n }\n if (a.key > b.key) {\n return 1;\n }\n\n return 0;\n });\n return resultData;\n }\n\n /**\n * Returns a list with all table names\n */\n async allTableKeys(): Promise<string[]> {\n const result = (await this.tableCfgs()).map((e) => e.key);\n return result;\n }\n\n /**\n * Returns the configuration of a given table\n */\n async tableCfg(table: TableKey): Promise<TableCfg> {\n const tableCfg = await this.tableCfgOrNull(table);\n if (!tableCfg) {\n throw new Error(`Table \"${table}\" not found`);\n }\n\n return tableCfg!;\n }\n\n /**\n * Returns the configuration of a given table or null if it does not exist.\n\n */\n async tableCfgOrNull(table: TableKey): Promise<TableCfg | null> {\n const tableCfgs = await this.tableCfgs();\n const tableCfg = tableCfgs.find((e) => e.key === table);\n return tableCfg ?? null;\n }\n\n /**\n * Returns a list of all column names of a given table\n */\n async allColumnKeys(table: TableKey): Promise<string[]> {\n const tableCfg = await this.tableCfg(table);\n const result = tableCfg.columns.map((column) => column.key);\n return result;\n }\n\n /**\n * Throws when a column does not exist in a given table\n * @param table - The table to check\n * @param columns - The column to check\n */\n async throwWhenColumnDoesNotExist(\n table: TableKey,\n columns: string[],\n ): Promise<void> {\n const tableCfg = await this.tableCfg(table);\n const columnKeys = tableCfg.columns.map((column) => column.key);\n const missingColumns = columns.filter(\n (column) => !columnKeys.includes(column),\n );\n if (missingColumns.length > 0) {\n throw new Error(\n `The following columns do not exist in table \"${table}\": ${missingColumns.join(\n ', ',\n )}.`,\n );\n }\n }\n\n /**\n * Throws when a table update is not compatible with the current table\n * configuration.\n */\n async throwWhenTableIsNotCompatible(update: TableCfg): Promise<void> {\n const prefix = `Invalid update of table able \"${update.key}\"`;\n\n throwOnInvalidTableCfg(update);\n\n // Check compatibility with existing table\n const existing = await this.tableCfgOrNull(update.key);\n if (existing) {\n // Have columns been deleted?\n if (existing.columns.length > update.columns.length) {\n const deletedColumnKeys = existing.columns\n .map((column) => column.key)\n .filter(\n (key) => !update.columns.some((column) => column.key === key),\n );\n /* v8 ignore next -- @preserve */\n if (deletedColumnKeys.length > 0) {\n const deletedColumns = deletedColumnKeys.join(', ');\n throw new Error(\n `${prefix}: Columns must not be deleted. ` +\n `Deleted columns: ${deletedColumns}}`,\n );\n }\n }\n\n // Have column keys changed?\n for (let i = 0; i < existing.columns.length; i++) {\n const before = existing.columns[i].key;\n const after = update.columns[i].key;\n if (before !== after) {\n throw new Error(\n `${prefix}: ` +\n `Column keys must not change! ` +\n `Column \"${before}\" was renamed into \"${after}\".`,\n );\n }\n }\n\n // Have column types changed?\n for (let i = 0; i < existing.columns.length; i++) {\n const column = existing.columns[i].key;\n const before = existing.columns[i].type;\n const after = update.columns[i].type;\n if (before !== after) {\n throw new Error(\n `${prefix}: ` +\n `Column types must not change! ` +\n `Type of column \"${column}\" was changed from \"${before}\" to ${after}.`,\n );\n }\n }\n }\n }\n\n /**\n * Throws if the data in the table do not match the table configuration\n */\n async throwWhenTableDataDoesNotMatchCfg(data: Rljson) {\n const errors: string[] = [];\n\n await iterateTables(data, async (tableKey) => {\n const tableCfg = await this.tableCfg(tableKey);\n const table = data[tableKey];\n\n // Ignore tableCfgs table\n /* v8 ignore next -- @preserve */\n if (table._type === 'tableCfgs') return;\n\n errors.push(...validateRljsonAgainstTableCfg(table._data, tableCfg));\n });\n\n if (errors.length > 0) {\n throw new Error(\n `Table data does not match the configuration.\\n\\nErrors:\\n${errors\n .map((e) => `- ${e}`)\n .join('\\n')}`,\n );\n }\n }\n\n /**\n * Sorts the data of a table by the hash and updates the table hash in place\n */\n sortTableDataAndUpdateHash(table: TableType): void {\n table._data.sort((a, b) => {\n const hashA = a._hash as string;\n const hashB = b._hash as string;\n /* v8 ignore next -- @preserve */\n if (hashA < hashB) {\n return -1;\n }\n /* v8 ignore next -- @preserve */\n if (hashA > hashB) {\n return 1;\n }\n\n /* v8 ignore next -- @preserve */\n return 0;\n });\n\n table._hash = '';\n hip(table, {\n updateExistingHashes: false,\n throwOnWrongHashes: false,\n });\n }\n}\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { hip, hsh } from '@rljson/hash';\nimport { IsReady } from '@rljson/is-ready';\nimport { copy, equals, JsonValue } from '@rljson/json';\nimport {\n ContentType,\n iterateTablesSync,\n Rljson,\n TableCfg,\n TableKey,\n TableType,\n validateRljsonAgainstTableCfg,\n} from '@rljson/rljson';\n\nimport { IoTools } from './io-tools.ts';\nimport { Io } from './io.ts';\n\n\n/**\n * In-Memory implementation of the Rljson Io interface.\n */\nexport class IoMem implements Io {\n // ...........................................................................\n // Constructor & example\n\n init(): Promise<void> {\n this._isOpen = true;\n return this._init();\n }\n\n close(): Promise<void> {\n this._isOpen = false;\n return Promise.resolve();\n }\n\n get isOpen(): boolean {\n return this._isOpen;\n }\n\n static example = async () => {\n const io = new IoMem();\n await io.init();\n return io;\n };\n\n // ...........................................................................\n // General\n isReady() {\n return this._isReady.promise;\n }\n\n // ...........................................................................\n // Dump\n\n dump(): Promise<Rljson> {\n return this._dump();\n }\n\n async dumpTable(request: { table: string }): Promise<Rljson> {\n return this._dumpTable(request);\n }\n\n // ...........................................................................\n // Meta Data\n\n async contentType(request: { table: string }): Promise<ContentType> {\n return this._contentType(request);\n }\n\n // ...........................................................................\n // Rows\n\n readRows(request: {\n table: string;\n where: { [column: string]: JsonValue };\n }): Promise<Rljson> {\n return this._readRows(request);\n }\n\n async rowCount(table: string): Promise<number> {\n const tableData = this._mem[table] as TableType;\n if (!tableData) {\n throw new Error(`Table \"${table}\" not found`);\n }\n return Promise.resolve(tableData._data.length);\n }\n\n // ...........................................................................\n // Write\n\n write(request: { data: Rljson }): Promise<void> {\n return this._write(request);\n }\n\n // ...........................................................................\n // Table management\n async tableExists(tableKey: TableKey): Promise<boolean> {\n const table = this._mem[tableKey] as TableType;\n return table ? true : false;\n }\n\n createOrExtendTable(request: { tableCfg: TableCfg }): Promise<void> {\n return this._createOrExtendTable(request);\n }\n\n async rawTableCfgs(): Promise<TableCfg[]> {\n const tables = this._mem.tableCfgs._data as TableCfg[];\n return tables;\n }\n\n // ######################\n // Private\n // ######################\n\n private _ioTools!: IoTools;\n\n private _isReady = new IsReady();\n private _isOpen = false;\n\n private _mem: Rljson = hip({} as Rljson);\n\n /**\n * Latest table configuration per table (the one with the most\n * columns). Kept in sync by _createTable/_extendTable so that reads\n * and writes need no repeated scan over all configurations.\n */\n private readonly _latestCfgs = new Map<TableKey, TableCfg>();\n\n /** Column key sets per table, derived from _latestCfgs */\n private readonly _columnKeys = new Map<TableKey, Set<string>>();\n\n /**\n * Per-table index of rows by content hash. Rows are only ever added,\n * never removed, so the index cannot go stale.\n */\n private readonly _rowIndex = new Map<TableKey, Map<string, any>>();\n\n /**\n * Tables whose table hash (and thus the global hash) is outdated\n * after writes. Hashes are refreshed lazily before they become\n * observable (dump, dumpTable, create/extend) instead of after every\n * single write — row hashes themselves are always up to date.\n */\n private readonly _dirtyTableHashes = new Set<TableKey>();\n\n // ...........................................................................\n /**\n * Recomputes the hashes of all dirty tables and the global hash.\n * Produces exactly the state an eager per-write update would have\n * produced (hashes are deterministic over the same data).\n */\n private _refreshHashes(): void {\n if (this._dirtyTableHashes.size === 0) {\n return;\n }\n\n for (const tableKey of this._dirtyTableHashes) {\n const table = this._mem[tableKey] as TableType;\n table._hash = '';\n hip(table, {\n updateExistingHashes: false,\n throwOnWrongHashes: false,\n });\n }\n this._dirtyTableHashes.clear();\n\n this._updateGlobalHash();\n }\n\n // ...........................................................................\n /**\n * Returns the row index of a table, building it lazily from the\n * table data on first access.\n * @param table - The table to index\n */\n private _rowIndexFor(table: TableKey): Map<string, any> {\n let index = this._rowIndex.get(table);\n if (!index) {\n index = new Map();\n const tableData = (this._mem[table] as TableType)._data;\n for (const row of tableData) {\n index.set(row._hash as string, row);\n }\n this._rowIndex.set(table, index);\n }\n return index;\n }\n\n // ...........................................................................\n /**\n * Inserts a row into hash-sorted table data at its sorted position —\n * preserves the order sortTableDataAndUpdateHash establishes without\n * a full re-sort.\n * @param data - The hash-sorted table data\n * @param row - The row to insert\n */\n private static _insertSortedByHash(data: any[], row: any): void {\n const hash = row._hash as string;\n let lo = 0;\n let hi = data.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if ((data[mid]._hash as string) < hash) {\n lo = mid + 1;\n } else {\n hi = mid;\n }\n }\n data.splice(lo, 0, row);\n }\n\n // ...........................................................................\n /**\n * The row filter predicate of readRows. Extracted so that the indexed\n * fast path and the full scan share identical semantics.\n * @param row - The row to check\n * @param where - The where clause\n */\n private static _rowMatchesWhere(\n row: any,\n where: { [column: string]: JsonValue },\n ): boolean {\n for (const column in where) {\n const a = row[column];\n const b = where[column];\n if (b === null && a === undefined) {\n return true;\n }\n\n if (!equals(a, b)) {\n return false;\n }\n }\n return true;\n }\n\n // ...........................................................................\n /**\n * Returns the latest table configuration, filling the cache lazily\n * from IoTools (which picks the config with the most columns).\n * @param table - The table to get the configuration for\n */\n private async _latestCfg(table: TableKey): Promise<TableCfg> {\n let cfg = this._latestCfgs.get(table);\n if (!cfg) {\n cfg = await this._ioTools.tableCfg(table);\n this._latestCfgs.set(table, cfg);\n }\n return cfg;\n }\n\n /**\n * Updates the cached latest configuration of a table\n * @param cfg - The new latest configuration\n */\n private _setLatestCfg(cfg: TableCfg): void {\n this._latestCfgs.set(cfg.key, cfg);\n this._columnKeys.set(cfg.key, new Set(cfg.columns.map((c) => c.key)));\n }\n\n /**\n * Throws when one of the given columns does not exist in the table.\n * Mirrors IoTools.throwWhenColumnDoesNotExist but uses the cached\n * configuration.\n * @param table - The table to check\n * @param columns - The columns to check\n */\n private async _throwWhenColumnDoesNotExist(\n table: TableKey,\n columns: string[],\n ): Promise<void> {\n let columnKeys = this._columnKeys.get(table);\n if (!columnKeys) {\n const cfg = await this._latestCfg(table);\n columnKeys = new Set(cfg.columns.map((c) => c.key));\n this._columnKeys.set(table, columnKeys);\n }\n\n const missingColumns = columns.filter((column) => !columnKeys.has(column));\n if (missingColumns.length > 0) {\n throw new Error(\n `The following columns do not exist in table \"${table}\": ${missingColumns.join(\n ', ',\n )}.`,\n );\n }\n }\n\n /**\n * Throws when the data does not match the table configurations.\n * Mirrors IoTools.throwWhenTableDataDoesNotMatchCfg but uses the\n * cached configurations.\n * @param data - The data to validate\n */\n private async _throwWhenTableDataDoesNotMatchCfg(\n data: Rljson,\n ): Promise<void> {\n const errors: string[] = [];\n\n for (const tableKey of Object.keys(data)) {\n const table = data[tableKey] as TableType;\n\n // Skip non-table values (like _hash) — mirrors iterateTables\n if (typeof table !== 'object' || !Array.isArray(table?._data)) continue;\n\n // Ignore tableCfgs table\n /* v8 ignore next -- @preserve */\n if (table._type === 'tableCfgs') continue;\n\n const tableCfg = await this._latestCfg(tableKey);\n errors.push(...validateRljsonAgainstTableCfg(table._data, tableCfg));\n }\n\n if (errors.length > 0) {\n throw new Error(\n `Table data does not match the configuration.\\n\\nErrors:\\n${errors\n .map((e) => `- ${e}`)\n .join('\\n')}`,\n );\n }\n }\n\n // ...........................................................................\n private async _init() {\n // Fold pending lazy hash updates — a re-init validates all hashes\n this._refreshHashes();\n\n // Reset caches — a re-init replaces the tableCfgs table, so cached\n // configs and indexes must be rebuilt\n this._rowIndex.clear();\n this._latestCfgs.clear();\n this._columnKeys.clear();\n\n this._ioTools = new IoTools(this);\n this._initTableCfgs();\n this._updateGlobalHash();\n await this._ioTools.initRevisionsTable();\n hsh(this._mem);\n\n this._isReady.resolve();\n }\n\n // ...........................................................................\n private _initTableCfgs = () => {\n const tableCfg = IoTools.tableCfgsTableCfg;\n\n this._mem.tableCfgs = hip({\n _type: 'tableCfgs',\n _data: [tableCfg],\n _tableCfg: tableCfg._hash as string,\n });\n };\n\n // ...........................................................................\n private _updateGlobalHash() {\n (this._mem as any)._hash = '';\n hip(this._mem, {\n updateExistingHashes: false,\n });\n }\n\n // ...........................................................................\n private _updateTableHash(tableKey: TableKey) {\n const table = this._mem[tableKey] as TableType;\n table._hash = '';\n hip(table, { updateExistingHashes: false });\n }\n\n // ...........................................................................\n private async _createOrExtendTable(request: {\n tableCfg: TableCfg;\n }): Promise<void> {\n // Fold pending lazy hash updates before the eager global hash\n // update of the create/extend paths\n this._refreshHashes();\n\n // Make sure that the table config is compatible\n // with an potential existing table\n const tableCfg = request.tableCfg;\n await this._ioTools.throwWhenTableIsNotCompatible(tableCfg);\n\n const { key } = tableCfg;\n\n // Recreate hashes in the case the existing hashes are wrong\n const newConfig = hsh(tableCfg);\n\n // Find an existing table config with the same hash\n const existingConfig = await this._ioTools.tableCfgOrNull(key);\n\n // Write the new config into the database\n if (!existingConfig) {\n this._createTable(newConfig, key);\n } else {\n this._extendTable(existingConfig, newConfig);\n }\n }\n\n // ...........................................................................\n private _createTable(newConfig: TableCfg, tableKey: TableKey) {\n // Write the table config into the database\n newConfig = hsh(newConfig);\n this._mem.tableCfgs._data.push(newConfig);\n this._ioTools.sortTableDataAndUpdateHash(this._mem.tableCfgs);\n this._setLatestCfg(newConfig);\n this._rowIndex.get('tableCfgs')?.set(newConfig._hash as string, newConfig);\n\n // Create a table and write it into the database\n const table: TableType = {\n _type: newConfig.type,\n _data: [],\n _tableCfg: newConfig._hash as string,\n };\n\n this._mem[tableKey] ??= hip(table);\n\n // Update hashes\n this._updateTableHash(tableKey);\n this._updateGlobalHash();\n }\n\n // ...........................................................................\n private _extendTable(existingConfig: TableCfg, newConfig: TableCfg) {\n // No columns added? Return.\n if (existingConfig.columns.length === newConfig.columns.length) {\n return;\n }\n\n // Write the new table config into the database\n newConfig = hsh(newConfig);\n this._mem.tableCfgs._data.push(newConfig);\n this._ioTools.sortTableDataAndUpdateHash(this._mem.tableCfgs);\n this._setLatestCfg(newConfig);\n this._rowIndex.get('tableCfgs')?.set(newConfig._hash as string, newConfig);\n\n // Update the config of the existing table\n const table = this._mem[newConfig.key] as TableType;\n table._tableCfg = newConfig._hash as string;\n\n // Update the hashes\n this._updateTableHash(newConfig.key);\n this._updateGlobalHash();\n }\n\n // ...........................................................................\n\n private async _dump(): Promise<Rljson> {\n this._refreshHashes();\n return copy(this._mem);\n }\n\n // ...........................................................................\n private async _dumpTable(request: { table: string }): Promise<Rljson> {\n await this._ioTools.throwWhenTableDoesNotExist(request.table);\n\n this._refreshHashes();\n const table = this._mem[request.table] as TableType;\n\n return {\n [request.table]: copy(table),\n };\n }\n\n // ...........................................................................\n private async _contentType(request: { table: string }): Promise<ContentType> {\n await this._ioTools.throwWhenTableDoesNotExist(request.table);\n\n return (this._mem[request.table] as TableType)._type;\n }\n\n // ...........................................................................\n private async _write(request: { data: Rljson }): Promise<void> {\n const addedData = hsh(request.data);\n const removedNullValues = this._removeNullValues(addedData);\n const tables = Object.keys(addedData);\n\n // Row hashes only change when null values were actually removed\n if (removedNullValues) {\n hsh(addedData);\n }\n\n await this._ioTools.throwWhenTablesDoNotExist(request.data);\n await this._throwWhenTableDataDoesNotMatchCfg(request.data);\n\n for (const table of tables) {\n if (table.startsWith('_')) {\n continue;\n }\n\n const oldTable = this._mem[table] as TableType;\n const newTable = addedData[table] as TableType;\n const rowIndex = this._rowIndexFor(table);\n\n // Table exists. Merge data — O(1) dedup via the row index and\n // sorted insert instead of a linear scan plus full re-sort\n for (const item of newTable._data) {\n const hash = item._hash as string;\n if (!rowIndex.has(hash)) {\n rowIndex.set(hash, item);\n IoMem._insertSortedByHash(oldTable._data, item);\n }\n }\n\n // Table and global hash are refreshed lazily before they become\n // observable — see _refreshHashes\n this._dirtyTableHashes.add(table);\n }\n }\n\n // ...........................................................................\n private async _readRows(request: {\n table: string;\n where: { [column: string]: JsonValue };\n }): Promise<Rljson> {\n await this._ioTools.throwWhenTableDoesNotExist(request.table);\n await this._throwWhenColumnDoesNotExist(\n request.table,\n Object.keys(request.where),\n );\n\n // Read table from data\n const table = this._mem[request.table] as TableType;\n\n // Filter table data. Lookups by content hash use the row index\n // instead of scanning the whole table.\n const whereHash = request.where['_hash'];\n let tableDataFiltered: any[];\n if (typeof whereHash === 'string') {\n const row = this._rowIndexFor(request.table).get(whereHash);\n tableDataFiltered =\n row && IoMem._rowMatchesWhere(row, request.where) ? [row] : [];\n } else {\n tableDataFiltered = table._data.filter((row) =>\n IoMem._rowMatchesWhere(row, request.where),\n );\n }\n\n // Create an table\n const tableFiltered: TableType = {\n _type: table._type,\n _data: tableDataFiltered,\n };\n\n this._ioTools.sortTableDataAndUpdateHash(tableFiltered);\n\n const result: Rljson = {\n [request.table]: tableFiltered,\n };\n\n return result;\n }\n\n _removeNullValues(rljson: Rljson): boolean {\n let removedAny = false;\n\n iterateTablesSync(rljson, (table) => {\n const data = rljson[table]._data;\n\n for (const row of data) {\n for (const key in row) {\n if (row[key] === null) {\n delete row[key];\n removedAny = true;\n }\n }\n }\n });\n\n return removedAny;\n }\n}\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { Io } from './io.ts';\nimport { Socket } from './socket.ts';\n\nexport class PeerSocketMock implements Socket {\n private _listenersMap: Map<string | symbol, Array<(...args: any[]) => void>> =\n new Map();\n\n connected: boolean = false;\n disconnected: boolean = true;\n\n constructor(private _io: Io) {}\n\n // ............................................................................\n /**\n * Removes a specific listener for the specified event.\n * @param eventName - The name of the event.\n * @param listener - The callback function to remove.\n * @returns The PeerSocketMock instance for chaining.\n */\n off(eventName: string | symbol, listener: (...args: any[]) => void): this {\n /* v8 ignore next -- @preserve */\n const listeners = this._listenersMap.get(eventName) || [];\n const index = listeners.indexOf(listener);\n /* v8 ignore else -- @preserve */\n if (index !== -1) {\n listeners.splice(index, 1);\n this._listenersMap.set(eventName, listeners);\n }\n return this;\n }\n\n // ............................................................................\n /**\n * Removes all listeners for the specified event, or all listeners if no event is specified.\n * @param eventName - (Optional) The name of the event.\n * @returns The PeerSocketMock instance for chaining.\n */\n removeAllListeners(eventName?: string | symbol): this {\n if (eventName) {\n this._listenersMap.delete(eventName);\n } else {\n this._listenersMap.clear();\n }\n return this;\n }\n\n // ............................................................................\n /**\n * Registers an event listener for the specified event.\n * @param eventName - The name of the event to listen for.\n * @param listener - The callback function to invoke when the event is emitted.\n * @returns The PeerSocketMock instance for chaining.\n */\n on(eventName: string | symbol, listener: (...args: any[]) => void): this {\n if (!this._listenersMap.has(eventName)) {\n this._listenersMap.set(eventName, []);\n }\n this._listenersMap.get(eventName)!.push(listener);\n return this;\n }\n\n // ...........................................................................\n /**\n * Simulates a connection event.\n *\n * Emits the 'connect' event to all registered listeners.\n */\n connect(): void {\n this.connected = true;\n this.disconnected = false;\n\n const listeners = this._listenersMap.get('connect') || [];\n for (const cb of listeners) {\n cb({});\n }\n }\n\n // ...........................................................................\n /**\n * Simulates a disconnection event.\n *\n * Emits the 'disconnect' event to all registered listeners.\n */\n disconnect(): void {\n this.connected = false;\n this.disconnected = true;\n\n const listeners = this._listenersMap.get('disconnect') || [];\n for (const cb of listeners) {\n cb({});\n }\n }\n\n // ............................................................................\n /**\n * Emits an event, invoking the corresponding method on the Io instance.\n * @param eventName - The name of the event to emit.\n * @param args - The arguments to pass to the event listener.\n * @returns\n */\n emit(eventName: string | symbol, ...args: any[]): boolean {\n const fn = (this._io as any)[eventName] as (...args: any[]) => Promise<any>;\n if (typeof fn !== 'function') {\n throw new Error(`Event ${eventName.toString()} not supported`);\n }\n const cb = args[args.length - 1];\n fn.apply(this._io, args.slice(0, -1))\n .then((result) => {\n cb(result, null);\n })\n .catch((err) => {\n cb(null, err);\n });\n\n return true;\n }\n}\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { JsonValue } from '@rljson/json';\nimport { ContentType, Rljson, TableCfg, TableKey } from '@rljson/rljson';\n\nimport { IoMem } from './io-mem.ts';\nimport { Io } from './io.ts';\nimport { PeerSocketMock } from './peer-socket-mock.ts';\nimport { Socket } from './socket.ts';\n\n\nexport class IoPeer implements Io {\n isOpen: boolean = false;\n\n constructor(\n private _socket: Socket,\n private _requestTimeoutMs: number = 30_000,\n ) {}\n\n // ...........................................................................\n /**\n * Wraps a promise with a timeout. If the promise does not settle within\n * `_requestTimeoutMs`, the returned promise rejects with a timeout error.\n * Clears the timer on settlement to avoid leaks and unhandled rejections.\n */\n private _withTimeout<T>(promise: Promise<T>, operation: string): Promise<T> {\n if (this._requestTimeoutMs <= 0) return promise;\n let timer: ReturnType<typeof setTimeout>;\n const timeoutPromise = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n reject(\n new Error(\n `Timeout after ${this._requestTimeoutMs}ms: ${operation}`,\n ),\n );\n }, this._requestTimeoutMs);\n });\n return Promise.race([promise, timeoutPromise]).finally(() => {\n clearTimeout(timer!);\n });\n }\n\n // ...........................................................................\n /**\n *\n * Initializes the Peer connection.\n * @returns\n */\n async init(): Promise<void> {\n // Update isOpen on connect/disconnect\n this._socket.on('connect', () => {\n this.isOpen = true;\n });\n this._socket.on('disconnect', () => {\n this.isOpen = false;\n });\n\n // Connect the socket\n this._socket.connect();\n\n // Wait for the socket to connect before returning\n return new Promise<void>((resolve) => {\n /* v8 ignore else -- @preserve */\n if (this._socket.connected) {\n this.isOpen = true;\n resolve();\n } else {\n this._socket.on('connect', () => {\n resolve();\n });\n }\n });\n }\n\n // ...........................................................................\n /**\n * Closes the Peer connection.\n * @returns\n */\n\n async close(): Promise<void> {\n // Disconnect the socket and wait for it to complete\n if (!this._socket.connected) return;\n\n return new Promise<void>((resolve) => {\n this._socket.on('disconnect', () => {\n resolve();\n });\n this._socket.disconnect();\n });\n }\n\n // ...........................................................................\n /**\n * Returns a promise that resolves once the Peer connection is ready.\n * @returns\n */\n async isReady(): Promise<void> {\n if (!!this._socket && this._socket.connected === true) this.isOpen = true;\n else this.isOpen = false;\n\n return !!this.isOpen ? Promise.resolve() : Promise.reject();\n }\n\n // ...........................................................................\n /**\n * Dumps the entire database content.\n * @returns A promise that resolves to the dumped database content.\n */\n async dump(): Promise<Rljson> {\n return this._withTimeout(\n new Promise((resolve) => {\n // Request dump, resolve once the data is received (ack)\n this._socket.emit('dump', (data: Rljson) => {\n resolve(data);\n });\n }),\n 'dump',\n );\n }\n\n // ...........................................................................\n /**\n * Dumps a specific table from the database.\n * @param request An object containing the table name to dump.\n * @returns A promise that resolves to the dumped table data.\n */\n dumpTable(request: { table: string }): Promise<Rljson> {\n return this._withTimeout(\n new Promise((resolve, reject) => {\n // Request dumpTable, resolve once the data is received (ack)\n this._socket.emit(\n 'dumpTable',\n request,\n (data: Rljson, error?: Error) => {\n if (error) reject(error);\n resolve(data);\n },\n );\n }),\n 'dumpTable',\n );\n }\n\n // ...........................................................................\n /**\n * Gets the content type of a specific table.\n * @param request An object containing the table name to get the content type for.\n * @returns A promise that resolves to the content type of the specified table.\n */\n contentType(request: { table: string }): Promise<ContentType> {\n return this._withTimeout(\n new Promise((resolve, reject) => {\n // Request contentType, resolve once the data is received (ack)\n this._socket.emit(\n 'contentType',\n request,\n (data: ContentType, error?: Error) => {\n /* v8 ignore next -- @preserve */\n if (error) reject(error);\n resolve(data);\n },\n );\n }),\n 'contentType',\n );\n }\n\n // ...........................................................................\n /**\n * Checks if a specific table exists in the database.\n * @param tableKey The key of the table to check for existence.\n * @returns A promise that resolves to true if the table exists, false otherwise.\n */\n tableExists(tableKey: TableKey): Promise<boolean> {\n return this._withTimeout(\n new Promise((resolve) => {\n // Request tableExists, resolve once the data is received (ack)\n this._socket.emit('tableExists', tableKey, (exists: boolean) => {\n resolve(exists);\n });\n }),\n 'tableExists',\n );\n }\n\n // ...........................................................................\n /**\n * Creates or extends a table with the given configuration.\n * @param request An object containing the table configuration.\n * @returns A promise that resolves once the table is created or extended.\n */\n createOrExtendTable(request: { tableCfg: TableCfg }): Promise<void> {\n return this._withTimeout(\n new Promise((resolve, reject) => {\n // Request createOrExtendTable, resolve once the data is received (ack)\n this._socket.emit(\n 'createOrExtendTable',\n request,\n (_?: boolean, error?: Error) => {\n if (error) reject(error);\n resolve();\n },\n );\n }),\n 'createOrExtendTable',\n );\n }\n\n // ...........................................................................\n /**\n * Retrieves the raw table configurations from the database.\n * @returns A promise that resolves to an array of table configurations.\n */\n rawTableCfgs(): Promise<TableCfg[]> {\n return this._withTimeout(\n new Promise((resolve) => {\n // Request rawTableCfgs, resolve once the data is received (ack)\n this._socket.emit('rawTableCfgs', (data: TableCfg[]) => {\n resolve(data);\n });\n }),\n 'rawTableCfgs',\n );\n }\n\n // ...........................................................................\n /**\n * Writes data to the database.\n * @param request An object containing the data to write.\n * @returns A promise that resolves once the data is written.\n */\n write(request: { data: Rljson }): Promise<void> {\n return this._withTimeout(\n new Promise((resolve, reject) => {\n // Request write, resolve once the data is received (ack)\n this._socket.emit('write', request, (_?: boolean, error?: Error) => {\n if (error) reject(error);\n resolve();\n });\n }),\n 'write',\n );\n }\n\n // ...........................................................................\n /**\n * Reads rows from a specific table that match the given criteria.\n * @param request An object containing the table name and the criteria for selecting rows.\n * @returns A promise that resolves to the selected rows.\n */\n readRows(request: {\n table: string;\n where: { [column: string]: JsonValue | null };\n }): Promise<Rljson> {\n return this._withTimeout(\n new Promise((resolve, reject) => {\n // Request readRows, resolve once the data is received (ack)\n this._socket.emit(\n 'readRows',\n request,\n (result?: Rljson, error?: Error) => {\n if (error) reject(error);\n resolve(result!);\n },\n );\n }),\n 'readRows',\n );\n }\n\n // ...........................................................................\n /**\n * Retrieves the number of rows in a specific table.\n * @param table The name of the table to count rows in.\n * @returns A promise that resolves to the number of rows in the specified table.\n */\n rowCount(table: string): Promise<number> {\n return this._withTimeout(\n new Promise((resolve, reject) => {\n // Request rowCount, resolve once the data is received (ack)\n this._socket.emit(\n 'rowCount',\n table,\n (count?: number, error?: Error) => {\n if (error) reject(error);\n resolve(count!);\n },\n );\n }),\n 'rowCount',\n );\n }\n\n // ...........................................................................\n static example = async () => {\n const ioMem = await IoMem.example();\n const socket = new PeerSocketMock(ioMem);\n const io = new IoPeer(socket);\n await io.init();\n return io;\n };\n}\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { hip } from '@rljson/hash';\nimport { Json, JsonValue, merge } from '@rljson/json';\nimport { ContentType, Rljson, RljsonTable, TableCfg, TableKey, TableType } from '@rljson/rljson';\n\nimport { IoMem } from './io-mem.ts';\nimport { IoPeer } from './io-peer.ts';\nimport { Io } from './io.ts';\nimport { PeerSocketMock } from './peer-socket-mock.ts';\n\n\n// ...........................................................................\n/**\n * Type representing an Io instance along with its capabilities and priority.\n */\nexport type IoMultiIo = {\n io: Io;\n id?: string;\n priority: number;\n read: boolean;\n write: boolean;\n dump: boolean;\n};\n\n// ...........................................................................\n/**\n * Multi Io implementation that combines multiple underlying Io instances\n * with different capabilities (read, write, dump) and priorities.\n */\nexport class IoMulti implements Io {\n isOpen: boolean = false;\n\n constructor(private _ios: Array<IoMultiIo>) {}\n\n // ...........................................................................\n /**\n *\n * Initializes all underlying Io instances.\n * @returns\n */\n async init(): Promise<void> {\n for (let idx = 0; idx < this._ios.length; idx++) {\n const { io } = this._ios[idx];\n if (io.isOpen === false) {\n throw new Error(\n 'All underlying Io instances must be initialized before initializing IoMulti',\n );\n }\n\n this._ios[idx] = { ...this._ios[idx], id: `io-${idx}` };\n }\n\n this.isOpen = true;\n return Promise.resolve();\n }\n\n // ...........................................................................\n /**\n * Closes all underlying Io instances.\n * @returns\n */\n async close(): Promise<void> {\n await Promise.all(this._ios.map((ioMultiIo) => ioMultiIo.io.close()));\n\n this.isOpen = false;\n\n return Promise.resolve();\n }\n\n // ...........................................................................\n /**\n * Returns a promise that resolves once all underlying Io instances are ready.\n * @returns\n */\n isReady(): Promise<void> {\n return Promise.all(\n this._ios.map((ioMultiIo) => ioMultiIo.io.isReady()),\n ).then(() => Promise.resolve());\n }\n\n // ...........................................................................\n /**\n * Dumps the entire database content by merging dumps from all dumpable underlying Io instances.\n * @returns\n */\n async dump(): Promise<Rljson> {\n /* v8 ignore next -- @preserve */\n if (this.dumpables.length === 0) {\n throw new Error('No dumpable Io available');\n }\n\n const dumps = await Promise.all(\n this.dumpables.map(({ io: dumpable }) => dumpable.dump()),\n );\n\n return merge(...dumps) as Rljson;\n }\n\n // ...........................................................................\n /**\n * Dumps a specific table by merging dumps from all dumpable underlying Io instances that contain the table.\n * @param request An object containing the table name to dump.\n * @returns A promise that resolves to the dumped table data.\n */\n async dumpTable(request: { table: string }): Promise<Rljson> {\n /* v8 ignore next -- @preserve */\n if (this.dumpables.length === 0) {\n throw new Error('No dumpable Io available');\n }\n\n const dumps: Rljson[] = [];\n\n for (const { io: dumpable } of this.dumpables) {\n try {\n const dump = await dumpable.dumpTable(request);\n dumps.push(dump);\n } catch {\n continue; // Table does not exist in this dumpable Io\n }\n }\n\n if (dumps.length === 0) {\n throw new Error(`Table \"${request.table}\" not found`);\n }\n\n return merge(...dumps) as Rljson;\n }\n\n // ...........................................................................\n /**\n * Retrieves the content type of a specific table from the first underlying readable Io instance that contains the table.\n * @param request An object containing the table name.\n * @returns A promise that resolves to the content type of the table.\n */\n async contentType(request: { table: string }): Promise<ContentType> {\n /* v8 ignore next -- @preserve */\n if (this.readables.length === 0) {\n throw new Error('No readable Io available');\n }\n\n for (const { io: readable } of this.readables) {\n return readable.contentType(request);\n }\n /* v8 ignore next -- @preserve */\n throw new Error(`Table \"${request.table}\" not found`);\n }\n\n // ...........................................................................\n /**\n * Checks if a specific table exists in any of the underlying readable Io\n * instances. Readables at the same priority level are queried in parallel\n * so that one slow peer does not block others.\n * @param tableKey The key of the table to check.\n * @returns A promise that resolves to true if the table exists in any readable Io, false otherwise.\n */\n async tableExists(tableKey: TableKey): Promise<boolean> {\n /* v8 ignore next -- @preserve */\n if (this.readables.length === 0) {\n throw new Error('No readable Io available');\n }\n\n const groups = IoMulti._groupByPriority(this.readables);\n for (const group of groups) {\n if (group.length === 1) {\n const exists = await group[0].io.tableExists(tableKey);\n if (exists) return true;\n } else {\n const results = await Promise.allSettled(\n group.map((r) => r.io.tableExists(tableKey)),\n );\n for (const result of results) {\n if (result.status === 'fulfilled' && result.value) return true;\n }\n }\n }\n return false;\n }\n\n // ...........................................................................\n /**\n * Creates or extends a table in all underlying writable Io instances.\n * @param request An object containing the table configuration.\n * @returns A promise that resolves once the table has been created or extended in all writable Io instances.\n */\n createOrExtendTable(request: { tableCfg: TableCfg }): Promise<void> {\n /* v8 ignore next -- @preserve */\n if (this.writables.length === 0) {\n throw new Error('No writable Io available');\n }\n //Create or extend table in all writables in parallel and resolve when all have completed\n const creations = this.writables.map(({ io: writable }) =>\n writable.createOrExtendTable(request),\n );\n return Promise.all(creations).then(() => Promise.resolve());\n }\n\n // ...........................................................................\n /**\n * Retrieves the raw table configurations from the highest priority underlying\n * readable Io instance that has any. Stops after the first readable that\n * returns results — this avoids expensive network round-trips to lower-\n * priority peers when the local cache (IoMem, priority 1) already has the\n * answer.\n * @returns A promise that resolves to an array of table configurations.\n */\n async rawTableCfgs(): Promise<TableCfg[]> {\n /* v8 ignore next -- @preserve */\n if (this.readables.length === 0) {\n throw new Error('No readable Io available');\n }\n\n const rawTableCfgs: Map<string, TableCfg> = new Map();\n for (const { io: readable } of this.readables) {\n const cfgs = await readable.rawTableCfgs();\n /* v8 ignore else -- @preserve */\n if (cfgs.length > 0) {\n for (const tableCfg of cfgs) {\n if (!rawTableCfgs.has(tableCfg.key)) {\n rawTableCfgs.set(tableCfg.key, tableCfg);\n }\n }\n break; // Stop after the first readable that has table configs\n }\n }\n return Array.from(rawTableCfgs.values());\n }\n\n // ...........................................................................\n /**\n * Writes data to all underlying writable Io instances.\n * @param request - An object containing the data to write.\n * @returns A promise that resolves once the data has been written to all writable Io instances.\n */\n write(request: { data: Rljson }): Promise<void> {\n /* v8 ignore next -- @preserve */\n if (this.writables.length === 0) {\n throw new Error('No writable Io available');\n }\n\n // Write to all writables in parallel and resolve when all have completed\n const writes = this.writables.map(({ io: writable }) =>\n writable.write(request),\n );\n return Promise.all(writes).then(() => Promise.resolve());\n }\n\n // ...........................................................................\n /**\n * Reads rows from a specific table. Readables are grouped by priority:\n * priorities are tried in ascending order. Within a priority group,\n * all readables are queried **in parallel** — only the first one to\n * return rows wins. This prevents one slow/stale peer from blocking\n * others at the same priority level.\n *\n * @param request An object containing the table name and where clause.\n * @returns A promise that resolves to the read rows.\n */\n async readRows(request: {\n table: string;\n where: { [column: string]: JsonValue | null };\n }): Promise<Rljson> {\n /* v8 ignore next -- @preserve */\n if (this.readables.length === 0) {\n throw new Error('No readable Io available');\n }\n\n let tableExistsAny = false;\n const rows: Map<string, Json> = new Map();\n let type: ContentType | undefined = undefined;\n let readFrom: string = '';\n\n const errors: Error[] = [];\n\n // Group readables by priority (already sorted by priority)\n const groups = IoMulti._groupByPriority(this.readables);\n\n for (const group of groups) {\n if (group.length === 1) {\n // Single readable at this priority — query directly (no race overhead)\n const readable = group[0];\n try {\n const { [request.table]: tableData } = await readable.io.readRows(\n request,\n );\n const tableRows = (tableData as RljsonTable<Json, ContentType>)\n ._data;\n const tableType = (tableData as RljsonTable<Json, ContentType>)\n ._type;\n tableExistsAny = true;\n type ??= tableType;\n\n if (tableRows.length > 0) {\n /* v8 ignore next -- @preserve */\n readFrom = readable.id ?? '';\n /* v8 ignore else -- @preserve */\n for (const tableRow of tableRows) {\n const ref = tableRow._hash as string;\n rows.set(ref, tableRow);\n }\n break; // Got rows — done\n }\n } catch (e) {\n errors.push(e as Error);\n }\n } else {\n // Multiple readables at the same priority — race them in parallel.\n // Collect all settled results and pick the first with rows.\n const results = await Promise.allSettled(\n group.map(async (readable) => {\n const { [request.table]: tableData } = await readable.io.readRows(\n request,\n );\n return {\n readable,\n tableRows: (tableData as RljsonTable<Json, ContentType>)._data,\n tableType: (tableData as RljsonTable<Json, ContentType>)._type,\n };\n }),\n );\n\n let foundRows = false;\n for (const result of results) {\n if (result.status === 'rejected') {\n errors.push(result.reason as Error);\n continue;\n }\n tableExistsAny = true;\n const { readable, tableRows, tableType } = result.value;\n type ??= tableType;\n if (tableRows.length > 0 && !foundRows) {\n foundRows = true;\n readFrom = readable.id ?? '';\n /* v8 ignore else -- @preserve */\n for (const tableRow of tableRows) {\n const ref = tableRow._hash as string;\n rows.set(ref, tableRow);\n }\n }\n }\n\n if (foundRows) break; // Got rows — done\n }\n }\n\n if (!tableExistsAny) {\n /* v8 ignore if -- @preserve */\n if (errors.length === 0) {\n throw new Error(`Table \"${request.table}\" not found`);\n } else {\n const preciseErrors = errors.filter(\n (err) => !err.message.includes(`Table \"${request.table}\" not found`),\n );\n if (preciseErrors.length > 0) {\n throw preciseErrors[0];\n } else {\n throw errors[0];\n }\n }\n } else {\n const rljson = {\n [request.table]: hip({ _data: Array.from(rows.values()), _type: type }),\n } as Rljson;\n\n // Write merged rows back to all writables (hot-swapping cache)\n if (this.writables.length > 0 && rows.size > 0) {\n for (const writeable of this.writables) {\n if (writeable.id === readFrom) {\n continue; // Skip writing back to the source readable Io\n }\n /* v8 ignore next -- @preserve */\n try {\n await writeable.io.write({\n data: rljson,\n });\n } catch {\n continue; // Table does not exist in this writable Io\n }\n }\n }\n\n // Return merged rows\n return rljson;\n }\n }\n\n // ...........................................................................\n /**\n * Retrieves the row count of a specific table by aggregating row counts from all dumpable underlying Io instances.\n * @param table The name of the table.\n * @returns A promise that resolves to the row count of the table.\n */\n async rowCount(table: string): Promise<number> {\n /* v8 ignore next -- @preserve */\n if (this.dumpables.length === 0) {\n throw new Error('No dumpable Io available');\n }\n\n const dumpTable = await this.dumpTable({ table });\n const tableData: TableType = dumpTable[table];\n /* v8 ignore next -- @preserve */\n if (!tableData) {\n throw new Error(`Table \"${table}\" not found`);\n }\n return Promise.resolve(tableData._data.length);\n }\n\n // ...........................................................................\n /**\n * Gets the list of underlying readable Io instances, sorted by priority.\n */\n get readables(): Array<IoMultiIo> {\n return this._ios\n .filter((ioMultiIo) => ioMultiIo.read)\n .sort((a, b) => a.priority - b.priority);\n }\n\n // ...........................................................................\n /**\n * Gets the list of underlying writable Io instances, sorted by priority.\n */\n get writables(): Array<IoMultiIo> {\n return this._ios\n .filter((ioMultiIo) => ioMultiIo.write)\n .sort((a, b) => a.priority - b.priority);\n }\n\n // ...........................................................................\n /**\n * Gets the list of underlying dumpable Io instances, sorted by priority.\n */\n get dumpables(): Array<IoMultiIo> {\n return this._ios\n .filter((ioMultiIo) => ioMultiIo.dump)\n .sort((a, b) => a.priority - b.priority);\n }\n\n // ...........................................................................\n /**\n * Groups IoMultiIo entries by their priority value.\n * Input must already be sorted by priority (ascending).\n * Returns an array of groups, each group containing entries with the same\n * priority.\n */\n static _groupByPriority(ios: Array<IoMultiIo>): Array<Array<IoMultiIo>> {\n const groups: Array<Array<IoMultiIo>> = [];\n let current: Array<IoMultiIo> = [];\n let currentPriority: number | null = null;\n\n for (const io of ios) {\n if (io.priority !== currentPriority) {\n if (current.length > 0) groups.push(current);\n current = [io];\n currentPriority = io.priority;\n } else {\n current.push(io);\n }\n }\n if (current.length > 0) groups.push(current);\n\n return groups;\n }\n\n // ...........................................................................\n static example = async () => {\n const ioPeerMem = await IoMem.example();\n await ioPeerMem.init();\n\n const ioPeerSocket = new PeerSocketMock(ioPeerMem);\n const ioPeer = new IoPeer(ioPeerSocket);\n await ioPeer.init();\n\n const ioMem = await IoMem.example();\n await ioMem.init();\n\n const ios: Array<IoMultiIo> = [\n { io: ioPeer, priority: 1, read: true, write: false, dump: false },\n { io: ioMem, priority: 0, read: true, write: true, dump: true },\n ];\n\n const ioMulti = new IoMulti(ios);\n await ioMulti.init();\n\n return ioMulti;\n };\n}\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { Io } from './io.ts';\nimport { Socket } from './socket.ts';\n\n\n/**\n * Bridges Socket events to Io method calls.\n *\n * This class listens to socket events and translates them into corresponding\n * Io method calls, automatically registering all Io interface methods.\n */\nexport class IoPeerBridge {\n private _eventHandlers: Map<string | symbol, (...args: any[]) => void> =\n new Map();\n\n constructor(private _io: Io, private _socket: Socket) {}\n\n /**\n * Starts the bridge by setting up connection event handlers and\n * automatically registering all Io methods.\n */\n start(): void {\n this._socket.on('connect', () => this._handleConnect());\n this._socket.on('disconnect', () => this._handleDisconnect());\n\n // Automatically register all Io interface methods\n this._registerIoMethods();\n }\n\n /**\n * Stops the bridge by removing all event handlers.\n */\n stop(): void {\n /* v8 ignore next -- @preserve */\n this._socket.off('connect', () => this._handleConnect());\n /* v8 ignore next -- @preserve */\n this._socket.off('disconnect', () => this._handleDisconnect());\n\n for (const [eventName, handler] of this._eventHandlers) {\n this._socket.off(eventName, handler);\n }\n this._eventHandlers.clear();\n }\n\n /**\n * Automatically registers all Io interface methods as socket event handlers.\n */\n private _registerIoMethods(): void {\n // Core Io interface methods\n const ioMethods = [\n 'init',\n 'isReady',\n 'close',\n 'tableExists',\n 'createOrExtendTable',\n 'write',\n 'readRows',\n 'rowCount',\n 'dumpTable',\n 'dump',\n 'contentType',\n 'rawTableCfgs',\n ];\n\n for (const methodName of ioMethods) {\n this.registerEvent(methodName);\n }\n }\n\n /**\n * Registers a socket event to be translated to an Io method call.\n *\n * @param eventName - The socket event name (should match an Io method name)\n * @param ioMethodName - (Optional) The Io method name if different from eventName\n */\n registerEvent(eventName: string, ioMethodName?: string): void {\n const methodName = ioMethodName || eventName;\n\n /* v8 ignore next -- @preserve */\n const handler = (...args: any[]) => {\n // The last argument is expected to be a callback function\n const callback = args[args.length - 1];\n const methodArgs = args.slice(0, -1);\n\n // Get the Io method\n const ioMethod = (this._io as any)[methodName];\n\n /* v8 ignore next -- @preserve */\n if (typeof ioMethod !== 'function') {\n const error = new Error(\n `Method \"${methodName}\" not found on Io instance`,\n );\n if (typeof callback === 'function') {\n callback(null, error);\n }\n return;\n }\n\n // Call the Io method and handle the response\n /* v8 ignore next -- @preserve */\n ioMethod\n .apply(this._io, methodArgs)\n .then((result: any) => {\n if (typeof callback === 'function') {\n // Call callback with just the result (no error parameter when successful)\n callback(result, null); // Two arguments\n }\n })\n .catch((error: any) => {\n if (typeof callback === 'function') {\n // For errors, send null as result and error as second parameter\n callback(null, error); // Two arguments\n }\n });\n };\n\n this._eventHandlers.set(eventName, handler);\n this._socket.on(eventName, handler);\n }\n\n /**\n * Registers multiple socket events at once.\n *\n * @param eventNames - Array of event names to register\n */\n registerEvents(eventNames: string[]): void {\n for (const eventName of eventNames) {\n this.registerEvent(eventName);\n }\n }\n\n /**\n * Unregisters a socket event handler.\n *\n * @param eventName - The event name to unregister\n */\n unregisterEvent(eventName: string | symbol): void {\n const handler = this._eventHandlers.get(eventName);\n if (handler) {\n this._socket.off(eventName, handler);\n this._eventHandlers.delete(eventName);\n }\n }\n\n /**\n * Emits a result back through the socket.\n *\n * @param eventName - The event name to emit\n * @param data - The data to send\n */\n emitToSocket(eventName: string | symbol, ...data: any[]): void {\n this._socket.emit(eventName, ...data);\n }\n\n /**\n * Calls an Io method directly and emits the result through the socket.\n *\n * @param ioMethodName - The Io method to call\n * @param socketEventName - The socket event to emit with the result\n * @param args - Arguments to pass to the Io method\n */\n async callIoAndEmit(\n ioMethodName: string,\n socketEventName: string | symbol,\n ...args: any[]\n ): Promise<void> {\n try {\n const ioMethod = (this._io as any)[ioMethodName];\n\n if (typeof ioMethod !== 'function') {\n throw new Error(`Method \"${ioMethodName}\" not found on Io instance`);\n }\n\n const result = await ioMethod.apply(this._io, args);\n this._socket.emit(socketEventName, result, null);\n } catch (error) {\n this._socket.emit(socketEventName, null, error);\n }\n }\n\n /* v8 ignore next -- @preserve */\n private _handleConnect(): void {\n // Override this method in subclasses to handle connection events\n }\n\n /* v8 ignore next -- @preserve */\n private _handleDisconnect(): void {\n // Override this method in subclasses to handle disconnection events\n }\n\n /**\n * Gets the current socket instance.\n */\n get socket(): Socket {\n return this._socket;\n }\n\n /**\n * Gets the current Io instance.\n */\n get io(): Io {\n return this._io;\n }\n\n /**\n * Returns whether the socket is currently connected.\n */\n get isConnected(): boolean {\n return this._socket.connected;\n }\n}\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { JsonValue } from '@rljson/json';\nimport { Rljson, TableCfg, TableKey } from '@rljson/rljson';\n\nimport { Io } from './io.ts';\nimport { Socket } from './socket.ts';\n\n\nexport class IoServer {\n private _sockets: Socket[] = [];\n\n constructor(private _io: Io) {}\n\n // ...........................................................................\n /**\n * Adds a socket to the IoServer instance.\n * @param socket - The socket to add.\n */\n async addSocket(socket: Socket): Promise<void> {\n // Add transport layer to the socket\n await this._addTransportLayer(socket);\n\n // Add socket to the list of sockets\n this._sockets.push(socket);\n }\n\n // ...........................................................................\n /**\n * Removes a transport layer from the given socket.\n * @param socket - The socket to remove the transport layer from.\n */\n removeSocket(socket: Socket): void {\n this._sockets = this._sockets.filter((s) => s !== socket);\n }\n\n // ...........................................................................\n /**\n * Adds a transport layer to the given socket.\n * @param socket - The socket to add the transport layer to.\n */\n private async _addTransportLayer(socket: Socket): Promise<void> {\n // CRUD operations — use arrow functions that read this._io at call time,\n // so that when _io is replaced (e.g. after _rebuildMultis), existing\n // socket handlers automatically use the latest Io instance.\n const crud = this._generateTransportLayerCRUD();\n for (const [key, fn] of Object.entries(crud)) {\n socket.on(key, (...args: any[]) => {\n const cb = args[args.length - 1];\n\n fn.apply(this, args.slice(0, -1))\n .then((result) => {\n cb(result, null);\n })\n .catch((err) => {\n cb(null, err);\n });\n });\n }\n }\n\n // ...........................................................................\n /**\n * Creates or extends a table with the given configuration.\n * @param request - An object containing the table configuration.\n */\n private async createOrExtendTable(request: {\n tableCfg: TableCfg;\n }): Promise<void> {\n return this._io.createOrExtendTable(request);\n }\n\n // ...........................................................................\n /**\n * Generates a transport layer object that always delegates to the current\n * this._io. Each method is an arrow function reading this._io at call\n * time so that external code can replace _io after construction and all\n * existing socket handlers pick up the new instance.\n */\n private _generateTransportLayerCRUD = () =>\n ({\n init: () => this._io.init(),\n close: () => this._io.close(),\n isOpen: () =>\n new Promise((resolve) => resolve(this._io.isOpen)) as Promise<boolean>,\n isReady: () => this._io.isReady(),\n dump: () => this._io.dump(),\n dumpTable: (request: { table: string }) => this._io.dumpTable(request),\n contentType: (request: { table: string }) =>\n this._io.contentType(request),\n tableExists: (tableKey: TableKey) => this._io.tableExists(tableKey),\n createOrExtendTable: (request: { tableCfg: TableCfg }) =>\n this.createOrExtendTable(request),\n rawTableCfgs: () => this._io.rawTableCfgs(),\n write: (request: { data: Rljson }) => this._io.write(request),\n readRows: (request: {\n table: string;\n where: { [column: string]: JsonValue | null };\n }) => this._io.readRows(request),\n rowCount: (table: string) => this._io.rowCount(table),\n } as { [key: string]: (...args: any[]) => Promise<any> });\n}\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { Io, IoMem } from './index.ts';\n\n// .............................................................................\n/**\n * Io implementation need to implement this interface to be used in\n * conformance tests.\n */\nexport interface IoTestSetup {\n /** setup before the single setups */\n beforeAll: () => Promise<void>;\n\n /**\n * Initializes the io implementation.\n * @returns The io implementation.\n */\n beforeEach: () => Promise<void>;\n\n /**\n * Tears down the io implementation.\n * @returns The io implementation.\n */\n afterEach: () => Promise<void>;\n\n /** cleanup after all tests */\n afterAll: () => Promise<void>;\n\n /**\n * The io implementation to be used in the conformance tests.\n */\n io: Io;\n}\n\n// .............................................................................\n// Example implementation of the IoTestSetup interface\nexport const exampleTestSetup = (): IoTestSetup => {\n return {\n io: new IoMem(),\n beforeAll: async () => {\n // This method can be used for any additional setup required before init.\n // Currently, it does nothing.\n },\n\n beforeEach: async () => {\n // Initialize the io implementation\n },\n afterEach: async () => {\n // Tear down the io implementation\n },\n\n afterAll: async () => {\n // This method can be used for any additional cleanup after tearDown.\n },\n };\n};\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { JsonValue } from '@rljson/json';\nimport { ContentType, Rljson, TableCfg, TableKey } from '@rljson/rljson';\n\n\n// .............................................................................\nexport interface Io {\n // ...........................................................................\n // General\n\n /** Starts the initialization */\n init(): Promise<void>;\n\n /** Closes the io */\n close(): Promise<void>;\n\n /** Returns true if io is opened */\n isOpen: boolean;\n\n /** A promise resolving once the Io interface is ready\n *\n * 💡 Use @rljson/is-ready\n */\n isReady(): Promise<void>;\n\n // ...........................................................................\n // Dump\n\n /** Returns the complete db content as Rljson */\n dump(): Promise<Rljson>;\n\n /** Returns the dump of a complete table */\n dumpTable(request: { table: string }): Promise<Rljson>;\n\n // ...........................................................................\n // Meta Data\n contentType(request: { table: string }): Promise<ContentType>;\n\n // ...........................................................................\n // Tables\n\n /**\n * Returns true if the table exists\n */\n tableExists(tableKey: TableKey): Promise<boolean>;\n\n /**\n * Creates a table with a given config.\n * If the table already exists, new columns are added to the existing table.\n * If the table does not exist, it is created with the given config.\n * If the table exists and columns are removed, an error is thrown.\n * If the table exists and the column type is changed, an error is thrown.\n */\n createOrExtendTable(request: { tableCfg: TableCfg }): Promise<void>;\n\n /**\n * Returns a json structure returning current table configurations\n */\n rawTableCfgs(): Promise<TableCfg[]>;\n\n // ...........................................................................\n // Write\n\n /** Writes Rljson data into the database */\n write(request: { data: Rljson }): Promise<void>;\n\n // ...........................................................................\n // Read rows\n\n /** Queries a list of rows */\n readRows(request: {\n table: string;\n where: { [column: string]: JsonValue | null };\n }): Promise<Rljson>;\n\n /** Returns the number of rows in the given table */\n rowCount(table: string): Promise<number>;\n}\n\n// .............................................................................\nexport const exampleIo =\n 'Checkout @rljson/io-mem for an example implementation';\n","/* v8 ignore file -- @preserve */\n// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { Json } from '@rljson/json';\nimport {\n Buffet,\n Cake,\n iterateTablesSync,\n Layer,\n Ref,\n Rljson,\n TableKey,\n} from '@rljson/rljson';\n\n// .............................................................................\n/**\n * Describes a row that references a child table row\n */\nexport interface ParentRef {\n /**\n * The parent table that references the child table\n */\n [parentTable: TableKey]: {\n /**\n * The parent row that references the child row\n */\n [parentRow: Ref]: {\n /**\n * Details about the reference, e.g. an array index etc.\n */\n details?: Json;\n };\n };\n}\n\n// .............................................................................\n/**\n * Describes the parent table rows referencing a child table row\n */\nexport interface ReverseRefs {\n /**\n * The child table we need the referencing rows for\n */\n [childTable: TableKey]: {\n /**\n * The row hashwe need the referencing rows for\n */\n [childRow: Ref]: ParentRef;\n };\n}\n\n/* v8 ignore start -- @preserve */\n\n// .............................................................................\n/**\n * Calculates the reverse references for a given rljson object\n */\nexport const calcReverseRefs = (rljson: Rljson): ReverseRefs => {\n const result: ReverseRefs = {};\n\n // ......................\n // Prepare data structure\n iterateTablesSync(rljson, (childTableKey, table) => {\n const childTable: { [childRowHash: string]: ParentRef } = {};\n result[childTableKey] = childTable;\n for (const childRow of table._data) {\n childTable[childRow._hash] = {};\n }\n });\n\n // ............................\n // Generate reverse references\n iterateTablesSync(rljson, (parentTableKey, parentTable) => {\n // Iterate all rows of each table\n for (const parentTableRow of parentTable._data) {\n // Find out whe other tables & rows are referenced by this row\n // Write these information intto result\n switch (parentTable._type) {\n case 'components':\n _writeComponentRefs(parentTableKey, parentTableRow, result);\n break;\n\n case 'layers': {\n _writeLayerRefs(parentTableKey, parentTableRow, result);\n break;\n }\n\n case 'sliceIds': {\n // Slice ids do not reference other tables\n break;\n }\n\n case 'cakes': {\n _writeCakeRefs(parentTableKey, parentTableRow, result);\n break;\n }\n\n case 'buffets': {\n _writeBuffetRefs(parentTableKey, parentTableRow, result);\n break;\n }\n }\n }\n });\n\n return result;\n};\n\n/* v8 ignore stop -- @preserve */\n\n// .............................................................................\nconst _writeComponentRefs = (\n parentTableName: TableKey,\n parentRow: Json,\n result: ReverseRefs,\n) => {\n const parentRowHash = parentRow._hash as string;\n\n for (const parentColumnName in parentRow) {\n if (parentColumnName.startsWith('_')) {\n continue;\n }\n\n if (!parentColumnName.endsWith('Ref')) {\n continue;\n }\n\n const childTableName = parentColumnName.slice(0, -3);\n const childRowHash = parentRow[parentColumnName] as string;\n\n _write(\n result,\n childTableName,\n childRowHash,\n parentTableName,\n parentRowHash,\n );\n }\n};\n\n// .............................................................................\nconst _writeLayerRefs = (\n parentTableName: TableKey,\n parentRow: Layer,\n result: ReverseRefs,\n) => {\n const childTableName = parentRow.componentsTable;\n const parentRowHash = parentRow._hash as string;\n\n for (const sliceId in parentRow.add) {\n if (sliceId.startsWith('_')) {\n continue;\n }\n\n const sliceHash = parentRow.add[sliceId] as string;\n\n _write(result, childTableName, sliceHash, parentTableName, parentRowHash);\n }\n};\n\n// .............................................................................\nconst _writeCakeRefs = (\n parentTableName: TableKey,\n parentRow: Cake,\n result: ReverseRefs,\n) => {\n const parentRowHash = parentRow._hash as string;\n\n for (const layer in parentRow.layers) {\n const childTableName = layer;\n const childRowHash = parentRow.layers[layer] as string;\n _write(\n result,\n childTableName,\n childRowHash,\n parentTableName,\n parentRowHash,\n );\n }\n};\n\n// .............................................................................\nconst _writeBuffetRefs = (\n parentTableName: TableKey,\n parentRow: Buffet,\n result: ReverseRefs,\n) => {\n const parentRowHash = parentRow._hash as string;\n\n for (const item of parentRow.items) {\n const childTableName = item.table;\n const childRowHash = item.ref;\n _write(\n result,\n childTableName,\n childRowHash,\n parentTableName,\n parentRowHash,\n );\n }\n};\n\n// .............................................................................\nconst _write = (\n result: ReverseRefs,\n childTableName: string,\n childRowHash: string,\n parentTableName: string,\n parentRowHash: string,\n) => {\n const referencesForChildTable = (result[childTableName] ??= {});\n const referencesForChildTableRow = (referencesForChildTable[childRowHash] ??=\n {});\n\n referencesForChildTableRow[parentTableName] ??= {};\n referencesForChildTableRow[parentTableName][parentRowHash] ??= {};\n};\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n/* v8 ignore file -- @preserve */\nimport { Socket } from './socket.ts';\n\nexport class SocketMock implements Socket {\n public connected: boolean = false;\n public disconnected: boolean = true;\n\n private _listeners: Map<string | symbol, Array<(...args: any[]) => void>> =\n new Map();\n private _onceListeners: Map<\n string | symbol,\n Array<(...args: any[]) => void>\n > = new Map();\n\n connect(): void {\n if (!this.connected) {\n this.connected = true;\n this.disconnected = false;\n this.emit('connect');\n }\n }\n\n disconnect(): void {\n if (this.connected) {\n this.connected = false;\n this.disconnected = true;\n this.emit('disconnect');\n }\n }\n\n on(eventName: string | symbol, listener: (...args: any[]) => void): this {\n if (!this._listeners.has(eventName)) {\n this._listeners.set(eventName, []);\n }\n this._listeners.get(eventName)!.push(listener);\n return this;\n }\n\n once(eventName: string | symbol, listener: (...args: any[]) => void): this {\n if (!this._onceListeners.has(eventName)) {\n this._onceListeners.set(eventName, []);\n }\n this._onceListeners.get(eventName)!.push(listener);\n return this;\n }\n\n off(eventName: string | symbol, listener?: (...args: any[]) => void): this {\n if (listener) {\n // Remove specific listener\n const regularListeners = this._listeners.get(eventName);\n if (regularListeners) {\n const index = regularListeners.indexOf(listener);\n if (index > -1) {\n regularListeners.splice(index, 1);\n }\n }\n\n const onceListeners = this._onceListeners.get(eventName);\n if (onceListeners) {\n const index = onceListeners.indexOf(listener);\n if (index > -1) {\n onceListeners.splice(index, 1);\n }\n }\n } else {\n // Remove all listeners for the event\n this._listeners.delete(eventName);\n this._onceListeners.delete(eventName);\n }\n return this;\n }\n\n emit(eventName: string | symbol, ...args: any[]): boolean {\n let hasListeners = false;\n\n // Emit to regular listeners\n const regularListeners = this._listeners.get(eventName);\n if (regularListeners && regularListeners.length > 0) {\n hasListeners = true;\n // Create a copy to avoid issues if listeners are removed during emission\n [...regularListeners].forEach((listener) => {\n try {\n listener(...args);\n } catch (error) {\n // In a real EventEmitter, this would be handled differently\n console.error(\n `Error in listener for event ${String(eventName)}:`,\n error,\n );\n }\n });\n }\n\n // Emit to once listeners and remove them\n const onceListeners = this._onceListeners.get(eventName);\n if (onceListeners && onceListeners.length > 0) {\n hasListeners = true;\n // Create a copy and clear the original array\n const listenersToCall = [...onceListeners];\n this._onceListeners.delete(eventName);\n\n listenersToCall.forEach((listener) => {\n try {\n listener(...args);\n } catch (error) {\n console.error(\n `Error in once listener for event ${String(eventName)}:`,\n error,\n );\n }\n });\n }\n\n return hasListeners;\n }\n\n removeAllListeners(eventName?: string | symbol): this {\n if (eventName !== undefined) {\n this._listeners.delete(eventName);\n this._onceListeners.delete(eventName);\n } else {\n this._listeners.clear();\n this._onceListeners.clear();\n }\n return this;\n }\n\n listenerCount(eventName: string | symbol): number {\n const regularCount = this._listeners.get(eventName)?.length || 0;\n const onceCount = this._onceListeners.get(eventName)?.length || 0;\n return regularCount + onceCount;\n }\n\n listeners(eventName: string | symbol): Array<(...args: any[]) => void> {\n const regularListeners = this._listeners.get(eventName) || [];\n const onceListeners = this._onceListeners.get(eventName) || [];\n return [...regularListeners, ...onceListeners];\n }\n\n eventNames(): Array<string | symbol> {\n const allEvents = new Set([\n ...this._listeners.keys(),\n ...this._onceListeners.keys(),\n ]);\n return Array.from(allEvents);\n }\n\n // Test helper methods\n reset(): void {\n this.connected = false;\n this.disconnected = true;\n this.removeAllListeners();\n }\n\n simulateError(error: Error): void {\n this.emit('error', error);\n }\n\n simulateMessage(message: any): void {\n this.emit('message', message);\n }\n\n // Get internal state for testing\n getListeners(): Map<string | symbol, Array<(...args: any[]) => void>> {\n return new Map(this._listeners);\n }\n\n getOnceListeners(): Map<string | symbol, Array<(...args: any[]) => void>> {\n return new Map(this._onceListeners);\n }\n}\n\n// ...existing code...\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\nimport { Socket } from './socket.ts';\n\n\n/**\n * Creates a pair of connected sockets that properly route messages between them.\n * Unlike SocketMock, this maintains directionality - when socketA emits, only socketB's\n * listeners fire, not socketA's own listeners.\n *\n * This is essential for client-server testing where both use the same socket instance\n * but need separate event handling.\n */\nexport function createSocketPair(): [\n DirectionalSocketMock,\n DirectionalSocketMock,\n] {\n const socketA = new DirectionalSocketMock();\n const socketB = new DirectionalSocketMock();\n\n // Connect them bidirectionally\n socketA._setPeer(socketB);\n socketB._setPeer(socketA);\n\n return [socketA, socketB];\n}\n\nexport class DirectionalSocketMock implements Socket {\n public connected: boolean = false;\n public disconnected: boolean = true;\n\n private _peer?: DirectionalSocketMock;\n private _listeners: Map<string | symbol, Array<(...args: any[]) => void>> =\n new Map();\n private _onceListeners: Map<\n string | symbol,\n Array<(...args: any[]) => void>\n > = new Map();\n\n _setPeer(peer: DirectionalSocketMock): void {\n this._peer = peer;\n }\n\n connect(): void {\n if (!this.connected) {\n this.connected = true;\n this.disconnected = false;\n // Trigger local 'connect' event\n this._triggerLocal('connect');\n // Trigger peer's 'connect' event\n if (this._peer) {\n this._peer._triggerLocal('connect');\n }\n }\n }\n\n disconnect(): void {\n if (this.connected) {\n this.connected = false;\n this.disconnected = true;\n this._triggerLocal('disconnect');\n if (this._peer) {\n this._peer._triggerLocal('disconnect');\n }\n }\n }\n\n on(eventName: string | symbol, listener: (...args: any[]) => void): this {\n if (!this._listeners.has(eventName)) {\n this._listeners.set(eventName, []);\n }\n this._listeners.get(eventName)!.push(listener);\n return this;\n }\n\n once(eventName: string | symbol, listener: (...args: any[]) => void): this {\n if (!this._onceListeners.has(eventName)) {\n this._onceListeners.set(eventName, []);\n }\n this._onceListeners.get(eventName)!.push(listener);\n return this;\n }\n\n off(eventName: string | symbol, listener?: (...args: any[]) => void): this {\n if (listener) {\n const regularListeners = this._listeners.get(eventName);\n if (regularListeners) {\n const index = regularListeners.indexOf(listener);\n if (index > -1) regularListeners.splice(index, 1);\n }\n const onceListeners = this._onceListeners.get(eventName);\n if (onceListeners) {\n const index = onceListeners.indexOf(listener);\n if (index > -1) onceListeners.splice(index, 1);\n }\n } else {\n this._listeners.delete(eventName);\n this._onceListeners.delete(eventName);\n }\n return this;\n }\n\n /**\n * Emits an event to the PEER socket (cross-socket emission).\n * This is the key difference from SocketMock - emit() sends to the other side,\n * not to local listeners.\n *\n * Implements Socket.IO acknowledgement pattern: the last argument can be a callback\n * that the peer will invoke to send a response back.\n */\n emit(eventName: string | symbol, ...args: any[]): boolean {\n if (!this._peer) {\n console.warn(\n `DirectionalSocketMock.emit: No peer connected for event ${String(eventName)}`,\n );\n return false;\n }\n\n // Trigger the event on the PEER socket, not locally\n this._peer._triggerLocal(eventName, ...args);\n return true;\n }\n\n /**\n * Triggers listeners on THIS socket (local emission).\n * Used internally when receiving events from peer.\n */\n private _triggerLocal(eventName: string | symbol, ...args: any[]): void {\n // Trigger regular listeners\n const regularListeners = this._listeners.get(eventName);\n if (regularListeners) {\n [...regularListeners].forEach((listener) => {\n try {\n listener(...args);\n } catch (error) {\n console.error(`Error in listener for ${String(eventName)}:`, error);\n }\n });\n }\n\n // Trigger and remove once listeners\n const onceListeners = this._onceListeners.get(eventName);\n if (onceListeners) {\n const listenersToCall = [...onceListeners];\n this._onceListeners.delete(eventName);\n listenersToCall.forEach((listener) => {\n try {\n listener(...args);\n } catch (error) {\n console.error(\n `Error in once listener for ${String(eventName)}:`,\n error,\n );\n }\n });\n }\n }\n\n removeAllListeners(eventName?: string | symbol): this {\n if (eventName !== undefined) {\n this._listeners.delete(eventName);\n this._onceListeners.delete(eventName);\n } else {\n this._listeners.clear();\n this._onceListeners.clear();\n }\n return this;\n }\n\n listenerCount(eventName: string | symbol): number {\n const regularCount = this._listeners.get(eventName)?.length || 0;\n const onceCount = this._onceListeners.get(eventName)?.length || 0;\n return regularCount + onceCount;\n }\n\n listeners(eventName: string | symbol): Array<(...args: any[]) => void> {\n const regularListeners = this._listeners.get(eventName) || [];\n const onceListeners = this._onceListeners.get(eventName) || [];\n return [...regularListeners, ...onceListeners];\n }\n\n eventNames(): Array<string | symbol> {\n const allEvents = new Set([\n ...this._listeners.keys(),\n ...this._onceListeners.keys(),\n ]);\n return Array.from(allEvents);\n }\n}\n","// @license\n// Copyright (c) 2025 Rljson\n//\n// Use of this source code is governed by terms that can be\n// found in the LICENSE file in the root of this package.\n\n//Interface for a generic Socket, similar to Node.js EventEmitter\n//This is a simplified version and may not cover all features of a full EventEmitter\nexport interface Socket {\n connected: boolean;\n disconnected: boolean;\n connect(): void;\n disconnect(): void;\n on(eventName: string | symbol, listener: (...args: any[]) => void): this;\n emit(eventName: string | symbol, ...args: any[]): boolean | this;\n off(eventName: string | symbol, listener?: (...args: any[]) => void): this;\n removeAllListeners(eventName?: string | symbol): this;\n}\n\nexport const socketExample = (): Socket => ({\n connected: false,\n disconnected: true,\n connect() {\n this.connected = true;\n this.disconnected = false;\n this.emit('connect');\n },\n disconnect() {\n this.connected = false;\n this.disconnected = true;\n this.emit('disconnect');\n },\n /* v8 ignore next -- @preserve */\n on() {\n // Implementation of event listener registration\n return this;\n },\n /* v8 ignore next -- @preserve */\n emit() {\n // Implementation of event emission\n return true;\n },\n /* v8 ignore next -- @preserve */\n off() {\n // Implementation of event listener removal\n return this;\n },\n /* v8 ignore next -- @preserve */\n removeAllListeners() {\n // Implementation of removing all listeners\n return this;\n },\n});\n"],"names":["e"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rljson/io",
3
- "version": "0.0.69",
3
+ "version": "0.0.70",
4
4
  "description": "Low level interface for reading and writing RLJSON data",
5
5
  "homepage": "https://github.com/rljson/io",
6
6
  "bugs": "https://github.com/rljson/io/issues",