@dxos/client-services 0.1.30-next.7c60cd3 → 0.1.31-next.ea8f0bc

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.
Files changed (148) hide show
  1. package/dist/lib/browser/{chunk-JLLUQQXD.mjs → chunk-ZIQUYEJS.mjs} +898 -1132
  2. package/dist/lib/browser/chunk-ZIQUYEJS.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +5 -41
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/browser/packlets/testing/index.mjs +163 -50
  6. package/dist/lib/browser/packlets/testing/index.mjs.map +4 -4
  7. package/dist/lib/node/index.cjs +785 -1043
  8. package/dist/lib/node/index.cjs.map +4 -4
  9. package/dist/lib/node/meta.json +1 -1
  10. package/dist/lib/node/packlets/testing/index.cjs +2812 -2686
  11. package/dist/lib/node/packlets/testing/index.cjs.map +4 -4
  12. package/dist/types/src/packlets/invitations/device-invitations-handler.d.ts +1 -2
  13. package/dist/types/src/packlets/invitations/device-invitations-handler.d.ts.map +1 -1
  14. package/dist/types/src/packlets/invitations/device-invitations-service.d.ts +1 -1
  15. package/dist/types/src/packlets/invitations/device-invitations-service.d.ts.map +1 -1
  16. package/dist/types/src/packlets/invitations/index.d.ts +0 -6
  17. package/dist/types/src/packlets/invitations/index.d.ts.map +1 -1
  18. package/dist/types/src/packlets/invitations/invitations-service.d.ts +2 -3
  19. package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
  20. package/dist/types/src/packlets/invitations/space-invitations-handler.d.ts +2 -4
  21. package/dist/types/src/packlets/invitations/space-invitations-handler.d.ts.map +1 -1
  22. package/dist/types/src/packlets/invitations/space-invitations-service.d.ts +2 -3
  23. package/dist/types/src/packlets/invitations/space-invitations-service.d.ts.map +1 -1
  24. package/dist/types/src/packlets/services/client-rpc-server.d.ts +22 -0
  25. package/dist/types/src/packlets/services/client-rpc-server.d.ts.map +1 -0
  26. package/dist/types/src/packlets/services/index.d.ts +2 -3
  27. package/dist/types/src/packlets/services/index.d.ts.map +1 -1
  28. package/dist/types/src/packlets/services/local-client-services.d.ts +3 -2
  29. package/dist/types/src/packlets/services/local-client-services.d.ts.map +1 -1
  30. package/dist/types/src/packlets/services/service-context.d.ts +1 -1
  31. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  32. package/dist/types/src/packlets/services/service-host.d.ts +22 -8
  33. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  34. package/dist/types/src/packlets/services/service-registry.d.ts +3 -1
  35. package/dist/types/src/packlets/services/service-registry.d.ts.map +1 -1
  36. package/dist/types/src/packlets/services/utils.d.ts +7 -0
  37. package/dist/types/src/packlets/services/utils.d.ts.map +1 -0
  38. package/dist/types/src/packlets/spaces/index.d.ts +2 -0
  39. package/dist/types/src/packlets/spaces/index.d.ts.map +1 -1
  40. package/dist/types/src/packlets/system/system-service.d.ts +2 -2
  41. package/dist/types/src/packlets/system/system-service.d.ts.map +1 -1
  42. package/dist/types/src/packlets/testing/host-test-builder.d.ts +43 -0
  43. package/dist/types/src/packlets/testing/host-test-builder.d.ts.map +1 -0
  44. package/dist/types/src/packlets/testing/index.d.ts +1 -0
  45. package/dist/types/src/packlets/testing/index.d.ts.map +1 -1
  46. package/dist/types/src/packlets/testing/invitation-utils.d.ts +1 -1
  47. package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
  48. package/dist/types/src/packlets/testing/test-builder.d.ts +30 -34
  49. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  50. package/dist/types/src/packlets/tests/client-services.test.d.ts +2 -0
  51. package/dist/types/src/packlets/tests/client-services.test.d.ts.map +1 -0
  52. package/dist/types/src/packlets/tests/client.test.d.ts +2 -0
  53. package/dist/types/src/packlets/tests/client.test.d.ts.map +1 -0
  54. package/dist/types/src/packlets/tests/halo-credentials.test.d.ts +2 -0
  55. package/dist/types/src/packlets/tests/halo-credentials.test.d.ts.map +1 -0
  56. package/dist/types/src/packlets/tests/halo-persistent.test.d.ts +2 -0
  57. package/dist/types/src/packlets/tests/halo-persistent.test.d.ts.map +1 -0
  58. package/dist/types/src/packlets/tests/halo-profile.test.d.ts +2 -0
  59. package/dist/types/src/packlets/tests/halo-profile.test.d.ts.map +1 -0
  60. package/dist/types/src/packlets/tests/shared-worker.test.d.ts +2 -0
  61. package/dist/types/src/packlets/tests/shared-worker.test.d.ts.map +1 -0
  62. package/dist/types/src/packlets/tests/spaces-invitations.test.d.ts +2 -0
  63. package/dist/types/src/packlets/tests/spaces-invitations.test.d.ts.map +1 -0
  64. package/dist/types/src/packlets/tests/spaces.test.d.ts +2 -0
  65. package/dist/types/src/packlets/tests/spaces.test.d.ts.map +1 -0
  66. package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts +0 -1
  67. package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts.map +1 -1
  68. package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts.map +1 -1
  69. package/dist/types/src/packlets/vault/index.d.ts +0 -2
  70. package/dist/types/src/packlets/vault/index.d.ts.map +1 -1
  71. package/dist/types/src/packlets/vault/shell-runtime.d.ts.map +1 -1
  72. package/dist/types/src/packlets/vault/worker-runtime.d.ts.map +1 -1
  73. package/dist/types/src/packlets/vault/worker-session.d.ts +4 -4
  74. package/dist/types/src/packlets/vault/worker-session.d.ts.map +1 -1
  75. package/package.json +30 -30
  76. package/src/packlets/invitations/device-invitations-handler.ts +10 -9
  77. package/src/packlets/invitations/device-invitations-service.test.ts +1 -1
  78. package/src/packlets/invitations/device-invitations-service.ts +1 -1
  79. package/src/packlets/invitations/index.ts +0 -6
  80. package/src/packlets/invitations/invitations-service.ts +7 -2
  81. package/src/packlets/invitations/space-invitations-handler.test.ts +3 -3
  82. package/src/packlets/invitations/space-invitations-handler.ts +11 -11
  83. package/src/packlets/invitations/space-invitations-service.test.ts +1 -1
  84. package/src/packlets/invitations/space-invitations-service.ts +2 -3
  85. package/src/packlets/services/client-rpc-server.ts +91 -0
  86. package/src/packlets/services/index.ts +2 -3
  87. package/src/packlets/services/local-client-services.ts +5 -1
  88. package/src/packlets/services/service-context.test.ts +4 -4
  89. package/src/packlets/services/service-context.ts +1 -1
  90. package/src/packlets/services/service-host.ts +52 -19
  91. package/src/packlets/services/service-registry.test.ts +2 -2
  92. package/src/packlets/services/service-registry.ts +9 -1
  93. package/src/packlets/services/utils.ts +53 -0
  94. package/src/packlets/spaces/data-space-manager.test.ts +4 -4
  95. package/src/packlets/spaces/index.ts +2 -0
  96. package/src/packlets/system/system-service.ts +3 -3
  97. package/src/packlets/testing/host-test-builder.ts +163 -0
  98. package/src/packlets/testing/index.ts +1 -0
  99. package/src/packlets/testing/invitation-utils.ts +1 -2
  100. package/src/packlets/testing/test-builder.ts +118 -140
  101. package/src/packlets/tests/client-services.test.ts +252 -0
  102. package/src/packlets/tests/client.test.ts +143 -0
  103. package/src/packlets/tests/halo-credentials.test.ts +94 -0
  104. package/src/packlets/tests/halo-persistent.test.ts +53 -0
  105. package/src/packlets/tests/halo-profile.test.ts +74 -0
  106. package/src/packlets/tests/shared-worker.test.ts +93 -0
  107. package/src/packlets/tests/spaces-invitations.test.ts +24 -0
  108. package/src/packlets/tests/spaces.test.ts +68 -0
  109. package/src/packlets/vault/iframe-host-runtime.ts +26 -34
  110. package/src/packlets/vault/iframe-proxy-runtime.ts +1 -1
  111. package/src/packlets/vault/index.ts +0 -2
  112. package/src/packlets/vault/shell-runtime.ts +1 -2
  113. package/src/packlets/vault/worker-runtime.ts +5 -15
  114. package/src/packlets/vault/worker-session.ts +39 -23
  115. package/dist/lib/browser/chunk-JLLUQQXD.mjs.map +0 -7
  116. package/dist/types/src/packlets/invitations/device-invitations-proxy.d.ts +0 -8
  117. package/dist/types/src/packlets/invitations/device-invitations-proxy.d.ts.map +0 -1
  118. package/dist/types/src/packlets/invitations/encoder.d.ts +0 -9
  119. package/dist/types/src/packlets/invitations/encoder.d.ts.map +0 -1
  120. package/dist/types/src/packlets/invitations/encoder.test.d.ts +0 -2
  121. package/dist/types/src/packlets/invitations/encoder.test.d.ts.map +0 -1
  122. package/dist/types/src/packlets/invitations/invitations-handler.d.ts +0 -56
  123. package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +0 -1
  124. package/dist/types/src/packlets/invitations/invitations-proxy.d.ts +0 -18
  125. package/dist/types/src/packlets/invitations/invitations-proxy.d.ts.map +0 -1
  126. package/dist/types/src/packlets/invitations/invitations.d.ts +0 -55
  127. package/dist/types/src/packlets/invitations/invitations.d.ts.map +0 -1
  128. package/dist/types/src/packlets/invitations/space-invitations-proxy.d.ts +0 -11
  129. package/dist/types/src/packlets/invitations/space-invitations-proxy.d.ts.map +0 -1
  130. package/dist/types/src/packlets/services/service-definitions.d.ts +0 -30
  131. package/dist/types/src/packlets/services/service-definitions.d.ts.map +0 -1
  132. package/dist/types/src/packlets/services/service-proxy.d.ts +0 -17
  133. package/dist/types/src/packlets/services/service-proxy.d.ts.map +0 -1
  134. package/dist/types/src/packlets/vault/services.d.ts +0 -21
  135. package/dist/types/src/packlets/vault/services.d.ts.map +0 -1
  136. package/dist/types/src/packlets/vault/shell-controller.d.ts +0 -18
  137. package/dist/types/src/packlets/vault/shell-controller.d.ts.map +0 -1
  138. package/src/packlets/invitations/device-invitations-proxy.ts +0 -14
  139. package/src/packlets/invitations/encoder.test.ts +0 -23
  140. package/src/packlets/invitations/encoder.ts +0 -26
  141. package/src/packlets/invitations/invitations-handler.ts +0 -68
  142. package/src/packlets/invitations/invitations-proxy.ts +0 -159
  143. package/src/packlets/invitations/invitations.ts +0 -113
  144. package/src/packlets/invitations/space-invitations-proxy.ts +0 -16
  145. package/src/packlets/services/service-definitions.ts +0 -68
  146. package/src/packlets/services/service-proxy.ts +0 -54
  147. package/src/packlets/vault/services.ts +0 -42
  148. package/src/packlets/vault/shell-controller.ts +0 -56
@@ -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
+ });
@@ -0,0 +1,93 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ import chai, { expect } from 'chai';
6
+ import chaiAsPromised from 'chai-as-promised';
7
+
8
+ import { sleep } from '@dxos/async';
9
+ import { Client, ClientServicesProxy, fromIFrame } from '@dxos/client';
10
+ import { Config } from '@dxos/config';
11
+ import { createLinkedPorts } from '@dxos/rpc';
12
+ import { describe, test, afterTest } from '@dxos/test';
13
+ import { MaybePromise } from '@dxos/util';
14
+
15
+ import { TestBuilder } from '../testing';
16
+ import { IFrameProxyRuntime, WorkerRuntime } from '../vault';
17
+
18
+ chai.use(chaiAsPromised);
19
+
20
+ const setup = (getConfig: () => MaybePromise<Config>) => {
21
+ const workerRuntime = new WorkerRuntime(getConfig);
22
+
23
+ const systemPorts = createLinkedPorts();
24
+ const workerProxyPorts = createLinkedPorts();
25
+ const proxyWindowPorts = createLinkedPorts();
26
+ const shellPorts = createLinkedPorts();
27
+ void workerRuntime.createSession({
28
+ systemPort: systemPorts[1],
29
+ appPort: workerProxyPorts[1],
30
+ shellPort: shellPorts[1]
31
+ });
32
+ const clientProxy = new IFrameProxyRuntime({
33
+ systemPort: systemPorts[0],
34
+ windowAppPort: proxyWindowPorts[0],
35
+ workerAppPort: workerProxyPorts[0],
36
+ shellPort: shellPorts[0]
37
+ });
38
+ const client = new Client({
39
+ services: new ClientServicesProxy(proxyWindowPorts[1])
40
+ });
41
+
42
+ return { workerRuntime, clientProxy, client };
43
+ };
44
+
45
+ describe('Shared worker', () => {
46
+ test('client connects to the worker', async () => {
47
+ const { workerRuntime, clientProxy, client } = setup(() => new Config({}));
48
+
49
+ await Promise.all([workerRuntime.start(), clientProxy.open('*'), client.initialize()]);
50
+
51
+ await client.halo.createIdentity();
52
+ });
53
+
54
+ test('initialization errors get propagated to the client', async () => {
55
+ const { workerRuntime, clientProxy, client } = setup(async () => {
56
+ await sleep(1);
57
+ throw new Error('Test error');
58
+ });
59
+
60
+ const promise = Promise.all([
61
+ workerRuntime.start().catch(() => {}), // This error should be propagated to client.initialize() call.
62
+ clientProxy.open('*')
63
+ ]);
64
+
65
+ await expect(client.initialize()).to.be.rejectedWith('Test error');
66
+
67
+ await promise;
68
+ });
69
+
70
+ test('host can be initialized after client', async () => {
71
+ const { workerRuntime, clientProxy, client } = setup(async () => {
72
+ await sleep(5);
73
+ return new Config({});
74
+ });
75
+
76
+ await Promise.all([workerRuntime.start(), clientProxy.open('*'), client.initialize()]);
77
+
78
+ await client.halo.createIdentity();
79
+ });
80
+
81
+ // TODO(burdon): Browser-only.
82
+ test.skip('creates client with remote iframe', async () => {
83
+ const testBuilder = new TestBuilder();
84
+
85
+ const client = new Client({
86
+ services: fromIFrame(testBuilder.config)
87
+ });
88
+
89
+ await client.initialize();
90
+ afterTest(() => client.destroy());
91
+ expect(client.initialized).to.be.true;
92
+ });
93
+ });
@@ -0,0 +1,24 @@
1
+ //
2
+ // Copyright 2021 DXOS.org
3
+ //
4
+
5
+ import { Client } from '@dxos/client';
6
+ import { describe, test, afterTest } from '@dxos/test';
7
+
8
+ import { TestBuilder, testSpace } from '../testing';
9
+
10
+ describe('Spaces/invitations', () => {
11
+ test('creates a space and invites a peer', async () => {
12
+ const testBuilder = new TestBuilder();
13
+
14
+ const client = new Client({ services: testBuilder.createLocal() });
15
+ afterTest(() => client.destroy());
16
+ await client.initialize();
17
+ await client.halo.createIdentity({ displayName: 'test-user' });
18
+
19
+ {
20
+ const space = await client.echo.createSpace();
21
+ await testSpace(space.internal.db);
22
+ }
23
+ });
24
+ });
@@ -0,0 +1,68 @@
1
+ //
2
+ // Copyright 2021 DXOS.org
3
+ //
4
+
5
+ import { expect } from 'chai';
6
+
7
+ import { Client } from '@dxos/client';
8
+ import { Config } from '@dxos/config';
9
+ import { log } from '@dxos/log';
10
+ import { createStorage, StorageType } from '@dxos/random-access-storage';
11
+ import { describe, test, afterTest } from '@dxos/test';
12
+
13
+ import { TestBuilder, testSpace } from '../testing';
14
+
15
+ describe('Spaces', () => {
16
+ test('creates a space', async () => {
17
+ const testBuilder = new TestBuilder();
18
+
19
+ const client = new Client({ services: testBuilder.createLocal() });
20
+ afterTest(() => client.destroy());
21
+
22
+ await client.initialize();
23
+ await client.halo.createIdentity({ displayName: 'test-user' });
24
+
25
+ // TODO(burdon): Extend basic queries.
26
+ const space = await client.echo.createSpace();
27
+ await testSpace(space.internal.db);
28
+
29
+ expect(space.getMembers()).to.be.length(1);
30
+ });
31
+
32
+ test('creates a space re-opens the client', async () => {
33
+ const testBuilder = new TestBuilder(new Config({ version: 1 }));
34
+ testBuilder.storage = createStorage({ type: StorageType.RAM });
35
+
36
+ const client = new Client({ services: testBuilder.createLocal() });
37
+ await client.initialize();
38
+ await client.halo.createIdentity({ displayName: 'test-user' });
39
+
40
+ let itemId: string;
41
+ {
42
+ // TODO(burdon): API (client.echo/client.halo).
43
+ const space = await client.echo.createSpace();
44
+ const {
45
+ objectsCreated: [item]
46
+ } = await testSpace(space.internal.db);
47
+ itemId = item.id;
48
+ expect(space.getMembers()).to.be.length(1);
49
+ }
50
+
51
+ await client.destroy();
52
+
53
+ log.break();
54
+
55
+ await client.initialize();
56
+
57
+ {
58
+ const result = client.echo.getSpaces();
59
+ expect(result).to.have.length(1);
60
+ const space = result[0];
61
+
62
+ const item = space.internal.db._itemManager.getItem(itemId)!;
63
+ expect(item).to.exist;
64
+ }
65
+
66
+ await client.destroy();
67
+ });
68
+ });
@@ -7,10 +7,11 @@ import { Config } from '@dxos/config';
7
7
  import { log, logInfo } from '@dxos/log';
8
8
  import { MemorySignalManager, MemorySignalManagerContext, WebsocketSignalManager } from '@dxos/messaging';
9
9
  import { createWebRTCTransportFactory, NetworkManager } from '@dxos/network-manager';
10
- import { createProtoRpcPeer, ProtoRpcPeer, RpcPort } from '@dxos/rpc';
10
+ import { RpcPort } from '@dxos/rpc';
11
11
  import { getAsyncValue, Provider } from '@dxos/util';
12
12
 
13
- import { clientServiceBundle, ClientServices, LocalClientServices } from '../services';
13
+ import { LocalClientServices } from '../services';
14
+ import { ClientRpcServer, ClientRpcServerParams } from '../services/client-rpc-server';
14
15
  import { ShellRuntime, ShellRuntimeImpl } from './shell-runtime';
15
16
 
16
17
  const LOCK_KEY = 'DXOS_RESOURCE_LOCK';
@@ -31,9 +32,6 @@ export class IFrameHostRuntime {
31
32
  private readonly _configProvider: Config | Provider<Promise<Config>>;
32
33
  private readonly _transportFactory = createWebRTCTransportFactory();
33
34
  private readonly _ready = new Trigger<Error | undefined>();
34
- private readonly _getService: <Service>(
35
- find: (services: Partial<ClientServices>) => Service | undefined
36
- ) => Promise<Service>;
37
35
 
38
36
  private readonly _appPort: RpcPort;
39
37
  private readonly _shellPort?: RpcPort;
@@ -41,7 +39,7 @@ export class IFrameHostRuntime {
41
39
 
42
40
  // TODO(dmaretskyi): Replace with host and figure out how to return services provider here.
43
41
  private _clientServices!: LocalClientServices;
44
- private _clientRpc!: ProtoRpcPeer<ClientServices>;
42
+ private _clientRpc!: ClientRpcServer;
45
43
  private _shellRuntime?: ShellRuntimeImpl;
46
44
 
47
45
  @logInfo
@@ -52,20 +50,6 @@ export class IFrameHostRuntime {
52
50
  this._appPort = appPort;
53
51
  this._shellPort = shellPort;
54
52
 
55
- this._getService = async (find) => {
56
- const error = await this._ready.wait();
57
- if (error) {
58
- throw error;
59
- }
60
-
61
- const service = await find(this._clientServices.services);
62
- if (!service) {
63
- throw new Error('Service not found');
64
- }
65
-
66
- return service;
67
- };
68
-
69
53
  if (this._shellPort) {
70
54
  this._shellRuntime = new ShellRuntimeImpl(this._shellPort);
71
55
  }
@@ -96,21 +80,29 @@ export class IFrameHostRuntime {
96
80
  })
97
81
  });
98
82
 
99
- this._clientRpc = createProtoRpcPeer({
100
- exposed: clientServiceBundle,
101
- handlers: {
102
- DataService: async () => await this._getService((services) => services.DataService),
103
- DeviceInvitationsService: async () => await this._getService((services) => services.DeviceInvitationsService),
104
- DevicesService: async () => await this._getService((services) => services.DevicesService),
105
- DevtoolsHost: async () => await this._getService((services) => services.DevtoolsHost),
106
- NetworkService: async () => await this._getService((services) => services.NetworkService),
107
- IdentityService: async () => await this._getService((services) => services.IdentityService),
108
- SpaceInvitationsService: async () => await this._getService((services) => services.SpaceInvitationsService),
109
- SpacesService: async () => await this._getService((services) => services.SpacesService),
110
- SystemService: async () => await this._getService((services) => services.SystemService),
111
- TracingService: async () => await this._getService((services) => services.TracingService)
83
+ const middleware: Pick<ClientRpcServerParams, 'handleCall' | 'handleStream'> = {
84
+ handleCall: async (method, params, handler) => {
85
+ const error = await this._ready.wait({ timeout: 3_000 });
86
+ if (error) {
87
+ throw error;
88
+ }
89
+
90
+ return handler(method, params);
112
91
  },
113
- port: this._appPort
92
+ handleStream: async (method, params, handler) => {
93
+ const error = await this._ready.wait({ timeout: 3_000 });
94
+ if (error) {
95
+ throw error;
96
+ }
97
+
98
+ return handler(method, params);
99
+ }
100
+ };
101
+
102
+ this._clientRpc = new ClientRpcServer({
103
+ serviceRegistry: this._clientServices.host.serviceRegistry,
104
+ port: this._appPort,
105
+ ...middleware
114
106
  });
115
107
 
116
108
  await Promise.all([this._clientServices.open(), this._clientRpc.open(), this._shellRuntime?.open()]);
@@ -2,11 +2,11 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
+ import { iframeServiceBundle, workerServiceBundle, WorkerServiceBundle } from '@dxos/client';
5
6
  import { WebRTCTransportService } from '@dxos/network-manager';
6
7
  import { BridgeService } from '@dxos/protocols/proto/dxos/mesh/bridge';
7
8
  import { createProtoRpcPeer, ProtoRpcPeer, RpcPort } from '@dxos/rpc';
8
9
 
9
- import { iframeServiceBundle, WorkerServiceBundle, workerServiceBundle } from './services';
10
10
  import { ShellRuntime, ShellRuntimeImpl } from './shell-runtime';
11
11
 
12
12
  // NOTE: Keep as RpcPorts to avoid dependency on @dxos/rpc-tunnel so we don't depend on browser-specific apis.
@@ -4,8 +4,6 @@
4
4
 
5
5
  export * from './iframe-host-runtime';
6
6
  export * from './iframe-proxy-runtime';
7
- export * from './services';
8
- export * from './shell-controller';
9
7
  export * from './shell-runtime';
10
8
  export * from './vault-resource-lock';
11
9
  export * from './worker-runtime';
@@ -5,12 +5,11 @@
5
5
  import assert from 'node:assert';
6
6
 
7
7
  import { Event } from '@dxos/async';
8
+ import { appServiceBundle, AppServiceBundle, shellServiceBundle } from '@dxos/client';
8
9
  import { PublicKey } from '@dxos/keys';
9
10
  import { AppContextRequest, LayoutRequest, ShellLayout } from '@dxos/protocols/proto/dxos/iframe';
10
11
  import { createProtoRpcPeer, ProtoRpcPeer, RpcPort } from '@dxos/rpc';
11
12
 
12
- import { AppServiceBundle, appServiceBundle, shellServiceBundle } from './services';
13
-
14
13
  export interface ShellRuntime {
15
14
  layoutUpdate: Event<LayoutRequest>;
16
15
  layout: ShellLayout;
@@ -36,14 +36,16 @@ export class WorkerRuntime {
36
36
  // prettier-ignore
37
37
  constructor(
38
38
  private readonly _configProvider: () => MaybePromise<Config>
39
- ) { }
39
+ ) {
40
+ this._clientServices = new ClientServicesHost();
41
+ }
40
42
 
41
43
  async start() {
42
44
  log('starting...');
43
45
  try {
44
46
  this._config = await this._configProvider();
45
47
  const signalServer = this._config.get('runtime.services.signal.server');
46
- this._clientServices = new ClientServicesHost({
48
+ this._clientServices.initialize({
47
49
  config: this._config,
48
50
  networkManager: new NetworkManager({
49
51
  log: true,
@@ -73,19 +75,7 @@ export class WorkerRuntime {
73
75
  */
74
76
  async createSession({ appPort, systemPort, shellPort }: CreateSessionParams) {
75
77
  const session = new WorkerSession({
76
- getService: async (find) => {
77
- const error = await this._ready.wait();
78
- if (error) {
79
- throw error;
80
- }
81
-
82
- const service = find(this._clientServices.services);
83
- if (!service) {
84
- throw new Error('Service not found');
85
- }
86
-
87
- return service;
88
- },
78
+ serviceHost: this._clientServices,
89
79
  appPort,
90
80
  systemPort,
91
81
  shellPort,