@dxos/echo-pipeline 0.7.3 → 0.7.4-staging.99db212
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/index.mjs +76 -37
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +78 -37
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +76 -37
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/automerge/automerge-host.d.ts +1 -0
- package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
- package/dist/types/src/automerge/collection-synchronizer.d.ts +3 -1
- package/dist/types/src/automerge/collection-synchronizer.d.ts.map +1 -1
- package/dist/types/src/automerge/space-collection.d.ts +2 -1
- package/dist/types/src/automerge/space-collection.d.ts.map +1 -1
- package/dist/types/src/db-host/data-service.d.ts +3 -0
- package/dist/types/src/db-host/data-service.d.ts.map +1 -1
- package/dist/types/src/db-host/echo-host.d.ts +1 -2
- package/dist/types/src/db-host/echo-host.d.ts.map +1 -1
- package/dist/types/src/db-host/index.d.ts +1 -0
- package/dist/types/src/db-host/index.d.ts.map +1 -1
- package/dist/types/src/db-host/space-state-manager.d.ts +4 -1
- package/dist/types/src/db-host/space-state-manager.d.ts.map +1 -1
- package/package.json +34 -34
- package/src/automerge/automerge-host.ts +4 -0
- package/src/automerge/collection-synchronizer.ts +24 -13
- package/src/automerge/space-collection.ts +4 -2
- package/src/db-host/data-service.ts +17 -3
- package/src/db-host/echo-host.ts +9 -6
- package/src/db-host/index.ts +1 -0
- package/src/db-host/space-state-manager.ts +9 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/echo-pipeline",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.4-staging.99db212",
|
|
4
4
|
"description": "ECHO database.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -37,44 +37,44 @@
|
|
|
37
37
|
"crc-32": "^1.2.2",
|
|
38
38
|
"level-transcoder": "^1.0.1",
|
|
39
39
|
"lodash.isequal": "^4.5.0",
|
|
40
|
-
"@dxos/
|
|
41
|
-
"@dxos/
|
|
42
|
-
"@dxos/
|
|
43
|
-
"@dxos/
|
|
44
|
-
"@dxos/
|
|
45
|
-
"@dxos/
|
|
46
|
-
"@dxos/
|
|
47
|
-
"@dxos/
|
|
48
|
-
"@dxos/
|
|
49
|
-
"@dxos/edge-client": "0.7.
|
|
50
|
-
"@dxos/feed-store": "0.7.
|
|
51
|
-
"@dxos/
|
|
52
|
-
"@dxos/
|
|
53
|
-
"@dxos/invariant": "0.7.
|
|
54
|
-
"@dxos/
|
|
55
|
-
"@dxos/
|
|
56
|
-
"@dxos/
|
|
57
|
-
"@dxos/
|
|
58
|
-
"@dxos/messaging": "0.7.
|
|
59
|
-
"@dxos/
|
|
60
|
-
"@dxos/protocols": "0.7.
|
|
61
|
-
"@dxos/
|
|
62
|
-
"@dxos/teleport": "0.7.
|
|
63
|
-
"@dxos/teleport-extension-gossip": "0.7.
|
|
64
|
-
"@dxos/
|
|
65
|
-
"@dxos/teleport-extension-
|
|
66
|
-
"@dxos/
|
|
67
|
-
"@dxos/
|
|
68
|
-
"@dxos/
|
|
69
|
-
"@dxos/
|
|
70
|
-
"@dxos/
|
|
71
|
-
"@dxos/
|
|
40
|
+
"@dxos/automerge": "0.7.4-staging.99db212",
|
|
41
|
+
"@dxos/async": "0.7.4-staging.99db212",
|
|
42
|
+
"@dxos/codec-protobuf": "0.7.4-staging.99db212",
|
|
43
|
+
"@dxos/context": "0.7.4-staging.99db212",
|
|
44
|
+
"@dxos/credentials": "0.7.4-staging.99db212",
|
|
45
|
+
"@dxos/debug": "0.7.4-staging.99db212",
|
|
46
|
+
"@dxos/echo-protocol": "0.7.4-staging.99db212",
|
|
47
|
+
"@dxos/echo-schema": "0.7.4-staging.99db212",
|
|
48
|
+
"@dxos/crypto": "0.7.4-staging.99db212",
|
|
49
|
+
"@dxos/edge-client": "0.7.4-staging.99db212",
|
|
50
|
+
"@dxos/feed-store": "0.7.4-staging.99db212",
|
|
51
|
+
"@dxos/hypercore": "0.7.4-staging.99db212",
|
|
52
|
+
"@dxos/indexing": "0.7.4-staging.99db212",
|
|
53
|
+
"@dxos/invariant": "0.7.4-staging.99db212",
|
|
54
|
+
"@dxos/kv-store": "0.7.4-staging.99db212",
|
|
55
|
+
"@dxos/log": "0.7.4-staging.99db212",
|
|
56
|
+
"@dxos/keys": "0.7.4-staging.99db212",
|
|
57
|
+
"@dxos/keyring": "0.7.4-staging.99db212",
|
|
58
|
+
"@dxos/messaging": "0.7.4-staging.99db212",
|
|
59
|
+
"@dxos/network-manager": "0.7.4-staging.99db212",
|
|
60
|
+
"@dxos/protocols": "0.7.4-staging.99db212",
|
|
61
|
+
"@dxos/node-std": "0.7.4-staging.99db212",
|
|
62
|
+
"@dxos/teleport": "0.7.4-staging.99db212",
|
|
63
|
+
"@dxos/teleport-extension-gossip": "0.7.4-staging.99db212",
|
|
64
|
+
"@dxos/random-access-storage": "0.7.4-staging.99db212",
|
|
65
|
+
"@dxos/teleport-extension-automerge-replicator": "0.7.4-staging.99db212",
|
|
66
|
+
"@dxos/teleport-extension-object-sync": "0.7.4-staging.99db212",
|
|
67
|
+
"@dxos/teleport-extension-replicator": "0.7.4-staging.99db212",
|
|
68
|
+
"@dxos/timeframe": "0.7.4-staging.99db212",
|
|
69
|
+
"@dxos/tracing": "0.7.4-staging.99db212",
|
|
70
|
+
"@dxos/typings": "0.7.4-staging.99db212",
|
|
71
|
+
"@dxos/util": "0.7.4-staging.99db212"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"@types/lodash.isequal": "^4.5.0",
|
|
75
75
|
"fast-check": "^3.19.0",
|
|
76
76
|
"get-port-please": "^3.1.1",
|
|
77
|
-
"@dxos/test-utils": "0.7.
|
|
77
|
+
"@dxos/test-utils": "0.7.4-staging.99db212"
|
|
78
78
|
},
|
|
79
79
|
"publishConfig": {
|
|
80
80
|
"access": "public"
|
|
@@ -453,6 +453,10 @@ export class AutomergeHost extends Resource {
|
|
|
453
453
|
this._collectionSynchronizer.setLocalCollectionState(collectionId, { documents });
|
|
454
454
|
}
|
|
455
455
|
|
|
456
|
+
async clearLocalCollectionState(collectionId: string) {
|
|
457
|
+
this._collectionSynchronizer.clearLocalCollectionState(collectionId);
|
|
458
|
+
}
|
|
459
|
+
|
|
456
460
|
private _onCollectionStateQueried(collectionId: string, peerId: PeerId) {
|
|
457
461
|
this._collectionSynchronizer.onCollectionStateQueried(collectionId, peerId);
|
|
458
462
|
}
|
|
@@ -31,6 +31,7 @@ export class CollectionSynchronizer extends Resource {
|
|
|
31
31
|
* CollectionId -> State.
|
|
32
32
|
*/
|
|
33
33
|
private readonly _perCollectionStates = new Map<string, PerCollectionState>();
|
|
34
|
+
private readonly _activeCollections = new Set<string>();
|
|
34
35
|
|
|
35
36
|
private readonly _connectedPeers = new Set<PeerId>();
|
|
36
37
|
|
|
@@ -48,8 +49,10 @@ export class CollectionSynchronizer extends Resource {
|
|
|
48
49
|
this._ctx,
|
|
49
50
|
async () => {
|
|
50
51
|
for (const collectionId of this._perCollectionStates.keys()) {
|
|
51
|
-
this.
|
|
52
|
-
|
|
52
|
+
if (this._activeCollections.has(collectionId)) {
|
|
53
|
+
this.refreshCollection(collectionId);
|
|
54
|
+
await asyncReturn();
|
|
55
|
+
}
|
|
53
56
|
}
|
|
54
57
|
},
|
|
55
58
|
POLL_INTERVAL,
|
|
@@ -57,32 +60,40 @@ export class CollectionSynchronizer extends Resource {
|
|
|
57
60
|
}
|
|
58
61
|
|
|
59
62
|
getRegisteredCollectionIds(): string[] {
|
|
60
|
-
return [...this.
|
|
63
|
+
return [...this._activeCollections];
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
getLocalCollectionState(collectionId: string): CollectionState | undefined {
|
|
64
|
-
return this.
|
|
67
|
+
return this._perCollectionStates.get(collectionId)?.localState;
|
|
65
68
|
}
|
|
66
69
|
|
|
67
70
|
setLocalCollectionState(collectionId: string, state: CollectionState) {
|
|
71
|
+
this._activeCollections.add(collectionId);
|
|
72
|
+
|
|
68
73
|
log('setLocalCollectionState', { collectionId, state });
|
|
69
|
-
this.
|
|
74
|
+
this._getOrCreatePerCollectionState(collectionId).localState = state;
|
|
70
75
|
|
|
71
76
|
queueMicrotask(async () => {
|
|
72
|
-
if (!this._ctx.disposed) {
|
|
77
|
+
if (!this._ctx.disposed && this._activeCollections.has(collectionId)) {
|
|
73
78
|
this._refreshInterestedPeers(collectionId);
|
|
74
79
|
this.refreshCollection(collectionId);
|
|
75
80
|
}
|
|
76
81
|
});
|
|
77
82
|
}
|
|
78
83
|
|
|
84
|
+
clearLocalCollectionState(collectionId: string) {
|
|
85
|
+
this._activeCollections.delete(collectionId);
|
|
86
|
+
this._perCollectionStates.delete(collectionId);
|
|
87
|
+
log('clearLocalCollectionState', { collectionId });
|
|
88
|
+
}
|
|
89
|
+
|
|
79
90
|
getRemoteCollectionStates(collectionId: string): ReadonlyMap<PeerId, CollectionState> {
|
|
80
|
-
return this.
|
|
91
|
+
return this._getOrCreatePerCollectionState(collectionId).remoteStates;
|
|
81
92
|
}
|
|
82
93
|
|
|
83
94
|
refreshCollection(collectionId: string) {
|
|
84
95
|
let scheduleAnotherRefresh = false;
|
|
85
|
-
const state = this.
|
|
96
|
+
const state = this._getOrCreatePerCollectionState(collectionId);
|
|
86
97
|
for (const peerId of this._connectedPeers) {
|
|
87
98
|
if (state.interestedPeers.has(peerId)) {
|
|
88
99
|
const lastQueried = state.lastQueried.get(peerId) ?? 0;
|
|
@@ -134,7 +145,7 @@ export class CollectionSynchronizer extends Resource {
|
|
|
134
145
|
* Callback when a peer queries the state of a collection.
|
|
135
146
|
*/
|
|
136
147
|
onCollectionStateQueried(collectionId: string, peerId: PeerId) {
|
|
137
|
-
const perCollectionState = this.
|
|
148
|
+
const perCollectionState = this._getOrCreatePerCollectionState(collectionId);
|
|
138
149
|
|
|
139
150
|
if (perCollectionState.localState) {
|
|
140
151
|
this._sendCollectionState(collectionId, peerId, perCollectionState.localState);
|
|
@@ -147,12 +158,12 @@ export class CollectionSynchronizer extends Resource {
|
|
|
147
158
|
onRemoteStateReceived(collectionId: string, peerId: PeerId, state: CollectionState) {
|
|
148
159
|
log('onRemoteStateReceived', { collectionId, peerId, state });
|
|
149
160
|
validateCollectionState(state);
|
|
150
|
-
const perCollectionState = this.
|
|
161
|
+
const perCollectionState = this._getOrCreatePerCollectionState(collectionId);
|
|
151
162
|
perCollectionState.remoteStates.set(peerId, state);
|
|
152
163
|
this.remoteStateUpdated.emit({ peerId, collectionId });
|
|
153
164
|
}
|
|
154
165
|
|
|
155
|
-
private
|
|
166
|
+
private _getOrCreatePerCollectionState(collectionId: string): PerCollectionState {
|
|
156
167
|
return defaultMap(this._perCollectionStates, collectionId, () => ({
|
|
157
168
|
localState: undefined,
|
|
158
169
|
remoteStates: new Map(),
|
|
@@ -164,9 +175,9 @@ export class CollectionSynchronizer extends Resource {
|
|
|
164
175
|
private _refreshInterestedPeers(collectionId: string) {
|
|
165
176
|
for (const peerId of this._connectedPeers) {
|
|
166
177
|
if (this._shouldSyncCollection(collectionId, peerId)) {
|
|
167
|
-
this.
|
|
178
|
+
this._getOrCreatePerCollectionState(collectionId).interestedPeers.add(peerId);
|
|
168
179
|
} else {
|
|
169
|
-
this.
|
|
180
|
+
this._getOrCreatePerCollectionState(collectionId).interestedPeers.delete(peerId);
|
|
170
181
|
}
|
|
171
182
|
}
|
|
172
183
|
}
|
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { type DocumentId } from '@dxos/automerge/automerge-repo';
|
|
5
6
|
import type { CollectionId } from '@dxos/echo-protocol';
|
|
6
7
|
import { invariant } from '@dxos/invariant';
|
|
7
8
|
import { SpaceId } from '@dxos/keys';
|
|
8
9
|
|
|
9
|
-
export const deriveCollectionIdFromSpaceId = (spaceId: SpaceId): CollectionId =>
|
|
10
|
+
export const deriveCollectionIdFromSpaceId = (spaceId: SpaceId, rootDocumentId?: DocumentId): CollectionId =>
|
|
11
|
+
(rootDocumentId ? `space:${spaceId}:${rootDocumentId}` : `space:${spaceId}`) as CollectionId;
|
|
10
12
|
|
|
11
13
|
export const getSpaceIdFromCollectionId = (collectionId: CollectionId): SpaceId => {
|
|
12
|
-
const spaceId = collectionId.
|
|
14
|
+
const spaceId = collectionId.split(':')[1];
|
|
13
15
|
invariant(SpaceId.isValid(spaceId));
|
|
14
16
|
return spaceId;
|
|
15
17
|
};
|
|
@@ -25,10 +25,12 @@ import {
|
|
|
25
25
|
} from '@dxos/protocols/proto/dxos/echo/service';
|
|
26
26
|
|
|
27
27
|
import { DocumentsSynchronizer } from './documents-synchronizer';
|
|
28
|
+
import { type SpaceStateManager } from './space-state-manager';
|
|
28
29
|
import { deriveCollectionIdFromSpaceId, type AutomergeHost } from '../automerge';
|
|
29
30
|
|
|
30
31
|
export type DataServiceParams = {
|
|
31
32
|
automergeHost: AutomergeHost;
|
|
33
|
+
spaceStateManager: SpaceStateManager;
|
|
32
34
|
updateIndexes: () => Promise<void>;
|
|
33
35
|
};
|
|
34
36
|
|
|
@@ -44,10 +46,12 @@ export class DataServiceImpl implements DataService {
|
|
|
44
46
|
private readonly _subscriptions = new Map<string, DocumentsSynchronizer>();
|
|
45
47
|
|
|
46
48
|
private readonly _automergeHost: AutomergeHost;
|
|
49
|
+
private readonly _spaceStateManager: SpaceStateManager;
|
|
47
50
|
private readonly _updateIndexes: () => Promise<void>;
|
|
48
51
|
|
|
49
52
|
constructor(params: DataServiceParams) {
|
|
50
53
|
this._automergeHost = params.automergeHost;
|
|
54
|
+
this._spaceStateManager = params.spaceStateManager;
|
|
51
55
|
this._updateIndexes = params.updateIndexes;
|
|
52
56
|
}
|
|
53
57
|
|
|
@@ -124,11 +128,21 @@ export class DataServiceImpl implements DataService {
|
|
|
124
128
|
|
|
125
129
|
subscribeSpaceSyncState(request: GetSpaceSyncStateRequest): Stream<SpaceSyncState> {
|
|
126
130
|
return new Stream<SpaceSyncState>(({ ctx, next, ready }) => {
|
|
127
|
-
|
|
128
|
-
|
|
131
|
+
const spaceId = request.spaceId;
|
|
132
|
+
invariant(SpaceId.isValid(spaceId));
|
|
133
|
+
|
|
134
|
+
const rootDocumentId = this._spaceStateManager.getSpaceRootDocumentId(spaceId);
|
|
135
|
+
let collectionId = rootDocumentId && deriveCollectionIdFromSpaceId(spaceId, rootDocumentId);
|
|
136
|
+
this._spaceStateManager.spaceDocumentListUpdated.on(ctx, (event) => {
|
|
137
|
+
const newId = deriveCollectionIdFromSpaceId(spaceId, event.spaceRootId);
|
|
138
|
+
if (newId !== collectionId) {
|
|
139
|
+
collectionId = newId;
|
|
140
|
+
scheduler.trigger();
|
|
141
|
+
}
|
|
142
|
+
});
|
|
129
143
|
|
|
130
144
|
const scheduler = new UpdateScheduler(ctx, async () => {
|
|
131
|
-
const state = await this._automergeHost.getCollectionSyncState(collectionId);
|
|
145
|
+
const state = collectionId ? await this._automergeHost.getCollectionSyncState(collectionId) : { peers: [] };
|
|
132
146
|
|
|
133
147
|
next({
|
|
134
148
|
peers: state.peers.map((peer) => ({
|
package/src/db-host/echo-host.ts
CHANGED
|
@@ -31,7 +31,6 @@ import {
|
|
|
31
31
|
type LoadDocOptions,
|
|
32
32
|
type CreateDocOptions,
|
|
33
33
|
type EchoReplicator,
|
|
34
|
-
type CollectionSyncState,
|
|
35
34
|
type EchoDataStats,
|
|
36
35
|
type PeerIdProvider,
|
|
37
36
|
} from '../automerge';
|
|
@@ -91,6 +90,7 @@ export class EchoHost extends Resource {
|
|
|
91
90
|
|
|
92
91
|
this._dataService = new DataServiceImpl({
|
|
93
92
|
automergeHost: this._automergeHost,
|
|
93
|
+
spaceStateManager: this._spaceStateManager,
|
|
94
94
|
updateIndexes: async () => {
|
|
95
95
|
await this._indexer.updateIndexes();
|
|
96
96
|
},
|
|
@@ -163,7 +163,15 @@ export class EchoHost extends Resource {
|
|
|
163
163
|
await this._spaceStateManager.open(ctx);
|
|
164
164
|
|
|
165
165
|
this._spaceStateManager.spaceDocumentListUpdated.on(this._ctx, (e) => {
|
|
166
|
+
if (e.previousRootId) {
|
|
167
|
+
void this._automergeHost.clearLocalCollectionState(deriveCollectionIdFromSpaceId(e.spaceId, e.previousRootId));
|
|
168
|
+
}
|
|
169
|
+
// TODO(yaroslav): remove collection without spaceRootId after release (production<->staging interop)
|
|
166
170
|
void this._automergeHost.updateLocalCollectionState(deriveCollectionIdFromSpaceId(e.spaceId), e.documentIds);
|
|
171
|
+
void this._automergeHost.updateLocalCollectionState(
|
|
172
|
+
deriveCollectionIdFromSpaceId(e.spaceId, e.spaceRootId),
|
|
173
|
+
e.documentIds,
|
|
174
|
+
);
|
|
167
175
|
});
|
|
168
176
|
}
|
|
169
177
|
|
|
@@ -249,11 +257,6 @@ export class EchoHost extends Resource {
|
|
|
249
257
|
async removeReplicator(replicator: EchoReplicator): Promise<void> {
|
|
250
258
|
await this._automergeHost.removeReplicator(replicator);
|
|
251
259
|
}
|
|
252
|
-
|
|
253
|
-
async getSpaceSyncState(spaceId: SpaceId): Promise<CollectionSyncState> {
|
|
254
|
-
const collectionId = deriveCollectionIdFromSpaceId(spaceId);
|
|
255
|
-
return this._automergeHost.getCollectionSyncState(collectionId);
|
|
256
|
-
}
|
|
257
260
|
}
|
|
258
261
|
|
|
259
262
|
export type { EchoDataStats };
|
package/src/db-host/index.ts
CHANGED
|
@@ -35,6 +35,10 @@ export class SpaceStateManager extends Resource {
|
|
|
35
35
|
return this._roots.get(documentId);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
getSpaceRootDocumentId(spaceId: SpaceId): DocumentId | undefined {
|
|
39
|
+
return this._rootBySpace.get(spaceId);
|
|
40
|
+
}
|
|
41
|
+
|
|
38
42
|
async assignRootToSpace(spaceId: SpaceId, handle: DocHandle<SpaceDoc>): Promise<DatabaseRoot> {
|
|
39
43
|
let root: DatabaseRoot;
|
|
40
44
|
if (this._roots.has(handle.documentId)) {
|
|
@@ -67,7 +71,9 @@ export class SpaceStateManager extends Resource {
|
|
|
67
71
|
const documentIds = [root.documentId, ...root.getAllLinkedDocuments().map((url) => interpretAsDocumentId(url))];
|
|
68
72
|
if (!isEqual(documentIds, this._lastSpaceDocumentList.get(spaceId))) {
|
|
69
73
|
this._lastSpaceDocumentList.set(spaceId, documentIds);
|
|
70
|
-
this.spaceDocumentListUpdated.emit(
|
|
74
|
+
this.spaceDocumentListUpdated.emit(
|
|
75
|
+
new SpaceDocumentListUpdatedEvent(spaceId, root.documentId, prevRootId, documentIds),
|
|
76
|
+
);
|
|
71
77
|
}
|
|
72
78
|
},
|
|
73
79
|
{ maxFrequency: 50 },
|
|
@@ -85,6 +91,8 @@ export class SpaceStateManager extends Resource {
|
|
|
85
91
|
export class SpaceDocumentListUpdatedEvent {
|
|
86
92
|
constructor(
|
|
87
93
|
public readonly spaceId: SpaceId,
|
|
94
|
+
public readonly spaceRootId: DocumentId,
|
|
95
|
+
public readonly previousRootId: DocumentId | undefined,
|
|
88
96
|
public readonly documentIds: DocumentId[],
|
|
89
97
|
) {}
|
|
90
98
|
}
|