@dxos/echo-pipeline 0.8.4-main.ae835ea → 0.8.4-main.bc2380dfbc
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/LICENSE +102 -5
- package/README.md +1 -1
- package/dist/lib/{browser/chunk-WJJXJTNS.mjs → neutral/chunk-46DCRDA7.mjs} +44 -13
- package/dist/lib/neutral/chunk-46DCRDA7.mjs.map +7 -0
- package/dist/lib/{browser/chunk-FR6GJ4S4.mjs → neutral/chunk-LR7UFVQX.mjs} +145 -618
- package/dist/lib/neutral/chunk-LR7UFVQX.mjs.map +7 -0
- package/dist/lib/{browser → neutral}/filter/index.mjs +1 -2
- package/dist/lib/neutral/index.mjs +7332 -0
- package/dist/lib/neutral/index.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/lib/{browser → neutral}/testing/index.mjs +49 -292
- package/dist/lib/neutral/testing/index.mjs.map +7 -0
- package/dist/types/src/automerge/automerge-host-subduction.test.d.ts +2 -0
- package/dist/types/src/automerge/automerge-host-subduction.test.d.ts.map +1 -0
- package/dist/types/src/automerge/automerge-host.d.ts +105 -27
- package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
- package/dist/types/src/automerge/automerge-repo-subduction.test.d.ts +2 -0
- package/dist/types/src/automerge/automerge-repo-subduction.test.d.ts.map +1 -0
- package/dist/types/src/automerge/automerge-repo.test.d.ts +1 -1
- package/dist/types/src/automerge/automerge-repo.test.d.ts.map +1 -1
- package/dist/types/src/automerge/automerge-subduction.test.d.ts +2 -0
- package/dist/types/src/automerge/automerge-subduction.test.d.ts.map +1 -0
- package/dist/types/src/automerge/collection-synchronizer.d.ts +22 -2
- package/dist/types/src/automerge/collection-synchronizer.d.ts.map +1 -1
- package/dist/types/src/automerge/echo-data-monitor.d.ts.map +1 -1
- package/dist/types/src/automerge/echo-network-adapter.d.ts +17 -11
- package/dist/types/src/automerge/echo-network-adapter.d.ts.map +1 -1
- package/dist/types/src/automerge/echo-replicator.d.ts +28 -16
- package/dist/types/src/automerge/echo-replicator.d.ts.map +1 -1
- package/dist/types/src/automerge/errors.d.ts +35 -0
- package/dist/types/src/automerge/errors.d.ts.map +1 -0
- package/dist/types/src/automerge/handle-state.d.ts +52 -0
- package/dist/types/src/automerge/handle-state.d.ts.map +1 -0
- package/dist/types/src/automerge/heads-store.d.ts +9 -2
- package/dist/types/src/automerge/heads-store.d.ts.map +1 -1
- package/dist/types/src/automerge/index.d.ts +2 -0
- package/dist/types/src/automerge/index.d.ts.map +1 -1
- package/dist/types/src/automerge/leveldb-storage-adapter.d.ts +10 -4
- package/dist/types/src/automerge/leveldb-storage-adapter.d.ts.map +1 -1
- package/dist/types/src/automerge/mesh-echo-replicator-connection.d.ts +8 -8
- package/dist/types/src/automerge/mesh-echo-replicator-connection.d.ts.map +1 -1
- package/dist/types/src/automerge/mesh-echo-replicator.d.ts +6 -5
- package/dist/types/src/automerge/mesh-echo-replicator.d.ts.map +1 -1
- package/dist/types/src/automerge/network-protocol.d.ts.map +1 -1
- package/dist/types/src/automerge/space-collection.d.ts.map +1 -1
- package/dist/types/src/common/feeds.d.ts.map +1 -1
- package/dist/types/src/common/space-id.d.ts.map +1 -1
- package/dist/types/src/db-host/automerge-data-source.d.ts +35 -0
- package/dist/types/src/db-host/automerge-data-source.d.ts.map +1 -0
- package/dist/types/src/db-host/automerge-data-source.test.d.ts +2 -0
- package/dist/types/src/db-host/automerge-data-source.test.d.ts.map +1 -0
- package/dist/types/src/db-host/automerge-metrics.d.ts.map +1 -1
- package/dist/types/src/db-host/data-service.d.ts +12 -6
- package/dist/types/src/db-host/data-service.d.ts.map +1 -1
- package/dist/types/src/db-host/database-root.d.ts +9 -3
- package/dist/types/src/db-host/database-root.d.ts.map +1 -1
- package/dist/types/src/db-host/documents-synchronizer.d.ts +30 -8
- package/dist/types/src/db-host/documents-synchronizer.d.ts.map +1 -1
- package/dist/types/src/db-host/echo-host.d.ts +74 -28
- package/dist/types/src/db-host/echo-host.d.ts.map +1 -1
- package/dist/types/src/db-host/index.d.ts +2 -0
- package/dist/types/src/db-host/index.d.ts.map +1 -1
- package/dist/types/src/db-host/invalidation-hint.d.ts +19 -0
- package/dist/types/src/db-host/invalidation-hint.d.ts.map +1 -0
- package/dist/types/src/db-host/local-queue-service.d.ts +19 -0
- package/dist/types/src/db-host/local-queue-service.d.ts.map +1 -0
- package/dist/types/src/db-host/query-invalidation.test.d.ts +2 -0
- package/dist/types/src/db-host/query-invalidation.test.d.ts.map +1 -0
- package/dist/types/src/db-host/query-service.d.ts +18 -10
- package/dist/types/src/db-host/query-service.d.ts.map +1 -1
- package/dist/types/src/db-host/queue-data-source.d.ts +38 -0
- package/dist/types/src/db-host/queue-data-source.d.ts.map +1 -0
- package/dist/types/src/db-host/queue-service.test.d.ts +2 -0
- package/dist/types/src/db-host/queue-service.test.d.ts.map +1 -0
- package/dist/types/src/db-host/space-state-manager.d.ts +3 -2
- package/dist/types/src/db-host/space-state-manager.d.ts.map +1 -1
- package/dist/types/src/db-host/stub.d.ts +11 -0
- package/dist/types/src/db-host/stub.d.ts.map +1 -0
- package/dist/types/src/edge/echo-edge-replicator.d.ts +7 -6
- package/dist/types/src/edge/echo-edge-replicator.d.ts.map +1 -1
- package/dist/types/src/edge/echo-edge-subduction-replicator.d.ts +39 -0
- package/dist/types/src/edge/echo-edge-subduction-replicator.d.ts.map +1 -0
- package/dist/types/src/edge/echo-edge-subduction-replicator.test.d.ts +2 -0
- package/dist/types/src/edge/echo-edge-subduction-replicator.test.d.ts.map +1 -0
- package/dist/types/src/edge/index.d.ts +1 -0
- package/dist/types/src/edge/index.d.ts.map +1 -1
- package/dist/types/src/edge/inflight-request-limiter.d.ts.map +1 -1
- package/dist/types/src/filter/filter-match.d.ts +1 -1
- package/dist/types/src/filter/filter-match.d.ts.map +1 -1
- package/dist/types/src/metadata/metadata-store.d.ts.map +1 -1
- package/dist/types/src/pipeline/message-selector.d.ts.map +1 -1
- package/dist/types/src/pipeline/pipeline.d.ts +2 -2
- package/dist/types/src/pipeline/pipeline.d.ts.map +1 -1
- package/dist/types/src/pipeline/timeframe-clock.d.ts.map +1 -1
- package/dist/types/src/query/errors.d.ts +16 -20
- package/dist/types/src/query/errors.d.ts.map +1 -1
- package/dist/types/src/query/plan.d.ts +59 -8
- package/dist/types/src/query/plan.d.ts.map +1 -1
- package/dist/types/src/query/query-executor.d.ts +55 -12
- package/dist/types/src/query/query-executor.d.ts.map +1 -1
- package/dist/types/src/query/query-planner.d.ts +10 -1
- package/dist/types/src/query/query-planner.d.ts.map +1 -1
- package/dist/types/src/space/admission-discovery-extension.d.ts.map +1 -1
- package/dist/types/src/space/auth.d.ts +3 -3
- package/dist/types/src/space/auth.d.ts.map +1 -1
- package/dist/types/src/space/control-pipeline.d.ts +4 -3
- package/dist/types/src/space/control-pipeline.d.ts.map +1 -1
- package/dist/types/src/space/space-manager.d.ts +7 -7
- package/dist/types/src/space/space-manager.d.ts.map +1 -1
- package/dist/types/src/space/space-protocol.d.ts +9 -8
- package/dist/types/src/space/space-protocol.d.ts.map +1 -1
- package/dist/types/src/space/space.d.ts +5 -5
- package/dist/types/src/space/space.d.ts.map +1 -1
- package/dist/types/src/testing/change-metadata.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +0 -2
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/testing/test-agent-builder.d.ts.map +1 -1
- package/dist/types/src/testing/test-feed-builder.d.ts.map +1 -1
- package/dist/types/src/testing/test-network-adapter.d.ts +1 -1
- package/dist/types/src/testing/test-network-adapter.d.ts.map +1 -1
- package/dist/types/src/testing/test-replicator.d.ts +13 -13
- package/dist/types/src/testing/test-replicator.d.ts.map +1 -1
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +56 -54
- package/src/automerge/automerge-host-subduction.test.ts +263 -0
- package/src/automerge/automerge-host.test.ts +145 -32
- package/src/automerge/automerge-host.ts +442 -163
- package/src/automerge/automerge-repo-subduction.test.ts +1054 -0
- package/src/automerge/automerge-repo.test.ts +284 -77
- package/src/automerge/automerge-subduction.test.ts +330 -0
- package/src/automerge/collection-synchronizer.test.ts +96 -16
- package/src/automerge/collection-synchronizer.ts +125 -26
- package/src/automerge/echo-network-adapter.test.ts +2 -1
- package/src/automerge/echo-network-adapter.ts +44 -32
- package/src/automerge/echo-replicator.ts +30 -16
- package/src/automerge/errors.ts +10 -0
- package/src/automerge/handle-state.ts +62 -0
- package/src/automerge/heads-store.ts +42 -3
- package/src/automerge/index.ts +2 -0
- package/src/automerge/leveldb-storage-adapter.ts +70 -4
- package/src/automerge/mesh-echo-replicator-connection.ts +8 -8
- package/src/automerge/mesh-echo-replicator.ts +14 -11
- package/src/db-host/automerge-data-source.test.ts +299 -0
- package/src/db-host/automerge-data-source.ts +187 -0
- package/src/db-host/data-service.ts +27 -10
- package/src/db-host/database-root.ts +19 -7
- package/src/db-host/documents-synchronizer.test.ts +145 -14
- package/src/db-host/documents-synchronizer.ts +158 -59
- package/src/db-host/echo-host.ts +376 -90
- package/src/db-host/index.ts +2 -0
- package/src/db-host/invalidation-hint.ts +50 -0
- package/src/db-host/local-queue-service.ts +127 -0
- package/src/db-host/query-invalidation.test.ts +270 -0
- package/src/db-host/query-service.ts +108 -111
- package/src/db-host/queue-data-source.ts +160 -0
- package/src/db-host/queue-service.test.ts +145 -0
- package/src/db-host/space-state-manager.ts +11 -9
- package/src/db-host/stub.ts +33 -0
- package/src/edge/echo-edge-replicator.test.ts +9 -9
- package/src/edge/echo-edge-replicator.ts +50 -42
- package/src/edge/echo-edge-subduction-replicator.test.ts +158 -0
- package/src/edge/echo-edge-subduction-replicator.ts +377 -0
- package/src/edge/index.ts +1 -0
- package/src/filter/filter-match.test.ts +41 -25
- package/src/filter/filter-match.ts +75 -20
- package/src/metadata/metadata-store.ts +8 -5
- package/src/pipeline/pipeline-stress.test.ts +1 -3
- package/src/pipeline/pipeline.test.ts +0 -1
- package/src/pipeline/pipeline.ts +2 -3
- package/src/query/errors.ts +2 -2
- package/src/query/plan.ts +73 -9
- package/src/query/query-executor.ts +1064 -172
- package/src/query/query-planner.test.ts +854 -86
- package/src/query/query-planner.ts +444 -38
- package/src/space/admission-discovery-extension.ts +1 -1
- package/src/space/auth.ts +6 -6
- package/src/space/control-pipeline.test.ts +2 -2
- package/src/space/control-pipeline.ts +7 -7
- package/src/space/space-manager.ts +12 -17
- package/src/space/space-protocol.browser.test.ts +13 -12
- package/src/space/space-protocol.test.ts +13 -13
- package/src/space/space-protocol.ts +16 -15
- package/src/space/space.test.ts +2 -2
- package/src/space/space.ts +9 -10
- package/src/testing/index.ts +0 -2
- package/src/testing/test-agent-builder.ts +0 -1
- package/src/testing/test-network-adapter.ts +24 -3
- package/src/testing/test-replicator.ts +15 -20
- package/src/util.ts +7 -3
- package/dist/lib/browser/chunk-CGS2ULMK.mjs +0 -11
- package/dist/lib/browser/chunk-CGS2ULMK.mjs.map +0 -7
- package/dist/lib/browser/chunk-FR6GJ4S4.mjs.map +0 -7
- package/dist/lib/browser/chunk-WJJXJTNS.mjs.map +0 -7
- package/dist/lib/browser/index.mjs +0 -5492
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/testing/index.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +0 -11
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-JQCCVDLT.mjs +0 -2144
- package/dist/lib/node-esm/chunk-JQCCVDLT.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-LEQ77KAT.mjs +0 -240
- package/dist/lib/node-esm/chunk-LEQ77KAT.mjs.map +0 -7
- package/dist/lib/node-esm/filter/index.mjs +0 -13
- package/dist/lib/node-esm/filter/index.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -5492
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/testing/index.mjs +0 -764
- package/dist/lib/node-esm/testing/index.mjs.map +0 -7
- package/dist/types/src/db-host/documents-iterator.d.ts +0 -7
- package/dist/types/src/db-host/documents-iterator.d.ts.map +0 -1
- package/dist/types/src/testing/test-data.d.ts +0 -18
- package/dist/types/src/testing/test-data.d.ts.map +0 -1
- package/dist/types/src/testing/test-schema.d.ts +0 -37
- package/dist/types/src/testing/test-schema.d.ts.map +0 -1
- package/src/db-host/documents-iterator.ts +0 -74
- package/src/testing/test-data.ts +0 -127
- package/src/testing/test-schema.ts +0 -53
- /package/dist/lib/{browser → neutral}/filter/index.mjs.map +0 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
DeleteFromQueueRequest,
|
|
7
|
+
InsertIntoQueueRequest,
|
|
8
|
+
QueryQueueRequest,
|
|
9
|
+
QueueQueryResult,
|
|
10
|
+
QueueService,
|
|
11
|
+
SyncQueueRequest,
|
|
12
|
+
} from '@dxos/protocols/proto/dxos/client/services';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Stub implementation for when Edge is not available.
|
|
16
|
+
*/
|
|
17
|
+
export class QueueServiceStub implements QueueService {
|
|
18
|
+
queryQueue(request: QueryQueueRequest): Promise<QueueQueryResult> {
|
|
19
|
+
throw new Error('Not available.');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
insertIntoQueue(request: InsertIntoQueueRequest): Promise<void> {
|
|
23
|
+
throw new Error('Not available.');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
deleteFromQueue(request: DeleteFromQueueRequest): Promise<void> {
|
|
27
|
+
throw new Error('Not available.');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
syncQueue(request: SyncQueueRequest): Promise<void> {
|
|
31
|
+
throw new Error('Not available.');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -7,6 +7,7 @@ import { getRandomPort } from 'get-port-please';
|
|
|
7
7
|
import { describe, expect, onTestFinished, test } from 'vitest';
|
|
8
8
|
|
|
9
9
|
import { Event } from '@dxos/async';
|
|
10
|
+
import { Context } from '@dxos/context';
|
|
10
11
|
import { EdgeClient, type EdgeHttpClient, MessageSchema, createEphemeralEdgeIdentity } from '@dxos/edge-client';
|
|
11
12
|
import { createTestEdgeWsServer } from '@dxos/edge-client/testing';
|
|
12
13
|
import { PublicKey, SpaceId } from '@dxos/keys';
|
|
@@ -16,8 +17,7 @@ import { createBuf } from '@dxos/protocols/buf';
|
|
|
16
17
|
import type { Peer } from '@dxos/protocols/proto/dxos/edge/messenger';
|
|
17
18
|
import { openAndClose } from '@dxos/test-utils';
|
|
18
19
|
|
|
19
|
-
import type {
|
|
20
|
-
|
|
20
|
+
import type { AutomergeReplicatorConnection, AutomergeReplicatorContext } from '../automerge';
|
|
21
21
|
import { EchoEdgeReplicator } from './echo-edge-replicator';
|
|
22
22
|
|
|
23
23
|
describe('EchoEdgeReplicator', () => {
|
|
@@ -28,7 +28,7 @@ describe('EchoEdgeReplicator', () => {
|
|
|
28
28
|
|
|
29
29
|
const { context, connectionOpen } = createMockContext();
|
|
30
30
|
const replicator = await connectReplicator(client, context);
|
|
31
|
-
await replicator.connectToSpace(spaceId);
|
|
31
|
+
await replicator.connectToSpace(Context.default(), spaceId);
|
|
32
32
|
|
|
33
33
|
client.setIdentity(await createEphemeralEdgeIdentity());
|
|
34
34
|
await connectionOpen.waitForCount(1);
|
|
@@ -55,7 +55,7 @@ describe('EchoEdgeReplicator', () => {
|
|
|
55
55
|
documentSpaceId: { [documentId]: spaceId },
|
|
56
56
|
});
|
|
57
57
|
const replicator = await connectReplicator(client, context);
|
|
58
|
-
await replicator.connectToSpace(spaceId);
|
|
58
|
+
await replicator.connectToSpace(Context.default(), spaceId);
|
|
59
59
|
|
|
60
60
|
await expect.poll(() => openConnections.length === 1).toBeTruthy();
|
|
61
61
|
expect(openConnections[0].shouldAdvertise({ documentId })).toBeTruthy();
|
|
@@ -69,7 +69,7 @@ describe('EchoEdgeReplicator', () => {
|
|
|
69
69
|
const remoteCollections: { [peerId: string]: { [documentId: string]: boolean } } = {};
|
|
70
70
|
const { context, openConnections } = createMockContext({ remoteCollections });
|
|
71
71
|
const replicator = await connectReplicator(client, context);
|
|
72
|
-
await replicator.connectToSpace(spaceId);
|
|
72
|
+
await replicator.connectToSpace(Context.default(), spaceId);
|
|
73
73
|
|
|
74
74
|
await expect.poll(() => openConnections.length === 1).toBeTruthy();
|
|
75
75
|
const connection = openConnections[0];
|
|
@@ -79,10 +79,10 @@ describe('EchoEdgeReplicator', () => {
|
|
|
79
79
|
});
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
-
const connectReplicator = async (client: EdgeClient, context:
|
|
82
|
+
const connectReplicator = async (client: EdgeClient, context: AutomergeReplicatorContext) => {
|
|
83
83
|
// EdgeHttpClient functionality is not tested here.
|
|
84
84
|
const replicator = new EchoEdgeReplicator({ edgeConnection: client, edgeHttpClient: {} as EdgeHttpClient });
|
|
85
|
-
await replicator.connect(context);
|
|
85
|
+
await replicator.connect(Context.default(), context);
|
|
86
86
|
onTestFinished(() => replicator.disconnect());
|
|
87
87
|
return replicator;
|
|
88
88
|
};
|
|
@@ -101,7 +101,7 @@ const createMockContext = (args?: {
|
|
|
101
101
|
documentSpaceId?: { [documentId: string]: SpaceId };
|
|
102
102
|
}) => {
|
|
103
103
|
const connectionOpen = new Event();
|
|
104
|
-
const openConnections:
|
|
104
|
+
const openConnections: AutomergeReplicatorConnection[] = [];
|
|
105
105
|
return {
|
|
106
106
|
context: {
|
|
107
107
|
getContainingSpaceIdForDocument: async (documentId) => args?.documentSpaceId?.[documentId] ?? null,
|
|
@@ -121,7 +121,7 @@ const createMockContext = (args?: {
|
|
|
121
121
|
},
|
|
122
122
|
|
|
123
123
|
peerId: PublicKey.random().toHex(),
|
|
124
|
-
} satisfies
|
|
124
|
+
} satisfies AutomergeReplicatorContext,
|
|
125
125
|
|
|
126
126
|
openConnections,
|
|
127
127
|
connectionOpen,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import * as
|
|
5
|
+
import * as A from '@automerge/automerge';
|
|
6
6
|
import { type DocumentId, type Heads, cbor } from '@automerge/automerge-repo';
|
|
7
7
|
|
|
8
8
|
import { Mutex, scheduleMicroTask, scheduleTask } from '@dxos/async';
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
type AutomergeProtocolMessage,
|
|
18
18
|
DocumentCodec,
|
|
19
19
|
EdgeService,
|
|
20
|
+
type ErrorProtocolMessage,
|
|
20
21
|
type ExportBundleRequest,
|
|
21
22
|
type ImportBundleRequest,
|
|
22
23
|
type PeerId,
|
|
@@ -26,17 +27,17 @@ import {
|
|
|
26
27
|
type Message as RouterMessage,
|
|
27
28
|
MessageSchema as RouterMessageSchema,
|
|
28
29
|
} from '@dxos/protocols/buf/dxos/edge/messenger_pb';
|
|
29
|
-
import {
|
|
30
|
+
import { trace } from '@dxos/tracing';
|
|
31
|
+
import { bufferToArray, compositeKey, setDeep } from '@dxos/util';
|
|
30
32
|
|
|
31
33
|
import {
|
|
32
|
-
type
|
|
33
|
-
type
|
|
34
|
-
type
|
|
35
|
-
type
|
|
36
|
-
type
|
|
34
|
+
type AutomergeReplicatorConnection,
|
|
35
|
+
type AutomergeReplicatorContext,
|
|
36
|
+
type EdgeAutomergeReplicator,
|
|
37
|
+
type ShouldAdvertiseProps,
|
|
38
|
+
type ShouldSyncCollectionProps,
|
|
37
39
|
getSpaceIdFromCollectionId,
|
|
38
40
|
} from '../automerge';
|
|
39
|
-
|
|
40
41
|
import { InflightRequestLimiter } from './inflight-request-limiter';
|
|
41
42
|
|
|
42
43
|
/**
|
|
@@ -46,33 +47,34 @@ const INITIAL_RESTART_DELAY = 500;
|
|
|
46
47
|
const RESTART_DELAY_JITTER = 250;
|
|
47
48
|
const MAX_RESTART_DELAY = 5000;
|
|
48
49
|
|
|
49
|
-
export type
|
|
50
|
+
export type EchoEdgeReplicatorProps = {
|
|
50
51
|
edgeConnection: EdgeConnection;
|
|
51
52
|
edgeHttpClient: EdgeHttpClient;
|
|
52
53
|
disableSharePolicy?: boolean;
|
|
53
54
|
};
|
|
54
55
|
|
|
55
|
-
|
|
56
|
+
@trace.resource()
|
|
57
|
+
export class EchoEdgeReplicator implements EdgeAutomergeReplicator {
|
|
56
58
|
private readonly _edgeConnection: EdgeConnection;
|
|
57
59
|
private readonly _edgeHttpClient: EdgeHttpClient;
|
|
58
60
|
private readonly _mutex = new Mutex();
|
|
59
61
|
|
|
60
62
|
private _ctx?: Context = undefined;
|
|
61
|
-
private _context:
|
|
63
|
+
private _context: AutomergeReplicatorContext | null = null;
|
|
62
64
|
private _connectedSpaces = new Set<SpaceId>();
|
|
63
65
|
private _connections = new Map<SpaceId, EdgeReplicatorConnection>();
|
|
64
66
|
private _sharePolicyEnabled = true;
|
|
65
67
|
|
|
66
|
-
constructor({ edgeConnection, edgeHttpClient, disableSharePolicy }:
|
|
68
|
+
constructor({ edgeConnection, edgeHttpClient, disableSharePolicy }: EchoEdgeReplicatorProps) {
|
|
67
69
|
this._edgeConnection = edgeConnection;
|
|
68
70
|
this._edgeHttpClient = edgeHttpClient;
|
|
69
71
|
this._sharePolicyEnabled = !disableSharePolicy;
|
|
70
72
|
}
|
|
71
73
|
|
|
72
|
-
async connect(context:
|
|
74
|
+
async connect(ctx: Context, context: AutomergeReplicatorContext): Promise<void> {
|
|
73
75
|
log('connecting...', { peerId: context.peerId, connectedSpaces: this._connectedSpaces.size });
|
|
74
76
|
this._context = context;
|
|
75
|
-
this._ctx =
|
|
77
|
+
this._ctx = ctx.derive();
|
|
76
78
|
this._ctx.onDispose(
|
|
77
79
|
this._edgeConnection.onReconnected(() => {
|
|
78
80
|
this._ctx && scheduleMicroTask(this._ctx, () => this._handleReconnect());
|
|
@@ -91,7 +93,7 @@ export class EchoEdgeReplicator implements EchoReplicator {
|
|
|
91
93
|
|
|
92
94
|
if (this._context !== null) {
|
|
93
95
|
for (const spaceId of spaces) {
|
|
94
|
-
await this._openConnection(spaceId);
|
|
96
|
+
await this._openConnection(this._ctx!, spaceId);
|
|
95
97
|
}
|
|
96
98
|
}
|
|
97
99
|
}
|
|
@@ -106,7 +108,9 @@ export class EchoEdgeReplicator implements EchoReplicator {
|
|
|
106
108
|
this._connections.clear();
|
|
107
109
|
}
|
|
108
110
|
|
|
109
|
-
|
|
111
|
+
@trace.span({ showInBrowserTimeline: true, op: 'replication' })
|
|
112
|
+
async connectToSpace(ctx: Context, spaceId: SpaceId): Promise<void> {
|
|
113
|
+
log('connectToSpace', { spaceId });
|
|
110
114
|
using _guard = await this._mutex.acquire();
|
|
111
115
|
|
|
112
116
|
if (this._connectedSpaces.has(spaceId)) {
|
|
@@ -114,9 +118,8 @@ export class EchoEdgeReplicator implements EchoReplicator {
|
|
|
114
118
|
}
|
|
115
119
|
this._connectedSpaces.add(spaceId);
|
|
116
120
|
|
|
117
|
-
// Check if AM-repo requested that we connect to remote peers.
|
|
118
121
|
if (this._context !== null) {
|
|
119
|
-
await this._openConnection(spaceId);
|
|
122
|
+
await this._openConnection(ctx, spaceId);
|
|
120
123
|
}
|
|
121
124
|
}
|
|
122
125
|
|
|
@@ -132,7 +135,8 @@ export class EchoEdgeReplicator implements EchoReplicator {
|
|
|
132
135
|
}
|
|
133
136
|
}
|
|
134
137
|
|
|
135
|
-
|
|
138
|
+
@trace.span({ showInBrowserTimeline: true, op: 'replication' })
|
|
139
|
+
private async _openConnection(ctx: Context, spaceId: SpaceId, reconnects: number = 0): Promise<void> {
|
|
136
140
|
invariant(this._context);
|
|
137
141
|
invariant(!this._connections.has(spaceId));
|
|
138
142
|
|
|
@@ -164,21 +168,21 @@ export class EchoEdgeReplicator implements EchoReplicator {
|
|
|
164
168
|
|
|
165
169
|
restartScheduled = true;
|
|
166
170
|
scheduleTask(
|
|
167
|
-
this._ctx
|
|
171
|
+
this._ctx!,
|
|
168
172
|
async () => {
|
|
169
173
|
using _guard = await this._mutex.acquire();
|
|
170
174
|
if (this._connections.get(spaceId) !== connection) {
|
|
171
175
|
return;
|
|
172
176
|
}
|
|
173
177
|
|
|
174
|
-
const
|
|
175
|
-
await connection.close();
|
|
178
|
+
const replicatorCtx = this._ctx;
|
|
179
|
+
await connection.close();
|
|
176
180
|
this._connections.delete(spaceId);
|
|
177
|
-
if (
|
|
181
|
+
if (replicatorCtx?.disposed) {
|
|
178
182
|
return;
|
|
179
183
|
}
|
|
180
184
|
log.trace('dxos.echo.edge.replicator.restart', { spaceId, reconnects, restartDelay });
|
|
181
|
-
await this._openConnection(spaceId, reconnects + 1);
|
|
185
|
+
await this._openConnection(replicatorCtx!, spaceId, reconnects + 1);
|
|
182
186
|
},
|
|
183
187
|
restartDelay,
|
|
184
188
|
);
|
|
@@ -186,15 +190,15 @@ export class EchoEdgeReplicator implements EchoReplicator {
|
|
|
186
190
|
});
|
|
187
191
|
this._connections.set(spaceId, connection);
|
|
188
192
|
|
|
189
|
-
await connection.open();
|
|
193
|
+
await connection.open(ctx);
|
|
190
194
|
}
|
|
191
195
|
}
|
|
192
196
|
|
|
193
|
-
type
|
|
197
|
+
type EdgeReplicatorConnectionsProps = {
|
|
194
198
|
edgeConnection: EdgeConnection;
|
|
195
199
|
edgeHttpClient: EdgeHttpClient;
|
|
196
200
|
spaceId: SpaceId;
|
|
197
|
-
context:
|
|
201
|
+
context: AutomergeReplicatorContext;
|
|
198
202
|
sharedPolicyEnabled: boolean;
|
|
199
203
|
onRemoteConnected: () => Promise<void>;
|
|
200
204
|
onRemoteDisconnected: () => Promise<void>;
|
|
@@ -204,14 +208,14 @@ type EdgeReplicatorConnectionsParams = {
|
|
|
204
208
|
const MAX_INFLIGHT_REQUESTS = 5;
|
|
205
209
|
const MAX_RATE_LIMIT_WAIT_TIME_MS = 3000;
|
|
206
210
|
|
|
207
|
-
class EdgeReplicatorConnection extends Resource implements
|
|
211
|
+
class EdgeReplicatorConnection extends Resource implements AutomergeReplicatorConnection {
|
|
208
212
|
private readonly _connectionId = randomUUID();
|
|
209
213
|
private readonly _edgeConnection: EdgeConnection;
|
|
210
214
|
private readonly _edgeHttpClient: EdgeHttpClient;
|
|
211
215
|
private readonly _remotePeerId: string | null = null;
|
|
212
216
|
private readonly _targetServiceId: string;
|
|
213
217
|
private readonly _spaceId: SpaceId;
|
|
214
|
-
private readonly _context:
|
|
218
|
+
private readonly _context: AutomergeReplicatorContext;
|
|
215
219
|
private readonly _sharedPolicyEnabled: boolean;
|
|
216
220
|
private readonly _onRemoteConnected: () => Promise<void>;
|
|
217
221
|
private readonly _onRemoteDisconnected: () => Promise<void>;
|
|
@@ -237,7 +241,7 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
237
241
|
onRemoteConnected,
|
|
238
242
|
onRemoteDisconnected,
|
|
239
243
|
onRestartRequested,
|
|
240
|
-
}:
|
|
244
|
+
}: EdgeReplicatorConnectionsProps) {
|
|
241
245
|
super();
|
|
242
246
|
this._edgeConnection = edgeConnection;
|
|
243
247
|
this._edgeHttpClient = edgeHttpClient;
|
|
@@ -247,8 +251,9 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
247
251
|
// This way automerge-repo will have separate sync states for every connection.
|
|
248
252
|
// This is important because the previous connection might have had some messages that failed to deliver
|
|
249
253
|
// abd if we don't clear the sync-state, automerge will not attempt to deliver them again.
|
|
250
|
-
this.
|
|
251
|
-
|
|
254
|
+
this._targetServiceId = compositeKey(EdgeService.AUTOMERGE_REPLICATOR, spaceId);
|
|
255
|
+
// TODO(wittjosiah): Use compositeKey.
|
|
256
|
+
this._remotePeerId = `${this._targetServiceId}-${this._connectionId}`;
|
|
252
257
|
this._sharedPolicyEnabled = sharedPolicyEnabled;
|
|
253
258
|
this._onRemoteConnected = onRemoteConnected;
|
|
254
259
|
this._onRemoteDisconnected = onRemoteDisconnected;
|
|
@@ -264,7 +269,7 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
264
269
|
write: async (message: AutomergeProtocolMessage, controller) => {
|
|
265
270
|
await this._requestLimiter.rateLimit(message);
|
|
266
271
|
|
|
267
|
-
await this._sendMessage(message);
|
|
272
|
+
await this._sendMessage(this._ctx, message);
|
|
268
273
|
},
|
|
269
274
|
});
|
|
270
275
|
}
|
|
@@ -297,7 +302,7 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
297
302
|
await this._onRemoteConnected();
|
|
298
303
|
}
|
|
299
304
|
|
|
300
|
-
protected override async _close(): Promise<void> {
|
|
305
|
+
protected override async _close(ctx: Context): Promise<void> {
|
|
301
306
|
log('closing...');
|
|
302
307
|
this._readableStreamController.close();
|
|
303
308
|
|
|
@@ -311,7 +316,7 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
311
316
|
return this._remotePeerId;
|
|
312
317
|
}
|
|
313
318
|
|
|
314
|
-
async shouldAdvertise(params:
|
|
319
|
+
async shouldAdvertise(params: ShouldAdvertiseProps): Promise<boolean> {
|
|
315
320
|
if (!this._sharedPolicyEnabled) {
|
|
316
321
|
return true;
|
|
317
322
|
}
|
|
@@ -336,7 +341,7 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
336
341
|
return spaceId === this._spaceId;
|
|
337
342
|
}
|
|
338
343
|
|
|
339
|
-
shouldSyncCollection(params:
|
|
344
|
+
shouldSyncCollection(params: ShouldSyncCollectionProps): boolean {
|
|
340
345
|
if (!this._sharedPolicyEnabled) {
|
|
341
346
|
return true;
|
|
342
347
|
}
|
|
@@ -365,7 +370,7 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
365
370
|
return true;
|
|
366
371
|
}
|
|
367
372
|
|
|
368
|
-
async pushBundle(bundle: { documentId: DocumentId; data: Uint8Array; heads: Heads }[]) {
|
|
373
|
+
async pushBundle(ctx: Context, bundle: { documentId: DocumentId; data: Uint8Array; heads: Heads }[]) {
|
|
369
374
|
const request: ImportBundleRequest = {
|
|
370
375
|
bundle: bundle.map(({ documentId, data, heads }) => ({
|
|
371
376
|
documentId,
|
|
@@ -373,12 +378,12 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
373
378
|
heads,
|
|
374
379
|
})),
|
|
375
380
|
};
|
|
376
|
-
await this._edgeHttpClient.importBundle(this._spaceId, request);
|
|
381
|
+
await this._edgeHttpClient.importBundle(ctx, this._spaceId, request);
|
|
377
382
|
}
|
|
378
383
|
|
|
379
|
-
async pullBundle(docHeads: Record<DocumentId, Heads>): Promise<Record<DocumentId, Uint8Array>> {
|
|
384
|
+
async pullBundle(ctx: Context, docHeads: Record<DocumentId, Heads>): Promise<Record<DocumentId, Uint8Array>> {
|
|
380
385
|
const request: ExportBundleRequest = { docHeads };
|
|
381
|
-
const response = await this._edgeHttpClient.exportBundle(this._spaceId, request);
|
|
386
|
+
const response = await this._edgeHttpClient.exportBundle(ctx, this._spaceId, request);
|
|
382
387
|
return Object.fromEntries(response.bundle.map((doc) => [doc.documentId, DocumentCodec.decode(doc.mutation)]));
|
|
383
388
|
}
|
|
384
389
|
|
|
@@ -387,6 +392,7 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
387
392
|
// AutomergeReplicator might return a Forbidden error if the credentials are not yet replicated.
|
|
388
393
|
// We restart the connection with some delay to account for that.
|
|
389
394
|
if (isErrorMessage(message)) {
|
|
395
|
+
log.verbose('stream error', { error: (message as ErrorProtocolMessage).message });
|
|
390
396
|
this._onRestartRequested();
|
|
391
397
|
return;
|
|
392
398
|
}
|
|
@@ -396,7 +402,7 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
396
402
|
this._readableStreamController.enqueue(message);
|
|
397
403
|
}
|
|
398
404
|
|
|
399
|
-
private async _sendMessage(message: AutomergeProtocolMessage): Promise<void> {
|
|
405
|
+
private async _sendMessage(ctx: Context, message: AutomergeProtocolMessage): Promise<void> {
|
|
400
406
|
// Fix the peer id.
|
|
401
407
|
(message as any).targetId = this._targetServiceId as PeerId;
|
|
402
408
|
|
|
@@ -413,6 +419,7 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
413
419
|
|
|
414
420
|
try {
|
|
415
421
|
await this._edgeConnection.send(
|
|
422
|
+
ctx,
|
|
416
423
|
buf.create(RouterMessageSchema, {
|
|
417
424
|
serviceId: this._targetServiceId,
|
|
418
425
|
source: {
|
|
@@ -438,10 +445,11 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
438
445
|
const isErrorMessage = (message: AutomergeProtocolMessage) => message.type === 'error';
|
|
439
446
|
|
|
440
447
|
const getMessageInfo = (msg: AutomergeProtocolMessage) => {
|
|
441
|
-
const { have, heads, need, changes } = msg.type === 'sync' ?
|
|
448
|
+
const { have, heads, need, changes } = msg.type === 'sync' ? A.decodeSyncMessage(msg.data) : {};
|
|
442
449
|
return {
|
|
443
450
|
type: msg.type,
|
|
444
451
|
documentId: 'documentId' in msg ? msg.documentId : undefined,
|
|
452
|
+
collectionId: 'collectionId' in msg ? msg.collectionId : undefined,
|
|
445
453
|
have,
|
|
446
454
|
heads,
|
|
447
455
|
need,
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { cbor } from '@automerge/automerge-repo';
|
|
6
|
+
import { getRandomPort } from 'get-port-please';
|
|
7
|
+
import { describe, expect, onTestFinished, test } from 'vitest';
|
|
8
|
+
|
|
9
|
+
import { Event } from '@dxos/async';
|
|
10
|
+
import { Context } from '@dxos/context';
|
|
11
|
+
import { EdgeClient, type EdgeHttpClient, MessageSchema, createEphemeralEdgeIdentity } from '@dxos/edge-client';
|
|
12
|
+
import { createTestEdgeWsServer } from '@dxos/edge-client/testing';
|
|
13
|
+
import { PublicKey, SpaceId } from '@dxos/keys';
|
|
14
|
+
import { EdgeService } from '@dxos/protocols';
|
|
15
|
+
import { createBuf } from '@dxos/protocols/buf';
|
|
16
|
+
import type { Peer } from '@dxos/protocols/proto/dxos/edge/messenger';
|
|
17
|
+
import { openAndClose } from '@dxos/test-utils';
|
|
18
|
+
import { compositeKey } from '@dxos/util';
|
|
19
|
+
|
|
20
|
+
import type { AutomergeReplicatorConnection, AutomergeReplicatorContext } from '../automerge';
|
|
21
|
+
import { EchoEdgeSubductionReplicator } from './echo-edge-subduction-replicator';
|
|
22
|
+
|
|
23
|
+
describe('EchoEdgeSubductionReplicator', () => {
|
|
24
|
+
test('opens a subduction connection when connectToSpace is called', async () => {
|
|
25
|
+
const { client } = await createClientServer();
|
|
26
|
+
|
|
27
|
+
const spaceId = SpaceId.random();
|
|
28
|
+
const { context, connectionOpen, openConnections } = createMockContext();
|
|
29
|
+
const replicator = await connectReplicator(client, context);
|
|
30
|
+
|
|
31
|
+
await replicator.connectToSpace(Context.default(), spaceId);
|
|
32
|
+
await connectionOpen.waitForCount(1);
|
|
33
|
+
|
|
34
|
+
expect(openConnections.length).toBe(1);
|
|
35
|
+
|
|
36
|
+
await replicator.disconnect();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('reconnects', async () => {
|
|
40
|
+
const { client, server } = await createClientServer();
|
|
41
|
+
|
|
42
|
+
const spaceId = SpaceId.random();
|
|
43
|
+
|
|
44
|
+
const { context, connectionOpen } = createMockContext();
|
|
45
|
+
const replicator = await connectReplicator(client, context);
|
|
46
|
+
await replicator.connectToSpace(Context.default(), spaceId);
|
|
47
|
+
|
|
48
|
+
client.setIdentity(await createEphemeralEdgeIdentity());
|
|
49
|
+
await connectionOpen.waitForCount(1);
|
|
50
|
+
|
|
51
|
+
// Subduction-era restart: edge emits a `subduction-reconnect` frame on the same
|
|
52
|
+
// SUBDUCTION_REPLICATOR service id; the connection tears down and the replicator
|
|
53
|
+
// opens a fresh connection on the next mutex pass.
|
|
54
|
+
const reconnectFrame = createSubductionReconnectMessage(
|
|
55
|
+
{ identityKey: client.identityKey, peerKey: client.peerKey },
|
|
56
|
+
spaceId,
|
|
57
|
+
);
|
|
58
|
+
await server.sendMessage(reconnectFrame);
|
|
59
|
+
await connectionOpen.waitForCount(1);
|
|
60
|
+
|
|
61
|
+
// Double restart to check for race conditions.
|
|
62
|
+
client.setIdentity(await createEphemeralEdgeIdentity());
|
|
63
|
+
await server.sendMessage(reconnectFrame);
|
|
64
|
+
await connectionOpen.waitForCount(1);
|
|
65
|
+
|
|
66
|
+
await replicator.disconnect();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
describe('shouldAdvertise', () => {
|
|
70
|
+
test('true if space document belongs to connection space', async () => {
|
|
71
|
+
const { client } = await createClientServer();
|
|
72
|
+
|
|
73
|
+
const spaceId = SpaceId.random();
|
|
74
|
+
const documentId = PublicKey.random().toHex();
|
|
75
|
+
const { context, openConnections, connectionOpen } = createMockContext({
|
|
76
|
+
documentSpaceId: { [documentId]: spaceId },
|
|
77
|
+
});
|
|
78
|
+
const replicator = await connectReplicator(client, context);
|
|
79
|
+
await replicator.connectToSpace(Context.default(), spaceId);
|
|
80
|
+
|
|
81
|
+
await connectionOpen.waitForCount(1);
|
|
82
|
+
expect(openConnections.length).toBe(1);
|
|
83
|
+
expect(await openConnections[0].shouldAdvertise({ documentId })).toBeTruthy();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('checks remote collection if space id can not be resolved', async () => {
|
|
87
|
+
const { client } = await createClientServer();
|
|
88
|
+
|
|
89
|
+
const spaceId = SpaceId.random();
|
|
90
|
+
const documentId = PublicKey.random().toHex();
|
|
91
|
+
const remoteCollections: { [peerId: string]: { [documentId: string]: boolean } } = {};
|
|
92
|
+
const { context, openConnections, connectionOpen } = createMockContext({ remoteCollections });
|
|
93
|
+
const replicator = await connectReplicator(client, context);
|
|
94
|
+
await replicator.connectToSpace(Context.default(), spaceId);
|
|
95
|
+
|
|
96
|
+
await connectionOpen.waitForCount(1);
|
|
97
|
+
const connection = openConnections[0];
|
|
98
|
+
expect(await connection.shouldAdvertise({ documentId })).toBeFalsy();
|
|
99
|
+
remoteCollections[connection.peerId] = { [documentId]: true };
|
|
100
|
+
expect(await connection.shouldAdvertise({ documentId })).toBeTruthy();
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const connectReplicator = async (client: EdgeClient, context: AutomergeReplicatorContext) => {
|
|
105
|
+
// EdgeHttpClient functionality is not used by the subduction replicator.
|
|
106
|
+
const replicator = new EchoEdgeSubductionReplicator({
|
|
107
|
+
edgeConnection: client,
|
|
108
|
+
edgeHttpClient: {} as EdgeHttpClient,
|
|
109
|
+
});
|
|
110
|
+
await replicator.connect(Context.default(), context);
|
|
111
|
+
onTestFinished(() => replicator.disconnect());
|
|
112
|
+
return replicator;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const createClientServer = async () => {
|
|
116
|
+
const server = await createTestEdgeWsServer(await getRandomPort());
|
|
117
|
+
onTestFinished(server.cleanup);
|
|
118
|
+
const client = new EdgeClient(await createEphemeralEdgeIdentity(), { socketEndpoint: server.endpoint });
|
|
119
|
+
await openAndClose(client);
|
|
120
|
+
return { client, server };
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const createMockContext = (args?: {
|
|
125
|
+
remoteCollections?: { [peerId: string]: { [documentId: string]: boolean } };
|
|
126
|
+
documentSpaceId?: { [documentId: string]: SpaceId };
|
|
127
|
+
}) => {
|
|
128
|
+
const connectionOpen = new Event();
|
|
129
|
+
const openConnections: AutomergeReplicatorConnection[] = [];
|
|
130
|
+
const context: AutomergeReplicatorContext = {
|
|
131
|
+
getContainingSpaceIdForDocument: async (documentId) => args?.documentSpaceId?.[documentId] ?? null,
|
|
132
|
+
getContainingSpaceForDocument: async () => null,
|
|
133
|
+
isDocumentInRemoteCollection: async (params) =>
|
|
134
|
+
args?.remoteCollections?.[params.peerId]?.[params.documentId] ?? false,
|
|
135
|
+
onConnectionAuthScopeChanged: () => {},
|
|
136
|
+
onConnectionClosed: (connection) => {
|
|
137
|
+
const idx = openConnections.indexOf(connection);
|
|
138
|
+
if (idx >= 0) {
|
|
139
|
+
openConnections.splice(idx, 1);
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
onConnectionOpen: (connection) => {
|
|
143
|
+
openConnections.push(connection);
|
|
144
|
+
connectionOpen.emit();
|
|
145
|
+
},
|
|
146
|
+
peerId: PublicKey.random().toHex(),
|
|
147
|
+
};
|
|
148
|
+
return { context, openConnections, connectionOpen };
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const createSubductionReconnectMessage = (target: Peer, spaceId: SpaceId) =>
|
|
152
|
+
createBuf(MessageSchema, {
|
|
153
|
+
target: [target],
|
|
154
|
+
serviceId: compositeKey(EdgeService.SUBDUCTION_REPLICATOR, spaceId),
|
|
155
|
+
payload: {
|
|
156
|
+
value: cbor.encode({ type: 'subduction-reconnect' }),
|
|
157
|
+
},
|
|
158
|
+
});
|