@dxos/client-services 0.1.53-main.e7b89d1 → 0.1.53-main.f5aedb7

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 (48) hide show
  1. package/dist/lib/browser/{chunk-BSRQYPXL.mjs → chunk-PWZ2J6KS.mjs} +650 -626
  2. package/dist/lib/browser/chunk-PWZ2J6KS.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 +6 -6
  7. package/dist/lib/browser/packlets/testing/index.mjs.map +3 -3
  8. package/dist/lib/node/index.cjs +720 -717
  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 +624 -602
  12. package/dist/lib/node/packlets/testing/index.cjs.map +3 -3
  13. package/dist/types/src/packlets/services/service-host.d.ts +7 -1
  14. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  15. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  16. package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts +1 -1
  17. package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts.map +1 -1
  18. package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts +1 -1
  19. package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts.map +1 -1
  20. package/dist/types/src/packlets/vault/shell-runtime.d.ts +1 -21
  21. package/dist/types/src/packlets/vault/shell-runtime.d.ts.map +1 -1
  22. package/package.json +33 -32
  23. package/src/packlets/identity/identity-manager.test.ts +1 -1
  24. package/src/packlets/identity/identity-manager.ts +8 -8
  25. package/src/packlets/identity/identity-service.ts +2 -2
  26. package/src/packlets/identity/identity.test.ts +1 -1
  27. package/src/packlets/identity/identity.ts +2 -2
  28. package/src/packlets/invitations/device-invitation-protocol.ts +4 -4
  29. package/src/packlets/invitations/invitation-extension.ts +5 -5
  30. package/src/packlets/invitations/invitations-handler.ts +6 -6
  31. package/src/packlets/invitations/invitations-service.ts +3 -3
  32. package/src/packlets/invitations/space-invitation-protocol.ts +9 -9
  33. package/src/packlets/locks/node.ts +2 -2
  34. package/src/packlets/logging/logging-service.ts +4 -4
  35. package/src/packlets/services/service-context.test.ts +1 -1
  36. package/src/packlets/services/service-context.ts +3 -3
  37. package/src/packlets/services/service-host.test.ts +50 -2
  38. package/src/packlets/services/service-host.ts +25 -9
  39. package/src/packlets/spaces/data-space-manager.ts +5 -5
  40. package/src/packlets/spaces/notarization-plugin.ts +4 -4
  41. package/src/packlets/testing/invitation-utils.ts +2 -2
  42. package/src/packlets/testing/test-builder.ts +1 -2
  43. package/src/packlets/vault/iframe-host-runtime.ts +2 -2
  44. package/src/packlets/vault/iframe-proxy-runtime.ts +2 -2
  45. package/src/packlets/vault/shell-runtime.ts +3 -49
  46. package/src/packlets/vault/worker-runtime.ts +1 -1
  47. package/src/packlets/vault/worker-session.ts +2 -2
  48. package/dist/lib/browser/chunk-BSRQYPXL.mjs.map +0 -7
@@ -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 { Trigger } from '@dxos/async';
8
8
  import { CredentialConsumer, getCredentialAssertion } from '@dxos/credentials';
@@ -161,7 +161,7 @@ export class ServiceContext {
161
161
 
162
162
  getInvitationHandler(invitation: Partial<Invitation> & Pick<Invitation, 'kind'>): InvitationProtocol {
163
163
  const factory = this._handlerFactories.get(invitation.kind);
164
- assert(factory, `Unknown invitation kind: ${invitation.kind}`);
164
+ invariant(factory, `Unknown invitation kind: ${invitation.kind}`);
165
165
  return factory(invitation);
166
166
  }
167
167
 
@@ -205,7 +205,7 @@ export class ServiceContext {
205
205
  await this.dataSpaceManager.open();
206
206
 
207
207
  this._handlerFactories.set(Invitation.Kind.SPACE, (invitation) => {
208
- assert(this.dataSpaceManager, 'dataSpaceManager not initialized yet');
208
+ invariant(this.dataSpaceManager, 'dataSpaceManager not initialized yet');
209
209
  return new SpaceInvitationProtocol(this.dataSpaceManager, signingContext, this.keyring, invitation.spaceKey);
210
210
  });
211
211
  this.initialized.wake();
@@ -2,19 +2,32 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { expect } from 'chai';
5
+ import chai, { expect } from 'chai';
6
+ import chaiAsPromised from 'chai-as-promised';
7
+ import { rmSync } from 'node:fs';
6
8
 
7
- import { latch, Trigger } from '@dxos/async';
9
+ import { asyncTimeout, latch, Trigger } from '@dxos/async';
8
10
  import { Config } from '@dxos/config';
9
11
  import { verifyPresentation } from '@dxos/credentials';
10
12
  import { PublicKey } from '@dxos/keys';
11
13
  import { MemorySignalManagerContext } from '@dxos/messaging';
14
+ import { Identity } from '@dxos/protocols/proto/dxos/client/services';
12
15
  import { Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
13
16
  import { afterTest, describe, test } from '@dxos/test';
17
+ import { isNode } from '@dxos/util';
14
18
 
15
19
  import { createMockCredential, createServiceHost } from '../testing';
16
20
 
21
+ chai.use(chaiAsPromised);
22
+
17
23
  describe('ClientServicesHost', () => {
24
+ const persistentStoragePath = '/tmp/dxos/client-services/service-host/storage';
25
+
26
+ afterEach(async () => {
27
+ // Clean up.
28
+ isNode() && rmSync(persistentStoragePath, { recursive: true, force: true });
29
+ });
30
+
18
31
  test('queryCredentials', async () => {
19
32
  const host = createServiceHost(new Config(), new MemorySignalManagerContext());
20
33
  await host.open();
@@ -97,4 +110,39 @@ describe('ClientServicesHost', () => {
97
110
  kind: 'pass',
98
111
  });
99
112
  });
113
+
114
+ test('storage reset', async () => {
115
+ const config = new Config({
116
+ runtime: { client: { storage: { persistent: true, path: persistentStoragePath } } },
117
+ });
118
+ {
119
+ const host = createServiceHost(config, new MemorySignalManagerContext());
120
+ await host.open();
121
+
122
+ await host.services.IdentityService?.createIdentity({});
123
+
124
+ expect(host._serviceContext.storage.size).to.exist;
125
+
126
+ await asyncTimeout(host.reset(), 1000);
127
+ await host.close();
128
+ }
129
+
130
+ {
131
+ const host = createServiceHost(config, new MemorySignalManagerContext());
132
+ await host.open();
133
+ const trigger = new Trigger<Identity>();
134
+
135
+ const stream = host.services.IdentityService?.queryIdentity();
136
+ await stream?.waitUntilReady();
137
+
138
+ stream?.subscribe((identity) => {
139
+ if (identity.identity) {
140
+ trigger.wake(identity.identity);
141
+ }
142
+ });
143
+ await expect(asyncTimeout(trigger.wait(), 200)).to.be.rejectedWith();
144
+ stream?.close();
145
+ await host.close();
146
+ }
147
+ }).onlyEnvironments('nodejs', 'chromium', 'firefox');
100
148
  });
@@ -2,11 +2,12 @@
2
2
  // Copyright 2021 DXOS.org
3
3
  //
4
4
 
5
- import assert from 'node:assert';
5
+ import invariant from 'tiny-invariant';
6
6
 
7
7
  import { Event, synchronized } from '@dxos/async';
8
- import { clientServiceBundle, ClientServices, createDefaultModelFactory } from '@dxos/client-protocol';
8
+ import { clientServiceBundle, ClientServices } from '@dxos/client-protocol';
9
9
  import { Config } from '@dxos/config';
10
+ import { DocumentModel } from '@dxos/document-model';
10
11
  import { DataServiceImpl } from '@dxos/echo-pipeline';
11
12
  import { PublicKey } from '@dxos/keys';
12
13
  import { log } from '@dxos/log';
@@ -16,6 +17,7 @@ import { createWebRTCTransportFactory, NetworkManager, TransportFactory } from '
16
17
  import { trace } from '@dxos/protocols';
17
18
  import { SystemStatus } from '@dxos/protocols/proto/dxos/client/services';
18
19
  import { Storage } from '@dxos/random-access-storage';
20
+ import { TextModel } from '@dxos/text-model';
19
21
 
20
22
  import { DevicesServiceImpl } from '../devices';
21
23
  import { DevtoolsServiceImpl, DevtoolsHostEvents } from '../devtools';
@@ -30,6 +32,11 @@ import { SystemServiceImpl } from '../system';
30
32
  import { ServiceContext } from './service-context';
31
33
  import { ServiceRegistry } from './service-registry';
32
34
 
35
+ // TODO(burdon): Factor out to spaces.
36
+ export const createDefaultModelFactory = () => {
37
+ return new ModelFactory().registerModel(DocumentModel).registerModel(TextModel);
38
+ };
39
+
33
40
  export type ClientServicesHostParams = {
34
41
  /**
35
42
  * Can be omitted if `initialize` is later called.
@@ -41,6 +48,11 @@ export type ClientServicesHostParams = {
41
48
  connectionLog?: boolean;
42
49
  storage?: Storage;
43
50
  lockKey?: string;
51
+ callbacks?: ClientServicesHostCallbacks;
52
+ };
53
+
54
+ export type ClientServicesHostCallbacks = {
55
+ onReset?: () => Promise<void>;
44
56
  };
45
57
 
46
58
  export type InitializeOptions = {
@@ -65,6 +77,7 @@ export class ClientServicesHost {
65
77
  private _signalManager?: SignalManager;
66
78
  private _networkManager?: NetworkManager;
67
79
  private _storage?: Storage;
80
+ private _callbacks?: ClientServicesHostCallbacks;
68
81
 
69
82
  _serviceContext!: ServiceContext;
70
83
  private _opening = false;
@@ -80,9 +93,11 @@ export class ClientServicesHost {
80
93
  storage,
81
94
  // TODO(wittjosiah): Turn this on by default.
82
95
  lockKey,
96
+ callbacks,
83
97
  }: ClientServicesHostParams = {}) {
84
98
  this._storage = storage;
85
99
  this._modelFactory = modelFactory;
100
+ this._callbacks = callbacks;
86
101
 
87
102
  if (config) {
88
103
  this.initialize({ config, transportFactory, signalManager });
@@ -150,10 +165,10 @@ export class ClientServicesHost {
150
165
  * Can only be called once.
151
166
  */
152
167
  initialize({ config, ...options }: InitializeOptions) {
153
- assert(!this._open, 'service host is open');
168
+ invariant(!this._open, 'service host is open');
154
169
 
155
170
  if (config) {
156
- assert(!this._config, 'config already set');
171
+ invariant(!this._config, 'config already set');
157
172
 
158
173
  this._config = config;
159
174
  if (!this._storage) {
@@ -170,7 +185,7 @@ export class ClientServicesHost {
170
185
  } = options;
171
186
  this._signalManager = signalManager;
172
187
 
173
- assert(!this._networkManager, 'network manager already set');
188
+ invariant(!this._networkManager, 'network manager already set');
174
189
  this._networkManager = new NetworkManager({
175
190
  log: connectionLog,
176
191
  transportFactory,
@@ -187,10 +202,10 @@ export class ClientServicesHost {
187
202
  const traceId = PublicKey.random().toHex();
188
203
  log.trace('dxos.sdk.client-services-host.open', trace.begin({ id: traceId }));
189
204
 
190
- assert(this._config, 'config not set');
191
- assert(this._storage, 'storage not set');
192
- assert(this._signalManager, 'signal manager not set');
193
- assert(this._networkManager, 'network manager not set');
205
+ invariant(this._config, 'config not set');
206
+ invariant(this._storage, 'storage not set');
207
+ invariant(this._signalManager, 'signal manager not set');
208
+ invariant(this._networkManager, 'network manager not set');
194
209
 
195
210
  this._opening = true;
196
211
  log('opening...', { lockKey: this._resourceLock?.lockKey });
@@ -277,5 +292,6 @@ export class ClientServicesHost {
277
292
  await this._storage!.reset();
278
293
  log('reset');
279
294
  log.trace('dxos.sdk.client-services-host.reset', trace.end({ id: traceId }));
295
+ await this._callbacks?.onReset?.();
280
296
  }
281
297
  }
@@ -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 { Event, synchronized, trackLeaks } from '@dxos/async';
8
8
  import { cancelWithContext, Context } from '@dxos/context';
@@ -112,7 +112,7 @@ export class DataSpaceManager {
112
112
  */
113
113
  @synchronized
114
114
  async createSpace() {
115
- assert(this._isOpen, 'Not open.');
115
+ invariant(this._isOpen, 'Not open.');
116
116
  const spaceKey = await this._keyring.createKey();
117
117
  const controlFeedKey = await this._keyring.createKey();
118
118
  const dataFeedKey = await this._keyring.createKey();
@@ -130,7 +130,7 @@ export class DataSpaceManager {
130
130
  await this._metadataStore.addSpace(metadata);
131
131
 
132
132
  const memberCredential = credentials[1];
133
- assert(getCredentialAssertion(memberCredential)['@type'] === 'dxos.halo.credentials.SpaceMember');
133
+ invariant(getCredentialAssertion(memberCredential)['@type'] === 'dxos.halo.credentials.SpaceMember');
134
134
  await this._signingContext.recordCredential(memberCredential);
135
135
 
136
136
  await space.initializeDataPipeline();
@@ -143,8 +143,8 @@ export class DataSpaceManager {
143
143
  @synchronized
144
144
  async acceptSpace(opts: AcceptSpaceOptions): Promise<DataSpace> {
145
145
  log('accept space', { opts });
146
- assert(this._isOpen, 'Not open.');
147
- assert(!this._spaces.has(opts.spaceKey), 'Space already exists.');
146
+ invariant(this._isOpen, 'Not open.');
147
+ invariant(!this._spaces.has(opts.spaceKey), 'Space already exists.');
148
148
 
149
149
  const metadata: SpaceMetadata = {
150
150
  key: opts.spaceKey,
@@ -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 { DeferredTask, Event, scheduleTask, sleep, TimeoutError, Trigger } from '@dxos/async';
8
8
  import { Context, rejectOnDispose } from '@dxos/context';
@@ -85,7 +85,7 @@ export class NotarizationPlugin implements CredentialProcessor {
85
85
  successDelay = DEFAULT_SUCCESS_DELAY,
86
86
  }: NotarizeParams) {
87
87
  log('notarize', { credentials });
88
- assert(
88
+ invariant(
89
89
  credentials.every((credential) => credential.id),
90
90
  'Credentials must have an id',
91
91
  );
@@ -175,7 +175,7 @@ export class NotarizationPlugin implements CredentialProcessor {
175
175
  }
176
176
 
177
177
  setWriter(writer: FeedWriter<Credential>) {
178
- assert(!this._writer, 'Writer already set.');
178
+ invariant(!this._writer, 'Writer already set.');
179
179
  this._writer = writer;
180
180
  }
181
181
 
@@ -194,7 +194,7 @@ export class NotarizationPlugin implements CredentialProcessor {
194
194
  throw new Error(WRITER_NOT_SET_ERROR_CODE);
195
195
  }
196
196
  for (const credential of request.credentials ?? []) {
197
- assert(credential.id, 'Credential must have an id');
197
+ invariant(credential.id, 'Credential must have an id');
198
198
  if (this._processedCredentials.has(credential.id)) {
199
199
  continue;
200
200
  }
@@ -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,7 +2,6 @@
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';
@@ -15,7 +14,7 @@ import { MemoryTransportFactory, NetworkManager } from '@dxos/network-manager';
15
14
  import { createStorage, Storage, StorageType } from '@dxos/random-access-storage';
16
15
  import { BlobStore } from '@dxos/teleport-extension-object-sync';
17
16
 
18
- import { ClientServicesHost, ServiceContext } from '../services';
17
+ import { ClientServicesHost, createDefaultModelFactory, ServiceContext } from '../services';
19
18
  import { SigningContext } from '../spaces';
20
19
 
21
20
  //
@@ -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'> = {