lakesync 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/adapter.d.ts +185 -20
  2. package/dist/adapter.js +13 -3
  3. package/dist/analyst.js +2 -2
  4. package/dist/{base-poller-BpUyuG2R.d.ts → base-poller-Bj9kX9dv.d.ts} +76 -19
  5. package/dist/catalogue.d.ts +1 -1
  6. package/dist/catalogue.js +3 -3
  7. package/dist/chunk-DGUM43GV.js +11 -0
  8. package/dist/{chunk-IRJ4QRWV.js → chunk-JI4C4R5H.js} +249 -140
  9. package/dist/chunk-JI4C4R5H.js.map +1 -0
  10. package/dist/{chunk-FHVTUKXL.js → chunk-KVSWLIJR.js} +2 -2
  11. package/dist/{chunk-P3FT7QCW.js → chunk-LDFFCG2K.js} +377 -247
  12. package/dist/chunk-LDFFCG2K.js.map +1 -0
  13. package/dist/{chunk-GUJWMK5P.js → chunk-LPWXOYNS.js} +373 -350
  14. package/dist/chunk-LPWXOYNS.js.map +1 -0
  15. package/dist/{chunk-QMS7TGFL.js → chunk-PYRS74YP.js} +15 -4
  16. package/dist/{chunk-QMS7TGFL.js.map → chunk-PYRS74YP.js.map} +1 -1
  17. package/dist/{chunk-NCZYFZ3B.js → chunk-QNITY4F6.js} +30 -7
  18. package/dist/{chunk-NCZYFZ3B.js.map → chunk-QNITY4F6.js.map} +1 -1
  19. package/dist/{chunk-SF7Y6ZUA.js → chunk-SSICS5KI.js} +2 -2
  20. package/dist/{chunk-UAUQGP3B.js → chunk-TMLG32QV.js} +2 -2
  21. package/dist/client.d.ts +164 -13
  22. package/dist/client.js +310 -163
  23. package/dist/client.js.map +1 -1
  24. package/dist/compactor.d.ts +1 -1
  25. package/dist/compactor.js +4 -4
  26. package/dist/connector-jira.d.ts +2 -2
  27. package/dist/connector-jira.js +3 -3
  28. package/dist/connector-salesforce.d.ts +2 -2
  29. package/dist/connector-salesforce.js +3 -3
  30. package/dist/{coordinator-D32a5rNk.d.ts → coordinator-NXy6tA0h.d.ts} +23 -16
  31. package/dist/{db-types-BlN-4KbQ.d.ts → db-types-CfLMUBfW.d.ts} +1 -1
  32. package/dist/gateway-server.d.ts +158 -64
  33. package/dist/gateway-server.js +482 -4003
  34. package/dist/gateway-server.js.map +1 -1
  35. package/dist/gateway.d.ts +61 -104
  36. package/dist/gateway.js +12 -6
  37. package/dist/index.d.ts +45 -10
  38. package/dist/index.js +14 -2
  39. package/dist/parquet.d.ts +1 -1
  40. package/dist/parquet.js +3 -3
  41. package/dist/proto.d.ts +1 -1
  42. package/dist/proto.js +3 -3
  43. package/dist/react.d.ts +47 -10
  44. package/dist/react.js +88 -40
  45. package/dist/react.js.map +1 -1
  46. package/dist/{registry-CPTgO9jv.d.ts → registry-BcspAtZI.d.ts} +19 -4
  47. package/dist/{gateway-Bpvatd9n.d.ts → request-handler-pUvL7ozF.d.ts} +139 -10
  48. package/dist/{resolver-CbuXm3nB.d.ts → resolver-CXxmC0jR.d.ts} +1 -1
  49. package/dist/{src-FPJQYQNA.js → src-B6NLV3FP.js} +4 -4
  50. package/dist/{src-RHKJFQKR.js → src-ROW4XLO7.js} +15 -3
  51. package/dist/{src-CLCALYDT.js → src-ZRHKG42A.js} +4 -4
  52. package/dist/{types-CLlD4XOy.d.ts → types-BdGBv2ba.d.ts} +17 -2
  53. package/dist/{types-D-E0VrfS.d.ts → types-BrcD1oJg.d.ts} +26 -19
  54. package/package.json +1 -1
  55. package/dist/chunk-7D4SUZUM.js +0 -38
  56. package/dist/chunk-GUJWMK5P.js.map +0 -1
  57. package/dist/chunk-IRJ4QRWV.js.map +0 -1
  58. package/dist/chunk-P3FT7QCW.js.map +0 -1
  59. /package/dist/{chunk-7D4SUZUM.js.map → chunk-DGUM43GV.js.map} +0 -0
  60. /package/dist/{chunk-FHVTUKXL.js.map → chunk-KVSWLIJR.js.map} +0 -0
  61. /package/dist/{chunk-SF7Y6ZUA.js.map → chunk-SSICS5KI.js.map} +0 -0
  62. /package/dist/{chunk-UAUQGP3B.js.map → chunk-TMLG32QV.js.map} +0 -0
  63. /package/dist/{src-CLCALYDT.js.map → src-B6NLV3FP.js.map} +0 -0
  64. /package/dist/{src-FPJQYQNA.js.map → src-ROW4XLO7.js.map} +0 -0
  65. /package/dist/{src-RHKJFQKR.js.map → src-ZRHKG42A.js.map} +0 -0
@@ -1,18 +1,19 @@
1
1
  import {
2
2
  isDatabaseAdapter,
3
3
  isMaterialisable
4
- } from "./chunk-GUJWMK5P.js";
4
+ } from "./chunk-LPWXOYNS.js";
5
5
  import {
6
6
  buildPartitionSpec,
7
7
  lakeSyncTableName,
8
8
  tableSchemaToIceberg
9
- } from "./chunk-UAUQGP3B.js";
9
+ } from "./chunk-TMLG32QV.js";
10
10
  import {
11
11
  writeDeltasToParquet
12
- } from "./chunk-SF7Y6ZUA.js";
12
+ } from "./chunk-SSICS5KI.js";
13
13
  import {
14
14
  AdapterNotFoundError,
15
15
  BackpressureError,
16
+ COLUMN_TYPES,
16
17
  Err,
17
18
  FlushError,
18
19
  HLC,
@@ -28,19 +29,25 @@ import {
28
29
  validateAction,
29
30
  validateConnectorConfig,
30
31
  validateSyncRules
31
- } from "./chunk-P3FT7QCW.js";
32
+ } from "./chunk-LDFFCG2K.js";
32
33
 
33
34
  // ../gateway/src/action-dispatcher.ts
35
+ var DEFAULT_MAX_CACHE_SIZE = 1e4;
36
+ var DEFAULT_CACHE_TTL_MS = 5 * 60 * 1e3;
34
37
  var ActionDispatcher = class {
35
38
  actionHandlers = /* @__PURE__ */ new Map();
36
39
  executedActions = /* @__PURE__ */ new Set();
37
40
  idempotencyMap = /* @__PURE__ */ new Map();
38
- constructor(handlers) {
41
+ maxCacheSize;
42
+ cacheTtlMs;
43
+ constructor(handlers, cacheConfig) {
39
44
  if (handlers) {
40
45
  for (const [name, handler] of Object.entries(handlers)) {
41
46
  this.actionHandlers.set(name, handler);
42
47
  }
43
48
  }
49
+ this.maxCacheSize = cacheConfig?.maxSize ?? DEFAULT_MAX_CACHE_SIZE;
50
+ this.cacheTtlMs = cacheConfig?.ttlMs ?? DEFAULT_CACHE_TTL_MS;
44
51
  }
45
52
  /**
46
53
  * Dispatch an action push to registered handlers.
@@ -55,6 +62,7 @@ var ActionDispatcher = class {
55
62
  * @returns A `Result` containing results for each action.
56
63
  */
57
64
  async dispatch(msg, hlcNow, context) {
65
+ this.evictStaleEntries();
58
66
  const results = [];
59
67
  for (const action of msg.actions) {
60
68
  const validation = validateAction(action);
@@ -62,7 +70,7 @@ var ActionDispatcher = class {
62
70
  return Err(validation.error);
63
71
  }
64
72
  if (this.executedActions.has(action.actionId)) {
65
- const cached = this.idempotencyMap.get(action.actionId);
73
+ const cached = this.getCachedResult(action.actionId);
66
74
  if (cached) {
67
75
  results.push(cached);
68
76
  continue;
@@ -70,7 +78,7 @@ var ActionDispatcher = class {
70
78
  continue;
71
79
  }
72
80
  if (action.idempotencyKey) {
73
- const cached = this.idempotencyMap.get(`idem:${action.idempotencyKey}`);
81
+ const cached = this.getCachedResult(`idem:${action.idempotencyKey}`);
74
82
  if (cached) {
75
83
  results.push(cached);
76
84
  continue;
@@ -163,10 +171,43 @@ var ActionDispatcher = class {
163
171
  }
164
172
  /** Cache an action result for idempotency deduplication. */
165
173
  cacheActionResult(action, result) {
174
+ const entry = { value: result, cachedAt: Date.now() };
166
175
  this.executedActions.add(action.actionId);
167
- this.idempotencyMap.set(action.actionId, result);
176
+ this.idempotencyMap.set(action.actionId, entry);
168
177
  if (action.idempotencyKey) {
169
- this.idempotencyMap.set(`idem:${action.idempotencyKey}`, result);
178
+ this.idempotencyMap.set(`idem:${action.idempotencyKey}`, entry);
179
+ }
180
+ }
181
+ /** Get a cached result if it exists and hasn't expired. */
182
+ getCachedResult(key) {
183
+ const entry = this.idempotencyMap.get(key);
184
+ if (!entry) return void 0;
185
+ if (Date.now() - entry.cachedAt > this.cacheTtlMs) {
186
+ this.idempotencyMap.delete(key);
187
+ return void 0;
188
+ }
189
+ return entry.value;
190
+ }
191
+ /** Evict expired entries and trim to max size. */
192
+ evictStaleEntries() {
193
+ const now = Date.now();
194
+ for (const [key, entry] of this.idempotencyMap) {
195
+ if (now - entry.cachedAt > this.cacheTtlMs) {
196
+ this.idempotencyMap.delete(key);
197
+ if (!key.startsWith("idem:")) {
198
+ this.executedActions.delete(key);
199
+ }
200
+ }
201
+ }
202
+ if (this.executedActions.size > this.maxCacheSize) {
203
+ const excess = this.executedActions.size - this.maxCacheSize;
204
+ let removed = 0;
205
+ for (const actionId of this.executedActions) {
206
+ if (removed >= excess) break;
207
+ this.executedActions.delete(actionId);
208
+ this.idempotencyMap.delete(actionId);
209
+ removed++;
210
+ }
170
211
  }
171
212
  }
172
213
  };
@@ -284,9 +325,18 @@ var DeltaBuffer = class {
284
325
  this.tableLog.delete(table);
285
326
  return tableDeltas;
286
327
  }
287
- /** Drain the log for flush. Returns log entries and clears both structures. */
288
- drain() {
289
- const entries = [...this.log];
328
+ /**
329
+ * Snapshot the current buffer state without clearing it.
330
+ *
331
+ * Useful for inspecting the buffer contents without draining.
332
+ * Use {@link clear} separately after a successful flush for
333
+ * transactional semantics.
334
+ */
335
+ snapshot() {
336
+ return { entries: [...this.log], byteSize: this.estimatedBytes };
337
+ }
338
+ /** Clear all buffer state. */
339
+ clear() {
290
340
  this.log = [];
291
341
  this.index.clear();
292
342
  this.deltaIds.clear();
@@ -294,6 +344,11 @@ var DeltaBuffer = class {
294
344
  this.createdAt = Date.now();
295
345
  this.tableBytes.clear();
296
346
  this.tableLog.clear();
347
+ }
348
+ /** Drain the log for flush. Returns log entries and clears both structures. */
349
+ drain() {
350
+ const { entries } = this.snapshot();
351
+ this.clear();
297
352
  return entries;
298
353
  }
299
354
  /** Number of log entries */
@@ -344,7 +399,7 @@ var MAX_PUSH_PAYLOAD_BYTES = 1048576;
344
399
  var MAX_DELTAS_PER_PUSH = 1e4;
345
400
  var MAX_PULL_LIMIT = 1e4;
346
401
  var DEFAULT_PULL_LIMIT = 100;
347
- var VALID_COLUMN_TYPES = /* @__PURE__ */ new Set(["string", "number", "boolean", "json", "null"]);
402
+ var VALID_COLUMN_TYPES = new Set(COLUMN_TYPES);
348
403
  var DEFAULT_MAX_BUFFER_BYTES = 4 * 1024 * 1024;
349
404
  var DEFAULT_MAX_BUFFER_AGE_MS = 3e4;
350
405
 
@@ -463,6 +518,117 @@ async function commitToCatalogue(objectKey, fileSizeInBytes, recordCount, catalo
463
518
  }
464
519
  }
465
520
 
521
+ // ../gateway/src/flush-coordinator.ts
522
+ var FlushCoordinator = class {
523
+ flushing = false;
524
+ /** Whether a flush is currently in progress. */
525
+ get isFlushing() {
526
+ return this.flushing;
527
+ }
528
+ /**
529
+ * Flush all entries from the buffer to the adapter.
530
+ *
531
+ * Drains the buffer first, then writes to the adapter. On failure,
532
+ * entries are restored to the buffer.
533
+ */
534
+ async flush(buffer, adapter, deps) {
535
+ if (this.flushing) {
536
+ return Err(new FlushError("Flush already in progress"));
537
+ }
538
+ if (buffer.logSize === 0) {
539
+ return Ok(void 0);
540
+ }
541
+ if (!adapter) {
542
+ return Err(new FlushError("No adapter configured"));
543
+ }
544
+ this.flushing = true;
545
+ const byteSize = isDatabaseAdapter(adapter) ? 0 : buffer.byteSize;
546
+ const entries = buffer.drain();
547
+ if (entries.length === 0) {
548
+ this.flushing = false;
549
+ return Ok(void 0);
550
+ }
551
+ try {
552
+ return await flushEntries(entries, byteSize, {
553
+ adapter,
554
+ config: deps.config,
555
+ restoreEntries: (e) => this.restoreEntries(buffer, e),
556
+ schemas: deps.schemas
557
+ });
558
+ } finally {
559
+ this.flushing = false;
560
+ }
561
+ }
562
+ /**
563
+ * Flush a single table's deltas from the buffer.
564
+ *
565
+ * Drains only the specified table's deltas and flushes them,
566
+ * leaving other tables in the buffer.
567
+ */
568
+ async flushTable(table, buffer, adapter, deps) {
569
+ if (this.flushing) {
570
+ return Err(new FlushError("Flush already in progress"));
571
+ }
572
+ if (!adapter) {
573
+ return Err(new FlushError("No adapter configured"));
574
+ }
575
+ const entries = buffer.drainTable(table);
576
+ if (entries.length === 0) {
577
+ return Ok(void 0);
578
+ }
579
+ this.flushing = true;
580
+ try {
581
+ return await flushEntries(
582
+ entries,
583
+ 0,
584
+ {
585
+ adapter,
586
+ config: deps.config,
587
+ restoreEntries: (e) => this.restoreEntries(buffer, e),
588
+ schemas: deps.schemas
589
+ },
590
+ table
591
+ );
592
+ } finally {
593
+ this.flushing = false;
594
+ }
595
+ }
596
+ /** Restore drained entries back to the buffer for retry. */
597
+ restoreEntries(buffer, entries) {
598
+ for (const entry of entries) {
599
+ buffer.append(entry);
600
+ }
601
+ }
602
+ };
603
+
604
+ // ../gateway/src/source-registry.ts
605
+ var SourceRegistry = class {
606
+ sources = /* @__PURE__ */ new Map();
607
+ constructor(initial) {
608
+ if (initial) {
609
+ for (const [name, adapter] of Object.entries(initial)) {
610
+ this.sources.set(name, adapter);
611
+ }
612
+ }
613
+ }
614
+ /** Register a named source adapter. */
615
+ register(name, adapter) {
616
+ this.sources.set(name, adapter);
617
+ }
618
+ /** Unregister a named source adapter. */
619
+ unregister(name) {
620
+ this.sources.delete(name);
621
+ }
622
+ /** Get a source adapter by name, or undefined if not registered. */
623
+ get(name) {
624
+ return this.sources.get(name);
625
+ }
626
+ /** List all registered source adapter names. */
627
+ list() {
628
+ return [...this.sources.keys()];
629
+ }
630
+ };
631
+
466
632
  // ../gateway/src/gateway.ts
467
633
  var SyncGateway = class {
468
634
  hlc;
@@ -470,20 +636,20 @@ var SyncGateway = class {
470
636
  actions;
471
637
  config;
472
638
  adapter;
473
- flushing = false;
639
+ sources;
640
+ flushCoordinator;
474
641
  constructor(config, adapter) {
475
642
  this.config = { sourceAdapters: {}, ...config };
476
643
  this.hlc = new HLC();
477
644
  this.buffer = new DeltaBuffer();
478
645
  this.adapter = this.config.adapter ?? adapter ?? null;
479
646
  this.actions = new ActionDispatcher(config.actionHandlers);
647
+ this.sources = new SourceRegistry(this.config.sourceAdapters);
648
+ this.flushCoordinator = new FlushCoordinator();
480
649
  }
481
- /** Restore drained entries back to the buffer for retry. */
482
- restoreEntries(entries) {
483
- for (const entry of entries) {
484
- this.buffer.append(entry);
485
- }
486
- }
650
+ // -----------------------------------------------------------------------
651
+ // Push — pipeline of validation steps then buffer append
652
+ // -----------------------------------------------------------------------
487
653
  /**
488
654
  * Handle an incoming push from a client.
489
655
  *
@@ -494,14 +660,8 @@ var SyncGateway = class {
494
660
  * or a `ClockDriftError` if the client clock is too far ahead.
495
661
  */
496
662
  handlePush(msg) {
497
- const backpressureLimit = this.config.maxBackpressureBytes ?? this.config.maxBufferBytes * 2;
498
- if (this.buffer.byteSize >= backpressureLimit) {
499
- return Err(
500
- new BackpressureError(
501
- `Buffer backpressure exceeded (${this.buffer.byteSize} >= ${backpressureLimit} bytes)`
502
- )
503
- );
504
- }
663
+ const bpResult = this.checkBackpressure();
664
+ if (!bpResult.ok) return bpResult;
505
665
  let accepted = 0;
506
666
  const ingested = [];
507
667
  for (const delta of msg.deltas) {
@@ -536,6 +696,18 @@ var SyncGateway = class {
536
696
  const serverHlc = this.hlc.now();
537
697
  return Ok({ serverHlc, accepted, deltas: ingested });
538
698
  }
699
+ /** Check buffer backpressure. */
700
+ checkBackpressure() {
701
+ const backpressureLimit = this.config.maxBackpressureBytes ?? this.config.maxBufferBytes * 2;
702
+ if (this.buffer.byteSize >= backpressureLimit) {
703
+ return Err(
704
+ new BackpressureError(
705
+ `Buffer backpressure exceeded (${this.buffer.byteSize} >= ${backpressureLimit} bytes)`
706
+ )
707
+ );
708
+ }
709
+ return Ok(void 0);
710
+ }
539
711
  handlePull(msg, context) {
540
712
  if (msg.source) {
541
713
  return this.handleAdapterPull(msg, context);
@@ -580,7 +752,7 @@ var SyncGateway = class {
580
752
  }
581
753
  /** Pull from a named source adapter. */
582
754
  async handleAdapterPull(msg, context) {
583
- const adapter = this.config.sourceAdapters?.[msg.source];
755
+ const adapter = this.sources.get(msg.source);
584
756
  if (!adapter) {
585
757
  return Err(new AdapterNotFoundError(`Source adapter "${msg.source}" not found`));
586
758
  }
@@ -598,7 +770,7 @@ var SyncGateway = class {
598
770
  return Ok({ deltas: sliced, serverHlc, hasMore });
599
771
  }
600
772
  // -----------------------------------------------------------------------
601
- // Flush — delegates to flush module
773
+ // Flush — delegates to FlushCoordinator
602
774
  // -----------------------------------------------------------------------
603
775
  /**
604
776
  * Flush the buffer to the configured adapter.
@@ -611,55 +783,15 @@ var SyncGateway = class {
611
783
  * @returns A `Result` indicating success or a `FlushError`.
612
784
  */
613
785
  async flush() {
614
- if (this.flushing) {
615
- return Err(new FlushError("Flush already in progress"));
616
- }
617
- if (this.buffer.logSize === 0) {
618
- return Ok(void 0);
619
- }
620
- if (!this.adapter) {
621
- return Err(new FlushError("No adapter configured"));
622
- }
623
- this.flushing = true;
624
- if (isDatabaseAdapter(this.adapter)) {
625
- const entries2 = this.buffer.drain();
626
- if (entries2.length === 0) {
627
- this.flushing = false;
628
- return Ok(void 0);
629
- }
630
- try {
631
- return await flushEntries(entries2, 0, {
632
- adapter: this.adapter,
633
- config: {
634
- gatewayId: this.config.gatewayId,
635
- flushFormat: this.config.flushFormat,
636
- tableSchema: this.config.tableSchema,
637
- catalogue: this.config.catalogue
638
- },
639
- restoreEntries: (e) => this.restoreEntries(e),
640
- schemas: this.config.schemas
641
- });
642
- } finally {
643
- this.flushing = false;
644
- }
645
- }
646
- const byteSize = this.buffer.byteSize;
647
- const entries = this.buffer.drain();
648
- try {
649
- return await flushEntries(entries, byteSize, {
650
- adapter: this.adapter,
651
- config: {
652
- gatewayId: this.config.gatewayId,
653
- flushFormat: this.config.flushFormat,
654
- tableSchema: this.config.tableSchema,
655
- catalogue: this.config.catalogue
656
- },
657
- restoreEntries: (e) => this.restoreEntries(e),
658
- schemas: this.config.schemas
659
- });
660
- } finally {
661
- this.flushing = false;
662
- }
786
+ return this.flushCoordinator.flush(this.buffer, this.adapter, {
787
+ config: {
788
+ gatewayId: this.config.gatewayId,
789
+ flushFormat: this.config.flushFormat,
790
+ tableSchema: this.config.tableSchema,
791
+ catalogue: this.config.catalogue
792
+ },
793
+ schemas: this.config.schemas
794
+ });
663
795
  }
664
796
  /**
665
797
  * Flush a single table's deltas from the buffer.
@@ -668,37 +800,15 @@ var SyncGateway = class {
668
800
  * leaving other tables in the buffer.
669
801
  */
670
802
  async flushTable(table) {
671
- if (this.flushing) {
672
- return Err(new FlushError("Flush already in progress"));
673
- }
674
- if (!this.adapter) {
675
- return Err(new FlushError("No adapter configured"));
676
- }
677
- const entries = this.buffer.drainTable(table);
678
- if (entries.length === 0) {
679
- return Ok(void 0);
680
- }
681
- this.flushing = true;
682
- try {
683
- return await flushEntries(
684
- entries,
685
- 0,
686
- {
687
- adapter: this.adapter,
688
- config: {
689
- gatewayId: this.config.gatewayId,
690
- flushFormat: this.config.flushFormat,
691
- tableSchema: this.config.tableSchema,
692
- catalogue: this.config.catalogue
693
- },
694
- restoreEntries: (e) => this.restoreEntries(e),
695
- schemas: this.config.schemas
696
- },
697
- table
698
- );
699
- } finally {
700
- this.flushing = false;
701
- }
803
+ return this.flushCoordinator.flushTable(table, this.buffer, this.adapter, {
804
+ config: {
805
+ gatewayId: this.config.gatewayId,
806
+ flushFormat: this.config.flushFormat,
807
+ tableSchema: this.config.tableSchema,
808
+ catalogue: this.config.catalogue
809
+ },
810
+ schemas: this.config.schemas
811
+ });
702
812
  }
703
813
  // -----------------------------------------------------------------------
704
814
  // Actions — delegates to ActionDispatcher
@@ -724,7 +834,7 @@ var SyncGateway = class {
724
834
  return this.actions.describe();
725
835
  }
726
836
  // -----------------------------------------------------------------------
727
- // Source adapters
837
+ // Source adapters — delegates to SourceRegistry
728
838
  // -----------------------------------------------------------------------
729
839
  /**
730
840
  * Register a named source adapter for adapter-sourced pulls.
@@ -733,7 +843,7 @@ var SyncGateway = class {
733
843
  * @param adapter - The database adapter to register.
734
844
  */
735
845
  registerSource(name, adapter) {
736
- this.config.sourceAdapters[name] = adapter;
846
+ this.sources.register(name, adapter);
737
847
  }
738
848
  /**
739
849
  * Unregister a named source adapter.
@@ -741,7 +851,7 @@ var SyncGateway = class {
741
851
  * @param name - The source name to remove.
742
852
  */
743
853
  unregisterSource(name) {
744
- delete this.config.sourceAdapters[name];
854
+ this.sources.unregister(name);
745
855
  }
746
856
  /**
747
857
  * List all registered source adapter names.
@@ -749,7 +859,7 @@ var SyncGateway = class {
749
859
  * @returns Array of registered source adapter names.
750
860
  */
751
861
  listSources() {
752
- return Object.keys(this.config.sourceAdapters);
862
+ return this.sources.list();
753
863
  }
754
864
  // -----------------------------------------------------------------------
755
865
  // Buffer queries
@@ -789,13 +899,17 @@ var SyncGateway = class {
789
899
  };
790
900
 
791
901
  // ../gateway/src/validation.ts
792
- function validatePushBody(raw, headerClientId) {
793
- let body;
902
+ function parseJson(raw, reviver) {
794
903
  try {
795
- body = JSON.parse(raw, bigintReviver);
904
+ return Ok(JSON.parse(raw, reviver));
796
905
  } catch {
797
906
  return Err({ status: 400, message: "Invalid JSON body" });
798
907
  }
908
+ }
909
+ function validatePushBody(raw, headerClientId) {
910
+ const parsed = parseJson(raw, bigintReviver);
911
+ if (!parsed.ok) return parsed;
912
+ const body = parsed.value;
799
913
  if (!body.clientId || !Array.isArray(body.deltas)) {
800
914
  return Err({ status: 400, message: "Missing required fields: clientId, deltas" });
801
915
  }
@@ -840,12 +954,9 @@ function parsePullParams(params) {
840
954
  return Ok(msg);
841
955
  }
842
956
  function validateActionBody(raw, headerClientId) {
843
- let body;
844
- try {
845
- body = JSON.parse(raw, bigintReviver);
846
- } catch {
847
- return Err({ status: 400, message: "Invalid JSON body" });
848
- }
957
+ const parsed = parseJson(raw, bigintReviver);
958
+ if (!parsed.ok) return parsed;
959
+ const body = parsed.value;
849
960
  if (!body.clientId || !Array.isArray(body.actions)) {
850
961
  return Err({ status: 400, message: "Missing required fields: clientId, actions" });
851
962
  }
@@ -858,12 +969,9 @@ function validateActionBody(raw, headerClientId) {
858
969
  return Ok(body);
859
970
  }
860
971
  function validateSchemaBody(raw) {
861
- let schema;
862
- try {
863
- schema = JSON.parse(raw);
864
- } catch {
865
- return Err({ status: 400, message: "Invalid JSON body" });
866
- }
972
+ const parsed = parseJson(raw);
973
+ if (!parsed.ok) return parsed;
974
+ const schema = parsed.value;
867
975
  if (!schema.table || !Array.isArray(schema.columns)) {
868
976
  return Err({ status: 400, message: "Missing required fields: table, columns" });
869
977
  }
@@ -1000,12 +1108,11 @@ async function handleSaveSchema(raw, store, gatewayId) {
1000
1108
  return { status: 200, body: { saved: true } };
1001
1109
  }
1002
1110
  async function handleSaveSyncRules(raw, store, gatewayId) {
1003
- let config;
1004
- try {
1005
- config = JSON.parse(raw);
1006
- } catch {
1007
- return { status: 400, body: { error: "Invalid JSON body" } };
1111
+ const parsed = parseJson(raw);
1112
+ if (!parsed.ok) {
1113
+ return { status: parsed.error.status, body: { error: parsed.error.message } };
1008
1114
  }
1115
+ const config = parsed.value;
1009
1116
  const validation = validateSyncRules(config);
1010
1117
  if (!validation.ok) {
1011
1118
  return { status: 400, body: { error: validation.error.message } };
@@ -1014,12 +1121,11 @@ async function handleSaveSyncRules(raw, store, gatewayId) {
1014
1121
  return { status: 200, body: { saved: true } };
1015
1122
  }
1016
1123
  async function handleRegisterConnector(raw, store) {
1017
- let body;
1018
- try {
1019
- body = JSON.parse(raw);
1020
- } catch {
1021
- return { status: 400, body: { error: "Invalid JSON body" } };
1124
+ const parsed = parseJson(raw);
1125
+ if (!parsed.ok) {
1126
+ return { status: parsed.error.status, body: { error: parsed.error.message } };
1022
1127
  }
1128
+ const body = parsed.value;
1023
1129
  const validation = validateConnectorConfig(body);
1024
1130
  if (!validation.ok) {
1025
1131
  return { status: 400, body: { error: validation.error.message } };
@@ -1146,7 +1252,10 @@ export {
1146
1252
  hlcRange,
1147
1253
  flushEntries,
1148
1254
  commitToCatalogue,
1255
+ FlushCoordinator,
1256
+ SourceRegistry,
1149
1257
  SyncGateway,
1258
+ parseJson,
1150
1259
  validatePushBody,
1151
1260
  parsePullParams,
1152
1261
  validateActionBody,
@@ -1166,4 +1275,4 @@ export {
1166
1275
  handleMetrics,
1167
1276
  SchemaManager
1168
1277
  };
1169
- //# sourceMappingURL=chunk-IRJ4QRWV.js.map
1278
+ //# sourceMappingURL=chunk-JI4C4R5H.js.map