@dxos/client 2.23.1-dev.f5b1145e → 2.24.1-dev.3a8cd54e
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/src/api/echo-proxy.d.ts +7 -7
- package/dist/src/api/echo-proxy.d.ts.map +1 -1
- package/dist/src/api/echo-proxy.js +1 -1
- package/dist/src/api/echo-proxy.js.map +1 -1
- package/dist/src/api/halo-proxy.d.ts +5 -7
- package/dist/src/api/halo-proxy.d.ts.map +1 -1
- package/dist/src/api/halo-proxy.js +8 -11
- package/dist/src/api/halo-proxy.js.map +1 -1
- package/dist/src/api/party-proxy.d.ts +1 -5
- package/dist/src/api/party-proxy.d.ts.map +1 -1
- package/dist/src/api/party-proxy.js +6 -3
- package/dist/src/api/party-proxy.js.map +1 -1
- package/dist/src/client/client.d.ts +5 -5
- package/dist/src/client/client.d.ts.map +1 -1
- package/dist/src/client/client.js +16 -8
- package/dist/src/client/client.js.map +1 -1
- package/dist/src/client/client.test.js +11 -8
- package/dist/src/client/client.test.js.map +1 -1
- package/dist/src/client/local-client.test.js +8 -5
- package/dist/src/client/local-client.test.js.map +1 -1
- package/dist/src/client/service-host/service-host.js +5 -5
- package/dist/src/client/service-host/service-host.js.map +1 -1
- package/dist/src/client/service-host/services/halo.d.ts +14 -0
- package/dist/src/client/service-host/services/halo.d.ts.map +1 -0
- package/dist/src/client/service-host/services/halo.js +69 -0
- package/dist/src/client/service-host/services/halo.js.map +1 -0
- package/dist/src/client/service-host/services/party.d.ts.map +1 -1
- package/dist/src/client/service-host/services/party.js +4 -4
- package/dist/src/client/service-host/services/party.js.map +1 -1
- package/dist/src/client/service-host/services/profile.d.ts +2 -6
- package/dist/src/client/service-host/services/profile.d.ts.map +1 -1
- package/dist/src/client/service-host/services/profile.js +0 -19
- package/dist/src/client/service-host/services/profile.js.map +1 -1
- package/dist/src/client/service-host/services/services.d.ts.map +1 -1
- package/dist/src/client/service-host/services/services.js +2 -0
- package/dist/src/client/service-host/services/services.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +12 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/interfaces/client-service-provider.d.ts +2 -1
- package/dist/src/interfaces/client-service-provider.d.ts.map +1 -1
- package/dist/src/interfaces/client-service-provider.js +1 -0
- package/dist/src/interfaces/client-service-provider.js.map +1 -1
- package/dist/src/proto/gen/dxos/client.d.ts +33 -15
- package/dist/src/proto/gen/dxos/client.d.ts.map +1 -1
- package/dist/src/proto/gen/dxos/client.js.map +1 -1
- package/dist/src/proto/gen/dxos/halo/keys.d.ts +2 -1
- package/dist/src/proto/gen/dxos/halo/keys.d.ts.map +1 -1
- package/dist/src/proto/gen/dxos/halo/keys.js +1 -0
- package/dist/src/proto/gen/dxos/halo/keys.js.map +1 -1
- package/dist/src/proto/gen/index.d.ts +4 -0
- package/dist/src/proto/gen/index.d.ts.map +1 -1
- package/dist/src/proto/gen/index.js +1 -1
- package/dist/src/proto/gen/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +23 -20
- package/src/api/echo-proxy.ts +9 -9
- package/src/api/halo-proxy.ts +12 -14
- package/src/api/party-proxy.ts +7 -4
- package/src/client/client.test.ts +13 -10
- package/src/client/client.ts +19 -9
- package/src/client/local-client.test.ts +10 -7
- package/src/client/service-host/service-host.ts +6 -6
- package/src/client/service-host/services/halo.ts +75 -0
- package/src/client/service-host/services/party.ts +6 -6
- package/src/client/service-host/services/profile.ts +1 -32
- package/src/client/service-host/services/services.ts +2 -0
- package/src/index.ts +15 -0
- package/src/interfaces/client-service-provider.ts +3 -1
- package/src/proto/gen/dxos/client.ts +32 -15
- package/src/proto/gen/dxos/halo/keys.ts +2 -1
- package/src/proto/gen/index.ts +5 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/client",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.24.1-dev.3a8cd54e",
|
|
4
4
|
"license": "AGPL-3.0",
|
|
5
5
|
"author": "DXOS.org",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -10,21 +10,21 @@
|
|
|
10
10
|
"src"
|
|
11
11
|
],
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@dxos/async": "2.
|
|
14
|
-
"@dxos/codec-protobuf": "2.
|
|
15
|
-
"@dxos/config": "2.
|
|
16
|
-
"@dxos/credentials": "2.
|
|
17
|
-
"@dxos/crypto": "2.
|
|
18
|
-
"@dxos/debug": "2.
|
|
19
|
-
"@dxos/echo-db": "2.
|
|
20
|
-
"@dxos/echo-protocol": "2.
|
|
21
|
-
"@dxos/feed-store": "2.
|
|
22
|
-
"@dxos/model-factory": "2.
|
|
23
|
-
"@dxos/network-manager": "2.
|
|
24
|
-
"@dxos/object-model": "2.
|
|
25
|
-
"@dxos/proto": "2.
|
|
26
|
-
"@dxos/rpc": "2.
|
|
27
|
-
"@dxos/util": "2.
|
|
13
|
+
"@dxos/async": "2.24.1-dev.3a8cd54e",
|
|
14
|
+
"@dxos/codec-protobuf": "2.24.1-dev.3a8cd54e",
|
|
15
|
+
"@dxos/config": "2.24.1-dev.3a8cd54e",
|
|
16
|
+
"@dxos/credentials": "2.24.1-dev.3a8cd54e",
|
|
17
|
+
"@dxos/crypto": "2.24.1-dev.3a8cd54e",
|
|
18
|
+
"@dxos/debug": "2.24.1-dev.3a8cd54e",
|
|
19
|
+
"@dxos/echo-db": "2.24.1-dev.3a8cd54e",
|
|
20
|
+
"@dxos/echo-protocol": "2.24.1-dev.3a8cd54e",
|
|
21
|
+
"@dxos/feed-store": "2.24.1-dev.3a8cd54e",
|
|
22
|
+
"@dxos/model-factory": "2.24.1-dev.3a8cd54e",
|
|
23
|
+
"@dxos/network-manager": "2.24.1-dev.3a8cd54e",
|
|
24
|
+
"@dxos/object-model": "2.24.1-dev.3a8cd54e",
|
|
25
|
+
"@dxos/proto": "2.24.1-dev.3a8cd54e",
|
|
26
|
+
"@dxos/rpc": "2.24.1-dev.3a8cd54e",
|
|
27
|
+
"@dxos/util": "2.24.1-dev.3a8cd54e",
|
|
28
28
|
"@wirelineio/registry-client": "~1.1.0-beta.3",
|
|
29
29
|
"abstract-leveldown": "~7.0.0",
|
|
30
30
|
"assert": "^2.0.0",
|
|
@@ -35,12 +35,15 @@
|
|
|
35
35
|
"lodash.defaultsdeep": "^4.6.1",
|
|
36
36
|
"memdown": "^5.1.0",
|
|
37
37
|
"readable-stream": "^3.6.0",
|
|
38
|
-
"uuid": "^8.3.2"
|
|
38
|
+
"uuid": "^8.3.2",
|
|
39
|
+
"@polkadot/util-crypto": "6.11.1",
|
|
40
|
+
"@polkadot/util": "6.11.1",
|
|
41
|
+
"@polkadot/keyring": "6.11.1"
|
|
39
42
|
},
|
|
40
43
|
"devDependencies": {
|
|
41
|
-
"@dxos/random-access-multi-storage": "2.
|
|
42
|
-
"@dxos/testutils": "2.
|
|
43
|
-
"@dxos/toolchain-node-library": "2.
|
|
44
|
+
"@dxos/random-access-multi-storage": "2.24.1-dev.3a8cd54e",
|
|
45
|
+
"@dxos/testutils": "2.24.0",
|
|
46
|
+
"@dxos/toolchain-node-library": "2.24.0",
|
|
44
47
|
"@types/debug": "^4.1.7",
|
|
45
48
|
"@types/expect": "~24.3.0",
|
|
46
49
|
"@types/jest": "^26.0.7",
|
package/src/api/echo-proxy.ts
CHANGED
|
@@ -16,20 +16,20 @@ import { ComplexMap, SubscriptionGroup } from '@dxos/util';
|
|
|
16
16
|
import { ClientServiceHost } from '../client/service-host';
|
|
17
17
|
import { ClientServiceProvider } from '../interfaces';
|
|
18
18
|
import { Invitation, InvitationProxy } from './invitations';
|
|
19
|
-
import {
|
|
19
|
+
import { Party } from './party-proxy';
|
|
20
20
|
|
|
21
|
-
export class PartyInvitation extends Invitation<
|
|
21
|
+
export class PartyInvitation extends Invitation<Party> {
|
|
22
22
|
/**
|
|
23
23
|
* Wait for the invitation flow to complete and return the target party.
|
|
24
24
|
*/
|
|
25
|
-
getParty (): Promise<
|
|
25
|
+
getParty (): Promise<Party> {
|
|
26
26
|
return this.wait();
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export class EchoProxy {
|
|
31
31
|
private readonly _modelFactory: ModelFactory;
|
|
32
|
-
private _parties = new ComplexMap<PublicKey,
|
|
32
|
+
private _parties = new ComplexMap<PublicKey, Party>(key => key.toHex());
|
|
33
33
|
private readonly _partiesChanged = new Event();
|
|
34
34
|
private readonly _subscriptions = new SubscriptionGroup();
|
|
35
35
|
|
|
@@ -68,7 +68,7 @@ export class EchoProxy {
|
|
|
68
68
|
partiesStream.subscribe(async data => {
|
|
69
69
|
for (const party of data.parties ?? []) {
|
|
70
70
|
if (!this._parties.has(party.publicKey)) {
|
|
71
|
-
const partyProxy = new
|
|
71
|
+
const partyProxy = new Party(this._serviceProvider, this._modelFactory, party);
|
|
72
72
|
await partyProxy.init();
|
|
73
73
|
this._parties.set(partyProxy.key, partyProxy);
|
|
74
74
|
|
|
@@ -114,7 +114,7 @@ export class EchoProxy {
|
|
|
114
114
|
/**
|
|
115
115
|
* Creates a new party.
|
|
116
116
|
*/
|
|
117
|
-
async createParty (): Promise<
|
|
117
|
+
async createParty (): Promise<Party> {
|
|
118
118
|
const [partyReceivedPromise, partyReceived] = latch();
|
|
119
119
|
|
|
120
120
|
const party = await this._serviceProvider.services.PartyService.CreateParty();
|
|
@@ -135,7 +135,7 @@ export class EchoProxy {
|
|
|
135
135
|
/**
|
|
136
136
|
* Clones the party from a snapshot.
|
|
137
137
|
*/
|
|
138
|
-
async cloneParty (snapshot: PartySnapshot): Promise<
|
|
138
|
+
async cloneParty (snapshot: PartySnapshot): Promise<Party> {
|
|
139
139
|
const [partyReceivedPromise, partyReceived] = latch();
|
|
140
140
|
|
|
141
141
|
const party = await this._serviceProvider.services.PartyService.CloneParty(snapshot);
|
|
@@ -156,11 +156,11 @@ export class EchoProxy {
|
|
|
156
156
|
/**
|
|
157
157
|
* Returns an individual party by its key.
|
|
158
158
|
*/
|
|
159
|
-
getParty (partyKey: PartyKey):
|
|
159
|
+
getParty (partyKey: PartyKey): Party | undefined {
|
|
160
160
|
return this._parties.get(partyKey);
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
queryParties (): ResultSet<
|
|
163
|
+
queryParties (): ResultSet<Party> {
|
|
164
164
|
return new ResultSet(this._partiesChanged, () => Array.from(this._parties.values()));
|
|
165
165
|
}
|
|
166
166
|
|
package/src/api/halo-proxy.ts
CHANGED
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { Event } from '@dxos/async';
|
|
6
|
+
import { KeyRecord } from '@dxos/credentials';
|
|
6
7
|
import { Contact, CreateProfileOptions, InvitationDescriptor, InvitationOptions, PartyMember, ResultSet } from '@dxos/echo-db';
|
|
7
8
|
import { SubscriptionGroup } from '@dxos/util';
|
|
8
9
|
|
|
9
10
|
import { ClientServiceProvider } from '../interfaces';
|
|
10
|
-
import { Profile } from '../proto/gen/dxos/client';
|
|
11
|
+
import { Profile, SignRequest } from '../proto/gen/dxos/client';
|
|
11
12
|
import { Invitation, InvitationProxy, InvitationRequest } from './invitations';
|
|
12
13
|
|
|
13
14
|
export interface CreateInvitationOptions extends InvitationOptions {
|
|
@@ -38,17 +39,6 @@ export class HaloProxy extends InvitationProxy {
|
|
|
38
39
|
return this._profile;
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
/**
|
|
42
|
-
* @deprecated Use `profile` instead.
|
|
43
|
-
*/
|
|
44
|
-
getProfile (): Profile | undefined {
|
|
45
|
-
return this._profile;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
hasProfile (): boolean {
|
|
49
|
-
return !!this.profile;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
42
|
/**
|
|
53
43
|
* Reset the identity and delete all key records.
|
|
54
44
|
*/
|
|
@@ -65,7 +55,7 @@ export class HaloProxy extends InvitationProxy {
|
|
|
65
55
|
/**
|
|
66
56
|
* Create Profile. Add Identity key if public and secret key are provided. Then initializes profile with given username.
|
|
67
57
|
* If not public and secret key are provided it relies on keyring to contain an identity key.
|
|
68
|
-
* @returns
|
|
58
|
+
* @returns User profile info.
|
|
69
59
|
*/
|
|
70
60
|
async createProfile ({ publicKey, secretKey, username }: CreateProfileOptions = {}): Promise<Profile> {
|
|
71
61
|
this._profile = await this._serviceProvider.services.ProfileService.CreateProfile({ publicKey, secretKey, username });
|
|
@@ -130,6 +120,14 @@ export class HaloProxy extends InvitationProxy {
|
|
|
130
120
|
);
|
|
131
121
|
}
|
|
132
122
|
|
|
123
|
+
async addKeyRecord (keyRecord: KeyRecord) {
|
|
124
|
+
await this._serviceProvider.services.HaloService.AddKeyRecord({ keyRecord });
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async sign (request: SignRequest) {
|
|
128
|
+
return await this._serviceProvider.services.HaloService.Sign(request);
|
|
129
|
+
}
|
|
130
|
+
|
|
133
131
|
/**
|
|
134
132
|
* Allocate resources and set-up internal subscriptions.
|
|
135
133
|
*
|
|
@@ -143,7 +141,7 @@ export class HaloProxy extends InvitationProxy {
|
|
|
143
141
|
}, () => {});
|
|
144
142
|
this._subscriptions.push(() => profileStream.close());
|
|
145
143
|
|
|
146
|
-
const contactsStream = this._serviceProvider.services.
|
|
144
|
+
const contactsStream = this._serviceProvider.services.HaloService.SubscribeContacts();
|
|
147
145
|
contactsStream.subscribe(data => {
|
|
148
146
|
this._contacts = data.contacts as PartyMember[];
|
|
149
147
|
this._contactsChanged.emit();
|
package/src/api/party-proxy.ts
CHANGED
|
@@ -13,7 +13,7 @@ import { ModelFactory } from '@dxos/model-factory';
|
|
|
13
13
|
import { ClientServiceHost } from '../client/service-host';
|
|
14
14
|
import { ClientServiceProxy } from '../client/service-proxy';
|
|
15
15
|
import { ClientServiceProvider } from '../interfaces';
|
|
16
|
-
import { Party } from '../proto/gen/dxos/client';
|
|
16
|
+
import { Party as PartyProto } from '../proto/gen/dxos/client';
|
|
17
17
|
import { streamToResultSet } from '../util';
|
|
18
18
|
import { InvitationRequest, InvitationProxy } from './invitations';
|
|
19
19
|
|
|
@@ -21,17 +21,20 @@ export interface CreationInvitationOptions {
|
|
|
21
21
|
inviteeKey?: PublicKey
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
export class
|
|
24
|
+
export class Party extends InvitationProxy {
|
|
25
25
|
private readonly _database?: Database;
|
|
26
26
|
|
|
27
27
|
private _key: PartyKey;
|
|
28
28
|
private _isOpen: boolean;
|
|
29
29
|
private _isActive: boolean;
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* @internal
|
|
33
|
+
*/
|
|
31
34
|
constructor (
|
|
32
35
|
private _serviceProvider: ClientServiceProvider,
|
|
33
36
|
private _modelFactory: ModelFactory,
|
|
34
|
-
_party:
|
|
37
|
+
_party: PartyProto
|
|
35
38
|
) {
|
|
36
39
|
super();
|
|
37
40
|
this._key = _party.publicKey;
|
|
@@ -72,7 +75,7 @@ export class PartyProxy extends InvitationProxy {
|
|
|
72
75
|
* Called by EchoProxy to update this party instance.
|
|
73
76
|
* @internal
|
|
74
77
|
*/
|
|
75
|
-
_processPartyUpdate (party:
|
|
78
|
+
_processPartyUpdate (party: PartyProto) {
|
|
76
79
|
this._key = party.publicKey;
|
|
77
80
|
this._isOpen = party.isOpen;
|
|
78
81
|
this._isActive = party.isActive;
|
|
@@ -7,7 +7,7 @@ import expect from 'expect';
|
|
|
7
7
|
import { it as test } from 'mocha';
|
|
8
8
|
|
|
9
9
|
import { sleep, waitForCondition } from '@dxos/async';
|
|
10
|
-
import {
|
|
10
|
+
import { ConfigV1Object } from '@dxos/config';
|
|
11
11
|
import { generateSeedPhrase, keyPairFromSeedPhrase } from '@dxos/crypto';
|
|
12
12
|
import { throwUnhandledRejection } from '@dxos/debug';
|
|
13
13
|
import { InvitationDescriptor } from '@dxos/echo-db';
|
|
@@ -61,10 +61,10 @@ describe('Client', () => {
|
|
|
61
61
|
afterTest(() => client.destroy());
|
|
62
62
|
|
|
63
63
|
await client.halo.createProfile({ username: 'test-user' });
|
|
64
|
-
expect(client.halo.
|
|
64
|
+
expect(!!client.halo.profile).toBeTruthy();
|
|
65
65
|
|
|
66
66
|
await expect(client.halo.createProfile({ username: 'test-user' })).rejects.toThrow();
|
|
67
|
-
expect(client.halo.
|
|
67
|
+
expect(!!client.halo.profile).toBeTruthy();
|
|
68
68
|
});
|
|
69
69
|
|
|
70
70
|
test('Recovers a profile with a seed phrase', async () => {
|
|
@@ -87,7 +87,7 @@ describe('Client', () => {
|
|
|
87
87
|
afterTest(() => recoveredClient.destroy());
|
|
88
88
|
|
|
89
89
|
await recoveredClient.halo.recoverProfile(seedPhrase);
|
|
90
|
-
await waitForCondition(() => !!recoveredClient.halo.
|
|
90
|
+
await waitForCondition(() => !!recoveredClient.halo.profile, 2000);
|
|
91
91
|
|
|
92
92
|
expect(recoveredClient.halo.profile).toBeDefined();
|
|
93
93
|
expect(recoveredClient.halo.profile!.publicKey).toEqual(client.halo.profile!.publicKey);
|
|
@@ -276,11 +276,14 @@ describe('Client', () => {
|
|
|
276
276
|
});
|
|
277
277
|
|
|
278
278
|
test('late-register models after refresh', async () => {
|
|
279
|
-
const config:
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
279
|
+
const config: ConfigV1Object = {
|
|
280
|
+
version: 1,
|
|
281
|
+
runtime: {
|
|
282
|
+
client: {
|
|
283
|
+
storage: {
|
|
284
|
+
persistent: true,
|
|
285
|
+
path: `/tmp/dxos-${Date.now()}`
|
|
286
|
+
}
|
|
284
287
|
}
|
|
285
288
|
}
|
|
286
289
|
};
|
|
@@ -300,7 +303,7 @@ describe('Client', () => {
|
|
|
300
303
|
{
|
|
301
304
|
const client = new Client(config);
|
|
302
305
|
await client.initialize();
|
|
303
|
-
await waitForCondition(() => client.halo.
|
|
306
|
+
await waitForCondition(() => !!client.halo.profile);
|
|
304
307
|
await sleep(10); // Make sure all events were processed.
|
|
305
308
|
|
|
306
309
|
client.registerModel(TestModel);
|
package/src/client/client.ts
CHANGED
|
@@ -6,7 +6,7 @@ import assert from 'assert';
|
|
|
6
6
|
import debug from 'debug';
|
|
7
7
|
|
|
8
8
|
import { synchronized } from '@dxos/async';
|
|
9
|
-
import { Config,
|
|
9
|
+
import { Config, ConfigV1Object } from '@dxos/config';
|
|
10
10
|
import { InvalidParameterError, TimeoutError } from '@dxos/debug';
|
|
11
11
|
import { OpenProgress, sortItemsTopologically } from '@dxos/echo-db';
|
|
12
12
|
import { DatabaseSnapshot } from '@dxos/echo-protocol';
|
|
@@ -17,6 +17,7 @@ import { RpcPort } from '@dxos/rpc';
|
|
|
17
17
|
import { EchoProxy, HaloProxy } from '../api';
|
|
18
18
|
import { DevtoolsHook } from '../devtools';
|
|
19
19
|
import { ClientServiceProvider, ClientServices, RemoteServiceConnectionTimeout } from '../interfaces';
|
|
20
|
+
import { InvalidConfigurationError } from '../interfaces/errors';
|
|
20
21
|
import { System } from '../proto/gen/dxos/config';
|
|
21
22
|
import { createWindowMessagePort, isNode } from '../util';
|
|
22
23
|
import { ClientServiceHost } from './service-host';
|
|
@@ -24,12 +25,17 @@ import { ClientServiceProxy } from './service-proxy';
|
|
|
24
25
|
|
|
25
26
|
const log = debug('dxos:client');
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
const EXPECTED_CONFIG_VERSION = 1;
|
|
28
29
|
|
|
29
|
-
export const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
export const defaultConfig: ConfigV1Object = { version: 1 };
|
|
31
|
+
|
|
32
|
+
export const defaultTestingConfig: ConfigV1Object = {
|
|
33
|
+
version: 1,
|
|
34
|
+
runtime: {
|
|
35
|
+
services: {
|
|
36
|
+
signal: {
|
|
37
|
+
server: 'ws://localhost:4000'
|
|
38
|
+
}
|
|
33
39
|
}
|
|
34
40
|
}
|
|
35
41
|
};
|
|
@@ -63,19 +69,23 @@ export class Client {
|
|
|
63
69
|
* Creates the client object based on supplied configuration.
|
|
64
70
|
* Requires initialization after creating by calling `.initialize()`.
|
|
65
71
|
*/
|
|
66
|
-
constructor (config:
|
|
72
|
+
constructor (config: ConfigV1Object | Config = { version: 1 }, options: ClientOptions = {}) {
|
|
67
73
|
if (typeof config !== 'object' || config == null) {
|
|
68
74
|
throw new InvalidParameterError('Invalid config.');
|
|
69
75
|
}
|
|
70
76
|
this._config = (config instanceof Config) ? config : new Config(config);
|
|
71
77
|
|
|
78
|
+
if (Object.keys(this._config.values).length > 0 && this._config.values.version !== EXPECTED_CONFIG_VERSION) {
|
|
79
|
+
throw new InvalidConfigurationError(`Expected config version 1, got ${this._config.values.version}.`);
|
|
80
|
+
}
|
|
81
|
+
|
|
72
82
|
this._options = options;
|
|
73
83
|
|
|
74
84
|
// TODO(burdon): Default error level: 'dxos:*:error'
|
|
75
85
|
// TODO(burdon): config.getProperty('system.debug', process.env.DEBUG, '');
|
|
76
|
-
debug.enable(this._config.values.system?.debug ?? process.env.DEBUG ?? 'dxos:*:error');
|
|
86
|
+
debug.enable(this._config.values.runtime?.system?.debug ?? process.env.DEBUG ?? 'dxos:*:error');
|
|
77
87
|
|
|
78
|
-
this._mode = this._config.get('
|
|
88
|
+
this._mode = this._config.get('runtime.client.mode', System.Mode.AUTOMATIC)!;
|
|
79
89
|
log(`mode=${System.Mode[this._mode]}`);
|
|
80
90
|
}
|
|
81
91
|
|
|
@@ -6,7 +6,7 @@ import expect from 'expect';
|
|
|
6
6
|
import { it as test } from 'mocha';
|
|
7
7
|
|
|
8
8
|
import { waitForCondition } from '@dxos/async';
|
|
9
|
-
import {
|
|
9
|
+
import { ConfigV1Object } from '@dxos/config';
|
|
10
10
|
|
|
11
11
|
import { Client } from './client';
|
|
12
12
|
|
|
@@ -31,11 +31,14 @@ describe('Client', () => {
|
|
|
31
31
|
|
|
32
32
|
describe('With persistent storage', () => {
|
|
33
33
|
test('persistent storage', async () => {
|
|
34
|
-
const config:
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
const config: ConfigV1Object = {
|
|
35
|
+
version: 1,
|
|
36
|
+
runtime: {
|
|
37
|
+
client: {
|
|
38
|
+
storage: {
|
|
39
|
+
persistent: true,
|
|
40
|
+
path: `/tmp/dxos-${Date.now()}`
|
|
41
|
+
}
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
44
|
};
|
|
@@ -54,7 +57,7 @@ describe('Client', () => {
|
|
|
54
57
|
{
|
|
55
58
|
const client = new Client(config);
|
|
56
59
|
await client.initialize();
|
|
57
|
-
await waitForCondition(() => client.halo.
|
|
60
|
+
await waitForCondition(() => !!client.halo.profile);
|
|
58
61
|
|
|
59
62
|
expect(client.halo.profile).toBeDefined();
|
|
60
63
|
await client.destroy();
|
|
@@ -20,8 +20,8 @@ export class ClientServiceHost implements ClientServiceProvider {
|
|
|
20
20
|
private readonly _config: Config
|
|
21
21
|
) {
|
|
22
22
|
const { feedStorage, keyStorage, snapshotStorage, metadataStorage } = createStorageObjects(
|
|
23
|
-
this._config.get('
|
|
24
|
-
this._config.get('
|
|
23
|
+
this._config.get('runtime.client.storage', {})!,
|
|
24
|
+
this._config.get('runtime.client.enableSnapshots', false)
|
|
25
25
|
);
|
|
26
26
|
|
|
27
27
|
this._echo = new ECHO({
|
|
@@ -30,12 +30,12 @@ export class ClientServiceHost implements ClientServiceProvider {
|
|
|
30
30
|
snapshotStorage,
|
|
31
31
|
metadataStorage,
|
|
32
32
|
networkManagerOptions: {
|
|
33
|
-
signal: this._config.get('services.signal.server') ? [this._config.get('services.signal.server')!] : undefined,
|
|
34
|
-
ice: this._config.get('services.ice'),
|
|
33
|
+
signal: this._config.get('runtime.services.signal.server') ? [this._config.get('runtime.services.signal.server')!] : undefined,
|
|
34
|
+
ice: this._config.get('runtime.services.ice'),
|
|
35
35
|
log: true
|
|
36
36
|
},
|
|
37
|
-
snapshots: this._config.get('
|
|
38
|
-
snapshotInterval: this._config.get('
|
|
37
|
+
snapshots: this._config.get('runtime.client.enableSnapshots', false),
|
|
38
|
+
snapshotInterval: this._config.get('runtime.client.snapshotInterval')
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
this.services = {
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import PolkadotKeyring from '@polkadot/keyring';
|
|
6
|
+
import { hexToU8a, u8aToHex } from '@polkadot/util';
|
|
7
|
+
import { cryptoWaitReady } from '@polkadot/util-crypto';
|
|
8
|
+
import assert from 'assert';
|
|
9
|
+
|
|
10
|
+
import { Stream } from '@dxos/codec-protobuf';
|
|
11
|
+
import { KeyRecord, KeyType } from '@dxos/credentials';
|
|
12
|
+
import { ECHO } from '@dxos/echo-db';
|
|
13
|
+
import { SubscriptionGroup } from '@dxos/util';
|
|
14
|
+
|
|
15
|
+
import { AddKeyRecordRequest, Contacts, HaloService as IHaloService, SignRequest, SignResponse } from '../../../proto/gen/dxos/client';
|
|
16
|
+
import { resultSetToStream } from '../../../util';
|
|
17
|
+
import { CreateServicesOpts } from './interfaces';
|
|
18
|
+
|
|
19
|
+
export class HaloService implements IHaloService {
|
|
20
|
+
constructor (private echo: ECHO) {}
|
|
21
|
+
|
|
22
|
+
SubscribeContacts (): Stream<Contacts> {
|
|
23
|
+
if (this.echo.halo.isInitialized) {
|
|
24
|
+
return resultSetToStream(this.echo.halo.queryContacts(), (contacts): Contacts => ({ contacts }));
|
|
25
|
+
} else {
|
|
26
|
+
return new Stream(({ next }) => {
|
|
27
|
+
const subGroup = new SubscriptionGroup();
|
|
28
|
+
|
|
29
|
+
setImmediate(async () => {
|
|
30
|
+
await this.echo.halo.identityReady.waitForCondition(() => this.echo.halo.isInitialized);
|
|
31
|
+
|
|
32
|
+
const resultSet = this.echo.halo.queryContacts();
|
|
33
|
+
next({ contacts: resultSet.value });
|
|
34
|
+
subGroup.push(resultSet.update.on(() => next({ contacts: resultSet.value })));
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return () => subGroup.unsubscribe();
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async AddKeyRecord (request: AddKeyRecordRequest): Promise<void> {
|
|
43
|
+
assert(request.keyRecord && request.keyRecord.publicKey, 'Missing key record.');
|
|
44
|
+
await this.echo.halo.keyring.addKeyRecord(request.keyRecord);
|
|
45
|
+
assert(await this.echo.halo.keyring.getKey(request.keyRecord.publicKey), 'Key not inserted correctly.');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private async polkadotSign (key: KeyRecord, payload: SignRequest['payload']): Promise<SignResponse> {
|
|
49
|
+
await cryptoWaitReady();
|
|
50
|
+
|
|
51
|
+
assert(key.secretKey, 'Secret key is missing.');
|
|
52
|
+
|
|
53
|
+
const keyring = new PolkadotKeyring({ type: 'sr25519' });
|
|
54
|
+
const keypair = keyring.addFromUri(key.secretKey.toString());
|
|
55
|
+
|
|
56
|
+
const signature = u8aToHex(keypair.sign(hexToU8a(payload), { withType: true }));
|
|
57
|
+
return {
|
|
58
|
+
signed: signature
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async Sign (request: SignRequest): Promise<SignResponse> {
|
|
63
|
+
assert(request.publicKey, 'Provide a publicKey of the key that should be used for signing.');
|
|
64
|
+
const key = await this.echo.halo.keyring.getFullKey(request.publicKey);
|
|
65
|
+
assert(key, 'Key not found.');
|
|
66
|
+
if (key.type === KeyType.DXNS) {
|
|
67
|
+
return this.polkadotSign(key, request.payload);
|
|
68
|
+
}
|
|
69
|
+
throw new Error('Only DXNS key signing is supported.');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export const createHaloService = ({ echo }: CreateServicesOpts): HaloService => {
|
|
74
|
+
return new HaloService(echo);
|
|
75
|
+
};
|
|
@@ -8,8 +8,8 @@ import { v4 } from 'uuid';
|
|
|
8
8
|
import { latch } from '@dxos/async';
|
|
9
9
|
import { Stream } from '@dxos/codec-protobuf';
|
|
10
10
|
import { defaultSecretValidator, generatePasscode, SecretProvider } from '@dxos/credentials';
|
|
11
|
-
import { raise } from '@dxos/debug';
|
|
12
|
-
import { ECHO,
|
|
11
|
+
import { InvalidStateError, raise } from '@dxos/debug';
|
|
12
|
+
import { ECHO, InvitationDescriptor, InvitationDescriptorType, PartyNotFoundError } from '@dxos/echo-db';
|
|
13
13
|
|
|
14
14
|
import {
|
|
15
15
|
InvitationState,
|
|
@@ -50,7 +50,7 @@ class PartyService implements IPartyService {
|
|
|
50
50
|
}
|
|
51
51
|
});
|
|
52
52
|
} catch (error) {
|
|
53
|
-
if (error instanceof
|
|
53
|
+
if (error instanceof InvalidStateError) {
|
|
54
54
|
// Do nothing.
|
|
55
55
|
} else {
|
|
56
56
|
throw error;
|
|
@@ -156,7 +156,7 @@ class PartyService implements IPartyService {
|
|
|
156
156
|
next({ state: InvitationState.CONNECTED });
|
|
157
157
|
return Buffer.from(secret);
|
|
158
158
|
};
|
|
159
|
-
invitation = await party.createInvitation({
|
|
159
|
+
invitation = await party.invitationManager.createInvitation({
|
|
160
160
|
secretProvider,
|
|
161
161
|
secretValidator: defaultSecretValidator
|
|
162
162
|
}, {
|
|
@@ -169,7 +169,7 @@ class PartyService implements IPartyService {
|
|
|
169
169
|
assert(invitation.type === InvitationDescriptorType.INTERACTIVE);
|
|
170
170
|
invitation.secret = Buffer.from(secret);
|
|
171
171
|
} else {
|
|
172
|
-
invitation = await party.createOfflineInvitation(request.inviteeKey);
|
|
172
|
+
invitation = await party.invitationManager.createOfflineInvitation(request.inviteeKey);
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
next({ state: InvitationState.WAITING_FOR_CONNECTION, descriptor: invitation.toProto() });
|
|
@@ -256,7 +256,7 @@ class PartyService implements IPartyService {
|
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
-
CreateSnapshot (request: CreateSnaspotRequest): Promise<PartySnapshot> {
|
|
259
|
+
async CreateSnapshot (request: CreateSnaspotRequest): Promise<PartySnapshot> {
|
|
260
260
|
assert(request.partyKey);
|
|
261
261
|
const party = this.echo.getParty(request.partyKey) ?? raise(new PartyNotFoundError(request.partyKey));
|
|
262
262
|
return party.createSnapshot();
|
|
@@ -9,22 +9,11 @@ import { latch } from '@dxos/async';
|
|
|
9
9
|
import { Stream } from '@dxos/codec-protobuf';
|
|
10
10
|
import { defaultSecretValidator, generatePasscode, SecretProvider } from '@dxos/credentials';
|
|
11
11
|
import { ECHO, InvitationDescriptor } from '@dxos/echo-db';
|
|
12
|
-
import { SubscriptionGroup } from '@dxos/util';
|
|
13
12
|
|
|
14
13
|
import {
|
|
15
|
-
InvitationState,
|
|
16
|
-
ProfileService as IProfileService,
|
|
17
|
-
AuthenticateInvitationRequest,
|
|
18
|
-
SubscribeProfileResponse,
|
|
19
|
-
InvitationRequest,
|
|
20
|
-
CreateProfileRequest,
|
|
21
|
-
Contacts,
|
|
22
|
-
RedeemedInvitation,
|
|
23
|
-
Profile
|
|
24
|
-
, RecoverProfileRequest
|
|
14
|
+
AuthenticateInvitationRequest, CreateProfileRequest, InvitationRequest, InvitationState, Profile, ProfileService as IProfileService, RecoverProfileRequest, RedeemedInvitation, SubscribeProfileResponse
|
|
25
15
|
} from '../../../proto/gen/dxos/client';
|
|
26
16
|
import { InvitationDescriptor as InvitationDescriptorProto } from '../../../proto/gen/dxos/echo/invitation';
|
|
27
|
-
import { resultSetToStream } from '../../../util';
|
|
28
17
|
import { CreateServicesOpts, InviteeInvitation, InviteeInvitations } from './interfaces';
|
|
29
18
|
|
|
30
19
|
export class ProfileService implements IProfileService {
|
|
@@ -122,26 +111,6 @@ export class ProfileService implements IProfileService {
|
|
|
122
111
|
invitation.secret = request.secret;
|
|
123
112
|
invitation.secretTrigger?.();
|
|
124
113
|
}
|
|
125
|
-
|
|
126
|
-
SubscribeContacts (): Stream<Contacts> {
|
|
127
|
-
if (this.echo.halo.isInitialized) {
|
|
128
|
-
return resultSetToStream(this.echo.halo.queryContacts(), (contacts): Contacts => ({ contacts }));
|
|
129
|
-
} else {
|
|
130
|
-
return new Stream(({ next }) => {
|
|
131
|
-
const subGroup = new SubscriptionGroup();
|
|
132
|
-
|
|
133
|
-
setImmediate(async () => {
|
|
134
|
-
await this.echo.halo.identityReady.waitForCondition(() => this.echo.halo.isInitialized);
|
|
135
|
-
|
|
136
|
-
const resultSet = this.echo.halo.queryContacts();
|
|
137
|
-
next({ contacts: resultSet.value });
|
|
138
|
-
subGroup.push(resultSet.update.on(() => next({ contacts: resultSet.value })));
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
return () => subGroup.unsubscribe();
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
114
|
}
|
|
146
115
|
|
|
147
116
|
export const createProfileService = ({ echo }: CreateServicesOpts): ProfileService => {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { ClientServices } from '../../../interfaces';
|
|
6
|
+
import { createHaloService } from './halo';
|
|
6
7
|
import { CreateServicesOpts } from './interfaces';
|
|
7
8
|
import { createPartyService } from './party';
|
|
8
9
|
import { createProfileService } from './profile';
|
|
@@ -12,6 +13,7 @@ export const createServices = (opts: CreateServicesOpts): Omit<ClientServices, '
|
|
|
12
13
|
return {
|
|
13
14
|
SystemService: createSystemService(opts),
|
|
14
15
|
ProfileService: createProfileService(opts),
|
|
16
|
+
HaloService: createHaloService(opts),
|
|
15
17
|
PartyService: createPartyService(opts),
|
|
16
18
|
DataService: opts.echo.dataService,
|
|
17
19
|
TracingService: {
|
package/src/index.ts
CHANGED
|
@@ -9,3 +9,18 @@ export * from './devtools/devtools-context';
|
|
|
9
9
|
export * from './devtools/devtools-host-events';
|
|
10
10
|
export * from './util';
|
|
11
11
|
export * as proto from './proto/gen';
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
Entity,
|
|
15
|
+
Item,
|
|
16
|
+
Link,
|
|
17
|
+
Database,
|
|
18
|
+
Selection,
|
|
19
|
+
SelectionResult,
|
|
20
|
+
InvitationDescriptor,
|
|
21
|
+
InvitationDescriptorType,
|
|
22
|
+
OpenProgress,
|
|
23
|
+
PartyMember,
|
|
24
|
+
ResultSet,
|
|
25
|
+
PARTY_ITEM_TYPE
|
|
26
|
+
} from '@dxos/echo-db';
|
|
@@ -7,13 +7,14 @@ import { DataService, schema as schemaProtocol } from '@dxos/echo-protocol';
|
|
|
7
7
|
import { createServiceBundle } from '@dxos/rpc';
|
|
8
8
|
|
|
9
9
|
import { schema } from '../proto/gen';
|
|
10
|
-
import { PartyService, ProfileService, SystemService } from '../proto/gen/dxos/client';
|
|
10
|
+
import { PartyService, ProfileService, SystemService, HaloService } from '../proto/gen/dxos/client';
|
|
11
11
|
import { DevtoolsHost, TracingService } from '../proto/gen/dxos/devtools';
|
|
12
12
|
|
|
13
13
|
// TODO(burdon): Is there a way to mark TS (generics) so cast isn't required for result of stream?
|
|
14
14
|
export interface ClientServices {
|
|
15
15
|
SystemService: SystemService;
|
|
16
16
|
ProfileService: ProfileService;
|
|
17
|
+
HaloService: HaloService;
|
|
17
18
|
PartyService: PartyService;
|
|
18
19
|
DataService: DataService;
|
|
19
20
|
DevtoolsHost: DevtoolsHost;
|
|
@@ -24,6 +25,7 @@ export const clientServiceBundle = createServiceBundle<ClientServices>({
|
|
|
24
25
|
SystemService: schema.getService('dxos.client.SystemService'),
|
|
25
26
|
ProfileService: schema.getService('dxos.client.ProfileService'),
|
|
26
27
|
PartyService: schema.getService('dxos.client.PartyService'),
|
|
28
|
+
HaloService: schema.getService('dxos.client.HaloService'),
|
|
27
29
|
// DataService is provided and implemented internally in ECHO so we import it from there.
|
|
28
30
|
DataService: schemaProtocol.getService('dxos.echo.service.DataService'),
|
|
29
31
|
DevtoolsHost: schema.getService('dxos.devtools.DevtoolsHost'),
|