@dxos/client-services 0.1.30-next.7c60cd3 → 0.1.30
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-JLLUQQXD.mjs → chunk-DFO3FW2W.mjs} +949 -1150
- package/dist/lib/browser/chunk-DFO3FW2W.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +5 -41
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/packlets/testing/index.mjs +221 -50
- package/dist/lib/browser/packlets/testing/index.mjs.map +4 -4
- package/dist/lib/node/index.cjs +837 -1062
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/packlets/testing/index.cjs +2937 -2719
- package/dist/lib/node/packlets/testing/index.cjs.map +4 -4
- package/dist/types/src/packlets/invitations/device-invitations-handler.d.ts +1 -2
- package/dist/types/src/packlets/invitations/device-invitations-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/device-invitations-service.d.ts +1 -1
- package/dist/types/src/packlets/invitations/device-invitations-service.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/index.d.ts +0 -6
- package/dist/types/src/packlets/invitations/index.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-service.d.ts +2 -3
- package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/space-invitations-handler.d.ts +2 -4
- package/dist/types/src/packlets/invitations/space-invitations-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/space-invitations-service.d.ts +2 -3
- package/dist/types/src/packlets/invitations/space-invitations-service.d.ts.map +1 -1
- package/dist/types/src/packlets/services/client-rpc-server.d.ts +22 -0
- package/dist/types/src/packlets/services/client-rpc-server.d.ts.map +1 -0
- package/dist/types/src/packlets/services/index.d.ts +2 -3
- package/dist/types/src/packlets/services/index.d.ts.map +1 -1
- package/dist/types/src/packlets/services/local-client-services.d.ts +3 -2
- package/dist/types/src/packlets/services/local-client-services.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +22 -8
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-registry.d.ts +3 -1
- package/dist/types/src/packlets/services/service-registry.d.ts.map +1 -1
- package/dist/types/src/packlets/services/utils.d.ts +7 -0
- package/dist/types/src/packlets/services/utils.d.ts.map +1 -0
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts +8 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/index.d.ts +2 -0
- package/dist/types/src/packlets/spaces/index.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts +4 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
- package/dist/types/src/packlets/system/system-service.d.ts +2 -2
- package/dist/types/src/packlets/system/system-service.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/host-test-builder.d.ts +43 -0
- package/dist/types/src/packlets/testing/host-test-builder.d.ts.map +1 -0
- package/dist/types/src/packlets/testing/index.d.ts +1 -0
- package/dist/types/src/packlets/testing/index.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/invitation-utils.d.ts +1 -1
- package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts +32 -34
- package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/packlets/tests/client-services.test.d.ts +2 -0
- package/dist/types/src/packlets/tests/client-services.test.d.ts.map +1 -0
- package/dist/types/src/packlets/tests/client.test.d.ts +2 -0
- package/dist/types/src/packlets/tests/client.test.d.ts.map +1 -0
- package/dist/types/src/packlets/tests/halo-credentials.test.d.ts +2 -0
- package/dist/types/src/packlets/tests/halo-credentials.test.d.ts.map +1 -0
- package/dist/types/src/packlets/tests/halo-persistent.test.d.ts +2 -0
- package/dist/types/src/packlets/tests/halo-persistent.test.d.ts.map +1 -0
- package/dist/types/src/packlets/tests/halo-profile.test.d.ts +2 -0
- package/dist/types/src/packlets/tests/halo-profile.test.d.ts.map +1 -0
- package/dist/types/src/packlets/tests/shared-worker.test.d.ts +2 -0
- package/dist/types/src/packlets/tests/shared-worker.test.d.ts.map +1 -0
- package/dist/types/src/packlets/tests/spaces-invitations.test.d.ts +2 -0
- package/dist/types/src/packlets/tests/spaces-invitations.test.d.ts.map +1 -0
- package/dist/types/src/packlets/tests/spaces.test.d.ts +2 -0
- package/dist/types/src/packlets/tests/spaces.test.d.ts.map +1 -0
- package/dist/types/src/packlets/tests/text.test.d.ts +2 -0
- package/dist/types/src/packlets/tests/text.test.d.ts.map +1 -0
- package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts +0 -1
- package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/index.d.ts +0 -2
- package/dist/types/src/packlets/vault/index.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/shell-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/worker-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/worker-session.d.ts +4 -4
- package/dist/types/src/packlets/vault/worker-session.d.ts.map +1 -1
- package/package.json +31 -30
- package/src/packlets/invitations/device-invitations-handler.ts +10 -9
- package/src/packlets/invitations/device-invitations-service.test.ts +1 -1
- package/src/packlets/invitations/device-invitations-service.ts +1 -1
- package/src/packlets/invitations/index.ts +0 -6
- package/src/packlets/invitations/invitations-service.ts +7 -2
- package/src/packlets/invitations/space-invitations-handler.test.ts +3 -3
- package/src/packlets/invitations/space-invitations-handler.ts +11 -11
- package/src/packlets/invitations/space-invitations-service.test.ts +1 -1
- package/src/packlets/invitations/space-invitations-service.ts +2 -3
- package/src/packlets/services/client-rpc-server.ts +91 -0
- package/src/packlets/services/index.ts +2 -3
- package/src/packlets/services/local-client-services.ts +5 -1
- package/src/packlets/services/service-context.test.ts +4 -4
- package/src/packlets/services/service-context.ts +1 -1
- package/src/packlets/services/service-host.ts +52 -19
- package/src/packlets/services/service-registry.test.ts +2 -2
- package/src/packlets/services/service-registry.ts +9 -1
- package/src/packlets/services/utils.ts +53 -0
- package/src/packlets/spaces/data-space-manager.test.ts +64 -4
- package/src/packlets/spaces/data-space-manager.ts +11 -7
- package/src/packlets/spaces/data-space.ts +13 -1
- package/src/packlets/spaces/index.ts +2 -0
- package/src/packlets/spaces/notarization-plugin.ts +9 -2
- package/src/packlets/spaces/spaces-service.ts +25 -0
- package/src/packlets/system/system-service.ts +3 -3
- package/src/packlets/testing/host-test-builder.ts +163 -0
- package/src/packlets/testing/index.ts +1 -0
- package/src/packlets/testing/invitation-utils.ts +1 -2
- package/src/packlets/testing/test-builder.ts +156 -138
- package/src/packlets/tests/client-services.test.ts +252 -0
- package/src/packlets/tests/client.test.ts +143 -0
- package/src/packlets/tests/halo-credentials.test.ts +94 -0
- package/src/packlets/tests/halo-persistent.test.ts +53 -0
- package/src/packlets/tests/halo-profile.test.ts +74 -0
- package/src/packlets/tests/shared-worker.test.ts +93 -0
- package/src/packlets/tests/spaces-invitations.test.ts +64 -0
- package/src/packlets/tests/spaces.test.ts +136 -0
- package/src/packlets/tests/text.test.ts +206 -0
- package/src/packlets/vault/iframe-host-runtime.ts +26 -34
- package/src/packlets/vault/iframe-proxy-runtime.ts +1 -1
- package/src/packlets/vault/index.ts +0 -2
- package/src/packlets/vault/shell-runtime.ts +1 -2
- package/src/packlets/vault/worker-runtime.ts +5 -15
- package/src/packlets/vault/worker-session.ts +39 -23
- package/dist/lib/browser/chunk-JLLUQQXD.mjs.map +0 -7
- package/dist/types/src/packlets/invitations/device-invitations-proxy.d.ts +0 -8
- package/dist/types/src/packlets/invitations/device-invitations-proxy.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/encoder.d.ts +0 -9
- package/dist/types/src/packlets/invitations/encoder.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/encoder.test.d.ts +0 -2
- package/dist/types/src/packlets/invitations/encoder.test.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts +0 -56
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/invitations-proxy.d.ts +0 -18
- package/dist/types/src/packlets/invitations/invitations-proxy.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/invitations.d.ts +0 -55
- package/dist/types/src/packlets/invitations/invitations.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/space-invitations-proxy.d.ts +0 -11
- package/dist/types/src/packlets/invitations/space-invitations-proxy.d.ts.map +0 -1
- package/dist/types/src/packlets/services/service-definitions.d.ts +0 -30
- package/dist/types/src/packlets/services/service-definitions.d.ts.map +0 -1
- package/dist/types/src/packlets/services/service-proxy.d.ts +0 -17
- package/dist/types/src/packlets/services/service-proxy.d.ts.map +0 -1
- package/dist/types/src/packlets/vault/services.d.ts +0 -21
- package/dist/types/src/packlets/vault/services.d.ts.map +0 -1
- package/dist/types/src/packlets/vault/shell-controller.d.ts +0 -18
- package/dist/types/src/packlets/vault/shell-controller.d.ts.map +0 -1
- package/src/packlets/invitations/device-invitations-proxy.ts +0 -14
- package/src/packlets/invitations/encoder.test.ts +0 -23
- package/src/packlets/invitations/encoder.ts +0 -26
- package/src/packlets/invitations/invitations-handler.ts +0 -68
- package/src/packlets/invitations/invitations-proxy.ts +0 -159
- package/src/packlets/invitations/invitations.ts +0 -113
- package/src/packlets/invitations/space-invitations-proxy.ts +0 -16
- package/src/packlets/services/service-definitions.ts +0 -68
- package/src/packlets/services/service-proxy.ts +0 -54
- package/src/packlets/vault/services.ts +0 -42
- package/src/packlets/vault/shell-controller.ts +0 -56
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2020 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { expect } from 'chai';
|
|
6
|
+
import assert from 'node:assert';
|
|
7
|
+
import waitForExpect from 'wait-for-expect';
|
|
8
|
+
|
|
9
|
+
import { Trigger } from '@dxos/async';
|
|
10
|
+
import { Space } from '@dxos/client';
|
|
11
|
+
import { raise } from '@dxos/debug';
|
|
12
|
+
import { log } from '@dxos/log';
|
|
13
|
+
import { Invitation, SpaceMember } from '@dxos/protocols/proto/dxos/client/services';
|
|
14
|
+
import { describe, test, afterTest } from '@dxos/test';
|
|
15
|
+
|
|
16
|
+
import { syncItems, TestBuilder } from '../testing';
|
|
17
|
+
|
|
18
|
+
// TODO(burdon): Use as set-up for test suite.
|
|
19
|
+
// TODO(burdon): Timeouts and progress callback/events.
|
|
20
|
+
|
|
21
|
+
describe('Client services', () => {
|
|
22
|
+
test('creates client with remote server', async () => {
|
|
23
|
+
const testBuilder = new TestBuilder();
|
|
24
|
+
|
|
25
|
+
const peer = testBuilder.createClientServicesHost();
|
|
26
|
+
await peer.open();
|
|
27
|
+
afterTest(() => peer.close());
|
|
28
|
+
|
|
29
|
+
const [client, server] = testBuilder.createClientServer(peer);
|
|
30
|
+
void server.open();
|
|
31
|
+
afterTest(() => server.close());
|
|
32
|
+
|
|
33
|
+
await client.initialize();
|
|
34
|
+
afterTest(() => client.destroy());
|
|
35
|
+
expect(client.initialized).to.be.true;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('creates clients with multiple peers connected via memory transport', async () => {
|
|
39
|
+
const testBuilder = new TestBuilder();
|
|
40
|
+
|
|
41
|
+
{
|
|
42
|
+
const peer1 = testBuilder.createClientServicesHost();
|
|
43
|
+
await peer1.open();
|
|
44
|
+
afterTest(() => peer1.close());
|
|
45
|
+
|
|
46
|
+
{
|
|
47
|
+
const [client1a, server1a] = testBuilder.createClientServer(peer1);
|
|
48
|
+
void server1a.open();
|
|
49
|
+
await client1a.initialize();
|
|
50
|
+
afterTest(() => Promise.all([client1a.destroy(), server1a.close()]));
|
|
51
|
+
expect(client1a.initialized).to.be.true;
|
|
52
|
+
|
|
53
|
+
await client1a.halo.createIdentity();
|
|
54
|
+
}
|
|
55
|
+
{
|
|
56
|
+
const [client1b, server1b] = testBuilder.createClientServer(peer1);
|
|
57
|
+
void server1b.open();
|
|
58
|
+
await client1b.initialize();
|
|
59
|
+
afterTest(() => Promise.all([client1b.destroy(), server1b.close()]));
|
|
60
|
+
expect(client1b.initialized).to.be.true;
|
|
61
|
+
|
|
62
|
+
// TODO(burdon): Test profile is available.
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
{
|
|
67
|
+
const peer2 = testBuilder.createClientServicesHost();
|
|
68
|
+
await peer2.open();
|
|
69
|
+
afterTest(() => peer2.close());
|
|
70
|
+
|
|
71
|
+
{
|
|
72
|
+
const [client2a, server2a] = testBuilder.createClientServer(peer2);
|
|
73
|
+
void server2a.open();
|
|
74
|
+
await client2a.initialize();
|
|
75
|
+
afterTest(() => Promise.all([client2a.destroy(), server2a.close()]));
|
|
76
|
+
expect(client2a.initialized).to.be.true;
|
|
77
|
+
|
|
78
|
+
await client2a.halo.createIdentity();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('creates identity and invites peer', async () => {
|
|
84
|
+
const testBuilder = new TestBuilder();
|
|
85
|
+
|
|
86
|
+
const peer1 = testBuilder.createClientServicesHost();
|
|
87
|
+
const peer2 = testBuilder.createClientServicesHost();
|
|
88
|
+
|
|
89
|
+
await peer1.open();
|
|
90
|
+
await peer2.open();
|
|
91
|
+
|
|
92
|
+
const [client1, server1] = testBuilder.createClientServer(peer1);
|
|
93
|
+
const [client2, server2] = testBuilder.createClientServer(peer2);
|
|
94
|
+
|
|
95
|
+
// Don't wait (otherwise will block).
|
|
96
|
+
{
|
|
97
|
+
void server1.open();
|
|
98
|
+
void server2.open();
|
|
99
|
+
|
|
100
|
+
await client1.initialize();
|
|
101
|
+
await client2.initialize();
|
|
102
|
+
|
|
103
|
+
await client1.halo.createIdentity();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const success1 = new Trigger<Invitation>();
|
|
107
|
+
const success2 = new Trigger<Invitation>();
|
|
108
|
+
|
|
109
|
+
const authenticationCode = new Trigger<string>();
|
|
110
|
+
|
|
111
|
+
{
|
|
112
|
+
const observable1 = client1.halo.createInvitation();
|
|
113
|
+
observable1.subscribe({
|
|
114
|
+
onConnecting: (invitation) => {
|
|
115
|
+
const observable2 = client2.halo.acceptInvitation(invitation);
|
|
116
|
+
observable2.subscribe({
|
|
117
|
+
onAuthenticating: async () => {
|
|
118
|
+
await observable2.authenticate(await authenticationCode.wait());
|
|
119
|
+
},
|
|
120
|
+
onSuccess: (invitation: Invitation) => {
|
|
121
|
+
// TODO(burdon): No device.
|
|
122
|
+
// expect(guest.identityManager.identity!.authorizedDeviceKeys.size).to.eq(1);
|
|
123
|
+
success2.wake(invitation);
|
|
124
|
+
},
|
|
125
|
+
onError: (err: Error) => raise(new Error(err.message))
|
|
126
|
+
});
|
|
127
|
+
},
|
|
128
|
+
onConnected: (invitation: Invitation) => {
|
|
129
|
+
assert(invitation.authenticationCode);
|
|
130
|
+
authenticationCode.wake(invitation.authenticationCode);
|
|
131
|
+
},
|
|
132
|
+
onSuccess: (invitation: Invitation) => {
|
|
133
|
+
success1.wake(invitation);
|
|
134
|
+
},
|
|
135
|
+
onCancelled: () => raise(new Error()),
|
|
136
|
+
onTimeout: (err: Error) => raise(new Error(err.message)),
|
|
137
|
+
onError: (err: Error) => raise(new Error(err.message))
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Check same identity.
|
|
142
|
+
const [invitation1, invitation2] = await Promise.all([success1.wait(), success2.wait()]);
|
|
143
|
+
expect(invitation1.identityKey).not.to.exist;
|
|
144
|
+
expect(invitation2.identityKey).to.deep.eq(client1.halo.identity!.identityKey);
|
|
145
|
+
expect(invitation2.identityKey).to.deep.eq(client2.halo.identity!.identityKey);
|
|
146
|
+
expect(invitation1.state).to.eq(Invitation.State.SUCCESS);
|
|
147
|
+
expect(invitation2.state).to.eq(Invitation.State.SUCCESS);
|
|
148
|
+
|
|
149
|
+
// Check devices.
|
|
150
|
+
// TODO(burdon): Incorrect number of devices.
|
|
151
|
+
await waitForExpect(async () => {
|
|
152
|
+
expect(client1.halo.getDevices()).to.have.lengthOf(2);
|
|
153
|
+
expect(client2.halo.getDevices()).to.have.lengthOf(2);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test('synchronizes data between two spaces after completing invitation', async () => {
|
|
158
|
+
const testBuilder = new TestBuilder();
|
|
159
|
+
|
|
160
|
+
const peer1 = testBuilder.createClientServicesHost();
|
|
161
|
+
const peer2 = testBuilder.createClientServicesHost();
|
|
162
|
+
|
|
163
|
+
await peer1.open();
|
|
164
|
+
await peer2.open();
|
|
165
|
+
|
|
166
|
+
const [client1, server1] = testBuilder.createClientServer(peer1);
|
|
167
|
+
const [client2, server2] = testBuilder.createClientServer(peer2);
|
|
168
|
+
|
|
169
|
+
// Don't wait (otherwise will block).
|
|
170
|
+
{
|
|
171
|
+
void server1.open();
|
|
172
|
+
void server2.open();
|
|
173
|
+
|
|
174
|
+
await client1.initialize();
|
|
175
|
+
await client2.initialize();
|
|
176
|
+
await client1.halo.createIdentity({ displayName: 'Peer 1' });
|
|
177
|
+
await client2.halo.createIdentity({ displayName: 'Peer 2' });
|
|
178
|
+
}
|
|
179
|
+
log('initialized');
|
|
180
|
+
|
|
181
|
+
afterTest(() => Promise.all([client1.destroy(), server1.close(), peer1.close()]));
|
|
182
|
+
afterTest(() => Promise.all([client2.destroy(), server2.close(), peer2.close()]));
|
|
183
|
+
|
|
184
|
+
const success1 = new Trigger<Invitation>();
|
|
185
|
+
const success2 = new Trigger<Invitation>();
|
|
186
|
+
|
|
187
|
+
const space1 = await client1.echo.createSpace();
|
|
188
|
+
log('createSpace', { key: space1.key });
|
|
189
|
+
const observable1 = space1.createInvitation({ type: Invitation.Type.INTERACTIVE_TESTING });
|
|
190
|
+
|
|
191
|
+
observable1.subscribe({
|
|
192
|
+
onConnecting: (invitation) => {
|
|
193
|
+
const observable2 = client2.echo.acceptInvitation(invitation);
|
|
194
|
+
observable2.subscribe({
|
|
195
|
+
onSuccess: (invitation: Invitation) => {
|
|
196
|
+
success2.wake(invitation);
|
|
197
|
+
},
|
|
198
|
+
onError: (err: Error) => raise(err)
|
|
199
|
+
});
|
|
200
|
+
},
|
|
201
|
+
onSuccess: (invitation) => {
|
|
202
|
+
log('onSuccess');
|
|
203
|
+
success1.wake(invitation);
|
|
204
|
+
},
|
|
205
|
+
onError: (err) => raise(err)
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
const [invitation1, invitation2] = await Promise.all([success1.wait(), success2.wait()]);
|
|
209
|
+
expect(invitation1.spaceKey).to.deep.eq(invitation2.spaceKey);
|
|
210
|
+
expect(invitation1.state).to.eq(Invitation.State.SUCCESS);
|
|
211
|
+
|
|
212
|
+
log('Invitation complete');
|
|
213
|
+
|
|
214
|
+
// TODO(burdon): Space should now be available?
|
|
215
|
+
const trigger = new Trigger<Space>();
|
|
216
|
+
await waitForExpect(() => {
|
|
217
|
+
const space2 = client2.echo.getSpace(invitation2.spaceKey!);
|
|
218
|
+
assert(space2);
|
|
219
|
+
expect(space2).to.exist;
|
|
220
|
+
trigger.wake(space2);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
const space2 = await trigger.wait();
|
|
224
|
+
|
|
225
|
+
for (const space of [space1, space2]) {
|
|
226
|
+
await waitForExpect(() => {
|
|
227
|
+
expect(space.getMembers()).to.deep.equal([
|
|
228
|
+
{
|
|
229
|
+
identity: {
|
|
230
|
+
identityKey: client1.halo.identity!.identityKey,
|
|
231
|
+
profile: {
|
|
232
|
+
displayName: 'Peer 1'
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
presence: SpaceMember.PresenceState.ONLINE
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
identity: {
|
|
239
|
+
identityKey: client2.halo.identity!.identityKey,
|
|
240
|
+
profile: {
|
|
241
|
+
displayName: 'Peer 2'
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
presence: SpaceMember.PresenceState.ONLINE
|
|
245
|
+
}
|
|
246
|
+
]);
|
|
247
|
+
}, 3_000);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
await syncItems(space1.internal.db, space2.internal.db);
|
|
251
|
+
});
|
|
252
|
+
});
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2020 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import chai, { expect } from 'chai';
|
|
6
|
+
import chaiAsPromised from 'chai-as-promised';
|
|
7
|
+
|
|
8
|
+
import { Client } from '@dxos/client';
|
|
9
|
+
import { Config } from '@dxos/config';
|
|
10
|
+
import { Runtime } from '@dxos/protocols/proto/dxos/config';
|
|
11
|
+
import { createStorage, StorageType } from '@dxos/random-access-storage';
|
|
12
|
+
import { describe, test, afterTest } from '@dxos/test';
|
|
13
|
+
|
|
14
|
+
import { TestBuilder } from '../testing';
|
|
15
|
+
|
|
16
|
+
chai.use(chaiAsPromised);
|
|
17
|
+
|
|
18
|
+
describe('Client', () => {
|
|
19
|
+
test('creates client with embedded services', async () => {
|
|
20
|
+
const testBuilder = new TestBuilder();
|
|
21
|
+
|
|
22
|
+
const client = new Client({ services: testBuilder.createLocal() });
|
|
23
|
+
await client.initialize();
|
|
24
|
+
afterTest(() => client.destroy());
|
|
25
|
+
expect(client.initialized).to.be.true;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('initialize and destroy multiple times', async () => {
|
|
29
|
+
const testBuilder = new TestBuilder();
|
|
30
|
+
|
|
31
|
+
const client = new Client({ services: testBuilder.createLocal() });
|
|
32
|
+
await client.initialize();
|
|
33
|
+
await client.initialize();
|
|
34
|
+
expect(client.initialized).to.be.true;
|
|
35
|
+
|
|
36
|
+
await client.destroy();
|
|
37
|
+
await client.destroy();
|
|
38
|
+
expect(client.initialized).to.be.false;
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('closes and reopens', async () => {
|
|
42
|
+
const testBuilder = new TestBuilder();
|
|
43
|
+
|
|
44
|
+
const client = new Client({ services: testBuilder.createLocal() });
|
|
45
|
+
await client.initialize();
|
|
46
|
+
expect(client.initialized).to.be.true;
|
|
47
|
+
|
|
48
|
+
await client.destroy();
|
|
49
|
+
expect(client.initialized).to.be.false;
|
|
50
|
+
|
|
51
|
+
await client.initialize();
|
|
52
|
+
expect(client.initialized).to.be.true;
|
|
53
|
+
|
|
54
|
+
await client.destroy();
|
|
55
|
+
expect(client.initialized).to.be.false;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('create space before identity', async () => {
|
|
59
|
+
const testBuilder = new TestBuilder();
|
|
60
|
+
|
|
61
|
+
const client = new Client({ services: testBuilder.createLocal() });
|
|
62
|
+
await client.initialize();
|
|
63
|
+
afterTest(() => client.destroy());
|
|
64
|
+
await expect(client.echo.createSpace()).to.eventually.be.rejectedWith(
|
|
65
|
+
'This device has no HALO identity available.'
|
|
66
|
+
);
|
|
67
|
+
}).timeout(1_000);
|
|
68
|
+
|
|
69
|
+
// TODO(burdon): Memory store is reset on close (feed store is closed).
|
|
70
|
+
test.skip('creates identity then resets the memory storage', async () => {
|
|
71
|
+
const config = new Config();
|
|
72
|
+
const testBuilder = new TestBuilder(config);
|
|
73
|
+
await runTest(testBuilder);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test('creates identity then resets the node storage', async () => {
|
|
77
|
+
const config = await getNodeConfig(true);
|
|
78
|
+
const testBuilder = new TestBuilder(config);
|
|
79
|
+
await runTest(testBuilder);
|
|
80
|
+
}).onlyEnvironments('nodejs');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// TODO(burdon): Factor out.
|
|
84
|
+
const getNodeConfig = async (reset = false) => {
|
|
85
|
+
const path = '/tmp/dxos/client/test/packlets/test';
|
|
86
|
+
if (reset) {
|
|
87
|
+
// TODO(burdon): Reconcile StorageType and ConfigProto types.
|
|
88
|
+
const storage = createStorage({ type: StorageType.NODE, root: path });
|
|
89
|
+
await storage.reset();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// TODO(burdon): Update API.
|
|
93
|
+
// TODO(burdon): Config not required if remote.
|
|
94
|
+
return new Config({
|
|
95
|
+
version: 1,
|
|
96
|
+
runtime: {
|
|
97
|
+
client: {
|
|
98
|
+
storage: {
|
|
99
|
+
persistent: true,
|
|
100
|
+
storageType: Runtime.Client.Storage.StorageDriver.NODE,
|
|
101
|
+
path // TODO(burdon): Change to root.
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// TODO(burdon): Develop test-suite.
|
|
109
|
+
const runTest = async (testBuilder: TestBuilder) => {
|
|
110
|
+
const client = new Client({ services: testBuilder.createLocal() });
|
|
111
|
+
const displayName = 'test-user';
|
|
112
|
+
|
|
113
|
+
{
|
|
114
|
+
// Create identity.
|
|
115
|
+
await client.initialize();
|
|
116
|
+
expect(client.halo.identity).not.to.exist;
|
|
117
|
+
const identity = await client.halo.createIdentity({ displayName });
|
|
118
|
+
expect(client.halo.identity).to.deep.eq(identity);
|
|
119
|
+
await client.destroy();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
{
|
|
123
|
+
// Should throw trying to create another.
|
|
124
|
+
await client.initialize();
|
|
125
|
+
expect(client.halo.identity).to.exist;
|
|
126
|
+
// TODO(burdon): Error type.
|
|
127
|
+
await expect(client.halo.createIdentity({ displayName })).to.be.rejected;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
{
|
|
131
|
+
// Reset storage.
|
|
132
|
+
// TODO(burdon): Reset doesn't work in memory (create store test).
|
|
133
|
+
await client.reset();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
{
|
|
137
|
+
// Start again.
|
|
138
|
+
await client.initialize();
|
|
139
|
+
await client.halo.createIdentity({ displayName });
|
|
140
|
+
expect(client.halo.identity).to.exist;
|
|
141
|
+
await client.destroy();
|
|
142
|
+
}
|
|
143
|
+
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2020 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
// @dxos/test platform=nodejs
|
|
6
|
+
|
|
7
|
+
import { expect } from 'chai';
|
|
8
|
+
|
|
9
|
+
import { asyncTimeout, Trigger } from '@dxos/async';
|
|
10
|
+
import { Client } from '@dxos/client';
|
|
11
|
+
import { Config } from '@dxos/config';
|
|
12
|
+
import { verifyPresentation } from '@dxos/credentials';
|
|
13
|
+
import { PublicKey } from '@dxos/keys';
|
|
14
|
+
import { log } from '@dxos/log';
|
|
15
|
+
import { describe, test, afterTest } from '@dxos/test';
|
|
16
|
+
|
|
17
|
+
import { TestBuilder } from '../testing';
|
|
18
|
+
|
|
19
|
+
describe('Halo', () => {
|
|
20
|
+
test('presentation', async () => {
|
|
21
|
+
const config = new Config({
|
|
22
|
+
version: 1,
|
|
23
|
+
runtime: {
|
|
24
|
+
client: {
|
|
25
|
+
storage: {
|
|
26
|
+
persistent: true, // TODO(burdon): Note required if path set.
|
|
27
|
+
path: `/tmp/dxos/client/${PublicKey.random().toHex()}`
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const testBuilder = new TestBuilder(config);
|
|
34
|
+
|
|
35
|
+
{
|
|
36
|
+
const client = new Client({ config, services: testBuilder.createLocal() });
|
|
37
|
+
afterTest(() => client.destroy());
|
|
38
|
+
await client.initialize();
|
|
39
|
+
|
|
40
|
+
await client.halo.createIdentity({ displayName: 'test-user' });
|
|
41
|
+
expect(client.halo.identity).exist;
|
|
42
|
+
|
|
43
|
+
const credentials = client.halo.queryCredentials({ type: 'dxos.halo.credentials.AdmittedFeed' });
|
|
44
|
+
const trigger = new Trigger();
|
|
45
|
+
credentials.subscribe({
|
|
46
|
+
onUpdate: (credentials) => {
|
|
47
|
+
if (credentials.length >= 2) {
|
|
48
|
+
trigger.wake();
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
onError: (err) => log.catch(err)
|
|
52
|
+
});
|
|
53
|
+
await asyncTimeout(trigger.wait(), 500);
|
|
54
|
+
|
|
55
|
+
const nonce = new Uint8Array([0, 0, 0, 0]);
|
|
56
|
+
const presentation = await client.halo.presentCredentials({
|
|
57
|
+
ids: credentials.value!.map(({ id }) => id!),
|
|
58
|
+
nonce: new Uint8Array([0, 0, 0, 0])
|
|
59
|
+
});
|
|
60
|
+
expect(presentation.credentials?.length).to.equal(2);
|
|
61
|
+
expect(await verifyPresentation(presentation)).to.deep.equal({ kind: 'pass' });
|
|
62
|
+
expect(presentation.proofs![0].nonce).to.deep.equal(nonce);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('query credentials', async () => {
|
|
67
|
+
const testBuilder = new TestBuilder();
|
|
68
|
+
|
|
69
|
+
const client = new Client({ services: testBuilder.createLocal() });
|
|
70
|
+
afterTest(() => client.destroy());
|
|
71
|
+
await client.initialize();
|
|
72
|
+
|
|
73
|
+
await client.halo.createIdentity({ displayName: 'test-user' });
|
|
74
|
+
expect(client.halo.identity).exist;
|
|
75
|
+
|
|
76
|
+
const credentials = client.halo.queryCredentials({ type: 'dxos.halo.credentials.AdmittedFeed' });
|
|
77
|
+
|
|
78
|
+
const trigger = new Trigger();
|
|
79
|
+
credentials.subscribe({
|
|
80
|
+
onUpdate: () => {
|
|
81
|
+
if (credentials.value?.length === 2) {
|
|
82
|
+
trigger.wake();
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
onError: (error) => {
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
await asyncTimeout(trigger.wait(), 500);
|
|
90
|
+
|
|
91
|
+
expect(credentials.value!.every((cred) => cred.subject.assertion['@type'] === 'dxos.halo.credentials.AdmittedFeed'))
|
|
92
|
+
.to.be.true;
|
|
93
|
+
});
|
|
94
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2020 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
// @dxos/test platform=nodejs
|
|
6
|
+
|
|
7
|
+
import { expect } from 'chai';
|
|
8
|
+
|
|
9
|
+
import { waitForCondition } from '@dxos/async';
|
|
10
|
+
import { Client } from '@dxos/client';
|
|
11
|
+
import { Config } from '@dxos/config';
|
|
12
|
+
import { PublicKey } from '@dxos/keys';
|
|
13
|
+
import { describe, test, afterTest } from '@dxos/test';
|
|
14
|
+
|
|
15
|
+
import { TestBuilder } from '../testing';
|
|
16
|
+
|
|
17
|
+
describe('Halo', () => {
|
|
18
|
+
test('reopens with persistent storage', async () => {
|
|
19
|
+
const config = new Config({
|
|
20
|
+
version: 1,
|
|
21
|
+
runtime: {
|
|
22
|
+
client: {
|
|
23
|
+
storage: {
|
|
24
|
+
persistent: true, // TODO(burdon): Note required if path set.
|
|
25
|
+
path: `/tmp/dxos/client/${PublicKey.random().toHex()}`
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const testBuilder = new TestBuilder(config);
|
|
32
|
+
|
|
33
|
+
{
|
|
34
|
+
const client = new Client({ config, services: testBuilder.createLocal() });
|
|
35
|
+
afterTest(() => client.destroy());
|
|
36
|
+
await client.initialize();
|
|
37
|
+
|
|
38
|
+
await client.halo.createIdentity({ displayName: 'test-user' });
|
|
39
|
+
expect(client.halo.identity).exist;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
{
|
|
43
|
+
const client = new Client({ config, services: testBuilder.createLocal() });
|
|
44
|
+
afterTest(() => client.destroy());
|
|
45
|
+
await client.initialize();
|
|
46
|
+
|
|
47
|
+
await waitForCondition(() => !!client.halo.identity);
|
|
48
|
+
expect(client.halo.identity).exist;
|
|
49
|
+
// TODO(burdon): Not working.
|
|
50
|
+
// expect(client.halo.identity!.displayName).to.eq('test-user');
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2021 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { expect } from 'chai';
|
|
6
|
+
|
|
7
|
+
import { Trigger } from '@dxos/async';
|
|
8
|
+
import { Client } from '@dxos/client';
|
|
9
|
+
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
10
|
+
import { describe, test, afterTest } from '@dxos/test';
|
|
11
|
+
|
|
12
|
+
import { TestBuilder } from '../testing';
|
|
13
|
+
|
|
14
|
+
describe('Halo', () => {
|
|
15
|
+
test('creates a identity', async () => {
|
|
16
|
+
const testBuilder = new TestBuilder();
|
|
17
|
+
|
|
18
|
+
const client = new Client({ services: testBuilder.createLocal() });
|
|
19
|
+
afterTest(() => client.destroy());
|
|
20
|
+
await client.initialize();
|
|
21
|
+
|
|
22
|
+
await client.halo.createIdentity({ displayName: 'test-user' });
|
|
23
|
+
expect(client.halo.identity).exist;
|
|
24
|
+
|
|
25
|
+
expect(await client.halo.getDevices()).to.have.lengthOf(1);
|
|
26
|
+
expect(client.halo.identity!.profile?.displayName).to.equal('test-user');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('device invitations', async () => {
|
|
30
|
+
const testBuilder = new TestBuilder();
|
|
31
|
+
|
|
32
|
+
const client1 = new Client({ services: testBuilder.createLocal() });
|
|
33
|
+
afterTest(() => client1.destroy());
|
|
34
|
+
await client1.initialize();
|
|
35
|
+
|
|
36
|
+
await client1.halo.createIdentity({ displayName: 'test-user' });
|
|
37
|
+
expect(client1.halo.identity).exist;
|
|
38
|
+
|
|
39
|
+
expect(await client1.halo.getDevices()).to.have.lengthOf(1);
|
|
40
|
+
|
|
41
|
+
const client2 = new Client({ services: testBuilder.createLocal() });
|
|
42
|
+
afterTest(() => client2.destroy());
|
|
43
|
+
await client2.initialize();
|
|
44
|
+
|
|
45
|
+
const done1 = new Trigger();
|
|
46
|
+
const done2 = new Trigger();
|
|
47
|
+
const invitation = client1.halo.createInvitation({ type: Invitation.Type.INTERACTIVE_TESTING });
|
|
48
|
+
invitation.subscribe({
|
|
49
|
+
onConnecting: (invitation) => {
|
|
50
|
+
const invitation2 = client2.halo.acceptInvitation(invitation, { type: Invitation.Type.INTERACTIVE_TESTING });
|
|
51
|
+
invitation2.subscribe({
|
|
52
|
+
onSuccess: () => {
|
|
53
|
+
done2.wake();
|
|
54
|
+
},
|
|
55
|
+
onError: (error) => {
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
onSuccess: async (invitation) => {
|
|
61
|
+
done1.wake();
|
|
62
|
+
},
|
|
63
|
+
onError: (error) => {
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
await done1.wait();
|
|
69
|
+
await done2.wait();
|
|
70
|
+
|
|
71
|
+
expect(await client1.halo.getDevices()).to.have.lengthOf(2);
|
|
72
|
+
expect(await client2.halo.getDevices()).to.have.lengthOf(2);
|
|
73
|
+
});
|
|
74
|
+
});
|