@dxos/client-services 0.5.8 → 0.5.9-main.0a0e87d
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-JECXTGZA.mjs → chunk-CMZ6YZOX.mjs} +1485 -1315
- package/dist/lib/browser/chunk-CMZ6YZOX.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +55 -363
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/packlets/testing/index.mjs +13 -12
- package/dist/lib/browser/packlets/testing/index.mjs.map +3 -3
- package/dist/lib/node/{chunk-OR7LRWDY.cjs → chunk-CA7UVCON.cjs} +1613 -1447
- package/dist/lib/node/chunk-CA7UVCON.cjs.map +7 -0
- package/dist/lib/node/index.cjs +93 -396
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/packlets/testing/index.cjs +18 -17
- package/dist/lib/node/packlets/testing/index.cjs.map +3 -3
- package/dist/types/src/index.d.ts +3 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/network.d.ts +4 -4
- package/dist/types/src/packlets/devtools/network.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/default-space-state-machine.d.ts +19 -0
- package/dist/types/src/packlets/identity/default-space-state-machine.d.ts.map +1 -0
- package/dist/types/src/packlets/identity/identity-service.d.ts +14 -7
- package/dist/types/src/packlets/identity/identity-service.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity.d.ts +4 -1
- package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
- package/dist/types/src/packlets/network/network-service.d.ts +2 -2
- package/dist/types/src/packlets/network/network-service.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts +4 -5
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +1 -1
- 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 -3
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts +2 -0
- package/dist/types/src/packlets/spaces/data-space.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/packlets/testing/test-builder.d.ts +11 -9
- package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/packlets/worker/index.d.ts +3 -0
- package/dist/types/src/packlets/worker/index.d.ts.map +1 -0
- package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -0
- package/dist/types/src/packlets/worker/worker-session.d.ts.map +1 -0
- package/dist/types/src/version.d.ts +1 -1
- package/dist/types/src/version.d.ts.map +1 -1
- package/package.json +36 -36
- package/src/index.ts +3 -3
- package/src/packlets/devtools/network.ts +4 -4
- package/src/packlets/identity/default-space-state-machine.ts +44 -0
- package/src/packlets/identity/identity-manager.test.ts +2 -2
- package/src/packlets/identity/identity-service.test.ts +35 -5
- package/src/packlets/identity/identity-service.ts +50 -8
- package/src/packlets/identity/identity.test.ts +8 -4
- package/src/packlets/identity/identity.ts +25 -2
- package/src/packlets/invitations/invitations-handler.ts +2 -2
- package/src/packlets/network/network-service.ts +2 -2
- package/src/packlets/services/service-context.ts +3 -3
- package/src/packlets/services/service-host.ts +16 -44
- package/src/packlets/spaces/data-space-manager.test.ts +46 -1
- package/src/packlets/spaces/data-space-manager.ts +54 -25
- package/src/packlets/spaces/data-space.ts +35 -6
- package/src/packlets/spaces/spaces-service.ts +3 -2
- package/src/packlets/testing/test-builder.ts +15 -10
- package/src/packlets/worker/index.ts +6 -0
- package/src/version.ts +1 -5
- package/dist/lib/browser/chunk-JECXTGZA.mjs.map +0 -7
- package/dist/lib/node/chunk-OR7LRWDY.cjs.map +0 -7
- package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts +0 -37
- package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts.map +0 -1
- package/dist/types/src/packlets/vault/index.d.ts +0 -6
- package/dist/types/src/packlets/vault/index.d.ts.map +0 -1
- package/dist/types/src/packlets/vault/shared-worker-connection.d.ts +0 -36
- package/dist/types/src/packlets/vault/shared-worker-connection.d.ts.map +0 -1
- package/dist/types/src/packlets/vault/shell-runtime.d.ts +0 -33
- package/dist/types/src/packlets/vault/shell-runtime.d.ts.map +0 -1
- package/dist/types/src/packlets/vault/worker-runtime.d.ts.map +0 -1
- package/dist/types/src/packlets/vault/worker-session.d.ts.map +0 -1
- package/src/packlets/vault/iframe-host-runtime.ts +0 -130
- package/src/packlets/vault/index.ts +0 -9
- package/src/packlets/vault/shared-worker-connection.ts +0 -115
- package/src/packlets/vault/shell-runtime.ts +0 -111
- /package/dist/types/src/packlets/{vault → worker}/worker-runtime.d.ts +0 -0
- /package/dist/types/src/packlets/{vault → worker}/worker-session.d.ts +0 -0
- /package/src/packlets/{vault → worker}/worker-runtime.ts +0 -0
- /package/src/packlets/{vault → worker}/worker-session.ts +0 -0
|
@@ -9,7 +9,7 @@ import { createKeyPair, sign } from '@dxos/crypto';
|
|
|
9
9
|
import { invariant } from '@dxos/invariant';
|
|
10
10
|
import { PublicKey } from '@dxos/keys';
|
|
11
11
|
import { log } from '@dxos/log';
|
|
12
|
-
import { createTeleportProtocolFactory, type
|
|
12
|
+
import { createTeleportProtocolFactory, type SwarmNetworkManager, type SwarmConnection } from '@dxos/network-manager';
|
|
13
13
|
import { InvalidInvitationExtensionRoleError, trace } from '@dxos/protocols';
|
|
14
14
|
import { type AdmissionKeypair, Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
15
15
|
import { type DeviceProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
@@ -61,7 +61,7 @@ export class InvitationsHandler {
|
|
|
61
61
|
* @internal
|
|
62
62
|
*/
|
|
63
63
|
constructor(
|
|
64
|
-
private readonly _networkManager:
|
|
64
|
+
private readonly _networkManager: SwarmNetworkManager,
|
|
65
65
|
private readonly _defaultTeleportParams?: Partial<TeleportParams>,
|
|
66
66
|
) {}
|
|
67
67
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { Stream } from '@dxos/codec-protobuf';
|
|
6
6
|
import { type SignalManager } from '@dxos/messaging';
|
|
7
|
-
import { type
|
|
7
|
+
import { type SwarmNetworkManager } from '@dxos/network-manager';
|
|
8
8
|
import {
|
|
9
9
|
type NetworkService,
|
|
10
10
|
type NetworkStatus,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
|
|
14
14
|
export class NetworkServiceImpl implements NetworkService {
|
|
15
15
|
constructor(
|
|
16
|
-
private readonly networkManager:
|
|
16
|
+
private readonly networkManager: SwarmNetworkManager,
|
|
17
17
|
private readonly signalManager: SignalManager,
|
|
18
18
|
) {}
|
|
19
19
|
|
|
@@ -15,7 +15,7 @@ import { PublicKey } from '@dxos/keys';
|
|
|
15
15
|
import { type LevelDB } from '@dxos/kv-store';
|
|
16
16
|
import { log } from '@dxos/log';
|
|
17
17
|
import { type SignalManager } from '@dxos/messaging';
|
|
18
|
-
import { type
|
|
18
|
+
import { type SwarmNetworkManager } from '@dxos/network-manager';
|
|
19
19
|
import { InvalidStorageVersionError, STORAGE_VERSION, trace } from '@dxos/protocols';
|
|
20
20
|
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
21
21
|
import type { FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
@@ -35,10 +35,10 @@ import {
|
|
|
35
35
|
import {
|
|
36
36
|
DeviceInvitationProtocol,
|
|
37
37
|
InvitationsHandler,
|
|
38
|
+
InvitationsManager,
|
|
38
39
|
SpaceInvitationProtocol,
|
|
39
40
|
type InvitationProtocol,
|
|
40
41
|
} from '../invitations';
|
|
41
|
-
import { InvitationsManager } from '../invitations/invitations-manager';
|
|
42
42
|
import { DataSpaceManager, type DataSpaceManagerRuntimeParams, type SigningContext } from '../spaces';
|
|
43
43
|
|
|
44
44
|
export type ServiceContextRuntimeParams = IdentityManagerRuntimeParams &
|
|
@@ -81,7 +81,7 @@ export class ServiceContext extends Resource {
|
|
|
81
81
|
constructor(
|
|
82
82
|
public readonly storage: Storage,
|
|
83
83
|
public readonly level: LevelDB,
|
|
84
|
-
public readonly networkManager:
|
|
84
|
+
public readonly networkManager: SwarmNetworkManager,
|
|
85
85
|
public readonly signalManager: SignalManager,
|
|
86
86
|
public readonly _runtimeParams?: ServiceContextRuntimeParams,
|
|
87
87
|
) {
|
|
@@ -3,22 +3,19 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { Event, synchronized } from '@dxos/async';
|
|
6
|
-
import { clientServiceBundle,
|
|
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 { type ObjectStructure, encodeReference, type SpaceDoc } from '@dxos/echo-protocol';
|
|
10
|
-
import { getTypeReference } from '@dxos/echo-schema';
|
|
11
9
|
import { invariant } from '@dxos/invariant';
|
|
12
10
|
import { PublicKey } from '@dxos/keys';
|
|
13
11
|
import { type LevelDB } from '@dxos/kv-store';
|
|
14
12
|
import { log } from '@dxos/log';
|
|
15
13
|
import { WebsocketSignalManager, type SignalManager } from '@dxos/messaging';
|
|
16
|
-
import {
|
|
14
|
+
import { SwarmNetworkManager, createSimplePeerTransportFactory, type TransportFactory } from '@dxos/network-manager';
|
|
17
15
|
import { trace } from '@dxos/protocols';
|
|
18
16
|
import { SystemStatus } from '@dxos/protocols/proto/dxos/client/services';
|
|
19
17
|
import { type Storage } from '@dxos/random-access-storage';
|
|
20
18
|
import { TRACE_PROCESSOR, trace as Trace } from '@dxos/tracing';
|
|
21
|
-
import { assignDeep } from '@dxos/util';
|
|
22
19
|
import { WebsocketRpcClient } from '@dxos/websocket-rpc';
|
|
23
20
|
|
|
24
21
|
import { ServiceContext, type ServiceContextRuntimeParams } from './service-context';
|
|
@@ -79,14 +76,14 @@ export class ClientServicesHost {
|
|
|
79
76
|
private _config?: Config;
|
|
80
77
|
private readonly _statusUpdate = new Event<void>();
|
|
81
78
|
private _signalManager?: SignalManager;
|
|
82
|
-
private _networkManager?:
|
|
79
|
+
private _networkManager?: SwarmNetworkManager;
|
|
83
80
|
private _storage?: Storage;
|
|
84
81
|
private _level?: LevelDB;
|
|
85
82
|
private _callbacks?: ClientServicesHostCallbacks;
|
|
86
83
|
private _devtoolsProxy?: WebsocketRpcClient<{}, ClientServices>;
|
|
87
84
|
|
|
88
85
|
private _serviceContext!: ServiceContext;
|
|
89
|
-
private readonly _runtimeParams
|
|
86
|
+
private readonly _runtimeParams: ServiceContextRuntimeParams;
|
|
90
87
|
private diagnosticsBroadcastHandler: CollectDiagnosticsBroadcastHandler;
|
|
91
88
|
|
|
92
89
|
@Trace.info()
|
|
@@ -109,7 +106,7 @@ export class ClientServicesHost {
|
|
|
109
106
|
this._storage = storage;
|
|
110
107
|
this._level = level;
|
|
111
108
|
this._callbacks = callbacks;
|
|
112
|
-
this._runtimeParams = runtimeParams;
|
|
109
|
+
this._runtimeParams = runtimeParams ?? {};
|
|
113
110
|
|
|
114
111
|
if (config) {
|
|
115
112
|
this.initialize({ config, transportFactory, signalManager });
|
|
@@ -210,7 +207,7 @@ export class ClientServicesHost {
|
|
|
210
207
|
this._signalManager = signalManager;
|
|
211
208
|
|
|
212
209
|
invariant(!this._networkManager, 'network manager already set');
|
|
213
|
-
this._networkManager = new
|
|
210
|
+
this._networkManager = new SwarmNetworkManager({
|
|
214
211
|
log: connectionLog,
|
|
215
212
|
transportFactory,
|
|
216
213
|
signalManager,
|
|
@@ -254,15 +251,17 @@ export class ClientServicesHost {
|
|
|
254
251
|
this._runtimeParams,
|
|
255
252
|
);
|
|
256
253
|
|
|
254
|
+
const identityService = new IdentityServiceImpl(
|
|
255
|
+
this._serviceContext.identityManager,
|
|
256
|
+
this._serviceContext.keyring,
|
|
257
|
+
() => this._serviceContext.dataSpaceManager!,
|
|
258
|
+
(params) => this._createIdentity(params),
|
|
259
|
+
(profile) => this._serviceContext.broadcastProfileUpdate(profile),
|
|
260
|
+
);
|
|
261
|
+
|
|
257
262
|
this._serviceRegistry.setServices({
|
|
258
263
|
SystemService: this._systemService,
|
|
259
|
-
|
|
260
|
-
IdentityService: new IdentityServiceImpl(
|
|
261
|
-
(params) => this._createIdentity(params),
|
|
262
|
-
this._serviceContext.identityManager,
|
|
263
|
-
this._serviceContext.keyring,
|
|
264
|
-
(profile) => this._serviceContext.broadcastProfileUpdate(profile),
|
|
265
|
-
),
|
|
264
|
+
IdentityService: identityService,
|
|
266
265
|
|
|
267
266
|
InvitationsService: new InvitationsServiceImpl(this._serviceContext.invitationsManager),
|
|
268
267
|
|
|
@@ -294,6 +293,7 @@ export class ClientServicesHost {
|
|
|
294
293
|
});
|
|
295
294
|
|
|
296
295
|
await this._serviceContext.open(ctx);
|
|
296
|
+
await identityService.open();
|
|
297
297
|
|
|
298
298
|
const devtoolsProxy = this._config?.get('runtime.client.devtoolsProxy');
|
|
299
299
|
if (devtoolsProxy) {
|
|
@@ -349,35 +349,7 @@ export class ClientServicesHost {
|
|
|
349
349
|
|
|
350
350
|
private async _createIdentity(params: CreateIdentityOptions) {
|
|
351
351
|
const identity = await this._serviceContext.createIdentity(params);
|
|
352
|
-
|
|
353
|
-
// Setup default space.
|
|
354
352
|
await this._serviceContext.initialized.wait();
|
|
355
|
-
const space = await this._serviceContext.dataSpaceManager!.createSpace();
|
|
356
|
-
|
|
357
|
-
const automergeIndex = space.automergeSpaceState.rootUrl;
|
|
358
|
-
invariant(automergeIndex);
|
|
359
|
-
const document = await this._serviceContext.echoHost.automergeRepo.find<SpaceDoc>(automergeIndex as any);
|
|
360
|
-
await document.whenReady();
|
|
361
|
-
|
|
362
|
-
// TODO(dmaretskyi): Better API for low-level data access.
|
|
363
|
-
const properties: ObjectStructure = {
|
|
364
|
-
system: {
|
|
365
|
-
type: encodeReference(getTypeReference(Properties)!),
|
|
366
|
-
},
|
|
367
|
-
data: {
|
|
368
|
-
[defaultKey]: identity.identityKey.toHex(),
|
|
369
|
-
},
|
|
370
|
-
meta: {
|
|
371
|
-
keys: [],
|
|
372
|
-
},
|
|
373
|
-
};
|
|
374
|
-
const propertiesId = PublicKey.random().toHex();
|
|
375
|
-
document.change((doc: SpaceDoc) => {
|
|
376
|
-
assignDeep(doc, ['objects', propertiesId], properties);
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
await this._serviceContext.echoHost.flush();
|
|
380
|
-
|
|
381
353
|
return identity;
|
|
382
354
|
}
|
|
383
355
|
}
|
|
@@ -12,7 +12,7 @@ import { log } from '@dxos/log';
|
|
|
12
12
|
import { SpaceState } from '@dxos/protocols/proto/dxos/client/services';
|
|
13
13
|
import { describe, openAndClose, test } from '@dxos/test';
|
|
14
14
|
|
|
15
|
-
import { TestBuilder } from '../testing';
|
|
15
|
+
import { TestBuilder, type TestPeer } from '../testing';
|
|
16
16
|
|
|
17
17
|
describe('DataSpaceManager', () => {
|
|
18
18
|
test('create space', async () => {
|
|
@@ -168,5 +168,50 @@ describe('DataSpaceManager', () => {
|
|
|
168
168
|
500,
|
|
169
169
|
);
|
|
170
170
|
});
|
|
171
|
+
|
|
172
|
+
test('activate opens a lazily loaded space', async () => {
|
|
173
|
+
const builder = new TestBuilder();
|
|
174
|
+
|
|
175
|
+
const peer = builder.createPeer();
|
|
176
|
+
await peer.createIdentity();
|
|
177
|
+
await openAndClose(peer.echoHost, peer.dataSpaceManager);
|
|
178
|
+
|
|
179
|
+
await peer.dataSpaceManager.createSpace();
|
|
180
|
+
await reloadDataSpaces(peer);
|
|
181
|
+
|
|
182
|
+
const space = getFirstSpace(peer);
|
|
183
|
+
expect(space.state).to.equal(SpaceState.CLOSED);
|
|
184
|
+
await space.activate();
|
|
185
|
+
await asyncTimeout(
|
|
186
|
+
space.stateUpdate.waitForCondition(() => space.state === SpaceState.READY),
|
|
187
|
+
500,
|
|
188
|
+
);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
test('deactivate lazily loaded space ', async () => {
|
|
192
|
+
const builder = new TestBuilder();
|
|
193
|
+
|
|
194
|
+
const peer = builder.createPeer();
|
|
195
|
+
await peer.createIdentity();
|
|
196
|
+
await openAndClose(peer.echoHost, peer.dataSpaceManager);
|
|
197
|
+
|
|
198
|
+
await peer.dataSpaceManager.createSpace();
|
|
199
|
+
await reloadDataSpaces(peer);
|
|
200
|
+
|
|
201
|
+
await getFirstSpace(peer).deactivate();
|
|
202
|
+
|
|
203
|
+
await reloadDataSpaces(peer);
|
|
204
|
+
|
|
205
|
+
expect(getFirstSpace(peer).state).to.eq(SpaceState.INACTIVE);
|
|
206
|
+
});
|
|
171
207
|
});
|
|
208
|
+
|
|
209
|
+
const reloadDataSpaces = async (peer: TestPeer) => {
|
|
210
|
+
await peer.dataSpaceManager.close();
|
|
211
|
+
await peer.dataSpaceManager.open();
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const getFirstSpace = (peer: TestPeer) => {
|
|
215
|
+
return Array.from(peer.dataSpaceManager.spaces.values())[0];
|
|
216
|
+
};
|
|
172
217
|
});
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
import { Event, synchronized, trackLeaks } from '@dxos/async';
|
|
6
6
|
import { type Doc } from '@dxos/automerge/automerge';
|
|
7
|
-
import { type AutomergeUrl } from '@dxos/automerge/automerge-repo';
|
|
7
|
+
import { type DocHandle, type AutomergeUrl } from '@dxos/automerge/automerge-repo';
|
|
8
|
+
import { PropertiesType } from '@dxos/client-protocol';
|
|
8
9
|
import { cancelWithContext, Context } from '@dxos/context';
|
|
9
10
|
import {
|
|
10
11
|
type CredentialSigner,
|
|
@@ -21,7 +22,8 @@ import {
|
|
|
21
22
|
type SpaceProtocol,
|
|
22
23
|
type SpaceProtocolSession,
|
|
23
24
|
} from '@dxos/echo-pipeline';
|
|
24
|
-
import { type SpaceDoc } from '@dxos/echo-protocol';
|
|
25
|
+
import { encodeReference, type ObjectStructure, type SpaceDoc } from '@dxos/echo-protocol';
|
|
26
|
+
import { getTypeReference } from '@dxos/echo-schema';
|
|
25
27
|
import { type FeedStore } from '@dxos/feed-store';
|
|
26
28
|
import { invariant } from '@dxos/invariant';
|
|
27
29
|
import { type Keyring } from '@dxos/keyring';
|
|
@@ -37,7 +39,7 @@ import { type PeerState } from '@dxos/protocols/proto/dxos/mesh/presence';
|
|
|
37
39
|
import { Gossip, Presence } from '@dxos/teleport-extension-gossip';
|
|
38
40
|
import { type Timeframe } from '@dxos/timeframe';
|
|
39
41
|
import { trace } from '@dxos/tracing';
|
|
40
|
-
import { ComplexMap, deferFunction, forEachAsync } from '@dxos/util';
|
|
42
|
+
import { assignDeep, ComplexMap, deferFunction, forEachAsync } from '@dxos/util';
|
|
41
43
|
|
|
42
44
|
import { DataSpace, findPropertiesObject } from './data-space';
|
|
43
45
|
import { spaceGenesis } from './genesis';
|
|
@@ -47,6 +49,9 @@ import { type InvitationsManager } from '../invitations';
|
|
|
47
49
|
const PRESENCE_ANNOUNCE_INTERVAL = 10_000;
|
|
48
50
|
const PRESENCE_OFFLINE_TIMEOUT = 20_000;
|
|
49
51
|
|
|
52
|
+
// Space properties key for default metadata.
|
|
53
|
+
const DEFAULT_SPACE_KEY = '__DEFAULT__';
|
|
54
|
+
|
|
50
55
|
export interface SigningContext {
|
|
51
56
|
identityKey: PublicKey;
|
|
52
57
|
deviceKey: PublicKey;
|
|
@@ -88,8 +93,6 @@ export class DataSpaceManager {
|
|
|
88
93
|
|
|
89
94
|
private _isOpen = false;
|
|
90
95
|
private readonly _instanceId = PublicKey.random().toHex();
|
|
91
|
-
private readonly _spaceMemberPresenceAnnounceInterval: number;
|
|
92
|
-
private readonly _spaceMemberPresenceOfflineTimeout: number;
|
|
93
96
|
|
|
94
97
|
constructor(
|
|
95
98
|
private readonly _spaceManager: SpaceManager,
|
|
@@ -99,15 +102,8 @@ export class DataSpaceManager {
|
|
|
99
102
|
private readonly _feedStore: FeedStore<FeedMessage>,
|
|
100
103
|
private readonly _echoHost: EchoHost,
|
|
101
104
|
private readonly _invitationsManager: InvitationsManager,
|
|
102
|
-
|
|
105
|
+
private readonly _params?: DataSpaceManagerRuntimeParams,
|
|
103
106
|
) {
|
|
104
|
-
const {
|
|
105
|
-
spaceMemberPresenceAnnounceInterval = PRESENCE_ANNOUNCE_INTERVAL,
|
|
106
|
-
spaceMemberPresenceOfflineTimeout = PRESENCE_OFFLINE_TIMEOUT,
|
|
107
|
-
} = params ?? {};
|
|
108
|
-
this._spaceMemberPresenceAnnounceInterval = spaceMemberPresenceAnnounceInterval;
|
|
109
|
-
this._spaceMemberPresenceOfflineTimeout = spaceMemberPresenceOfflineTimeout;
|
|
110
|
-
|
|
111
107
|
trace.diagnostic({
|
|
112
108
|
id: 'spaces',
|
|
113
109
|
name: 'Spaces',
|
|
@@ -157,12 +153,6 @@ export class DataSpaceManager {
|
|
|
157
153
|
this._isOpen = true;
|
|
158
154
|
this.updated.emit();
|
|
159
155
|
|
|
160
|
-
for (const space of this._spaces.values()) {
|
|
161
|
-
if (space.state !== SpaceState.INACTIVE) {
|
|
162
|
-
space.initializeDataPipelineAsync();
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
156
|
log.trace('dxos.echo.data-space-manager.open', Trace.end({ id: this._instanceId }));
|
|
167
157
|
}
|
|
168
158
|
|
|
@@ -174,6 +164,7 @@ export class DataSpaceManager {
|
|
|
174
164
|
for (const space of this._spaces.values()) {
|
|
175
165
|
await space.close();
|
|
176
166
|
}
|
|
167
|
+
this._spaces.clear();
|
|
177
168
|
}
|
|
178
169
|
|
|
179
170
|
/**
|
|
@@ -197,6 +188,7 @@ export class DataSpaceManager {
|
|
|
197
188
|
|
|
198
189
|
const root = await this._echoHost.createSpaceRoot(spaceKey);
|
|
199
190
|
const space = await this._constructSpace(metadata);
|
|
191
|
+
await space.open();
|
|
200
192
|
|
|
201
193
|
const credentials = await spaceGenesis(this._keyring, this._signingContext, space.inner, root.url);
|
|
202
194
|
await this._metadataStore.addSpace(metadata);
|
|
@@ -211,6 +203,46 @@ export class DataSpaceManager {
|
|
|
211
203
|
return space;
|
|
212
204
|
}
|
|
213
205
|
|
|
206
|
+
async isDefaultSpace(space: DataSpace): Promise<boolean> {
|
|
207
|
+
const rootDoc = await this._getSpaceRootDocument(space);
|
|
208
|
+
const [_, properties] = findPropertiesObject(rootDoc.docSync()) ?? [];
|
|
209
|
+
return properties?.data?.[DEFAULT_SPACE_KEY] === this._signingContext.identityKey.toHex();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async createDefaultSpace() {
|
|
213
|
+
const space = await this.createSpace();
|
|
214
|
+
const document = await this._getSpaceRootDocument(space);
|
|
215
|
+
|
|
216
|
+
// TODO(dmaretskyi): Better API for low-level data access.
|
|
217
|
+
const properties: ObjectStructure = {
|
|
218
|
+
system: {
|
|
219
|
+
type: encodeReference(getTypeReference(PropertiesType)!),
|
|
220
|
+
},
|
|
221
|
+
data: {
|
|
222
|
+
[DEFAULT_SPACE_KEY]: this._signingContext.identityKey.toHex(),
|
|
223
|
+
},
|
|
224
|
+
meta: {
|
|
225
|
+
keys: [],
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const propertiesId = PublicKey.random().toHex();
|
|
230
|
+
document.change((doc: SpaceDoc) => {
|
|
231
|
+
assignDeep(doc, ['objects', propertiesId], properties);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
await this._echoHost.flush();
|
|
235
|
+
return space;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
private async _getSpaceRootDocument(space: DataSpace): Promise<DocHandle<SpaceDoc>> {
|
|
239
|
+
const automergeIndex = space.automergeSpaceState.rootUrl;
|
|
240
|
+
invariant(automergeIndex);
|
|
241
|
+
const document = this._echoHost.automergeRepo.find<SpaceDoc>(automergeIndex as any);
|
|
242
|
+
await document.whenReady();
|
|
243
|
+
return document;
|
|
244
|
+
}
|
|
245
|
+
|
|
214
246
|
// TODO(burdon): Rename join space.
|
|
215
247
|
@synchronized
|
|
216
248
|
async acceptSpace(opts: AcceptSpaceOptions): Promise<DataSpace> {
|
|
@@ -226,6 +258,7 @@ export class DataSpaceManager {
|
|
|
226
258
|
};
|
|
227
259
|
|
|
228
260
|
const space = await this._constructSpace(metadata);
|
|
261
|
+
await space.open();
|
|
229
262
|
await this._metadataStore.addSpace(metadata);
|
|
230
263
|
space.initializeDataPipelineAsync();
|
|
231
264
|
|
|
@@ -254,8 +287,8 @@ export class DataSpaceManager {
|
|
|
254
287
|
localPeerId: this._signingContext.deviceKey,
|
|
255
288
|
});
|
|
256
289
|
const presence = new Presence({
|
|
257
|
-
announceInterval: this.
|
|
258
|
-
offlineTimeout: this.
|
|
290
|
+
announceInterval: this._params?.spaceMemberPresenceAnnounceInterval ?? PRESENCE_ANNOUNCE_INTERVAL,
|
|
291
|
+
offlineTimeout: this._params?.spaceMemberPresenceOfflineTimeout ?? PRESENCE_OFFLINE_TIMEOUT,
|
|
259
292
|
identityKey: this._signingContext.identityKey,
|
|
260
293
|
gossip,
|
|
261
294
|
});
|
|
@@ -336,10 +369,6 @@ export class DataSpaceManager {
|
|
|
336
369
|
}
|
|
337
370
|
});
|
|
338
371
|
|
|
339
|
-
if (metadata.state !== SpaceState.INACTIVE) {
|
|
340
|
-
await dataSpace.open();
|
|
341
|
-
}
|
|
342
|
-
|
|
343
372
|
if (metadata.controlTimeframe) {
|
|
344
373
|
dataSpace.inner.controlPipeline.state.setTargetTimeframe(metadata.controlTimeframe);
|
|
345
374
|
}
|
|
@@ -9,6 +9,7 @@ import { timed, warnAfterTimeout } from '@dxos/debug';
|
|
|
9
9
|
import { type EchoHost } from '@dxos/echo-db';
|
|
10
10
|
import {
|
|
11
11
|
AutomergeDocumentLoaderImpl,
|
|
12
|
+
createIdFromSpaceKey,
|
|
12
13
|
createMappedFeedWriter,
|
|
13
14
|
type MetadataStore,
|
|
14
15
|
type Space,
|
|
@@ -75,6 +76,7 @@ export type DataSpaceParams = {
|
|
|
75
76
|
|
|
76
77
|
export type CreateEpochOptions = {
|
|
77
78
|
migration?: CreateEpochRequest.Migration;
|
|
79
|
+
newAutomergeRoot?: string;
|
|
78
80
|
};
|
|
79
81
|
|
|
80
82
|
@trackLeaks('open', 'close')
|
|
@@ -141,6 +143,11 @@ export class DataSpace {
|
|
|
141
143
|
log('new state', { state: SpaceState[this._state] });
|
|
142
144
|
}
|
|
143
145
|
|
|
146
|
+
@trace.info()
|
|
147
|
+
get id() {
|
|
148
|
+
return this._inner.id;
|
|
149
|
+
}
|
|
150
|
+
|
|
144
151
|
@trace.info()
|
|
145
152
|
get key() {
|
|
146
153
|
return this._inner.key;
|
|
@@ -186,10 +193,13 @@ export class DataSpace {
|
|
|
186
193
|
|
|
187
194
|
@synchronized
|
|
188
195
|
async open() {
|
|
189
|
-
|
|
196
|
+
if (this._state === SpaceState.CLOSED) {
|
|
197
|
+
await this._open();
|
|
198
|
+
}
|
|
190
199
|
}
|
|
191
200
|
|
|
192
201
|
private async _open() {
|
|
202
|
+
await this._presence.open();
|
|
193
203
|
await this._gossip.open();
|
|
194
204
|
await this._notarizationPlugin.open();
|
|
195
205
|
await this._inner.spaceState.addCredentialProcessor(this._notarizationPlugin);
|
|
@@ -221,7 +231,7 @@ export class DataSpace {
|
|
|
221
231
|
await this._inner.spaceState.removeCredentialProcessor(this._notarizationPlugin);
|
|
222
232
|
await this._notarizationPlugin.close();
|
|
223
233
|
|
|
224
|
-
await this._presence.
|
|
234
|
+
await this._presence.close();
|
|
225
235
|
await this._gossip.close();
|
|
226
236
|
}
|
|
227
237
|
|
|
@@ -446,6 +456,7 @@ export class DataSpace {
|
|
|
446
456
|
const rootHandle = this._echoHost.automergeRepo.find(currentRootUrl as any);
|
|
447
457
|
await cancelWithContext(this._ctx, asyncTimeout(rootHandle.whenReady(), 10_000));
|
|
448
458
|
const newRoot = this._echoHost.automergeRepo.create(rootHandle.docSync());
|
|
459
|
+
await this._echoHost.automergeRepo.flush([newRoot.documentId]);
|
|
449
460
|
invariant(typeof newRoot.url === 'string' && newRoot.url.length > 0);
|
|
450
461
|
// TODO(dmaretskyi): Unify epoch construction.
|
|
451
462
|
epoch = {
|
|
@@ -476,7 +487,11 @@ export class DataSpace {
|
|
|
476
487
|
invariant(typeof newRoot.url === 'string' && newRoot.url.length > 0);
|
|
477
488
|
|
|
478
489
|
// Create new automerge documents for all objects.
|
|
479
|
-
const docLoader = new AutomergeDocumentLoaderImpl(
|
|
490
|
+
const docLoader = new AutomergeDocumentLoaderImpl(
|
|
491
|
+
await createIdFromSpaceKey(this.key),
|
|
492
|
+
this._echoHost.automergeRepo,
|
|
493
|
+
this.key,
|
|
494
|
+
);
|
|
480
495
|
await docLoader.loadSpaceRootDocHandle(this._ctx, { rootUrl: newRoot.url });
|
|
481
496
|
|
|
482
497
|
otherObjects.forEach(([key, value]) => {
|
|
@@ -497,6 +512,18 @@ export class DataSpace {
|
|
|
497
512
|
};
|
|
498
513
|
}
|
|
499
514
|
break;
|
|
515
|
+
case CreateEpochRequest.Migration.REPLACE_AUTOMERGE_ROOT:
|
|
516
|
+
{
|
|
517
|
+
invariant(options.newAutomergeRoot);
|
|
518
|
+
// TODO(dmaretskyi): Unify epoch construction.
|
|
519
|
+
epoch = {
|
|
520
|
+
previousId: this._automergeSpaceState.lastEpoch?.id,
|
|
521
|
+
number: (this._automergeSpaceState.lastEpoch?.subject.assertion.number ?? -1) + 1,
|
|
522
|
+
timeframe: this._automergeSpaceState.lastEpoch?.subject.assertion.timeframe ?? new Timeframe(),
|
|
523
|
+
automergeRoot: options.newAutomergeRoot,
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
break;
|
|
500
527
|
}
|
|
501
528
|
|
|
502
529
|
if (!epoch) {
|
|
@@ -516,11 +543,12 @@ export class DataSpace {
|
|
|
516
543
|
});
|
|
517
544
|
|
|
518
545
|
await this.inner.controlPipeline.state.waitUntilTimeframe(new Timeframe([[receipt.feedKey, receipt.seq]]));
|
|
546
|
+
await this._echoHost.updateIndexes();
|
|
519
547
|
}
|
|
520
548
|
|
|
521
549
|
@synchronized
|
|
522
550
|
async activate() {
|
|
523
|
-
if (
|
|
551
|
+
if (![SpaceState.CLOSED, SpaceState.INACTIVE].includes(this._state)) {
|
|
524
552
|
return;
|
|
525
553
|
}
|
|
526
554
|
|
|
@@ -534,10 +562,11 @@ export class DataSpace {
|
|
|
534
562
|
if (this._state === SpaceState.INACTIVE) {
|
|
535
563
|
return;
|
|
536
564
|
}
|
|
537
|
-
|
|
538
565
|
// Unregister from data service.
|
|
539
566
|
await this._metadataStore.setSpaceState(this.key, SpaceState.INACTIVE);
|
|
540
|
-
|
|
567
|
+
if (this._state !== SpaceState.CLOSED) {
|
|
568
|
+
await this._close();
|
|
569
|
+
}
|
|
541
570
|
this._state = SpaceState.INACTIVE;
|
|
542
571
|
log('new state', { state: SpaceState[this._state] });
|
|
543
572
|
this.stateUpdate.emit();
|
|
@@ -208,14 +208,15 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
async createEpoch({ spaceKey, migration }: CreateEpochRequest) {
|
|
211
|
+
async createEpoch({ spaceKey, migration, automergeRootUrl }: CreateEpochRequest) {
|
|
212
212
|
const dataSpaceManager = await this._getDataSpaceManager();
|
|
213
213
|
const space = dataSpaceManager.spaces.get(spaceKey) ?? raise(new SpaceNotFoundError(spaceKey));
|
|
214
|
-
await space.createEpoch({ migration });
|
|
214
|
+
await space.createEpoch({ migration, newAutomergeRoot: automergeRootUrl });
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
private _serializeSpace(space: DataSpace): Space {
|
|
218
218
|
return {
|
|
219
|
+
id: space.id,
|
|
219
220
|
spaceKey: space.key,
|
|
220
221
|
state: space.state,
|
|
221
222
|
error: space.error ? encodeError(space.error) : undefined,
|
|
@@ -13,14 +13,14 @@ import { Keyring } from '@dxos/keyring';
|
|
|
13
13
|
import { type LevelDB } from '@dxos/kv-store';
|
|
14
14
|
import { createTestLevel } from '@dxos/kv-store/testing';
|
|
15
15
|
import { MemorySignalManager, MemorySignalManagerContext } from '@dxos/messaging';
|
|
16
|
-
import { MemoryTransportFactory,
|
|
16
|
+
import { MemoryTransportFactory, SwarmNetworkManager } from '@dxos/network-manager';
|
|
17
17
|
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
18
18
|
import { createStorage, StorageType, type Storage } from '@dxos/random-access-storage';
|
|
19
19
|
import { BlobStore } from '@dxos/teleport-extension-object-sync';
|
|
20
20
|
|
|
21
21
|
import { InvitationsHandler, InvitationsManager, SpaceInvitationProtocol } from '../invitations';
|
|
22
|
-
import { ClientServicesHost, ServiceContext } from '../services';
|
|
23
|
-
import { DataSpaceManager, type SigningContext } from '../spaces';
|
|
22
|
+
import { ClientServicesHost, ServiceContext, type ServiceContextRuntimeParams } from '../services';
|
|
23
|
+
import { DataSpaceManager, type DataSpaceManagerRuntimeParams, type SigningContext } from '../spaces';
|
|
24
24
|
|
|
25
25
|
//
|
|
26
26
|
// TODO(burdon): Replace with test builder.
|
|
@@ -37,12 +37,14 @@ export const createServiceHost = (config: Config, signalManagerContext: MemorySi
|
|
|
37
37
|
export const createServiceContext = async ({
|
|
38
38
|
signalContext = new MemorySignalManagerContext(),
|
|
39
39
|
storage = createStorage({ type: StorageType.RAM }),
|
|
40
|
+
runtimeParams,
|
|
40
41
|
}: {
|
|
41
42
|
signalContext?: MemorySignalManagerContext;
|
|
42
43
|
storage?: Storage;
|
|
44
|
+
runtimeParams?: ServiceContextRuntimeParams;
|
|
43
45
|
} = {}) => {
|
|
44
46
|
const signalManager = new MemorySignalManager(signalContext);
|
|
45
|
-
const networkManager = new
|
|
47
|
+
const networkManager = new SwarmNetworkManager({
|
|
46
48
|
signalManager,
|
|
47
49
|
transportFactory: MemoryTransportFactory,
|
|
48
50
|
});
|
|
@@ -51,6 +53,7 @@ export const createServiceContext = async ({
|
|
|
51
53
|
|
|
52
54
|
return new ServiceContext(storage, level, networkManager, signalManager, {
|
|
53
55
|
invitationConnectionDefaultParams: { controlHeartbeatInterval: 200 },
|
|
56
|
+
...runtimeParams,
|
|
54
57
|
});
|
|
55
58
|
};
|
|
56
59
|
|
|
@@ -88,6 +91,7 @@ export class TestBuilder {
|
|
|
88
91
|
|
|
89
92
|
export type TestPeerOpts = {
|
|
90
93
|
dataStore?: StorageType;
|
|
94
|
+
dataSpaceParams?: DataSpaceManagerRuntimeParams;
|
|
91
95
|
};
|
|
92
96
|
|
|
93
97
|
export type TestPeerProps = {
|
|
@@ -96,7 +100,7 @@ export type TestPeerProps = {
|
|
|
96
100
|
feedStore?: FeedStore<any>;
|
|
97
101
|
metadataStore?: MetadataStore;
|
|
98
102
|
keyring?: Keyring;
|
|
99
|
-
networkManager?:
|
|
103
|
+
networkManager?: SwarmNetworkManager;
|
|
100
104
|
spaceManager?: SpaceManager;
|
|
101
105
|
dataSpaceManager?: DataSpaceManager;
|
|
102
106
|
snapshotStore?: SnapshotStore;
|
|
@@ -110,8 +114,8 @@ export class TestPeer {
|
|
|
110
114
|
private _props: TestPeerProps = {};
|
|
111
115
|
|
|
112
116
|
constructor(
|
|
113
|
-
private readonly
|
|
114
|
-
private readonly
|
|
117
|
+
private readonly _signalContext: MemorySignalManagerContext,
|
|
118
|
+
private readonly _opts: TestPeerOpts = { dataStore: StorageType.RAM },
|
|
115
119
|
) {}
|
|
116
120
|
|
|
117
121
|
get props() {
|
|
@@ -119,7 +123,7 @@ export class TestPeer {
|
|
|
119
123
|
}
|
|
120
124
|
|
|
121
125
|
get storage() {
|
|
122
|
-
return (this._props.storage ??= createStorage({ type: this.
|
|
126
|
+
return (this._props.storage ??= createStorage({ type: this._opts.dataStore }));
|
|
123
127
|
}
|
|
124
128
|
|
|
125
129
|
get keyring() {
|
|
@@ -155,8 +159,8 @@ export class TestPeer {
|
|
|
155
159
|
}
|
|
156
160
|
|
|
157
161
|
get networkManager() {
|
|
158
|
-
return (this._props.networkManager ??= new
|
|
159
|
-
signalManager: new MemorySignalManager(this.
|
|
162
|
+
return (this._props.networkManager ??= new SwarmNetworkManager({
|
|
163
|
+
signalManager: new MemorySignalManager(this._signalContext),
|
|
160
164
|
transportFactory: MemoryTransportFactory,
|
|
161
165
|
}));
|
|
162
166
|
}
|
|
@@ -191,6 +195,7 @@ export class TestPeer {
|
|
|
191
195
|
this.feedStore,
|
|
192
196
|
this.echoHost,
|
|
193
197
|
this.invitationsManager,
|
|
198
|
+
this._opts.dataSpaceParams,
|
|
194
199
|
));
|
|
195
200
|
}
|
|
196
201
|
|
package/src/version.ts
CHANGED