@dxos/client 2.24.1-dev.98738ed5 → 2.25.1-dev.839e2254
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.map +1 -1
- package/dist/src/api/echo-proxy.js +9 -7
- package/dist/src/api/echo-proxy.js.map +1 -1
- package/dist/src/api/halo-proxy.d.ts +4 -1
- package/dist/src/api/halo-proxy.d.ts.map +1 -1
- package/dist/src/api/halo-proxy.js +18 -9
- package/dist/src/api/halo-proxy.js.map +1 -1
- package/dist/src/api/party-proxy.d.ts +5 -1
- package/dist/src/api/party-proxy.d.ts.map +1 -1
- package/dist/src/api/party-proxy.js +12 -6
- package/dist/src/api/party-proxy.js.map +1 -1
- package/dist/src/client/client-services.test.js +5 -5
- package/dist/src/client/client.js +3 -3
- package/dist/src/client/client.js.map +1 -1
- package/dist/src/client/client.test.js +2 -2
- package/dist/src/client/client.test.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 +73 -0
- package/dist/src/client/service-host/services/halo.js.map +1 -0
- package/dist/src/client/service-host/services/party.d.ts +10 -10
- package/dist/src/client/service-host/services/party.js +10 -10
- package/dist/src/client/service-host/services/profile.d.ts +7 -8
- package/dist/src/client/service-host/services/profile.d.ts.map +1 -1
- package/dist/src/client/service-host/services/profile.js +6 -25
- 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 +4 -2
- package/dist/src/client/service-host/services/services.js.map +1 -1
- package/dist/src/client/service-host/services/system.js +2 -2
- package/dist/src/devtools/devtools-host.js +19 -19
- package/dist/src/devtools/items.js +2 -2
- package/dist/src/devtools/items.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 +52 -34
- 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/devtools.d.ts +21 -21
- package/dist/src/proto/gen/dxos/echo/service.d.ts +3 -3
- 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 +22 -19
- package/src/api/echo-proxy.ts +11 -7
- package/src/api/halo-proxy.ts +24 -10
- package/src/api/party-proxy.ts +14 -7
- package/src/client/client-services.test.ts +5 -5
- package/src/client/client.test.ts +2 -2
- package/src/client/client.ts +3 -3
- package/src/client/service-host/services/halo.ts +80 -0
- package/src/client/service-host/services/party.ts +10 -10
- package/src/client/service-host/services/profile.ts +7 -38
- package/src/client/service-host/services/services.ts +4 -2
- package/src/client/service-host/services/system.ts +2 -2
- package/src/devtools/devtools-host.ts +19 -19
- package/src/devtools/items.ts +2 -2
- package/src/interfaces/client-service-provider.ts +3 -1
- package/src/proto/gen/dxos/client.ts +51 -34
- package/src/proto/gen/dxos/devtools.ts +21 -21
- package/src/proto/gen/dxos/echo/service.ts +3 -3
- 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.25.1-dev.839e2254",
|
|
4
4
|
"license": "AGPL-3.0",
|
|
5
5
|
"author": "DXOS.org",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -10,21 +10,24 @@
|
|
|
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.25.1-dev.839e2254",
|
|
14
|
+
"@dxos/codec-protobuf": "2.25.1-dev.839e2254",
|
|
15
|
+
"@dxos/config": "2.25.1-dev.839e2254",
|
|
16
|
+
"@dxos/credentials": "2.25.1-dev.839e2254",
|
|
17
|
+
"@dxos/crypto": "2.25.1-dev.839e2254",
|
|
18
|
+
"@dxos/debug": "2.25.1-dev.839e2254",
|
|
19
|
+
"@dxos/echo-db": "2.25.1-dev.839e2254",
|
|
20
|
+
"@dxos/echo-protocol": "2.25.1-dev.839e2254",
|
|
21
|
+
"@dxos/feed-store": "2.25.1-dev.839e2254",
|
|
22
|
+
"@dxos/model-factory": "2.25.1-dev.839e2254",
|
|
23
|
+
"@dxos/network-manager": "2.25.1-dev.839e2254",
|
|
24
|
+
"@dxos/object-model": "2.25.1-dev.839e2254",
|
|
25
|
+
"@dxos/proto": "2.25.1-dev.839e2254",
|
|
26
|
+
"@dxos/rpc": "2.25.1-dev.839e2254",
|
|
27
|
+
"@dxos/util": "2.25.1-dev.839e2254",
|
|
28
|
+
"@polkadot/keyring": "6.11.1",
|
|
29
|
+
"@polkadot/util": "6.11.1",
|
|
30
|
+
"@polkadot/util-crypto": "6.11.1",
|
|
28
31
|
"@wirelineio/registry-client": "~1.1.0-beta.3",
|
|
29
32
|
"abstract-leveldown": "~7.0.0",
|
|
30
33
|
"assert": "^2.0.0",
|
|
@@ -38,9 +41,9 @@
|
|
|
38
41
|
"uuid": "^8.3.2"
|
|
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.25.1-dev.839e2254",
|
|
45
|
+
"@dxos/testutils": "2.25.0",
|
|
46
|
+
"@dxos/toolchain-node-library": "2.25.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
|
@@ -63,8 +63,10 @@ export class EchoProxy {
|
|
|
63
63
|
/**
|
|
64
64
|
* @internal
|
|
65
65
|
*/
|
|
66
|
-
_open () {
|
|
67
|
-
const
|
|
66
|
+
async _open () {
|
|
67
|
+
const gotParties = this._partiesChanged.waitForCount(1);
|
|
68
|
+
|
|
69
|
+
const partiesStream = this._serviceProvider.services.PartyService.subscribeParties();
|
|
68
70
|
partiesStream.subscribe(async data => {
|
|
69
71
|
for (const party of data.parties ?? []) {
|
|
70
72
|
if (!this._parties.has(party.publicKey)) {
|
|
@@ -79,7 +81,7 @@ export class EchoProxy {
|
|
|
79
81
|
}
|
|
80
82
|
});
|
|
81
83
|
|
|
82
|
-
const partyStream = this._serviceProvider.services.PartyService.
|
|
84
|
+
const partyStream = this._serviceProvider.services.PartyService.subscribeToParty({ partyKey: party.publicKey });
|
|
83
85
|
partyStream.subscribe(async ({ party }) => {
|
|
84
86
|
if (!party) {
|
|
85
87
|
return;
|
|
@@ -94,6 +96,8 @@ export class EchoProxy {
|
|
|
94
96
|
this._partiesChanged.emit();
|
|
95
97
|
}, () => {});
|
|
96
98
|
this._subscriptions.push(() => partiesStream.close());
|
|
99
|
+
|
|
100
|
+
await gotParties;
|
|
97
101
|
}
|
|
98
102
|
|
|
99
103
|
/**
|
|
@@ -117,7 +121,7 @@ export class EchoProxy {
|
|
|
117
121
|
async createParty (): Promise<Party> {
|
|
118
122
|
const [partyReceivedPromise, partyReceived] = latch();
|
|
119
123
|
|
|
120
|
-
const party = await this._serviceProvider.services.PartyService.
|
|
124
|
+
const party = await this._serviceProvider.services.PartyService.createParty();
|
|
121
125
|
|
|
122
126
|
const handler = () => {
|
|
123
127
|
if (this._parties.has(party.publicKey)) {
|
|
@@ -138,7 +142,7 @@ export class EchoProxy {
|
|
|
138
142
|
async cloneParty (snapshot: PartySnapshot): Promise<Party> {
|
|
139
143
|
const [partyReceivedPromise, partyReceived] = latch();
|
|
140
144
|
|
|
141
|
-
const party = await this._serviceProvider.services.PartyService.
|
|
145
|
+
const party = await this._serviceProvider.services.PartyService.cloneParty(snapshot);
|
|
142
146
|
|
|
143
147
|
const handler = () => {
|
|
144
148
|
if (this._parties.has(party.publicKey)) {
|
|
@@ -170,12 +174,12 @@ export class EchoProxy {
|
|
|
170
174
|
* To be used with `party.createInvitation` on the inviter side.
|
|
171
175
|
*/
|
|
172
176
|
acceptInvitation (invitationDescriptor: InvitationDescriptor): PartyInvitation {
|
|
173
|
-
const invitationProcessStream = this._serviceProvider.services.PartyService.
|
|
177
|
+
const invitationProcessStream = this._serviceProvider.services.PartyService.acceptInvitation(invitationDescriptor.toProto());
|
|
174
178
|
const { authenticate, waitForFinish } = InvitationProxy.handleInvitationRedemption({
|
|
175
179
|
stream: invitationProcessStream,
|
|
176
180
|
invitationDescriptor,
|
|
177
181
|
onAuthenticate: async (request) => {
|
|
178
|
-
await this._serviceProvider.services.PartyService.
|
|
182
|
+
await this._serviceProvider.services.PartyService.authenticateInvitation(request);
|
|
179
183
|
}
|
|
180
184
|
});
|
|
181
185
|
|
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 {
|
|
@@ -42,7 +43,7 @@ export class HaloProxy extends InvitationProxy {
|
|
|
42
43
|
* Reset the identity and delete all key records.
|
|
43
44
|
*/
|
|
44
45
|
async reset () {
|
|
45
|
-
await this._serviceProvider.services.SystemService.
|
|
46
|
+
await this._serviceProvider.services.SystemService.reset();
|
|
46
47
|
this._profileChanged.emit();
|
|
47
48
|
}
|
|
48
49
|
|
|
@@ -57,7 +58,7 @@ export class HaloProxy extends InvitationProxy {
|
|
|
57
58
|
* @returns User profile info.
|
|
58
59
|
*/
|
|
59
60
|
async createProfile ({ publicKey, secretKey, username }: CreateProfileOptions = {}): Promise<Profile> {
|
|
60
|
-
this._profile = await this._serviceProvider.services.ProfileService.
|
|
61
|
+
this._profile = await this._serviceProvider.services.ProfileService.createProfile({ publicKey, secretKey, username });
|
|
61
62
|
return this._profile;
|
|
62
63
|
}
|
|
63
64
|
|
|
@@ -72,7 +73,7 @@ export class HaloProxy extends InvitationProxy {
|
|
|
72
73
|
* Joins an existing identity HALO from a recovery seed phrase.
|
|
73
74
|
*/
|
|
74
75
|
async recoverProfile (seedPhrase: string) {
|
|
75
|
-
this._profile = await this._serviceProvider.services.ProfileService.
|
|
76
|
+
this._profile = await this._serviceProvider.services.ProfileService.recoverProfile({ seedPhrase });
|
|
76
77
|
return this._profile;
|
|
77
78
|
}
|
|
78
79
|
|
|
@@ -85,7 +86,7 @@ export class HaloProxy extends InvitationProxy {
|
|
|
85
86
|
* To be used with `client.halo.joinHaloInvitation` on the invitee side.
|
|
86
87
|
*/
|
|
87
88
|
async createInvitation (): Promise<InvitationRequest> {
|
|
88
|
-
const stream = await this._serviceProvider.services.ProfileService.
|
|
89
|
+
const stream = await this._serviceProvider.services.ProfileService.createInvitation();
|
|
89
90
|
return this.createInvitationRequest({ stream });
|
|
90
91
|
}
|
|
91
92
|
|
|
@@ -98,12 +99,12 @@ export class HaloProxy extends InvitationProxy {
|
|
|
98
99
|
* To be used with `client.halo.createHaloInvitation` on the inviter side.
|
|
99
100
|
*/
|
|
100
101
|
acceptInvitation (invitationDescriptor: InvitationDescriptor): Invitation {
|
|
101
|
-
const invitationProcessStream = this._serviceProvider.services.ProfileService.
|
|
102
|
+
const invitationProcessStream = this._serviceProvider.services.ProfileService.acceptInvitation(invitationDescriptor.toProto());
|
|
102
103
|
const { authenticate, waitForFinish } = InvitationProxy.handleInvitationRedemption({
|
|
103
104
|
stream: invitationProcessStream,
|
|
104
105
|
invitationDescriptor,
|
|
105
106
|
onAuthenticate: async (request) => {
|
|
106
|
-
await this._serviceProvider.services.ProfileService.
|
|
107
|
+
await this._serviceProvider.services.ProfileService.authenticateInvitation(request);
|
|
107
108
|
}
|
|
108
109
|
});
|
|
109
110
|
|
|
@@ -119,25 +120,38 @@ export class HaloProxy extends InvitationProxy {
|
|
|
119
120
|
);
|
|
120
121
|
}
|
|
121
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
|
+
|
|
122
131
|
/**
|
|
123
132
|
* Allocate resources and set-up internal subscriptions.
|
|
124
133
|
*
|
|
125
134
|
* @internal
|
|
126
135
|
*/
|
|
127
|
-
_open () {
|
|
128
|
-
const
|
|
136
|
+
async _open () {
|
|
137
|
+
const gotProfile = this._profileChanged.waitForCount(1);
|
|
138
|
+
const gotContacts = this._contactsChanged.waitForCount(1);
|
|
139
|
+
|
|
140
|
+
const profileStream = this._serviceProvider.services.ProfileService.subscribeProfile();
|
|
129
141
|
profileStream.subscribe(data => {
|
|
130
142
|
this._profile = data.profile;
|
|
131
143
|
this._profileChanged.emit();
|
|
132
144
|
}, () => {});
|
|
133
145
|
this._subscriptions.push(() => profileStream.close());
|
|
134
146
|
|
|
135
|
-
const contactsStream = this._serviceProvider.services.
|
|
147
|
+
const contactsStream = this._serviceProvider.services.HaloService.subscribeContacts();
|
|
136
148
|
contactsStream.subscribe(data => {
|
|
137
149
|
this._contacts = data.contacts as PartyMember[];
|
|
138
150
|
this._contactsChanged.emit();
|
|
139
151
|
}, () => {});
|
|
140
152
|
this._subscriptions.push(() => contactsStream.close());
|
|
153
|
+
|
|
154
|
+
await Promise.all([gotProfile, gotContacts]);
|
|
141
155
|
}
|
|
142
156
|
|
|
143
157
|
/**
|
package/src/api/party-proxy.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { PublicKey } from '@dxos/crypto';
|
|
6
6
|
import { failUndefined } from '@dxos/debug';
|
|
7
7
|
import {
|
|
8
|
-
ActivationOptions, Database, PARTY_ITEM_TYPE, PARTY_TITLE_PROPERTY, RemoteDatabaseBackend
|
|
8
|
+
ActivationOptions, Database, PARTY_ITEM_TYPE, PARTY_TITLE_PROPERTY, RemoteDatabaseBackend, RootSelector
|
|
9
9
|
} from '@dxos/echo-db';
|
|
10
10
|
import { PartyKey } from '@dxos/echo-protocol';
|
|
11
11
|
import { ModelFactory } from '@dxos/model-factory';
|
|
@@ -109,7 +109,7 @@ export class Party extends InvitationProxy {
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
async setOpen (open: boolean) {
|
|
112
|
-
await this._serviceProvider.services.PartyService.
|
|
112
|
+
await this._serviceProvider.services.PartyService.setPartyState({
|
|
113
113
|
partyKey: this.key,
|
|
114
114
|
open
|
|
115
115
|
});
|
|
@@ -118,13 +118,20 @@ export class Party extends InvitationProxy {
|
|
|
118
118
|
async setActive (active: boolean, options: ActivationOptions) {
|
|
119
119
|
const activeGlobal = options.global ? active : undefined;
|
|
120
120
|
const activeDevice = options.device ? active : undefined;
|
|
121
|
-
await this._serviceProvider.services.PartyService.
|
|
121
|
+
await this._serviceProvider.services.PartyService.setPartyState({
|
|
122
122
|
partyKey: this.key,
|
|
123
123
|
activeGlobal,
|
|
124
124
|
activeDevice
|
|
125
125
|
});
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Returns a selection context, which can be used to traverse the object graph.
|
|
130
|
+
*/
|
|
131
|
+
get select (): RootSelector {
|
|
132
|
+
return this.database.select.bind(this.database);
|
|
133
|
+
}
|
|
134
|
+
|
|
128
135
|
/**
|
|
129
136
|
* Creates an invitation to a given party.
|
|
130
137
|
* The Invitation flow requires the inviter and invitee to be online at the same time.
|
|
@@ -136,13 +143,13 @@ export class Party extends InvitationProxy {
|
|
|
136
143
|
* @param inviteeKey Public key of the invitee. In this case no secret exchange is required, but only the specified recipient can accept the invitation.
|
|
137
144
|
*/
|
|
138
145
|
async createInvitation ({ inviteeKey }: CreationInvitationOptions = {}): Promise<InvitationRequest> {
|
|
139
|
-
const stream = this._serviceProvider.services.PartyService.
|
|
146
|
+
const stream = this._serviceProvider.services.PartyService.createInvitation({ partyKey: this.key, inviteeKey });
|
|
140
147
|
return this.createInvitationRequest({ stream });
|
|
141
148
|
}
|
|
142
149
|
|
|
143
150
|
queryMembers () {
|
|
144
151
|
return streamToResultSet(
|
|
145
|
-
this._serviceProvider.services.PartyService.
|
|
152
|
+
this._serviceProvider.services.PartyService.subscribeMembers({ partyKey: this.key }),
|
|
146
153
|
(response) => response?.members ?? []
|
|
147
154
|
);
|
|
148
155
|
}
|
|
@@ -164,11 +171,11 @@ export class Party extends InvitationProxy {
|
|
|
164
171
|
}
|
|
165
172
|
|
|
166
173
|
private getPropertiesItem () {
|
|
167
|
-
const items = this.database.select(
|
|
174
|
+
const items = this.database.select({ type: PARTY_ITEM_TYPE }).query().result;
|
|
168
175
|
return items[0];
|
|
169
176
|
}
|
|
170
177
|
|
|
171
178
|
createSnapshot () {
|
|
172
|
-
return this._serviceProvider.services.PartyService.
|
|
179
|
+
return this._serviceProvider.services.PartyService.createSnapshot({ partyKey: this.key });
|
|
173
180
|
}
|
|
174
181
|
}
|
|
@@ -31,24 +31,24 @@ describe('Client Services', () => {
|
|
|
31
31
|
const invitee = await setup();
|
|
32
32
|
afterTest(() => invitee.client.destroy());
|
|
33
33
|
|
|
34
|
-
await inviter.services.ProfileService.
|
|
34
|
+
await inviter.services.ProfileService.createProfile({ username: 'test-user' });
|
|
35
35
|
|
|
36
36
|
const invitation = await new Promise<InvitationRequest>((resolve, reject) => {
|
|
37
|
-
inviter.services.ProfileService.
|
|
37
|
+
inviter.services.ProfileService.createInvitation().subscribe(resolve, reject);
|
|
38
38
|
});
|
|
39
39
|
assert(invitation.descriptor);
|
|
40
40
|
|
|
41
41
|
const redeemedInvitation = await new Promise<RedeemedInvitation>((resolve, reject) => {
|
|
42
|
-
invitee.services.ProfileService.
|
|
42
|
+
invitee.services.ProfileService.acceptInvitation(invitation.descriptor!).subscribe(resolve, reject);
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
-
await invitee.services.ProfileService.
|
|
45
|
+
await invitee.services.ProfileService.authenticateInvitation({
|
|
46
46
|
processId: redeemedInvitation.id,
|
|
47
47
|
secret: invitation.descriptor.secret
|
|
48
48
|
});
|
|
49
49
|
|
|
50
50
|
const [inviteeProfileLatch, inviteeProfileTrigger] = latch();
|
|
51
|
-
invitee.services.ProfileService.
|
|
51
|
+
invitee.services.ProfileService.subscribeProfile().subscribe(inviteeProfile => {
|
|
52
52
|
if (inviteeProfile.profile?.username === 'test-user') {
|
|
53
53
|
inviteeProfileTrigger();
|
|
54
54
|
}
|
|
@@ -309,8 +309,8 @@ describe('Client', () => {
|
|
|
309
309
|
client.registerModel(TestModel);
|
|
310
310
|
|
|
311
311
|
const party = client.echo.queryParties().first;
|
|
312
|
-
const selection = party.database.select(
|
|
313
|
-
await selection.update.waitForCondition(() => selection.
|
|
312
|
+
const selection = party.database.select({ type: 'test' }).query();
|
|
313
|
+
await selection.update.waitForCondition(() => selection.result.length > 0);
|
|
314
314
|
|
|
315
315
|
const item = selection.expectOne();
|
|
316
316
|
|
package/src/client/client.ts
CHANGED
|
@@ -169,8 +169,8 @@ export class Client {
|
|
|
169
169
|
this._halo = new HaloProxy(this._serviceProvider);
|
|
170
170
|
this._echo = new EchoProxy(this._serviceProvider);
|
|
171
171
|
|
|
172
|
-
this._halo._open();
|
|
173
|
-
this._echo._open();
|
|
172
|
+
await this._halo._open();
|
|
173
|
+
await this._echo._open();
|
|
174
174
|
|
|
175
175
|
this._initialized = true; // TODO(burdon): Initialized === halo.initialized?
|
|
176
176
|
clearInterval(timeout);
|
|
@@ -233,7 +233,7 @@ export class Client {
|
|
|
233
233
|
// Recreate echo instance? Big impact on hooks. Test.
|
|
234
234
|
@synchronized
|
|
235
235
|
async reset () {
|
|
236
|
-
await this.services.SystemService.
|
|
236
|
+
await this.services.SystemService.reset();
|
|
237
237
|
this._initialized = false;
|
|
238
238
|
}
|
|
239
239
|
|
|
@@ -0,0 +1,80 @@
|
|
|
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
|
+
// If profile does not exist, send an empty array.
|
|
28
|
+
if (!this.echo.halo.isInitialized) {
|
|
29
|
+
next({ contacts: [] });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const subGroup = new SubscriptionGroup();
|
|
33
|
+
|
|
34
|
+
setImmediate(async () => {
|
|
35
|
+
await this.echo.halo.identityReady.waitForCondition(() => this.echo.halo.isInitialized);
|
|
36
|
+
|
|
37
|
+
const resultSet = this.echo.halo.queryContacts();
|
|
38
|
+
next({ contacts: resultSet.value });
|
|
39
|
+
subGroup.push(resultSet.update.on(() => next({ contacts: resultSet.value })));
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return () => subGroup.unsubscribe();
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async addKeyRecord (request: AddKeyRecordRequest): Promise<void> {
|
|
48
|
+
assert(request.keyRecord && request.keyRecord.publicKey, 'Missing key record.');
|
|
49
|
+
await this.echo.halo.keyring.addKeyRecord(request.keyRecord);
|
|
50
|
+
assert(await this.echo.halo.keyring.getKey(request.keyRecord.publicKey), 'Key not inserted correctly.');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private async polkadotSign (key: KeyRecord, payload: SignRequest['payload']): Promise<SignResponse> {
|
|
54
|
+
await cryptoWaitReady();
|
|
55
|
+
|
|
56
|
+
assert(key.secretKey, 'Secret key is missing.');
|
|
57
|
+
|
|
58
|
+
const keyring = new PolkadotKeyring({ type: 'sr25519' });
|
|
59
|
+
const keypair = keyring.addFromUri(key.secretKey.toString());
|
|
60
|
+
|
|
61
|
+
const signature = u8aToHex(keypair.sign(hexToU8a(payload), { withType: true }));
|
|
62
|
+
return {
|
|
63
|
+
signed: signature
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async sign (request: SignRequest): Promise<SignResponse> {
|
|
68
|
+
assert(request.publicKey, 'Provide a publicKey of the key that should be used for signing.');
|
|
69
|
+
const key = await this.echo.halo.keyring.getFullKey(request.publicKey);
|
|
70
|
+
assert(key, 'Key not found.');
|
|
71
|
+
if (key.type === KeyType.DXNS) {
|
|
72
|
+
return this.polkadotSign(key, request.payload);
|
|
73
|
+
}
|
|
74
|
+
throw new Error('Only DXNS key signing is supported.');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export const createHaloService = ({ echo }: CreateServicesOpts): HaloService => {
|
|
79
|
+
return new HaloService(echo);
|
|
80
|
+
};
|
|
@@ -37,7 +37,7 @@ class PartyService implements IPartyService {
|
|
|
37
37
|
|
|
38
38
|
constructor (private echo: ECHO) {}
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
subscribeToParty (request: SubscribePartyRequest): Stream<SubscribePartyResponse> {
|
|
41
41
|
const update = (next: (message: SubscribePartyResponse) => void) => {
|
|
42
42
|
try {
|
|
43
43
|
const party = this.echo.getParty(request.partyKey);
|
|
@@ -83,7 +83,7 @@ class PartyService implements IPartyService {
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
subscribeParties () {
|
|
87
87
|
return resultSetToStream(this.echo.queryParties(), (parties): SubscribePartiesResponse => {
|
|
88
88
|
return ({
|
|
89
89
|
parties: parties.map(party => ({
|
|
@@ -96,7 +96,7 @@ class PartyService implements IPartyService {
|
|
|
96
96
|
});
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
async
|
|
99
|
+
async createParty () {
|
|
100
100
|
const party = await this.echo.createParty();
|
|
101
101
|
return {
|
|
102
102
|
publicKey: party.key,
|
|
@@ -105,7 +105,7 @@ class PartyService implements IPartyService {
|
|
|
105
105
|
};
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
async
|
|
108
|
+
async cloneParty (snapshot: PartySnapshot): Promise<Party> {
|
|
109
109
|
const party = await this.echo.cloneParty(snapshot);
|
|
110
110
|
return {
|
|
111
111
|
publicKey: party.key,
|
|
@@ -114,7 +114,7 @@ class PartyService implements IPartyService {
|
|
|
114
114
|
};
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
async
|
|
117
|
+
async setPartyState (request: SetPartyStateRequest) {
|
|
118
118
|
const party = this.echo.getParty(request.partyKey);
|
|
119
119
|
if (!party) {
|
|
120
120
|
throw new Error('Party not found');
|
|
@@ -144,7 +144,7 @@ class PartyService implements IPartyService {
|
|
|
144
144
|
};
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
|
|
147
|
+
createInvitation (request: CreateInvitationRequest): Stream<InvitationRequest> {
|
|
148
148
|
return new Stream(({ next, close }) => {
|
|
149
149
|
const party = this.echo.getParty(request.partyKey) ?? raise(new PartyNotFoundError(request.partyKey));
|
|
150
150
|
setImmediate(async () => {
|
|
@@ -185,7 +185,7 @@ class PartyService implements IPartyService {
|
|
|
185
185
|
});
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
|
|
188
|
+
acceptInvitation (request: InvitationDescriptorProto): Stream<RedeemedInvitation> {
|
|
189
189
|
return new Stream(({ next, close }) => {
|
|
190
190
|
const id = v4();
|
|
191
191
|
const [secretLatch, secretTrigger] = latch();
|
|
@@ -221,7 +221,7 @@ class PartyService implements IPartyService {
|
|
|
221
221
|
});
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
-
async
|
|
224
|
+
async authenticateInvitation (request: AuthenticateInvitationRequest) {
|
|
225
225
|
assert(request.processId, 'Process ID is missing.');
|
|
226
226
|
const invitation = this.inviteeInvitations.get(request.processId);
|
|
227
227
|
assert(invitation, 'Invitation not found.');
|
|
@@ -232,7 +232,7 @@ class PartyService implements IPartyService {
|
|
|
232
232
|
invitation.secretTrigger?.();
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
-
|
|
235
|
+
subscribeMembers (request: SubscribeMembersRequest): Stream<SubscribeMembersResponse> {
|
|
236
236
|
const party = this.echo.getParty(request.partyKey);
|
|
237
237
|
if (party) {
|
|
238
238
|
return resultSetToStream(party.queryMembers(), (members): SubscribeMembersResponse => ({ members }));
|
|
@@ -256,7 +256,7 @@ class PartyService implements IPartyService {
|
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
-
async
|
|
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 {
|
|
@@ -32,7 +21,7 @@ export class ProfileService implements IProfileService {
|
|
|
32
21
|
|
|
33
22
|
constructor (private echo: ECHO) {}
|
|
34
23
|
|
|
35
|
-
|
|
24
|
+
subscribeProfile (): Stream<SubscribeProfileResponse> {
|
|
36
25
|
return new Stream(({ next }) => {
|
|
37
26
|
const emitNext = () => next({
|
|
38
27
|
profile: this.echo.halo.isInitialized ? this.echo.halo.getProfile() : undefined
|
|
@@ -43,11 +32,11 @@ export class ProfileService implements IProfileService {
|
|
|
43
32
|
});
|
|
44
33
|
}
|
|
45
34
|
|
|
46
|
-
async
|
|
35
|
+
async createProfile (request: CreateProfileRequest) {
|
|
47
36
|
return this.echo.halo.createProfile(request);
|
|
48
37
|
}
|
|
49
38
|
|
|
50
|
-
async
|
|
39
|
+
async recoverProfile (request: RecoverProfileRequest): Promise<Profile> {
|
|
51
40
|
if (!request.seedPhrase) {
|
|
52
41
|
throw new Error('Recovery SeedPhrase not provided.');
|
|
53
42
|
}
|
|
@@ -58,7 +47,7 @@ export class ProfileService implements IProfileService {
|
|
|
58
47
|
return profile;
|
|
59
48
|
}
|
|
60
49
|
|
|
61
|
-
|
|
50
|
+
createInvitation (): Stream<InvitationRequest> {
|
|
62
51
|
return new Stream(({ next, close }) => {
|
|
63
52
|
setImmediate(async () => {
|
|
64
53
|
const secret = Buffer.from(generatePasscode());
|
|
@@ -82,7 +71,7 @@ export class ProfileService implements IProfileService {
|
|
|
82
71
|
});
|
|
83
72
|
}
|
|
84
73
|
|
|
85
|
-
|
|
74
|
+
acceptInvitation (request: InvitationDescriptorProto): Stream<RedeemedInvitation> {
|
|
86
75
|
return new Stream(({ next, close }) => {
|
|
87
76
|
const id = v4();
|
|
88
77
|
const [secretLatch, secretTrigger] = latch();
|
|
@@ -112,7 +101,7 @@ export class ProfileService implements IProfileService {
|
|
|
112
101
|
});
|
|
113
102
|
}
|
|
114
103
|
|
|
115
|
-
async
|
|
104
|
+
async authenticateInvitation (request: AuthenticateInvitationRequest) {
|
|
116
105
|
assert(request.processId, 'Process ID is missing.');
|
|
117
106
|
const invitation = this.inviteeInvitations.get(request.processId);
|
|
118
107
|
assert(invitation, 'Invitation not found.');
|
|
@@ -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,13 +13,14 @@ 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: {
|
|
18
|
-
|
|
20
|
+
setTracingOptions: () => {
|
|
19
21
|
throw new Error('Tracing not available');
|
|
20
22
|
},
|
|
21
|
-
|
|
23
|
+
subscribeToRpcTrace: () => {
|
|
22
24
|
throw new Error('Tracing not available');
|
|
23
25
|
}
|
|
24
26
|
}
|