@dxos/client-services 0.6.11 → 0.6.12-main.568932b
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-QYVLLBAA.mjs → chunk-AHZ7ASHC.mjs} +5619 -5143
- package/dist/lib/browser/chunk-AHZ7ASHC.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +3 -3
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +5 -6
- package/dist/lib/browser/testing/index.mjs.map +2 -2
- package/dist/lib/node/{chunk-F7G2TXVG.cjs → chunk-YJWFC43Y.cjs} +5391 -4915
- package/dist/lib/node/chunk-YJWFC43Y.cjs.map +7 -0
- package/dist/lib/node/index.cjs +46 -46
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +11 -12
- package/dist/lib/node/testing/index.cjs.map +2 -2
- package/dist/lib/node-esm/chunk-7ADUGZEP.mjs +8192 -0
- package/dist/lib/node-esm/chunk-7ADUGZEP.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +416 -0
- package/dist/lib/node-esm/index.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -0
- package/dist/lib/node-esm/testing/index.mjs +418 -0
- package/dist/lib/node-esm/testing/index.mjs.map +7 -0
- package/dist/types/src/packlets/diagnostics/diagnostics-broadcast.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/authenticator.node.test.d.ts +2 -0
- package/dist/types/src/packlets/identity/authenticator.node.test.d.ts.map +1 -0
- package/dist/types/src/packlets/identity/contacts-service.d.ts +1 -1
- package/dist/types/src/packlets/identity/contacts-service.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-manager.d.ts +19 -7
- package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity.d.ts +8 -1
- package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-host-extension.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts +7 -6
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +1 -0
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts +6 -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 +4 -3
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts +3 -0
- package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/edge-feed-replicator.test.d.ts +2 -0
- package/dist/types/src/packlets/spaces/edge-feed-replicator.test.d.ts.map +1 -0
- package/dist/types/src/packlets/spaces/epoch-migrations.d.ts +1 -1
- package/dist/types/src/packlets/spaces/epoch-migrations.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +31 -6
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
- package/dist/types/src/packlets/storage/storage.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts +1 -2
- package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -1
- package/dist/types/src/testing/setup.d.ts +3 -0
- package/dist/types/src/testing/setup.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 +43 -39
- package/src/packlets/devices/devices-service.test.ts +4 -5
- package/src/packlets/diagnostics/diagnostics-broadcast.ts +1 -0
- package/src/packlets/identity/{authenticator.test.ts → authenticator.node.test.ts} +2 -3
- package/src/packlets/identity/authenticator.ts +5 -2
- package/src/packlets/identity/contacts-service.ts +1 -1
- package/src/packlets/identity/identity-manager.test.ts +5 -6
- package/src/packlets/identity/identity-manager.ts +35 -19
- package/src/packlets/identity/identity-service.test.ts +4 -8
- package/src/packlets/identity/identity.test.ts +128 -239
- package/src/packlets/identity/identity.ts +42 -8
- package/src/packlets/invitations/device-invitation-protocol.test.ts +7 -4
- package/src/packlets/invitations/invitation-host-extension.ts +0 -3
- package/src/packlets/invitations/invitations-handler.test.ts +14 -7
- package/src/packlets/invitations/invitations-handler.ts +1 -1
- package/src/packlets/invitations/space-invitation-protocol.test.ts +4 -3
- package/src/packlets/logging/logging.test.ts +1 -2
- package/src/packlets/network/network-service.test.ts +2 -3
- package/src/packlets/services/service-context.test.ts +3 -1
- package/src/packlets/services/service-context.ts +64 -28
- package/src/packlets/services/service-host.test.ts +8 -12
- package/src/packlets/services/service-host.ts +8 -6
- package/src/packlets/services/service-registry.test.ts +1 -2
- package/src/packlets/spaces/data-space-manager.test.ts +2 -2
- package/src/packlets/spaces/data-space-manager.ts +38 -5
- package/src/packlets/spaces/data-space.ts +34 -6
- package/src/packlets/spaces/edge-feed-replicator.test.ts +251 -0
- package/src/packlets/spaces/edge-feed-replicator.ts +80 -22
- package/src/packlets/spaces/epoch-migrations.ts +2 -2
- package/src/packlets/spaces/notarization-plugin.test.ts +10 -7
- package/src/packlets/spaces/notarization-plugin.ts +169 -29
- package/src/packlets/spaces/spaces-service.test.ts +5 -9
- package/src/packlets/spaces/spaces-service.ts +6 -1
- package/src/packlets/storage/storage.ts +0 -1
- package/src/packlets/system/system-service.test.ts +1 -2
- package/src/packlets/testing/test-builder.ts +2 -3
- package/src/packlets/worker/worker-runtime.ts +2 -2
- package/src/testing/setup.ts +11 -0
- package/src/version.ts +1 -5
- package/dist/lib/browser/chunk-QYVLLBAA.mjs.map +0 -7
- package/dist/lib/node/chunk-F7G2TXVG.cjs.map +0 -7
- package/dist/types/src/packlets/identity/authenticator.test.d.ts +0 -2
- package/dist/types/src/packlets/identity/authenticator.test.d.ts.map +0 -1
- package/dist/types/src/packlets/services/automerge-host.test.d.ts +0 -2
- package/dist/types/src/packlets/services/automerge-host.test.d.ts.map +0 -1
- package/src/packlets/services/automerge-host.test.ts +0 -60
|
@@ -14,10 +14,12 @@ import {
|
|
|
14
14
|
} from '@dxos/credentials';
|
|
15
15
|
import { type Signer } from '@dxos/crypto';
|
|
16
16
|
import { type Space } from '@dxos/echo-pipeline';
|
|
17
|
-
import {
|
|
17
|
+
import { type EdgeConnection } from '@dxos/edge-client';
|
|
18
|
+
import { writeMessages, type FeedWrapper } from '@dxos/feed-store';
|
|
18
19
|
import { invariant } from '@dxos/invariant';
|
|
19
20
|
import { PublicKey, type SpaceId } from '@dxos/keys';
|
|
20
21
|
import { log } from '@dxos/log';
|
|
22
|
+
import { type Runtime } from '@dxos/protocols/proto/dxos/config';
|
|
21
23
|
import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
22
24
|
import {
|
|
23
25
|
AdmittedFeed,
|
|
@@ -32,6 +34,7 @@ import { type ComplexMap, ComplexSet } from '@dxos/util';
|
|
|
32
34
|
|
|
33
35
|
import { TrustedKeySetAuthVerifier } from './authenticator';
|
|
34
36
|
import { DefaultSpaceStateMachine } from './default-space-state-machine';
|
|
37
|
+
import { EdgeFeedReplicator } from '../spaces';
|
|
35
38
|
|
|
36
39
|
export type IdentityParams = {
|
|
37
40
|
identityKey: PublicKey;
|
|
@@ -39,6 +42,9 @@ export type IdentityParams = {
|
|
|
39
42
|
signer: Signer;
|
|
40
43
|
space: Space;
|
|
41
44
|
presence?: Presence;
|
|
45
|
+
|
|
46
|
+
edgeConnection?: EdgeConnection;
|
|
47
|
+
edgeFeatures?: Runtime.Client.EdgeFeatures;
|
|
42
48
|
};
|
|
43
49
|
|
|
44
50
|
/**
|
|
@@ -52,6 +58,8 @@ export class Identity {
|
|
|
52
58
|
private readonly _deviceStateMachine: DeviceStateMachine;
|
|
53
59
|
private readonly _profileStateMachine: ProfileStateMachine;
|
|
54
60
|
private readonly _defaultSpaceStateMachine: DefaultSpaceStateMachine;
|
|
61
|
+
private readonly _edgeFeedReplicator?: EdgeFeedReplicator = undefined;
|
|
62
|
+
|
|
55
63
|
public readonly authVerifier: TrustedKeySetAuthVerifier;
|
|
56
64
|
|
|
57
65
|
public readonly identityKey: PublicKey;
|
|
@@ -59,15 +67,15 @@ export class Identity {
|
|
|
59
67
|
|
|
60
68
|
public readonly stateUpdate = new Event();
|
|
61
69
|
|
|
62
|
-
constructor(
|
|
63
|
-
this.space = space;
|
|
64
|
-
this._signer = signer;
|
|
65
|
-
this._presence = presence;
|
|
70
|
+
constructor(params: IdentityParams) {
|
|
71
|
+
this.space = params.space;
|
|
72
|
+
this._signer = params.signer;
|
|
73
|
+
this._presence = params.presence;
|
|
66
74
|
|
|
67
|
-
this.identityKey = identityKey;
|
|
68
|
-
this.deviceKey = deviceKey;
|
|
75
|
+
this.identityKey = params.identityKey;
|
|
76
|
+
this.deviceKey = params.deviceKey;
|
|
69
77
|
|
|
70
|
-
log.trace('dxos.halo.device', { deviceKey });
|
|
78
|
+
log.trace('dxos.halo.device', { deviceKey: params.deviceKey });
|
|
71
79
|
|
|
72
80
|
this._deviceStateMachine = new DeviceStateMachine({
|
|
73
81
|
identityKey: this.identityKey,
|
|
@@ -88,6 +96,10 @@ export class Identity {
|
|
|
88
96
|
update: this.stateUpdate,
|
|
89
97
|
authTimeout: AUTH_TIMEOUT,
|
|
90
98
|
});
|
|
99
|
+
|
|
100
|
+
if (params.edgeConnection && params.edgeFeatures?.feedReplicator) {
|
|
101
|
+
this._edgeFeedReplicator = new EdgeFeedReplicator({ messenger: params.edgeConnection, spaceId: this.space.id });
|
|
102
|
+
}
|
|
91
103
|
}
|
|
92
104
|
|
|
93
105
|
// TODO(burdon): Expose state object?
|
|
@@ -105,7 +117,14 @@ export class Identity {
|
|
|
105
117
|
await this.space.spaceState.addCredentialProcessor(this._deviceStateMachine);
|
|
106
118
|
await this.space.spaceState.addCredentialProcessor(this._profileStateMachine);
|
|
107
119
|
await this.space.spaceState.addCredentialProcessor(this._defaultSpaceStateMachine);
|
|
120
|
+
|
|
121
|
+
if (this._edgeFeedReplicator) {
|
|
122
|
+
this.space.protocol.feedAdded.append(this._onFeedAdded);
|
|
123
|
+
}
|
|
124
|
+
|
|
108
125
|
await this.space.open(ctx);
|
|
126
|
+
|
|
127
|
+
await this._edgeFeedReplicator?.open();
|
|
109
128
|
}
|
|
110
129
|
|
|
111
130
|
@trace.span()
|
|
@@ -115,6 +134,13 @@ export class Identity {
|
|
|
115
134
|
await this.space.spaceState.removeCredentialProcessor(this._defaultSpaceStateMachine);
|
|
116
135
|
await this.space.spaceState.removeCredentialProcessor(this._profileStateMachine);
|
|
117
136
|
await this.space.spaceState.removeCredentialProcessor(this._deviceStateMachine);
|
|
137
|
+
|
|
138
|
+
if (this._edgeFeedReplicator) {
|
|
139
|
+
this.space.protocol.feedAdded.remove(this._onFeedAdded);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
await this._edgeFeedReplicator?.close();
|
|
143
|
+
|
|
118
144
|
await this.space.close();
|
|
119
145
|
}
|
|
120
146
|
|
|
@@ -151,6 +177,10 @@ export class Identity {
|
|
|
151
177
|
return this._presence;
|
|
152
178
|
}
|
|
153
179
|
|
|
180
|
+
get signer() {
|
|
181
|
+
return this._signer;
|
|
182
|
+
}
|
|
183
|
+
|
|
154
184
|
/**
|
|
155
185
|
* Issues credentials as identity.
|
|
156
186
|
* Requires identity to be ready.
|
|
@@ -223,4 +253,8 @@ export class Identity {
|
|
|
223
253
|
].map((credential): FeedMessage.Payload => ({ credential: { credential } })),
|
|
224
254
|
);
|
|
225
255
|
}
|
|
256
|
+
|
|
257
|
+
private _onFeedAdded = async (feed: FeedWrapper<any>) => {
|
|
258
|
+
await this._edgeFeedReplicator!.addFeed(feed);
|
|
259
|
+
};
|
|
226
260
|
}
|
|
@@ -2,19 +2,20 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { expect } from '
|
|
5
|
+
import { describe, expect, test, onTestFinished } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { asyncChain } from '@dxos/async';
|
|
8
8
|
import { Context } from '@dxos/context';
|
|
9
9
|
import { AlreadyJoinedError } from '@dxos/protocols';
|
|
10
10
|
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
11
|
-
import { describe, test, afterTest } from '@dxos/test';
|
|
12
11
|
|
|
13
12
|
import { type ServiceContext } from '../services';
|
|
14
13
|
import { createPeers, createServiceContext, performInvitation } from '../testing';
|
|
15
14
|
|
|
16
15
|
const closeAfterTest = async (peer: ServiceContext) => {
|
|
17
|
-
|
|
16
|
+
onTestFinished(async () => {
|
|
17
|
+
await peer.close();
|
|
18
|
+
});
|
|
18
19
|
return peer;
|
|
19
20
|
};
|
|
20
21
|
|
|
@@ -22,7 +23,9 @@ describe('services/device', () => {
|
|
|
22
23
|
test('creates identity', async () => {
|
|
23
24
|
const peer = await createServiceContext();
|
|
24
25
|
await peer.open(new Context());
|
|
25
|
-
|
|
26
|
+
onTestFinished(async () => {
|
|
27
|
+
await peer.close();
|
|
28
|
+
});
|
|
26
29
|
|
|
27
30
|
const identity = await peer.createIdentity();
|
|
28
31
|
expect(identity).not.to.be.undefined;
|
|
@@ -106,13 +106,11 @@ export class InvitationHostExtension extends RpcExtension<
|
|
|
106
106
|
|
|
107
107
|
introduce: async (request) => {
|
|
108
108
|
const { profile, invitationId } = request;
|
|
109
|
-
|
|
110
109
|
const traceId = PublicKey.random().toHex();
|
|
111
110
|
log.trace('dxos.sdk.invitation-handler.host.introduce', trace.begin({ id: traceId }));
|
|
112
111
|
|
|
113
112
|
const invitation = this._requireActiveInvitation();
|
|
114
113
|
this._assertInvitationState(Invitation.State.CONNECTED);
|
|
115
|
-
|
|
116
114
|
if (invitationId !== invitation?.invitationId) {
|
|
117
115
|
log.warn('incorrect invitationId', { expected: invitation.invitationId, actual: invitationId });
|
|
118
116
|
this._callbacks.onError(new Error('Incorrect invitationId.'));
|
|
@@ -126,7 +124,6 @@ export class InvitationHostExtension extends RpcExtension<
|
|
|
126
124
|
log('guest introduced themselves', { guestProfile: profile });
|
|
127
125
|
this.guestProfile = profile;
|
|
128
126
|
this._callbacks.onStateUpdate(Invitation.State.READY_FOR_AUTHENTICATION);
|
|
129
|
-
|
|
130
127
|
this._challenge =
|
|
131
128
|
invitation.authMethod === Invitation.AuthMethod.KNOWN_PUBLIC_KEY ? randomBytes(32) : undefined;
|
|
132
129
|
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { expect } from '
|
|
5
|
+
import { beforeEach, onTestFinished, describe, expect, test } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { type PushStream, sleep, Trigger, waitForCondition } from '@dxos/async';
|
|
8
8
|
import { Context } from '@dxos/context';
|
|
9
9
|
import { PublicKey } from '@dxos/keys';
|
|
10
10
|
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
11
|
-
import {
|
|
11
|
+
import { openAndClose } from '@dxos/test-utils';
|
|
12
12
|
import { range } from '@dxos/util';
|
|
13
13
|
|
|
14
14
|
import { type InvitationProtocol } from './invitation-protocol';
|
|
@@ -34,6 +34,7 @@ type StateUpdateSink = PushStream<Invitation> & {
|
|
|
34
34
|
|
|
35
35
|
describe('InvitationHandler', () => {
|
|
36
36
|
let testBuilder: TestBuilder;
|
|
37
|
+
|
|
37
38
|
beforeEach(() => {
|
|
38
39
|
testBuilder = new TestBuilder();
|
|
39
40
|
});
|
|
@@ -163,7 +164,7 @@ describe('InvitationHandler', () => {
|
|
|
163
164
|
expect(guest.ctx.disposed).to.be.true;
|
|
164
165
|
});
|
|
165
166
|
|
|
166
|
-
test('guest gives up after trying with three hosts', async () => {
|
|
167
|
+
test('guest gives up after trying with three hosts', { timeout: 20_000 }, async () => {
|
|
167
168
|
const hosts: PeerSetup[] = [await createPeer()];
|
|
168
169
|
const [host] = hosts;
|
|
169
170
|
const invitation = await createInvitation(host, { multiUse: true });
|
|
@@ -181,7 +182,7 @@ describe('InvitationHandler', () => {
|
|
|
181
182
|
|
|
182
183
|
await sleep(10);
|
|
183
184
|
expect(guest.sink.lastState).to.eq(Invitation.State.ERROR);
|
|
184
|
-
})
|
|
185
|
+
});
|
|
185
186
|
|
|
186
187
|
test('single host - many guests', async () => {
|
|
187
188
|
const hosts: PeerSetup[] = [await createPeer()];
|
|
@@ -261,7 +262,9 @@ describe('InvitationHandler', () => {
|
|
|
261
262
|
});
|
|
262
263
|
const protocol = new SpaceInvitationProtocol(peer.dataSpaceManager, peer.identity, peer.keyring, spaceKey);
|
|
263
264
|
const ctx = new Context();
|
|
264
|
-
|
|
265
|
+
onTestFinished(async () => {
|
|
266
|
+
await ctx.dispose();
|
|
267
|
+
});
|
|
265
268
|
const sink = newStateUpdateSink();
|
|
266
269
|
return { ctx, sink, peer, protocol, handler: invitationHandler, spaceKey };
|
|
267
270
|
};
|
|
@@ -269,14 +272,18 @@ describe('InvitationHandler', () => {
|
|
|
269
272
|
const hostInvitation = async (setup: PeerSetup, invitation: Invitation) => {
|
|
270
273
|
await setup.ctx.dispose();
|
|
271
274
|
setup.ctx = new Context();
|
|
272
|
-
|
|
275
|
+
onTestFinished(async () => {
|
|
276
|
+
await setup.ctx.dispose();
|
|
277
|
+
});
|
|
273
278
|
setup.handler.handleInvitationFlow(setup.ctx, setup.sink, setup.protocol, invitation);
|
|
274
279
|
};
|
|
275
280
|
|
|
276
281
|
const acceptInvitation = async (setup: PeerSetup, invitation: Invitation): Promise<Trigger<string>> => {
|
|
277
282
|
await setup.ctx.dispose();
|
|
278
283
|
setup.ctx = new Context();
|
|
279
|
-
|
|
284
|
+
onTestFinished(async () => {
|
|
285
|
+
await setup.ctx.dispose();
|
|
286
|
+
});
|
|
280
287
|
const authCodeInput = new Trigger<string>();
|
|
281
288
|
setup.handler.acceptInvitation(setup.ctx, setup.sink, setup.protocol, invitation, authCodeInput);
|
|
282
289
|
return authCodeInput;
|
|
@@ -463,7 +463,7 @@ export class InvitationsHandler {
|
|
|
463
463
|
oldState: stateToString(invitation.state),
|
|
464
464
|
});
|
|
465
465
|
} else {
|
|
466
|
-
log
|
|
466
|
+
log('invitation state update', {
|
|
467
467
|
actor: actor?.constructor.name,
|
|
468
468
|
newState: stateToString(newState),
|
|
469
469
|
oldState: stateToString(invitation.state),
|
|
@@ -2,20 +2,21 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { expect } from '
|
|
5
|
+
import { onTestFinished, describe, expect, test } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { asyncChain, Trigger } from '@dxos/async';
|
|
8
8
|
import { raise } from '@dxos/debug';
|
|
9
9
|
import { AlreadyJoinedError } from '@dxos/protocols';
|
|
10
10
|
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
11
|
-
import { afterTest, describe, test } from '@dxos/test';
|
|
12
11
|
|
|
13
12
|
import { type ServiceContext } from '../services';
|
|
14
13
|
import { createIdentity, createPeers } from '../testing';
|
|
15
14
|
import { acceptInvitation, createInvitation, performInvitation } from '../testing/invitation-utils';
|
|
16
15
|
|
|
17
16
|
const closeAfterTest = async (peer: ServiceContext) => {
|
|
18
|
-
|
|
17
|
+
onTestFinished(async () => {
|
|
18
|
+
await peer.close();
|
|
19
|
+
});
|
|
19
20
|
return peer;
|
|
20
21
|
};
|
|
21
22
|
|
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { expect } from '
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, test } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { Trigger } from '@dxos/async';
|
|
8
8
|
import { log, LogLevel } from '@dxos/log';
|
|
9
9
|
import { type LogEntry } from '@dxos/protocols/proto/dxos/client/services';
|
|
10
|
-
import { beforeEach, describe, test } from '@dxos/test';
|
|
11
10
|
|
|
12
11
|
import { LoggingServiceImpl } from './logging-service';
|
|
13
12
|
|
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { expect } from '
|
|
5
|
+
import { afterEach, onTestFinished, beforeEach, describe, expect, test } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { Trigger } from '@dxos/async';
|
|
8
8
|
import { Context } from '@dxos/context';
|
|
9
9
|
import { type NetworkService, ConnectionState } from '@dxos/protocols/proto/dxos/client/services';
|
|
10
|
-
import { afterEach, afterTest, beforeEach, describe, test } from '@dxos/test';
|
|
11
10
|
|
|
12
11
|
import { NetworkServiceImpl } from './network-service';
|
|
13
12
|
import { type ServiceContext } from '../services';
|
|
@@ -41,7 +40,7 @@ describe('NetworkService', () => {
|
|
|
41
40
|
query.subscribe(({ swarm }) => {
|
|
42
41
|
result.wake(swarm);
|
|
43
42
|
});
|
|
44
|
-
|
|
43
|
+
onTestFinished(() => query.close());
|
|
45
44
|
expect(await result.wait()).to.equal(ConnectionState.ONLINE);
|
|
46
45
|
|
|
47
46
|
result = new Trigger<ConnectionState | undefined>();
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { describe, test } from 'vitest';
|
|
6
|
+
|
|
5
7
|
import { MemorySignalManagerContext, MemorySignalManager } from '@dxos/messaging';
|
|
6
8
|
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
7
|
-
import {
|
|
9
|
+
import { openAndClose } from '@dxos/test-utils';
|
|
8
10
|
|
|
9
11
|
import { createServiceContext, performInvitation } from '../testing';
|
|
10
12
|
|
|
@@ -2,13 +2,20 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Trigger } from '@dxos/async';
|
|
5
|
+
import { Mutex, scheduleMicroTask, Trigger } from '@dxos/async';
|
|
6
6
|
import { Context, Resource } from '@dxos/context';
|
|
7
7
|
import { getCredentialAssertion, type CredentialProcessor } from '@dxos/credentials';
|
|
8
|
-
import { failUndefined } from '@dxos/debug';
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
import { failUndefined, warnAfterTimeout } from '@dxos/debug';
|
|
9
|
+
import {
|
|
10
|
+
EchoEdgeReplicator,
|
|
11
|
+
EchoHost,
|
|
12
|
+
MeshEchoReplicator,
|
|
13
|
+
MetadataStore,
|
|
14
|
+
SpaceManager,
|
|
15
|
+
valueEncoding,
|
|
16
|
+
} from '@dxos/echo-pipeline';
|
|
17
|
+
import { createChainEdgeIdentity, createEphemeralEdgeIdentity } from '@dxos/edge-client';
|
|
18
|
+
import type { EdgeHttpClient, EdgeConnection } from '@dxos/edge-client';
|
|
12
19
|
import { FeedFactory, FeedStore } from '@dxos/feed-store';
|
|
13
20
|
import { invariant } from '@dxos/invariant';
|
|
14
21
|
import { Keyring } from '@dxos/keyring';
|
|
@@ -31,7 +38,7 @@ import { safeInstanceof } from '@dxos/util';
|
|
|
31
38
|
import {
|
|
32
39
|
IdentityManager,
|
|
33
40
|
type CreateIdentityOptions,
|
|
34
|
-
type
|
|
41
|
+
type IdentityManagerParams,
|
|
35
42
|
type JoinIdentityParams,
|
|
36
43
|
} from '../identity';
|
|
37
44
|
import {
|
|
@@ -43,7 +50,10 @@ import {
|
|
|
43
50
|
} from '../invitations';
|
|
44
51
|
import { DataSpaceManager, type DataSpaceManagerRuntimeParams, type SigningContext } from '../spaces';
|
|
45
52
|
|
|
46
|
-
export type ServiceContextRuntimeParams =
|
|
53
|
+
export type ServiceContextRuntimeParams = Pick<
|
|
54
|
+
IdentityManagerParams,
|
|
55
|
+
'devicePresenceOfflineTimeout' | 'devicePresenceAnnounceInterval'
|
|
56
|
+
> &
|
|
47
57
|
DataSpaceManagerRuntimeParams & {
|
|
48
58
|
invitationConnectionDefaultParams?: Partial<TeleportParams>;
|
|
49
59
|
disableP2pReplication?: boolean;
|
|
@@ -56,6 +66,8 @@ export type ServiceContextRuntimeParams = IdentityManagerRuntimeParams &
|
|
|
56
66
|
@safeInstanceof('dxos.client-services.ServiceContext')
|
|
57
67
|
@Trace.resource()
|
|
58
68
|
export class ServiceContext extends Resource {
|
|
69
|
+
private readonly _edgeIdentityUpdateMutex = new Mutex();
|
|
70
|
+
|
|
59
71
|
public readonly initialized = new Trigger();
|
|
60
72
|
public readonly metadataStore: MetadataStore;
|
|
61
73
|
public readonly blobStore: BlobStore;
|
|
@@ -87,6 +99,7 @@ export class ServiceContext extends Resource {
|
|
|
87
99
|
public readonly networkManager: SwarmNetworkManager,
|
|
88
100
|
public readonly signalManager: SignalManager,
|
|
89
101
|
private readonly _edgeConnection: EdgeConnection | undefined,
|
|
102
|
+
private readonly _edgeHttpClient: EdgeHttpClient | undefined,
|
|
90
103
|
public readonly _runtimeParams?: ServiceContextRuntimeParams,
|
|
91
104
|
private readonly _edgeFeatures?: Runtime.Client.EdgeFeatures,
|
|
92
105
|
) {
|
|
@@ -116,32 +129,50 @@ export class ServiceContext extends Resource {
|
|
|
116
129
|
disableP2pReplication: this._runtimeParams?.disableP2pReplication,
|
|
117
130
|
});
|
|
118
131
|
|
|
119
|
-
this.identityManager = new IdentityManager(
|
|
120
|
-
this.metadataStore,
|
|
121
|
-
this.keyring,
|
|
122
|
-
this.feedStore,
|
|
123
|
-
this.spaceManager,
|
|
124
|
-
this._runtimeParams
|
|
125
|
-
|
|
132
|
+
this.identityManager = new IdentityManager({
|
|
133
|
+
metadataStore: this.metadataStore,
|
|
134
|
+
keyring: this.keyring,
|
|
135
|
+
feedStore: this.feedStore,
|
|
136
|
+
spaceManager: this.spaceManager,
|
|
137
|
+
devicePresenceOfflineTimeout: this._runtimeParams?.devicePresenceOfflineTimeout,
|
|
138
|
+
devicePresenceAnnounceInterval: this._runtimeParams?.devicePresenceAnnounceInterval,
|
|
139
|
+
edgeConnection: this._edgeConnection,
|
|
140
|
+
edgeFeatures: this._edgeFeatures,
|
|
141
|
+
callbacks: {
|
|
126
142
|
onIdentityConstruction: (identity) => {
|
|
127
143
|
if (this._edgeConnection) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
144
|
+
scheduleMicroTask(this._ctx, async () => {
|
|
145
|
+
using _ = await this._edgeIdentityUpdateMutex.acquire();
|
|
146
|
+
|
|
147
|
+
log.info('Setting identity on edge connection', {
|
|
148
|
+
identity: identity.identityKey.toHex(),
|
|
149
|
+
oldIdentity: this._edgeConnection!.identityKey,
|
|
150
|
+
swarms: this.networkManager.topics,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
await warnAfterTimeout(10_000, 'Waiting for identity to be ready for edge connection', async () => {
|
|
154
|
+
await identity.ready();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
invariant(identity.deviceCredentialChain);
|
|
158
|
+
this._edgeConnection!.setIdentity(
|
|
159
|
+
await createChainEdgeIdentity(
|
|
160
|
+
identity.signer,
|
|
161
|
+
identity.identityKey,
|
|
162
|
+
identity.deviceKey,
|
|
163
|
+
identity.deviceCredentialChain,
|
|
164
|
+
[], // TODO(dmaretskyi): Service access credentials.
|
|
165
|
+
),
|
|
166
|
+
);
|
|
167
|
+
this.networkManager.setPeerInfo({
|
|
168
|
+
identityKey: identity.identityKey.toHex(),
|
|
169
|
+
peerKey: identity.deviceKey.toHex(),
|
|
170
|
+
});
|
|
140
171
|
});
|
|
141
172
|
}
|
|
142
173
|
},
|
|
143
174
|
},
|
|
144
|
-
);
|
|
175
|
+
});
|
|
145
176
|
|
|
146
177
|
this.echoHost = new EchoHost({ kv: this.level });
|
|
147
178
|
|
|
@@ -185,7 +216,11 @@ export class ServiceContext extends Resource {
|
|
|
185
216
|
|
|
186
217
|
log('opening...');
|
|
187
218
|
log.trace('dxos.sdk.service-context.open', trace.begin({ id: this._instanceId }));
|
|
188
|
-
|
|
219
|
+
if (this._edgeConnection) {
|
|
220
|
+
// TODO(dmaretskyi): Use device key.
|
|
221
|
+
this._edgeConnection.setIdentity(await createEphemeralEdgeIdentity());
|
|
222
|
+
await this._edgeConnection.open();
|
|
223
|
+
}
|
|
189
224
|
await this.signalManager.open();
|
|
190
225
|
await this.networkManager.open();
|
|
191
226
|
|
|
@@ -292,6 +327,7 @@ export class ServiceContext extends Resource {
|
|
|
292
327
|
echoHost: this.echoHost,
|
|
293
328
|
invitationsManager: this.invitationsManager,
|
|
294
329
|
edgeConnection: this._edgeConnection,
|
|
330
|
+
edgeHttpClient: this._edgeHttpClient,
|
|
295
331
|
echoEdgeReplicator: this._echoEdgeReplicator,
|
|
296
332
|
meshReplicator: this._meshReplicator,
|
|
297
333
|
runtimeParams: this._runtimeParams as DataSpaceManagerRuntimeParams,
|
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import chai, { expect } from 'chai';
|
|
6
|
-
import chaiAsPromised from 'chai-as-promised';
|
|
7
5
|
import { rmSync } from 'node:fs';
|
|
6
|
+
import { afterEach, onTestFinished, describe, expect, test } from 'vitest';
|
|
8
7
|
|
|
9
8
|
import { asyncTimeout, latch, Trigger } from '@dxos/async';
|
|
10
9
|
import { Config } from '@dxos/config';
|
|
@@ -14,13 +13,10 @@ import { type PublicKey } from '@dxos/keys';
|
|
|
14
13
|
import { MemorySignalManagerContext } from '@dxos/messaging';
|
|
15
14
|
import { type Identity } from '@dxos/protocols/proto/dxos/client/services';
|
|
16
15
|
import { type Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
17
|
-
import { afterTest, describe, test } from '@dxos/test';
|
|
18
16
|
import { isNode } from '@dxos/util';
|
|
19
17
|
|
|
20
18
|
import { createMockCredential, createServiceHost } from '../testing';
|
|
21
19
|
|
|
22
|
-
chai.use(chaiAsPromised);
|
|
23
|
-
|
|
24
20
|
describe('ClientServicesHost', () => {
|
|
25
21
|
const dataRoot = '/tmp/dxos/client-services/service-host/storage';
|
|
26
22
|
|
|
@@ -38,7 +34,7 @@ describe('ClientServicesHost', () => {
|
|
|
38
34
|
test('queryCredentials', async () => {
|
|
39
35
|
const host = createServiceHost(new Config(), new MemorySignalManagerContext());
|
|
40
36
|
await host.open(new Context());
|
|
41
|
-
|
|
37
|
+
onTestFinished(() => host.close());
|
|
42
38
|
|
|
43
39
|
await host.services.IdentityService!.createIdentity({});
|
|
44
40
|
const { spaceKey } = await host.services.SpacesService!.createSpace();
|
|
@@ -49,7 +45,7 @@ describe('ClientServicesHost', () => {
|
|
|
49
45
|
tick();
|
|
50
46
|
// console.log(credential);
|
|
51
47
|
});
|
|
52
|
-
|
|
48
|
+
onTestFinished(() => stream.close());
|
|
53
49
|
|
|
54
50
|
await done();
|
|
55
51
|
});
|
|
@@ -57,7 +53,7 @@ describe('ClientServicesHost', () => {
|
|
|
57
53
|
test('write and query credentials', async () => {
|
|
58
54
|
const host = createServiceHost(new Config(), new MemorySignalManagerContext());
|
|
59
55
|
await host.open(new Context());
|
|
60
|
-
|
|
56
|
+
onTestFinished(() => host.close());
|
|
61
57
|
|
|
62
58
|
await host.services.IdentityService!.createIdentity({});
|
|
63
59
|
|
|
@@ -86,7 +82,7 @@ describe('ClientServicesHost', () => {
|
|
|
86
82
|
queriedCredential.wake(credential);
|
|
87
83
|
}
|
|
88
84
|
});
|
|
89
|
-
|
|
85
|
+
onTestFinished(() => credentials.close());
|
|
90
86
|
|
|
91
87
|
await queriedCredential.wait();
|
|
92
88
|
});
|
|
@@ -94,7 +90,7 @@ describe('ClientServicesHost', () => {
|
|
|
94
90
|
test('sign presentation', async () => {
|
|
95
91
|
const host = createServiceHost(new Config(), new MemorySignalManagerContext());
|
|
96
92
|
await host.open(new Context());
|
|
97
|
-
|
|
93
|
+
onTestFinished(() => host.close());
|
|
98
94
|
|
|
99
95
|
await host.services.IdentityService!.createIdentity({});
|
|
100
96
|
|
|
@@ -147,9 +143,9 @@ describe('ClientServicesHost', () => {
|
|
|
147
143
|
trigger.wake(identity.identity);
|
|
148
144
|
}
|
|
149
145
|
});
|
|
150
|
-
await expect(asyncTimeout(trigger.wait(), 200)).
|
|
146
|
+
await expect(asyncTimeout(trigger.wait(), 200)).rejects.toBeInstanceOf(Error);
|
|
151
147
|
await stream?.close();
|
|
152
148
|
await host.close();
|
|
153
149
|
}
|
|
154
|
-
})
|
|
150
|
+
});
|
|
155
151
|
});
|
|
@@ -6,7 +6,7 @@ import { Event, synchronized } from '@dxos/async';
|
|
|
6
6
|
import { clientServiceBundle, type ClientServices } from '@dxos/client-protocol';
|
|
7
7
|
import { type Config } from '@dxos/config';
|
|
8
8
|
import { Context } from '@dxos/context';
|
|
9
|
-
import { EdgeClient, type EdgeConnection } from '@dxos/edge-client';
|
|
9
|
+
import { EdgeClient, EdgeHttpClient, createStubEdgeIdentity, type EdgeConnection } from '@dxos/edge-client';
|
|
10
10
|
import { invariant } from '@dxos/invariant';
|
|
11
11
|
import { PublicKey } from '@dxos/keys';
|
|
12
12
|
import { type LevelDB } from '@dxos/kv-store';
|
|
@@ -15,7 +15,7 @@ import { EdgeSignalManager, WebsocketSignalManager, type SignalManager } from '@
|
|
|
15
15
|
import {
|
|
16
16
|
SwarmNetworkManager,
|
|
17
17
|
createIceProvider,
|
|
18
|
-
|
|
18
|
+
createRtcTransportFactory,
|
|
19
19
|
type TransportFactory,
|
|
20
20
|
} from '@dxos/network-manager';
|
|
21
21
|
import { trace } from '@dxos/protocols';
|
|
@@ -29,9 +29,9 @@ import { ServiceRegistry } from './service-registry';
|
|
|
29
29
|
import { DevicesServiceImpl } from '../devices';
|
|
30
30
|
import { DevtoolsHostEvents, DevtoolsServiceImpl } from '../devtools';
|
|
31
31
|
import {
|
|
32
|
-
type CollectDiagnosticsBroadcastHandler,
|
|
33
32
|
createCollectDiagnosticsBroadcastHandler,
|
|
34
33
|
createDiagnostics,
|
|
34
|
+
type CollectDiagnosticsBroadcastHandler,
|
|
35
35
|
} from '../diagnostics';
|
|
36
36
|
import { IdentityServiceImpl, type CreateIdentityOptions } from '../identity';
|
|
37
37
|
import { ContactsServiceImpl } from '../identity/contacts-service';
|
|
@@ -89,6 +89,7 @@ export class ClientServicesHost {
|
|
|
89
89
|
private _callbacks?: ClientServicesHostCallbacks;
|
|
90
90
|
private _devtoolsProxy?: WebsocketRpcClient<{}, ClientServices>;
|
|
91
91
|
private _edgeConnection?: EdgeConnection = undefined;
|
|
92
|
+
private _edgeHttpClient?: EdgeHttpClient = undefined;
|
|
92
93
|
|
|
93
94
|
private _serviceContext!: ServiceContext;
|
|
94
95
|
private readonly _runtimeParams: ServiceContextRuntimeParams;
|
|
@@ -212,13 +213,13 @@ export class ClientServicesHost {
|
|
|
212
213
|
|
|
213
214
|
const edgeEndpoint = config?.get('runtime.services.edge.url');
|
|
214
215
|
if (edgeEndpoint) {
|
|
215
|
-
|
|
216
|
-
this.
|
|
216
|
+
this._edgeConnection = new EdgeClient(createStubEdgeIdentity(), { socketEndpoint: edgeEndpoint });
|
|
217
|
+
this._edgeHttpClient = new EdgeHttpClient(edgeEndpoint);
|
|
217
218
|
}
|
|
218
219
|
|
|
219
220
|
const {
|
|
220
221
|
connectionLog = true,
|
|
221
|
-
transportFactory =
|
|
222
|
+
transportFactory = createRtcTransportFactory(
|
|
222
223
|
{ iceServers: this._config?.get('runtime.services.ice') },
|
|
223
224
|
this._config?.get('runtime.services.iceProviders') &&
|
|
224
225
|
createIceProvider(this._config!.get('runtime.services.iceProviders')!),
|
|
@@ -278,6 +279,7 @@ export class ClientServicesHost {
|
|
|
278
279
|
this._networkManager,
|
|
279
280
|
this._signalManager,
|
|
280
281
|
this._edgeConnection,
|
|
282
|
+
this._edgeHttpClient,
|
|
281
283
|
this._runtimeParams,
|
|
282
284
|
this._config.get('runtime.client.edgeFeatures'),
|
|
283
285
|
);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { expect } from '
|
|
5
|
+
import { describe, expect, test } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { Event } from '@dxos/async';
|
|
8
8
|
import { type ClientServices } from '@dxos/client-protocol';
|
|
@@ -12,7 +12,6 @@ import { log } from '@dxos/log';
|
|
|
12
12
|
import { schema } from '@dxos/protocols/proto';
|
|
13
13
|
import { type SystemService, SystemStatus } from '@dxos/protocols/proto/dxos/client/services';
|
|
14
14
|
import { createLinkedPorts, createProtoRpcPeer, createServiceBundle } from '@dxos/rpc';
|
|
15
|
-
import { describe, test } from '@dxos/test';
|
|
16
15
|
|
|
17
16
|
import { ServiceRegistry } from './service-registry';
|
|
18
17
|
import { SystemServiceImpl } from '../system';
|