@dxos/client-services 0.1.52 → 0.1.53-main.01cbc6b

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 (64) hide show
  1. package/dist/lib/browser/{chunk-C3SPTMW3.mjs → chunk-EYXOVYW5.mjs} +817 -694
  2. package/dist/lib/browser/chunk-EYXOVYW5.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +101 -120
  4. package/dist/lib/browser/index.mjs.map +3 -3
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/packlets/testing/index.mjs +24 -7
  7. package/dist/lib/browser/packlets/testing/index.mjs.map +3 -3
  8. package/dist/lib/node/index.cjs +884 -782
  9. package/dist/lib/node/index.cjs.map +3 -3
  10. package/dist/lib/node/meta.json +1 -1
  11. package/dist/lib/node/packlets/testing/index.cjs +801 -664
  12. package/dist/lib/node/packlets/testing/index.cjs.map +3 -3
  13. package/dist/types/src/packlets/devtools/devtools.d.ts.map +1 -1
  14. package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
  15. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  16. package/dist/types/src/packlets/services/service-host.d.ts +7 -1
  17. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  18. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  19. package/dist/types/src/packlets/spaces/data-space.d.ts +11 -2
  20. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  21. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +2 -1
  22. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
  23. package/dist/types/src/packlets/spaces/spaces-service.d.ts +2 -2
  24. package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
  25. package/dist/types/src/packlets/testing/test-builder.d.ts +7 -1
  26. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  27. package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts +1 -1
  28. package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts.map +1 -1
  29. package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts +1 -1
  30. package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts.map +1 -1
  31. package/dist/types/src/packlets/vault/shell-runtime.d.ts +1 -21
  32. package/dist/types/src/packlets/vault/shell-runtime.d.ts.map +1 -1
  33. package/package.json +33 -32
  34. package/src/packlets/devtools/devtools.ts +2 -2
  35. package/src/packlets/identity/identity-manager.test.ts +1 -1
  36. package/src/packlets/identity/identity-manager.ts +8 -8
  37. package/src/packlets/identity/identity-service.ts +2 -2
  38. package/src/packlets/identity/identity.test.ts +1 -1
  39. package/src/packlets/identity/identity.ts +22 -27
  40. package/src/packlets/invitations/device-invitation-protocol.ts +4 -4
  41. package/src/packlets/invitations/invitation-extension.ts +5 -5
  42. package/src/packlets/invitations/invitations-handler.ts +6 -6
  43. package/src/packlets/invitations/invitations-service.ts +3 -3
  44. package/src/packlets/invitations/space-invitation-protocol.ts +9 -9
  45. package/src/packlets/locks/node.ts +2 -2
  46. package/src/packlets/logging/logging-service.ts +4 -4
  47. package/src/packlets/services/service-context.test.ts +1 -1
  48. package/src/packlets/services/service-context.ts +12 -10
  49. package/src/packlets/services/service-host.test.ts +50 -2
  50. package/src/packlets/services/service-host.ts +28 -10
  51. package/src/packlets/spaces/data-space-manager.test.ts +72 -118
  52. package/src/packlets/spaces/data-space-manager.ts +18 -9
  53. package/src/packlets/spaces/data-space.ts +66 -20
  54. package/src/packlets/spaces/notarization-plugin.test.ts +1 -1
  55. package/src/packlets/spaces/notarization-plugin.ts +9 -5
  56. package/src/packlets/spaces/spaces-service.ts +46 -32
  57. package/src/packlets/testing/invitation-utils.ts +2 -2
  58. package/src/packlets/testing/test-builder.ts +36 -4
  59. package/src/packlets/vault/iframe-host-runtime.ts +2 -2
  60. package/src/packlets/vault/iframe-proxy-runtime.ts +2 -2
  61. package/src/packlets/vault/shell-runtime.ts +3 -49
  62. package/src/packlets/vault/worker-runtime.ts +1 -1
  63. package/src/packlets/vault/worker-session.ts +2 -2
  64. package/dist/lib/browser/chunk-C3SPTMW3.mjs.map +0 -7
@@ -2,10 +2,12 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- import { EventSubscriptions, scheduleTask } from '@dxos/async';
5
+ import { EventSubscriptions, UpdateScheduler, scheduleTask } from '@dxos/async';
6
6
  import { Stream } from '@dxos/codec-protobuf';
7
- import { raise, todo } from '@dxos/debug';
7
+ import { CredentialProcessor } from '@dxos/credentials';
8
+ import { raise } from '@dxos/debug';
8
9
  import { DataServiceSubscriptions, SpaceManager, SpaceNotFoundError } from '@dxos/echo-pipeline';
10
+ import { ApiError } from '@dxos/errors';
9
11
  import { log } from '@dxos/log';
10
12
  import { encodeError } from '@dxos/protocols';
11
13
  import {
@@ -15,6 +17,7 @@ import {
15
17
  QuerySpacesResponse,
16
18
  Space,
17
19
  SpaceMember,
20
+ SpaceState,
18
21
  SpacesService,
19
22
  SubscribeMessagesRequest,
20
23
  UpdateSpaceRequest,
@@ -28,8 +31,6 @@ import { IdentityManager } from '../identity';
28
31
  import { DataSpace } from './data-space';
29
32
  import { DataSpaceManager } from './data-space-manager';
30
33
 
31
- const TIMEFRAME_UPDATE_DEBOUNCE_TIME = 500;
32
-
33
34
  export class SpacesServiceImpl implements SpacesService {
34
35
  constructor(
35
36
  private readonly _identityManager: IdentityManager,
@@ -45,21 +46,40 @@ export class SpacesServiceImpl implements SpacesService {
45
46
 
46
47
  const dataSpaceManager = await this._getDataSpaceManager();
47
48
  const space = await dataSpaceManager.createSpace();
48
- return this._transformSpace(space);
49
+ return this._serializeSpace(space);
49
50
  }
50
51
 
51
- async updateSpace(request: UpdateSpaceRequest) {
52
- todo();
52
+ async updateSpace({ spaceKey, state }: UpdateSpaceRequest) {
53
+ const dataSpaceManager = await this._getDataSpaceManager();
54
+ const space = dataSpaceManager.spaces.get(spaceKey) ?? raise(new SpaceNotFoundError(spaceKey));
55
+
56
+ if (state) {
57
+ switch (state) {
58
+ case SpaceState.ACTIVE:
59
+ await space.activate();
60
+ break;
61
+
62
+ case SpaceState.INACTIVE:
63
+ await space.deactivate();
64
+ break;
65
+ default:
66
+ throw new ApiError('Invalid space state');
67
+ }
68
+ }
53
69
  }
54
70
 
55
71
  querySpaces(): Stream<QuerySpacesResponse> {
56
72
  return new Stream<QuerySpacesResponse>(({ next, ctx }) => {
57
- const onUpdate = async () => {
58
- const dataSpaceManager = await this._getDataSpaceManager();
59
- const spaces = Array.from(dataSpaceManager.spaces.values()).map((space) => this._transformSpace(space));
60
- log('update', { spaces });
61
- next({ spaces });
62
- };
73
+ const scheduler = new UpdateScheduler(
74
+ ctx,
75
+ async () => {
76
+ const dataSpaceManager = await this._getDataSpaceManager();
77
+ const spaces = Array.from(dataSpaceManager.spaces.values()).map((space) => this._serializeSpace(space));
78
+ log('update', { spaces });
79
+ next({ spaces });
80
+ },
81
+ { maxFrequency: 2 },
82
+ );
63
83
 
64
84
  scheduleTask(ctx, async () => {
65
85
  const dataSpaceManager = await this._getDataSpaceManager();
@@ -72,31 +92,25 @@ export class SpacesServiceImpl implements SpacesService {
72
92
  subscriptions.clear();
73
93
 
74
94
  for (const space of dataSpaceManager.spaces.values()) {
75
- subscriptions.add(space.stateUpdate.on(ctx, onUpdate));
76
- subscriptions.add(space.presence.updated.on(ctx, onUpdate));
77
- subscriptions.add(space.dataPipeline.onNewEpoch.on(ctx, onUpdate));
95
+ subscriptions.add(space.stateUpdate.on(ctx, () => scheduler.trigger()));
96
+ subscriptions.add(space.presence.updated.on(ctx, () => scheduler.trigger()));
97
+ subscriptions.add(space.dataPipeline.onNewEpoch.on(ctx, () => scheduler.trigger()));
78
98
 
79
99
  // Pipeline progress.
80
- space.inner.controlPipeline.state.timeframeUpdate
81
- .debounce(TIMEFRAME_UPDATE_DEBOUNCE_TIME)
82
- .on(ctx, onUpdate);
100
+ space.inner.controlPipeline.state.timeframeUpdate.on(ctx, () => scheduler.trigger());
83
101
  if (space.dataPipeline.pipelineState) {
84
- subscriptions.add(
85
- space.dataPipeline.pipelineState.timeframeUpdate
86
- .debounce(TIMEFRAME_UPDATE_DEBOUNCE_TIME)
87
- .on(ctx, onUpdate),
88
- );
102
+ subscriptions.add(space.dataPipeline.pipelineState.timeframeUpdate.on(ctx, () => scheduler.trigger()));
89
103
  }
90
104
  }
91
105
  };
92
106
 
93
107
  dataSpaceManager.updated.on(ctx, () => {
94
108
  subscribeSpaces();
95
- void onUpdate();
109
+ scheduler.trigger();
96
110
  });
97
111
  subscribeSpaces();
98
112
 
99
- void onUpdate();
113
+ scheduler.trigger();
100
114
  });
101
115
 
102
116
  if (!this._identityManager.identity) {
@@ -128,13 +142,13 @@ export class SpacesServiceImpl implements SpacesService {
128
142
  return new Stream(({ ctx, next }) => {
129
143
  const space = this._spaceManager.spaces.get(spaceKey) ?? raise(new SpaceNotFoundError(spaceKey));
130
144
 
131
- const processor = space.spaceState.registerProcessor({
132
- process: async (credential) => {
145
+ const processor: CredentialProcessor = {
146
+ processCredential: async (credential) => {
133
147
  next(credential);
134
148
  },
135
- });
136
- ctx.onDispose(() => processor.close());
137
- scheduleTask(ctx, () => processor.open());
149
+ };
150
+ ctx.onDispose(() => space.spaceState.removeCredentialProcessor(processor));
151
+ scheduleTask(ctx, () => space.spaceState.addCredentialProcessor(processor));
138
152
  });
139
153
  }
140
154
 
@@ -151,7 +165,7 @@ export class SpacesServiceImpl implements SpacesService {
151
165
  await space.createEpoch();
152
166
  }
153
167
 
154
- private _transformSpace(space: DataSpace): Space {
168
+ private _serializeSpace(space: DataSpace): Space {
155
169
  return {
156
170
  spaceKey: space.key,
157
171
  state: space.state,
@@ -2,7 +2,7 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import assert from 'node:assert';
5
+ import invariant from 'tiny-invariant';
6
6
 
7
7
  import { Trigger } from '@dxos/async';
8
8
  import { AuthenticatingInvitationObservable, CancellableInvitationObservable } from '@dxos/client-protocol';
@@ -82,7 +82,7 @@ export const performInvitation = ({
82
82
  if (hooks?.guest?.onConnecting?.(guestObservable)) {
83
83
  break;
84
84
  }
85
- assert(hostInvitation.swarmKey!.equals(guestInvitation.swarmKey!));
85
+ invariant(hostInvitation.swarmKey!.equals(guestInvitation.swarmKey!));
86
86
  break;
87
87
  }
88
88
 
@@ -2,11 +2,18 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- import { createDefaultModelFactory } from '@dxos/client-protocol';
6
5
  import { Config } from '@dxos/config';
7
6
  import { Context } from '@dxos/context';
8
7
  import { createCredentialSignerWithChain, CredentialGenerator } from '@dxos/credentials';
9
- import { SnapshotStore, DataPipeline, MetadataStore, SpaceManager, valueEncoding } from '@dxos/echo-pipeline';
8
+ import { failUndefined } from '@dxos/debug';
9
+ import {
10
+ SnapshotStore,
11
+ DataPipeline,
12
+ MetadataStore,
13
+ SpaceManager,
14
+ valueEncoding,
15
+ DataServiceSubscriptions,
16
+ } from '@dxos/echo-pipeline';
10
17
  import { testLocalDatabase } from '@dxos/echo-pipeline/testing';
11
18
  import { FeedFactory, FeedStore } from '@dxos/feed-store';
12
19
  import { Keyring } from '@dxos/keyring';
@@ -15,8 +22,8 @@ import { MemoryTransportFactory, NetworkManager } from '@dxos/network-manager';
15
22
  import { createStorage, Storage, StorageType } from '@dxos/random-access-storage';
16
23
  import { BlobStore } from '@dxos/teleport-extension-object-sync';
17
24
 
18
- import { ClientServicesHost, ServiceContext } from '../services';
19
- import { SigningContext } from '../spaces';
25
+ import { ClientServicesHost, createDefaultModelFactory, ServiceContext } from '../services';
26
+ import { DataSpaceManager, SigningContext } from '../spaces';
20
27
 
21
28
  //
22
29
  // TODO(burdon): Replace with test builder.
@@ -97,7 +104,9 @@ export type TestPeerProps = {
97
104
  keyring?: Keyring;
98
105
  networkManager?: NetworkManager;
99
106
  spaceManager?: SpaceManager;
107
+ dataSpaceManager?: DataSpaceManager;
100
108
  snapshotStore?: SnapshotStore;
109
+ signingContext?: SigningContext;
101
110
  blobStore?: BlobStore;
102
111
  };
103
112
 
@@ -109,6 +118,10 @@ export class TestPeer {
109
118
  private readonly opts: TestPeerOpts = { storageType: StorageType.RAM },
110
119
  ) {}
111
120
 
121
+ get props() {
122
+ return this._props;
123
+ }
124
+
112
125
  get storage() {
113
126
  return (this._props.storage ??= createStorage({ type: this.opts.storageType }));
114
127
  }
@@ -159,6 +172,25 @@ export class TestPeer {
159
172
  }));
160
173
  }
161
174
 
175
+ get identity() {
176
+ return this._props.signingContext ?? failUndefined();
177
+ }
178
+
179
+ get dataSpaceManager() {
180
+ return (this._props.dataSpaceManager ??= new DataSpaceManager(
181
+ this.spaceManager,
182
+ this.metadataStore,
183
+ new DataServiceSubscriptions(),
184
+ this.keyring,
185
+ this.identity,
186
+ this.feedStore,
187
+ ));
188
+ }
189
+
190
+ async createIdentity() {
191
+ this._props.signingContext ??= await createSigningContext(this.keyring);
192
+ }
193
+
162
194
  async destroy() {
163
195
  await this.storage.reset();
164
196
  }
@@ -3,7 +3,7 @@
3
3
  //
4
4
 
5
5
  import { Trigger } from '@dxos/async';
6
- import { PROXY_CONNECTION_TIMEOUT } from '@dxos/client-protocol';
6
+ import { PROXY_CONNECTION_TIMEOUT, ShellRuntime } from '@dxos/client-protocol';
7
7
  import { Config } from '@dxos/config';
8
8
  import { log, logInfo } from '@dxos/log';
9
9
  import { MemorySignalManager, MemorySignalManagerContext, WebsocketSignalManager } from '@dxos/messaging';
@@ -13,7 +13,7 @@ import { getAsyncValue, MaybePromise, Provider } from '@dxos/util';
13
13
 
14
14
  import { ClientServicesHost } from '../services';
15
15
  import { ClientRpcServer, ClientRpcServerParams } from '../services/client-rpc-server';
16
- import { ShellRuntime, ShellRuntimeImpl } from './shell-runtime';
16
+ import { ShellRuntimeImpl } from './shell-runtime';
17
17
 
18
18
  const LOCK_KEY = 'DXOS_RESOURCE_LOCK';
19
19
 
@@ -3,7 +3,7 @@
3
3
  //
4
4
 
5
5
  import { Trigger } from '@dxos/async';
6
- import { iframeServiceBundle, workerServiceBundle, WorkerServiceBundle } from '@dxos/client-protocol';
6
+ import { iframeServiceBundle, ShellRuntime, workerServiceBundle, WorkerServiceBundle } from '@dxos/client-protocol';
7
7
  import { Config } from '@dxos/config';
8
8
  import { RemoteServiceConnectionError } from '@dxos/errors';
9
9
  import { log } from '@dxos/log';
@@ -12,7 +12,7 @@ import { BridgeService } from '@dxos/protocols/proto/dxos/mesh/bridge';
12
12
  import { createProtoRpcPeer, ProtoRpcPeer, RpcPort } from '@dxos/rpc';
13
13
  import { getAsyncValue, MaybePromise, Provider } from '@dxos/util';
14
14
 
15
- import { ShellRuntime, ShellRuntimeImpl } from './shell-runtime';
15
+ import { ShellRuntimeImpl } from './shell-runtime';
16
16
 
17
17
  // NOTE: Keep as RpcPorts to avoid dependency on @dxos/rpc-tunnel so we don't depend on browser-specific apis.
18
18
  export type IFrameProxyRuntimeParams = {
@@ -2,23 +2,14 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import assert from 'node:assert';
5
+ import invariant from 'tiny-invariant';
6
6
 
7
7
  import { Event } from '@dxos/async';
8
- import { appServiceBundle, AppServiceBundle, shellServiceBundle } from '@dxos/client-protocol';
8
+ import { appServiceBundle, AppServiceBundle, ShellRuntime, 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';
12
12
 
13
- export interface ShellRuntime {
14
- layoutUpdate: Event<LayoutRequest>;
15
- layout: ShellLayout;
16
- invitationCode?: string;
17
- spaceKey?: PublicKey;
18
- setLayout: (layout: ShellLayout, options?: Omit<LayoutRequest, 'layout'>) => void;
19
- setAppContext: (context: AppContextRequest) => Promise<void>;
20
- }
21
-
22
13
  /**
23
14
  * Endpoint that handles shell services.
24
15
  */
@@ -51,7 +42,7 @@ export class ShellRuntimeImpl implements ShellRuntime {
51
42
  }
52
43
 
53
44
  async setAppContext(context: AppContextRequest) {
54
- assert(this._appRpc, 'runtime not open');
45
+ invariant(this._appRpc, 'runtime not open');
55
46
 
56
47
  await this._appRpc.rpc.AppService.setContext(context);
57
48
  }
@@ -81,40 +72,3 @@ export class ShellRuntimeImpl implements ShellRuntime {
81
72
  this._appRpc = undefined;
82
73
  }
83
74
  }
84
-
85
- export class MemoryShellRuntime implements ShellRuntime {
86
- readonly layoutUpdate = new Event<LayoutRequest>();
87
- readonly contextUpdate = new Event<AppContextRequest>();
88
- private _layout: ShellLayout;
89
- private _invitationCode?: string;
90
- private _spaceKey?: PublicKey;
91
-
92
- constructor({ layout, invitationCode, spaceKey }: Partial<LayoutRequest> & Partial<AppContextRequest> = {}) {
93
- this._layout = layout ?? ShellLayout.DEFAULT;
94
- this._invitationCode = invitationCode;
95
- this._spaceKey = spaceKey;
96
- }
97
-
98
- get layout() {
99
- return this._layout;
100
- }
101
-
102
- get invitationCode() {
103
- return this._invitationCode;
104
- }
105
-
106
- get spaceKey() {
107
- return this._spaceKey;
108
- }
109
-
110
- setLayout(layout: ShellLayout, options: Omit<LayoutRequest, 'layout'> = {}) {
111
- this._layout = layout;
112
- this._invitationCode = options.invitationCode;
113
- this._spaceKey = options.spaceKey;
114
- this.layoutUpdate.emit({ layout, ...options });
115
- }
116
-
117
- async setAppContext(context: AppContextRequest) {
118
- this.contextUpdate.emit(context);
119
- }
120
- }
@@ -37,7 +37,7 @@ export class WorkerRuntime {
37
37
  constructor(
38
38
  private readonly _configProvider: () => MaybePromise<Config>
39
39
  ) {
40
- this._clientServices = new ClientServicesHost();
40
+ this._clientServices = new ClientServicesHost({ callbacks: { onReset: async () => { self.close(); } } });
41
41
  }
42
42
 
43
43
  get host() {
@@ -2,7 +2,7 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- import assert from 'node:assert';
5
+ import invariant from 'tiny-invariant';
6
6
 
7
7
  import { asyncTimeout, Trigger } from '@dxos/async';
8
8
  import {
@@ -48,7 +48,7 @@ export class WorkerSession {
48
48
  public bridgeService?: BridgeService;
49
49
 
50
50
  constructor({ serviceHost, systemPort, appPort, shellPort, readySignal }: WorkerSessionParams) {
51
- assert(serviceHost);
51
+ invariant(serviceHost);
52
52
  this._serviceHost = serviceHost;
53
53
 
54
54
  const middleware: Pick<ClientRpcServerParams, 'handleCall' | 'handleStream'> = {