@dxos/client-services 0.1.41 → 0.1.45-next.45667d4

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 (164) hide show
  1. package/dist/lib/browser/{chunk-T73F4MV4.mjs → chunk-IHSMRQ3L.mjs} +985 -867
  2. package/dist/lib/browser/chunk-IHSMRQ3L.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +7 -3
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/browser/packlets/testing/index.mjs +121 -297
  6. package/dist/lib/browser/packlets/testing/index.mjs.map +4 -4
  7. package/dist/lib/node/index.cjs +589 -469
  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 +688 -740
  11. package/dist/lib/node/packlets/testing/index.cjs.map +4 -4
  12. package/dist/types/src/index.d.ts +1 -0
  13. package/dist/types/src/index.d.ts.map +1 -1
  14. package/dist/types/src/packlets/devices/devices-service.d.ts +1 -1
  15. package/dist/types/src/packlets/devices/devices-service.d.ts.map +1 -1
  16. package/dist/types/src/packlets/devtools/devtools.d.ts +4 -2
  17. package/dist/types/src/packlets/devtools/devtools.d.ts.map +1 -1
  18. package/dist/types/src/packlets/devtools/keys.d.ts.map +1 -1
  19. package/dist/types/src/packlets/devtools/network.d.ts +5 -4
  20. package/dist/types/src/packlets/devtools/network.d.ts.map +1 -1
  21. package/dist/types/src/packlets/identity/authenticator.d.ts +1 -1
  22. package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
  23. package/dist/types/src/packlets/identity/identity-manager.d.ts +2 -4
  24. package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
  25. package/dist/types/src/packlets/identity/identity.d.ts +1 -1
  26. package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
  27. package/dist/types/src/packlets/invitations/invitation-extension.d.ts +2 -3
  28. package/dist/types/src/packlets/invitations/invitation-extension.d.ts.map +1 -1
  29. package/dist/types/src/packlets/invitations/invitations-handler.d.ts +1 -3
  30. package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
  31. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts +1 -2
  32. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts.map +1 -1
  33. package/dist/types/src/packlets/network/network-service.d.ts +6 -4
  34. package/dist/types/src/packlets/network/network-service.d.ts.map +1 -1
  35. package/dist/types/src/packlets/services/client-rpc-server.d.ts +2 -2
  36. package/dist/types/src/packlets/services/client-rpc-server.d.ts.map +1 -1
  37. package/dist/types/src/packlets/services/index.d.ts +0 -1
  38. package/dist/types/src/packlets/services/index.d.ts.map +1 -1
  39. package/dist/types/src/packlets/services/local-client-services.d.ts +1 -1
  40. package/dist/types/src/packlets/services/local-client-services.d.ts.map +1 -1
  41. package/dist/types/src/packlets/services/service-context.d.ts +4 -2
  42. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  43. package/dist/types/src/packlets/services/service-host.d.ts +16 -9
  44. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  45. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +12 -7
  46. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  47. package/dist/types/src/packlets/spaces/data-space.d.ts +15 -10
  48. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  49. package/dist/types/src/packlets/spaces/genesis.d.ts +5 -0
  50. package/dist/types/src/packlets/spaces/genesis.d.ts.map +1 -0
  51. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +4 -4
  52. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
  53. package/dist/types/src/packlets/spaces/spaces-service.d.ts +2 -1
  54. package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
  55. package/dist/types/src/packlets/system/system-service.d.ts +1 -1
  56. package/dist/types/src/packlets/system/system-service.d.ts.map +1 -1
  57. package/dist/types/src/packlets/testing/credential-utils.d.ts +1 -1
  58. package/dist/types/src/packlets/testing/index.d.ts +0 -1
  59. package/dist/types/src/packlets/testing/index.d.ts.map +1 -1
  60. package/dist/types/src/packlets/testing/invitation-utils.d.ts +13 -7
  61. package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
  62. package/dist/types/src/packlets/testing/test-builder.d.ts +35 -32
  63. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  64. package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts +1 -1
  65. package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts.map +1 -1
  66. package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts +5 -2
  67. package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts.map +1 -1
  68. package/dist/types/src/packlets/vault/vault-resource-lock.d.ts +1 -1
  69. package/dist/types/src/packlets/vault/vault-resource-lock.d.ts.map +1 -1
  70. package/dist/types/src/packlets/vault/worker-runtime.d.ts +1 -1
  71. package/dist/types/src/packlets/vault/worker-runtime.d.ts.map +1 -1
  72. package/dist/types/src/packlets/vault/worker-session.d.ts +4 -7
  73. package/dist/types/src/packlets/vault/worker-session.d.ts.map +1 -1
  74. package/package.json +30 -31
  75. package/src/index.ts +1 -0
  76. package/src/packlets/devices/devices-service.ts +5 -5
  77. package/src/packlets/devtools/devtools.ts +25 -4
  78. package/src/packlets/devtools/feeds.ts +10 -10
  79. package/src/packlets/devtools/keys.ts +6 -6
  80. package/src/packlets/devtools/network.ts +14 -13
  81. package/src/packlets/devtools/spaces.ts +4 -4
  82. package/src/packlets/identity/authenticator.test.ts +1 -1
  83. package/src/packlets/identity/authenticator.ts +2 -2
  84. package/src/packlets/identity/identity-manager.test.ts +17 -13
  85. package/src/packlets/identity/identity-manager.ts +21 -22
  86. package/src/packlets/identity/identity-service.ts +3 -3
  87. package/src/packlets/identity/identity.test.ts +65 -36
  88. package/src/packlets/identity/identity.ts +17 -17
  89. package/src/packlets/invitations/device-invitation-protocol.test.ts +1 -1
  90. package/src/packlets/invitations/device-invitation-protocol.ts +7 -7
  91. package/src/packlets/invitations/invitation-extension.ts +16 -27
  92. package/src/packlets/invitations/invitations-handler.ts +17 -25
  93. package/src/packlets/invitations/invitations-service.ts +11 -11
  94. package/src/packlets/invitations/space-invitation-protocol.test.ts +9 -9
  95. package/src/packlets/invitations/space-invitation-protocol.ts +11 -12
  96. package/src/packlets/logging/logging-service.ts +8 -3
  97. package/src/packlets/network/network-service.test.ts +8 -8
  98. package/src/packlets/network/network-service.ts +20 -8
  99. package/src/packlets/services/client-rpc-server.ts +5 -5
  100. package/src/packlets/services/index.ts +0 -1
  101. package/src/packlets/services/local-client-services.ts +1 -1
  102. package/src/packlets/services/service-context.test.ts +3 -3
  103. package/src/packlets/services/service-context.ts +26 -24
  104. package/src/packlets/services/service-host.test.ts +6 -6
  105. package/src/packlets/services/service-host.ts +57 -31
  106. package/src/packlets/services/service-registry.test.ts +20 -38
  107. package/src/packlets/spaces/data-space-manager.test.ts +17 -29
  108. package/src/packlets/spaces/data-space-manager.ts +29 -35
  109. package/src/packlets/spaces/data-space.ts +73 -47
  110. package/src/packlets/spaces/genesis.ts +81 -0
  111. package/src/packlets/spaces/notarization-plugin.test.ts +2 -2
  112. package/src/packlets/spaces/notarization-plugin.ts +12 -12
  113. package/src/packlets/spaces/spaces-service.test.ts +2 -2
  114. package/src/packlets/spaces/spaces-service.ts +21 -10
  115. package/src/packlets/storage/storage.ts +3 -3
  116. package/src/packlets/system/system-service.test.ts +1 -1
  117. package/src/packlets/system/system-service.ts +1 -1
  118. package/src/packlets/testing/credential-utils.ts +4 -4
  119. package/src/packlets/testing/index.ts +0 -1
  120. package/src/packlets/testing/invitation-utils.ts +28 -33
  121. package/src/packlets/testing/test-builder.ts +132 -168
  122. package/src/packlets/vault/iframe-host-runtime.ts +8 -11
  123. package/src/packlets/vault/iframe-proxy-runtime.ts +25 -9
  124. package/src/packlets/vault/shell-runtime.ts +4 -4
  125. package/src/packlets/vault/vault-resource-lock.ts +2 -2
  126. package/src/packlets/vault/worker-runtime.ts +7 -9
  127. package/src/packlets/vault/worker-session.ts +24 -45
  128. package/dist/lib/browser/chunk-T73F4MV4.mjs.map +0 -7
  129. package/dist/types/src/packlets/services/utils.d.ts +0 -7
  130. package/dist/types/src/packlets/services/utils.d.ts.map +0 -1
  131. package/dist/types/src/packlets/testing/host-test-builder.d.ts +0 -43
  132. package/dist/types/src/packlets/testing/host-test-builder.d.ts.map +0 -1
  133. package/dist/types/src/packlets/tests/client-services.test.d.ts +0 -2
  134. package/dist/types/src/packlets/tests/client-services.test.d.ts.map +0 -1
  135. package/dist/types/src/packlets/tests/client.test.d.ts +0 -2
  136. package/dist/types/src/packlets/tests/client.test.d.ts.map +0 -1
  137. package/dist/types/src/packlets/tests/halo-credentials.test.d.ts +0 -2
  138. package/dist/types/src/packlets/tests/halo-credentials.test.d.ts.map +0 -1
  139. package/dist/types/src/packlets/tests/halo-persistent.test.d.ts +0 -2
  140. package/dist/types/src/packlets/tests/halo-persistent.test.d.ts.map +0 -1
  141. package/dist/types/src/packlets/tests/halo-profile.test.d.ts +0 -2
  142. package/dist/types/src/packlets/tests/halo-profile.test.d.ts.map +0 -1
  143. package/dist/types/src/packlets/tests/invitations.test.d.ts +0 -2
  144. package/dist/types/src/packlets/tests/invitations.test.d.ts.map +0 -1
  145. package/dist/types/src/packlets/tests/shared-worker.test.d.ts +0 -2
  146. package/dist/types/src/packlets/tests/shared-worker.test.d.ts.map +0 -1
  147. package/dist/types/src/packlets/tests/spaces-invitations.test.d.ts +0 -2
  148. package/dist/types/src/packlets/tests/spaces-invitations.test.d.ts.map +0 -1
  149. package/dist/types/src/packlets/tests/spaces.test.d.ts +0 -2
  150. package/dist/types/src/packlets/tests/spaces.test.d.ts.map +0 -1
  151. package/dist/types/src/packlets/tests/text.test.d.ts +0 -2
  152. package/dist/types/src/packlets/tests/text.test.d.ts.map +0 -1
  153. package/src/packlets/services/utils.ts +0 -53
  154. package/src/packlets/testing/host-test-builder.ts +0 -163
  155. package/src/packlets/tests/client-services.test.ts +0 -222
  156. package/src/packlets/tests/client.test.ts +0 -140
  157. package/src/packlets/tests/halo-credentials.test.ts +0 -94
  158. package/src/packlets/tests/halo-persistent.test.ts +0 -53
  159. package/src/packlets/tests/halo-profile.test.ts +0 -48
  160. package/src/packlets/tests/invitations.test.ts +0 -389
  161. package/src/packlets/tests/shared-worker.test.ts +0 -92
  162. package/src/packlets/tests/spaces-invitations.test.ts +0 -46
  163. package/src/packlets/tests/spaces.test.ts +0 -147
  164. package/src/packlets/tests/text.test.ts +0 -206
@@ -5,15 +5,7 @@
5
5
  import assert from 'node:assert';
6
6
 
7
7
  import { Trigger } from '@dxos/async';
8
- import {
9
- AuthenticatingInvitationObservable,
10
- CancellableInvitationObservable,
11
- Client,
12
- EchoProxy,
13
- HaloProxy,
14
- InvitationsProxy,
15
- SpaceProxy
16
- } from '@dxos/client';
8
+ import { AuthenticatingInvitationObservable, CancellableInvitationObservable } from '@dxos/client-protocol';
17
9
  import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
18
10
 
19
11
  import { ServiceContext } from '../services';
@@ -29,10 +21,18 @@ export const sanitizeInvitation = (invitation: Invitation): Invitation => {
29
21
  authMethod: invitation.authMethod,
30
22
  swarmKey: invitation.swarmKey,
31
23
  state: invitation.state,
32
- timeout: invitation.timeout
24
+ timeout: invitation.timeout,
33
25
  };
34
26
  };
35
27
 
28
+ export type InvitationHost = {
29
+ createInvitation(options?: Partial<Invitation>): CancellableInvitationObservable;
30
+ };
31
+
32
+ export type InvitationGuest = {
33
+ acceptInvitation(invitation: Invitation): AuthenticatingInvitationObservable;
34
+ };
35
+
36
36
  export type PerformInvitationCallbacks<T> = {
37
37
  onConnecting?: (value: T) => boolean | void;
38
38
  onConnected?: (value: T) => boolean | void;
@@ -45,8 +45,8 @@ export type PerformInvitationCallbacks<T> = {
45
45
  };
46
46
 
47
47
  export type PerformInvitationParams = {
48
- host: ServiceContext | InvitationsProxy | HaloProxy | SpaceProxy;
49
- guest: ServiceContext | InvitationsProxy | HaloProxy | EchoProxy | Client;
48
+ host: ServiceContext | InvitationHost;
49
+ guest: ServiceContext | InvitationGuest;
50
50
  options?: Partial<Invitation>;
51
51
  hooks?: {
52
52
  host?: PerformInvitationCallbacks<CancellableInvitationObservable>;
@@ -60,7 +60,7 @@ export const performInvitation = ({
60
60
  host,
61
61
  guest,
62
62
  options,
63
- hooks
63
+ hooks,
64
64
  }: PerformInvitationParams): [Promise<Result>, Promise<Result>] => {
65
65
  const hostComplete = new Trigger<Result>();
66
66
  const guestComplete = new Trigger<Result>();
@@ -133,7 +133,7 @@ export const performInvitation = ({
133
133
  return;
134
134
  }
135
135
  guestComplete.wake({ error });
136
- }
136
+ },
137
137
  );
138
138
  break;
139
139
  }
@@ -188,44 +188,39 @@ export const performInvitation = ({
188
188
  return;
189
189
  }
190
190
  hostComplete.wake({ error });
191
- }
191
+ },
192
192
  );
193
193
 
194
194
  return [hostComplete.wait(), guestComplete.wait()];
195
195
  };
196
196
 
197
197
  const createInvitation = (
198
- host: ServiceContext | InvitationsProxy | HaloProxy | SpaceProxy,
199
- options?: Partial<Invitation>
198
+ host: ServiceContext | InvitationHost,
199
+ options?: Partial<Invitation>,
200
200
  ): CancellableInvitationObservable => {
201
201
  options ??= {
202
202
  authMethod: Invitation.AuthMethod.NONE,
203
- ...(options ?? {})
203
+ ...(options ?? {}),
204
204
  };
205
205
 
206
- if (host instanceof InvitationsProxy || host instanceof HaloProxy || host instanceof SpaceProxy) {
207
- return host.createInvitation(options);
206
+ if (host instanceof ServiceContext) {
207
+ const hostHandler = host.getInvitationHandler({ kind: Invitation.Kind.SPACE, ...options });
208
+ return host.invitations.createInvitation(hostHandler, options);
208
209
  }
209
210
 
210
- const hostHandler = host.getInvitationHandler({ kind: Invitation.Kind.SPACE, ...options });
211
- return host.invitations.createInvitation(hostHandler, options);
211
+ return host.createInvitation(options);
212
212
  };
213
213
 
214
214
  const acceptInvitation = (
215
- guest: ServiceContext | InvitationsProxy | HaloProxy | EchoProxy | Client,
216
- invitation: Invitation
215
+ guest: ServiceContext | InvitationGuest,
216
+ invitation: Invitation,
217
217
  ): AuthenticatingInvitationObservable => {
218
218
  invitation = sanitizeInvitation(invitation);
219
219
 
220
- if (
221
- guest instanceof InvitationsProxy ||
222
- guest instanceof HaloProxy ||
223
- guest instanceof EchoProxy ||
224
- guest instanceof Client
225
- ) {
226
- return guest.acceptInvitation(invitation);
220
+ if (guest instanceof ServiceContext) {
221
+ const guestHandler = guest.getInvitationHandler({ kind: invitation.kind });
222
+ return guest.invitations.acceptInvitation(guestHandler, invitation);
227
223
  }
228
224
 
229
- const guestHandler = guest.getInvitationHandler({ kind: invitation.kind });
230
- return guest.invitations.acceptInvitation(guestHandler, invitation);
225
+ return guest.acceptInvitation(invitation);
231
226
  };
@@ -1,193 +1,157 @@
1
1
  //
2
- // Copyright 2020 DXOS.org
2
+ // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- import assert from 'node:assert';
6
-
7
- import { asyncTimeout, Trigger } from '@dxos/async';
8
- import { Client, ClientServices, ClientServicesProxy, createDefaultModelFactory, Invitation } from '@dxos/client';
5
+ import { createDefaultModelFactory } from '@dxos/client-protocol';
9
6
  import { Config } from '@dxos/config';
10
- import { raise } from '@dxos/debug';
11
- import { DocumentModel } from '@dxos/document-model';
12
- import { DatabaseProxy, genesisMutation } from '@dxos/echo-db';
13
- import { PublicKey } from '@dxos/keys';
14
- import { log } from '@dxos/log';
15
- import { MemorySignalManager, MemorySignalManagerContext, WebsocketSignalManager } from '@dxos/messaging';
16
- import { createWebRTCTransportFactory, MemoryTransportFactory, NetworkManager } from '@dxos/network-manager';
17
- import { Storage } from '@dxos/random-access-storage';
18
- import { createLinkedPorts, createProtoRpcPeer, ProtoRpcPeer } from '@dxos/rpc';
19
-
20
- import { ClientServicesHost, LocalClientServices } from '../services';
21
-
22
- export const testConfigWithLocalSignal = new Config({
23
- version: 1,
24
- runtime: {
25
- services: {
26
- signaling: [
27
- {
28
- // TODO(burdon): Port numbers and global consts?
29
- server: 'ws://localhost:4000/.well-known/dx/signal'
30
- }
31
- ]
32
- }
33
- }
34
- });
7
+ import { createCredentialSignerWithChain, CredentialGenerator } from '@dxos/credentials';
8
+ import { SnapshotStore, DataPipeline, MetadataStore, SpaceManager, valueEncoding } from '@dxos/echo-pipeline';
9
+ import { testLocalDatabase } from '@dxos/echo-pipeline/testing';
10
+ import { FeedFactory, FeedStore } from '@dxos/feed-store';
11
+ import { Keyring } from '@dxos/keyring';
12
+ import { MemorySignalManager, MemorySignalManagerContext } from '@dxos/messaging';
13
+ import { MemoryTransportFactory, NetworkManager } from '@dxos/network-manager';
14
+ import { createStorage, Storage, StorageType } from '@dxos/random-access-storage';
15
+
16
+ import { ClientServicesHost, ServiceContext } from '../services';
17
+ import { SigningContext } from '../spaces';
35
18
 
36
- /**
37
- * Client builder supports different configurations, incl. signaling, transports, storage.
38
- */
39
- export class TestBuilder {
40
- private readonly _config: Config;
19
+ //
20
+ // TODO(burdon): Replace with test builder.
21
+ //
41
22
 
42
- public storage?: Storage;
23
+ export const createServiceHost = (config: Config, signalManagerContext: MemorySignalManagerContext) => {
24
+ return new ClientServicesHost({
25
+ config,
26
+ signalManager: new MemorySignalManager(signalManagerContext),
27
+ transportFactory: MemoryTransportFactory,
28
+ });
29
+ };
43
30
 
44
- // prettier-ignore
45
- constructor (
46
- config?: Config,
47
- private readonly _modelFactory = createDefaultModelFactory(),
48
- private readonly _signalManagerContext = new MemorySignalManagerContext()
49
- ) {
50
- this._config = config ?? new Config();
51
- }
31
+ export const createServiceContext = ({
32
+ signalContext = new MemorySignalManagerContext(),
33
+ storage = createStorage({ type: StorageType.RAM }),
34
+ }: {
35
+ signalContext?: MemorySignalManagerContext;
36
+ storage?: Storage;
37
+ } = {}) => {
38
+ const signalManager = new MemorySignalManager(signalContext);
39
+ const networkManager = new NetworkManager({
40
+ signalManager,
41
+ transportFactory: MemoryTransportFactory,
42
+ });
43
+
44
+ const modelFactory = createDefaultModelFactory();
45
+ return new ServiceContext(storage, networkManager, signalManager, modelFactory);
46
+ };
52
47
 
53
- get config(): Config {
54
- return this._config;
55
- }
48
+ export const createPeers = async (numPeers: number) => {
49
+ const signalContext = new MemorySignalManagerContext();
56
50
 
57
- /**
58
- * Get network manager using local shared memory or remote signal manager.
59
- */
60
- get networkManager() {
61
- const signals = this._config.get('runtime.services.signaling');
62
- if (signals) {
63
- return new NetworkManager({
64
- log: true,
65
- signalManager: new WebsocketSignalManager(signals),
66
- transportFactory: createWebRTCTransportFactory({
67
- iceServers: this._config.get('runtime.services.ice')
68
- })
69
- });
70
- }
71
-
72
- // Memory transport with shared context.
73
- return new NetworkManager({
74
- log: true,
75
- signalManager: new MemorySignalManager(this._signalManagerContext),
76
- transportFactory: MemoryTransportFactory
77
- });
78
- }
51
+ return await Promise.all(
52
+ Array.from(Array(numPeers)).map(async () => {
53
+ const peer = createServiceContext({ signalContext });
54
+ await peer.open();
55
+ return peer;
56
+ }),
57
+ );
58
+ };
79
59
 
80
- /**
81
- * Create backend service handlers.
82
- */
83
- createClientServicesHost() {
84
- return new ClientServicesHost({
85
- config: this._config,
86
- modelFactory: this._modelFactory,
87
- networkManager: this.networkManager,
88
- storage: this.storage
89
- });
90
- }
60
+ export const createIdentity = async (peer: ServiceContext) => {
61
+ await peer.createIdentity();
62
+ return peer;
63
+ };
91
64
 
92
- /**
93
- * Create local services host.
94
- */
95
- createLocal() {
96
- return new LocalClientServices({
97
- config: this._config,
98
- modelFactory: this._modelFactory,
99
- networkManager: this.networkManager,
100
- storage: this.storage
101
- });
102
- }
65
+ // TODO(burdon): Remove @dxos/client-testing.
66
+ // TODO(burdon): Create builder and make configurable.
67
+ export const syncItemsLocal = async (db1: DataPipeline, db2: DataPipeline) => {
68
+ await testLocalDatabase(db1, db2);
69
+ await testLocalDatabase(db2, db1);
70
+ };
103
71
 
104
- /**
105
- * Create client/server.
106
- */
107
- createClientServer(host: ClientServicesHost = this.createClientServicesHost()): [Client, ProtoRpcPeer<{}>] {
108
- const [proxyPort, hostPort] = createLinkedPorts();
109
- const server = createProtoRpcPeer({
110
- exposed: host.descriptors,
111
- handlers: host.services as ClientServices,
112
- port: hostPort
113
- });
114
- // TODO(dmaretskyi): Refactor.
115
-
116
- const client = new Client({ services: new ClientServicesProxy(proxyPort) });
117
- return [client, server];
72
+ export class TestBuilder {
73
+ public readonly signalContext = new MemorySignalManagerContext();
74
+
75
+ createPeer(): TestPeer {
76
+ return new TestPeer(this.signalContext);
118
77
  }
119
78
  }
120
79
 
121
- export const testSpace = async (create: DatabaseProxy, check: DatabaseProxy = create) => {
122
- const objectId = PublicKey.random().toHex();
80
+ export type TestPeerProps = {
81
+ storage?: Storage;
82
+ feedStore?: FeedStore<any>;
83
+ metadataStore?: MetadataStore;
84
+ keyring?: Keyring;
85
+ networkManager?: NetworkManager;
86
+ spaceManager?: SpaceManager;
87
+ snapshotStore?: SnapshotStore;
88
+ };
123
89
 
124
- const result = create.mutate(genesisMutation(objectId, DocumentModel.meta.type));
90
+ export class TestPeer {
91
+ private _props: TestPeerProps = {};
125
92
 
126
- await result.batch.getReceipt();
127
- // TODO(dmaretskiy): await result.waitToBeProcessed()
128
- assert(create._itemManager.entities.has(result.objectsUpdated[0].id));
93
+ constructor(private readonly signalContext: MemorySignalManagerContext) {}
129
94
 
130
- await asyncTimeout(
131
- check.itemUpdate.waitForCondition(() => check._itemManager.entities.has(objectId)),
132
- 1000
133
- );
95
+ get storage() {
96
+ return (this._props.storage ??= createStorage({ type: StorageType.RAM }));
97
+ }
134
98
 
135
- return result;
136
- };
99
+ get keyring() {
100
+ return (this._props.keyring ??= new Keyring(this.storage.createDirectory('keyring')));
101
+ }
137
102
 
138
- export const syncItems = async (db1: DatabaseProxy, db2: DatabaseProxy) => {
139
- // Check item replicated from 1 => 2.
140
- await testSpace(db1, db2);
103
+ get feedStore() {
104
+ return (this._props.feedStore ??= new FeedStore({
105
+ factory: new FeedFactory({
106
+ root: this.storage.createDirectory('feeds'),
107
+ signer: this.keyring,
108
+ hypercore: {
109
+ valueEncoding,
110
+ },
111
+ }),
112
+ }));
113
+ }
141
114
 
142
- // Check item replicated from 2 => 1.
143
- await testSpace(db2, db1);
144
- };
115
+ get metadataStore() {
116
+ return (this._props.metadataStore ??= new MetadataStore(this.storage.createDirectory('metadata')));
117
+ }
145
118
 
146
- export const joinCommonSpace = async ([initialPeer, ...peers]: Client[], spaceKey?: PublicKey): Promise<PublicKey> => {
147
- const rootSpace = spaceKey ? initialPeer.getSpace(spaceKey) : await initialPeer.createSpace();
148
- assert(rootSpace, 'Space not found.');
149
-
150
- await Promise.all(
151
- peers.map(async (peer) => {
152
- const hostDone = new Trigger<Invitation>();
153
- const guestDone = new Trigger<Invitation>();
154
-
155
- const hostObservable = rootSpace.createInvitation({ authMethod: Invitation.AuthMethod.NONE });
156
- log('invitation created');
157
- hostObservable.subscribe(
158
- (hostInvitation) => {
159
- switch (hostInvitation.state) {
160
- case Invitation.State.CONNECTING: {
161
- const guestObservable = peer.acceptInvitation(hostInvitation);
162
- log('invitation accepted');
163
-
164
- guestObservable.subscribe(
165
- (guestInvitation) => {
166
- switch (guestInvitation.state) {
167
- case Invitation.State.SUCCESS: {
168
- guestDone.wake(guestInvitation);
169
- log('invitation guestDone');
170
- break;
171
- }
172
- }
173
- },
174
- (err) => raise(err)
175
- );
176
- break;
177
- }
178
-
179
- case Invitation.State.SUCCESS: {
180
- hostDone.wake(hostInvitation);
181
- log('invitation hostDone');
182
- }
183
- }
184
- },
185
- (err) => raise(err)
186
- );
119
+ get snapshotStore() {
120
+ return (this._props.snapshotStore ??= new SnapshotStore(this.storage.createDirectory('snapshots')));
121
+ }
187
122
 
188
- await Promise.all([hostDone.wait(), guestDone.wait()]);
189
- })
190
- );
123
+ get networkManager() {
124
+ return (this._props.networkManager ??= new NetworkManager({
125
+ signalManager: new MemorySignalManager(this.signalContext),
126
+ transportFactory: MemoryTransportFactory,
127
+ }));
128
+ }
129
+
130
+ get spaceManager() {
131
+ return (this._props.spaceManager ??= new SpaceManager({
132
+ feedStore: this.feedStore,
133
+ networkManager: this.networkManager,
134
+ metadataStore: this.metadataStore,
135
+ modelFactory: createDefaultModelFactory(),
136
+ snapshotStore: this.snapshotStore,
137
+ }));
138
+ }
139
+ }
191
140
 
192
- return rootSpace.key;
141
+ export const createSigningContext = async (keyring: Keyring): Promise<SigningContext> => {
142
+ const identityKey = await keyring.createKey();
143
+ const deviceKey = await keyring.createKey();
144
+
145
+ return {
146
+ identityKey,
147
+ deviceKey,
148
+ credentialSigner: createCredentialSignerWithChain(
149
+ keyring,
150
+ {
151
+ credential: await new CredentialGenerator(keyring, identityKey, deviceKey).createDeviceAuthorization(deviceKey),
152
+ },
153
+ deviceKey,
154
+ ),
155
+ recordCredential: async () => {}, // No-op.
156
+ };
193
157
  };
@@ -6,7 +6,7 @@ import { Trigger } from '@dxos/async';
6
6
  import { Config } from '@dxos/config';
7
7
  import { log, logInfo } from '@dxos/log';
8
8
  import { MemorySignalManager, MemorySignalManagerContext, WebsocketSignalManager } from '@dxos/messaging';
9
- import { createWebRTCTransportFactory, NetworkManager, TransportFactory } from '@dxos/network-manager';
9
+ import { createWebRTCTransportFactory, TransportFactory } from '@dxos/network-manager';
10
10
  import { RpcPort } from '@dxos/rpc';
11
11
  import { getAsyncValue, MaybePromise, Provider } from '@dxos/util';
12
12
 
@@ -70,19 +70,16 @@ export class IFrameHostRuntime {
70
70
  try {
71
71
  this._config = await getAsyncValue(this._configProvider);
72
72
  this._transportFactory = createWebRTCTransportFactory({
73
- iceServers: this._config.get('runtime.services.ice')
73
+ iceServers: this._config.get('runtime.services.ice'),
74
74
  });
75
75
  const signals = this._config.get('runtime.services.signaling');
76
76
  this._clientServices = new LocalClientServices({
77
77
  lockKey: LOCK_KEY,
78
78
  config: this._config,
79
- networkManager: new NetworkManager({
80
- log: true,
81
- signalManager: signals
82
- ? new WebsocketSignalManager(signals)
83
- : new MemorySignalManager(new MemorySignalManagerContext()), // TODO(dmaretskyi): Inject this context.
84
- transportFactory: this._transportFactory
85
- })
79
+ signalManager: signals
80
+ ? new WebsocketSignalManager(signals)
81
+ : new MemorySignalManager(new MemorySignalManagerContext()), // TODO(dmaretskyi): Inject this context.
82
+ transportFactory: this._transportFactory,
86
83
  });
87
84
 
88
85
  const middleware: Pick<ClientRpcServerParams, 'handleCall' | 'handleStream'> = {
@@ -101,13 +98,13 @@ export class IFrameHostRuntime {
101
98
  }
102
99
 
103
100
  return handler(method, params);
104
- }
101
+ },
105
102
  };
106
103
 
107
104
  this._clientRpc = new ClientRpcServer({
108
105
  serviceRegistry: this._clientServices.host.serviceRegistry,
109
106
  port: this._appPort,
110
- ...middleware
107
+ ...middleware,
111
108
  });
112
109
 
113
110
  await Promise.all([this._clientServices.open(), this._clientRpc.open(), this._shellRuntime?.open()]);
@@ -2,7 +2,9 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- import { Config, iframeServiceBundle, workerServiceBundle, WorkerServiceBundle } from '@dxos/client';
5
+ import { Trigger } from '@dxos/async';
6
+ import { iframeServiceBundle, workerServiceBundle, WorkerServiceBundle } from '@dxos/client-protocol';
7
+ import { Config } from '@dxos/config';
6
8
  import { RemoteServiceConnectionError } from '@dxos/errors';
7
9
  import { log } from '@dxos/log';
8
10
  import { WebRTCTransportService } from '@dxos/network-manager';
@@ -23,9 +25,11 @@ export type IFrameProxyRuntimeParams = {
23
25
  * Manages the client connection to the shared worker.
24
26
  */
25
27
  export class IFrameProxyRuntime {
28
+ private readonly _id = String(Math.floor(Math.random() * 1000000));
26
29
  private readonly _configProvider: IFrameProxyRuntimeParams['config'];
27
30
  private readonly _systemPort: RpcPort;
28
31
  private readonly _shellPort?: RpcPort;
32
+ private _release = new Trigger();
29
33
  private _config!: Config;
30
34
  private _transportService!: BridgeService;
31
35
  private _systemRpc!: ProtoRpcPeer<WorkerServiceBundle>;
@@ -49,7 +53,7 @@ export class IFrameProxyRuntime {
49
53
  this._config = await getAsyncValue(this._configProvider);
50
54
 
51
55
  this._transportService = new WebRTCTransportService({
52
- iceServers: this._config.get('runtime.services.ice')
56
+ iceServers: this._config.get('runtime.services.ice'),
53
57
  });
54
58
 
55
59
  this._systemRpc = createProtoRpcPeer({
@@ -57,19 +61,26 @@ export class IFrameProxyRuntime {
57
61
  exposed: iframeServiceBundle,
58
62
  handlers: {
59
63
  BridgeService: this._transportService,
60
- IframeService: {
61
- async heartbeat() {
62
- // Ok.
63
- }
64
- }
65
64
  },
66
65
  port: this._systemPort,
67
- timeout: 200
66
+ timeout: 200,
68
67
  });
69
68
 
69
+ let lockKey: string | undefined;
70
+ if (typeof navigator !== 'undefined') {
71
+ lockKey = this._lockKey(origin);
72
+ this._release = new Trigger();
73
+ const ready = new Trigger();
74
+ void navigator.locks.request(lockKey, async () => {
75
+ ready.wake();
76
+ await this._release.wait();
77
+ });
78
+ await ready.wait();
79
+ }
80
+
70
81
  try {
71
82
  await this._systemRpc.open();
72
- await this._systemRpc.rpc.WorkerService.start({ origin });
83
+ await this._systemRpc.rpc.WorkerService.start({ origin, lockKey });
73
84
  } catch (err) {
74
85
  log.catch(err);
75
86
  throw new RemoteServiceConnectionError('Failed to connect to worker');
@@ -78,8 +89,13 @@ export class IFrameProxyRuntime {
78
89
  }
79
90
 
80
91
  async close() {
92
+ this._release.wake();
81
93
  await this._shellRuntime?.close();
82
94
  await this._systemRpc.rpc.WorkerService.stop();
83
95
  await this._systemRpc.close();
84
96
  }
97
+
98
+ private _lockKey(origin: string) {
99
+ return `${origin}-${this._id}`;
100
+ }
85
101
  }
@@ -5,7 +5,7 @@
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
+ import { appServiceBundle, AppServiceBundle, shellServiceBundle } from '@dxos/client-protocol';
9
9
  import { PublicKey } from '@dxos/keys';
10
10
  import { AppContextRequest, LayoutRequest, ShellLayout } from '@dxos/protocols/proto/dxos/iframe';
11
11
  import { createProtoRpcPeer, ProtoRpcPeer, RpcPort } from '@dxos/rpc';
@@ -67,10 +67,10 @@ export class ShellRuntimeImpl implements ShellRuntime {
67
67
  this._invitationCode = request.invitationCode;
68
68
  this._spaceKey = request.spaceKey;
69
69
  this.layoutUpdate.emit(request);
70
- }
71
- }
70
+ },
71
+ },
72
72
  },
73
- port: this._port
73
+ port: this._port,
74
74
  });
75
75
 
76
76
  await this._appRpc.open();
@@ -7,7 +7,7 @@ import { log, logInfo } from '@dxos/log';
7
7
  import { MaybePromise } from '@dxos/util';
8
8
 
9
9
  enum Message {
10
- ACQUIRING = 'acquiring'
10
+ ACQUIRING = 'acquiring',
11
11
  }
12
12
 
13
13
  export type VaultResourceLockOptions = {
@@ -37,7 +37,7 @@ export class VaultResourceLock {
37
37
 
38
38
  async acquire() {
39
39
  this._broadcastChannel.postMessage({
40
- message: Message.ACQUIRING
40
+ message: Message.ACQUIRING,
41
41
  });
42
42
 
43
43
  try {
@@ -6,7 +6,7 @@ import { Trigger } from '@dxos/async';
6
6
  import { Config } from '@dxos/config';
7
7
  import { log } from '@dxos/log';
8
8
  import { MemorySignalManager, MemorySignalManagerContext, WebsocketSignalManager } from '@dxos/messaging';
9
- import { NetworkManager, WebRTCTransportProxyFactory } from '@dxos/network-manager';
9
+ import { WebRTCTransportProxyFactory } from '@dxos/network-manager';
10
10
  import { RpcPort } from '@dxos/rpc';
11
11
  import { MaybePromise } from '@dxos/util';
12
12
 
@@ -51,13 +51,10 @@ export class WorkerRuntime {
51
51
  const signals = this._config.get('runtime.services.signaling');
52
52
  this._clientServices.initialize({
53
53
  config: this._config,
54
- networkManager: new NetworkManager({
55
- log: true,
56
- signalManager: signals
57
- ? new WebsocketSignalManager(signals)
58
- : new MemorySignalManager(new MemorySignalManagerContext()), // TODO(dmaretskyi): Inject this context.
59
- transportFactory: this._transportFactory
60
- })
54
+ signalManager: signals
55
+ ? new WebsocketSignalManager(signals)
56
+ : new MemorySignalManager(new MemorySignalManagerContext()), // TODO(dmaretskyi): Inject this context.
57
+ transportFactory: this._transportFactory,
61
58
  });
62
59
 
63
60
  await this._clientServices.open();
@@ -83,7 +80,7 @@ export class WorkerRuntime {
83
80
  appPort,
84
81
  systemPort,
85
82
  shellPort,
86
- readySignal: this._ready
83
+ readySignal: this._ready,
87
84
  });
88
85
 
89
86
  // When tab is closed.
@@ -102,6 +99,7 @@ export class WorkerRuntime {
102
99
  * Selects one of the existing session fro WebRTC networking.
103
100
  */
104
101
  private _reconnectWebrtc() {
102
+ log('reconnecting webrtc...');
105
103
  // Check if current session is already closed.
106
104
  if (this._sessionForNetworking) {
107
105
  if (!this.sessions.has(this._sessionForNetworking)) {