@dxos/client-services 0.5.8 → 0.5.9-main.079a532
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-QZ5LNV55.mjs} +1781 -1480
- package/dist/lib/browser/chunk-QZ5LNV55.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +55 -365
- 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 +14 -14
- package/dist/lib/browser/packlets/testing/index.mjs.map +3 -3
- package/dist/lib/node/{chunk-OR7LRWDY.cjs → chunk-V7UMWFUS.cjs} +2055 -1761
- package/dist/lib/node/chunk-V7UMWFUS.cjs.map +7 -0
- package/dist/lib/node/index.cjs +92 -397
- 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 +19 -19
- 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/automerge-space-state.d.ts +4 -1
- package/dist/types/src/packlets/spaces/automerge-space-state.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 +11 -9
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/epoch-migrations.d.ts +23 -0
- package/dist/types/src/packlets/spaces/epoch-migrations.d.ts.map +1 -0
- package/dist/types/src/packlets/spaces/spaces-service.d.ts +2 -2
- 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 +55 -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 +4 -7
- package/src/packlets/services/service-host.ts +16 -44
- package/src/packlets/spaces/automerge-space-state.ts +11 -2
- package/src/packlets/spaces/data-space-manager.test.ts +46 -1
- package/src/packlets/spaces/data-space-manager.ts +81 -31
- package/src/packlets/spaces/data-space.ts +89 -132
- package/src/packlets/spaces/epoch-migrations.ts +135 -0
- package/src/packlets/spaces/spaces-service.ts +5 -2
- package/src/packlets/testing/test-builder.ts +16 -14
- 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
|
@@ -7,6 +7,7 @@ import expect from 'expect';
|
|
|
7
7
|
import { Context } from '@dxos/context';
|
|
8
8
|
import { CredentialGenerator, verifyCredential } from '@dxos/credentials';
|
|
9
9
|
import {
|
|
10
|
+
createIdFromSpaceKey,
|
|
10
11
|
MetadataStore,
|
|
11
12
|
MOCK_AUTH_PROVIDER,
|
|
12
13
|
MOCK_AUTH_VERIFIER,
|
|
@@ -20,7 +21,7 @@ import { FeedFactory, FeedStore } from '@dxos/feed-store';
|
|
|
20
21
|
import { Keyring } from '@dxos/keyring';
|
|
21
22
|
import { type PublicKey } from '@dxos/keys';
|
|
22
23
|
import { MemorySignalManager, MemorySignalManagerContext } from '@dxos/messaging';
|
|
23
|
-
import { MemoryTransportFactory,
|
|
24
|
+
import { MemoryTransportFactory, SwarmNetworkManager } from '@dxos/network-manager';
|
|
24
25
|
import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
25
26
|
import { AdmittedFeed } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
26
27
|
import { createStorage, StorageType } from '@dxos/random-access-storage';
|
|
@@ -78,7 +79,7 @@ describe('identity/identity', () => {
|
|
|
78
79
|
credentialAuthenticator: MOCK_AUTH_VERIFIER,
|
|
79
80
|
},
|
|
80
81
|
blobStore,
|
|
81
|
-
networkManager: new
|
|
82
|
+
networkManager: new SwarmNetworkManager({
|
|
82
83
|
signalManager: new MemorySignalManager(new MemorySignalManagerContext()),
|
|
83
84
|
transportFactory: MemoryTransportFactory,
|
|
84
85
|
}),
|
|
@@ -86,6 +87,7 @@ describe('identity/identity', () => {
|
|
|
86
87
|
|
|
87
88
|
await metadataStore.setIdentityRecord({ haloSpace: { key: spaceKey }, identityKey, deviceKey });
|
|
88
89
|
const space: Space = new Space({
|
|
90
|
+
id: await createIdFromSpaceKey(spaceKey),
|
|
89
91
|
spaceKey,
|
|
90
92
|
protocol,
|
|
91
93
|
genesisFeed: controlFeed,
|
|
@@ -193,7 +195,7 @@ describe('identity/identity', () => {
|
|
|
193
195
|
credentialAuthenticator: MOCK_AUTH_VERIFIER, // createHaloAuthVerifier(() => identity.authorizedDeviceKeys),
|
|
194
196
|
},
|
|
195
197
|
blobStore,
|
|
196
|
-
networkManager: new
|
|
198
|
+
networkManager: new SwarmNetworkManager({
|
|
197
199
|
signalManager: new MemorySignalManager(signalContext),
|
|
198
200
|
transportFactory: MemoryTransportFactory,
|
|
199
201
|
}),
|
|
@@ -201,6 +203,7 @@ describe('identity/identity', () => {
|
|
|
201
203
|
|
|
202
204
|
await metadataStore.setIdentityRecord({ haloSpace: { key: spaceKey }, identityKey, deviceKey });
|
|
203
205
|
const space = new Space({
|
|
206
|
+
id: await createIdFromSpaceKey(spaceKey),
|
|
204
207
|
spaceKey,
|
|
205
208
|
protocol,
|
|
206
209
|
genesisFeed: controlFeed,
|
|
@@ -281,7 +284,7 @@ describe('identity/identity', () => {
|
|
|
281
284
|
credentialAuthenticator: MOCK_AUTH_VERIFIER, // createHaloAuthVerifier(() => identity.authorizedDeviceKeys),
|
|
282
285
|
},
|
|
283
286
|
blobStore,
|
|
284
|
-
networkManager: new
|
|
287
|
+
networkManager: new SwarmNetworkManager({
|
|
285
288
|
signalManager: new MemorySignalManager(signalContext),
|
|
286
289
|
transportFactory: MemoryTransportFactory,
|
|
287
290
|
}),
|
|
@@ -293,6 +296,7 @@ describe('identity/identity', () => {
|
|
|
293
296
|
deviceKey,
|
|
294
297
|
});
|
|
295
298
|
const space = new Space({
|
|
299
|
+
id: await createIdFromSpaceKey(spaceKey),
|
|
296
300
|
spaceKey,
|
|
297
301
|
protocol,
|
|
298
302
|
genesisFeed: await feedStore.openFeed(genesisFeedKey),
|
|
@@ -16,7 +16,7 @@ import { type Signer } from '@dxos/crypto';
|
|
|
16
16
|
import { type Space } from '@dxos/echo-pipeline';
|
|
17
17
|
import { writeMessages } from '@dxos/feed-store';
|
|
18
18
|
import { invariant } from '@dxos/invariant';
|
|
19
|
-
import { PublicKey } from '@dxos/keys';
|
|
19
|
+
import { PublicKey, type SpaceId } from '@dxos/keys';
|
|
20
20
|
import { log } from '@dxos/log';
|
|
21
21
|
import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
22
22
|
import {
|
|
@@ -26,10 +26,12 @@ import {
|
|
|
26
26
|
} from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
27
27
|
import { type DeviceAdmissionRequest } from '@dxos/protocols/proto/dxos/halo/invitations';
|
|
28
28
|
import { type Presence } from '@dxos/teleport-extension-gossip';
|
|
29
|
+
import { Timeframe } from '@dxos/timeframe';
|
|
29
30
|
import { trace } from '@dxos/tracing';
|
|
30
31
|
import { type ComplexMap, ComplexSet } from '@dxos/util';
|
|
31
32
|
|
|
32
33
|
import { TrustedKeySetAuthVerifier } from './authenticator';
|
|
34
|
+
import { DefaultSpaceStateMachine } from './default-space-state-machine';
|
|
33
35
|
|
|
34
36
|
export type IdentityParams = {
|
|
35
37
|
identityKey: PublicKey;
|
|
@@ -49,6 +51,7 @@ export class Identity {
|
|
|
49
51
|
private readonly _presence?: Presence;
|
|
50
52
|
private readonly _deviceStateMachine: DeviceStateMachine;
|
|
51
53
|
private readonly _profileStateMachine: ProfileStateMachine;
|
|
54
|
+
private readonly _defaultSpaceStateMachine: DefaultSpaceStateMachine;
|
|
52
55
|
public readonly authVerifier: TrustedKeySetAuthVerifier;
|
|
53
56
|
|
|
54
57
|
public readonly identityKey: PublicKey;
|
|
@@ -75,6 +78,10 @@ export class Identity {
|
|
|
75
78
|
identityKey: this.identityKey,
|
|
76
79
|
onUpdate: () => this.stateUpdate.emit(),
|
|
77
80
|
});
|
|
81
|
+
this._defaultSpaceStateMachine = new DefaultSpaceStateMachine({
|
|
82
|
+
identityKey: this.identityKey,
|
|
83
|
+
onUpdate: () => this.stateUpdate.emit(),
|
|
84
|
+
});
|
|
78
85
|
|
|
79
86
|
this.authVerifier = new TrustedKeySetAuthVerifier({
|
|
80
87
|
trustedKeysProvider: () => new ComplexSet(PublicKey.hash, this.authorizedDeviceKeys.keys()),
|
|
@@ -88,17 +95,24 @@ export class Identity {
|
|
|
88
95
|
return this._deviceStateMachine.authorizedDeviceKeys;
|
|
89
96
|
}
|
|
90
97
|
|
|
98
|
+
get defaultSpaceId(): SpaceId | undefined {
|
|
99
|
+
return this._defaultSpaceStateMachine.spaceId;
|
|
100
|
+
}
|
|
101
|
+
|
|
91
102
|
@trace.span()
|
|
92
103
|
async open(ctx: Context) {
|
|
104
|
+
await this._presence?.open();
|
|
93
105
|
await this.space.spaceState.addCredentialProcessor(this._deviceStateMachine);
|
|
94
106
|
await this.space.spaceState.addCredentialProcessor(this._profileStateMachine);
|
|
107
|
+
await this.space.spaceState.addCredentialProcessor(this._defaultSpaceStateMachine);
|
|
95
108
|
await this.space.open(ctx);
|
|
96
109
|
}
|
|
97
110
|
|
|
98
111
|
@trace.span()
|
|
99
112
|
async close(ctx: Context) {
|
|
100
|
-
await this._presence?.
|
|
113
|
+
await this._presence?.close();
|
|
101
114
|
await this.authVerifier.close();
|
|
115
|
+
await this.space.spaceState.removeCredentialProcessor(this._defaultSpaceStateMachine);
|
|
102
116
|
await this.space.spaceState.removeCredentialProcessor(this._profileStateMachine);
|
|
103
117
|
await this.space.spaceState.removeCredentialProcessor(this._deviceStateMachine);
|
|
104
118
|
await this.space.close();
|
|
@@ -157,6 +171,15 @@ export class Identity {
|
|
|
157
171
|
return createCredentialSignerWithKey(this._signer, this.deviceKey);
|
|
158
172
|
}
|
|
159
173
|
|
|
174
|
+
async updateDefaultSpace(spaceId: SpaceId) {
|
|
175
|
+
const credential = await this.getDeviceCredentialSigner().createCredential({
|
|
176
|
+
subject: this.identityKey,
|
|
177
|
+
assertion: { '@type': 'dxos.halo.credentials.DefaultSpace', spaceId },
|
|
178
|
+
});
|
|
179
|
+
const receipt = await this.controlPipeline.writer.write({ credential: { credential } });
|
|
180
|
+
await this.controlPipeline.state.waitUntilTimeframe(new Timeframe([[receipt.feedKey, receipt.seq]]));
|
|
181
|
+
}
|
|
182
|
+
|
|
160
183
|
async admitDevice({ deviceKey, controlFeedKey, dataFeedKey }: DeviceAdmissionRequest) {
|
|
161
184
|
log('Admitting device:', {
|
|
162
185
|
identityKey: this.identityKey,
|
|
@@ -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
|
) {
|
|
@@ -120,10 +120,7 @@ export class ServiceContext extends Resource {
|
|
|
120
120
|
this._runtimeParams as IdentityManagerRuntimeParams,
|
|
121
121
|
);
|
|
122
122
|
|
|
123
|
-
this.echoHost = new EchoHost({
|
|
124
|
-
kv: this.level,
|
|
125
|
-
storage: this.storage,
|
|
126
|
-
});
|
|
123
|
+
this.echoHost = new EchoHost({ kv: this.level });
|
|
127
124
|
|
|
128
125
|
this.invitations = new InvitationsHandler(this.networkManager, _runtimeParams?.invitationConnectionDefaultParams);
|
|
129
126
|
this.invitationsManager = new InvitationsManager(
|
|
@@ -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
|
}
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { Event } from '@dxos/async';
|
|
6
|
+
import { Resource, type Context } from '@dxos/context';
|
|
6
7
|
import { type CredentialProcessor, type SpecificCredential, checkCredentialType } from '@dxos/credentials';
|
|
7
8
|
import { type Credential, type Epoch } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
8
9
|
|
|
9
|
-
export class AutomergeSpaceState implements CredentialProcessor {
|
|
10
|
+
export class AutomergeSpaceState extends Resource implements CredentialProcessor {
|
|
10
11
|
public rootUrl: string | undefined = undefined;
|
|
11
12
|
public lastEpoch: SpecificCredential<Epoch> | undefined = undefined;
|
|
12
13
|
|
|
@@ -14,7 +15,15 @@ export class AutomergeSpaceState implements CredentialProcessor {
|
|
|
14
15
|
|
|
15
16
|
private _isProcessingRootDocs = false;
|
|
16
17
|
|
|
17
|
-
constructor(private readonly _onNewRoot: (rootUrl: string) => void) {
|
|
18
|
+
constructor(private readonly _onNewRoot: (rootUrl: string) => void) {
|
|
19
|
+
super();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
protected override async _open(ctx: Context): Promise<void> {}
|
|
23
|
+
|
|
24
|
+
protected override async _close(ctx: Context): Promise<void> {
|
|
25
|
+
this._isProcessingRootDocs = false;
|
|
26
|
+
}
|
|
18
27
|
|
|
19
28
|
async processCredential(credential: Credential) {
|
|
20
29
|
if (!checkCredentialType(credential, 'dxos.halo.credentials.Epoch')) {
|
|
@@ -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,15 +4,16 @@
|
|
|
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';
|
|
8
|
-
import {
|
|
7
|
+
import { type AutomergeUrl, type DocHandle } from '@dxos/automerge/automerge-repo';
|
|
8
|
+
import { PropertiesType } from '@dxos/client-protocol';
|
|
9
|
+
import { Context, cancelWithContext } from '@dxos/context';
|
|
9
10
|
import {
|
|
11
|
+
getCredentialAssertion,
|
|
10
12
|
type CredentialSigner,
|
|
11
13
|
type DelegateInvitationCredential,
|
|
12
|
-
getCredentialAssertion,
|
|
13
14
|
type MemberInfo,
|
|
14
15
|
} from '@dxos/credentials';
|
|
15
|
-
import { type EchoHost } from '@dxos/echo-db';
|
|
16
|
+
import { convertLegacyReferences, findInlineObjectOfType, type EchoHost } from '@dxos/echo-db';
|
|
16
17
|
import {
|
|
17
18
|
AuthStatus,
|
|
18
19
|
type MetadataStore,
|
|
@@ -21,7 +22,14 @@ import {
|
|
|
21
22
|
type SpaceProtocol,
|
|
22
23
|
type SpaceProtocolSession,
|
|
23
24
|
} from '@dxos/echo-pipeline';
|
|
24
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
LEGACY_TYPE_PROPERTIES,
|
|
27
|
+
SpaceDocVersion,
|
|
28
|
+
encodeReference,
|
|
29
|
+
type ObjectStructure,
|
|
30
|
+
type SpaceDoc,
|
|
31
|
+
} from '@dxos/echo-protocol';
|
|
32
|
+
import { TYPE_PROPERTIES, generateEchoId, getTypeReference } from '@dxos/echo-schema';
|
|
25
33
|
import { type FeedStore } from '@dxos/feed-store';
|
|
26
34
|
import { invariant } from '@dxos/invariant';
|
|
27
35
|
import { type Keyring } from '@dxos/keyring';
|
|
@@ -31,15 +39,15 @@ import { trace as Trace } from '@dxos/protocols';
|
|
|
31
39
|
import { Invitation, SpaceState } from '@dxos/protocols/proto/dxos/client/services';
|
|
32
40
|
import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
33
41
|
import { type SpaceMetadata } from '@dxos/protocols/proto/dxos/echo/metadata';
|
|
34
|
-
import { type Credential, type ProfileDocument
|
|
42
|
+
import { SpaceMember, type Credential, type ProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
35
43
|
import { type DelegateSpaceInvitation } from '@dxos/protocols/proto/dxos/halo/invitations';
|
|
36
44
|
import { type PeerState } from '@dxos/protocols/proto/dxos/mesh/presence';
|
|
37
45
|
import { Gossip, Presence } from '@dxos/teleport-extension-gossip';
|
|
38
46
|
import { type Timeframe } from '@dxos/timeframe';
|
|
39
47
|
import { trace } from '@dxos/tracing';
|
|
40
|
-
import { ComplexMap, deferFunction, forEachAsync } from '@dxos/util';
|
|
48
|
+
import { ComplexMap, assignDeep, deferFunction, forEachAsync } from '@dxos/util';
|
|
41
49
|
|
|
42
|
-
import { DataSpace
|
|
50
|
+
import { DataSpace } from './data-space';
|
|
43
51
|
import { spaceGenesis } from './genesis';
|
|
44
52
|
import { createAuthProvider } from '../identity';
|
|
45
53
|
import { type InvitationsManager } from '../invitations';
|
|
@@ -47,6 +55,9 @@ import { type InvitationsManager } from '../invitations';
|
|
|
47
55
|
const PRESENCE_ANNOUNCE_INTERVAL = 10_000;
|
|
48
56
|
const PRESENCE_OFFLINE_TIMEOUT = 20_000;
|
|
49
57
|
|
|
58
|
+
// Space properties key for default metadata.
|
|
59
|
+
const DEFAULT_SPACE_KEY = '__DEFAULT__';
|
|
60
|
+
|
|
50
61
|
export interface SigningContext {
|
|
51
62
|
identityKey: PublicKey;
|
|
52
63
|
deviceKey: PublicKey;
|
|
@@ -88,8 +99,6 @@ export class DataSpaceManager {
|
|
|
88
99
|
|
|
89
100
|
private _isOpen = false;
|
|
90
101
|
private readonly _instanceId = PublicKey.random().toHex();
|
|
91
|
-
private readonly _spaceMemberPresenceAnnounceInterval: number;
|
|
92
|
-
private readonly _spaceMemberPresenceOfflineTimeout: number;
|
|
93
102
|
|
|
94
103
|
constructor(
|
|
95
104
|
private readonly _spaceManager: SpaceManager,
|
|
@@ -99,15 +108,8 @@ export class DataSpaceManager {
|
|
|
99
108
|
private readonly _feedStore: FeedStore<FeedMessage>,
|
|
100
109
|
private readonly _echoHost: EchoHost,
|
|
101
110
|
private readonly _invitationsManager: InvitationsManager,
|
|
102
|
-
|
|
111
|
+
private readonly _params?: DataSpaceManagerRuntimeParams,
|
|
103
112
|
) {
|
|
104
|
-
const {
|
|
105
|
-
spaceMemberPresenceAnnounceInterval = PRESENCE_ANNOUNCE_INTERVAL,
|
|
106
|
-
spaceMemberPresenceOfflineTimeout = PRESENCE_OFFLINE_TIMEOUT,
|
|
107
|
-
} = params ?? {};
|
|
108
|
-
this._spaceMemberPresenceAnnounceInterval = spaceMemberPresenceAnnounceInterval;
|
|
109
|
-
this._spaceMemberPresenceOfflineTimeout = spaceMemberPresenceOfflineTimeout;
|
|
110
|
-
|
|
111
113
|
trace.diagnostic({
|
|
112
114
|
id: 'spaces',
|
|
113
115
|
name: 'Spaces',
|
|
@@ -117,7 +119,7 @@ export class DataSpaceManager {
|
|
|
117
119
|
const rootHandle = rootUrl ? this._echoHost.automergeRepo.find(rootUrl as AutomergeUrl) : undefined;
|
|
118
120
|
const rootDoc = rootHandle?.docSync() as Doc<SpaceDoc> | undefined;
|
|
119
121
|
|
|
120
|
-
const properties = rootDoc &&
|
|
122
|
+
const properties = rootDoc && findInlineObjectOfType(rootDoc, TYPE_PROPERTIES);
|
|
121
123
|
|
|
122
124
|
return {
|
|
123
125
|
key: space.key.toHex(),
|
|
@@ -157,12 +159,6 @@ export class DataSpaceManager {
|
|
|
157
159
|
this._isOpen = true;
|
|
158
160
|
this.updated.emit();
|
|
159
161
|
|
|
160
|
-
for (const space of this._spaces.values()) {
|
|
161
|
-
if (space.state !== SpaceState.INACTIVE) {
|
|
162
|
-
space.initializeDataPipelineAsync();
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
162
|
log.trace('dxos.echo.data-space-manager.open', Trace.end({ id: this._instanceId }));
|
|
167
163
|
}
|
|
168
164
|
|
|
@@ -174,6 +170,7 @@ export class DataSpaceManager {
|
|
|
174
170
|
for (const space of this._spaces.values()) {
|
|
175
171
|
await space.close();
|
|
176
172
|
}
|
|
173
|
+
this._spaces.clear();
|
|
177
174
|
}
|
|
178
175
|
|
|
179
176
|
/**
|
|
@@ -197,6 +194,7 @@ export class DataSpaceManager {
|
|
|
197
194
|
|
|
198
195
|
const root = await this._echoHost.createSpaceRoot(spaceKey);
|
|
199
196
|
const space = await this._constructSpace(metadata);
|
|
197
|
+
await space.open();
|
|
200
198
|
|
|
201
199
|
const credentials = await spaceGenesis(this._keyring, this._signingContext, space.inner, root.url);
|
|
202
200
|
await this._metadataStore.addSpace(metadata);
|
|
@@ -211,6 +209,61 @@ export class DataSpaceManager {
|
|
|
211
209
|
return space;
|
|
212
210
|
}
|
|
213
211
|
|
|
212
|
+
async isDefaultSpace(space: DataSpace): Promise<boolean> {
|
|
213
|
+
if (!space.databaseRoot) {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
switch (space.databaseRoot.getVersion()) {
|
|
217
|
+
case SpaceDocVersion.CURRENT: {
|
|
218
|
+
const [_, properties] = findInlineObjectOfType(space.databaseRoot.docSync()!, TYPE_PROPERTIES) ?? [];
|
|
219
|
+
return properties?.data?.[DEFAULT_SPACE_KEY] === this._signingContext.identityKey.toHex();
|
|
220
|
+
}
|
|
221
|
+
case SpaceDocVersion.LEGACY: {
|
|
222
|
+
const convertedDoc = await convertLegacyReferences(space.databaseRoot.docSync()!);
|
|
223
|
+
const [_, properties] = findInlineObjectOfType(convertedDoc, LEGACY_TYPE_PROPERTIES) ?? [];
|
|
224
|
+
return properties?.data?.[DEFAULT_SPACE_KEY] === this._signingContext.identityKey.toHex();
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
default:
|
|
228
|
+
log.warn('unknown space version', { version: space.databaseRoot.getVersion(), spaceId: space.id });
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async createDefaultSpace() {
|
|
234
|
+
const space = await this.createSpace();
|
|
235
|
+
const document = await this._getSpaceRootDocument(space);
|
|
236
|
+
|
|
237
|
+
// TODO(dmaretskyi): Better API for low-level data access.
|
|
238
|
+
const properties: ObjectStructure = {
|
|
239
|
+
system: {
|
|
240
|
+
type: encodeReference(getTypeReference(PropertiesType)!),
|
|
241
|
+
},
|
|
242
|
+
data: {
|
|
243
|
+
[DEFAULT_SPACE_KEY]: this._signingContext.identityKey.toHex(),
|
|
244
|
+
},
|
|
245
|
+
meta: {
|
|
246
|
+
keys: [],
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
const propertiesId = generateEchoId();
|
|
251
|
+
document.change((doc: SpaceDoc) => {
|
|
252
|
+
assignDeep(doc, ['objects', propertiesId], properties);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
await this._echoHost.flush();
|
|
256
|
+
return space;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
private async _getSpaceRootDocument(space: DataSpace): Promise<DocHandle<SpaceDoc>> {
|
|
260
|
+
const automergeIndex = space.automergeSpaceState.rootUrl;
|
|
261
|
+
invariant(automergeIndex);
|
|
262
|
+
const document = this._echoHost.automergeRepo.find<SpaceDoc>(automergeIndex as any);
|
|
263
|
+
await document.whenReady();
|
|
264
|
+
return document;
|
|
265
|
+
}
|
|
266
|
+
|
|
214
267
|
// TODO(burdon): Rename join space.
|
|
215
268
|
@synchronized
|
|
216
269
|
async acceptSpace(opts: AcceptSpaceOptions): Promise<DataSpace> {
|
|
@@ -226,6 +279,7 @@ export class DataSpaceManager {
|
|
|
226
279
|
};
|
|
227
280
|
|
|
228
281
|
const space = await this._constructSpace(metadata);
|
|
282
|
+
await space.open();
|
|
229
283
|
await this._metadataStore.addSpace(metadata);
|
|
230
284
|
space.initializeDataPipelineAsync();
|
|
231
285
|
|
|
@@ -254,8 +308,8 @@ export class DataSpaceManager {
|
|
|
254
308
|
localPeerId: this._signingContext.deviceKey,
|
|
255
309
|
});
|
|
256
310
|
const presence = new Presence({
|
|
257
|
-
announceInterval: this.
|
|
258
|
-
offlineTimeout: this.
|
|
311
|
+
announceInterval: this._params?.spaceMemberPresenceAnnounceInterval ?? PRESENCE_ANNOUNCE_INTERVAL,
|
|
312
|
+
offlineTimeout: this._params?.spaceMemberPresenceOfflineTimeout ?? PRESENCE_OFFLINE_TIMEOUT,
|
|
259
313
|
identityKey: this._signingContext.identityKey,
|
|
260
314
|
gossip,
|
|
261
315
|
});
|
|
@@ -336,10 +390,6 @@ export class DataSpaceManager {
|
|
|
336
390
|
}
|
|
337
391
|
});
|
|
338
392
|
|
|
339
|
-
if (metadata.state !== SpaceState.INACTIVE) {
|
|
340
|
-
await dataSpace.open();
|
|
341
|
-
}
|
|
342
|
-
|
|
343
393
|
if (metadata.controlTimeframe) {
|
|
344
394
|
dataSpace.inner.controlPipeline.state.setTargetTimeframe(metadata.controlTimeframe);
|
|
345
395
|
}
|