@dxos/client-services 0.1.23 → 0.1.24
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-R2FEBB66.mjs +3865 -0
- package/dist/lib/browser/chunk-R2FEBB66.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +56 -3066
- 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 +198 -0
- package/dist/lib/browser/packlets/testing/index.mjs.map +7 -0
- package/dist/lib/node/index.cjs +1401 -645
- 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 +3688 -0
- package/dist/lib/node/packlets/testing/index.cjs.map +7 -0
- package/dist/types/src/packlets/deprecated/profile.d.ts +3 -1
- package/dist/types/src/packlets/deprecated/profile.d.ts.map +1 -1
- package/dist/types/src/packlets/deprecated/space.d.ts.map +1 -1
- package/dist/types/src/packlets/deprecated/system.d.ts +15 -9
- package/dist/types/src/packlets/deprecated/system.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/devtools.d.ts +2 -2
- package/dist/types/src/packlets/devtools/devtools.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/feeds.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/network.d.ts +3 -3
- package/dist/types/src/packlets/devtools/network.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/spaces.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/authenticator.d.ts +1 -1
- package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-manager.d.ts +7 -1
- package/dist/types/src/packlets/identity/identity-manager.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/invitations/halo-invitations-handler.d.ts +11 -3
- package/dist/types/src/packlets/invitations/halo-invitations-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations.d.ts +1 -1
- package/dist/types/src/packlets/invitations/invitations.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/space-invitations-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts +2 -0
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.test.d.ts +2 -0
- package/dist/types/src/packlets/services/service-context.test.d.ts.map +1 -0
- package/dist/types/src/packlets/services/service-definitions.d.ts +1 -1
- package/dist/types/src/packlets/services/service-definitions.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +9 -6
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-registry.d.ts +4 -3
- package/dist/types/src/packlets/services/service-registry.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts +9 -2
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts +18 -4
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +50 -0
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -0
- package/dist/types/src/packlets/spaces/notarization-plugin.test.d.ts +2 -0
- package/dist/types/src/packlets/spaces/notarization-plugin.test.d.ts.map +1 -0
- package/dist/types/src/packlets/spaces/spaces-service.d.ts +2 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/credential-utils.d.ts +8 -0
- package/dist/types/src/packlets/testing/credential-utils.d.ts.map +1 -0
- package/dist/types/src/packlets/testing/index.d.ts +2 -0
- package/dist/types/src/packlets/testing/index.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/invitation-utils.d.ts +3 -0
- package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -0
- package/dist/types/src/packlets/testing/test-builder.d.ts +2 -2
- package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts +28 -0
- package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts.map +1 -0
- package/dist/types/src/packlets/vault/{iframe-runtime.d.ts → iframe-proxy-runtime.d.ts} +4 -4
- package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts.map +1 -0
- package/dist/types/src/packlets/vault/index.d.ts +4 -1
- package/dist/types/src/packlets/vault/index.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/vault-resource-lock.d.ts +19 -0
- package/dist/types/src/packlets/vault/vault-resource-lock.d.ts.map +1 -0
- package/dist/types/src/packlets/vault/worker-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/worker-session.d.ts +4 -4
- package/dist/types/src/packlets/vault/worker-session.d.ts.map +1 -1
- package/package.json +29 -29
- package/src/packlets/deprecated/profile.ts +20 -2
- package/src/packlets/deprecated/space.ts +41 -37
- package/src/packlets/deprecated/system.ts +26 -13
- package/src/packlets/devtools/devtools.ts +4 -4
- package/src/packlets/devtools/feeds.ts +11 -6
- package/src/packlets/devtools/network.ts +20 -9
- package/src/packlets/devtools/spaces.ts +7 -6
- package/src/packlets/identity/authenticator.ts +11 -6
- package/src/packlets/identity/identity-manager.test.ts +24 -15
- package/src/packlets/identity/identity-manager.ts +22 -8
- package/src/packlets/identity/identity.test.ts +21 -22
- package/src/packlets/identity/identity.ts +10 -5
- package/src/packlets/invitations/halo-invitations-handler.test.ts +4 -45
- package/src/packlets/invitations/halo-invitations-handler.ts +33 -17
- package/src/packlets/invitations/invitations.ts +2 -1
- package/src/packlets/invitations/space-invitations-handler.test.ts +43 -26
- package/src/packlets/invitations/space-invitations-handler.ts +8 -11
- package/src/packlets/services/service-context.test.ts +56 -0
- package/src/packlets/services/service-context.ts +60 -4
- package/src/packlets/services/service-definitions.ts +1 -1
- package/src/packlets/services/service-host.test.ts +74 -5
- package/src/packlets/services/service-host.ts +85 -23
- package/src/packlets/services/service-registry.test.ts +2 -1
- package/src/packlets/services/service-registry.ts +5 -1
- package/src/packlets/spaces/data-space-manager.test.ts +71 -14
- package/src/packlets/spaces/data-space-manager.ts +49 -8
- package/src/packlets/spaces/data-space.ts +113 -14
- package/src/packlets/spaces/notarization-plugin.test.ts +81 -0
- package/src/packlets/spaces/notarization-plugin.ts +211 -0
- package/src/packlets/spaces/spaces-service.ts +9 -1
- package/src/packlets/testing/credential-utils.ts +28 -0
- package/src/packlets/testing/index.ts +2 -0
- package/src/packlets/testing/invitation-utils.ts +44 -0
- package/src/packlets/testing/test-builder.ts +14 -18
- package/src/packlets/vault/iframe-host-runtime.ts +112 -0
- package/src/packlets/vault/{iframe-runtime.ts → iframe-proxy-runtime.ts} +3 -3
- package/src/packlets/vault/index.ts +4 -1
- package/src/packlets/vault/vault-resource-lock.ts +76 -0
- package/src/packlets/vault/worker-runtime.ts +13 -3
- package/src/packlets/vault/worker-session.ts +17 -17
- package/dist/types/src/packlets/vault/iframe-runtime.d.ts.map +0 -1
|
@@ -4,21 +4,23 @@
|
|
|
4
4
|
|
|
5
5
|
import { Config } from '@dxos/config';
|
|
6
6
|
import { raise } from '@dxos/debug';
|
|
7
|
+
import { DocumentModel } from '@dxos/document-model';
|
|
7
8
|
import { DataServiceImpl } from '@dxos/echo-db';
|
|
8
9
|
import { log } from '@dxos/log';
|
|
9
10
|
import { ModelFactory } from '@dxos/model-factory';
|
|
10
11
|
import { NetworkManager } from '@dxos/network-manager';
|
|
11
|
-
import {
|
|
12
|
+
import { Status } from '@dxos/protocols/proto/dxos/client';
|
|
12
13
|
import { Storage } from '@dxos/random-access-storage';
|
|
13
14
|
import { TextModel } from '@dxos/text-model';
|
|
14
15
|
|
|
15
|
-
import { SpaceServiceImpl, ProfileServiceImpl,
|
|
16
|
+
import { SpaceServiceImpl, ProfileServiceImpl, TracingServiceImpl, SystemServiceImpl } from '../deprecated';
|
|
16
17
|
import { DevtoolsServiceImpl, DevtoolsHostEvents } from '../devtools';
|
|
17
18
|
import { DevicesServiceImpl } from '../identity/devices-service-impl';
|
|
18
19
|
import { HaloInvitationsServiceImpl, SpaceInvitationsServiceImpl } from '../invitations';
|
|
19
20
|
import { NetworkServiceImpl } from '../network';
|
|
20
21
|
import { SpacesServiceImpl } from '../spaces';
|
|
21
22
|
import { createStorageObjects } from '../storage';
|
|
23
|
+
import { VaultResourceLock } from '../vault';
|
|
22
24
|
import { ServiceContext } from './service-context';
|
|
23
25
|
import { ClientServicesProvider, ClientServices, clientServiceBundle } from './service-definitions';
|
|
24
26
|
import { ServiceRegistry } from './service-registry';
|
|
@@ -26,7 +28,7 @@ import { ServiceRegistry } from './service-registry';
|
|
|
26
28
|
// TODO(burdon): Factor out to spaces.
|
|
27
29
|
// TODO(burdon): Defaults (with TextModel).
|
|
28
30
|
export const createDefaultModelFactory = () => {
|
|
29
|
-
return new ModelFactory().registerModel(
|
|
31
|
+
return new ModelFactory().registerModel(DocumentModel).registerModel(TextModel);
|
|
30
32
|
};
|
|
31
33
|
|
|
32
34
|
type ClientServicesHostParams = {
|
|
@@ -34,31 +36,77 @@ type ClientServicesHostParams = {
|
|
|
34
36
|
modelFactory?: ModelFactory;
|
|
35
37
|
networkManager: NetworkManager;
|
|
36
38
|
storage?: Storage;
|
|
39
|
+
lockKey?: string;
|
|
37
40
|
};
|
|
38
41
|
|
|
39
42
|
/**
|
|
40
43
|
* Remote service implementation.
|
|
41
44
|
*/
|
|
42
45
|
export class ClientServicesHost implements ClientServicesProvider {
|
|
43
|
-
private
|
|
44
|
-
private _serviceRegistry
|
|
46
|
+
private readonly _resourceLock?: VaultResourceLock;
|
|
47
|
+
private readonly _serviceRegistry: ServiceRegistry<ClientServices>;
|
|
48
|
+
private readonly _systemService: SystemServiceImpl;
|
|
45
49
|
|
|
46
50
|
private readonly _config: Config;
|
|
47
51
|
private readonly _modelFactory: ModelFactory;
|
|
48
52
|
private readonly _networkManager: NetworkManager;
|
|
49
|
-
private _storage: Storage;
|
|
53
|
+
private readonly _storage: Storage;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @internal
|
|
57
|
+
*/
|
|
58
|
+
_serviceContext!: ServiceContext;
|
|
59
|
+
private _open = false;
|
|
50
60
|
|
|
51
61
|
constructor({
|
|
52
62
|
config,
|
|
53
63
|
modelFactory = createDefaultModelFactory(),
|
|
54
64
|
// TODO(burdon): Create ApolloLink abstraction (see Client).
|
|
55
65
|
networkManager,
|
|
56
|
-
storage = createStorageObjects(config.get('runtime.client.storage', {})!).storage
|
|
66
|
+
storage = createStorageObjects(config.get('runtime.client.storage', {})!).storage,
|
|
67
|
+
lockKey
|
|
57
68
|
}: ClientServicesHostParams) {
|
|
58
69
|
this._config = config;
|
|
59
70
|
this._modelFactory = modelFactory;
|
|
60
71
|
this._networkManager = networkManager;
|
|
61
72
|
this._storage = storage;
|
|
73
|
+
|
|
74
|
+
this._resourceLock = lockKey
|
|
75
|
+
? new VaultResourceLock({
|
|
76
|
+
lockKey,
|
|
77
|
+
onAcquire: () => this.open(),
|
|
78
|
+
onRelease: () => this.close()
|
|
79
|
+
})
|
|
80
|
+
: undefined;
|
|
81
|
+
|
|
82
|
+
this._systemService = new SystemServiceImpl({
|
|
83
|
+
config: this._config,
|
|
84
|
+
|
|
85
|
+
onInit: async () => {
|
|
86
|
+
await this._resourceLock?.acquire();
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
onStatus: async () => {
|
|
90
|
+
if (!this.isOpen) {
|
|
91
|
+
return { status: Status.INACTIVE };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return { status: Status.ACTIVE };
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
onReset: async () => {
|
|
98
|
+
await this._serviceContext?.reset();
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// TODO(burdon): Start to think of DMG (dynamic services).
|
|
103
|
+
this._serviceRegistry = new ServiceRegistry<ClientServices>(clientServiceBundle, {
|
|
104
|
+
SystemService: this._systemService
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
get isOpen() {
|
|
109
|
+
return this._open;
|
|
62
110
|
}
|
|
63
111
|
|
|
64
112
|
get descriptors() {
|
|
@@ -70,27 +118,21 @@ export class ClientServicesHost implements ClientServicesProvider {
|
|
|
70
118
|
}
|
|
71
119
|
|
|
72
120
|
async open() {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const deviceKey = this._serviceContext.identityManager.identity?.deviceKey;
|
|
77
|
-
log('opened', { deviceKey });
|
|
78
|
-
}
|
|
121
|
+
if (this._open) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
79
124
|
|
|
80
|
-
|
|
81
|
-
const deviceKey = this._serviceContext.identityManager.identity?.deviceKey;
|
|
82
|
-
log('closing...', { deviceKey });
|
|
83
|
-
await this._serviceContext.close();
|
|
84
|
-
log('closed', { deviceKey });
|
|
85
|
-
}
|
|
125
|
+
log('opening...');
|
|
86
126
|
|
|
87
|
-
|
|
88
|
-
async _initialize() {
|
|
127
|
+
// TODO(wittjosiah): Make re-entrant.
|
|
89
128
|
// TODO(burdon): Break into components.
|
|
90
129
|
this._serviceContext = new ServiceContext(this._storage, this._networkManager, this._modelFactory);
|
|
91
130
|
|
|
92
131
|
// TODO(burdon): Start to think of DMG (dynamic services).
|
|
93
|
-
this._serviceRegistry
|
|
132
|
+
this._serviceRegistry.setServices({
|
|
133
|
+
// TODO(burdon): Move to new protobuf definitions.
|
|
134
|
+
SystemService: this._systemService,
|
|
135
|
+
|
|
94
136
|
HaloInvitationsService: new HaloInvitationsServiceImpl(
|
|
95
137
|
this._serviceContext.identityManager,
|
|
96
138
|
this._serviceContext.haloInvitations
|
|
@@ -112,8 +154,10 @@ export class ClientServicesHost implements ClientServicesProvider {
|
|
|
112
154
|
|
|
113
155
|
// TODO(burdon): Move to new protobuf definitions.
|
|
114
156
|
ProfileService: new ProfileServiceImpl(this._serviceContext),
|
|
157
|
+
|
|
158
|
+
// TODO(burdon): Port old SubscribeSpaces to QueryServices>
|
|
115
159
|
SpaceService: new SpaceServiceImpl(this._serviceContext),
|
|
116
|
-
|
|
160
|
+
|
|
117
161
|
TracingService: new TracingServiceImpl(this._config),
|
|
118
162
|
DevtoolsHost: new DevtoolsServiceImpl({
|
|
119
163
|
events: new DevtoolsHostEvents(),
|
|
@@ -121,5 +165,23 @@ export class ClientServicesHost implements ClientServicesProvider {
|
|
|
121
165
|
context: this._serviceContext
|
|
122
166
|
})
|
|
123
167
|
});
|
|
168
|
+
|
|
169
|
+
await this._serviceContext.open();
|
|
170
|
+
this._open = true;
|
|
171
|
+
const deviceKey = this._serviceContext.identityManager.identity?.deviceKey;
|
|
172
|
+
log('opened', { deviceKey });
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async close() {
|
|
176
|
+
if (!this._open) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const deviceKey = this._serviceContext.identityManager.identity?.deviceKey;
|
|
181
|
+
log('closing...', { deviceKey });
|
|
182
|
+
this._serviceRegistry.setServices({ SystemService: this._systemService });
|
|
183
|
+
await this._serviceContext.close();
|
|
184
|
+
this._open = false;
|
|
185
|
+
log('closed', { deviceKey });
|
|
124
186
|
}
|
|
125
187
|
}
|
|
@@ -13,6 +13,7 @@ import { describe, test } from '@dxos/test';
|
|
|
13
13
|
|
|
14
14
|
import { SpaceInvitationsProxy, SpaceInvitationsServiceImpl } from '../invitations';
|
|
15
15
|
import { createServiceContext } from '../testing';
|
|
16
|
+
import { ClientServices } from './service-definitions';
|
|
16
17
|
import { ServiceRegistry } from './service-registry';
|
|
17
18
|
|
|
18
19
|
// TODO(burdon): Create TestService (that doesn't require peers).
|
|
@@ -54,7 +55,7 @@ describe('service registry', () => {
|
|
|
54
55
|
|
|
55
56
|
const server = createProtoRpcPeer({
|
|
56
57
|
exposed: serviceRegistry.descriptors,
|
|
57
|
-
handlers: serviceRegistry.services,
|
|
58
|
+
handlers: serviceRegistry.services as ClientServices,
|
|
58
59
|
port: serverPort
|
|
59
60
|
});
|
|
60
61
|
|
|
@@ -11,7 +11,7 @@ export class ServiceRegistry<Services> {
|
|
|
11
11
|
// prettier-ignore
|
|
12
12
|
constructor (
|
|
13
13
|
private readonly _serviceBundle: ServiceBundle<Services>,
|
|
14
|
-
private
|
|
14
|
+
private _handlers: Partial<Services>
|
|
15
15
|
) {}
|
|
16
16
|
|
|
17
17
|
get descriptors() {
|
|
@@ -21,4 +21,8 @@ export class ServiceRegistry<Services> {
|
|
|
21
21
|
get services() {
|
|
22
22
|
return this._handlers;
|
|
23
23
|
}
|
|
24
|
+
|
|
25
|
+
setServices(services: Partial<Services>) {
|
|
26
|
+
this._handlers = services;
|
|
27
|
+
}
|
|
24
28
|
}
|
|
@@ -5,16 +5,43 @@
|
|
|
5
5
|
import { expect } from 'chai';
|
|
6
6
|
|
|
7
7
|
import { createAdmissionCredentials } from '@dxos/credentials';
|
|
8
|
+
import { DocumentModel } from '@dxos/document-model';
|
|
8
9
|
import { AuthStatus, DataServiceSubscriptions } from '@dxos/echo-db';
|
|
9
10
|
import { writeMessages } from '@dxos/feed-store';
|
|
11
|
+
import { log } from '@dxos/log';
|
|
10
12
|
import { ModelFactory } from '@dxos/model-factory';
|
|
11
|
-
import { ObjectModel } from '@dxos/object-model';
|
|
12
13
|
import { test, describe } from '@dxos/test';
|
|
13
14
|
|
|
14
15
|
import { createSigningContext, syncItems, TestBuilder } from '../testing';
|
|
15
16
|
import { DataSpaceManager } from './data-space-manager';
|
|
16
17
|
|
|
17
18
|
describe('DataSpaceManager', () => {
|
|
19
|
+
test('create space', async () => {
|
|
20
|
+
const builder = new TestBuilder();
|
|
21
|
+
|
|
22
|
+
const peer = builder.createPeer();
|
|
23
|
+
const identity = await createSigningContext(peer.keyring);
|
|
24
|
+
const dataSpaceManager = new DataSpaceManager(
|
|
25
|
+
peer.spaceManager,
|
|
26
|
+
peer.metadataStore,
|
|
27
|
+
new DataServiceSubscriptions(),
|
|
28
|
+
peer.keyring,
|
|
29
|
+
identity,
|
|
30
|
+
new ModelFactory().registerModel(DocumentModel),
|
|
31
|
+
peer.feedStore,
|
|
32
|
+
peer.snapshotStore
|
|
33
|
+
);
|
|
34
|
+
const space = await dataSpaceManager.createSpace();
|
|
35
|
+
|
|
36
|
+
// Process all written mutations.
|
|
37
|
+
await space.inner.controlPipeline.state.waitUntilTimeframe(space.inner.controlPipeline.state.endTimeframe);
|
|
38
|
+
|
|
39
|
+
expect(space.inner.spaceState.genesisCredential).to.exist;
|
|
40
|
+
expect(space.inner.spaceState.members.size).to.equal(1);
|
|
41
|
+
expect(space.inner.spaceState.feeds.size).to.equal(2);
|
|
42
|
+
expect(space.inner.protocol.feeds.size).to.equal(2);
|
|
43
|
+
});
|
|
44
|
+
|
|
18
45
|
test('sync between peers', async () => {
|
|
19
46
|
const builder = new TestBuilder();
|
|
20
47
|
|
|
@@ -26,7 +53,8 @@ describe('DataSpaceManager', () => {
|
|
|
26
53
|
new DataServiceSubscriptions(),
|
|
27
54
|
peer1.keyring,
|
|
28
55
|
identity1,
|
|
29
|
-
new ModelFactory().registerModel(
|
|
56
|
+
new ModelFactory().registerModel(DocumentModel),
|
|
57
|
+
peer1.feedStore,
|
|
30
58
|
peer1.snapshotStore
|
|
31
59
|
);
|
|
32
60
|
|
|
@@ -38,17 +66,13 @@ describe('DataSpaceManager', () => {
|
|
|
38
66
|
new DataServiceSubscriptions(),
|
|
39
67
|
peer2.keyring,
|
|
40
68
|
identity2,
|
|
41
|
-
new ModelFactory().registerModel(
|
|
69
|
+
new ModelFactory().registerModel(DocumentModel),
|
|
70
|
+
peer2.feedStore,
|
|
42
71
|
peer1.snapshotStore
|
|
43
72
|
);
|
|
44
73
|
|
|
45
74
|
const space1 = await dataSpaceManager1.createSpace();
|
|
46
|
-
|
|
47
|
-
spaceKey: space1.key,
|
|
48
|
-
genesisFeedKey: space1.inner.genesisFeedKey,
|
|
49
|
-
controlFeedKey: await peer2.keyring.createKey(),
|
|
50
|
-
dataFeedKey: await peer2.keyring.createKey()
|
|
51
|
-
});
|
|
75
|
+
await space1.inner.controlPipeline.state.waitUntilTimeframe(space1.inner.controlPipeline.state.endTimeframe);
|
|
52
76
|
|
|
53
77
|
// Admit peer2 to space1.
|
|
54
78
|
await writeMessages(
|
|
@@ -56,15 +80,48 @@ describe('DataSpaceManager', () => {
|
|
|
56
80
|
await createAdmissionCredentials(
|
|
57
81
|
identity1.credentialSigner,
|
|
58
82
|
identity2.identityKey,
|
|
59
|
-
identity2.deviceKey,
|
|
60
83
|
space1.key,
|
|
61
|
-
|
|
62
|
-
space2.inner.dataFeedKey,
|
|
63
|
-
space2.inner.genesisFeedKey
|
|
84
|
+
space1.inner.genesisFeedKey
|
|
64
85
|
)
|
|
65
86
|
);
|
|
66
87
|
|
|
67
|
-
|
|
88
|
+
// Accept must be called after admission so that the peer can authenticate for notarization.
|
|
89
|
+
const space2 = await dataSpaceManager2.acceptSpace({
|
|
90
|
+
spaceKey: space1.key,
|
|
91
|
+
genesisFeedKey: space1.inner.genesisFeedKey
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
log('', {
|
|
95
|
+
peer1: {
|
|
96
|
+
identity: identity1.identityKey,
|
|
97
|
+
device: identity1.deviceKey,
|
|
98
|
+
control: space1.inner.controlFeedKey,
|
|
99
|
+
data: space1.inner.dataFeedKey
|
|
100
|
+
},
|
|
101
|
+
peer2: {
|
|
102
|
+
identity: identity2.identityKey,
|
|
103
|
+
device: identity2.deviceKey,
|
|
104
|
+
control: space2.inner.controlFeedKey,
|
|
105
|
+
data: space2.inner.dataFeedKey
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
await space1.inner.controlPipeline.state.waitUntilTimeframe(space1.inner.controlPipeline.state.endTimeframe);
|
|
110
|
+
await space2.inner.controlPipeline.state.waitUntilTimeframe(space1.inner.controlPipeline.state.endTimeframe);
|
|
111
|
+
|
|
112
|
+
log('', {
|
|
113
|
+
space1: {
|
|
114
|
+
timeframe: space1.inner.controlPipeline.state.timeframe,
|
|
115
|
+
endTimeframe: space1.inner.controlPipeline.state.endTimeframe
|
|
116
|
+
},
|
|
117
|
+
space2: {
|
|
118
|
+
timeframe: space2.inner.controlPipeline.state.timeframe,
|
|
119
|
+
endTimeframe: space2.inner.controlPipeline.state.endTimeframe
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
log.break();
|
|
123
|
+
|
|
124
|
+
await syncItems(space1.dataPipelineController, space2.dataPipelineController);
|
|
68
125
|
|
|
69
126
|
expect(space1.inner.protocol.sessions.get(identity2.deviceKey)).to.exist;
|
|
70
127
|
expect(space1.inner.protocol.sessions.get(identity2.deviceKey)?.authStatus).to.equal(AuthStatus.SUCCESS);
|
|
@@ -6,8 +6,8 @@ import assert from 'node:assert';
|
|
|
6
6
|
|
|
7
7
|
import { Event, synchronized, trackLeaks } from '@dxos/async';
|
|
8
8
|
import { Context } from '@dxos/context';
|
|
9
|
+
import { getCredentialAssertion } from '@dxos/credentials';
|
|
9
10
|
import {
|
|
10
|
-
AcceptSpaceOptions,
|
|
11
11
|
DataServiceSubscriptions,
|
|
12
12
|
MetadataStore,
|
|
13
13
|
SigningContext,
|
|
@@ -17,10 +17,12 @@ import {
|
|
|
17
17
|
SpaceManager,
|
|
18
18
|
SnapshotManager
|
|
19
19
|
} from '@dxos/echo-db';
|
|
20
|
+
import { FeedStore } from '@dxos/feed-store';
|
|
20
21
|
import { Keyring } from '@dxos/keyring';
|
|
21
22
|
import { PublicKey } from '@dxos/keys';
|
|
22
23
|
import { log } from '@dxos/log';
|
|
23
24
|
import { ModelFactory } from '@dxos/model-factory';
|
|
25
|
+
import { FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
24
26
|
import { SpaceMetadata } from '@dxos/protocols/proto/dxos/echo/metadata';
|
|
25
27
|
import { Presence } from '@dxos/teleport-extension-presence';
|
|
26
28
|
import { ComplexMap, deferFunction } from '@dxos/util';
|
|
@@ -28,6 +30,13 @@ import { ComplexMap, deferFunction } from '@dxos/util';
|
|
|
28
30
|
import { createAuthProvider } from '../identity';
|
|
29
31
|
import { DataSpace } from './data-space';
|
|
30
32
|
|
|
33
|
+
const DATA_PIPELINE_READY_TIMEOUT = 3_000;
|
|
34
|
+
|
|
35
|
+
export type AcceptSpaceOptions = {
|
|
36
|
+
spaceKey: PublicKey;
|
|
37
|
+
genesisFeedKey: PublicKey;
|
|
38
|
+
};
|
|
39
|
+
|
|
31
40
|
@trackLeaks('open', 'close')
|
|
32
41
|
export class DataSpaceManager {
|
|
33
42
|
private readonly _ctx = new Context();
|
|
@@ -43,6 +52,7 @@ export class DataSpaceManager {
|
|
|
43
52
|
private readonly _keyring: Keyring,
|
|
44
53
|
private readonly _signingContext: SigningContext,
|
|
45
54
|
private readonly _modelFactory: ModelFactory,
|
|
55
|
+
private readonly _feedStore: FeedStore<FeedMessage>,
|
|
46
56
|
private readonly _snapshotStore: SnapshotStore
|
|
47
57
|
) {}
|
|
48
58
|
|
|
@@ -59,10 +69,18 @@ export class DataSpaceManager {
|
|
|
59
69
|
for (const spaceMetadata of this._metadataStore.spaces) {
|
|
60
70
|
log('load space', { spaceMetadata });
|
|
61
71
|
const space = await this._constructSpace(spaceMetadata);
|
|
62
|
-
|
|
72
|
+
await space.initializeDataPipeline();
|
|
73
|
+
if (spaceMetadata.dataTimeframe) {
|
|
63
74
|
log('waiting for latest timeframe', { spaceMetadata });
|
|
64
|
-
await space.dataPipelineController.
|
|
75
|
+
await space.dataPipelineController.pipelineState!.setTargetTimeframe(spaceMetadata.dataTimeframe);
|
|
65
76
|
}
|
|
77
|
+
await space.dataPipelineController.pipelineState!.waitUntilReachedTargetTimeframe({
|
|
78
|
+
timeout: DATA_PIPELINE_READY_TIMEOUT
|
|
79
|
+
});
|
|
80
|
+
this._dataServiceSubscriptions.registerSpace(
|
|
81
|
+
space.key,
|
|
82
|
+
space.dataPipelineController.databaseBackend!.createDataServiceHost()
|
|
83
|
+
);
|
|
66
84
|
}
|
|
67
85
|
}
|
|
68
86
|
|
|
@@ -92,9 +110,19 @@ export class DataSpaceManager {
|
|
|
92
110
|
log('creating space...', { spaceKey });
|
|
93
111
|
const space = await this._constructSpace(metadata);
|
|
94
112
|
|
|
95
|
-
await spaceGenesis(this._keyring, this._signingContext, space.inner);
|
|
113
|
+
const credentials = await spaceGenesis(this._keyring, this._signingContext, space.inner);
|
|
96
114
|
await this._metadataStore.addSpace(metadata);
|
|
97
115
|
|
|
116
|
+
const memberCredential = credentials[1];
|
|
117
|
+
assert(getCredentialAssertion(memberCredential)['@type'] === 'dxos.halo.credentials.SpaceMember');
|
|
118
|
+
await this._signingContext.recordCredential(memberCredential);
|
|
119
|
+
|
|
120
|
+
await space.initializeDataPipeline();
|
|
121
|
+
this._dataServiceSubscriptions.registerSpace(
|
|
122
|
+
space.key,
|
|
123
|
+
space.dataPipelineController.databaseBackend!.createDataServiceHost()
|
|
124
|
+
);
|
|
125
|
+
|
|
98
126
|
this.updated.emit();
|
|
99
127
|
return space;
|
|
100
128
|
}
|
|
@@ -106,13 +134,17 @@ export class DataSpaceManager {
|
|
|
106
134
|
|
|
107
135
|
const metadata: SpaceMetadata = {
|
|
108
136
|
key: opts.spaceKey,
|
|
109
|
-
genesisFeedKey: opts.genesisFeedKey
|
|
110
|
-
controlFeedKey: opts.controlFeedKey,
|
|
111
|
-
dataFeedKey: opts.dataFeedKey
|
|
137
|
+
genesisFeedKey: opts.genesisFeedKey
|
|
112
138
|
};
|
|
113
139
|
|
|
114
140
|
const space = await this._constructSpace(metadata);
|
|
115
141
|
await this._metadataStore.addSpace(metadata);
|
|
142
|
+
await space.initializeDataPipeline();
|
|
143
|
+
this._dataServiceSubscriptions.registerSpace(
|
|
144
|
+
space.key,
|
|
145
|
+
space.dataPipelineController.databaseBackend!.createDataServiceHost()
|
|
146
|
+
);
|
|
147
|
+
|
|
116
148
|
this.updated.emit();
|
|
117
149
|
return space;
|
|
118
150
|
}
|
|
@@ -126,6 +158,10 @@ export class DataSpaceManager {
|
|
|
126
158
|
});
|
|
127
159
|
const snapshotManager = new SnapshotManager(this._snapshotStore);
|
|
128
160
|
|
|
161
|
+
const controlFeed =
|
|
162
|
+
metadata.controlFeedKey && (await this._feedStore.openFeed(metadata.controlFeedKey, { writable: true }));
|
|
163
|
+
const dataFeed = metadata.dataFeedKey && (await this._feedStore.openFeed(metadata.dataFeedKey, { writable: true }));
|
|
164
|
+
|
|
129
165
|
const space: Space = await this._spaceManager.constructSpace({
|
|
130
166
|
metadata,
|
|
131
167
|
swarmIdentity: {
|
|
@@ -139,8 +175,11 @@ export class DataSpaceManager {
|
|
|
139
175
|
presence.createExtension({ remotePeerId: session.remotePeerId })
|
|
140
176
|
);
|
|
141
177
|
session.addExtension('dxos.mesh.teleport.objectsync', snapshotManager.objectSync.createExtension());
|
|
178
|
+
session.addExtension('dxos.mesh.teleport.notarization', dataSpace.notarizationPlugin.createExtension());
|
|
142
179
|
}
|
|
143
180
|
});
|
|
181
|
+
controlFeed && space.setControlFeed(controlFeed);
|
|
182
|
+
dataFeed && space.setDataFeed(dataFeed);
|
|
144
183
|
|
|
145
184
|
const dataSpace = new DataSpace({
|
|
146
185
|
inner: space,
|
|
@@ -149,11 +188,13 @@ export class DataSpaceManager {
|
|
|
149
188
|
snapshotManager,
|
|
150
189
|
presence,
|
|
151
190
|
memberKey: this._signingContext.identityKey,
|
|
191
|
+
keyring: this._keyring,
|
|
192
|
+
feedStore: this._feedStore,
|
|
193
|
+
signingContext: this._signingContext,
|
|
152
194
|
snapshotId: metadata.snapshot
|
|
153
195
|
});
|
|
154
196
|
|
|
155
197
|
await dataSpace.open();
|
|
156
|
-
this._dataServiceSubscriptions.registerSpace(space.key, dataSpace.database.createDataServiceHost());
|
|
157
198
|
this._spaces.set(metadata.key, dataSpace);
|
|
158
199
|
return dataSpace;
|
|
159
200
|
}
|