@dxos/echo-pipeline 0.8.2 → 0.8.3-main.7f5a14c

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 (47) hide show
  1. package/dist/lib/browser/{chunk-3XSXS5EX.mjs → chunk-35I6ERLG.mjs} +2 -2
  2. package/dist/lib/browser/chunk-35I6ERLG.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +355 -352
  4. package/dist/lib/browser/index.mjs.map +3 -3
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +4 -4
  7. package/dist/lib/browser/testing/index.mjs.map +3 -3
  8. package/dist/lib/node/{chunk-SG2PL5RH.cjs → chunk-JXX6LF5U.cjs} +5 -5
  9. package/dist/lib/node/chunk-JXX6LF5U.cjs.map +7 -0
  10. package/dist/lib/node/index.cjs +321 -320
  11. package/dist/lib/node/index.cjs.map +3 -3
  12. package/dist/lib/node/meta.json +1 -1
  13. package/dist/lib/node/testing/index.cjs +13 -13
  14. package/dist/lib/node/testing/index.cjs.map +3 -3
  15. package/dist/lib/node-esm/{chunk-3BZP75TJ.mjs → chunk-5BHLPT24.mjs} +2 -2
  16. package/dist/lib/node-esm/chunk-5BHLPT24.mjs.map +7 -0
  17. package/dist/lib/node-esm/index.mjs +355 -352
  18. package/dist/lib/node-esm/index.mjs.map +3 -3
  19. package/dist/lib/node-esm/meta.json +1 -1
  20. package/dist/lib/node-esm/testing/index.mjs +4 -4
  21. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  22. package/dist/types/src/automerge/echo-network-adapter.d.ts +3 -3
  23. package/dist/types/src/automerge/echo-network-adapter.d.ts.map +1 -1
  24. package/dist/types/src/automerge/mesh-echo-replicator.d.ts.map +1 -1
  25. package/dist/types/src/db-host/documents-synchronizer.d.ts +1 -1
  26. package/dist/types/src/db-host/documents-synchronizer.d.ts.map +1 -1
  27. package/dist/types/src/edge/echo-edge-replicator.d.ts.map +1 -1
  28. package/dist/types/src/query/query-executor.d.ts.map +1 -1
  29. package/package.json +35 -35
  30. package/src/automerge/automerge-host.ts +3 -3
  31. package/src/automerge/automerge-repo.test.ts +48 -4
  32. package/src/automerge/echo-network-adapter.test.ts +7 -8
  33. package/src/automerge/echo-network-adapter.ts +50 -46
  34. package/src/automerge/mesh-echo-replicator.ts +1 -0
  35. package/src/db-host/data-service.ts +1 -1
  36. package/src/db-host/documents-iterator.ts +1 -1
  37. package/src/db-host/documents-synchronizer.test.ts +1 -1
  38. package/src/db-host/documents-synchronizer.ts +5 -3
  39. package/src/db-host/query-service.ts +3 -3
  40. package/src/edge/echo-edge-replicator.ts +2 -3
  41. package/src/pipeline/pipeline.ts +1 -1
  42. package/src/query/query-executor.ts +6 -6
  43. package/src/testing/change-metadata.ts +1 -1
  44. package/src/testing/test-replicator.ts +2 -2
  45. package/dist/lib/browser/chunk-3XSXS5EX.mjs.map +0 -7
  46. package/dist/lib/node/chunk-SG2PL5RH.cjs.map +0 -7
  47. package/dist/lib/node-esm/chunk-3BZP75TJ.mjs.map +0 -7
@@ -43,6 +43,13 @@ export type EchoNetworkAdapterParams = {
43
43
  monitor?: NetworkDataMonitor;
44
44
  };
45
45
 
46
+ type ConnectionEntry = {
47
+ isOpen: boolean;
48
+ connection: ReplicatorConnection;
49
+ reader: ReadableStreamDefaultReader<AutomergeProtocolMessage>;
50
+ writer: WritableStreamDefaultWriter<AutomergeProtocolMessage>;
51
+ };
52
+
46
53
  /**
47
54
  * Manages a set of {@link EchoReplicator} instances.
48
55
  */
@@ -110,6 +117,13 @@ export class EchoNetworkAdapter extends NetworkAdapter {
110
117
  await this._connected.wait({ timeout: 10_000 });
111
118
  }
112
119
 
120
+ public onConnectionAuthScopeChanged(peer: PeerId): void {
121
+ const entry = this._connections.get(peer);
122
+ if (entry) {
123
+ this._onConnectionAuthScopeChanged(entry.connection);
124
+ }
125
+ }
126
+
113
127
  @synchronized
114
128
  async addReplicator(replicator: EchoReplicator): Promise<void> {
115
129
  invariant(this._lifecycleState === LifecycleState.OPEN);
@@ -178,52 +192,57 @@ export class EchoNetworkAdapter extends NetworkAdapter {
178
192
  this._send(message);
179
193
  }
180
194
 
195
+ // TODO(dmaretskyi): Remove.
196
+ getPeersInterestedInCollection(collectionId: string): PeerId[] {
197
+ return Array.from(this._connections.values())
198
+ .map((connection) => {
199
+ return connection.connection.shouldSyncCollection({ collectionId })
200
+ ? (connection.connection.peerId as PeerId)
201
+ : null;
202
+ })
203
+ .filter(isNonNullable);
204
+ }
205
+
181
206
  private _send(message: Message): void {
182
207
  const connectionEntry = this._connections.get(message.targetId);
183
208
  if (!connectionEntry) {
184
209
  throw new Error('Connection not found.');
185
210
  }
186
211
 
187
- const writeStart = Date.now();
188
212
  // TODO(dmaretskyi): Find a way to enforce backpressure on AM-repo.
213
+ const start = Date.now();
189
214
  connectionEntry.writer
190
215
  .write(message as AutomergeProtocolMessage)
191
216
  .then(() => {
192
- const durationMs = Date.now() - writeStart;
193
- this._params.monitor?.recordMessageSent(message, durationMs);
217
+ this._params.monitor?.recordMessageSent(message, Date.now() - start);
194
218
  })
195
219
  .catch((err) => {
196
220
  if (connectionEntry.isOpen) {
197
221
  log.catch(err);
198
222
  }
223
+
199
224
  this._params.monitor?.recordMessageSendingFailed(message);
200
225
  });
201
226
  }
202
227
 
203
- // TODO(dmaretskyi): Remove.
204
- getPeersInterestedInCollection(collectionId: string): PeerId[] {
205
- return Array.from(this._connections.values())
206
- .map((connection) => {
207
- return connection.connection.shouldSyncCollection({ collectionId })
208
- ? (connection.connection.peerId as PeerId)
209
- : null;
210
- })
211
- .filter(isNonNullable);
212
- }
213
-
214
228
  private _onConnectionOpen(connection: ReplicatorConnection): void {
215
- log('Connection opened', { peerId: connection.peerId });
229
+ log('connection opened', { peerId: connection.peerId });
216
230
  invariant(!this._connections.has(connection.peerId as PeerId));
217
- const reader = connection.readable.getReader();
218
- const writer = connection.writable.getWriter();
219
- const connectionEntry: ConnectionEntry = { connection, reader, writer, isOpen: true };
231
+ const connectionEntry: ConnectionEntry = {
232
+ isOpen: true,
233
+ connection,
234
+ reader: connection.readable.getReader(),
235
+ writer: connection.writable.getWriter(),
236
+ };
237
+
220
238
  this._connections.set(connection.peerId as PeerId, connectionEntry);
221
239
 
240
+ // Read inbound messages.
222
241
  queueMicrotask(async () => {
223
242
  try {
224
243
  while (true) {
225
244
  // TODO(dmaretskyi): Find a way to enforce backpressure on AM-repo.
226
- const { done, value } = await reader.read();
245
+ const { done, value } = await connectionEntry.reader.read();
227
246
  if (done) {
228
247
  break;
229
248
  }
@@ -253,11 +272,18 @@ export class EchoNetworkAdapter extends NetworkAdapter {
253
272
  this._params.monitor?.recordMessageReceived(message);
254
273
  }
255
274
 
256
- public onConnectionAuthScopeChanged(peer: PeerId): void {
257
- const entry = this._connections.get(peer);
258
- if (entry) {
259
- this._onConnectionAuthScopeChanged(entry.connection);
260
- }
275
+ private _onConnectionClosed(connection: ReplicatorConnection): void {
276
+ log('connection closed', { peerId: connection.peerId });
277
+ const entry = this._connections.get(connection.peerId as PeerId);
278
+ invariant(entry);
279
+
280
+ entry.isOpen = false;
281
+ this.emit('peer-disconnected', { peerId: connection.peerId as PeerId });
282
+ this._params.monitor?.recordPeerDisconnected(connection.peerId);
283
+
284
+ void entry.reader.cancel().catch((err) => log.catch(err));
285
+ void entry.writer.abort().catch((err) => log.catch(err));
286
+ this._connections.delete(connection.peerId as PeerId);
261
287
  }
262
288
 
263
289
  /**
@@ -272,21 +298,6 @@ export class EchoNetworkAdapter extends NetworkAdapter {
272
298
  this._emitPeerCandidate(connection);
273
299
  }
274
300
 
275
- private _onConnectionClosed(connection: ReplicatorConnection): void {
276
- log('Connection closed', { peerId: connection.peerId });
277
- const entry = this._connections.get(connection.peerId as PeerId);
278
- invariant(entry);
279
-
280
- entry.isOpen = false;
281
- this.emit('peer-disconnected', { peerId: connection.peerId as PeerId });
282
- this._params.monitor?.recordPeerDisconnected(connection.peerId);
283
-
284
- void entry.reader.cancel().catch((err) => log.catch(err));
285
- void entry.writer.abort().catch((err) => log.catch(err));
286
-
287
- this._connections.delete(connection.peerId as PeerId);
288
- }
289
-
290
301
  private _emitPeerCandidate(connection: ReplicatorConnection): void {
291
302
  this.emit('peer-candidate', {
292
303
  peerId: connection.peerId as PeerId,
@@ -295,13 +306,6 @@ export class EchoNetworkAdapter extends NetworkAdapter {
295
306
  }
296
307
  }
297
308
 
298
- type ConnectionEntry = {
299
- connection: ReplicatorConnection;
300
- reader: ReadableStreamDefaultReader<AutomergeProtocolMessage>;
301
- writer: WritableStreamDefaultWriter<AutomergeProtocolMessage>;
302
- isOpen: boolean;
303
- };
304
-
305
309
  export const createEchoPeerMetadata = (): PeerMetadata =>
306
310
  ({
307
311
  // TODO(dmaretskyi): Refactor this.
@@ -125,6 +125,7 @@ export class MeshEchoReplicator implements EchoReplicator {
125
125
  documentId: params.documentId,
126
126
  acceptDocument: remoteDocumentExists,
127
127
  });
128
+
128
129
  // If a document is not present locally return true if another peer claims to have it.
129
130
  // Simply returning true will add the peer to "generous peers list" for this document which will
130
131
  // start replication of the document after we receive, even if the peer is not in the corresponding space.
@@ -92,7 +92,7 @@ export class DataServiceImpl implements DataService {
92
92
  const synchronizer = this._subscriptions.get(request.subscriptionId);
93
93
  invariant(synchronizer, 'Subscription not found');
94
94
 
95
- synchronizer.update(request.updates);
95
+ await synchronizer.update(request.updates);
96
96
  }
97
97
 
98
98
  async flush(request: FlushRequest): Promise<void> {
@@ -42,7 +42,7 @@ export const createSelectedDocumentsIterator = (automergeHost: AutomergeHost) =>
42
42
  doc = A.view(doc, heads);
43
43
  const end = Date.now();
44
44
  if (end - begin > LOG_VIEW_OPERATION_THRESHOLD) {
45
- log.info('Checking out document version is taking too long', {
45
+ log('Checking out document version is taking too long', {
46
46
  duration: end - begin,
47
47
  requestedHeads: heads,
48
48
  originalHeads: currentHeads,
@@ -23,7 +23,7 @@ describe('DocumentsSynchronizer', () => {
23
23
  });
24
24
  await openAndClose(synchronizer);
25
25
 
26
- synchronizer.update([
26
+ await synchronizer.update([
27
27
  {
28
28
  documentId: parseAutomergeUrl(generateAutomergeUrl()).documentId,
29
29
  mutation: A.save(A.from({ text: 'hello' })),
@@ -12,6 +12,8 @@ import { invariant } from '@dxos/invariant';
12
12
  import { log } from '@dxos/log';
13
13
  import { type BatchedDocumentUpdates, type DocumentUpdate } from '@dxos/protocols/proto/dxos/echo/service';
14
14
 
15
+ import { FIND_PARAMS } from '../automerge';
16
+
15
17
  const MAX_UPDATE_FREQ = 10; // [updates/sec]
16
18
 
17
19
  export type DocumentsSynchronizerParams = {
@@ -86,10 +88,10 @@ export class DocumentsSynchronizer extends Resource {
86
88
  this._syncStates.clear();
87
89
  }
88
90
 
89
- update(updates: DocumentUpdate[]): void {
91
+ async update(updates: DocumentUpdate[]): Promise<void> {
90
92
  for (const { documentId, mutation, isNew } of updates) {
91
93
  if (isNew) {
92
- const { handle: doc } = this._params.repo.findWithProgress<DatabaseDirectory>(documentId as DocumentId);
94
+ const doc = await this._params.repo.find<DatabaseDirectory>(documentId as DocumentId, FIND_PARAMS);
93
95
  doc.update((doc) => A.loadIncremental(doc, mutation));
94
96
  this._startSync(doc);
95
97
  } else {
@@ -100,7 +102,7 @@ export class DocumentsSynchronizer extends Resource {
100
102
 
101
103
  private _startSync(doc: DocHandle<DatabaseDirectory>): void {
102
104
  if (this._syncStates.has(doc.documentId)) {
103
- log.info('Document already being synced', { documentId: doc.documentId });
105
+ log('Document already being synced', { documentId: doc.documentId });
104
106
  return;
105
107
  }
106
108
 
@@ -138,7 +138,7 @@ export class QueryServiceImpl extends Resource implements QueryService {
138
138
  * Re-index all loaded documents.
139
139
  */
140
140
  async reindex(): Promise<void> {
141
- log.info('Reindexing all documents...');
141
+ log('Reindexing all documents...');
142
142
  const iterator = createDocumentsIterator(this._params.automergeHost);
143
143
  const ids: IdToHeads = new Map();
144
144
  for await (const documents of iterator()) {
@@ -146,11 +146,11 @@ export class QueryServiceImpl extends Resource implements QueryService {
146
146
  ids.set(id, heads);
147
147
  }
148
148
  if (ids.size % 100 === 0) {
149
- log.info('Collected documents...', { count: ids.size });
149
+ log('Collected documents...', { count: ids.size });
150
150
  }
151
151
  }
152
152
 
153
- log.info('Marking all documents as dirty...', { count: ids.size });
153
+ log('Marking all documents as dirty...', { count: ids.size });
154
154
  await this._params.indexer.reindex(ids);
155
155
  }
156
156
  }
@@ -58,9 +58,8 @@ export class EchoEdgeReplicator implements EchoReplicator {
58
58
  }
59
59
 
60
60
  async connect(context: EchoReplicatorContext): Promise<void> {
61
- log.info('connecting...', { peerId: context.peerId, connectedSpaces: this._connectedSpaces.size });
61
+ log('connecting...', { peerId: context.peerId, connectedSpaces: this._connectedSpaces.size });
62
62
  this._context = context;
63
-
64
63
  this._ctx = Context.default();
65
64
  this._ctx.onDispose(
66
65
  this._edgeConnection.onReconnected(() => {
@@ -146,7 +145,7 @@ export class EchoEdgeReplicator implements EchoReplicator {
146
145
  const restartDelay =
147
146
  Math.min(MAX_RESTART_DELAY, INITIAL_RESTART_DELAY * reconnects) + Math.random() * RESTART_DELAY_JITTER;
148
147
 
149
- log.info('connection restart scheduled', { spaceId, reconnects, restartDelay });
148
+ log('connection restart scheduled', { spaceId, reconnects, restartDelay });
150
149
 
151
150
  restartScheduled = true;
152
151
  scheduleTask(
@@ -409,7 +409,7 @@ export class Pipeline implements PipelineAccessor {
409
409
  if (err) {
410
410
  // log.warn(err); // TODO(burdon): Feed is closed/Download was cancelled.
411
411
  } else {
412
- log.info('downloaded', { data }); // TODO(burdon): Never called.
412
+ log('downloaded', { data }); // TODO(burdon): Never called.
413
413
  }
414
414
  });
415
415
 
@@ -97,6 +97,8 @@ type StepExecutionResult = {
97
97
  trace: ExecutionTrace;
98
98
  };
99
99
 
100
+ const TRACE_QUERY_EXECUTION = false;
101
+
100
102
  /**
101
103
  * Executes query plans against the Indexer and AutomergeHost.
102
104
  *
@@ -186,12 +188,10 @@ export class QueryExecutor extends Resource {
186
188
  workingSet[index].documentId !== item.documentId,
187
189
  );
188
190
 
189
- // log.info('Query execution result', {
190
- // changed,
191
- // trace: ExecutionTrace.format(trace),
192
- // });
193
- // eslint-disable-next-line no-console
194
- // console.log(ExecutionTrace.format(trace));
191
+ if (TRACE_QUERY_EXECUTION) {
192
+ // eslint-disable-next-line no-console
193
+ console.log(ExecutionTrace.format(trace));
194
+ }
195
195
 
196
196
  return {
197
197
  changed,
@@ -16,7 +16,7 @@ const EchoMetadata = schema.getCodecForType('dxos.echo.metadata.EchoMetadata');
16
16
  * Use this only for testing purposes.
17
17
  */
18
18
  export const changeStorageVersionInMetadata = async (storage: Storage, version: number) => {
19
- log.info('Changing storage version in metadata. USE ONLY FOR TESTING.');
19
+ log('Changing storage version in metadata. USE ONLY FOR TESTING.');
20
20
  const metadata = new MetadataStore(storage.createDirectory('metadata'));
21
21
  await metadata.load();
22
22
  const echoMetadata = metadata.metadata;
@@ -83,7 +83,7 @@ export class TestReplicationNetwork extends Resource {
83
83
  const forward = new TransformStream({
84
84
  transform: async (message, controller) => {
85
85
  if (LOG) {
86
- log.info('replicate', { from: peer1, to: peer2, message });
86
+ log('replicate', { from: peer1, to: peer2, message });
87
87
  }
88
88
 
89
89
  if (this._latency !== undefined) {
@@ -96,7 +96,7 @@ export class TestReplicationNetwork extends Resource {
96
96
  const backwards = new TransformStream({
97
97
  transform: async (message, controller) => {
98
98
  if (LOG) {
99
- log.info('replicate', { from: peer2, to: peer1, message });
99
+ log('replicate', { from: peer2, to: peer1, message });
100
100
  }
101
101
 
102
102
  if (this._latency !== undefined) {