@powerhousedao/connect 1.0.8 → 1.0.10-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/LICENSE +661 -0
  2. package/dist/.env +0 -5
  3. package/dist/assets/{app-D3TxLTK-.css → app-BIIVKAZr.css} +241 -60
  4. package/dist/assets/{app-Bw1Ba-jV.js → app-CsiwsM42.js} +2262 -1224
  5. package/dist/assets/{app-loader-KTD3Q6e9.js → app-loader-C7A2YjX4.js} +876 -577
  6. package/dist/assets/{app-loader-CjrEwupY.css → app-loader-pcztQTL4.css} +189 -26
  7. package/dist/assets/{ccip-D3HujWHr.js → ccip-BG1d6viz.js} +3 -3
  8. package/dist/assets/{content-D3TuBhK9.js → content-0UFgs2d1.js} +37 -7
  9. package/dist/assets/{index-DpasqVlD.js → index-BMDqhr-9.js} +3 -3
  10. package/dist/assets/{index-DsNVpRhT.js → index-CTEGX1We.js} +670 -519
  11. package/dist/assets/{index-yFk8X8m1.js → index-yr0-SqYf.js} +4 -4
  12. package/dist/assets/{main.CzEw2R-H.js → main.BmcV9296.js} +1 -1
  13. package/dist/assets/{style-D4JhTt_m.css → style-Ce3V83BE.css} +31 -36
  14. package/dist/external-packages.js +5 -0
  15. package/dist/hmr.js +4 -1
  16. package/dist/index.html +1 -4
  17. package/dist/modules/@powerhousedao/reactor-browser/{chunk-G6LMXRY5.js → chunk-2ONJ2PX4.js} +1 -1
  18. package/dist/modules/@powerhousedao/reactor-browser/{chunk-P46ZMPJ3.js → chunk-3C54663M.js} +1 -1
  19. package/dist/modules/@powerhousedao/reactor-browser/{chunk-6AXML2S3.js → chunk-5QJXNK35.js} +1 -1
  20. package/dist/modules/@powerhousedao/reactor-browser/{chunk-FW7N6EJH.js → chunk-C7QRY43M.js} +3 -3
  21. package/dist/modules/@powerhousedao/reactor-browser/{chunk-45DCPCA7.js → chunk-CO2RVWYY.js} +1 -1
  22. package/dist/modules/@powerhousedao/reactor-browser/{chunk-POMUCSTC.js → chunk-ISDEPHKP.js} +74 -20
  23. package/dist/modules/@powerhousedao/reactor-browser/{chunk-F3RCGUF6.js → chunk-NHD6VUCD.js} +2 -2
  24. package/dist/modules/@powerhousedao/reactor-browser/{chunk-YOX3ZAET.js → chunk-SQ5HIKYV.js} +581 -334
  25. package/dist/modules/@powerhousedao/reactor-browser/{chunk-M2UUQ5LH.js → chunk-U34SEKEB.js} +2 -2
  26. package/dist/modules/@powerhousedao/reactor-browser/{chunk-4LZZ55AN.js → chunk-XV42KZK3.js} +1 -1
  27. package/dist/modules/@powerhousedao/reactor-browser/context/index.js +2 -2
  28. package/dist/modules/@powerhousedao/reactor-browser/context/read-mode.js +2 -2
  29. package/dist/modules/@powerhousedao/reactor-browser/hooks/index.js +8 -8
  30. package/dist/modules/@powerhousedao/reactor-browser/hooks/useAddDebouncedOperations.js +3 -3
  31. package/dist/modules/@powerhousedao/reactor-browser/hooks/useConnectCrypto.js +2 -2
  32. package/dist/modules/@powerhousedao/reactor-browser/hooks/useDocumentDrives.js +2 -2
  33. package/dist/modules/@powerhousedao/reactor-browser/hooks/useDocumentEditor.js +5 -5
  34. package/dist/modules/@powerhousedao/reactor-browser/hooks/useDriveActions.js +2 -2
  35. package/dist/modules/@powerhousedao/reactor-browser/hooks/useDriveActionsWithUiNodes.js +3 -3
  36. package/dist/modules/@powerhousedao/reactor-browser/index.js +10 -10
  37. package/dist/modules/@powerhousedao/reactor-browser/reactor.js +2 -2
  38. package/dist/swEnv.js +0 -3
  39. package/dist/vite-envs.sh +1 -28
  40. package/package.json +9 -9
@@ -1,4 +1,4 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/app-Bw1Ba-jV.js","assets/main.CzEw2R-H.js","assets/app-D3TxLTK-.css"])))=>i.map(i=>d[i]);
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/app-CsiwsM42.js","assets/main.BmcV9296.js","assets/app-BIIVKAZr.css"])))=>i.map(i=>d[i]);
2
2
  var __defProp = Object.defineProperty;
3
3
  var __typeError = (msg) => {
4
4
  throw TypeError(msg);
@@ -11,7 +11,7 @@ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot
11
11
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
12
12
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
13
13
  var _tags, _levelString, _errorHandler, _ConsoleLogger_instances, levelValue_get, _getDocumentModelModule, _drives, _ReadModeService_instances, parseGraphQLErrors_fn, fetchDrive_fn, _a, _ServiceWorkerManager_instances, handleServiceWorkerMessage_fn, handleServiceWorker_fn;
14
- import { _ as __vitePreload } from "./main.CzEw2R-H.js";
14
+ import { _ as __vitePreload } from "./main.BmcV9296.js";
15
15
  import { jsx, jsxs } from "react/jsx-runtime";
16
16
  import { useState, useEffect, Suspense, lazy } from "react";
17
17
  function _mergeNamespaces(n, m) {
@@ -86,34 +86,78 @@ class DocumentEditorDebugTools {
86
86
  this.document = void 0;
87
87
  }
88
88
  }
89
+ const trimResultingState = (document) => {
90
+ const global2 = document.operations.global.map((e) => {
91
+ delete e.resultingState;
92
+ return e;
93
+ });
94
+ const local = document.operations.local.map((e) => {
95
+ delete e.resultingState;
96
+ return e;
97
+ });
98
+ return { ...document, operations: { global: global2, local } };
99
+ };
89
100
  class InMemoryCache {
90
101
  constructor() {
91
- __publicField(this, "cache", /* @__PURE__ */ new Map());
102
+ __publicField(this, "idTodocument", /* @__PURE__ */ new Map());
103
+ __publicField(this, "idToDrive", /* @__PURE__ */ new Map());
104
+ __publicField(this, "slugToDriveId", /* @__PURE__ */ new Map());
92
105
  }
93
- async setDocument(drive, id, document) {
94
- var _a2;
95
- const global2 = document.operations.global.map((e) => {
96
- delete e.resultingState;
97
- return e;
98
- });
99
- const local = document.operations.local.map((e) => {
100
- delete e.resultingState;
101
- return e;
102
- });
103
- const doc = { ...document, operations: { global: global2, local } };
104
- if (!this.cache.has(drive)) {
105
- this.cache.set(drive, /* @__PURE__ */ new Map());
106
+ clear() {
107
+ this.idTodocument.clear();
108
+ this.idToDrive.clear();
109
+ this.slugToDriveId.clear();
110
+ }
111
+ /////////////////////////////////////////////////////////////////////////////
112
+ // ICache
113
+ /////////////////////////////////////////////////////////////////////////////
114
+ async setDocument(documentId, document) {
115
+ const doc = trimResultingState(document);
116
+ this.idTodocument.set(documentId, doc);
117
+ }
118
+ async getDocument(documentId) {
119
+ return this.idTodocument.get(documentId);
120
+ }
121
+ async deleteDocument(documentId) {
122
+ return this.idTodocument.delete(documentId);
123
+ }
124
+ async setDrive(driveId, drive) {
125
+ const doc = trimResultingState(drive);
126
+ this.idToDrive.set(driveId, doc);
127
+ }
128
+ async getDrive(driveId) {
129
+ return this.idToDrive.get(driveId);
130
+ }
131
+ async deleteDrive(driveId) {
132
+ const drive = this.idToDrive.get(driveId);
133
+ if (!drive) {
134
+ return false;
106
135
  }
107
- (_a2 = this.cache.get(drive)) == null ? void 0 : _a2.set(id, doc);
108
- return true;
136
+ const slug = drive.state.global.slug;
137
+ if (slug) {
138
+ this.slugToDriveId.delete(slug);
139
+ }
140
+ return this.idToDrive.delete(driveId);
109
141
  }
110
- async deleteDocument(drive, id) {
111
- var _a2;
112
- return ((_a2 = this.cache.get(drive)) == null ? void 0 : _a2.delete(id)) ?? false;
142
+ async setDriveBySlug(slug, drive) {
143
+ const driveId = drive.state.global.id;
144
+ this.slugToDriveId.set(slug, driveId);
145
+ this.setDrive(driveId, drive);
113
146
  }
114
- async getDocument(drive, id) {
115
- var _a2;
116
- return (_a2 = this.cache.get(drive)) == null ? void 0 : _a2.get(id);
147
+ async getDriveBySlug(slug) {
148
+ const driveId = this.slugToDriveId.get(slug);
149
+ if (!driveId) {
150
+ return void 0;
151
+ }
152
+ return this.getDrive(driveId);
153
+ }
154
+ async deleteDriveBySlug(slug) {
155
+ const driveId = this.slugToDriveId.get(slug);
156
+ if (!driveId) {
157
+ return false;
158
+ }
159
+ this.slugToDriveId.delete(slug);
160
+ return this.deleteDrive(driveId);
117
161
  }
118
162
  }
119
163
  const K = [
@@ -22473,7 +22517,14 @@ class DefaultDrivesManager {
22473
22517
  }
22474
22518
  const PULL_DRIVE_INTERVAL = 1500;
22475
22519
  const MAX_REVISIONS_PER_ACK = 100;
22476
- const _PullResponderTransmitter = class _PullResponderTransmitter {
22520
+ let _staticLogger;
22521
+ const staticLogger = () => {
22522
+ if (!_staticLogger) {
22523
+ _staticLogger = childLogger(["PullResponderTransmitter", "static"]);
22524
+ }
22525
+ return _staticLogger;
22526
+ };
22527
+ class PullResponderTransmitter {
22477
22528
  constructor(listener, manager) {
22478
22529
  __publicField(this, "logger", childLogger([
22479
22530
  "PullResponderTransmitter",
@@ -22486,8 +22537,18 @@ const _PullResponderTransmitter = class _PullResponderTransmitter {
22486
22537
  this.logger.verbose(`constructor(listener: ${listener.listenerId})`);
22487
22538
  }
22488
22539
  getStrands(options) {
22489
- this.logger.verbose(`getStrands(drive: ${this.listener.driveId}, listener: ${this.listener.listenerId})`);
22490
- return this.manager.getStrands(this.listener.driveId, this.listener.listenerId, options);
22540
+ this.logger.verbose(`[SYNC DEBUG] PullResponderTransmitter.getStrands called for drive: ${this.listener.driveId}, listener: ${this.listener.listenerId}, options: ${JSON.stringify(options || {})}`);
22541
+ return this.manager.getStrands(this.listener.driveId, this.listener.listenerId, options).then((strands) => {
22542
+ this.logger.verbose(`[SYNC DEBUG] PullResponderTransmitter.getStrands returning ${strands.length} strands for drive: ${this.listener.driveId}, listener: ${this.listener.listenerId}`);
22543
+ if (strands.length === 0) {
22544
+ this.logger.verbose(`[SYNC DEBUG] No strands returned for drive: ${this.listener.driveId}, listener: ${this.listener.listenerId}`);
22545
+ } else {
22546
+ for (const strand of strands) {
22547
+ this.logger.verbose(`[SYNC DEBUG] Strand for drive: ${strand.driveId}, document: ${strand.documentId}, scope: ${strand.scope}, operations: ${strand.operations.length}`);
22548
+ }
22549
+ }
22550
+ return strands;
22551
+ });
22491
22552
  }
22492
22553
  disconnect() {
22493
22554
  return Promise.resolve();
@@ -22497,7 +22558,7 @@ const _PullResponderTransmitter = class _PullResponderTransmitter {
22497
22558
  const syncUnits = await this.manager.getListenerSyncUnitIds(driveId, listenerId);
22498
22559
  let success = true;
22499
22560
  for (const revision of revisions) {
22500
- const syncUnit = syncUnits.find((s) => s.scope === revision.scope && s.branch === revision.branch && s.driveId === revision.driveId && s.documentId == revision.documentId);
22561
+ const syncUnit = syncUnits.find((s) => s.scope === revision.scope && s.branch === revision.branch && s.documentId == revision.documentId);
22501
22562
  if (!syncUnit) {
22502
22563
  this.logger.warn("Unknown sync unit was acknowledged", revision);
22503
22564
  success = false;
@@ -22507,16 +22568,22 @@ const _PullResponderTransmitter = class _PullResponderTransmitter {
22507
22568
  }
22508
22569
  return success;
22509
22570
  }
22510
- static async registerPullResponder(driveId, url, filter) {
22571
+ static async registerPullResponder(driveId, url, filter, listenerId) {
22511
22572
  var _a2;
22512
- _PullResponderTransmitter.staticLogger.verbose(`registerPullResponder(url: ${url})`, filter);
22573
+ staticLogger().verbose(`registerPullResponder(url: ${url})`, filter);
22513
22574
  const result = await requestGraphql(url, gql`
22514
- mutation registerPullResponderListener($filter: InputListenerFilter!) {
22515
- registerPullResponderListener(filter: $filter) {
22575
+ mutation registerPullResponderListener(
22576
+ $filter: InputListenerFilter!
22577
+ $listenerId: String
22578
+ ) {
22579
+ registerPullResponderListener(
22580
+ filter: $filter
22581
+ listenerId: $listenerId
22582
+ ) {
22516
22583
  listenerId
22517
22584
  }
22518
22585
  }
22519
- `, { filter });
22586
+ `, { filter, listenerId });
22520
22587
  const error = (_a2 = result.errors) == null ? void 0 : _a2.at(0);
22521
22588
  if (error) {
22522
22589
  throw error;
@@ -22528,7 +22595,7 @@ const _PullResponderTransmitter = class _PullResponderTransmitter {
22528
22595
  }
22529
22596
  static async pullStrands(driveId, url, listenerId, options) {
22530
22597
  var _a2;
22531
- this.staticLogger.verbose(`pullStrands(url: ${url}, listener: ${listenerId})`);
22598
+ staticLogger().verbose(`[SYNC DEBUG] PullResponderTransmitter.pullStrands called for drive: ${driveId}, url: ${url}, listener: ${listenerId}, options: ${JSON.stringify(options || {})}`);
22532
22599
  const result = await requestGraphql(url, gql`
22533
22600
  query strands($listenerId: ID!) {
22534
22601
  system {
@@ -22568,27 +22635,34 @@ const _PullResponderTransmitter = class _PullResponderTransmitter {
22568
22635
  `, { listenerId });
22569
22636
  const error = (_a2 = result.errors) == null ? void 0 : _a2.at(0);
22570
22637
  if (error) {
22638
+ staticLogger().verbose(`[SYNC DEBUG] Error pulling strands for drive: ${driveId}, listener: ${listenerId}, error: ${JSON.stringify(error)}`);
22571
22639
  throw error;
22572
22640
  }
22573
22641
  if (!result.system) {
22642
+ staticLogger().verbose(`[SYNC DEBUG] No system data returned when pulling strands for drive: ${driveId}, listener: ${listenerId}`);
22574
22643
  return [];
22575
22644
  }
22576
- return result.system.sync.strands.map((s) => ({
22645
+ const strands = result.system.sync.strands.map((s) => ({
22577
22646
  ...s,
22578
22647
  operations: s.operations.map((o) => ({
22579
22648
  ...o,
22580
22649
  input: JSON.parse(o.input)
22581
22650
  }))
22582
22651
  }));
22652
+ staticLogger().verbose(`[SYNC DEBUG] PullResponderTransmitter.pullStrands returning ${strands.length} strands for drive: ${driveId}, listener: ${listenerId}`);
22653
+ if (strands.length > 0) {
22654
+ staticLogger().verbose(`[SYNC DEBUG] Strands being returned: ${strands.map((s) => `${s.documentId}:${s.scope}`).join(", ")}`);
22655
+ }
22656
+ return strands;
22583
22657
  }
22584
22658
  static async acknowledgeStrands(url, listenerId, revisions) {
22585
- this.staticLogger.verbose(`acknowledgeStrands(url: ${url}, listener: ${listenerId})`, revisions);
22659
+ staticLogger().verbose(`acknowledgeStrands(url: ${url}, listener: ${listenerId})`, revisions);
22586
22660
  const chunks = [];
22587
22661
  for (let i = 0; i < revisions.length; i += MAX_REVISIONS_PER_ACK) {
22588
22662
  chunks.push(revisions.slice(i, i + MAX_REVISIONS_PER_ACK));
22589
22663
  }
22590
22664
  if (chunks.length > 1) {
22591
- this.staticLogger.verbose(`Breaking strand acknowledgement into ${chunks.length} chunks...`);
22665
+ staticLogger().verbose(`Breaking strand acknowledgement into ${chunks.length} chunks...`);
22592
22666
  }
22593
22667
  const results = await Promise.allSettled(chunks.map(async (chunk) => {
22594
22668
  var _a2;
@@ -22613,75 +22687,125 @@ const _PullResponderTransmitter = class _PullResponderTransmitter {
22613
22687
  throw new Error("Error acknowledging strands");
22614
22688
  }
22615
22689
  }
22690
+ /**
22691
+ * This function will only throw if `onError` throws an error (or there is
22692
+ * an unintentionally unhandled error in the pull loop).
22693
+ *
22694
+ * All other errors are caught, logged, and passed to `onError`.
22695
+ *
22696
+ * Because of this, `onError` _may be called multiple times_.
22697
+ */
22616
22698
  static async executePull(driveId, trigger, onStrandUpdate, onError, onRevisions, onAcknowledge) {
22617
- var _a2;
22618
- this.staticLogger.verbose(`executePull(driveId: ${driveId}), trigger:`, trigger);
22699
+ var _a2, _b;
22700
+ staticLogger().verbose(`executePull(driveId: ${driveId}), trigger:`, trigger);
22701
+ staticLogger().info(`[SYNC DEBUG] PullResponderTransmitter.executePull starting for drive: ${driveId}, listenerId: ${trigger.data.listenerId}`);
22702
+ const { url } = trigger.data;
22703
+ let strands;
22704
+ let error;
22705
+ const listenerId = trigger.data.listenerId;
22619
22706
  try {
22620
- const { url, listenerId } = trigger.data;
22621
- const strands = await _PullResponderTransmitter.pullStrands(driveId, url, listenerId);
22622
- this.staticLogger.verbose("Pulled strands...");
22623
- if (!strands.length) {
22624
- onRevisions == null ? void 0 : onRevisions([]);
22625
- this.staticLogger.verbose("No new strands, skipping...");
22626
- return;
22627
- }
22628
- const listenerRevisions = [];
22629
- for (const strand of strands) {
22630
- const operations = strand.operations.map((op) => ({
22631
- ...op,
22632
- scope: strand.scope,
22633
- branch: strand.branch
22634
- }));
22635
- this.staticLogger.verbose("Processing strand...");
22636
- let error = void 0;
22637
- try {
22638
- const result = await onStrandUpdate(strand, {
22639
- type: "trigger",
22640
- trigger
22641
- });
22642
- if (result.error) {
22643
- throw result.error;
22707
+ strands = await PullResponderTransmitter.pullStrands(driveId, url, listenerId);
22708
+ } catch (e) {
22709
+ error = e;
22710
+ const graphqlError = error;
22711
+ const errors = ((_a2 = graphqlError.response) == null ? void 0 : _a2.errors) ?? [];
22712
+ for (const err of errors) {
22713
+ if (err.message === "Listener not found") {
22714
+ staticLogger().verbose(`[SYNC DEBUG] Auto-registering pull responder for drive: ${driveId}`);
22715
+ await PullResponderTransmitter.registerPullResponder(trigger.driveId, url, trigger.filter, listenerId);
22716
+ try {
22717
+ strands = await PullResponderTransmitter.pullStrands(driveId, url, listenerId);
22718
+ staticLogger().verbose(`Successfully auto-registered and pulled strands for drive: ${driveId}, listenerId: ${listenerId}`);
22719
+ } catch (error2) {
22720
+ staticLogger().error(`Could not resolve 'Listener not found' error by registering a new pull responder for drive: ${driveId}, listenerId: ${listenerId}: ${error2}`);
22721
+ onError(error2);
22722
+ return;
22644
22723
  }
22645
- } catch (e) {
22646
- error = e;
22647
- onError(error);
22724
+ break;
22648
22725
  }
22649
- listenerRevisions.push({
22650
- branch: strand.branch,
22651
- documentId: strand.documentId || "",
22652
- driveId: strand.driveId,
22653
- revision: ((_a2 = operations.pop()) == null ? void 0 : _a2.index) ?? -1,
22654
- scope: strand.scope,
22655
- status: error ? error instanceof OperationError ? error.status : "ERROR" : "SUCCESS",
22656
- error
22657
- });
22658
22726
  }
22659
- this.staticLogger.verbose("Processed strands...");
22660
- onRevisions == null ? void 0 : onRevisions(listenerRevisions);
22661
- this.staticLogger.verbose("Acknowledging strands...");
22662
- let success = false;
22727
+ }
22728
+ if (!strands) {
22729
+ staticLogger().error(`Error pulling strands for drive, and could not auto-register: ${driveId}, listenerId: ${trigger.data.listenerId}: ${error}`);
22730
+ onError(error);
22731
+ return;
22732
+ }
22733
+ if (!strands.length) {
22734
+ staticLogger().verbose(`[SYNC DEBUG] No strands returned in pull cycle for drive: ${driveId}, listenerId: ${trigger.data.listenerId}`);
22663
22735
  try {
22664
- await _PullResponderTransmitter.acknowledgeStrands(url, listenerId, listenerRevisions.map((revision) => {
22665
- const { error, ...rest } = revision;
22666
- return rest;
22667
- }));
22668
- success = true;
22669
- } catch (error) {
22670
- this.staticLogger.error("ACK error", error);
22671
- }
22672
- if (success) {
22673
- this.staticLogger.verbose("Acknowledged strands successfully.");
22674
- } else {
22675
- this.staticLogger.error("Failed to acknowledge strands");
22736
+ onRevisions == null ? void 0 : onRevisions([]);
22737
+ } catch (error2) {
22738
+ staticLogger().error(`Error calling onRevisions for drive: ${driveId}, listenerId: ${trigger.data.listenerId}: ${error2}`);
22739
+ onError(error2);
22676
22740
  }
22741
+ return;
22742
+ }
22743
+ staticLogger().verbose(`[SYNC DEBUG] Processing ${strands.length} strands in pull cycle for drive: ${driveId}, listenerId: ${trigger.data.listenerId}`);
22744
+ const listenerRevisions = [];
22745
+ for (const strand of strands) {
22746
+ const operations = strand.operations.map((op) => ({
22747
+ ...op,
22748
+ scope: strand.scope,
22749
+ branch: strand.branch
22750
+ }));
22751
+ staticLogger().verbose(`[SYNC DEBUG] Processing strand for drive: ${strand.driveId}, document: ${strand.documentId}, scope: ${strand.scope}, with ${operations.length} operations`);
22752
+ let error2 = void 0;
22753
+ try {
22754
+ const result = await onStrandUpdate(strand, {
22755
+ type: "trigger",
22756
+ trigger
22757
+ });
22758
+ if (result.error) {
22759
+ throw result.error;
22760
+ }
22761
+ } catch (e) {
22762
+ staticLogger().error(`Error processing strand for drive: ${strand.driveId}, document: ${strand.documentId}, scope: ${strand.scope}, with ${operations.length} operations: ${e}`);
22763
+ error2 = e;
22764
+ onError(error2);
22765
+ }
22766
+ listenerRevisions.push({
22767
+ branch: strand.branch,
22768
+ documentId: strand.documentId || "",
22769
+ driveId: strand.driveId,
22770
+ revision: ((_b = operations.pop()) == null ? void 0 : _b.index) ?? -1,
22771
+ scope: strand.scope,
22772
+ status: error2 ? error2 instanceof OperationError ? error2.status : "ERROR" : "SUCCESS",
22773
+ error: error2
22774
+ });
22775
+ }
22776
+ staticLogger().verbose("Processed strands...");
22777
+ try {
22778
+ onRevisions == null ? void 0 : onRevisions(listenerRevisions);
22779
+ } catch (error2) {
22780
+ staticLogger().error(`Error calling onRevisions for drive: ${driveId}, listenerId: ${trigger.data.listenerId}: ${error2}`);
22781
+ onError(error2);
22782
+ }
22783
+ staticLogger().verbose(`[SYNC DEBUG] Acknowledging ${listenerRevisions.length} strands for drive: ${driveId}, listenerId: ${trigger.data.listenerId}`);
22784
+ let success = false;
22785
+ try {
22786
+ await PullResponderTransmitter.acknowledgeStrands(url, trigger.data.listenerId, listenerRevisions.map((revision) => {
22787
+ const { error: error2, ...rest } = revision;
22788
+ return rest;
22789
+ }));
22790
+ success = true;
22791
+ } catch (error2) {
22792
+ staticLogger().error(`Error acknowledging strands for drive: ${driveId}, listenerId: ${trigger.data.listenerId}: ${error2}`);
22793
+ onError(error2);
22794
+ }
22795
+ if (success) {
22796
+ staticLogger().verbose(`[SYNC DEBUG] Successfully acknowledged strands for drive: ${driveId}, listenerId: ${trigger.data.listenerId}`);
22797
+ } else {
22798
+ staticLogger().error("Failed to acknowledge strands");
22799
+ }
22800
+ try {
22677
22801
  onAcknowledge == null ? void 0 : onAcknowledge(success);
22678
- } catch (error) {
22679
- this.staticLogger.error("Pull error", error);
22680
- onError(error);
22802
+ } catch (error2) {
22803
+ staticLogger().error(`Error calling onAcknowledge for drive: ${driveId}, listenerId: ${trigger.data.listenerId}: ${error2}`);
22804
+ onError(error2);
22681
22805
  }
22682
22806
  }
22683
22807
  static setupPull(driveId, trigger, onStrandUpdate, onError, onRevisions, onAcknowledge) {
22684
- this.staticLogger.verbose(`setupPull(drive: ${driveId}), trigger:`, trigger);
22808
+ staticLogger().verbose(`[SYNC DEBUG] PullResponderTransmitter.setupPull initiated for drive: ${driveId}, listenerId: ${trigger.data.listenerId}`);
22685
22809
  const { interval } = trigger.data;
22686
22810
  let loopInterval = PULL_DRIVE_INTERVAL;
22687
22811
  if (interval) {
@@ -22693,20 +22817,25 @@ const _PullResponderTransmitter = class _PullResponderTransmitter {
22693
22817
  } catch {
22694
22818
  }
22695
22819
  }
22820
+ staticLogger().verbose(`[SYNC DEBUG] Pull interval set to ${loopInterval}ms for drive: ${driveId}, listenerId: ${trigger.data.listenerId}`);
22696
22821
  let isCancelled = false;
22697
22822
  let timeout;
22698
22823
  const executeLoop = async () => {
22699
22824
  while (!isCancelled) {
22700
- this.staticLogger.verbose("Execute loop...");
22825
+ staticLogger().verbose(`[SYNC DEBUG] Starting pull cycle for drive: ${driveId}, listenerId: ${trigger.data.listenerId}`);
22701
22826
  await this.executePull(driveId, trigger, onStrandUpdate, onError, onRevisions, onAcknowledge);
22827
+ staticLogger().verbose(`[SYNC DEBUG] Completed pull cycle for drive: ${driveId}, listenerId: ${trigger.data.listenerId}, waiting ${loopInterval}ms for next cycle`);
22702
22828
  await new Promise((resolve) => {
22703
- this.staticLogger.verbose(`Scheduling next pull in ${loopInterval} ms`);
22829
+ staticLogger().verbose(`Scheduling next pull in ${loopInterval} ms`);
22704
22830
  timeout = setTimeout(resolve, loopInterval);
22705
22831
  });
22706
22832
  }
22707
22833
  };
22708
- executeLoop().catch(this.staticLogger.error);
22834
+ executeLoop().catch((error) => {
22835
+ staticLogger().error(`Error in executeLoop for drive: ${driveId}, listenerId: ${trigger.data.listenerId}: ${error}`);
22836
+ });
22709
22837
  return () => {
22838
+ staticLogger().verbose(`[SYNC DEBUG] Cancelling pull loop for drive: ${driveId}, listenerId: ${trigger.data.listenerId}`);
22710
22839
  isCancelled = true;
22711
22840
  if (timeout !== void 0) {
22712
22841
  clearTimeout(timeout);
@@ -22714,17 +22843,20 @@ const _PullResponderTransmitter = class _PullResponderTransmitter {
22714
22843
  };
22715
22844
  }
22716
22845
  static async createPullResponderTrigger(driveId, url, options) {
22717
- this.staticLogger.verbose(`createPullResponderTrigger(drive: ${driveId}, url: ${url})`);
22846
+ staticLogger().verbose(`createPullResponderTrigger(drive: ${driveId}, url: ${url})`);
22718
22847
  const { pullFilter, pullInterval } = options;
22719
- const listenerId = await _PullResponderTransmitter.registerPullResponder(driveId, url, pullFilter ?? {
22848
+ const filter = pullFilter ?? {
22720
22849
  documentId: ["*"],
22721
22850
  documentType: ["*"],
22722
22851
  branch: ["*"],
22723
22852
  scope: ["*"]
22724
- });
22853
+ };
22854
+ const listenerId = await PullResponderTransmitter.registerPullResponder(driveId, url, filter);
22725
22855
  const pullTrigger = {
22726
22856
  id: generateUUID(),
22727
22857
  type: "PullResponder",
22858
+ driveId,
22859
+ filter,
22728
22860
  data: {
22729
22861
  url,
22730
22862
  listenerId,
@@ -22736,142 +22868,307 @@ const _PullResponderTransmitter = class _PullResponderTransmitter {
22736
22868
  static isPullResponderTrigger(trigger) {
22737
22869
  return trigger.type === "PullResponder";
22738
22870
  }
22739
- };
22740
- __publicField(_PullResponderTransmitter, "staticLogger", childLogger([
22741
- "PullResponderTransmitter",
22742
- "static"
22743
- ]));
22744
- let PullResponderTransmitter = _PullResponderTransmitter;
22745
- var TransmitterType;
22746
- (function(TransmitterType2) {
22747
- TransmitterType2[TransmitterType2["Internal"] = 0] = "Internal";
22748
- TransmitterType2[TransmitterType2["SwitchboardPush"] = 1] = "SwitchboardPush";
22749
- TransmitterType2[TransmitterType2["PullResponder"] = 2] = "PullResponder";
22750
- TransmitterType2[TransmitterType2["SecureConnect"] = 3] = "SecureConnect";
22751
- TransmitterType2[TransmitterType2["MatrixConnect"] = 4] = "MatrixConnect";
22752
- TransmitterType2[TransmitterType2["RESTWebhook"] = 5] = "RESTWebhook";
22753
- })(TransmitterType || (TransmitterType = {}));
22754
- const DefaultListenerManagerOptions = {
22755
- sequentialUpdates: true
22756
- };
22757
- function filterOperationsByRevision(operations, revisions) {
22758
- if (!revisions) {
22759
- return operations;
22760
- }
22761
- return Object.keys(operations).reduce((acc, scope) => {
22762
- const revision = revisions[scope];
22763
- if (revision !== void 0) {
22764
- acc[scope] = operations[scope].filter((op) => op.index <= revision);
22765
- }
22766
- return acc;
22767
- }, { global: [], local: [] });
22768
22871
  }
22769
- function isAtRevision(document, revisions) {
22770
- return !revisions || Object.entries(revisions).find(([scope, revision]) => {
22771
- const operation = document.operations[scope].at(-1);
22772
- if (revision === -1) {
22773
- return operation !== void 0;
22774
- }
22775
- return (operation == null ? void 0 : operation.index) !== revision;
22776
- }) === void 0;
22872
+ var defaults;
22873
+ var hasRequiredDefaults;
22874
+ function requireDefaults() {
22875
+ if (hasRequiredDefaults) return defaults;
22876
+ hasRequiredDefaults = 1;
22877
+ defaults = {
22878
+ space: "",
22879
+ cycles: false,
22880
+ replacer: (k, v) => v,
22881
+ stringify: JSON.stringify
22882
+ };
22883
+ return defaults;
22777
22884
  }
22778
- class BaseDocumentDriveServer {
22779
- constructor(documentModelModules, storage, documentStorage, cache, queueManager, eventEmitter, synchronizationManager, listenerManager, options) {
22780
- // external dependencies
22781
- __publicField(this, "documentModelModules");
22782
- __publicField(this, "storage");
22783
- __publicField(this, "documentStorage");
22784
- __publicField(this, "cache");
22785
- __publicField(this, "queueManager");
22786
- __publicField(this, "eventEmitter");
22787
- __publicField(this, "options");
22788
- __publicField(this, "listenerManager");
22789
- __publicField(this, "synchronizationManager");
22790
- // internal dependencies
22791
- __publicField(this, "defaultDrivesManager");
22792
- __publicField(this, "defaultDrivesManagerDelegate", {
22793
- detachDrive: this.detachDrive.bind(this),
22794
- emit: (...args) => this.eventEmitter.emit("defaultRemoteDrive", ...args)
22795
- });
22796
- __publicField(this, "queueDelegate", {
22797
- checkDocumentExists: (documentId) => this.documentStorage.exists(documentId),
22798
- processOperationJob: async ({ driveId, documentId, operations, options }) => {
22799
- return documentId ? this.addOperations(driveId, documentId, operations, options) : this.addDriveOperations(driveId, operations, options);
22800
- },
22801
- processActionJob: async ({ driveId, documentId, actions: actions2, options }) => {
22802
- return documentId ? this.addActions(driveId, documentId, actions2, options) : this.addDriveActions(driveId, actions2, options);
22803
- },
22804
- processJob: async (job) => {
22805
- if (isOperationJob(job)) {
22806
- return this.queueDelegate.processOperationJob(job);
22807
- } else if (isActionJob(job)) {
22808
- return this.queueDelegate.processActionJob(job);
22809
- } else {
22810
- throw new Error("Unknown job type", job);
22811
- }
22812
- }
22813
- });
22814
- // internal state
22815
- __publicField(this, "triggerMap", /* @__PURE__ */ new Map());
22816
- __publicField(this, "initializePromise");
22817
- var _a2, _b;
22818
- this.documentModelModules = documentModelModules;
22819
- this.storage = storage;
22820
- this.documentStorage = documentStorage;
22821
- this.cache = cache;
22822
- this.queueManager = queueManager;
22823
- this.eventEmitter = eventEmitter;
22824
- this.synchronizationManager = synchronizationManager;
22825
- this.listenerManager = listenerManager;
22826
- this.options = {
22827
- ...options,
22828
- defaultDrives: {
22829
- ...options == null ? void 0 : options.defaultDrives
22830
- },
22831
- listenerManager: {
22832
- ...DefaultListenerManagerOptions,
22833
- ...options == null ? void 0 : options.listenerManager
22834
- },
22835
- taskQueueMethod: (options == null ? void 0 : options.taskQueueMethod) === void 0 ? RunAsap.runAsap : options.taskQueueMethod
22836
- };
22837
- this.defaultDrivesManager = new DefaultDrivesManager(this, this.defaultDrivesManagerDelegate, options);
22838
- (_b = (_a2 = this.storage).setStorageDelegate) == null ? void 0 : _b.call(_a2, {
22839
- getCachedOperations: async (drive, id) => {
22840
- try {
22841
- const document = await this.cache.getDocument(drive, id);
22842
- return document == null ? void 0 : document.operations;
22843
- } catch (error) {
22844
- logger$1.error(error);
22845
- return void 0;
22846
- }
22847
- }
22848
- });
22849
- this.initializePromise = this._initialize();
22850
- }
22851
- // workaround for testing the ephemeral listeners -- we don't have DI in place yet
22852
- // todo: remove this once we have DI
22853
- get listeners() {
22854
- return this.listenerManager;
22855
- }
22856
- initialize() {
22857
- return this.initializePromise;
22885
+ var util;
22886
+ var hasRequiredUtil;
22887
+ function requireUtil() {
22888
+ if (hasRequiredUtil) return util;
22889
+ hasRequiredUtil = 1;
22890
+ util = {
22891
+ isArray: Array.isArray,
22892
+ assign: Object.assign,
22893
+ isObject: (v) => typeof v === "object",
22894
+ isFunction: (v) => typeof v === "function",
22895
+ isBoolean: (v) => typeof v === "boolean",
22896
+ isRegex: (v) => v instanceof RegExp,
22897
+ keys: Object.keys
22898
+ };
22899
+ return util;
22900
+ }
22901
+ var lib;
22902
+ var hasRequiredLib;
22903
+ function requireLib() {
22904
+ if (hasRequiredLib) return lib;
22905
+ hasRequiredLib = 1;
22906
+ const DEFAULTS = requireDefaults();
22907
+ const isFunction = requireUtil().isFunction;
22908
+ const isBoolean = requireUtil().isBoolean;
22909
+ const isObject = requireUtil().isObject;
22910
+ const isArray = requireUtil().isArray;
22911
+ const isRegex = requireUtil().isRegex;
22912
+ const assign = requireUtil().assign;
22913
+ const keys = requireUtil().keys;
22914
+ function serialize(obj) {
22915
+ if (obj === null || obj === void 0) return obj;
22916
+ if (isRegex(obj)) return obj.toString();
22917
+ return obj.toJSON ? obj.toJSON() : obj;
22858
22918
  }
22859
- async _initialize() {
22860
- await this.listenerManager.initialize(this.handleListenerError);
22861
- await this.queueManager.init(this.queueDelegate, (error) => {
22862
- logger$1.error(`Error initializing queue manager`, error);
22863
- errors.push(error);
22864
- });
22919
+ function stringifyDeterministic(obj, opts) {
22920
+ opts = opts || assign({}, DEFAULTS);
22921
+ if (isFunction(opts)) opts = { compare: opts };
22922
+ const space = opts.space || DEFAULTS.space;
22923
+ const cycles = isBoolean(opts.cycles) ? opts.cycles : DEFAULTS.cycles;
22924
+ const replacer = opts.replacer || DEFAULTS.replacer;
22925
+ const stringify2 = opts.stringify || DEFAULTS.stringify;
22926
+ const compare = opts.compare && /* @__PURE__ */ function(f) {
22927
+ return function(node) {
22928
+ return function(a, b) {
22929
+ const aobj = { key: a, value: node[a] };
22930
+ const bobj = { key: b, value: node[b] };
22931
+ return f(aobj, bobj);
22932
+ };
22933
+ };
22934
+ }(opts.compare);
22935
+ if (!cycles) stringify2(obj);
22936
+ const seen = [];
22937
+ return function _deterministic(parent, key, node, level) {
22938
+ const indent2 = space ? "\n" + new Array(level + 1).join(space) : "";
22939
+ const colonSeparator = space ? ": " : ":";
22940
+ node = serialize(node);
22941
+ node = replacer.call(parent, key, node);
22942
+ if (node === void 0) return;
22943
+ if (!isObject(node) || node === null) return stringify2(node);
22944
+ if (isArray(node)) {
22945
+ const out = [];
22946
+ for (let i = 0; i < node.length; i++) {
22947
+ const item = _deterministic(node, i, node[i], level + 1) || stringify2(null);
22948
+ out.push(indent2 + space + item);
22949
+ }
22950
+ return "[" + out.join(",") + indent2 + "]";
22951
+ } else {
22952
+ if (cycles) {
22953
+ if (seen.indexOf(node) !== -1) {
22954
+ return stringify2("[Circular]");
22955
+ } else {
22956
+ seen.push(node);
22957
+ }
22958
+ }
22959
+ const nodeKeys = keys(node).sort(compare && compare(node));
22960
+ const out = [];
22961
+ for (let i = 0; i < nodeKeys.length; i++) {
22962
+ const key2 = nodeKeys[i];
22963
+ const value = _deterministic(node, key2, node[key2], level + 1);
22964
+ if (!value) continue;
22965
+ const keyValue = stringify2(key2) + colonSeparator + value;
22966
+ out.push(indent2 + space + keyValue);
22967
+ }
22968
+ seen.splice(seen.indexOf(node), 1);
22969
+ return "{" + out.join(",") + indent2 + "}";
22970
+ }
22971
+ }({ "": obj }, "", obj, 0);
22972
+ }
22973
+ lib = stringifyDeterministic;
22974
+ return lib;
22975
+ }
22976
+ var libExports = requireLib();
22977
+ const stringify = /* @__PURE__ */ getDefaultExportFromCjs(libExports);
22978
+ const SYNC_OPS_BATCH_LIMIT = 10;
22979
+ class SwitchboardPushTransmitter {
22980
+ constructor(targetURL) {
22981
+ __publicField(this, "targetURL");
22982
+ __publicField(this, "logger", childLogger([
22983
+ "SwitchboardPushTransmitter",
22984
+ Math.floor(Math.random() * 999).toString()
22985
+ ]));
22986
+ this.targetURL = targetURL;
22987
+ }
22988
+ async transmit(strands, source) {
22989
+ var _a2;
22990
+ if (source.type === "trigger" && ((_a2 = source.trigger.data) == null ? void 0 : _a2.url) === this.targetURL) {
22991
+ this.logger.verbose(`Cutting trigger loop from ${this.targetURL}.`);
22992
+ return strands.map((strand) => {
22993
+ var _a3;
22994
+ return {
22995
+ driveId: strand.driveId,
22996
+ documentId: strand.documentId,
22997
+ scope: strand.scope,
22998
+ branch: strand.branch,
22999
+ status: "SUCCESS",
23000
+ revision: ((_a3 = strand.operations.at(-1)) == null ? void 0 : _a3.index) ?? -1
23001
+ };
23002
+ });
23003
+ }
23004
+ const culledStrands = [];
23005
+ let opsCounter = 0;
23006
+ for (let s = 0; opsCounter <= SYNC_OPS_BATCH_LIMIT && s < strands.length; s++) {
23007
+ const currentStrand = strands.at(s);
23008
+ if (!currentStrand) {
23009
+ break;
23010
+ }
23011
+ const newOps = Math.min(SYNC_OPS_BATCH_LIMIT - opsCounter, currentStrand.operations.length);
23012
+ culledStrands.push({
23013
+ ...currentStrand,
23014
+ operations: currentStrand.operations.slice(0, newOps)
23015
+ });
23016
+ opsCounter += newOps;
23017
+ }
23018
+ this.logger.verbose(` Total update: [${strands.map((s) => s.operations.length).join(", ")}] operations`);
23019
+ this.logger.verbose(`Culled update: [${culledStrands.map((s) => s.operations.length).join(", ")}] operations`);
23020
+ try {
23021
+ const { pushUpdates } = await requestGraphql(this.targetURL, gql`
23022
+ mutation pushUpdates($strands: [InputStrandUpdate!]) {
23023
+ pushUpdates(strands: $strands) {
23024
+ driveId
23025
+ documentId
23026
+ scope
23027
+ branch
23028
+ status
23029
+ revision
23030
+ error
23031
+ }
23032
+ }
23033
+ `, {
23034
+ strands: culledStrands.map((strand) => ({
23035
+ ...strand,
23036
+ operations: strand.operations.map((op) => ({
23037
+ ...op,
23038
+ input: stringify(op.input)
23039
+ }))
23040
+ }))
23041
+ });
23042
+ if (!pushUpdates) {
23043
+ throw new Error("Couldn't update listener revision");
23044
+ }
23045
+ return pushUpdates;
23046
+ } catch (e) {
23047
+ this.logger.error(e);
23048
+ throw e;
23049
+ }
23050
+ return [];
23051
+ }
23052
+ }
23053
+ var TransmitterType;
23054
+ (function(TransmitterType2) {
23055
+ TransmitterType2[TransmitterType2["Internal"] = 0] = "Internal";
23056
+ TransmitterType2[TransmitterType2["SwitchboardPush"] = 1] = "SwitchboardPush";
23057
+ TransmitterType2[TransmitterType2["PullResponder"] = 2] = "PullResponder";
23058
+ TransmitterType2[TransmitterType2["SecureConnect"] = 3] = "SecureConnect";
23059
+ TransmitterType2[TransmitterType2["MatrixConnect"] = 4] = "MatrixConnect";
23060
+ TransmitterType2[TransmitterType2["RESTWebhook"] = 5] = "RESTWebhook";
23061
+ })(TransmitterType || (TransmitterType = {}));
23062
+ const DefaultListenerManagerOptions = {
23063
+ sequentialUpdates: true
23064
+ };
23065
+ function filterOperationsByRevision(operations, revisions) {
23066
+ if (!revisions) {
23067
+ return operations;
23068
+ }
23069
+ return Object.keys(operations).reduce((acc, scope) => {
23070
+ const revision = revisions[scope];
23071
+ if (revision !== void 0) {
23072
+ acc[scope] = operations[scope].filter((op) => op.index <= revision);
23073
+ }
23074
+ return acc;
23075
+ }, { global: [], local: [] });
23076
+ }
23077
+ function isAtRevision(document, revisions) {
23078
+ return !revisions || Object.entries(revisions).find(([scope, revision]) => {
23079
+ const operation = document.operations[scope].at(-1);
23080
+ if (revision === -1) {
23081
+ return operation !== void 0;
23082
+ }
23083
+ return (operation == null ? void 0 : operation.index) !== revision;
23084
+ }) === void 0;
23085
+ }
23086
+ class BaseDocumentDriveServer {
23087
+ constructor(documentModelModules, storage, documentStorage, cache, queueManager, eventEmitter, synchronizationManager, listenerManager, options) {
23088
+ __publicField(this, "logger", childLogger(["BaseDocumentDriveServer"]));
23089
+ // external dependencies
23090
+ __publicField(this, "documentModelModules");
23091
+ __publicField(this, "storage");
23092
+ __publicField(this, "documentStorage");
23093
+ __publicField(this, "cache");
23094
+ __publicField(this, "queueManager");
23095
+ __publicField(this, "eventEmitter");
23096
+ __publicField(this, "options");
23097
+ __publicField(this, "listenerManager");
23098
+ __publicField(this, "synchronizationManager");
23099
+ // internal dependencies
23100
+ __publicField(this, "defaultDrivesManager");
23101
+ __publicField(this, "defaultDrivesManagerDelegate", {
23102
+ detachDrive: this.detachDrive.bind(this),
23103
+ emit: (...args) => this.eventEmitter.emit("defaultRemoteDrive", ...args)
23104
+ });
23105
+ __publicField(this, "queueDelegate", {
23106
+ checkDocumentExists: (documentId) => this.documentStorage.exists(documentId),
23107
+ processOperationJob: async ({ driveId, documentId, operations, options }) => {
23108
+ return documentId ? this.addOperations(driveId, documentId, operations, options) : this.addDriveOperations(driveId, operations, options);
23109
+ },
23110
+ processActionJob: async ({ driveId, documentId, actions: actions2, options }) => {
23111
+ return documentId ? this.addActions(driveId, documentId, actions2, options) : this.addDriveActions(driveId, actions2, options);
23112
+ },
23113
+ processJob: async (job) => {
23114
+ if (isOperationJob(job)) {
23115
+ return this.queueDelegate.processOperationJob(job);
23116
+ } else if (isActionJob(job)) {
23117
+ return this.queueDelegate.processActionJob(job);
23118
+ } else {
23119
+ throw new Error("Unknown job type", job);
23120
+ }
23121
+ }
23122
+ });
23123
+ // internal state
23124
+ __publicField(this, "triggerMap", /* @__PURE__ */ new Map());
23125
+ __publicField(this, "initializePromise");
23126
+ this.documentModelModules = documentModelModules;
23127
+ this.storage = storage;
23128
+ this.documentStorage = documentStorage;
23129
+ this.cache = cache;
23130
+ this.queueManager = queueManager;
23131
+ this.eventEmitter = eventEmitter;
23132
+ this.synchronizationManager = synchronizationManager;
23133
+ this.listenerManager = listenerManager;
23134
+ this.options = {
23135
+ ...options,
23136
+ defaultDrives: {
23137
+ ...options == null ? void 0 : options.defaultDrives
23138
+ },
23139
+ listenerManager: {
23140
+ ...DefaultListenerManagerOptions,
23141
+ ...options == null ? void 0 : options.listenerManager
23142
+ },
23143
+ taskQueueMethod: (options == null ? void 0 : options.taskQueueMethod) === void 0 ? RunAsap.runAsap : options.taskQueueMethod
23144
+ };
23145
+ this.defaultDrivesManager = new DefaultDrivesManager(this, this.defaultDrivesManagerDelegate, options);
23146
+ this.initializePromise = this._initialize();
23147
+ }
23148
+ // workaround for testing the ephemeral listeners -- we don't have DI in place yet
23149
+ // todo: remove this once we have DI
23150
+ get listeners() {
23151
+ return this.listenerManager;
23152
+ }
23153
+ initialize() {
23154
+ return this.initializePromise;
23155
+ }
23156
+ async _initialize() {
23157
+ await this.listenerManager.initialize(this.handleListenerError);
23158
+ await this.queueManager.init(this.queueDelegate, (error) => {
23159
+ this.logger.error(`Error initializing queue manager`, error);
23160
+ errors.push(error);
23161
+ });
22865
23162
  try {
22866
23163
  await this.defaultDrivesManager.removeOldremoteDrives();
22867
23164
  } catch (error) {
22868
- logger$1.error(error);
23165
+ this.logger.error(error);
22869
23166
  }
22870
23167
  const errors = [];
22871
23168
  const drives = await this.getDrives();
22872
23169
  for (const drive of drives) {
22873
23170
  await this._initializeDrive(drive).catch((error) => {
22874
- logger$1.error(`Error initializing drive ${drive}`, error);
23171
+ this.logger.error(`Error initializing drive ${drive}`, error);
22875
23172
  errors.push(error);
22876
23173
  });
22877
23174
  }
@@ -22901,7 +23198,7 @@ class BaseDocumentDriveServer {
22901
23198
  return source.type === "local" ? "push" : "pull";
22902
23199
  }
22903
23200
  handleListenerError(error, driveId, listener) {
22904
- logger$1.error(`Listener ${listener.listener.label ?? listener.listener.listenerId} error:`, error);
23201
+ this.logger.error(`Listener ${listener.listener.label ?? listener.listener.listenerId} error:`, error);
22905
23202
  const status = error instanceof OperationError ? error.status : "ERROR";
22906
23203
  this.synchronizationManager.updateSyncStatus(driveId, { push: status }, error);
22907
23204
  }
@@ -22964,9 +23261,9 @@ class BaseDocumentDriveServer {
22964
23261
  if (pushListener) {
22965
23262
  this.getSynchronizationUnitsRevision(driveId, syncUnits).then((syncUnitRevisions) => {
22966
23263
  for (const revision of syncUnitRevisions) {
22967
- this.listenerManager.updateListenerRevision(pushListener.listenerId, driveId, revision.syncId, revision.revision).catch(logger$1.error);
23264
+ this.listenerManager.updateListenerRevision(pushListener.listenerId, driveId, revision.syncId, revision.revision).catch(this.logger.error);
22968
23265
  }
22969
- }).catch(logger$1.error);
23266
+ }).catch(this.logger.error);
22970
23267
  }
22971
23268
  }
22972
23269
  });
@@ -22987,11 +23284,59 @@ class BaseDocumentDriveServer {
22987
23284
  return this.triggerMap.delete(driveId);
22988
23285
  }
22989
23286
  async _initializeDrive(driveId) {
23287
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i;
22990
23288
  const drive = await this.getDrive(driveId);
23289
+ this.logger.verbose(`[SYNC DEBUG] Initializing drive ${driveId} with slug "${drive.state.global.slug}"`);
22991
23290
  await this.synchronizationManager.initializeDriveSyncStatus(driveId, drive);
22992
23291
  if (this.shouldSyncRemoteDrive(drive)) {
23292
+ this.logger.verbose(`[SYNC DEBUG] Starting sync for remote drive ${driveId}`);
22993
23293
  await this.startSyncRemoteDrive(driveId);
22994
23294
  }
23295
+ this.logger.verbose(`[SYNC DEBUG] Processing ${drive.state.local.listeners.length} listeners for drive ${driveId}`);
23296
+ for (const zodListener of drive.state.local.listeners) {
23297
+ if (((_a2 = zodListener.callInfo) == null ? void 0 : _a2.transmitterType) === "SwitchboardPush") {
23298
+ this.logger.verbose(`[SYNC DEBUG] Setting up SwitchboardPush listener ${zodListener.listenerId} for drive ${driveId}`);
23299
+ const transmitter = new SwitchboardPushTransmitter(((_b = zodListener.callInfo) == null ? void 0 : _b.data) ?? "");
23300
+ this.logger.verbose(`[SYNC DEBUG] Created SwitchboardPush transmitter with URL: ${((_c = zodListener.callInfo) == null ? void 0 : _c.data) || "none"}`);
23301
+ await this.listenerManager.setListener(driveId, {
23302
+ block: zodListener.block,
23303
+ driveId: drive.state.global.id,
23304
+ filter: {
23305
+ branch: ((_d = zodListener.filter) == null ? void 0 : _d.branch) ?? [],
23306
+ documentId: ((_e = zodListener.filter) == null ? void 0 : _e.documentId) ?? [],
23307
+ documentType: ((_f = zodListener.filter) == null ? void 0 : _f.documentType) ?? [],
23308
+ scope: ((_g = zodListener.filter) == null ? void 0 : _g.scope) ?? []
23309
+ },
23310
+ listenerId: zodListener.listenerId,
23311
+ callInfo: zodListener.callInfo,
23312
+ system: zodListener.system,
23313
+ label: zodListener.label ?? "",
23314
+ transmitter
23315
+ }).then(() => {
23316
+ this.logger.verbose(`[SYNC DEBUG] Successfully set up listener ${zodListener.listenerId} for drive ${driveId}`);
23317
+ });
23318
+ } else if (((_h = zodListener.callInfo) == null ? void 0 : _h.transmitterType) === "PullResponder") {
23319
+ this.logger.verbose(`[SYNC DEBUG] Setting up PullResponder listener ${zodListener.listenerId} for drive ${driveId}`);
23320
+ const pullResponderListener = {
23321
+ driveId,
23322
+ listenerId: zodListener.listenerId,
23323
+ block: false,
23324
+ filter: zodListener.filter,
23325
+ system: false,
23326
+ label: `PullResponder #${zodListener.listenerId}`,
23327
+ callInfo: {
23328
+ data: "",
23329
+ name: "PullResponder",
23330
+ transmitterType: "PullResponder"
23331
+ }
23332
+ };
23333
+ const pullResponder = new PullResponderTransmitter(pullResponderListener, this.listenerManager);
23334
+ pullResponderListener.transmitter = pullResponder;
23335
+ await this.listenerManager.setListener(driveId, pullResponderListener);
23336
+ } else {
23337
+ this.logger.error(`Skipping listener ${zodListener.listenerId} with unsupported type ${((_i = zodListener.callInfo) == null ? void 0 : _i.transmitterType) || "unknown"}`);
23338
+ }
23339
+ }
22995
23340
  }
22996
23341
  // Delegate synchronization methods to synchronizationManager
22997
23342
  getSynchronizationUnits(driveId, documentId, scope, branch, documentType2) {
@@ -23033,7 +23378,7 @@ class BaseDocumentDriveServer {
23033
23378
  };
23034
23379
  await this.storage.createDrive(id, document);
23035
23380
  if (input.global.slug) {
23036
- await this.cache.deleteDocument("drives-slug", input.global.slug);
23381
+ await this.cache.deleteDriveBySlug(input.global.slug);
23037
23382
  }
23038
23383
  await this._initializeDrive(id);
23039
23384
  this.eventEmitter.emit("driveAdded", document);
@@ -23065,7 +23410,7 @@ class BaseDocumentDriveServer {
23065
23410
  const result = await Promise.allSettled([
23066
23411
  this.stopSyncRemoteDrive(driveId),
23067
23412
  this.listenerManager.removeDrive(driveId),
23068
- this.cache.deleteDocument("drives", driveId),
23413
+ this.cache.deleteDrive(driveId),
23069
23414
  this.storage.deleteDrive(driveId)
23070
23415
  ]);
23071
23416
  result.forEach((r) => {
@@ -23080,7 +23425,7 @@ class BaseDocumentDriveServer {
23080
23425
  async getDrive(driveId, options) {
23081
23426
  let document;
23082
23427
  try {
23083
- const cachedDocument = await this.cache.getDocument("drives", driveId);
23428
+ const cachedDocument = await this.cache.getDrive(driveId);
23084
23429
  if (cachedDocument && isDocumentDrive(cachedDocument)) {
23085
23430
  document = cachedDocument;
23086
23431
  if (isAtRevision(document, options == null ? void 0 : options.revisions)) {
@@ -23088,7 +23433,7 @@ class BaseDocumentDriveServer {
23088
23433
  }
23089
23434
  }
23090
23435
  } catch (e) {
23091
- logger$1.error("Error getting drive from cache", e);
23436
+ this.logger.error("Error getting drive from cache", e);
23092
23437
  }
23093
23438
  const driveStorage = document ?? await this.storage.getDrive(driveId);
23094
23439
  const result = this._buildDocument(driveStorage, options);
@@ -23096,43 +23441,43 @@ class BaseDocumentDriveServer {
23096
23441
  throw new Error(`Document with id ${driveId} is not a Document Drive`);
23097
23442
  } else {
23098
23443
  if (!(options == null ? void 0 : options.revisions)) {
23099
- this.cache.setDocument("drives", driveId, result).catch(logger$1.error);
23444
+ this.cache.setDrive(driveId, result).catch(this.logger.error);
23100
23445
  }
23101
23446
  return result;
23102
23447
  }
23103
23448
  }
23104
23449
  async getDriveBySlug(slug, options) {
23105
23450
  try {
23106
- const document2 = await this.cache.getDocument("drives-slug", slug);
23107
- if (document2 && isDocumentDrive(document2)) {
23108
- return document2;
23451
+ const drive = await this.cache.getDriveBySlug(slug);
23452
+ if (drive) {
23453
+ return drive;
23109
23454
  }
23110
23455
  } catch (e) {
23111
- logger$1.error("Error getting drive from cache", e);
23456
+ this.logger.error("Error getting drive from cache", e);
23112
23457
  }
23113
23458
  const driveStorage = await this.storage.getDriveBySlug(slug);
23114
23459
  const document = this._buildDocument(driveStorage, options);
23115
23460
  if (!isDocumentDrive(document)) {
23116
23461
  throw new Error(`Document with slug ${slug} is not a Document Drive`);
23117
23462
  } else {
23118
- this.cache.setDocument("drives-slug", slug, document).catch(logger$1.error);
23463
+ this.cache.setDriveBySlug(slug, document).catch(this.logger.error);
23119
23464
  return document;
23120
23465
  }
23121
23466
  }
23122
23467
  async getDocument(driveId, documentId, options) {
23123
23468
  let cachedDocument;
23124
23469
  try {
23125
- cachedDocument = await this.cache.getDocument(driveId, documentId);
23470
+ cachedDocument = await this.cache.getDocument(documentId);
23126
23471
  if (cachedDocument && isAtRevision(cachedDocument, options == null ? void 0 : options.revisions)) {
23127
23472
  return cachedDocument;
23128
23473
  }
23129
23474
  } catch (e) {
23130
- logger$1.error("Error getting document from cache", e);
23475
+ this.logger.error("Error getting document from cache", e);
23131
23476
  }
23132
23477
  const documentStorage = cachedDocument ?? await this.storage.getDocument(driveId, documentId);
23133
23478
  const document = this._buildDocument(documentStorage, options);
23134
23479
  if (!(options == null ? void 0 : options.revisions)) {
23135
- this.cache.setDocument(driveId, documentId, document).catch(logger$1.error);
23480
+ this.cache.setDocument(documentId, document).catch(this.logger.error);
23136
23481
  }
23137
23482
  return document;
23138
23483
  }
@@ -23187,9 +23532,9 @@ class BaseDocumentDriveServer {
23187
23532
  }
23188
23533
  await this.listenerManager.removeSyncUnits(driveId, syncUnits);
23189
23534
  } catch (error) {
23190
- logger$1.warn("Error deleting document", error);
23535
+ this.logger.warn("Error deleting document", error);
23191
23536
  }
23192
- await this.cache.deleteDocument(driveId, documentId);
23537
+ await this.cache.deleteDocument(documentId);
23193
23538
  return this.storage.deleteDocument(driveId, documentId);
23194
23539
  }
23195
23540
  async _processOperations(driveId, documentId, documentStorage, operations) {
@@ -23361,33 +23706,35 @@ class BaseDocumentDriveServer {
23361
23706
  if (result) {
23362
23707
  return result;
23363
23708
  }
23709
+ let jobId;
23710
+ const promise = new Promise((resolve, reject) => {
23711
+ const unsubscribe = this.queueManager.on("jobCompleted", (job, result2) => {
23712
+ if (job.jobId === jobId) {
23713
+ unsubscribe();
23714
+ unsubscribeError();
23715
+ resolve(result2);
23716
+ }
23717
+ });
23718
+ const unsubscribeError = this.queueManager.on("jobFailed", (job, error) => {
23719
+ if (job.jobId === jobId) {
23720
+ unsubscribe();
23721
+ unsubscribeError();
23722
+ reject(error);
23723
+ }
23724
+ });
23725
+ });
23364
23726
  try {
23365
- const jobId = await this.queueManager.addJob({
23727
+ jobId = await this.queueManager.addJob({
23366
23728
  driveId,
23367
23729
  documentId,
23368
23730
  operations,
23369
23731
  options
23370
23732
  });
23371
- return new Promise((resolve, reject) => {
23372
- const unsubscribe = this.queueManager.on("jobCompleted", (job, result2) => {
23373
- if (job.jobId === jobId) {
23374
- unsubscribe();
23375
- unsubscribeError();
23376
- resolve(result2);
23377
- }
23378
- });
23379
- const unsubscribeError = this.queueManager.on("jobFailed", (job, error) => {
23380
- if (job.jobId === jobId) {
23381
- unsubscribe();
23382
- unsubscribeError();
23383
- reject(error);
23384
- }
23385
- });
23386
- });
23387
23733
  } catch (error) {
23388
- logger$1.error("Error adding job", error);
23734
+ this.logger.error("Error adding job", error);
23389
23735
  throw error;
23390
23736
  }
23737
+ return promise;
23391
23738
  }
23392
23739
  async queueAction(driveId, documentId, action, options) {
23393
23740
  return this.queueActions(driveId, documentId, [action], options);
@@ -23417,7 +23764,7 @@ class BaseDocumentDriveServer {
23417
23764
  });
23418
23765
  });
23419
23766
  } catch (error) {
23420
- logger$1.error("Error adding job", error);
23767
+ this.logger.error("Error adding job", error);
23421
23768
  throw error;
23422
23769
  }
23423
23770
  }
@@ -23448,7 +23795,7 @@ class BaseDocumentDriveServer {
23448
23795
  });
23449
23796
  });
23450
23797
  } catch (error) {
23451
- logger$1.error("Error adding drive job", error);
23798
+ this.logger.error("Error adding drive job", error);
23452
23799
  throw error;
23453
23800
  }
23454
23801
  }
@@ -23465,7 +23812,7 @@ class BaseDocumentDriveServer {
23465
23812
  await this._addOperations(driveId, documentId, async (documentStorage) => {
23466
23813
  const result2 = await this._processOperations(driveId, documentId, documentStorage, operations);
23467
23814
  if (!result2.document) {
23468
- logger$1.error("Invalid document");
23815
+ this.logger.error("Invalid document");
23469
23816
  throw result2.error ?? new Error("Invalid document");
23470
23817
  }
23471
23818
  document = result2.document;
@@ -23479,7 +23826,7 @@ class BaseDocumentDriveServer {
23479
23826
  };
23480
23827
  });
23481
23828
  if (document) {
23482
- this.cache.setDocument(driveId, documentId, document).catch(logger$1.error);
23829
+ this.cache.setDocument(documentId, document).catch(this.logger.error);
23483
23830
  }
23484
23831
  const { scopes, branches } = operationsApplied.reduce((acc, operation) => {
23485
23832
  if (!acc.scopes.includes(operation.scope)) {
@@ -23512,7 +23859,7 @@ class BaseDocumentDriveServer {
23512
23859
  });
23513
23860
  }
23514
23861
  }).catch((error2) => {
23515
- logger$1.error("Non handled error updating sync revision", error2);
23862
+ this.logger.error("Non handled error updating sync revision", error2);
23516
23863
  this.synchronizationManager.updateSyncStatus(driveId, {
23517
23864
  [operationSource]: "ERROR"
23518
23865
  }, error2);
@@ -23614,7 +23961,7 @@ class BaseDocumentDriveServer {
23614
23961
  });
23615
23962
  });
23616
23963
  } catch (error) {
23617
- logger$1.error("Error adding drive job", error);
23964
+ this.logger.error("Error adding drive job", error);
23618
23965
  throw error;
23619
23966
  }
23620
23967
  }
@@ -23642,7 +23989,7 @@ class BaseDocumentDriveServer {
23642
23989
  if (!document || !isDocumentDrive(document)) {
23643
23990
  throw error ?? new Error("Invalid Document Drive document");
23644
23991
  }
23645
- this.cache.setDocument("drives", driveId, document).catch(logger$1.error);
23992
+ this.cache.setDrive(driveId, document).catch(this.logger.error);
23646
23993
  const lastOperation = operationsApplied.filter((op) => op.scope === "global").slice().pop();
23647
23994
  if (lastOperation) {
23648
23995
  const newOp = operationsApplied.find((appliedOp) => !operations.find((o) => o.id === appliedOp.id && o.index === appliedOp.index && o.skip === appliedOp.skip && o.hash === appliedOp.hash));
@@ -23651,7 +23998,6 @@ class BaseDocumentDriveServer {
23651
23998
  this.listenerManager.updateSynchronizationRevisions(driveId, [
23652
23999
  {
23653
24000
  syncId: "0",
23654
- driveId,
23655
24001
  documentId: "",
23656
24002
  scope: "global",
23657
24003
  branch: "main",
@@ -23670,7 +24016,7 @@ class BaseDocumentDriveServer {
23670
24016
  });
23671
24017
  }
23672
24018
  }).catch((error2) => {
23673
- logger$1.error("Non handled error updating sync revision", error2);
24019
+ this.logger.error("Non handled error updating sync revision", error2);
23674
24020
  this.synchronizationManager.updateSyncStatus(driveId, {
23675
24021
  [operationSource]: "ERROR"
23676
24022
  }, error2);
@@ -23772,9 +24118,26 @@ class BaseDocumentDriveServer {
23772
24118
  scope: strand.scope,
23773
24119
  branch: strand.branch
23774
24120
  }));
23775
- const result = await (!strand.documentId ? this.queueDriveOperations(strand.driveId, operations, { source }) : this.queueOperations(strand.driveId, strand.documentId, operations, {
23776
- source
23777
- }));
24121
+ let result;
24122
+ if (strand.documentId) {
24123
+ try {
24124
+ result = await this.queueOperations(strand.driveId, strand.documentId, operations, {
24125
+ source
24126
+ });
24127
+ } catch (error) {
24128
+ this.logger.error("Error queueing operations", error);
24129
+ throw error;
24130
+ }
24131
+ } else {
24132
+ try {
24133
+ result = await this.queueDriveOperations(strand.driveId, operations, {
24134
+ source
24135
+ });
24136
+ } catch (error) {
24137
+ this.logger.error("Error queueing operations", error);
24138
+ throw error;
24139
+ }
24140
+ }
23778
24141
  if (result.status === "ERROR") {
23779
24142
  const syncUnits = strand.documentId !== "" ? (await this.getSynchronizationUnitsIds(strand.driveId, [strand.documentId], [strand.scope], [strand.branch])).map((s) => s.syncId) : [strand.driveId];
23780
24143
  const operationSource = this.getOperationSource(source);
@@ -23790,18 +24153,15 @@ const DocumentDriveServer = ReadModeServer(BaseDocumentDriveServer);
23790
24153
  class MemoryStorage {
23791
24154
  constructor() {
23792
24155
  __publicField(this, "documents");
23793
- __publicField(this, "drives");
23794
24156
  __publicField(this, "driveManifests");
23795
- __publicField(this, "slugToDriveId", {});
23796
24157
  this.documents = {};
23797
- this.drives = {};
23798
24158
  this.driveManifests = {};
23799
24159
  }
23800
24160
  ////////////////////////////////
23801
24161
  // IDocumentStorage
23802
24162
  ////////////////////////////////
23803
24163
  exists(documentId) {
23804
- return Promise.resolve(!!this.documents[documentId]);
24164
+ return Promise.resolve(!!this.documents[documentId] || !!this.documents[`drive/${documentId}`]);
23805
24165
  }
23806
24166
  create(documentId, document) {
23807
24167
  this.documents[documentId] = document;
@@ -23810,10 +24170,52 @@ class MemoryStorage {
23810
24170
  get(documentId) {
23811
24171
  const document = this.documents[documentId];
23812
24172
  if (!document) {
24173
+ const drive = this.documents[`drive/${documentId}`];
24174
+ if (drive) {
24175
+ return Promise.resolve(drive);
24176
+ }
23813
24177
  throw new Error(`Document with id ${documentId} not found`);
23814
24178
  }
23815
24179
  return Promise.resolve(document);
23816
24180
  }
24181
+ async delete(documentId) {
24182
+ const drives = await this.getDrives();
24183
+ for (const driveId of drives) {
24184
+ if (driveId === documentId)
24185
+ continue;
24186
+ await this.removeChild(driveId, documentId);
24187
+ }
24188
+ delete this.driveManifests[documentId];
24189
+ if (this.documents[documentId]) {
24190
+ delete this.documents[documentId];
24191
+ return Promise.resolve(true);
24192
+ }
24193
+ return Promise.resolve(false);
24194
+ }
24195
+ async addChild(parentId, childId) {
24196
+ if (parentId === childId) {
24197
+ throw new Error("Cannot associate a document with itself");
24198
+ }
24199
+ const children = await this.getChildren(childId);
24200
+ if (children.includes(parentId)) {
24201
+ throw new Error("Cannot associate a document with its child");
24202
+ }
24203
+ const manifest = this.getManifest(parentId);
24204
+ manifest.documentIds.add(childId);
24205
+ this.updateDriveManifest(parentId, manifest);
24206
+ }
24207
+ async removeChild(parentId, childId) {
24208
+ const manifest = this.getManifest(parentId);
24209
+ if (manifest.documentIds.delete(childId)) {
24210
+ this.updateDriveManifest(parentId, manifest);
24211
+ return true;
24212
+ }
24213
+ return false;
24214
+ }
24215
+ async getChildren(parentId) {
24216
+ const manifest = this.getManifest(parentId);
24217
+ return [...manifest.documentIds];
24218
+ }
23817
24219
  ////////////////////////////////
23818
24220
  // IDriveStorage
23819
24221
  ////////////////////////////////
@@ -23821,27 +24223,19 @@ class MemoryStorage {
23821
24223
  return this.exists(id);
23822
24224
  }
23823
24225
  getDocuments(drive) {
23824
- const manifest = this.getDriveManifest(drive);
24226
+ const manifest = this.getManifest(drive);
23825
24227
  return Promise.resolve([...manifest.documentIds]);
23826
24228
  }
23827
24229
  getDocument(driveId, id) {
23828
24230
  return this.get(id);
23829
24231
  }
23830
- async saveDocument(drive, id, document) {
23831
- this.documents[id] = document;
23832
- const manifest = this.getDriveManifest(drive);
23833
- manifest.documentIds.add(id);
23834
- this.updateDriveManifest(drive, manifest);
23835
- }
23836
24232
  async clearStorage() {
23837
24233
  this.documents = {};
23838
- this.drives = {};
23839
24234
  this.driveManifests = {};
23840
- this.slugToDriveId = {};
23841
24235
  }
23842
24236
  async createDocument(drive, id, document) {
23843
24237
  await this.create(id, document);
23844
- const manifest = this.getDriveManifest(drive);
24238
+ const manifest = this.getManifest(drive);
23845
24239
  manifest.documentIds.add(id);
23846
24240
  this.updateDriveManifest(drive, manifest);
23847
24241
  }
@@ -23858,59 +24252,60 @@ class MemoryStorage {
23858
24252
  };
23859
24253
  }
23860
24254
  async deleteDocument(drive, id) {
23861
- const drives = await this.getDrives();
23862
- for (const driveId of drives) {
23863
- const manifest = this.getDriveManifest(driveId);
23864
- if (manifest.documentIds.has(id)) {
23865
- manifest.documentIds.delete(id);
23866
- this.updateDriveManifest(driveId, manifest);
23867
- }
23868
- }
23869
- delete this.documents[id];
24255
+ this.delete(id);
23870
24256
  }
23871
24257
  async getDrives() {
23872
- return Object.keys(this.drives);
24258
+ return Object.keys(this.driveManifests);
23873
24259
  }
23874
24260
  async getDrive(id) {
23875
- const drive = this.drives[id];
24261
+ const drive = this.documents[`drive/${id}`];
23876
24262
  if (!drive) {
23877
24263
  throw new DriveNotFoundError(id);
23878
24264
  }
23879
24265
  return drive;
23880
24266
  }
23881
24267
  async getDriveBySlug(slug) {
23882
- const driveId = this.slugToDriveId[slug];
23883
- if (!driveId) {
23884
- throw new Error(`Drive with slug ${slug} not found`);
24268
+ for (const driveId of Object.keys(this.driveManifests)) {
24269
+ const drive = this.documents[`drive/${driveId}`];
24270
+ if (drive.initialState.state.global.slug === slug) {
24271
+ return drive;
24272
+ }
23885
24273
  }
23886
- return this.getDrive(driveId);
24274
+ throw new Error(`Drive with slug ${slug} not found`);
23887
24275
  }
23888
24276
  async createDrive(id, drive) {
23889
- this.drives[id] = drive;
23890
- this.updateDriveManifest(id, { documentIds: /* @__PURE__ */ new Set() });
23891
- const { slug } = drive.initialState.state.global;
24277
+ const slug = drive.initialState.state.global.slug;
23892
24278
  if (slug) {
23893
- this.slugToDriveId[slug] = id;
24279
+ let existingDrive;
24280
+ try {
24281
+ existingDrive = await this.getDriveBySlug(slug);
24282
+ } catch {
24283
+ }
24284
+ if (existingDrive) {
24285
+ throw new Error(`Drive with slug ${slug} already exists`);
24286
+ }
23894
24287
  }
24288
+ await this.create(`drive/${id}`, drive);
24289
+ this.updateDriveManifest(id, { documentIds: /* @__PURE__ */ new Set() });
23895
24290
  }
23896
24291
  async addDriveOperations(id, operations, header) {
23897
24292
  const drive = await this.getDrive(id);
23898
24293
  const mergedOperations = mergeOperations(drive.operations, operations);
23899
- this.drives[id] = {
24294
+ this.documents[`drive/${id}`] = {
23900
24295
  ...drive,
23901
24296
  ...header,
23902
24297
  operations: mergedOperations
23903
24298
  };
23904
24299
  }
23905
24300
  async deleteDrive(id) {
23906
- const manifest = this.getDriveManifest(id);
24301
+ const manifest = this.getManifest(id);
23907
24302
  const drives = await this.getDrives();
23908
24303
  await Promise.all([...manifest.documentIds].map((docId) => {
23909
24304
  for (const driveId of drives) {
23910
24305
  if (driveId === id) {
23911
24306
  continue;
23912
24307
  }
23913
- const manifest2 = this.getDriveManifest(driveId);
24308
+ const manifest2 = this.getManifest(driveId);
23914
24309
  if (manifest2.documentIds.has(docId)) {
23915
24310
  return;
23916
24311
  }
@@ -23918,24 +24313,18 @@ class MemoryStorage {
23918
24313
  delete this.documents[docId];
23919
24314
  }));
23920
24315
  delete this.driveManifests[id];
23921
- delete this.drives[id];
23922
- for (const [slug, driveId] of Object.entries(this.slugToDriveId)) {
23923
- if (driveId === id) {
23924
- delete this.slugToDriveId[slug];
23925
- }
23926
- }
24316
+ delete this.documents[id];
23927
24317
  }
23928
24318
  async getSynchronizationUnitsRevision(units) {
23929
24319
  const results = await Promise.allSettled(units.map(async (unit) => {
23930
24320
  try {
23931
- const document = await (unit.documentId ? this.getDocument(unit.driveId, unit.documentId) : this.getDrive(unit.driveId));
24321
+ const document = await this.get(unit.documentId);
23932
24322
  if (!document) {
23933
24323
  return void 0;
23934
24324
  }
23935
24325
  const operation = document.operations[unit.scope].at(-1);
23936
24326
  if (operation) {
23937
24327
  return {
23938
- driveId: unit.driveId,
23939
24328
  documentId: unit.documentId,
23940
24329
  scope: unit.scope,
23941
24330
  branch: unit.branch,
@@ -23957,7 +24346,7 @@ class MemoryStorage {
23957
24346
  ////////////////////////////////
23958
24347
  // Private
23959
24348
  ////////////////////////////////
23960
- getDriveManifest(driveId) {
24349
+ getManifest(driveId) {
23961
24350
  if (!this.driveManifests[driveId]) {
23962
24351
  this.driveManifests[driveId] = { documentIds: /* @__PURE__ */ new Set() };
23963
24352
  }
@@ -24122,11 +24511,10 @@ const _ListenerManager = class _ListenerManager {
24122
24511
  throw new Error("Maximum retries exhausted.");
24123
24512
  }
24124
24513
  const listenerUpdates = [];
24125
- for (const [driveId, drive] of this.listenerStateByDriveId) {
24126
- for (const [listenerId, listenerState] of drive) {
24514
+ for (const [driveId, listenerStateById] of this.listenerStateByDriveId) {
24515
+ for (const [listenerId, listenerState] of listenerStateById) {
24127
24516
  const transmitter = listenerState.listener.transmitter;
24128
24517
  if (!(transmitter == null ? void 0 : transmitter.transmit)) {
24129
- this.logger.verbose(`Transmitter not set on listener: ${listenerId}`);
24130
24518
  continue;
24131
24519
  }
24132
24520
  const syncUnits = await this.getListenerSyncUnits(driveId, listenerId);
@@ -24138,7 +24526,7 @@ const _ListenerManager = class _ListenerManager {
24138
24526
  this.logger.verbose(`Abandoning push for sync unit ${syncUnit.syncId}: already up-to-date (${unitState.listenerRev} >= ${syncUnit.revision})`);
24139
24527
  return;
24140
24528
  } else {
24141
- this.logger.verbose(`Listener out-of-date for sync unit (${syncUnit.driveId}, ${syncUnit.scope}, ${syncUnit.documentId}): ${unitState == null ? void 0 : unitState.listenerRev} < ${syncUnit.revision}`);
24529
+ this.logger.verbose(`Listener out-of-date for sync unit (${syncUnit.scope}, ${syncUnit.documentId}): ${unitState == null ? void 0 : unitState.listenerRev} < ${syncUnit.revision}`);
24142
24530
  }
24143
24531
  const opData = [];
24144
24532
  try {
@@ -24280,57 +24668,78 @@ const _ListenerManager = class _ListenerManager {
24280
24668
  }
24281
24669
  }
24282
24670
  async getStrands(driveId, listenerId, options) {
24283
- const listenerState = this.getListenerState(driveId, listenerId);
24284
- const strands = [];
24285
- const syncUnits = await this.getListenerSyncUnits(driveId, listenerId);
24286
- const limit = options == null ? void 0 : options.limit;
24287
- let operationsCount = 0;
24288
- const tasks = syncUnits.map((syncUnit) => async () => {
24289
- if (limit && operationsCount >= limit) {
24290
- return;
24291
- }
24292
- if (syncUnit.revision < 0) {
24293
- return;
24294
- }
24295
- const entry = listenerState.syncUnits.get(syncUnit.syncId);
24296
- if (entry && entry.listenerRev >= syncUnit.revision) {
24297
- return;
24298
- }
24299
- const { documentId, driveId: driveId2, scope, branch } = syncUnit;
24300
- try {
24301
- const operations = await this.syncManager.getOperationData(
24302
- // DEAL WITH INVALID SYNC ID ERROR
24303
- driveId2,
24304
- syncUnit.syncId,
24305
- {
24306
- since: options == null ? void 0 : options.since,
24307
- fromRevision: (options == null ? void 0 : options.fromRevision) ?? (entry == null ? void 0 : entry.listenerRev),
24308
- limit: limit ? limit - operationsCount : void 0
24671
+ this.logger.verbose(`[SYNC DEBUG] ListenerManager.getStrands called for drive: ${driveId}, listener: ${listenerId}, options: ${JSON.stringify(options || {})}`);
24672
+ let listenerState;
24673
+ try {
24674
+ listenerState = this.getListenerState(driveId, listenerId);
24675
+ this.logger.verbose(`[SYNC DEBUG] Found listener state for drive: ${driveId}, listener: ${listenerId}, status: ${listenerState.listenerStatus}`);
24676
+ } catch (error) {
24677
+ this.logger.error(`[SYNC DEBUG] Failed to find listener state for drive: ${driveId}, listener: ${listenerId}. Error: ${error}`);
24678
+ throw error;
24679
+ }
24680
+ const strands = [];
24681
+ try {
24682
+ const syncUnits = await this.getListenerSyncUnits(driveId, listenerId);
24683
+ this.logger.verbose(`[SYNC DEBUG] Retrieved ${syncUnits.length} sync units for drive: ${driveId}, listener: ${listenerId}`);
24684
+ const limit = options == null ? void 0 : options.limit;
24685
+ let operationsCount = 0;
24686
+ const tasks = syncUnits.map((syncUnit) => async () => {
24687
+ if (limit && operationsCount >= limit) {
24688
+ return;
24689
+ }
24690
+ if (syncUnit.revision < 0) {
24691
+ this.logger.verbose(`[SYNC DEBUG] Skipping sync unit with negative revision: ${syncUnit.syncId}, revision: ${syncUnit.revision}`);
24692
+ return;
24693
+ }
24694
+ const entry = listenerState.syncUnits.get(syncUnit.syncId);
24695
+ if (entry && entry.listenerRev >= syncUnit.revision) {
24696
+ this.logger.verbose(`[SYNC DEBUG] Skipping sync unit - listener already up to date: ${syncUnit.syncId}, listenerRev: ${entry.listenerRev}, revision: ${syncUnit.revision}`);
24697
+ return;
24698
+ }
24699
+ const { documentId, scope, branch } = syncUnit;
24700
+ try {
24701
+ this.logger.verbose(`[SYNC DEBUG] Getting operations for syncUnit: ${syncUnit.syncId}, documentId: ${documentId}, scope: ${scope}, branch: ${branch}`);
24702
+ const operations = await this.syncManager.getOperationData(
24703
+ // DEAL WITH INVALID SYNC ID ERROR
24704
+ driveId,
24705
+ syncUnit.syncId,
24706
+ {
24707
+ since: options == null ? void 0 : options.since,
24708
+ fromRevision: (options == null ? void 0 : options.fromRevision) ?? (entry == null ? void 0 : entry.listenerRev),
24709
+ limit: limit ? limit - operationsCount : void 0
24710
+ }
24711
+ );
24712
+ this.logger.verbose(`[SYNC DEBUG] Retrieved ${operations.length} operations for syncUnit: ${syncUnit.syncId}`);
24713
+ if (!operations.length) {
24714
+ return;
24309
24715
  }
24310
- );
24311
- if (!operations.length) {
24716
+ operationsCount += operations.length;
24717
+ strands.push({
24718
+ driveId,
24719
+ documentId,
24720
+ scope,
24721
+ branch,
24722
+ operations
24723
+ });
24724
+ this.logger.verbose(`[SYNC DEBUG] Added strand with ${operations.length} operations for syncUnit: ${syncUnit.syncId}`);
24725
+ } catch (error) {
24726
+ this.logger.error(`Error getting operations for syncUnit: ${syncUnit.syncId}, error: ${error}`);
24312
24727
  return;
24313
24728
  }
24314
- operationsCount += operations.length;
24315
- strands.push({
24316
- driveId: driveId2,
24317
- documentId,
24318
- scope,
24319
- branch,
24320
- operations
24321
- });
24322
- } catch (error) {
24323
- this.logger.error(error);
24324
- return;
24325
- }
24326
- });
24327
- if (this.options.sequentialUpdates) {
24328
- for (const task of tasks) {
24329
- await task();
24729
+ });
24730
+ if (this.options.sequentialUpdates) {
24731
+ this.logger.verbose(`[SYNC DEBUG] Processing ${tasks.length} sync units sequentially`);
24732
+ for (const task of tasks) {
24733
+ await task();
24734
+ }
24735
+ } else {
24736
+ this.logger.verbose(`[SYNC DEBUG] Processing ${tasks.length} sync units in parallel`);
24737
+ await Promise.all(tasks.map((task) => task()));
24330
24738
  }
24331
- } else {
24332
- await Promise.all(tasks.map((task) => task()));
24739
+ } catch (error) {
24740
+ this.logger.error(`Error in getStrands: ${error}`);
24333
24741
  }
24742
+ this.logger.verbose(`ListenerManager.getStrands returning ${strands.length} strands for drive: ${driveId}, listener: ${listenerId}`);
24334
24743
  return strands;
24335
24744
  }
24336
24745
  getListenerState(driveId, listenerId) {
@@ -24356,187 +24765,6 @@ const _ListenerManager = class _ListenerManager {
24356
24765
  };
24357
24766
  __publicField(_ListenerManager, "LISTENER_UPDATE_DELAY", 250);
24358
24767
  let ListenerManager = _ListenerManager;
24359
- var defaults;
24360
- var hasRequiredDefaults;
24361
- function requireDefaults() {
24362
- if (hasRequiredDefaults) return defaults;
24363
- hasRequiredDefaults = 1;
24364
- defaults = {
24365
- space: "",
24366
- cycles: false,
24367
- replacer: (k, v) => v,
24368
- stringify: JSON.stringify
24369
- };
24370
- return defaults;
24371
- }
24372
- var util;
24373
- var hasRequiredUtil;
24374
- function requireUtil() {
24375
- if (hasRequiredUtil) return util;
24376
- hasRequiredUtil = 1;
24377
- util = {
24378
- isArray: Array.isArray,
24379
- assign: Object.assign,
24380
- isObject: (v) => typeof v === "object",
24381
- isFunction: (v) => typeof v === "function",
24382
- isBoolean: (v) => typeof v === "boolean",
24383
- isRegex: (v) => v instanceof RegExp,
24384
- keys: Object.keys
24385
- };
24386
- return util;
24387
- }
24388
- var lib;
24389
- var hasRequiredLib;
24390
- function requireLib() {
24391
- if (hasRequiredLib) return lib;
24392
- hasRequiredLib = 1;
24393
- const DEFAULTS = requireDefaults();
24394
- const isFunction = requireUtil().isFunction;
24395
- const isBoolean = requireUtil().isBoolean;
24396
- const isObject = requireUtil().isObject;
24397
- const isArray = requireUtil().isArray;
24398
- const isRegex = requireUtil().isRegex;
24399
- const assign = requireUtil().assign;
24400
- const keys = requireUtil().keys;
24401
- function serialize(obj) {
24402
- if (obj === null || obj === void 0) return obj;
24403
- if (isRegex(obj)) return obj.toString();
24404
- return obj.toJSON ? obj.toJSON() : obj;
24405
- }
24406
- function stringifyDeterministic(obj, opts) {
24407
- opts = opts || assign({}, DEFAULTS);
24408
- if (isFunction(opts)) opts = { compare: opts };
24409
- const space = opts.space || DEFAULTS.space;
24410
- const cycles = isBoolean(opts.cycles) ? opts.cycles : DEFAULTS.cycles;
24411
- const replacer = opts.replacer || DEFAULTS.replacer;
24412
- const stringify2 = opts.stringify || DEFAULTS.stringify;
24413
- const compare = opts.compare && /* @__PURE__ */ function(f) {
24414
- return function(node) {
24415
- return function(a, b) {
24416
- const aobj = { key: a, value: node[a] };
24417
- const bobj = { key: b, value: node[b] };
24418
- return f(aobj, bobj);
24419
- };
24420
- };
24421
- }(opts.compare);
24422
- if (!cycles) stringify2(obj);
24423
- const seen = [];
24424
- return function _deterministic(parent, key, node, level) {
24425
- const indent2 = space ? "\n" + new Array(level + 1).join(space) : "";
24426
- const colonSeparator = space ? ": " : ":";
24427
- node = serialize(node);
24428
- node = replacer.call(parent, key, node);
24429
- if (node === void 0) return;
24430
- if (!isObject(node) || node === null) return stringify2(node);
24431
- if (isArray(node)) {
24432
- const out = [];
24433
- for (let i = 0; i < node.length; i++) {
24434
- const item = _deterministic(node, i, node[i], level + 1) || stringify2(null);
24435
- out.push(indent2 + space + item);
24436
- }
24437
- return "[" + out.join(",") + indent2 + "]";
24438
- } else {
24439
- if (cycles) {
24440
- if (seen.indexOf(node) !== -1) {
24441
- return stringify2("[Circular]");
24442
- } else {
24443
- seen.push(node);
24444
- }
24445
- }
24446
- const nodeKeys = keys(node).sort(compare && compare(node));
24447
- const out = [];
24448
- for (let i = 0; i < nodeKeys.length; i++) {
24449
- const key2 = nodeKeys[i];
24450
- const value = _deterministic(node, key2, node[key2], level + 1);
24451
- if (!value) continue;
24452
- const keyValue = stringify2(key2) + colonSeparator + value;
24453
- out.push(indent2 + space + keyValue);
24454
- }
24455
- seen.splice(seen.indexOf(node), 1);
24456
- return "{" + out.join(",") + indent2 + "}";
24457
- }
24458
- }({ "": obj }, "", obj, 0);
24459
- }
24460
- lib = stringifyDeterministic;
24461
- return lib;
24462
- }
24463
- var libExports = requireLib();
24464
- const stringify = /* @__PURE__ */ getDefaultExportFromCjs(libExports);
24465
- const SYNC_OPS_BATCH_LIMIT = 10;
24466
- class SwitchboardPushTransmitter {
24467
- constructor(targetURL) {
24468
- __publicField(this, "targetURL");
24469
- __publicField(this, "logger", childLogger([
24470
- "SwitchboardPushTransmitter",
24471
- Math.floor(Math.random() * 999).toString()
24472
- ]));
24473
- this.targetURL = targetURL;
24474
- }
24475
- async transmit(strands, source) {
24476
- var _a2;
24477
- if (source.type === "trigger" && ((_a2 = source.trigger.data) == null ? void 0 : _a2.url) === this.targetURL) {
24478
- this.logger.verbose(`Cutting trigger loop from ${this.targetURL}.`);
24479
- return strands.map((strand) => {
24480
- var _a3;
24481
- return {
24482
- driveId: strand.driveId,
24483
- documentId: strand.documentId,
24484
- scope: strand.scope,
24485
- branch: strand.branch,
24486
- status: "SUCCESS",
24487
- revision: ((_a3 = strand.operations.at(-1)) == null ? void 0 : _a3.index) ?? -1
24488
- };
24489
- });
24490
- }
24491
- const culledStrands = [];
24492
- let opsCounter = 0;
24493
- for (let s = 0; opsCounter <= SYNC_OPS_BATCH_LIMIT && s < strands.length; s++) {
24494
- const currentStrand = strands.at(s);
24495
- if (!currentStrand) {
24496
- break;
24497
- }
24498
- const newOps = Math.min(SYNC_OPS_BATCH_LIMIT - opsCounter, currentStrand.operations.length);
24499
- culledStrands.push({
24500
- ...currentStrand,
24501
- operations: currentStrand.operations.slice(0, newOps)
24502
- });
24503
- opsCounter += newOps;
24504
- }
24505
- this.logger.verbose(` Total update: [${strands.map((s) => s.operations.length).join(", ")}] operations`);
24506
- this.logger.verbose(`Culled update: [${culledStrands.map((s) => s.operations.length).join(", ")}] operations`);
24507
- try {
24508
- const { pushUpdates } = await requestGraphql(this.targetURL, gql`
24509
- mutation pushUpdates($strands: [InputStrandUpdate!]) {
24510
- pushUpdates(strands: $strands) {
24511
- driveId
24512
- documentId
24513
- scope
24514
- branch
24515
- status
24516
- revision
24517
- error
24518
- }
24519
- }
24520
- `, {
24521
- strands: culledStrands.map((strand) => ({
24522
- ...strand,
24523
- operations: strand.operations.map((op) => ({
24524
- ...op,
24525
- input: stringify(op.input)
24526
- }))
24527
- }))
24528
- });
24529
- if (!pushUpdates) {
24530
- throw new Error("Couldn't update listener revision");
24531
- }
24532
- return pushUpdates;
24533
- } catch (e) {
24534
- this.logger.error(e);
24535
- throw e;
24536
- }
24537
- return [];
24538
- }
24539
- }
24540
24768
  class TransmitterFactory {
24541
24769
  constructor(listenerManager) {
24542
24770
  __publicField(this, "listenerManager");
@@ -24575,18 +24803,20 @@ class SynchronizationManager {
24575
24803
  }
24576
24804
  async getSynchronizationUnits(driveId, documentId, scope, branch, documentType2) {
24577
24805
  const synchronizationUnitsQuery = await this.getSynchronizationUnitsIds(driveId, documentId, scope, branch, documentType2);
24806
+ this.logger.verbose(`getSynchronizationUnits query: ${JSON.stringify(synchronizationUnitsQuery)}`);
24578
24807
  return this.getSynchronizationUnitsRevision(driveId, synchronizationUnitsQuery);
24579
24808
  }
24580
24809
  async getSynchronizationUnitsRevision(driveId, syncUnitsQuery) {
24581
24810
  const drive = await this.getDrive(driveId);
24582
24811
  const revisions = await this.storage.getSynchronizationUnitsRevision(syncUnitsQuery);
24812
+ this.logger.verbose(`getSynchronizationUnitsRevision: ${JSON.stringify(revisions)}`);
24583
24813
  const synchronizationUnits = syncUnitsQuery.map((s) => ({
24584
24814
  ...s,
24585
24815
  lastUpdated: drive.created,
24586
24816
  revision: -1
24587
24817
  }));
24588
24818
  for (const revision of revisions) {
24589
- const syncUnit = synchronizationUnits.find((s) => revision.driveId === s.driveId && revision.documentId === s.documentId && revision.scope === s.scope && revision.branch === s.branch);
24819
+ const syncUnit = synchronizationUnits.find((s) => revision.documentId === s.documentId && revision.scope === s.scope && revision.branch === s.branch);
24590
24820
  if (syncUnit) {
24591
24821
  syncUnit.revision = revision.revision;
24592
24822
  syncUnit.lastUpdated = revision.lastUpdated;
@@ -24599,7 +24829,7 @@ class SynchronizationManager {
24599
24829
  const nodes = drive.state.global.nodes.filter((node) => isFileNode(node) && (!(documentId == null ? void 0 : documentId.length) || documentId.includes(node.id) || documentId.includes("*")) && (!(documentType2 == null ? void 0 : documentType2.length) || documentType2.includes(node.documentType) || documentType2.includes("*")));
24600
24830
  if ((!documentId || documentId.includes("*") || documentId.includes("")) && (!(documentType2 == null ? void 0 : documentType2.length) || documentType2.includes("powerhouse/document-drive") || documentType2.includes("*"))) {
24601
24831
  nodes.unshift({
24602
- id: "",
24832
+ id: driveId,
24603
24833
  documentType: "powerhouse/document-drive",
24604
24834
  synchronizationUnits: [
24605
24835
  {
@@ -24641,7 +24871,6 @@ class SynchronizationManager {
24641
24871
  syncId,
24642
24872
  scope: syncUnit.scope,
24643
24873
  branch: syncUnit.branch,
24644
- driveId,
24645
24874
  documentId: node.id,
24646
24875
  documentType: node.documentType
24647
24876
  };
@@ -24659,7 +24888,6 @@ class SynchronizationManager {
24659
24888
  syncId,
24660
24889
  scope,
24661
24890
  branch,
24662
- driveId,
24663
24891
  documentId,
24664
24892
  documentType: documentType2,
24665
24893
  lastUpdated: lastOperation.timestamp ?? document.lastModified,
@@ -24667,14 +24895,27 @@ class SynchronizationManager {
24667
24895
  };
24668
24896
  }
24669
24897
  async getOperationData(driveId, syncId, filter) {
24898
+ this.logger.verbose(`[SYNC DEBUG] SynchronizationManager.getOperationData called for drive: ${driveId}, syncId: ${syncId}, filter: ${JSON.stringify(filter)}`);
24670
24899
  const syncUnit = syncId === "0" ? { documentId: "", scope: "global" } : await this.getSynchronizationUnitIdInfo(driveId, syncId);
24671
24900
  if (!syncUnit) {
24901
+ this.logger.error(`SYNC DEBUG] Invalid Sync Id ${syncId} in drive ${driveId}`);
24672
24902
  throw new Error(`Invalid Sync Id ${syncId} in drive ${driveId}`);
24673
24903
  }
24904
+ this.logger.verbose(`[SYNC DEBUG] Found sync unit: documentId: ${syncUnit.documentId}, scope: ${syncUnit.scope}`);
24674
24905
  const document = syncId === "0" ? await this.getDrive(driveId) : await this.getDocument(driveId, syncUnit.documentId);
24906
+ this.logger.verbose(`[SYNC DEBUG] Retrieved document ${syncUnit.documentId} with type: ${document.documentType}`);
24675
24907
  const operations = document.operations[syncUnit.scope] ?? [];
24908
+ this.logger.verbose(`[SYNC DEBUG] Found ${operations.length} total operations in scope ${syncUnit.scope}`);
24676
24909
  const filteredOperations = operations.filter((operation) => Object.keys(filter).length === 0 || (filter.since === void 0 || isBefore(filter.since, operation.timestamp)) && (filter.fromRevision === void 0 || operation.index > filter.fromRevision));
24910
+ this.logger.verbose(`[SYNC DEBUG] Filtered to ${filteredOperations.length} operations based on filter criteria` + (filter.fromRevision !== void 0 ? ` (fromRevision: ${filter.fromRevision})` : ""));
24677
24911
  const limitedOperations = filter.limit ? filteredOperations.slice(0, filter.limit) : filteredOperations;
24912
+ this.logger.verbose(`[SYNC DEBUG] Returning ${limitedOperations.length} operations after applying limit`);
24913
+ if (limitedOperations.length > 0) {
24914
+ const firstOp = limitedOperations[0];
24915
+ const lastOp = limitedOperations[limitedOperations.length - 1];
24916
+ this.logger.verbose(`[SYNC DEBUG] First operation: index=${firstOp.index}, type=${firstOp.type}`);
24917
+ this.logger.verbose(`[SYNC DEBUG] Last operation: index=${lastOp.index}, type=${lastOp.type}`);
24918
+ }
24678
24919
  return limitedOperations.map((operation) => ({
24679
24920
  hash: operation.hash,
24680
24921
  index: operation.index,
@@ -24688,7 +24929,7 @@ class SynchronizationManager {
24688
24929
  }
24689
24930
  async getDrive(driveId) {
24690
24931
  try {
24691
- const cachedDocument = await this.cache.getDocument("drives", driveId);
24932
+ const cachedDocument = await this.cache.getDrive(driveId);
24692
24933
  if (cachedDocument && isDocumentDrive(cachedDocument)) {
24693
24934
  return cachedDocument;
24694
24935
  }
@@ -24704,7 +24945,7 @@ class SynchronizationManager {
24704
24945
  }
24705
24946
  async getDocument(driveId, documentId) {
24706
24947
  try {
24707
- const cachedDocument = await this.cache.getDocument(driveId, documentId);
24948
+ const cachedDocument = await this.cache.getDocument(documentId);
24708
24949
  if (cachedDocument) {
24709
24950
  return cachedDocument;
24710
24951
  }
@@ -25180,6 +25421,9 @@ function Modified(props) {
25180
25421
  function Moved(props) {
25181
25422
  return jsxs("svg", { ...props, width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [jsx("path", { d: "M7.07143 1.96429C7.07143 2.2207 6.86356 2.42857 6.60714 2.42857H5.21429C3.67578 2.42857 2.42857 3.67578 2.42857 5.21429V10.7857C2.42857 12.3242 3.67578 13.5714 5.21429 13.5714H10.7857C12.3242 13.5714 13.5714 12.3242 13.5714 10.7857V9.39286C13.5714 9.13644 13.7793 8.92857 14.0357 8.92857C14.2921 8.92857 14.5 9.13644 14.5 9.39286V10.7857C14.5 12.8371 12.8371 14.5 10.7857 14.5H5.21429C3.16294 14.5 1.5 12.8371 1.5 10.7857V5.21429C1.5 3.16294 3.16294 1.5 5.21429 1.5H6.60714C6.86356 1.5 7.07143 1.70787 7.07143 1.96429Z", fill: "currentcolor" }), jsx("path", { d: "M14 6.5V2.5C14 2.22386 13.7761 2 13.5 2H9.5", stroke: "currentcolor", strokeLinecap: "round" }), jsx("path", { d: "M7 10L7.28346 9.29136C8.39378 6.51556 10.4269 4.20728 13.0403 2.75539L13.5 2.5", stroke: "currentcolor", strokeLinecap: "round" })] });
25182
25423
  }
25424
+ function Npm(props) {
25425
+ return jsx("svg", { ...props, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 128 128", children: jsx("path", { fill: "#cb3837", d: "M2 38.5h124v43.71H64v7.29H36.44v-7.29H2zm6.89 36.43h13.78V53.07h6.89v21.86h6.89V45.79H8.89zm34.44-29.14v36.42h13.78v-7.28h13.78V45.79zm13.78 7.29H64v14.56h-6.89zm20.67-7.29v29.14h13.78V53.07h6.89v21.86h6.89V53.07h6.89v21.86h6.89V45.79z" }) });
25426
+ }
25183
25427
  function PackageManager(props) {
25184
25428
  return jsx("svg", { ...props, width: "12", height: "12", viewBox: "0 0 12 12", fill: "currentcolor", children: jsx("path", { d: "M1.22323 -0.00109863C0.549226 -0.00109863 -0.00610352 0.533576 -0.00610352 1.20691V2.79089C-0.00610352 3.46423 0.549226 3.9989 1.22323 3.9989H4.0979C4.7719 3.9989 5.32723 3.46423 5.32723 2.79089V1.20691C5.32723 0.533576 4.7719 -0.00109863 4.0979 -0.00109863H1.22323ZM7.9939 -0.00109863C7.25723 -0.00109863 6.66056 0.595568 6.66056 1.33223V5.33223C6.66056 6.0689 7.25723 6.66557 7.9939 6.66557H10.6606C11.3972 6.66557 11.9939 6.0689 11.9939 5.33223V1.33223C11.9939 0.595568 11.3972 -0.00109863 10.6606 -0.00109863H7.9939ZM1.32723 5.33223C0.590563 5.33223 -0.00610352 5.9289 -0.00610352 6.66557V10.6656C-0.00610352 11.4022 0.590563 11.9989 1.32723 11.9989H3.9939C4.73056 11.9989 5.32723 11.4022 5.32723 10.6656V6.66557C5.32723 5.9289 4.73056 5.33223 3.9939 5.33223H1.32723ZM7.88989 7.9989C7.21589 7.9989 6.66056 8.53358 6.66056 9.20691V10.7909C6.66056 11.4642 7.21589 11.9989 7.88989 11.9989H10.7646C11.4386 11.9989 11.9939 11.4642 11.9939 10.7909V9.20691C11.9939 8.53358 11.4386 7.9989 10.7646 7.9989H7.88989Z" }) });
25185
25429
  }
@@ -25368,6 +25612,7 @@ const iconComponents = {
25368
25612
  M,
25369
25613
  Modified,
25370
25614
  Moved,
25615
+ Npm,
25371
25616
  PackageManager,
25372
25617
  Pencil,
25373
25618
  PeopleFill,
@@ -25545,7 +25790,7 @@ const nodeOptionsMap = {
25545
25790
  };
25546
25791
  const name = "@powerhousedao/connect";
25547
25792
  const productName = "Powerhouse-Connect";
25548
- const version$1 = "1.0.8";
25793
+ const version$1 = "1.0.10-dev.0";
25549
25794
  const description = "Powerhouse Connect";
25550
25795
  const main = "./dist/index.html";
25551
25796
  const type = "module";
@@ -28338,6 +28583,10 @@ const _BrowserStorage = class _BrowserStorage {
28338
28583
  name: namespace ? `${namespace}:${_BrowserStorage.DBName}` : _BrowserStorage.DBName
28339
28584
  }));
28340
28585
  }
28586
+ async clear() {
28587
+ const db = await this.db;
28588
+ await db.clear();
28589
+ }
28341
28590
  ////////////////////////////////
28342
28591
  // IDocumentStorage
28343
28592
  ////////////////////////////////
@@ -28358,13 +28607,57 @@ const _BrowserStorage = class _BrowserStorage {
28358
28607
  }
28359
28608
  return document;
28360
28609
  }
28610
+ async delete(documentId) {
28611
+ const db = await this.db;
28612
+ const document = await db.getItem(this.buildDocumentKey(documentId));
28613
+ if (!document) {
28614
+ return false;
28615
+ }
28616
+ const drives = await this.getDrives();
28617
+ for (const driveId of drives) {
28618
+ if (driveId === documentId)
28619
+ continue;
28620
+ await this.removeChild(driveId, documentId);
28621
+ }
28622
+ await db.removeItem(this.buildManifestKey(documentId));
28623
+ await db.removeItem(this.buildDocumentKey(documentId));
28624
+ return true;
28625
+ }
28626
+ async removeChild(parentId, childId) {
28627
+ const manifest = await this.getManifest(parentId);
28628
+ const docIndex = manifest.documentIds.indexOf(childId);
28629
+ if (docIndex !== -1) {
28630
+ manifest.documentIds.splice(docIndex, 1);
28631
+ await this.updateDriveManifest(parentId, manifest);
28632
+ return true;
28633
+ }
28634
+ return false;
28635
+ }
28636
+ async addChild(parentId, childId) {
28637
+ if (parentId === childId) {
28638
+ throw new Error("Cannot associate a document with itself");
28639
+ }
28640
+ const children = await this.getChildren(childId);
28641
+ if (children.includes(parentId)) {
28642
+ throw new Error("Cannot associate a document with its child");
28643
+ }
28644
+ const manifest = await this.getManifest(parentId);
28645
+ if (!manifest.documentIds.includes(childId)) {
28646
+ manifest.documentIds.push(childId);
28647
+ await this.updateDriveManifest(parentId, manifest);
28648
+ }
28649
+ }
28650
+ async getChildren(parentId) {
28651
+ const manifest = await this.getManifest(parentId);
28652
+ return manifest.documentIds;
28653
+ }
28361
28654
  ////////////////////////////////
28362
28655
  // IDriveStorage
28363
28656
  ////////////////////////////////
28364
28657
  checkDocumentExists(drive, documentId) {
28365
28658
  return this.exists(documentId);
28366
28659
  }
28367
- async getDriveManifest(driveId) {
28660
+ async getManifest(driveId) {
28368
28661
  const db = await this.db;
28369
28662
  const manifest = await db.getItem(this.buildManifestKey(driveId));
28370
28663
  return manifest || { documentIds: [] };
@@ -28374,7 +28667,7 @@ const _BrowserStorage = class _BrowserStorage {
28374
28667
  await db.setItem(this.buildManifestKey(driveId), manifest);
28375
28668
  }
28376
28669
  async getDocuments(drive) {
28377
- const manifest = await this.getDriveManifest(drive);
28670
+ const manifest = await this.getManifest(drive);
28378
28671
  return manifest.documentIds;
28379
28672
  }
28380
28673
  async getDocument(driveId, id) {
@@ -28382,7 +28675,7 @@ const _BrowserStorage = class _BrowserStorage {
28382
28675
  }
28383
28676
  async createDocument(drive, id, document) {
28384
28677
  await this.create(id, document);
28385
- const manifest = await this.getDriveManifest(drive);
28678
+ const manifest = await this.getManifest(drive);
28386
28679
  if (!manifest.documentIds.includes(id)) {
28387
28680
  manifest.documentIds.push(id);
28388
28681
  await this.updateDriveManifest(drive, manifest);
@@ -28390,7 +28683,7 @@ const _BrowserStorage = class _BrowserStorage {
28390
28683
  }
28391
28684
  async deleteDocument(drive, id) {
28392
28685
  await (await this.db).removeItem(this.buildDocumentKey(id));
28393
- const manifest = await this.getDriveManifest(drive);
28686
+ const manifest = await this.getManifest(drive);
28394
28687
  const docIndex = manifest.documentIds.indexOf(id);
28395
28688
  if (docIndex !== -1) {
28396
28689
  manifest.documentIds.splice(docIndex, 1);
@@ -28416,12 +28709,13 @@ const _BrowserStorage = class _BrowserStorage {
28416
28709
  async getDrives() {
28417
28710
  const db = await this.db;
28418
28711
  const keys = await db.keys();
28419
- return keys.filter((key) => key.startsWith(_BrowserStorage.DRIVES_KEY)).map((key) => key.slice(_BrowserStorage.DRIVES_KEY.length + _BrowserStorage.SEP.length));
28712
+ return keys.filter((key) => key.startsWith(_BrowserStorage.MANIFEST_KEY)).map((key) => key.slice(_BrowserStorage.MANIFEST_KEY.length + _BrowserStorage.SEP.length));
28420
28713
  }
28421
28714
  async getDrive(id) {
28422
- const db = await this.db;
28423
- const drive = await db.getItem(this.buildDriveKey(id));
28424
- if (!drive) {
28715
+ let drive;
28716
+ try {
28717
+ drive = await this.get(id);
28718
+ } catch {
28425
28719
  throw new DriveNotFoundError(id);
28426
28720
  }
28427
28721
  return drive;
@@ -28437,8 +28731,18 @@ const _BrowserStorage = class _BrowserStorage {
28437
28731
  throw new Error(`Drive with slug ${slug} not found`);
28438
28732
  }
28439
28733
  async createDrive(id, drive) {
28440
- const db = await this.db;
28441
- await db.setItem(this.buildDriveKey(id), drive);
28734
+ const slug = drive.initialState.state.global.slug;
28735
+ if (slug) {
28736
+ let existingDrive;
28737
+ try {
28738
+ existingDrive = await this.getDriveBySlug(slug);
28739
+ } catch {
28740
+ }
28741
+ if (existingDrive) {
28742
+ throw new Error(`Drive with slug ${slug} already exists`);
28743
+ }
28744
+ }
28745
+ await this.create(id, drive);
28442
28746
  await this.updateDriveManifest(id, { documentIds: [] });
28443
28747
  }
28444
28748
  async deleteDrive(id) {
@@ -28446,13 +28750,13 @@ const _BrowserStorage = class _BrowserStorage {
28446
28750
  await Promise.all(documents.map((doc) => this.deleteDocument(id, doc)));
28447
28751
  const db = await this.db;
28448
28752
  await db.removeItem(this.buildManifestKey(id));
28449
- return db.removeItem(this.buildDriveKey(id));
28753
+ return db.removeItem(this.buildDocumentKey(id));
28450
28754
  }
28451
28755
  async addDriveOperations(id, operations, header) {
28452
28756
  const drive = await this.getDrive(id);
28453
28757
  const mergedOperations = mergeOperations(drive.operations, operations);
28454
28758
  const db = await this.db;
28455
- await db.setItem(this.buildDriveKey(id), {
28759
+ await db.setItem(this.buildDocumentKey(id), {
28456
28760
  ...drive,
28457
28761
  ...header,
28458
28762
  operations: mergedOperations
@@ -28461,14 +28765,13 @@ const _BrowserStorage = class _BrowserStorage {
28461
28765
  async getSynchronizationUnitsRevision(units) {
28462
28766
  const results = await Promise.allSettled(units.map(async (unit) => {
28463
28767
  try {
28464
- const document = await (unit.documentId ? this.getDocument(unit.driveId, unit.documentId) : this.getDrive(unit.driveId));
28768
+ const document = await this.get(unit.documentId);
28465
28769
  if (!document) {
28466
28770
  return void 0;
28467
28771
  }
28468
28772
  const operation = document.operations[unit.scope].at(-1);
28469
28773
  if (operation) {
28470
28774
  return {
28471
- driveId: unit.driveId,
28472
28775
  documentId: unit.documentId,
28473
28776
  scope: unit.scope,
28474
28777
  branch: unit.branch,
@@ -28500,7 +28803,7 @@ const _BrowserStorage = class _BrowserStorage {
28500
28803
  const drive = await this.getDrive(driveId);
28501
28804
  const migratedDrive = migrateDocumentOperationSignatures(drive);
28502
28805
  if (migratedDrive !== drive) {
28503
- return (await this.db).setItem(this.buildDriveKey(driveId), migratedDrive);
28806
+ return (await this.db).setItem(this.buildDocumentKey(driveId), migratedDrive);
28504
28807
  }
28505
28808
  }
28506
28809
  async migrateDocument(drive, id) {
@@ -28513,9 +28816,6 @@ const _BrowserStorage = class _BrowserStorage {
28513
28816
  ////////////////////////////////
28514
28817
  // Private methods
28515
28818
  ////////////////////////////////
28516
- buildDriveKey(driveId) {
28517
- return `${_BrowserStorage.DRIVES_KEY}${_BrowserStorage.SEP}${driveId}`;
28518
- }
28519
28819
  buildDocumentKey(documentId) {
28520
28820
  return `${_BrowserStorage.DOCUMENT_KEY}${_BrowserStorage.SEP}${documentId}`;
28521
28821
  }
@@ -28525,7 +28825,6 @@ const _BrowserStorage = class _BrowserStorage {
28525
28825
  };
28526
28826
  __publicField(_BrowserStorage, "DBName", "DOCUMENT_DRIVES");
28527
28827
  __publicField(_BrowserStorage, "SEP", ":");
28528
- __publicField(_BrowserStorage, "DRIVES_KEY", "DRIVES");
28529
28828
  __publicField(_BrowserStorage, "DOCUMENT_KEY", "DOCUMENT");
28530
28829
  __publicField(_BrowserStorage, "MANIFEST_KEY", "MANIFEST");
28531
28830
  let BrowserStorage = _BrowserStorage;
@@ -31131,7 +31430,7 @@ if (window.__VITE_ENVS.MODE === "development") {
31131
31430
  } else {
31132
31431
  serviceWorkerManager.registerServiceWorker(false);
31133
31432
  }
31134
- const App = lazy(() => __vitePreload(() => import("./app-Bw1Ba-jV.js").then((n) => n.aN), true ? __vite__mapDeps([0,1,2]) : void 0));
31433
+ const App = lazy(() => __vitePreload(() => import("./app-CsiwsM42.js").then((n) => n.aN), true ? __vite__mapDeps([0,1,2]) : void 0));
31135
31434
  const AppLoader = /* @__PURE__ */ jsx(Suspense, { children: /* @__PURE__ */ jsx(App, {}) });
31136
31435
  const appLoader = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
31137
31436
  __proto__: null,