@dxos/echo-pipeline 0.6.0 → 0.6.1-main.09a92b0

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 (42) hide show
  1. package/dist/lib/browser/{chunk-HS77A4I4.mjs → chunk-A2LCXJVD.mjs} +16 -1
  2. package/dist/lib/browser/chunk-A2LCXJVD.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +323 -211
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +1 -1
  7. package/dist/lib/node/{chunk-Y5U7UXEL.cjs → chunk-GHBIMYZK.cjs} +19 -4
  8. package/dist/lib/node/chunk-GHBIMYZK.cjs.map +7 -0
  9. package/dist/lib/node/index.cjs +364 -258
  10. package/dist/lib/node/index.cjs.map +4 -4
  11. package/dist/lib/node/meta.json +1 -1
  12. package/dist/lib/node/testing/index.cjs +11 -11
  13. package/dist/types/src/automerge/automerge-host.d.ts +13 -9
  14. package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
  15. package/dist/types/src/automerge/echo-network-adapter.d.ts +2 -2
  16. package/dist/types/src/automerge/echo-network-adapter.d.ts.map +1 -1
  17. package/dist/types/src/automerge/echo-network-adapter.test.d.ts +2 -0
  18. package/dist/types/src/automerge/echo-network-adapter.test.d.ts.map +1 -0
  19. package/dist/types/src/automerge/echo-replicator.d.ts +5 -6
  20. package/dist/types/src/automerge/echo-replicator.d.ts.map +1 -1
  21. package/dist/types/src/automerge/heads-store.d.ts +13 -0
  22. package/dist/types/src/automerge/heads-store.d.ts.map +1 -0
  23. package/dist/types/src/automerge/mesh-echo-replicator-connection.d.ts +35 -0
  24. package/dist/types/src/automerge/mesh-echo-replicator-connection.d.ts.map +1 -0
  25. package/dist/types/src/automerge/mesh-echo-replicator.d.ts +2 -2
  26. package/dist/types/src/automerge/mesh-echo-replicator.d.ts.map +1 -1
  27. package/dist/types/src/db-host/data-service.d.ts +4 -2
  28. package/dist/types/src/db-host/data-service.d.ts.map +1 -1
  29. package/package.json +33 -33
  30. package/src/automerge/automerge-doc-loader.ts +1 -1
  31. package/src/automerge/automerge-host.test.ts +34 -17
  32. package/src/automerge/automerge-host.ts +61 -17
  33. package/src/automerge/automerge-repo.test.ts +76 -1
  34. package/src/automerge/echo-network-adapter.test.ts +131 -0
  35. package/src/automerge/echo-network-adapter.ts +10 -6
  36. package/src/automerge/echo-replicator.ts +6 -9
  37. package/src/automerge/heads-store.ts +39 -0
  38. package/src/automerge/mesh-echo-replicator-connection.ts +130 -0
  39. package/src/automerge/mesh-echo-replicator.ts +15 -123
  40. package/src/db-host/data-service.ts +22 -2
  41. package/dist/lib/browser/chunk-HS77A4I4.mjs.map +0 -7
  42. package/dist/lib/node/chunk-Y5U7UXEL.cjs.map +0 -7
@@ -25,20 +25,22 @@ import {
25
25
  mapTimeframeToFeedIndexes,
26
26
  startAfter,
27
27
  valueEncoding
28
- } from "./chunk-HS77A4I4.mjs";
28
+ } from "./chunk-A2LCXJVD.mjs";
29
29
 
30
30
  // packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts
31
31
  import { Event, asyncTimeout } from "@dxos/async";
32
32
  import { next as automerge, getBackend, getHeads, isAutomerge, save } from "@dxos/automerge/automerge";
33
33
  import { Repo } from "@dxos/automerge/automerge-repo";
34
- import { Context, cancelWithContext } from "@dxos/context";
34
+ import { Resource as Resource2, cancelWithContext } from "@dxos/context";
35
+ import { invariant as invariant3 } from "@dxos/invariant";
35
36
  import { PublicKey } from "@dxos/keys";
37
+ import { log as log2 } from "@dxos/log";
36
38
  import { objectPointerCodec } from "@dxos/protocols";
37
39
  import { trace } from "@dxos/tracing";
38
40
  import { mapValues } from "@dxos/util";
39
41
 
40
42
  // packages/core/echo/echo-pipeline/src/automerge/echo-network-adapter.ts
41
- import { Trigger, synchronized } from "@dxos/async";
43
+ import { synchronized, Trigger } from "@dxos/async";
42
44
  import { NetworkAdapter } from "@dxos/automerge/automerge-repo";
43
45
  import { LifecycleState } from "@dxos/context";
44
46
  import { invariant } from "@dxos/invariant";
@@ -87,19 +89,13 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
87
89
  disconnect() {
88
90
  }
89
91
  async open() {
90
- invariant(this._lifecycleState === LifecycleState.CLOSED, void 0, {
91
- F: __dxlog_file,
92
- L: 60,
93
- S: this,
94
- A: [
95
- "this._lifecycleState === LifecycleState.CLOSED",
96
- ""
97
- ]
98
- });
92
+ if (this._lifecycleState === LifecycleState.OPEN) {
93
+ return;
94
+ }
99
95
  this._lifecycleState = LifecycleState.OPEN;
100
96
  log("emit ready", void 0, {
101
97
  F: __dxlog_file,
102
- L: 63,
98
+ L: 65,
103
99
  S: this,
104
100
  C: (f, a) => f(...a)
105
101
  });
@@ -108,15 +104,9 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
108
104
  });
109
105
  }
110
106
  async close() {
111
- invariant(this._lifecycleState === LifecycleState.OPEN, void 0, {
112
- F: __dxlog_file,
113
- L: 71,
114
- S: this,
115
- A: [
116
- "this._lifecycleState === LifecycleState.OPEN",
117
- ""
118
- ]
119
- });
107
+ if (this._lifecycleState === LifecycleState.CLOSED) {
108
+ return;
109
+ }
120
110
  for (const replicator of this._replicators) {
121
111
  await replicator.disconnect();
122
112
  }
@@ -131,7 +121,7 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
131
121
  async addReplicator(replicator) {
132
122
  invariant(this._lifecycleState === LifecycleState.OPEN, void 0, {
133
123
  F: __dxlog_file,
134
- L: 87,
124
+ L: 91,
135
125
  S: this,
136
126
  A: [
137
127
  "this._lifecycleState === LifecycleState.OPEN",
@@ -140,7 +130,7 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
140
130
  });
141
131
  invariant(this.peerId, void 0, {
142
132
  F: __dxlog_file,
143
- L: 88,
133
+ L: 92,
144
134
  S: this,
145
135
  A: [
146
136
  "this.peerId",
@@ -149,7 +139,7 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
149
139
  });
150
140
  invariant(!this._replicators.has(replicator), void 0, {
151
141
  F: __dxlog_file,
152
- L: 89,
142
+ L: 93,
153
143
  S: this,
154
144
  A: [
155
145
  "!this._replicators.has(replicator)",
@@ -168,7 +158,7 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
168
158
  async removeReplicator(replicator) {
169
159
  invariant(this._lifecycleState === LifecycleState.OPEN, void 0, {
170
160
  F: __dxlog_file,
171
- L: 103,
161
+ L: 107,
172
162
  S: this,
173
163
  A: [
174
164
  "this._lifecycleState === LifecycleState.OPEN",
@@ -177,7 +167,7 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
177
167
  });
178
168
  invariant(this._replicators.has(replicator), void 0, {
179
169
  F: __dxlog_file,
180
- L: 104,
170
+ L: 108,
181
171
  S: this,
182
172
  A: [
183
173
  "this._replicators.has(replicator)",
@@ -187,25 +177,25 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
187
177
  await replicator.disconnect();
188
178
  this._replicators.delete(replicator);
189
179
  }
190
- async shouldAdvertize(peerId, params) {
180
+ async shouldAdvertise(peerId, params) {
191
181
  const connection = this._connections.get(peerId);
192
182
  if (!connection) {
193
183
  return false;
194
184
  }
195
- return connection.connection.shouldAdvertize(params);
185
+ return connection.connection.shouldAdvertise(params);
196
186
  }
197
187
  _onConnectionOpen(connection) {
198
188
  log("Connection opened", {
199
189
  peerId: connection.peerId
200
190
  }, {
201
191
  F: __dxlog_file,
202
- L: 119,
192
+ L: 123,
203
193
  S: this,
204
194
  C: (f, a) => f(...a)
205
195
  });
206
196
  invariant(!this._connections.has(connection.peerId), void 0, {
207
197
  F: __dxlog_file,
208
- L: 120,
198
+ L: 124,
209
199
  S: this,
210
200
  A: [
211
201
  "!this._connections.has(connection.peerId as PeerId)",
@@ -234,7 +224,7 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
234
224
  if (connectionEntry.isOpen) {
235
225
  log.catch(err, void 0, {
236
226
  F: __dxlog_file,
237
- L: 139,
227
+ L: 143,
238
228
  S: this,
239
229
  C: (f, a) => f(...a)
240
230
  });
@@ -245,7 +235,7 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
245
235
  peerId: connection.peerId
246
236
  }, {
247
237
  F: __dxlog_file,
248
- L: 144,
238
+ L: 148,
249
239
  S: this,
250
240
  C: (f, a) => f(...a)
251
241
  });
@@ -260,14 +250,14 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
260
250
  peerId: connection.peerId
261
251
  }, {
262
252
  F: __dxlog_file,
263
- L: 153,
253
+ L: 157,
264
254
  S: this,
265
255
  C: (f, a) => f(...a)
266
256
  });
267
257
  const entry = this._connections.get(connection.peerId);
268
258
  invariant(entry, void 0, {
269
259
  F: __dxlog_file,
270
- L: 155,
260
+ L: 159,
271
261
  S: this,
272
262
  A: [
273
263
  "entry",
@@ -284,14 +274,14 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
284
274
  peerId: connection.peerId
285
275
  }, {
286
276
  F: __dxlog_file,
287
- L: 161,
277
+ L: 165,
288
278
  S: this,
289
279
  C: (f, a) => f(...a)
290
280
  });
291
281
  const entry = this._connections.get(connection.peerId);
292
282
  invariant(entry, void 0, {
293
283
  F: __dxlog_file,
294
- L: 163,
284
+ L: 167,
295
285
  S: this,
296
286
  A: [
297
287
  "entry",
@@ -304,13 +294,13 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
304
294
  });
305
295
  void entry.reader.cancel().catch((err) => log.catch(err, void 0, {
306
296
  F: __dxlog_file,
307
- L: 168,
297
+ L: 172,
308
298
  S: this,
309
299
  C: (f, a) => f(...a)
310
300
  }));
311
301
  void entry.writer.abort().catch((err) => log.catch(err, void 0, {
312
302
  F: __dxlog_file,
313
- L: 169,
303
+ L: 173,
314
304
  S: this,
315
305
  C: (f, a) => f(...a)
316
306
  }));
@@ -341,6 +331,34 @@ var createEchoPeerMetadata = () => ({
341
331
  });
342
332
  var isEchoPeerMetadata = (metadata) => metadata?.dxos_peerSource === "EchoNetworkAdapter";
343
333
 
334
+ // packages/core/echo/echo-pipeline/src/automerge/heads-store.ts
335
+ import { headsEncoding } from "@dxos/indexing";
336
+ var HeadsStore = class {
337
+ constructor({ db }) {
338
+ this._db = db;
339
+ }
340
+ setHeads(documentId, heads, batch) {
341
+ batch.put(documentId, heads, {
342
+ sublevel: this._db,
343
+ keyEncoding: "utf8",
344
+ valueEncoding: headsEncoding
345
+ });
346
+ }
347
+ async getHeads(documentId) {
348
+ try {
349
+ return await this._db.get(documentId, {
350
+ keyEncoding: "utf8",
351
+ valueEncoding: headsEncoding
352
+ });
353
+ } catch (err) {
354
+ if (err.notFound) {
355
+ return void 0;
356
+ }
357
+ throw err;
358
+ }
359
+ }
360
+ };
361
+
344
362
  // packages/core/echo/echo-pipeline/src/automerge/leveldb-storage-adapter.ts
345
363
  import { LifecycleState as LifecycleState2, Resource } from "@dxos/context";
346
364
  var LevelDBStorageAdapter = class extends Resource {
@@ -587,25 +605,26 @@ function _ts_decorate2(decorators, target, key, desc) {
587
605
  return c > 3 && r && Object.defineProperty(target, key, r), r;
588
606
  }
589
607
  var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts";
590
- var AutomergeHost = class {
608
+ var AutomergeHost = class extends Resource2 {
591
609
  constructor({ db, indexMetadataStore }) {
592
- this._ctx = new Context(void 0, {
593
- F: __dxlog_file3,
594
- L: 71
595
- });
610
+ super();
596
611
  this._echoNetworkAdapter = new EchoNetworkAdapter({
597
612
  getContainingSpaceForDocument: this._getContainingSpaceForDocument.bind(this)
598
613
  });
614
+ this._db = db;
599
615
  this._storage = new LevelDBStorageAdapter({
600
- db,
616
+ db: db.sublevel("automerge"),
601
617
  callbacks: {
602
618
  beforeSave: async (params) => this._beforeSave(params),
603
619
  afterSave: async () => this._afterSave()
604
620
  }
605
621
  });
622
+ this._headsStore = new HeadsStore({
623
+ db: db.sublevel("heads")
624
+ });
606
625
  this._indexMetadataStore = indexMetadataStore;
607
626
  }
608
- async open() {
627
+ async _open() {
609
628
  this._peerId = `host-${PublicKey.random().toHex()}`;
610
629
  await this._storage.open?.();
611
630
  this._clientNetwork = new LocalHostNetworkAdapter();
@@ -625,7 +644,7 @@ var AutomergeHost = class {
625
644
  await this._clientNetwork.whenConnected();
626
645
  await this._echoNetworkAdapter.whenConnected();
627
646
  }
628
- async close() {
647
+ async _close() {
629
648
  await this._storage.close?.();
630
649
  await this._clientNetwork.close();
631
650
  await this._echoNetworkAdapter.close();
@@ -637,6 +656,9 @@ var AutomergeHost = class {
637
656
  get repo() {
638
657
  return this._repo;
639
658
  }
659
+ get loadedDocsCount() {
660
+ return Object.keys(this._repo.handles).length;
661
+ }
640
662
  async addReplicator(replicator) {
641
663
  await this._echoNetworkAdapter.addReplicator(replicator);
642
664
  }
@@ -676,6 +698,56 @@ var AutomergeHost = class {
676
698
  return this._repo.create(initialValue);
677
699
  }
678
700
  }
701
+ async reIndexHeads(documentIds) {
702
+ for (const documentId of documentIds) {
703
+ log2.info("reindexing heads for document", {
704
+ documentId
705
+ }, {
706
+ F: __dxlog_file3,
707
+ L: 195,
708
+ S: this,
709
+ C: (f, a) => f(...a)
710
+ });
711
+ const handle = this._repo.find(documentId);
712
+ await handle.whenReady([
713
+ "ready",
714
+ "requesting"
715
+ ]);
716
+ if (handle.inState([
717
+ "requesting"
718
+ ])) {
719
+ log2.warn("document is not available locally, skipping", {
720
+ documentId
721
+ }, {
722
+ F: __dxlog_file3,
723
+ L: 199,
724
+ S: this,
725
+ C: (f, a) => f(...a)
726
+ });
727
+ continue;
728
+ }
729
+ const doc = handle.docSync();
730
+ invariant3(doc, void 0, {
731
+ F: __dxlog_file3,
732
+ L: 204,
733
+ S: this,
734
+ A: [
735
+ "doc",
736
+ ""
737
+ ]
738
+ });
739
+ const heads = getHeads(doc);
740
+ const batch = this._db.batch();
741
+ this._headsStore.setHeads(documentId, heads, batch);
742
+ await batch.write();
743
+ }
744
+ log2.info("done reindexing heads", void 0, {
745
+ F: __dxlog_file3,
746
+ L: 211,
747
+ S: this,
748
+ C: (f, a) => f(...a)
749
+ });
750
+ }
679
751
  // TODO(dmaretskyi): Share based on HALO permissions and space affinity.
680
752
  // Hosts, running in the worker, don't share documents unless requested by other peers.
681
753
  // NOTE: If both peers return sharePolicy=false the replication will not happen
@@ -689,7 +761,7 @@ var AutomergeHost = class {
689
761
  }
690
762
  const peerMetadata = this.repo.peerMetadataByPeerId[peerId];
691
763
  if (isEchoPeerMetadata(peerMetadata)) {
692
- return this._echoNetworkAdapter.shouldAdvertize(peerId, {
764
+ return this._echoNetworkAdapter.shouldAdvertise(peerId, {
693
765
  documentId
694
766
  });
695
767
  }
@@ -705,7 +777,8 @@ var AutomergeHost = class {
705
777
  return;
706
778
  }
707
779
  const spaceKey = getSpaceKeyFromDoc(doc) ?? void 0;
708
- const lastAvailableHash = getHeads(doc);
780
+ const heads = getHeads(doc);
781
+ this._headsStore.setHeads(handle.documentId, heads, batch);
709
782
  const objectIds = Object.keys(doc.objects ?? {});
710
783
  const encodedIds = objectIds.map((objectId) => objectPointerCodec.encode({
711
784
  documentId: handle.documentId,
@@ -714,7 +787,7 @@ var AutomergeHost = class {
714
787
  }));
715
788
  const idToLastHash = new Map(encodedIds.map((id) => [
716
789
  id,
717
- lastAvailableHash
790
+ heads
718
791
  ]));
719
792
  this._indexMetadataStore.markDirty(idToLastHash, batch);
720
793
  }
@@ -763,18 +836,30 @@ var AutomergeHost = class {
763
836
  /**
764
837
  * Flush documents to disk.
765
838
  */
766
- async flush({ states }) {
839
+ async flush({ states } = {}) {
767
840
  if (states) {
768
841
  await Promise.all(states.map(async ({ heads, documentId }) => {
769
842
  if (!heads) {
770
843
  return;
771
844
  }
772
- const handle = this.repo.handles[documentId] ?? this._repo.find(documentId);
845
+ const handle = this._repo.handles[documentId] ?? this._repo.find(documentId);
773
846
  await waitForHeads(handle, heads);
774
847
  }) ?? []);
775
848
  }
776
849
  await this._repo.flush(states?.map(({ documentId }) => documentId));
777
850
  }
851
+ async getHeads(documentId) {
852
+ const handle = this._repo.handles[documentId];
853
+ if (handle) {
854
+ const doc = handle.docSync();
855
+ if (!doc) {
856
+ return void 0;
857
+ }
858
+ return getHeads(doc);
859
+ } else {
860
+ return this._headsStore.getHeads(documentId);
861
+ }
862
+ }
778
863
  /**
779
864
  * Host <-> Client sync.
780
865
  */
@@ -847,8 +932,8 @@ import { interpretAsDocumentId } from "@dxos/automerge/automerge-repo";
847
932
  import { cancelWithContext as cancelWithContext2 } from "@dxos/context";
848
933
  import { warnAfterTimeout } from "@dxos/debug";
849
934
  import { SpaceDocVersion } from "@dxos/echo-protocol";
850
- import { invariant as invariant3 } from "@dxos/invariant";
851
- import { log as log2 } from "@dxos/log";
935
+ import { invariant as invariant4 } from "@dxos/invariant";
936
+ import { log as log3 } from "@dxos/log";
852
937
  import { trace as trace2 } from "@dxos/tracing";
853
938
  function _ts_decorate3(decorators, target, key, desc) {
854
939
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -886,7 +971,7 @@ var AutomergeDocumentLoaderImpl = class {
886
971
  }
887
972
  const existingDocHandle = await this._initDocHandle(ctx, spaceState.rootUrl);
888
973
  const doc = existingDocHandle.docSync();
889
- invariant3(doc, void 0, {
974
+ invariant4(doc, void 0, {
890
975
  F: __dxlog_file4,
891
976
  L: 84,
892
977
  S: this,
@@ -895,7 +980,7 @@ var AutomergeDocumentLoaderImpl = class {
895
980
  ""
896
981
  ]
897
982
  });
898
- invariant3(doc.version === SpaceDocVersion.CURRENT, void 0, {
983
+ invariant4(doc.version === SpaceDocVersion.CURRENT, void 0, {
899
984
  F: __dxlog_file4,
900
985
  L: 85,
901
986
  S: this,
@@ -916,7 +1001,7 @@ var AutomergeDocumentLoaderImpl = class {
916
1001
  let hasUrlsToLoad = false;
917
1002
  const urlsToLoad = {};
918
1003
  for (const objectId of objectIds) {
919
- invariant3(this._spaceRootDocHandle, void 0, {
1004
+ invariant4(this._spaceRootDocHandle, void 0, {
920
1005
  F: __dxlog_file4,
921
1006
  L: 97,
922
1007
  S: this,
@@ -929,7 +1014,7 @@ var AutomergeDocumentLoaderImpl = class {
929
1014
  continue;
930
1015
  }
931
1016
  const spaceRootDoc = this._spaceRootDocHandle.docSync();
932
- invariant3(spaceRootDoc, void 0, {
1017
+ invariant4(spaceRootDoc, void 0, {
933
1018
  F: __dxlog_file4,
934
1019
  L: 102,
935
1020
  S: this,
@@ -941,7 +1026,7 @@ var AutomergeDocumentLoaderImpl = class {
941
1026
  const documentUrl = (spaceRootDoc.links ?? {})[objectId];
942
1027
  if (documentUrl == null) {
943
1028
  this._objectsPendingDocumentLoad.add(objectId);
944
- log2.info("loading delayed until object links are initialized", {
1029
+ log3.info("loading delayed until object links are initialized", {
945
1030
  objectId
946
1031
  }, {
947
1032
  F: __dxlog_file4,
@@ -959,7 +1044,7 @@ var AutomergeDocumentLoaderImpl = class {
959
1044
  }
960
1045
  }
961
1046
  getObjectDocumentId(objectId) {
962
- invariant3(this._spaceRootDocHandle, void 0, {
1047
+ invariant4(this._spaceRootDocHandle, void 0, {
963
1048
  F: __dxlog_file4,
964
1049
  L: 118,
965
1050
  S: this,
@@ -969,7 +1054,7 @@ var AutomergeDocumentLoaderImpl = class {
969
1054
  ]
970
1055
  });
971
1056
  const spaceRootDoc = this._spaceRootDocHandle.docSync();
972
- invariant3(spaceRootDoc, void 0, {
1057
+ invariant4(spaceRootDoc, void 0, {
973
1058
  F: __dxlog_file4,
974
1059
  L: 120,
975
1060
  S: this,
@@ -993,7 +1078,7 @@ var AutomergeDocumentLoaderImpl = class {
993
1078
  linksAwaitingLoad.forEach(([objectId]) => this._objectsPendingDocumentLoad.delete(objectId));
994
1079
  }
995
1080
  getSpaceRootDocHandle() {
996
- invariant3(this._spaceRootDocHandle, void 0, {
1081
+ invariant4(this._spaceRootDocHandle, void 0, {
997
1082
  F: __dxlog_file4,
998
1083
  L: 140,
999
1084
  S: this,
@@ -1005,7 +1090,7 @@ var AutomergeDocumentLoaderImpl = class {
1005
1090
  return this._spaceRootDocHandle;
1006
1091
  }
1007
1092
  createDocumentForObject(objectId) {
1008
- invariant3(this._spaceRootDocHandle, void 0, {
1093
+ invariant4(this._spaceRootDocHandle, void 0, {
1009
1094
  F: __dxlog_file4,
1010
1095
  L: 145,
1011
1096
  S: this,
@@ -1047,7 +1132,7 @@ var AutomergeDocumentLoaderImpl = class {
1047
1132
  };
1048
1133
  const objectDocumentHandle = this._objectDocumentHandles.get(objectId);
1049
1134
  if (objectDocumentHandle != null && objectDocumentHandle.url !== automergeUrl) {
1050
- log2.warn("object already inlined in a different document, ignoring the link", {
1135
+ log3.warn("object already inlined in a different document, ignoring the link", {
1051
1136
  ...logMeta,
1052
1137
  actualDocumentUrl: objectDocumentHandle.url
1053
1138
  }, {
@@ -1059,7 +1144,7 @@ var AutomergeDocumentLoaderImpl = class {
1059
1144
  continue;
1060
1145
  }
1061
1146
  if (objectDocumentHandle?.url === automergeUrl) {
1062
- log2.warn("object document was already loaded", logMeta, {
1147
+ log3.warn("object document was already loaded", logMeta, {
1063
1148
  F: __dxlog_file4,
1064
1149
  L: 184,
1065
1150
  S: this,
@@ -1068,7 +1153,7 @@ var AutomergeDocumentLoaderImpl = class {
1068
1153
  continue;
1069
1154
  }
1070
1155
  const handle = this._repo.find(automergeUrl);
1071
- log2.debug("document loading triggered", logMeta, {
1156
+ log3.debug("document loading triggered", logMeta, {
1072
1157
  F: __dxlog_file4,
1073
1158
  L: 188,
1074
1159
  S: this,
@@ -1088,7 +1173,7 @@ var AutomergeDocumentLoaderImpl = class {
1088
1173
  break;
1089
1174
  } catch (err) {
1090
1175
  if (`${err}`.includes("Timeout")) {
1091
- log2.info("wraparound", {
1176
+ log3.info("wraparound", {
1092
1177
  id: docHandle.documentId,
1093
1178
  state: docHandle.state
1094
1179
  }, {
@@ -1117,15 +1202,13 @@ var AutomergeDocumentLoaderImpl = class {
1117
1202
  }
1118
1203
  async _createObjectOnDocumentLoad(handle, objectId) {
1119
1204
  try {
1120
- await handle.doc([
1121
- "ready"
1122
- ]);
1205
+ await handle.whenReady();
1123
1206
  const logMeta = {
1124
1207
  objectId,
1125
1208
  docUrl: handle.url
1126
1209
  };
1127
1210
  if (this.onObjectDocumentLoaded.listenerCount() === 0) {
1128
- log2.info("document loaded after all listeners were removed", logMeta, {
1211
+ log3.info("document loaded after all listeners were removed", logMeta, {
1129
1212
  F: __dxlog_file4,
1130
1213
  L: 231,
1131
1214
  S: this,
@@ -1135,7 +1218,7 @@ var AutomergeDocumentLoaderImpl = class {
1135
1218
  }
1136
1219
  const objectDocHandle = this._objectDocumentHandles.get(objectId);
1137
1220
  if (objectDocHandle?.url !== handle.url) {
1138
- log2.warn("object was rebound while a document was loading, discarding handle", logMeta, {
1221
+ log3.warn("object was rebound while a document was loading, discarding handle", logMeta, {
1139
1222
  F: __dxlog_file4,
1140
1223
  L: 236,
1141
1224
  S: this,
@@ -1149,7 +1232,7 @@ var AutomergeDocumentLoaderImpl = class {
1149
1232
  });
1150
1233
  } catch (err) {
1151
1234
  const shouldRetryLoading = this.onObjectDocumentLoaded.listenerCount() > 0;
1152
- log2.warn("failed to load a document", {
1235
+ log3.warn("failed to load a document", {
1153
1236
  objectId,
1154
1237
  automergeUrl: handle.url,
1155
1238
  retryLoading: shouldRetryLoading,
@@ -1176,14 +1259,134 @@ AutomergeDocumentLoaderImpl = _ts_decorate3([
1176
1259
  ], AutomergeDocumentLoaderImpl);
1177
1260
 
1178
1261
  // packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator.ts
1179
- import { cbor as cbor2 } from "@dxos/automerge/automerge-repo";
1180
- import { Resource as Resource2 } from "@dxos/context";
1181
- import { invariant as invariant4 } from "@dxos/invariant";
1262
+ import { invariant as invariant6 } from "@dxos/invariant";
1182
1263
  import { PublicKey as PublicKey2 } from "@dxos/keys";
1183
- import { log as log3 } from "@dxos/log";
1184
- import { AutomergeReplicator } from "@dxos/teleport-extension-automerge-replicator";
1264
+ import { log as log5 } from "@dxos/log";
1185
1265
  import { ComplexMap, ComplexSet, defaultMap } from "@dxos/util";
1186
- var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator.ts";
1266
+
1267
+ // packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator-connection.ts
1268
+ import { cbor as cbor2 } from "@dxos/automerge/automerge-repo";
1269
+ import { Resource as Resource3 } from "@dxos/context";
1270
+ import { invariant as invariant5 } from "@dxos/invariant";
1271
+ import { log as log4 } from "@dxos/log";
1272
+ import { AutomergeReplicator } from "@dxos/teleport-extension-automerge-replicator";
1273
+ var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator-connection.ts";
1274
+ var DEFAULT_FACTORY = (params) => new AutomergeReplicator(...params);
1275
+ var MeshReplicatorConnection = class extends Resource3 {
1276
+ constructor(_params) {
1277
+ super();
1278
+ this._params = _params;
1279
+ this.remoteDeviceKey = null;
1280
+ this._remotePeerId = null;
1281
+ this._isEnabled = false;
1282
+ let readableStreamController;
1283
+ this.readable = new ReadableStream({
1284
+ start: (controller) => {
1285
+ readableStreamController = controller;
1286
+ this._ctx.onDispose(() => controller.close());
1287
+ }
1288
+ });
1289
+ this.writable = new WritableStream({
1290
+ write: async (message, controller) => {
1291
+ invariant5(this._isEnabled, "Writing to a disabled connection", {
1292
+ F: __dxlog_file5,
1293
+ L: 47,
1294
+ S: this,
1295
+ A: [
1296
+ "this._isEnabled",
1297
+ "'Writing to a disabled connection'"
1298
+ ]
1299
+ });
1300
+ try {
1301
+ await this.replicatorExtension.sendSyncMessage({
1302
+ payload: cbor2.encode(message)
1303
+ });
1304
+ } catch (err) {
1305
+ controller.error(err);
1306
+ this._disconnectIfEnabled();
1307
+ }
1308
+ }
1309
+ });
1310
+ const createAutomergeReplicator = this._params.replicatorFactory ?? DEFAULT_FACTORY;
1311
+ this.replicatorExtension = createAutomergeReplicator([
1312
+ {
1313
+ peerId: this._params.ownPeerId
1314
+ },
1315
+ {
1316
+ onStartReplication: async (info, remotePeerId) => {
1317
+ this.remoteDeviceKey = remotePeerId;
1318
+ this._remotePeerId = info.id;
1319
+ log4("onStartReplication", {
1320
+ id: info.id,
1321
+ thisPeerId: this.peerId,
1322
+ remotePeerId: remotePeerId.toHex()
1323
+ }, {
1324
+ F: __dxlog_file5,
1325
+ L: 81,
1326
+ S: this,
1327
+ C: (f, a) => f(...a)
1328
+ });
1329
+ this._params.onRemoteConnected();
1330
+ },
1331
+ onSyncMessage: async ({ payload }) => {
1332
+ if (!this._isEnabled) {
1333
+ return;
1334
+ }
1335
+ const message = cbor2.decode(payload);
1336
+ readableStreamController.enqueue(message);
1337
+ },
1338
+ onClose: async () => {
1339
+ this._disconnectIfEnabled();
1340
+ }
1341
+ }
1342
+ ]);
1343
+ }
1344
+ _disconnectIfEnabled() {
1345
+ if (this._isEnabled) {
1346
+ this._params.onRemoteDisconnected();
1347
+ }
1348
+ }
1349
+ get peerId() {
1350
+ invariant5(this._remotePeerId != null, "Remote peer has not connected yet.", {
1351
+ F: __dxlog_file5,
1352
+ L: 107,
1353
+ S: this,
1354
+ A: [
1355
+ "this._remotePeerId != null",
1356
+ "'Remote peer has not connected yet.'"
1357
+ ]
1358
+ });
1359
+ return this._remotePeerId;
1360
+ }
1361
+ async shouldAdvertise(params) {
1362
+ return this._params.shouldAdvertise(params);
1363
+ }
1364
+ /**
1365
+ * Start exchanging messages with the remote peer.
1366
+ * Call after the remote peer has connected.
1367
+ */
1368
+ enable() {
1369
+ invariant5(this._remotePeerId != null, "Remote peer has not connected yet.", {
1370
+ F: __dxlog_file5,
1371
+ L: 120,
1372
+ S: this,
1373
+ A: [
1374
+ "this._remotePeerId != null",
1375
+ "'Remote peer has not connected yet.'"
1376
+ ]
1377
+ });
1378
+ this._isEnabled = true;
1379
+ }
1380
+ /**
1381
+ * Stop exchanging messages with the remote peer.
1382
+ */
1383
+ disable() {
1384
+ this._isEnabled = false;
1385
+ }
1386
+ };
1387
+
1388
+ // packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator.ts
1389
+ var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator.ts";
1187
1390
  var MeshEchoReplicator = class {
1188
1391
  constructor() {
1189
1392
  this._connections = /* @__PURE__ */ new Set();
@@ -1208,10 +1411,10 @@ var MeshEchoReplicator = class {
1208
1411
  this._connectionsPerPeer.clear();
1209
1412
  this._context = null;
1210
1413
  }
1211
- createExtension() {
1212
- invariant4(this._context, void 0, {
1213
- F: __dxlog_file5,
1214
- L: 54,
1414
+ createExtension(extensionFactory) {
1415
+ invariant6(this._context, void 0, {
1416
+ F: __dxlog_file6,
1417
+ L: 51,
1215
1418
  S: this,
1216
1419
  A: [
1217
1420
  "this._context",
@@ -1220,18 +1423,19 @@ var MeshEchoReplicator = class {
1220
1423
  });
1221
1424
  const connection = new MeshReplicatorConnection({
1222
1425
  ownPeerId: this._context.peerId,
1426
+ replicatorFactory: extensionFactory,
1223
1427
  onRemoteConnected: async () => {
1224
- log3("onRemoteConnected", {
1428
+ log5("onRemoteConnected", {
1225
1429
  peerId: connection.peerId
1226
1430
  }, {
1227
- F: __dxlog_file5,
1228
- L: 59,
1431
+ F: __dxlog_file6,
1432
+ L: 57,
1229
1433
  S: this,
1230
1434
  C: (f, a) => f(...a)
1231
1435
  });
1232
- invariant4(this._context, void 0, {
1233
- F: __dxlog_file5,
1234
- L: 60,
1436
+ invariant6(this._context, void 0, {
1437
+ F: __dxlog_file6,
1438
+ L: 58,
1235
1439
  S: this,
1236
1440
  A: [
1237
1441
  "this._context",
@@ -1243,36 +1447,36 @@ var MeshEchoReplicator = class {
1243
1447
  } else {
1244
1448
  this._connectionsPerPeer.set(connection.peerId, connection);
1245
1449
  this._context.onConnectionOpen(connection);
1246
- await connection.enable();
1450
+ connection.enable();
1247
1451
  }
1248
1452
  },
1249
1453
  onRemoteDisconnected: async () => {
1250
- log3("onRemoteDisconnected", {
1454
+ log5("onRemoteDisconnected", {
1251
1455
  peerId: connection.peerId
1252
1456
  }, {
1253
- F: __dxlog_file5,
1254
- L: 71,
1457
+ F: __dxlog_file6,
1458
+ L: 69,
1255
1459
  S: this,
1256
1460
  C: (f, a) => f(...a)
1257
1461
  });
1258
1462
  this._context?.onConnectionClosed(connection);
1259
1463
  this._connectionsPerPeer.delete(connection.peerId);
1260
- await connection.disable();
1464
+ connection.disable();
1261
1465
  this._connections.delete(connection);
1262
1466
  },
1263
- shouldAdvertize: async (params) => {
1264
- log3("shouldAdvertize", {
1467
+ shouldAdvertise: async (params) => {
1468
+ log5("shouldAdvertise", {
1265
1469
  peerId: connection.peerId,
1266
1470
  documentId: params.documentId
1267
1471
  }, {
1268
- F: __dxlog_file5,
1269
- L: 78,
1472
+ F: __dxlog_file6,
1473
+ L: 76,
1270
1474
  S: this,
1271
1475
  C: (f, a) => f(...a)
1272
1476
  });
1273
- invariant4(this._context, void 0, {
1274
- F: __dxlog_file5,
1275
- L: 79,
1477
+ invariant6(this._context, void 0, {
1478
+ F: __dxlog_file6,
1479
+ L: 77,
1276
1480
  S: this,
1277
1481
  A: [
1278
1482
  "this._context",
@@ -1282,12 +1486,12 @@ var MeshEchoReplicator = class {
1282
1486
  try {
1283
1487
  const spaceKey = await this._context.getContainingSpaceForDocument(params.documentId);
1284
1488
  if (!spaceKey) {
1285
- log3("space key not found for share policy check", {
1489
+ log5("space key not found for share policy check", {
1286
1490
  peerId: connection.peerId,
1287
1491
  documentId: params.documentId
1288
1492
  }, {
1289
- F: __dxlog_file5,
1290
- L: 83,
1493
+ F: __dxlog_file6,
1494
+ L: 81,
1291
1495
  S: this,
1292
1496
  C: (f, a) => f(...a)
1293
1497
  });
@@ -1295,19 +1499,19 @@ var MeshEchoReplicator = class {
1295
1499
  }
1296
1500
  const authorizedDevices = this._authorizedDevices.get(spaceKey);
1297
1501
  if (!connection.remoteDeviceKey) {
1298
- log3("device key not found for share policy check", {
1502
+ log5("device key not found for share policy check", {
1299
1503
  peerId: connection.peerId,
1300
1504
  documentId: params.documentId
1301
1505
  }, {
1302
- F: __dxlog_file5,
1303
- L: 93,
1506
+ F: __dxlog_file6,
1507
+ L: 91,
1304
1508
  S: this,
1305
1509
  C: (f, a) => f(...a)
1306
1510
  });
1307
1511
  return false;
1308
1512
  }
1309
1513
  const isAuthorized = authorizedDevices?.has(connection.remoteDeviceKey) ?? false;
1310
- log3("share policy check", {
1514
+ log5("share policy check", {
1311
1515
  localPeer: this._context.peerId,
1312
1516
  remotePeer: connection.peerId,
1313
1517
  documentId: params.documentId,
@@ -1315,16 +1519,16 @@ var MeshEchoReplicator = class {
1315
1519
  spaceKey,
1316
1520
  isAuthorized
1317
1521
  }, {
1318
- F: __dxlog_file5,
1319
- L: 101,
1522
+ F: __dxlog_file6,
1523
+ L: 99,
1320
1524
  S: this,
1321
1525
  C: (f, a) => f(...a)
1322
1526
  });
1323
1527
  return isAuthorized;
1324
1528
  } catch (err) {
1325
- log3.catch(err, void 0, {
1326
- F: __dxlog_file5,
1327
- L: 111,
1529
+ log5.catch(err, void 0, {
1530
+ F: __dxlog_file6,
1531
+ L: 109,
1328
1532
  S: this,
1329
1533
  C: (f, a) => f(...a)
1330
1534
  });
@@ -1336,115 +1540,23 @@ var MeshEchoReplicator = class {
1336
1540
  return connection.replicatorExtension;
1337
1541
  }
1338
1542
  authorizeDevice(spaceKey, deviceKey) {
1339
- log3("authorizeDevice", {
1543
+ log5("authorizeDevice", {
1340
1544
  spaceKey,
1341
1545
  deviceKey
1342
1546
  }, {
1343
- F: __dxlog_file5,
1344
- L: 122,
1547
+ F: __dxlog_file6,
1548
+ L: 120,
1345
1549
  S: this,
1346
1550
  C: (f, a) => f(...a)
1347
1551
  });
1348
1552
  defaultMap(this._authorizedDevices, spaceKey, () => new ComplexSet(PublicKey2.hash)).add(deviceKey);
1349
1553
  for (const connection of this._connections) {
1350
1554
  if (connection.remoteDeviceKey && connection.remoteDeviceKey.equals(deviceKey)) {
1351
- this._context?.onConnectionAuthScopeChanged(connection);
1352
- }
1353
- }
1354
- }
1355
- };
1356
- var MeshReplicatorConnection = class extends Resource2 {
1357
- constructor(_params) {
1358
- super();
1359
- this._params = _params;
1360
- this.remoteDeviceKey = null;
1361
- this._remotePeerId = null;
1362
- this._isEnabled = false;
1363
- let readableStreamController;
1364
- this.readable = new ReadableStream({
1365
- start: (controller) => {
1366
- readableStreamController = controller;
1367
- this._ctx.onDispose(() => controller.close());
1368
- }
1369
- });
1370
- this.writable = new WritableStream({
1371
- write: async (message, controller) => {
1372
- this.replicatorExtension.sendSyncMessage({
1373
- payload: cbor2.encode(message)
1374
- }).catch((err) => {
1375
- controller.error(err);
1376
- });
1377
- }
1378
- });
1379
- this.replicatorExtension = new AutomergeReplicator({
1380
- peerId: this._params.ownPeerId
1381
- }, {
1382
- onStartReplication: async (info, remotePeerId) => {
1383
- this.remoteDeviceKey = remotePeerId;
1384
- this._remotePeerId = info.id;
1385
- log3("onStartReplication", {
1386
- id: info.id,
1387
- thisPeerId: this.peerId,
1388
- remotePeerId: remotePeerId.toHex()
1389
- }, {
1390
- F: __dxlog_file5,
1391
- L: 192,
1392
- S: this,
1393
- C: (f, a) => f(...a)
1394
- });
1395
- await this._params.onRemoteConnected();
1396
- },
1397
- onSyncMessage: async ({ payload }) => {
1398
- if (!this._isEnabled) {
1399
- return;
1400
- }
1401
- const message = cbor2.decode(payload);
1402
- readableStreamController.enqueue(message);
1403
- },
1404
- onClose: async () => {
1405
- if (!this._isEnabled) {
1406
- return;
1555
+ if (this._connectionsPerPeer.has(connection.peerId)) {
1556
+ this._context?.onConnectionAuthScopeChanged(connection);
1407
1557
  }
1408
- await this._params.onRemoteDisconnected();
1409
1558
  }
1410
- });
1411
- }
1412
- get peerId() {
1413
- invariant4(this._remotePeerId != null, "Remote peer has not connected yet.", {
1414
- F: __dxlog_file5,
1415
- L: 215,
1416
- S: this,
1417
- A: [
1418
- "this._remotePeerId != null",
1419
- "'Remote peer has not connected yet.'"
1420
- ]
1421
- });
1422
- return this._remotePeerId;
1423
- }
1424
- async shouldAdvertize(params) {
1425
- return this._params.shouldAdvertize(params);
1426
- }
1427
- /**
1428
- * Start exchanging messages with the remote peer.
1429
- * Call after the remote peer has connected.
1430
- */
1431
- async enable() {
1432
- invariant4(this._remotePeerId != null, "Remote peer has not connected yet.", {
1433
- F: __dxlog_file5,
1434
- L: 228,
1435
- S: this,
1436
- A: [
1437
- "this._remotePeerId != null",
1438
- "'Remote peer has not connected yet.'"
1439
- ]
1440
- });
1441
- this._isEnabled = true;
1442
- }
1443
- /**
1444
- * Stop exchanging messages with the remote peer.
1445
- */
1446
- async disable() {
1447
- this._isEnabled = false;
1559
+ }
1448
1560
  }
1449
1561
  };
1450
1562
  export {