@dxos/client-services 0.1.35 → 0.1.36
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-H5IXSSI7.mjs → chunk-2AYYVPWN.mjs} +835 -950
- package/dist/lib/browser/chunk-2AYYVPWN.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +9 -11
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/packlets/testing/index.mjs +212 -74
- package/dist/lib/browser/packlets/testing/index.mjs.map +3 -3
- package/dist/lib/node/index.cjs +942 -1058
- 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 +1089 -1067
- package/dist/lib/node/packlets/testing/index.cjs.map +4 -4
- package/dist/types/src/packlets/identity/identity-manager.d.ts +1 -0
- package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity.d.ts +3 -3
- package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts +18 -0
- package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts.map +1 -0
- package/dist/types/src/packlets/invitations/device-invitation-protocol.test.d.ts +2 -0
- package/dist/types/src/packlets/invitations/device-invitation-protocol.test.d.ts.map +1 -0
- package/dist/types/src/packlets/invitations/index.d.ts +4 -4
- package/dist/types/src/packlets/invitations/index.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-protocol.d.ts +12 -0
- package/dist/types/src/packlets/invitations/invitation-protocol.d.ts.map +1 -0
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts +38 -0
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -0
- package/dist/types/src/packlets/invitations/invitations-service.d.ts +13 -15
- package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts +22 -0
- package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts.map +1 -0
- package/dist/types/src/packlets/invitations/space-invitation-protocol.test.d.ts +2 -0
- package/dist/types/src/packlets/invitations/space-invitation-protocol.test.d.ts.map +1 -0
- package/dist/types/src/packlets/services/service-context.d.ts +6 -4
- package/dist/types/src/packlets/services/service-context.d.ts.map +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 +2 -0
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/invitation-utils.d.ts +31 -2
- package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts +3 -3
- package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/packlets/tests/invitations.test.d.ts +2 -0
- package/dist/types/src/packlets/tests/invitations.test.d.ts.map +1 -0
- package/dist/types/src/packlets/vault/worker-runtime.d.ts +2 -0
- package/dist/types/src/packlets/vault/worker-runtime.d.ts.map +1 -1
- package/package.json +30 -30
- package/src/packlets/identity/identity-manager.ts +2 -1
- package/src/packlets/identity/identity.ts +3 -3
- package/src/packlets/invitations/{device-invitations-handler.test.ts → device-invitation-protocol.test.ts} +3 -3
- package/src/packlets/invitations/device-invitation-protocol.ts +83 -0
- package/src/packlets/invitations/index.ts +4 -4
- package/src/packlets/invitations/invitation-protocol.ts +21 -0
- package/src/packlets/invitations/invitations-handler.ts +462 -0
- package/src/packlets/invitations/invitations-service.ts +127 -104
- package/src/packlets/invitations/space-invitation-protocol.test.ts +221 -0
- package/src/packlets/invitations/space-invitation-protocol.ts +117 -0
- package/src/packlets/services/service-context.test.ts +11 -4
- package/src/packlets/services/service-context.ts +40 -19
- package/src/packlets/services/service-host.ts +4 -12
- package/src/packlets/services/service-registry.test.ts +23 -25
- package/src/packlets/spaces/data-space-manager.ts +5 -0
- package/src/packlets/spaces/spaces-service.ts +7 -2
- package/src/packlets/storage/storage.ts +2 -0
- package/src/packlets/testing/invitation-utils.ts +219 -31
- package/src/packlets/testing/test-builder.ts +33 -22
- package/src/packlets/tests/client-services.test.ts +33 -76
- package/src/packlets/tests/halo-profile.test.ts +2 -28
- package/src/packlets/tests/invitations.test.ts +389 -0
- package/src/packlets/tests/spaces-invitations.test.ts +12 -30
- package/src/packlets/tests/spaces.test.ts +30 -28
- package/src/packlets/vault/worker-runtime.ts +4 -0
- package/dist/lib/browser/chunk-H5IXSSI7.mjs.map +0 -7
- package/dist/types/src/packlets/invitations/device-invitations-handler.d.ts +0 -30
- package/dist/types/src/packlets/invitations/device-invitations-handler.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/device-invitations-handler.test.d.ts +0 -2
- package/dist/types/src/packlets/invitations/device-invitations-handler.test.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/device-invitations-service.d.ts +0 -13
- package/dist/types/src/packlets/invitations/device-invitations-service.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/device-invitations-service.test.d.ts +0 -2
- package/dist/types/src/packlets/invitations/device-invitations-service.test.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/space-invitations-handler.d.ts +0 -26
- package/dist/types/src/packlets/invitations/space-invitations-handler.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/space-invitations-handler.test.d.ts +0 -2
- package/dist/types/src/packlets/invitations/space-invitations-handler.test.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/space-invitations-service.d.ts +0 -16
- package/dist/types/src/packlets/invitations/space-invitations-service.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/space-invitations-service.test.d.ts +0 -2
- package/dist/types/src/packlets/invitations/space-invitations-service.test.d.ts.map +0 -1
- package/src/packlets/invitations/device-invitations-handler.ts +0 -370
- package/src/packlets/invitations/device-invitations-service.test.ts +0 -96
- package/src/packlets/invitations/device-invitations-service.ts +0 -24
- package/src/packlets/invitations/space-invitations-handler.test.ts +0 -246
- package/src/packlets/invitations/space-invitations-handler.ts +0 -463
- package/src/packlets/invitations/space-invitations-service.test.ts +0 -129
- package/src/packlets/invitations/space-invitations-service.ts +0 -35
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import assert from 'node:assert';
|
|
6
|
+
|
|
5
7
|
import { Trigger } from '@dxos/async';
|
|
8
|
+
import { Invitation } from '@dxos/client';
|
|
6
9
|
import { CredentialConsumer, getCredentialAssertion } from '@dxos/credentials';
|
|
7
10
|
import { failUndefined } from '@dxos/debug';
|
|
8
11
|
import {
|
|
@@ -25,7 +28,12 @@ import { Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
|
25
28
|
import { Storage } from '@dxos/random-access-storage';
|
|
26
29
|
|
|
27
30
|
import { CreateIdentityOptions, IdentityManager, JoinIdentityParams } from '../identity';
|
|
28
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
DeviceInvitationProtocol,
|
|
33
|
+
InvitationsHandler,
|
|
34
|
+
InvitationProtocol,
|
|
35
|
+
SpaceInvitationProtocol
|
|
36
|
+
} from '../invitations';
|
|
29
37
|
import { DataSpaceManager } from '../spaces';
|
|
30
38
|
|
|
31
39
|
/**
|
|
@@ -41,13 +49,17 @@ export class ServiceContext {
|
|
|
41
49
|
public readonly keyring: Keyring;
|
|
42
50
|
public readonly spaceManager: SpaceManager;
|
|
43
51
|
public readonly identityManager: IdentityManager;
|
|
44
|
-
public readonly
|
|
45
|
-
|
|
46
|
-
private _deviceSpaceSync?: CredentialConsumer<any>;
|
|
52
|
+
public readonly invitations: InvitationsHandler;
|
|
47
53
|
|
|
48
54
|
// Initialized after identity is initialized.
|
|
49
55
|
public dataSpaceManager?: DataSpaceManager;
|
|
50
|
-
|
|
56
|
+
|
|
57
|
+
private readonly _handlerFactories = new Map<
|
|
58
|
+
Invitation.Kind,
|
|
59
|
+
(invitation: Partial<Invitation>) => InvitationProtocol
|
|
60
|
+
>();
|
|
61
|
+
|
|
62
|
+
private _deviceSpaceSync?: CredentialConsumer<any>;
|
|
51
63
|
|
|
52
64
|
private readonly _instanceId = PublicKey.random().toHex();
|
|
53
65
|
|
|
@@ -57,6 +69,7 @@ export class ServiceContext {
|
|
|
57
69
|
public readonly networkManager: NetworkManager,
|
|
58
70
|
public readonly modelFactory: ModelFactory
|
|
59
71
|
) {
|
|
72
|
+
networkManager._traceParent = this._instanceId;
|
|
60
73
|
// TODO(burdon): Move strings to constants.
|
|
61
74
|
this.metadataStore = new MetadataStore(storage.createDirectory('metadata'));
|
|
62
75
|
this.snapshotStore = new SnapshotStore(storage.createDirectory('snapshots'));
|
|
@@ -76,6 +89,7 @@ export class ServiceContext {
|
|
|
76
89
|
feedStore: this.feedStore,
|
|
77
90
|
networkManager: this.networkManager
|
|
78
91
|
});
|
|
92
|
+
this.spaceManager._traceParent = this._instanceId;
|
|
79
93
|
|
|
80
94
|
this.identityManager = new IdentityManager(
|
|
81
95
|
this.metadataStore,
|
|
@@ -83,19 +97,21 @@ export class ServiceContext {
|
|
|
83
97
|
this.feedStore,
|
|
84
98
|
this.spaceManager
|
|
85
99
|
);
|
|
100
|
+
this.identityManager._traceParent = this._instanceId;
|
|
101
|
+
|
|
102
|
+
this.invitations = new InvitationsHandler(this.networkManager);
|
|
86
103
|
|
|
87
104
|
// TODO(burdon): _initialize called in multiple places.
|
|
88
105
|
// TODO(burdon): Call _initialize on success.
|
|
89
|
-
this.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
});
|
|
106
|
+
this._handlerFactories.set(Invitation.Kind.DEVICE, () => new DeviceInvitationProtocol(
|
|
107
|
+
this.keyring,
|
|
108
|
+
() => this.identityManager.identity ?? failUndefined(),
|
|
109
|
+
this._acceptIdentity.bind(this)
|
|
110
|
+
));
|
|
95
111
|
}
|
|
96
112
|
|
|
97
113
|
async open() {
|
|
98
|
-
log.trace('dxos.sdk.
|
|
114
|
+
log.trace('dxos.sdk.service-context', trace.begin({ id: this._instanceId }));
|
|
99
115
|
|
|
100
116
|
log('opening...');
|
|
101
117
|
await this.networkManager.open();
|
|
@@ -118,7 +134,7 @@ export class ServiceContext {
|
|
|
118
134
|
this.dataServiceSubscriptions.clear();
|
|
119
135
|
log('closed');
|
|
120
136
|
|
|
121
|
-
log.trace('dxos.sdk.
|
|
137
|
+
log.trace('dxos.sdk.service-context', trace.end({ id: this._instanceId }));
|
|
122
138
|
}
|
|
123
139
|
|
|
124
140
|
async reset() {
|
|
@@ -135,6 +151,12 @@ export class ServiceContext {
|
|
|
135
151
|
return identity;
|
|
136
152
|
}
|
|
137
153
|
|
|
154
|
+
getInvitationHandler(invitation: Partial<Invitation> & Pick<Invitation, 'kind'>): InvitationProtocol {
|
|
155
|
+
const factory = this._handlerFactories.get(invitation.kind);
|
|
156
|
+
assert(factory, `Unknown invitation kind: ${invitation.kind}`);
|
|
157
|
+
return factory(invitation);
|
|
158
|
+
}
|
|
159
|
+
|
|
138
160
|
private async _acceptIdentity(params: JoinIdentityParams) {
|
|
139
161
|
const identity = await this.identityManager.acceptIdentity(params);
|
|
140
162
|
|
|
@@ -166,14 +188,13 @@ export class ServiceContext {
|
|
|
166
188
|
this.feedStore,
|
|
167
189
|
this.snapshotStore
|
|
168
190
|
);
|
|
191
|
+
this.dataSpaceManager._traceParent = this._instanceId;
|
|
169
192
|
await this.dataSpaceManager.open();
|
|
170
193
|
|
|
171
|
-
this.
|
|
172
|
-
this.
|
|
173
|
-
this.dataSpaceManager,
|
|
174
|
-
|
|
175
|
-
this.keyring
|
|
176
|
-
);
|
|
194
|
+
this._handlerFactories.set(Invitation.Kind.SPACE, (invitation) => {
|
|
195
|
+
assert(this.dataSpaceManager, 'dataSpaceManager not initialized yet');
|
|
196
|
+
return new SpaceInvitationProtocol(this.dataSpaceManager, signingContext, this.keyring, invitation.spaceKey);
|
|
197
|
+
});
|
|
177
198
|
this.initialized.wake();
|
|
178
199
|
|
|
179
200
|
this._deviceSpaceSync = identity.space.spaceState.registerProcessor({
|
|
@@ -7,7 +7,6 @@ import assert from 'node:assert';
|
|
|
7
7
|
import { Event } from '@dxos/async';
|
|
8
8
|
import { clientServiceBundle, ClientServices, createDefaultModelFactory, PublicKey } from '@dxos/client';
|
|
9
9
|
import { Config } from '@dxos/config';
|
|
10
|
-
import { raise } from '@dxos/debug';
|
|
11
10
|
import { DataServiceImpl } from '@dxos/echo-pipeline';
|
|
12
11
|
import { log } from '@dxos/log';
|
|
13
12
|
import { ModelFactory } from '@dxos/model-factory';
|
|
@@ -20,7 +19,7 @@ import { TracingServiceImpl } from '../deprecated';
|
|
|
20
19
|
import { DevicesServiceImpl } from '../devices';
|
|
21
20
|
import { DevtoolsServiceImpl, DevtoolsHostEvents } from '../devtools';
|
|
22
21
|
import { IdentityServiceImpl } from '../identity';
|
|
23
|
-
import {
|
|
22
|
+
import { InvitationsServiceImpl } from '../invitations';
|
|
24
23
|
import { NetworkServiceImpl } from '../network';
|
|
25
24
|
import { SpacesServiceImpl } from '../spaces';
|
|
26
25
|
import { createStorageObjects } from '../storage';
|
|
@@ -185,18 +184,11 @@ export class ClientServicesHost {
|
|
|
185
184
|
|
|
186
185
|
IdentityService: new IdentityServiceImpl(this._serviceContext),
|
|
187
186
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
DeviceInvitationsService: new DeviceInvitationsServiceImpl(
|
|
191
|
-
this._serviceContext.identityManager,
|
|
192
|
-
this._serviceContext.deviceInvitations
|
|
187
|
+
InvitationsService: new InvitationsServiceImpl(this._serviceContext.invitations, (invitation) =>
|
|
188
|
+
this._serviceContext.getInvitationHandler(invitation)
|
|
193
189
|
),
|
|
194
190
|
|
|
195
|
-
|
|
196
|
-
this._serviceContext.identityManager,
|
|
197
|
-
() => this._serviceContext.spaceInvitations ?? raise(new Error('SpaceInvitations not initialized')),
|
|
198
|
-
() => this._serviceContext.dataSpaceManager ?? raise(new Error('SpaceManager not initialized'))
|
|
199
|
-
),
|
|
191
|
+
DevicesService: new DevicesServiceImpl(this._serviceContext.identityManager),
|
|
200
192
|
|
|
201
193
|
SpacesService: new SpacesServiceImpl(
|
|
202
194
|
this._serviceContext.identityManager,
|
|
@@ -5,25 +5,25 @@
|
|
|
5
5
|
import assert from 'node:assert';
|
|
6
6
|
|
|
7
7
|
import { Trigger } from '@dxos/async';
|
|
8
|
-
import { ClientServices,
|
|
8
|
+
import { ClientServices, InvitationsProxy } from '@dxos/client';
|
|
9
9
|
import { log } from '@dxos/log';
|
|
10
10
|
import { schema } from '@dxos/protocols';
|
|
11
|
-
import { Invitation,
|
|
11
|
+
import { Invitation, InvitationsService } from '@dxos/protocols/proto/dxos/client/services';
|
|
12
12
|
import { createLinkedPorts, createProtoRpcPeer, createServiceBundle } from '@dxos/rpc';
|
|
13
13
|
import { describe, test } from '@dxos/test';
|
|
14
14
|
|
|
15
|
-
import {
|
|
15
|
+
import { InvitationsServiceImpl } from '../invitations';
|
|
16
16
|
import { createServiceContext } from '../testing';
|
|
17
17
|
import { ServiceRegistry } from './service-registry';
|
|
18
18
|
|
|
19
19
|
// TODO(burdon): Create TestService (that doesn't require peers).
|
|
20
20
|
|
|
21
21
|
type TestServices = {
|
|
22
|
-
|
|
22
|
+
InvitationsService: InvitationsService;
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
const serviceBundle = createServiceBundle<TestServices>({
|
|
26
|
-
|
|
26
|
+
InvitationsService: schema.getService('dxos.client.services.InvitationsService')
|
|
27
27
|
});
|
|
28
28
|
|
|
29
29
|
describe('service registry', () => {
|
|
@@ -33,14 +33,11 @@ describe('service registry', () => {
|
|
|
33
33
|
await serviceContext.createIdentity();
|
|
34
34
|
|
|
35
35
|
assert(serviceContext.dataSpaceManager);
|
|
36
|
-
assert(serviceContext.spaceInvitations);
|
|
37
36
|
const space = await serviceContext.dataSpaceManager.createSpace();
|
|
38
37
|
|
|
39
38
|
const serviceRegistry = new ServiceRegistry(serviceBundle, {
|
|
40
|
-
|
|
41
|
-
serviceContext.
|
|
42
|
-
() => serviceContext.spaceInvitations!,
|
|
43
|
-
() => serviceContext.dataSpaceManager!
|
|
39
|
+
InvitationsService: new InvitationsServiceImpl(serviceContext.invitations, (invitation) =>
|
|
40
|
+
serviceContext.getInvitationHandler(invitation)
|
|
44
41
|
)
|
|
45
42
|
});
|
|
46
43
|
|
|
@@ -66,21 +63,22 @@ describe('service registry', () => {
|
|
|
66
63
|
const done = new Trigger(); // createRpcServer
|
|
67
64
|
|
|
68
65
|
{
|
|
69
|
-
const spaceInvitationsProxy = new
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
66
|
+
const spaceInvitationsProxy = new InvitationsProxy(proxy.rpc.InvitationsService, () => ({
|
|
67
|
+
kind: Invitation.Kind.SPACE,
|
|
68
|
+
spaceKey: space.key
|
|
69
|
+
}));
|
|
70
|
+
const observer = spaceInvitationsProxy.createInvitation();
|
|
71
|
+
observer.subscribe((invitation: Invitation) => {
|
|
72
|
+
switch (invitation.state) {
|
|
73
|
+
case Invitation.State.CONNECTING: {
|
|
74
|
+
log('connecting', invitation);
|
|
75
|
+
void observer.cancel();
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
case Invitation.State.CANCELLED: {
|
|
80
|
+
done.wake();
|
|
81
|
+
}
|
|
84
82
|
}
|
|
85
83
|
});
|
|
86
84
|
}
|
|
@@ -23,6 +23,7 @@ import { Keyring } from '@dxos/keyring';
|
|
|
23
23
|
import { PublicKey } from '@dxos/keys';
|
|
24
24
|
import { log } from '@dxos/log';
|
|
25
25
|
import { ModelFactory } from '@dxos/model-factory';
|
|
26
|
+
import { trace } from '@dxos/protocols';
|
|
26
27
|
import { FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
27
28
|
import { SpaceMetadata } from '@dxos/protocols/proto/dxos/echo/metadata';
|
|
28
29
|
import { Gossip, Presence } from '@dxos/teleport-extension-gossip';
|
|
@@ -58,6 +59,8 @@ export class DataSpaceManager {
|
|
|
58
59
|
private readonly _spaces = new ComplexMap<PublicKey, DataSpace>(PublicKey.hash);
|
|
59
60
|
|
|
60
61
|
private _isOpen = false;
|
|
62
|
+
private readonly _instanceId = PublicKey.random().toHex();
|
|
63
|
+
public _traceParent?: string;
|
|
61
64
|
|
|
62
65
|
constructor(
|
|
63
66
|
private readonly _spaceManager: SpaceManager,
|
|
@@ -78,6 +81,7 @@ export class DataSpaceManager {
|
|
|
78
81
|
@synchronized
|
|
79
82
|
async open() {
|
|
80
83
|
log('open');
|
|
84
|
+
log.trace('dxos.echo.data-space-manager', trace.begin({ id: this._instanceId, parentId: this._traceParent }));
|
|
81
85
|
await this._metadataStore.load();
|
|
82
86
|
log('metadata loaded', { spaces: this._metadataStore.spaces.length });
|
|
83
87
|
|
|
@@ -99,6 +103,7 @@ export class DataSpaceManager {
|
|
|
99
103
|
for (const space of this._spaces.values()) {
|
|
100
104
|
await space.close();
|
|
101
105
|
}
|
|
106
|
+
log.trace('dxos.echo.data-space-manager', trace.end({ id: this._instanceId }));
|
|
102
107
|
}
|
|
103
108
|
|
|
104
109
|
/**
|
|
@@ -149,10 +149,15 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
149
149
|
spaceKey: space.key,
|
|
150
150
|
state: space.state,
|
|
151
151
|
pipeline: {
|
|
152
|
-
|
|
152
|
+
controlFeeds: space.inner.controlPipeline.state.feeds.map((feed) => feed.key),
|
|
153
153
|
currentControlTimeframe: space.inner.controlPipeline.state.timeframe,
|
|
154
|
+
targetControlTimeframe: space.inner.controlPipeline.state.targetTimeframe,
|
|
155
|
+
totalControlTimeframe: space.inner.controlPipeline.state.endTimeframe,
|
|
156
|
+
|
|
157
|
+
dataFeeds: space.dataPipeline.pipelineState?.feeds.map((feed) => feed.key) ?? [],
|
|
154
158
|
currentDataTimeframe: space.dataPipeline.pipelineState?.timeframe,
|
|
155
|
-
targetDataTimeframe: space.dataPipeline.pipelineState?.targetTimeframe
|
|
159
|
+
targetDataTimeframe: space.dataPipeline.pipelineState?.targetTimeframe,
|
|
160
|
+
totalDataTimeframe: space.dataPipeline.pipelineState?.endTimeframe
|
|
156
161
|
},
|
|
157
162
|
members: Array.from(space.inner.spaceState.members.values()).map((member) => ({
|
|
158
163
|
identity: {
|
|
@@ -54,6 +54,8 @@ const toStorageType = (type: StorageDriver | undefined): StorageType | undefined
|
|
|
54
54
|
return StorageType.IDB;
|
|
55
55
|
case StorageDriver.NODE:
|
|
56
56
|
return StorageType.NODE;
|
|
57
|
+
case StorageDriver.WEBFS:
|
|
58
|
+
return StorageType.WEBFS;
|
|
57
59
|
default:
|
|
58
60
|
throw new Error(`Invalid storage type: ${StorageDriver[type]}`);
|
|
59
61
|
}
|
|
@@ -5,39 +5,227 @@
|
|
|
5
5
|
import assert from 'node:assert';
|
|
6
6
|
|
|
7
7
|
import { Trigger } from '@dxos/async';
|
|
8
|
-
import {
|
|
9
|
-
|
|
8
|
+
import {
|
|
9
|
+
AuthenticatingInvitationObservable,
|
|
10
|
+
CancellableInvitationObservable,
|
|
11
|
+
Client,
|
|
12
|
+
EchoProxy,
|
|
13
|
+
HaloProxy,
|
|
14
|
+
InvitationsProxy,
|
|
15
|
+
SpaceProxy
|
|
16
|
+
} from '@dxos/client';
|
|
10
17
|
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
11
18
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
19
|
+
import { ServiceContext } from '../services';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Strip secrets from invitation before giving it to the peer.
|
|
23
|
+
*/
|
|
24
|
+
export const sanitizeInvitation = (invitation: Invitation): Invitation => {
|
|
25
|
+
return {
|
|
26
|
+
invitationId: invitation.invitationId,
|
|
27
|
+
type: invitation.type,
|
|
28
|
+
kind: invitation.kind,
|
|
29
|
+
authMethod: invitation.authMethod,
|
|
30
|
+
swarmKey: invitation.swarmKey,
|
|
31
|
+
state: invitation.state,
|
|
32
|
+
timeout: invitation.timeout
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type PerformInvitationCallbacks<T> = {
|
|
37
|
+
onConnecting?: (value: T) => boolean | void;
|
|
38
|
+
onConnected?: (value: T) => boolean | void;
|
|
39
|
+
onReady?: (value: T) => boolean | void;
|
|
40
|
+
onAuthenticating?: (value: T) => boolean | void;
|
|
41
|
+
onSuccess?: (value: T) => boolean | void;
|
|
42
|
+
onCancelled?: (value: T) => boolean | void;
|
|
43
|
+
onTimeout?: (value: T) => boolean | void;
|
|
44
|
+
onError?: (value: T) => boolean | void;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type PerformInvitationParams = {
|
|
48
|
+
host: ServiceContext | InvitationsProxy | HaloProxy | SpaceProxy;
|
|
49
|
+
guest: ServiceContext | InvitationsProxy | HaloProxy | EchoProxy | Client;
|
|
50
|
+
options?: Partial<Invitation>;
|
|
51
|
+
hooks?: {
|
|
52
|
+
host?: PerformInvitationCallbacks<CancellableInvitationObservable>;
|
|
53
|
+
guest?: PerformInvitationCallbacks<AuthenticatingInvitationObservable>;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export type Result = { invitation?: Invitation; error?: Error };
|
|
58
|
+
|
|
59
|
+
export const performInvitation = ({
|
|
60
|
+
host,
|
|
61
|
+
guest,
|
|
62
|
+
options,
|
|
63
|
+
hooks
|
|
64
|
+
}: PerformInvitationParams): [Promise<Result>, Promise<Result>] => {
|
|
65
|
+
const hostComplete = new Trigger<Result>();
|
|
66
|
+
const guestComplete = new Trigger<Result>();
|
|
67
|
+
const authCode = new Trigger<string>();
|
|
68
|
+
|
|
69
|
+
const hostObservable = createInvitation(host, options);
|
|
70
|
+
hostObservable.subscribe(
|
|
71
|
+
async (hostInvitation: Invitation) => {
|
|
72
|
+
switch (hostInvitation.state) {
|
|
73
|
+
case Invitation.State.CONNECTING: {
|
|
74
|
+
if (hooks?.host?.onConnecting?.(hostObservable)) {
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
const guestObservable = acceptInvitation(guest, hostInvitation);
|
|
78
|
+
guestObservable.subscribe(
|
|
79
|
+
async (guestInvitation: Invitation) => {
|
|
80
|
+
switch (guestInvitation.state) {
|
|
81
|
+
case Invitation.State.CONNECTING: {
|
|
82
|
+
if (hooks?.guest?.onConnecting?.(guestObservable)) {
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
assert(hostInvitation.swarmKey!.equals(guestInvitation.swarmKey!));
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
case Invitation.State.CONNECTED: {
|
|
90
|
+
hooks?.guest?.onConnected?.(guestObservable);
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
case Invitation.State.READY_FOR_AUTHENTICATION: {
|
|
95
|
+
if (hooks?.guest?.onReady?.(guestObservable)) {
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
await guestObservable.authenticate(await authCode.wait());
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
case Invitation.State.AUTHENTICATING: {
|
|
103
|
+
hooks?.guest?.onAuthenticating?.(guestObservable);
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
case Invitation.State.SUCCESS: {
|
|
108
|
+
if (hooks?.guest?.onSuccess?.(guestObservable)) {
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
guestComplete.wake({ invitation: guestInvitation });
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
case Invitation.State.CANCELLED: {
|
|
116
|
+
if (hooks?.guest?.onCancelled?.(guestObservable)) {
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
guestComplete.wake({ invitation: guestInvitation });
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
case Invitation.State.TIMEOUT: {
|
|
124
|
+
if (hooks?.guest?.onTimeout?.(guestObservable)) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
guestComplete.wake({ invitation: guestInvitation });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
(error: Error) => {
|
|
132
|
+
if (hooks?.guest?.onError?.(guestObservable)) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
guestComplete.wake({ error });
|
|
136
|
+
}
|
|
137
|
+
);
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
case Invitation.State.CONNECTED: {
|
|
142
|
+
hooks?.host?.onConnected?.(hostObservable);
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
case Invitation.State.READY_FOR_AUTHENTICATION: {
|
|
147
|
+
if (hooks?.host?.onReady?.(hostObservable)) {
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
if (hostInvitation.authCode) {
|
|
151
|
+
authCode.wake(hostInvitation.authCode);
|
|
152
|
+
}
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
case Invitation.State.AUTHENTICATING: {
|
|
157
|
+
hooks?.host?.onAuthenticating?.(hostObservable);
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
case Invitation.State.SUCCESS: {
|
|
162
|
+
if (hooks?.host?.onSuccess?.(hostObservable)) {
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
hostComplete.wake({ invitation: hostInvitation });
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
case Invitation.State.CANCELLED: {
|
|
170
|
+
if (hooks?.host?.onCancelled?.(hostObservable)) {
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
hostComplete.wake({ invitation: hostInvitation });
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
case Invitation.State.TIMEOUT: {
|
|
178
|
+
if (hooks?.host?.onTimeout?.(hostObservable)) {
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
hostComplete.wake({ invitation: hostInvitation });
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
36
185
|
},
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
186
|
+
(error: Error) => {
|
|
187
|
+
if (hooks?.host?.onError?.(hostObservable)) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
hostComplete.wake({ error });
|
|
191
|
+
}
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
return [hostComplete.wait(), guestComplete.wait()];
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const createInvitation = (
|
|
198
|
+
host: ServiceContext | InvitationsProxy | HaloProxy | SpaceProxy,
|
|
199
|
+
options?: Partial<Invitation>
|
|
200
|
+
): CancellableInvitationObservable => {
|
|
201
|
+
options ??= {
|
|
202
|
+
authMethod: Invitation.AuthMethod.NONE,
|
|
203
|
+
...(options ?? {})
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
if (host instanceof InvitationsProxy || host instanceof HaloProxy || host instanceof SpaceProxy) {
|
|
207
|
+
return host.createInvitation(options);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const hostHandler = host.getInvitationHandler({ kind: Invitation.Kind.SPACE, ...options });
|
|
211
|
+
return host.invitations.createInvitation(hostHandler, options);
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const acceptInvitation = (
|
|
215
|
+
guest: ServiceContext | InvitationsProxy | HaloProxy | EchoProxy | Client,
|
|
216
|
+
invitation: Invitation
|
|
217
|
+
): AuthenticatingInvitationObservable => {
|
|
218
|
+
invitation = sanitizeInvitation(invitation);
|
|
219
|
+
|
|
220
|
+
if (
|
|
221
|
+
guest instanceof InvitationsProxy ||
|
|
222
|
+
guest instanceof HaloProxy ||
|
|
223
|
+
guest instanceof EchoProxy ||
|
|
224
|
+
guest instanceof Client
|
|
225
|
+
) {
|
|
226
|
+
return guest.acceptInvitation(invitation);
|
|
227
|
+
}
|
|
40
228
|
|
|
41
|
-
|
|
42
|
-
|
|
229
|
+
const guestHandler = guest.getInvitationHandler({ kind: invitation.kind });
|
|
230
|
+
return guest.invitations.acceptInvitation(guestHandler, invitation);
|
|
43
231
|
};
|
|
@@ -9,7 +9,7 @@ import { Client, ClientServices, ClientServicesProxy, createDefaultModelFactory,
|
|
|
9
9
|
import { Config } from '@dxos/config';
|
|
10
10
|
import { raise } from '@dxos/debug';
|
|
11
11
|
import { DocumentModel } from '@dxos/document-model';
|
|
12
|
-
import {
|
|
12
|
+
import { DatabaseProxy, genesisMutation } from '@dxos/echo-db';
|
|
13
13
|
import { PublicKey } from '@dxos/keys';
|
|
14
14
|
import { log } from '@dxos/log';
|
|
15
15
|
import { MemorySignalManager, MemorySignalManagerContext, WebsocketSignalManager } from '@dxos/messaging';
|
|
@@ -116,7 +116,7 @@ export class TestBuilder {
|
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
export const testSpace = async (create:
|
|
119
|
+
export const testSpace = async (create: DatabaseProxy, check: DatabaseProxy = create) => {
|
|
120
120
|
const objectId = PublicKey.random().toHex();
|
|
121
121
|
|
|
122
122
|
const result = create.mutate(genesisMutation(objectId, DocumentModel.meta.type));
|
|
@@ -133,7 +133,7 @@ export const testSpace = async (create: DatabaseBackendProxy, check: DatabaseBac
|
|
|
133
133
|
return result;
|
|
134
134
|
};
|
|
135
135
|
|
|
136
|
-
export const syncItems = async (db1:
|
|
136
|
+
export const syncItems = async (db1: DatabaseProxy, db2: DatabaseProxy) => {
|
|
137
137
|
// Check item replicated from 1 => 2.
|
|
138
138
|
await testSpace(db1, db2);
|
|
139
139
|
|
|
@@ -150,27 +150,38 @@ export const joinCommonSpace = async ([initialPeer, ...peers]: Client[], spaceKe
|
|
|
150
150
|
const hostDone = new Trigger<Invitation>();
|
|
151
151
|
const guestDone = new Trigger<Invitation>();
|
|
152
152
|
|
|
153
|
-
const
|
|
153
|
+
const hostObservable = rootSpace.createInvitation({ authMethod: Invitation.AuthMethod.NONE });
|
|
154
154
|
log('invitation created');
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
155
|
+
hostObservable.subscribe(
|
|
156
|
+
(hostInvitation) => {
|
|
157
|
+
switch (hostInvitation.state) {
|
|
158
|
+
case Invitation.State.CONNECTING: {
|
|
159
|
+
const guestObservable = peer.acceptInvitation(hostInvitation);
|
|
160
|
+
log('invitation accepted');
|
|
161
|
+
|
|
162
|
+
guestObservable.subscribe(
|
|
163
|
+
(guestInvitation) => {
|
|
164
|
+
switch (guestInvitation.state) {
|
|
165
|
+
case Invitation.State.SUCCESS: {
|
|
166
|
+
guestDone.wake(guestInvitation);
|
|
167
|
+
log('invitation guestDone');
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
(err) => raise(err)
|
|
173
|
+
);
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
case Invitation.State.SUCCESS: {
|
|
178
|
+
hostDone.wake(hostInvitation);
|
|
179
|
+
log('invitation hostDone');
|
|
180
|
+
}
|
|
181
|
+
}
|
|
167
182
|
},
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
log('invitation hostDone');
|
|
171
|
-
},
|
|
172
|
-
onError: (err) => raise(err)
|
|
173
|
-
});
|
|
183
|
+
(err) => raise(err)
|
|
184
|
+
);
|
|
174
185
|
|
|
175
186
|
await Promise.all([hostDone.wait(), guestDone.wait()]);
|
|
176
187
|
})
|