@dxos/echo-pipeline 0.3.11-next.e28df4f → 0.3.11-next.ee2b64c
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.
- package/dist/lib/browser/{chunk-D7UMNYLJ.mjs → chunk-IOUMNVGJ.mjs} +14 -8
- package/dist/lib/browser/{chunk-D7UMNYLJ.mjs.map → chunk-IOUMNVGJ.mjs.map} +2 -2
- package/dist/lib/browser/index.mjs +1 -1
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +1 -1
- package/dist/lib/node/{chunk-GQW6RLGD.cjs → chunk-PDU65RAS.cjs} +17 -11
- package/dist/lib/node/{chunk-GQW6RLGD.cjs.map → chunk-PDU65RAS.cjs.map} +2 -2
- package/dist/lib/node/index.cjs +26 -26
- package/dist/lib/node/index.cjs.map +1 -1
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +16 -16
- package/dist/types/src/automerge/automerge-host.d.ts +1 -0
- package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
- package/package.json +33 -33
- package/src/automerge/automerge-host.test.ts +62 -1
- package/src/automerge/automerge-host.ts +11 -5
|
@@ -7,7 +7,7 @@ import expect from 'expect';
|
|
|
7
7
|
import waitForExpect from 'wait-for-expect';
|
|
8
8
|
|
|
9
9
|
import { Trigger, asyncTimeout, sleep } from '@dxos/async';
|
|
10
|
-
import { type Message, NetworkAdapter, type PeerId, Repo } from '@dxos/automerge/automerge-repo';
|
|
10
|
+
import { type Message, NetworkAdapter, type PeerId, Repo, type HandleState } from '@dxos/automerge/automerge-repo';
|
|
11
11
|
import { invariant } from '@dxos/invariant';
|
|
12
12
|
import { log } from '@dxos/log';
|
|
13
13
|
import { StorageType, createStorage } from '@dxos/random-access-storage';
|
|
@@ -353,6 +353,67 @@ describe('AutomergeHost', () => {
|
|
|
353
353
|
|
|
354
354
|
await docC.whenReady();
|
|
355
355
|
});
|
|
356
|
+
|
|
357
|
+
test('replicate document after request', async () => {
|
|
358
|
+
const [adapter1, adapter2] = TestAdapter.createPair();
|
|
359
|
+
const repoA = new Repo({
|
|
360
|
+
peerId: 'A' as any,
|
|
361
|
+
network: [adapter1],
|
|
362
|
+
sharePolicy: async () => true,
|
|
363
|
+
});
|
|
364
|
+
const repoB = new Repo({
|
|
365
|
+
peerId: 'B' as any,
|
|
366
|
+
network: [adapter2],
|
|
367
|
+
sharePolicy: async () => true,
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
const unavailable: HandleState = 'unavailable';
|
|
371
|
+
|
|
372
|
+
{
|
|
373
|
+
// Connect repos.
|
|
374
|
+
adapter1.ready();
|
|
375
|
+
adapter2.ready();
|
|
376
|
+
await adapter1.onConnect.wait();
|
|
377
|
+
await adapter2.onConnect.wait();
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const docA = repoA.create();
|
|
381
|
+
// NOTE: Doesn't work if the doc is empty.
|
|
382
|
+
docA.change((doc: any) => {
|
|
383
|
+
doc.text = 'Hello world';
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
const docB = repoB.find(docA.url);
|
|
387
|
+
{
|
|
388
|
+
// Request document from repoB.
|
|
389
|
+
await asyncTimeout(docB.whenReady([unavailable]), 1_000);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
{
|
|
393
|
+
// Failing to find a document.
|
|
394
|
+
// await (docB.whenReady([unavailable]), 1_000);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
{
|
|
398
|
+
adapter1.peerCandidate(adapter2.peerId!);
|
|
399
|
+
await sleep(100);
|
|
400
|
+
adapter2.peerCandidate(adapter1.peerId!);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
{
|
|
404
|
+
await asyncTimeout(docB.whenReady([unavailable]), 1_000);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
{
|
|
408
|
+
// Note: Retry hack.
|
|
409
|
+
adapter1.peerDisconnected(adapter2.peerId!);
|
|
410
|
+
adapter2.peerDisconnected(adapter1.peerId!);
|
|
411
|
+
adapter1.peerCandidate(adapter2.peerId!);
|
|
412
|
+
adapter2.peerCandidate(adapter1.peerId!);
|
|
413
|
+
|
|
414
|
+
await asyncTimeout(docB.whenReady(), 1_000);
|
|
415
|
+
}
|
|
416
|
+
});
|
|
356
417
|
});
|
|
357
418
|
|
|
358
419
|
class TestAdapter extends NetworkAdapter {
|
|
@@ -255,6 +255,7 @@ class LocalHostNetworkAdapter extends NetworkAdapter {
|
|
|
255
255
|
*/
|
|
256
256
|
export class MeshNetworkAdapter extends NetworkAdapter {
|
|
257
257
|
private readonly _extensions: Map<string, AutomergeReplicator> = new Map();
|
|
258
|
+
private _connected = new Trigger();
|
|
258
259
|
|
|
259
260
|
/**
|
|
260
261
|
* Emits `ready` event. That signals to `Repo` that it can start using the adapter.
|
|
@@ -269,6 +270,7 @@ export class MeshNetworkAdapter extends NetworkAdapter {
|
|
|
269
270
|
|
|
270
271
|
override connect(peerId: PeerId): void {
|
|
271
272
|
this.peerId = peerId;
|
|
273
|
+
this._connected.wake();
|
|
272
274
|
}
|
|
273
275
|
|
|
274
276
|
override send(message: Message): void {
|
|
@@ -292,18 +294,22 @@ export class MeshNetworkAdapter extends NetworkAdapter {
|
|
|
292
294
|
},
|
|
293
295
|
{
|
|
294
296
|
onStartReplication: async (info, remotePeerId /** Teleport ID */) => {
|
|
297
|
+
await this._connected.wait();
|
|
298
|
+
|
|
295
299
|
// Note: We store only one extension per peer.
|
|
296
300
|
// There can be a case where two connected peers have more than one teleport connection between them
|
|
297
301
|
// and each of them uses different teleport connections to send messages.
|
|
298
302
|
// It works because we receive messages from all teleport connections and Automerge Repo dedup them.
|
|
299
303
|
// TODO(mykola): Use only one teleport connection per peer.
|
|
300
|
-
if (this._extensions.has(info.id)) {
|
|
301
|
-
|
|
304
|
+
if (!this._extensions.has(info.id)) {
|
|
305
|
+
peerInfo = info;
|
|
306
|
+
// TODO(mykola): Fix race condition?
|
|
307
|
+
this._extensions.set(info.id, extension);
|
|
308
|
+
} else {
|
|
309
|
+
// TODO(mykola): retry hack.
|
|
310
|
+
this.emit('peer-disconnected', { peerId: info.id as PeerId });
|
|
302
311
|
}
|
|
303
312
|
|
|
304
|
-
peerInfo = info;
|
|
305
|
-
// TODO(mykola): Fix race condition?
|
|
306
|
-
this._extensions.set(info.id, extension);
|
|
307
313
|
this.emit('peer-candidate', {
|
|
308
314
|
// TODO(mykola): Hack, stop abusing `peerMetadata` field.
|
|
309
315
|
peerMetadata: {
|