@dxos/client-services 0.6.12-main.78ddbdf → 0.6.12-main.7907542
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-XSFLJVDP.mjs → chunk-6UTFANWL.mjs} +686 -304
- package/dist/lib/browser/chunk-6UTFANWL.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +1 -1
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +2 -2
- package/dist/lib/browser/testing/index.mjs.map +2 -2
- package/dist/lib/node/{chunk-F3WGFGEN.cjs → chunk-2UUETFZ2.cjs} +776 -394
- package/dist/lib/node/chunk-2UUETFZ2.cjs.map +7 -0
- package/dist/lib/node/index.cjs +45 -45
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +8 -8
- package/dist/lib/node/testing/index.cjs.map +2 -2
- package/dist/lib/node-esm/{chunk-3HDLTAT2.mjs → chunk-EQAI46LQ.mjs} +686 -304
- package/dist/lib/node-esm/chunk-EQAI46LQ.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +1 -1
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +2 -2
- package/dist/lib/node-esm/testing/index.mjs.map +2 -2
- package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/contacts-service.d.ts +1 -1
- package/dist/types/src/packlets/identity/contacts-service.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity.d.ts +1 -0
- package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts +4 -2
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +1 -0
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts +5 -1
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts +3 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts +2 -0
- package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +31 -6
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
- package/dist/types/src/version.d.ts +1 -1
- package/package.json +38 -38
- package/src/packlets/identity/authenticator.ts +5 -2
- package/src/packlets/identity/contacts-service.ts +1 -1
- package/src/packlets/identity/identity.ts +4 -0
- package/src/packlets/services/service-context.ts +41 -17
- package/src/packlets/services/service-host.ts +7 -5
- package/src/packlets/spaces/data-space-manager.ts +32 -4
- package/src/packlets/spaces/data-space.ts +27 -4
- package/src/packlets/spaces/edge-feed-replicator.test.ts +22 -15
- package/src/packlets/spaces/edge-feed-replicator.ts +45 -25
- package/src/packlets/spaces/notarization-plugin.test.ts +8 -4
- package/src/packlets/spaces/notarization-plugin.ts +169 -29
- package/src/packlets/spaces/spaces-service.ts +6 -1
- package/src/packlets/testing/test-builder.ts +1 -1
- package/src/version.ts +1 -1
- package/dist/lib/browser/chunk-XSFLJVDP.mjs.map +0 -7
- package/dist/lib/node/chunk-F3WGFGEN.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-3HDLTAT2.mjs.map +0 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/client-services",
|
|
3
|
-
"version": "0.6.12-main.
|
|
3
|
+
"version": "0.6.12-main.7907542",
|
|
4
4
|
"description": "DXOS client services implementation",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -47,48 +47,48 @@
|
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"cbor-x": "^1.5.4",
|
|
49
49
|
"platform": "^1.3.6",
|
|
50
|
-
"@dxos/async": "0.6.12-main.
|
|
51
|
-
"@dxos/client-protocol": "0.6.12-main.
|
|
52
|
-
"@dxos/
|
|
53
|
-
"@dxos/codec-protobuf": "0.6.12-main.
|
|
54
|
-
"@dxos/
|
|
55
|
-
"@dxos/context": "0.6.12-main.
|
|
56
|
-
"@dxos/
|
|
57
|
-
"@dxos/
|
|
58
|
-
"@dxos/
|
|
59
|
-
"@dxos/
|
|
60
|
-
"@dxos/echo-pipeline": "0.6.12-main.
|
|
61
|
-
"@dxos/echo-protocol": "0.6.12-main.
|
|
62
|
-
"@dxos/
|
|
63
|
-
"@dxos/
|
|
64
|
-
"@dxos/
|
|
65
|
-
"@dxos/
|
|
66
|
-
"@dxos/invariant": "0.6.12-main.
|
|
67
|
-
"@dxos/keyring": "0.6.12-main.
|
|
68
|
-
"@dxos/keys": "0.6.12-main.
|
|
69
|
-
"@dxos/lock-file": "0.6.12-main.
|
|
70
|
-
"@dxos/
|
|
71
|
-
"@dxos/
|
|
72
|
-
"@dxos/messaging": "0.6.12-main.
|
|
73
|
-
"@dxos/network-manager": "0.6.12-main.
|
|
74
|
-
"@dxos/node-std": "0.6.12-main.
|
|
75
|
-
"@dxos/
|
|
76
|
-
"@dxos/
|
|
77
|
-
"@dxos/
|
|
78
|
-
"@dxos/
|
|
79
|
-
"@dxos/teleport-extension-
|
|
80
|
-
"@dxos/
|
|
81
|
-
"@dxos/
|
|
82
|
-
"@dxos/
|
|
83
|
-
"@dxos/util": "0.6.12-main.
|
|
84
|
-
"@dxos/websocket-rpc": "0.6.12-main.
|
|
50
|
+
"@dxos/async": "0.6.12-main.7907542",
|
|
51
|
+
"@dxos/client-protocol": "0.6.12-main.7907542",
|
|
52
|
+
"@dxos/automerge": "0.6.12-main.7907542",
|
|
53
|
+
"@dxos/codec-protobuf": "0.6.12-main.7907542",
|
|
54
|
+
"@dxos/config": "0.6.12-main.7907542",
|
|
55
|
+
"@dxos/context": "0.6.12-main.7907542",
|
|
56
|
+
"@dxos/credentials": "0.6.12-main.7907542",
|
|
57
|
+
"@dxos/debug": "0.6.12-main.7907542",
|
|
58
|
+
"@dxos/echo-db": "0.6.12-main.7907542",
|
|
59
|
+
"@dxos/crypto": "0.6.12-main.7907542",
|
|
60
|
+
"@dxos/echo-pipeline": "0.6.12-main.7907542",
|
|
61
|
+
"@dxos/echo-protocol": "0.6.12-main.7907542",
|
|
62
|
+
"@dxos/edge-client": "0.6.12-main.7907542",
|
|
63
|
+
"@dxos/echo-schema": "0.6.12-main.7907542",
|
|
64
|
+
"@dxos/feed-store": "0.6.12-main.7907542",
|
|
65
|
+
"@dxos/indexing": "0.6.12-main.7907542",
|
|
66
|
+
"@dxos/invariant": "0.6.12-main.7907542",
|
|
67
|
+
"@dxos/keyring": "0.6.12-main.7907542",
|
|
68
|
+
"@dxos/keys": "0.6.12-main.7907542",
|
|
69
|
+
"@dxos/lock-file": "0.6.12-main.7907542",
|
|
70
|
+
"@dxos/kv-store": "0.6.12-main.7907542",
|
|
71
|
+
"@dxos/log": "0.6.12-main.7907542",
|
|
72
|
+
"@dxos/messaging": "0.6.12-main.7907542",
|
|
73
|
+
"@dxos/network-manager": "0.6.12-main.7907542",
|
|
74
|
+
"@dxos/node-std": "0.6.12-main.7907542",
|
|
75
|
+
"@dxos/protocols": "0.6.12-main.7907542",
|
|
76
|
+
"@dxos/random-access-storage": "0.6.12-main.7907542",
|
|
77
|
+
"@dxos/rpc": "0.6.12-main.7907542",
|
|
78
|
+
"@dxos/teleport": "0.6.12-main.7907542",
|
|
79
|
+
"@dxos/teleport-extension-object-sync": "0.6.12-main.7907542",
|
|
80
|
+
"@dxos/teleport-extension-gossip": "0.6.12-main.7907542",
|
|
81
|
+
"@dxos/timeframe": "0.6.12-main.7907542",
|
|
82
|
+
"@dxos/tracing": "0.6.12-main.7907542",
|
|
83
|
+
"@dxos/util": "0.6.12-main.7907542",
|
|
84
|
+
"@dxos/websocket-rpc": "0.6.12-main.7907542"
|
|
85
85
|
},
|
|
86
86
|
"devDependencies": {
|
|
87
87
|
"@types/platform": "^1.3.4",
|
|
88
88
|
"@types/readable-stream": "^2.3.9",
|
|
89
89
|
"get-port-please": "^3.1.1",
|
|
90
|
-
"@dxos/signal": "0.6.12-main.
|
|
91
|
-
"@dxos/test-utils": "0.6.12-main.
|
|
90
|
+
"@dxos/signal": "0.6.12-main.7907542",
|
|
91
|
+
"@dxos/test-utils": "0.6.12-main.7907542"
|
|
92
92
|
},
|
|
93
93
|
"publishConfig": {
|
|
94
94
|
"access": "public"
|
|
@@ -67,7 +67,7 @@ export class TrustedKeySetAuthVerifier {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
if (this._isTrustedKey(credential.issuer)) {
|
|
70
|
-
log('key is
|
|
70
|
+
log('key is trusted -- auth success', { key: credential.issuer });
|
|
71
71
|
return true;
|
|
72
72
|
}
|
|
73
73
|
|
|
@@ -81,7 +81,10 @@ export class TrustedKeySetAuthVerifier {
|
|
|
81
81
|
log('auth success', { key: credential.issuer });
|
|
82
82
|
trigger.wake(true);
|
|
83
83
|
} else {
|
|
84
|
-
log('key is not currently in trusted set, waiting...', {
|
|
84
|
+
log('key is not currently in trusted set, waiting...', {
|
|
85
|
+
key: credential.issuer,
|
|
86
|
+
trusted: [...this._params.trustedKeysProvider()],
|
|
87
|
+
});
|
|
85
88
|
}
|
|
86
89
|
});
|
|
87
90
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { EventSubscriptions, scheduleTask, UpdateScheduler } from '@dxos/async';
|
|
6
6
|
import { Stream } from '@dxos/codec-protobuf';
|
|
7
7
|
import { type MemberInfo } from '@dxos/credentials';
|
|
8
|
-
import type
|
|
8
|
+
import { type SpaceManager } from '@dxos/echo-pipeline';
|
|
9
9
|
import { PublicKey } from '@dxos/keys';
|
|
10
10
|
import { type Contact, type ContactBook, type ContactsService } from '@dxos/protocols/proto/dxos/client/services';
|
|
11
11
|
import { ComplexMap, ComplexSet } from '@dxos/util';
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Trigger } from '@dxos/async';
|
|
5
|
+
import { Mutex, scheduleMicroTask, Trigger } from '@dxos/async';
|
|
6
6
|
import { Context, Resource } from '@dxos/context';
|
|
7
7
|
import { getCredentialAssertion, type CredentialProcessor } from '@dxos/credentials';
|
|
8
|
-
import { failUndefined } from '@dxos/debug';
|
|
8
|
+
import { failUndefined, warnAfterTimeout } from '@dxos/debug';
|
|
9
9
|
import {
|
|
10
10
|
EchoEdgeReplicator,
|
|
11
11
|
EchoHost,
|
|
@@ -14,7 +14,8 @@ import {
|
|
|
14
14
|
SpaceManager,
|
|
15
15
|
valueEncoding,
|
|
16
16
|
} from '@dxos/echo-pipeline';
|
|
17
|
-
import
|
|
17
|
+
import { createChainEdgeIdentity, createEphemeralEdgeIdentity } from '@dxos/edge-client';
|
|
18
|
+
import type { EdgeHttpClient, EdgeConnection } from '@dxos/edge-client';
|
|
18
19
|
import { FeedFactory, FeedStore } from '@dxos/feed-store';
|
|
19
20
|
import { invariant } from '@dxos/invariant';
|
|
20
21
|
import { Keyring } from '@dxos/keyring';
|
|
@@ -37,8 +38,8 @@ import { safeInstanceof } from '@dxos/util';
|
|
|
37
38
|
import {
|
|
38
39
|
IdentityManager,
|
|
39
40
|
type CreateIdentityOptions,
|
|
40
|
-
type JoinIdentityParams,
|
|
41
41
|
type IdentityManagerParams,
|
|
42
|
+
type JoinIdentityParams,
|
|
42
43
|
} from '../identity';
|
|
43
44
|
import {
|
|
44
45
|
DeviceInvitationProtocol,
|
|
@@ -65,6 +66,8 @@ export type ServiceContextRuntimeParams = Pick<
|
|
|
65
66
|
@safeInstanceof('dxos.client-services.ServiceContext')
|
|
66
67
|
@Trace.resource()
|
|
67
68
|
export class ServiceContext extends Resource {
|
|
69
|
+
private readonly _edgeIdentityUpdateMutex = new Mutex();
|
|
70
|
+
|
|
68
71
|
public readonly initialized = new Trigger();
|
|
69
72
|
public readonly metadataStore: MetadataStore;
|
|
70
73
|
public readonly blobStore: BlobStore;
|
|
@@ -96,6 +99,7 @@ export class ServiceContext extends Resource {
|
|
|
96
99
|
public readonly networkManager: SwarmNetworkManager,
|
|
97
100
|
public readonly signalManager: SignalManager,
|
|
98
101
|
private readonly _edgeConnection: EdgeConnection | undefined,
|
|
102
|
+
private readonly _edgeHttpClient: EdgeHttpClient | undefined,
|
|
99
103
|
public readonly _runtimeParams?: ServiceContextRuntimeParams,
|
|
100
104
|
private readonly _edgeFeatures?: Runtime.Client.EdgeFeatures,
|
|
101
105
|
) {
|
|
@@ -137,18 +141,33 @@ export class ServiceContext extends Resource {
|
|
|
137
141
|
callbacks: {
|
|
138
142
|
onIdentityConstruction: (identity) => {
|
|
139
143
|
if (this._edgeConnection) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
144
|
+
scheduleMicroTask(this._ctx, async () => {
|
|
145
|
+
using _ = await this._edgeIdentityUpdateMutex.acquire();
|
|
146
|
+
|
|
147
|
+
log.info('Setting identity on edge connection', {
|
|
148
|
+
identity: identity.identityKey.toHex(),
|
|
149
|
+
oldIdentity: this._edgeConnection!.identityKey,
|
|
150
|
+
swarms: this.networkManager.topics,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
await warnAfterTimeout(10_000, 'Waiting for identity to be ready for edge connection', async () => {
|
|
154
|
+
await identity.ready();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
invariant(identity.deviceCredentialChain);
|
|
158
|
+
this._edgeConnection!.setIdentity(
|
|
159
|
+
await createChainEdgeIdentity(
|
|
160
|
+
identity.signer,
|
|
161
|
+
identity.identityKey,
|
|
162
|
+
identity.deviceKey,
|
|
163
|
+
identity.deviceCredentialChain,
|
|
164
|
+
[], // TODO(dmaretskyi): Service access credentials.
|
|
165
|
+
),
|
|
166
|
+
);
|
|
167
|
+
this.networkManager.setPeerInfo({
|
|
168
|
+
identityKey: identity.identityKey.toHex(),
|
|
169
|
+
peerKey: identity.deviceKey.toHex(),
|
|
170
|
+
});
|
|
152
171
|
});
|
|
153
172
|
}
|
|
154
173
|
},
|
|
@@ -197,7 +216,11 @@ export class ServiceContext extends Resource {
|
|
|
197
216
|
|
|
198
217
|
log('opening...');
|
|
199
218
|
log.trace('dxos.sdk.service-context.open', trace.begin({ id: this._instanceId }));
|
|
200
|
-
|
|
219
|
+
if (this._edgeConnection) {
|
|
220
|
+
// TODO(dmaretskyi): Use device key.
|
|
221
|
+
this._edgeConnection.setIdentity(await createEphemeralEdgeIdentity());
|
|
222
|
+
await this._edgeConnection.open();
|
|
223
|
+
}
|
|
201
224
|
await this.signalManager.open();
|
|
202
225
|
await this.networkManager.open();
|
|
203
226
|
|
|
@@ -304,6 +327,7 @@ export class ServiceContext extends Resource {
|
|
|
304
327
|
echoHost: this.echoHost,
|
|
305
328
|
invitationsManager: this.invitationsManager,
|
|
306
329
|
edgeConnection: this._edgeConnection,
|
|
330
|
+
edgeHttpClient: this._edgeHttpClient,
|
|
307
331
|
echoEdgeReplicator: this._echoEdgeReplicator,
|
|
308
332
|
meshReplicator: this._meshReplicator,
|
|
309
333
|
runtimeParams: this._runtimeParams as DataSpaceManagerRuntimeParams,
|
|
@@ -6,7 +6,7 @@ import { Event, synchronized } from '@dxos/async';
|
|
|
6
6
|
import { clientServiceBundle, type ClientServices } from '@dxos/client-protocol';
|
|
7
7
|
import { type Config } from '@dxos/config';
|
|
8
8
|
import { Context } from '@dxos/context';
|
|
9
|
-
import { EdgeClient, type EdgeConnection } from '@dxos/edge-client';
|
|
9
|
+
import { EdgeClient, EdgeHttpClient, createStubEdgeIdentity, type EdgeConnection } from '@dxos/edge-client';
|
|
10
10
|
import { invariant } from '@dxos/invariant';
|
|
11
11
|
import { PublicKey } from '@dxos/keys';
|
|
12
12
|
import { type LevelDB } from '@dxos/kv-store';
|
|
@@ -15,8 +15,8 @@ import { EdgeSignalManager, WebsocketSignalManager, type SignalManager } from '@
|
|
|
15
15
|
import {
|
|
16
16
|
SwarmNetworkManager,
|
|
17
17
|
createIceProvider,
|
|
18
|
-
type TransportFactory,
|
|
19
18
|
createRtcTransportFactory,
|
|
19
|
+
type TransportFactory,
|
|
20
20
|
} from '@dxos/network-manager';
|
|
21
21
|
import { trace } from '@dxos/protocols';
|
|
22
22
|
import { SystemStatus } from '@dxos/protocols/proto/dxos/client/services';
|
|
@@ -29,9 +29,9 @@ import { ServiceRegistry } from './service-registry';
|
|
|
29
29
|
import { DevicesServiceImpl } from '../devices';
|
|
30
30
|
import { DevtoolsHostEvents, DevtoolsServiceImpl } from '../devtools';
|
|
31
31
|
import {
|
|
32
|
-
type CollectDiagnosticsBroadcastHandler,
|
|
33
32
|
createCollectDiagnosticsBroadcastHandler,
|
|
34
33
|
createDiagnostics,
|
|
34
|
+
type CollectDiagnosticsBroadcastHandler,
|
|
35
35
|
} from '../diagnostics';
|
|
36
36
|
import { IdentityServiceImpl, type CreateIdentityOptions } from '../identity';
|
|
37
37
|
import { ContactsServiceImpl } from '../identity/contacts-service';
|
|
@@ -89,6 +89,7 @@ export class ClientServicesHost {
|
|
|
89
89
|
private _callbacks?: ClientServicesHostCallbacks;
|
|
90
90
|
private _devtoolsProxy?: WebsocketRpcClient<{}, ClientServices>;
|
|
91
91
|
private _edgeConnection?: EdgeConnection = undefined;
|
|
92
|
+
private _edgeHttpClient?: EdgeHttpClient = undefined;
|
|
92
93
|
|
|
93
94
|
private _serviceContext!: ServiceContext;
|
|
94
95
|
private readonly _runtimeParams: ServiceContextRuntimeParams;
|
|
@@ -212,8 +213,8 @@ export class ClientServicesHost {
|
|
|
212
213
|
|
|
213
214
|
const edgeEndpoint = config?.get('runtime.services.edge.url');
|
|
214
215
|
if (edgeEndpoint) {
|
|
215
|
-
|
|
216
|
-
this.
|
|
216
|
+
this._edgeConnection = new EdgeClient(createStubEdgeIdentity(), { socketEndpoint: edgeEndpoint });
|
|
217
|
+
this._edgeHttpClient = new EdgeHttpClient(edgeEndpoint);
|
|
217
218
|
}
|
|
218
219
|
|
|
219
220
|
const {
|
|
@@ -278,6 +279,7 @@ export class ClientServicesHost {
|
|
|
278
279
|
this._networkManager,
|
|
279
280
|
this._signalManager,
|
|
280
281
|
this._edgeConnection,
|
|
282
|
+
this._edgeHttpClient,
|
|
281
283
|
this._runtimeParams,
|
|
282
284
|
this._config.get('runtime.client.edgeFeatures'),
|
|
283
285
|
);
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
type SpaceDoc,
|
|
37
37
|
} from '@dxos/echo-protocol';
|
|
38
38
|
import { TYPE_PROPERTIES, generateEchoId, getTypeReference } from '@dxos/echo-schema';
|
|
39
|
-
import type { EdgeConnection } from '@dxos/edge-client';
|
|
39
|
+
import type { EdgeConnection, EdgeHttpClient } from '@dxos/edge-client';
|
|
40
40
|
import { writeMessages, type FeedStore } from '@dxos/feed-store';
|
|
41
41
|
import { invariant } from '@dxos/invariant';
|
|
42
42
|
import { type Keyring } from '@dxos/keyring';
|
|
@@ -46,7 +46,7 @@ import { AlreadyJoinedError, trace as Trace } from '@dxos/protocols';
|
|
|
46
46
|
import { Invitation, SpaceState } from '@dxos/protocols/proto/dxos/client/services';
|
|
47
47
|
import { type Runtime } from '@dxos/protocols/proto/dxos/config';
|
|
48
48
|
import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
49
|
-
import { type SpaceMetadata } from '@dxos/protocols/proto/dxos/echo/metadata';
|
|
49
|
+
import { type SpaceMetadata, EdgeReplicationSetting } from '@dxos/protocols/proto/dxos/echo/metadata';
|
|
50
50
|
import { SpaceMember, type Credential, type ProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
51
51
|
import { type DelegateSpaceInvitation } from '@dxos/protocols/proto/dxos/halo/invitations';
|
|
52
52
|
import { type PeerState } from '@dxos/protocols/proto/dxos/mesh/presence';
|
|
@@ -110,6 +110,7 @@ export type DataSpaceManagerParams = {
|
|
|
110
110
|
echoHost: EchoHost;
|
|
111
111
|
invitationsManager: InvitationsManager;
|
|
112
112
|
edgeConnection?: EdgeConnection;
|
|
113
|
+
edgeHttpClient?: EdgeHttpClient;
|
|
113
114
|
meshReplicator?: MeshEchoReplicator;
|
|
114
115
|
echoEdgeReplicator?: EchoEdgeReplicator;
|
|
115
116
|
runtimeParams?: DataSpaceManagerRuntimeParams;
|
|
@@ -138,6 +139,7 @@ export class DataSpaceManager extends Resource {
|
|
|
138
139
|
private readonly _echoHost: EchoHost;
|
|
139
140
|
private readonly _invitationsManager: InvitationsManager;
|
|
140
141
|
private readonly _edgeConnection?: EdgeConnection = undefined;
|
|
142
|
+
private readonly _edgeHttpClient?: EdgeHttpClient = undefined;
|
|
141
143
|
private readonly _edgeFeatures?: Runtime.Client.EdgeFeatures = undefined;
|
|
142
144
|
private readonly _meshReplicator?: MeshEchoReplicator = undefined;
|
|
143
145
|
private readonly _echoEdgeReplicator?: EchoEdgeReplicator = undefined;
|
|
@@ -157,6 +159,7 @@ export class DataSpaceManager extends Resource {
|
|
|
157
159
|
this._edgeConnection = params.edgeConnection;
|
|
158
160
|
this._edgeFeatures = params.edgeFeatures;
|
|
159
161
|
this._echoEdgeReplicator = params.echoEdgeReplicator;
|
|
162
|
+
this._edgeHttpClient = params.edgeHttpClient;
|
|
160
163
|
this._runtimeParams = params.runtimeParams;
|
|
161
164
|
|
|
162
165
|
trace.diagnostic({
|
|
@@ -391,6 +394,24 @@ export class DataSpaceManager extends Resource {
|
|
|
391
394
|
});
|
|
392
395
|
}
|
|
393
396
|
|
|
397
|
+
async setSpaceEdgeReplicationSetting(spaceKey: PublicKey, setting: EdgeReplicationSetting) {
|
|
398
|
+
const space = this._spaces.get(spaceKey);
|
|
399
|
+
invariant(space, 'Space not found.');
|
|
400
|
+
|
|
401
|
+
await this._metadataStore.setSpaceEdgeReplicationSetting(spaceKey, setting);
|
|
402
|
+
|
|
403
|
+
if (space.isOpen) {
|
|
404
|
+
switch (setting) {
|
|
405
|
+
case EdgeReplicationSetting.DISABLED:
|
|
406
|
+
await this._echoEdgeReplicator?.disconnectFromSpace(space.id);
|
|
407
|
+
break;
|
|
408
|
+
case EdgeReplicationSetting.ENABLED:
|
|
409
|
+
await this._echoEdgeReplicator?.connectToSpace(space.id);
|
|
410
|
+
break;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
394
415
|
private async _constructSpace(metadata: SpaceMetadata) {
|
|
395
416
|
log('construct space', { metadata });
|
|
396
417
|
const gossip = new Gossip({
|
|
@@ -482,13 +503,20 @@ export class DataSpaceManager extends Resource {
|
|
|
482
503
|
},
|
|
483
504
|
cache: metadata.cache,
|
|
484
505
|
edgeConnection: this._edgeConnection,
|
|
506
|
+
edgeHttpClient: this._edgeHttpClient,
|
|
485
507
|
edgeFeatures: this._edgeFeatures,
|
|
486
508
|
});
|
|
487
509
|
dataSpace.postOpen.append(async () => {
|
|
488
|
-
|
|
510
|
+
const setting = dataSpace.getEdgeReplicationSetting();
|
|
511
|
+
if (setting === EdgeReplicationSetting.ENABLED) {
|
|
512
|
+
await this._echoEdgeReplicator?.connectToSpace(dataSpace.id);
|
|
513
|
+
}
|
|
489
514
|
});
|
|
490
515
|
dataSpace.preClose.append(async () => {
|
|
491
|
-
|
|
516
|
+
const setting = dataSpace.getEdgeReplicationSetting();
|
|
517
|
+
if (setting === EdgeReplicationSetting.ENABLED) {
|
|
518
|
+
await this._echoEdgeReplicator?.disconnectFromSpace(dataSpace.id);
|
|
519
|
+
}
|
|
492
520
|
});
|
|
493
521
|
|
|
494
522
|
presence.newPeer.on((peerState) => {
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
type Space,
|
|
16
16
|
} from '@dxos/echo-pipeline';
|
|
17
17
|
import { SpaceDocVersion } from '@dxos/echo-protocol';
|
|
18
|
-
import type { EdgeConnection } from '@dxos/edge-client';
|
|
18
|
+
import type { EdgeConnection, EdgeHttpClient } from '@dxos/edge-client';
|
|
19
19
|
import { type FeedStore, type FeedWrapper } from '@dxos/feed-store';
|
|
20
20
|
import { failedInvariant } from '@dxos/invariant';
|
|
21
21
|
import { type Keyring } from '@dxos/keyring';
|
|
@@ -80,6 +80,7 @@ export type DataSpaceParams = {
|
|
|
80
80
|
callbacks?: DataSpaceCallbacks;
|
|
81
81
|
cache?: SpaceCache;
|
|
82
82
|
edgeConnection?: EdgeConnection;
|
|
83
|
+
edgeHttpClient?: EdgeHttpClient;
|
|
83
84
|
edgeFeatures?: Runtime.Client.EdgeFeatures;
|
|
84
85
|
};
|
|
85
86
|
|
|
@@ -101,7 +102,7 @@ export class DataSpace {
|
|
|
101
102
|
private readonly _feedStore: FeedStore<FeedMessage>;
|
|
102
103
|
private readonly _metadataStore: MetadataStore;
|
|
103
104
|
private readonly _signingContext: SigningContext;
|
|
104
|
-
private readonly _notarizationPlugin
|
|
105
|
+
private readonly _notarizationPlugin: NotarizationPlugin;
|
|
105
106
|
private readonly _callbacks: DataSpaceCallbacks;
|
|
106
107
|
private readonly _cache?: SpaceCache = undefined;
|
|
107
108
|
private readonly _echoHost: EchoHost;
|
|
@@ -141,6 +142,11 @@ export class DataSpace {
|
|
|
141
142
|
this._signingContext = params.signingContext;
|
|
142
143
|
this._callbacks = params.callbacks ?? {};
|
|
143
144
|
this._echoHost = params.echoHost;
|
|
145
|
+
this._notarizationPlugin = new NotarizationPlugin({
|
|
146
|
+
spaceId: this._inner.id,
|
|
147
|
+
edgeClient: params.edgeHttpClient,
|
|
148
|
+
edgeFeatures: params.edgeFeatures,
|
|
149
|
+
});
|
|
144
150
|
|
|
145
151
|
this.authVerifier = new TrustedKeySetAuthVerifier({
|
|
146
152
|
trustedKeysProvider: () =>
|
|
@@ -323,6 +329,7 @@ export class DataSpace {
|
|
|
323
329
|
this._state = SpaceState.SPACE_INITIALIZING;
|
|
324
330
|
log('new state', { state: SpaceState[this._state] });
|
|
325
331
|
|
|
332
|
+
log('initializing control pipeline');
|
|
326
333
|
await this._initializeAndReadControlPipeline();
|
|
327
334
|
|
|
328
335
|
// Allow other tasks to run before loading the data pipeline.
|
|
@@ -330,10 +337,13 @@ export class DataSpace {
|
|
|
330
337
|
|
|
331
338
|
const ready = this.stateUpdate.waitForCondition(() => this._state === SpaceState.SPACE_READY);
|
|
332
339
|
|
|
340
|
+
log('initializing automerge root');
|
|
333
341
|
this._automergeSpaceState.startProcessingRootDocs();
|
|
334
342
|
|
|
335
343
|
// TODO(dmaretskyi): Change so `initializeDataPipeline` doesn't wait for the space to be READY, but rather any state with a valid root.
|
|
344
|
+
log('waiting for space to be ready');
|
|
336
345
|
await ready;
|
|
346
|
+
log('space is ready');
|
|
337
347
|
}
|
|
338
348
|
|
|
339
349
|
private async _enterReadyState() {
|
|
@@ -350,6 +360,7 @@ export class DataSpace {
|
|
|
350
360
|
private async _initializeAndReadControlPipeline() {
|
|
351
361
|
await this._inner.controlPipeline.state.waitUntilReachedTargetTimeframe({
|
|
352
362
|
ctx: this._ctx,
|
|
363
|
+
timeout: 10_000,
|
|
353
364
|
breakOnStall: false,
|
|
354
365
|
});
|
|
355
366
|
|
|
@@ -413,8 +424,16 @@ export class DataSpace {
|
|
|
413
424
|
}
|
|
414
425
|
|
|
415
426
|
if (credentials.length > 0) {
|
|
416
|
-
|
|
417
|
-
|
|
427
|
+
try {
|
|
428
|
+
log('will notarize credentials for feed admission', { count: credentials.length });
|
|
429
|
+
// Never times out
|
|
430
|
+
await this.notarizationPlugin.notarize({ ctx: this._ctx, credentials, timeout: 0 });
|
|
431
|
+
|
|
432
|
+
log('credentials notarized');
|
|
433
|
+
} catch (err) {
|
|
434
|
+
log.error('error notarizing credentials for feed admission', err);
|
|
435
|
+
throw err;
|
|
436
|
+
}
|
|
418
437
|
|
|
419
438
|
// Set this after credentials are notarized so that on failure we will retry.
|
|
420
439
|
await this._metadataStore.setWritableFeedKeys(this.key, this.inner.controlFeedKey!, this.inner.dataFeedKey!);
|
|
@@ -551,6 +570,10 @@ export class DataSpace {
|
|
|
551
570
|
this.stateUpdate.emit();
|
|
552
571
|
}
|
|
553
572
|
|
|
573
|
+
getEdgeReplicationSetting() {
|
|
574
|
+
return this._metadataStore.getSpaceEdgeReplicationSetting(this.key);
|
|
575
|
+
}
|
|
576
|
+
|
|
554
577
|
private _onFeedAdded = async (feed: FeedWrapper<any>) => {
|
|
555
578
|
await this._edgeFeedReplicator!.addFeed(feed);
|
|
556
579
|
};
|
|
@@ -9,12 +9,12 @@ import { describe, test, onTestFinished, vi, expect } from 'vitest';
|
|
|
9
9
|
import { Trigger, sleep } from '@dxos/async';
|
|
10
10
|
import { Context } from '@dxos/context';
|
|
11
11
|
import { valueEncoding } from '@dxos/echo-pipeline';
|
|
12
|
-
import { EdgeClient, EdgeIdentityChangedError } from '@dxos/edge-client';
|
|
12
|
+
import { createEphemeralEdgeIdentity, EdgeClient, EdgeIdentityChangedError } from '@dxos/edge-client';
|
|
13
13
|
import { createTestEdgeWsServer } from '@dxos/edge-client/testing';
|
|
14
14
|
import { FeedFactory, FeedStore } from '@dxos/feed-store';
|
|
15
15
|
import { type FeedWrapper } from '@dxos/feed-store';
|
|
16
16
|
import { Keyring } from '@dxos/keyring';
|
|
17
|
-
import {
|
|
17
|
+
import { SpaceId } from '@dxos/keys';
|
|
18
18
|
import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
19
19
|
import { createStorage } from '@dxos/random-access-storage';
|
|
20
20
|
import { openAndClose } from '@dxos/test-utils';
|
|
@@ -41,6 +41,16 @@ describe('EdgeFeedReplicator', () => {
|
|
|
41
41
|
expect(messageSink[0].type).toEqual('get-metadata');
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
+
test('replicates if added to a connected client', async () => {
|
|
45
|
+
const { endpoint, admitConnection, messageSink } = await createEdge();
|
|
46
|
+
const { messenger } = await createClient(endpoint);
|
|
47
|
+
admitConnection.wake();
|
|
48
|
+
await expect.poll(() => messenger.isConnected).toBeTruthy();
|
|
49
|
+
|
|
50
|
+
await attachReplicator(messenger);
|
|
51
|
+
await expect.poll(() => messageSink.length).toEqual(1);
|
|
52
|
+
});
|
|
53
|
+
|
|
44
54
|
test('sends a block', async () => {
|
|
45
55
|
const { endpoint, admitConnection, messageSink } = await createEdge();
|
|
46
56
|
const { messenger } = await createClient(endpoint);
|
|
@@ -63,7 +73,7 @@ describe('EdgeFeedReplicator', () => {
|
|
|
63
73
|
admitConnection.wake();
|
|
64
74
|
await expect.poll(() => messageSink.length).toEqual(1);
|
|
65
75
|
|
|
66
|
-
updateIdentity(messenger);
|
|
76
|
+
await updateIdentity(messenger);
|
|
67
77
|
await messenger.reconnect.waitForCount(1);
|
|
68
78
|
|
|
69
79
|
await expect.poll(() => messageSink.length).toEqual(2);
|
|
@@ -83,7 +93,7 @@ describe('EdgeFeedReplicator', () => {
|
|
|
83
93
|
|
|
84
94
|
await expect.poll(() => sendSpy.mock.calls.length).toEqual(1);
|
|
85
95
|
expect(messageSink.length).toEqual(0);
|
|
86
|
-
updateIdentity(messenger);
|
|
96
|
+
await updateIdentity(messenger);
|
|
87
97
|
|
|
88
98
|
await expect.poll(() => messageSink.length).toEqual(1);
|
|
89
99
|
expect(messageSink[0].type).toEqual('get-metadata');
|
|
@@ -107,10 +117,9 @@ describe('EdgeFeedReplicator', () => {
|
|
|
107
117
|
|
|
108
118
|
await expect.poll(() => sendSpy.mock.calls.length).toEqual(2);
|
|
109
119
|
expect(messageSink.length).toEqual(0);
|
|
110
|
-
updateIdentity(messenger);
|
|
120
|
+
await updateIdentity(messenger);
|
|
111
121
|
|
|
112
|
-
await expect.poll(() => messageSink.
|
|
113
|
-
expect(messageSink[1].type).toEqual('data');
|
|
122
|
+
await expect.poll(() => messageSink.find((msg) => msg.type === 'data')).toBeDefined();
|
|
114
123
|
});
|
|
115
124
|
|
|
116
125
|
test('propagates errors unrelated to reconnect', async () => {
|
|
@@ -137,7 +146,7 @@ describe('EdgeFeedReplicator', () => {
|
|
|
137
146
|
const { messenger } = await createClient(endpoint);
|
|
138
147
|
|
|
139
148
|
await attachReplicator(messenger);
|
|
140
|
-
updateIdentity(messenger);
|
|
149
|
+
await updateIdentity(messenger);
|
|
141
150
|
await sleep(100);
|
|
142
151
|
admitConnection.wake();
|
|
143
152
|
|
|
@@ -154,7 +163,7 @@ describe('EdgeFeedReplicator', () => {
|
|
|
154
163
|
await sleep(10);
|
|
155
164
|
|
|
156
165
|
admitConnection.reset();
|
|
157
|
-
updateIdentity(messenger);
|
|
166
|
+
await updateIdentity(messenger);
|
|
158
167
|
await appendMessage(feed);
|
|
159
168
|
await sleep(20);
|
|
160
169
|
admitConnection.wake();
|
|
@@ -171,7 +180,7 @@ describe('EdgeFeedReplicator', () => {
|
|
|
171
180
|
await sleep(10);
|
|
172
181
|
|
|
173
182
|
void appendMessage(feed);
|
|
174
|
-
updateIdentity(messenger);
|
|
183
|
+
await updateIdentity(messenger);
|
|
175
184
|
|
|
176
185
|
await expect.poll(() => feedLength()).toEqual(1);
|
|
177
186
|
});
|
|
@@ -203,8 +212,7 @@ describe('EdgeFeedReplicator', () => {
|
|
|
203
212
|
};
|
|
204
213
|
|
|
205
214
|
const createClient = async (endpoint: string) => {
|
|
206
|
-
const
|
|
207
|
-
const messenger = new EdgeClient(peerKey, peerKey, { socketEndpoint: endpoint });
|
|
215
|
+
const messenger = new EdgeClient(await createEphemeralEdgeIdentity(), { socketEndpoint: endpoint });
|
|
208
216
|
const sendSpy = vi.spyOn(messenger, 'send');
|
|
209
217
|
await openAndClose(messenger);
|
|
210
218
|
return { messenger, sendSpy };
|
|
@@ -235,9 +243,8 @@ describe('EdgeFeedReplicator', () => {
|
|
|
235
243
|
return feedStore.openFeed(await keyring.createKey(), { writable: true });
|
|
236
244
|
};
|
|
237
245
|
|
|
238
|
-
const updateIdentity = (messenger: EdgeClient) => {
|
|
239
|
-
|
|
240
|
-
messenger.setIdentity({ peerKey: messenger.peerKey, identityKey });
|
|
246
|
+
const updateIdentity = async (messenger: EdgeClient) => {
|
|
247
|
+
messenger.setIdentity(await createEphemeralEdgeIdentity());
|
|
241
248
|
};
|
|
242
249
|
|
|
243
250
|
const appendMessage = (feed: FeedWrapper<FeedMessage>) => feed.append({ timeframe: new Timeframe() });
|