@dxos/client-services 0.8.4-main.7ace549 → 0.8.4-main.937b3ca

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 (111) hide show
  1. package/dist/lib/browser/chunk-NQSC7HOE.mjs +22 -0
  2. package/dist/lib/browser/chunk-NQSC7HOE.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-QCWEHHJW.mjs +24 -0
  4. package/dist/lib/browser/chunk-QCWEHHJW.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-NXGWBEOK.mjs → chunk-UDCUM4WV.mjs} +922 -1265
  6. package/dist/lib/browser/chunk-UDCUM4WV.mjs.map +7 -0
  7. package/dist/lib/browser/index.mjs +432 -65
  8. package/dist/lib/browser/index.mjs.map +4 -4
  9. package/dist/lib/browser/meta.json +1 -1
  10. package/dist/lib/browser/packlets/diagnostics/browser-diagnostics-broadcast.mjs +93 -0
  11. package/dist/lib/browser/packlets/diagnostics/browser-diagnostics-broadcast.mjs.map +7 -0
  12. package/dist/lib/browser/packlets/diagnostics/diagnostics-broadcast.mjs +11 -0
  13. package/dist/lib/browser/packlets/diagnostics/diagnostics-broadcast.mjs.map +7 -0
  14. package/dist/lib/browser/packlets/locks/browser.mjs +126 -0
  15. package/dist/lib/browser/packlets/locks/browser.mjs.map +7 -0
  16. package/dist/lib/browser/packlets/locks/node.mjs +66 -0
  17. package/dist/lib/browser/packlets/locks/node.mjs.map +7 -0
  18. package/dist/lib/browser/testing/index.mjs +24 -12
  19. package/dist/lib/browser/testing/index.mjs.map +3 -3
  20. package/dist/lib/node-esm/chunk-2SZHAWBN.mjs +24 -0
  21. package/dist/lib/node-esm/chunk-2SZHAWBN.mjs.map +7 -0
  22. package/dist/lib/node-esm/chunk-PKEGMOQ4.mjs +22 -0
  23. package/dist/lib/node-esm/chunk-PKEGMOQ4.mjs.map +7 -0
  24. package/dist/lib/node-esm/{chunk-AO4R6IID.mjs → chunk-Q56HAUWS.mjs} +421 -633
  25. package/dist/lib/node-esm/chunk-Q56HAUWS.mjs.map +7 -0
  26. package/dist/lib/node-esm/index.mjs +432 -65
  27. package/dist/lib/node-esm/index.mjs.map +4 -4
  28. package/dist/lib/node-esm/meta.json +1 -1
  29. package/dist/lib/node-esm/packlets/diagnostics/browser-diagnostics-broadcast.mjs +93 -0
  30. package/dist/lib/node-esm/packlets/diagnostics/browser-diagnostics-broadcast.mjs.map +7 -0
  31. package/dist/lib/node-esm/packlets/diagnostics/diagnostics-broadcast.mjs +11 -0
  32. package/dist/lib/node-esm/packlets/diagnostics/diagnostics-broadcast.mjs.map +7 -0
  33. package/dist/lib/node-esm/packlets/locks/browser.mjs +126 -0
  34. package/dist/lib/node-esm/packlets/locks/browser.mjs.map +7 -0
  35. package/dist/lib/node-esm/packlets/locks/node.mjs +66 -0
  36. package/dist/lib/node-esm/packlets/locks/node.mjs.map +7 -0
  37. package/dist/lib/node-esm/testing/index.mjs +24 -12
  38. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  39. package/dist/types/src/packlets/devtools/devtools.d.ts +2 -2
  40. package/dist/types/src/packlets/devtools/devtools.d.ts.map +1 -1
  41. package/dist/types/src/packlets/diagnostics/index.d.ts +1 -1
  42. package/dist/types/src/packlets/diagnostics/index.d.ts.map +1 -1
  43. package/dist/types/src/packlets/identity/authenticator.d.ts +2 -2
  44. package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
  45. package/dist/types/src/packlets/identity/default-space-state-machine.d.ts +2 -2
  46. package/dist/types/src/packlets/identity/default-space-state-machine.d.ts.map +1 -1
  47. package/dist/types/src/packlets/identity/identity-manager.d.ts +4 -4
  48. package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
  49. package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts +2 -2
  50. package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts.map +1 -1
  51. package/dist/types/src/packlets/identity/identity.d.ts +2 -2
  52. package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
  53. package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts +2 -2
  54. package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts.map +1 -1
  55. package/dist/types/src/packlets/invitations/invitations-handler.d.ts +4 -4
  56. package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
  57. package/dist/types/src/packlets/locks/index.d.ts +1 -1
  58. package/dist/types/src/packlets/locks/index.d.ts.map +1 -1
  59. package/dist/types/src/packlets/services/client-rpc-server.d.ts +2 -2
  60. package/dist/types/src/packlets/services/client-rpc-server.d.ts.map +1 -1
  61. package/dist/types/src/packlets/services/service-context.d.ts +13 -7
  62. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  63. package/dist/types/src/packlets/services/service-host.d.ts +19 -5
  64. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  65. package/dist/types/src/packlets/space-export/space-archive-writer.d.ts.map +1 -1
  66. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +10 -5
  67. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  68. package/dist/types/src/packlets/spaces/data-space.d.ts +2 -2
  69. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  70. package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts +2 -2
  71. package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts.map +1 -1
  72. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +6 -6
  73. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
  74. package/dist/types/src/packlets/testing/invitation-utils.d.ts +6 -3
  75. package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
  76. package/dist/types/src/packlets/testing/test-builder.d.ts +6 -5
  77. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  78. package/dist/types/src/packlets/worker/worker-runtime.d.ts +23 -4
  79. package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -1
  80. package/dist/types/src/packlets/worker/worker-session.d.ts +2 -2
  81. package/dist/types/src/packlets/worker/worker-session.d.ts.map +1 -1
  82. package/dist/types/src/version.d.ts +1 -1
  83. package/dist/types/tsconfig.tsbuildinfo +1 -1
  84. package/package.json +70 -48
  85. package/src/packlets/devtools/devtools.ts +2 -2
  86. package/src/packlets/diagnostics/index.ts +1 -1
  87. package/src/packlets/identity/authenticator.ts +2 -2
  88. package/src/packlets/identity/default-space-state-machine.ts +2 -2
  89. package/src/packlets/identity/identity-manager.ts +6 -6
  90. package/src/packlets/identity/identity-recovery-manager.ts +2 -2
  91. package/src/packlets/identity/identity.ts +2 -2
  92. package/src/packlets/invitations/device-invitation-protocol.ts +2 -2
  93. package/src/packlets/invitations/invitations-handler.ts +6 -6
  94. package/src/packlets/locks/index.ts +1 -1
  95. package/src/packlets/services/client-rpc-server.ts +4 -4
  96. package/src/packlets/services/service-context.ts +30 -19
  97. package/src/packlets/services/service-host.ts +56 -16
  98. package/src/packlets/space-export/space-archive-writer.ts +3 -2
  99. package/src/packlets/spaces/data-space-manager.ts +35 -16
  100. package/src/packlets/spaces/data-space.ts +6 -5
  101. package/src/packlets/spaces/edge-feed-replicator.ts +2 -2
  102. package/src/packlets/spaces/epoch-migrations.ts +2 -2
  103. package/src/packlets/spaces/notarization-plugin.test.ts +2 -2
  104. package/src/packlets/spaces/notarization-plugin.ts +6 -6
  105. package/src/packlets/testing/invitation-utils.ts +7 -4
  106. package/src/packlets/testing/test-builder.ts +36 -10
  107. package/src/packlets/worker/worker-runtime.ts +141 -11
  108. package/src/packlets/worker/worker-session.ts +4 -4
  109. package/src/version.ts +1 -1
  110. package/dist/lib/browser/chunk-NXGWBEOK.mjs.map +0 -7
  111. package/dist/lib/node-esm/chunk-AO4R6IID.mjs.map +0 -7
@@ -2,6 +2,12 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
+ import * as Reactivity from '@effect/experimental/Reactivity';
6
+ import type * as SqlClient from '@effect/sql/SqlClient';
7
+ import * as Effect from 'effect/Effect';
8
+ import * as Layer from 'effect/Layer';
9
+ import * as ManagedRuntime from 'effect/ManagedRuntime';
10
+
5
11
  import { Trigger } from '@dxos/async';
6
12
  import { DEFAULT_WORKER_BROADCAST_CHANNEL } from '@dxos/client-protocol';
7
13
  import { type Config } from '@dxos/config';
@@ -16,6 +22,10 @@ import {
16
22
  } from '@dxos/messaging';
17
23
  import { RtcTransportProxyFactory } from '@dxos/network-manager';
18
24
  import { type RpcPort } from '@dxos/rpc';
25
+ import * as OpfsWorker from '@dxos/sql-sqlite/OpfsWorker';
26
+ import * as SqlExport from '@dxos/sql-sqlite/SqlExport';
27
+ import * as SqliteClient from '@dxos/sql-sqlite/SqliteClient';
28
+ import * as SqlTransaction from '@dxos/sql-sqlite/SqlTransaction';
19
29
  import { type MaybePromise } from '@dxos/util';
20
30
 
21
31
  import { ClientServicesHost } from '../services';
@@ -23,7 +33,7 @@ import { ClientServicesHost } from '../services';
23
33
  import { WorkerSession } from './worker-session';
24
34
 
25
35
  // NOTE: Keep as RpcPorts to avoid dependency on @dxos/rpc-tunnel so we don't depend on browser-specific apis.
26
- export type CreateSessionParams = {
36
+ export type CreateSessionProps = {
27
37
  appPort: RpcPort;
28
38
  systemPort: RpcPort;
29
39
  shellPort?: RpcPort;
@@ -35,10 +45,16 @@ export type WorkerRuntimeOptions = {
35
45
  acquireLock: () => Promise<void>;
36
46
  releaseLock: () => void;
37
47
  onStop?: () => Promise<void>;
48
+ /**
49
+ * @default true
50
+ */
51
+ automaticallyConnectWebrtc?: boolean;
52
+
53
+ enableSqlite?: boolean;
38
54
  };
39
55
 
40
56
  /**
41
- * Runtime for the shared worker.
57
+ * Runtime for the shared and dedciated worker.
42
58
  * Manages connections from proxies (in tabs).
43
59
  * Tabs make requests to the `ClientServicesHost`, and provide a WebRTC gateway.
44
60
  */
@@ -52,11 +68,17 @@ export class WorkerRuntime {
52
68
  private readonly _sessions = new Set<WorkerSession>();
53
69
  private readonly _clientServices!: ClientServicesHost;
54
70
  private readonly _channel: string;
71
+ private readonly _automaticallyConnectWebrtc: boolean;
72
+ private readonly _livenessLock = new WebLockWrapper(`@dxos/client-services/WorkerRuntime/${crypto.randomUUID()}`);
55
73
  private _broadcastChannel?: BroadcastChannel;
56
74
  private _sessionForNetworking?: WorkerSession; // TODO(burdon): Expose to client QueryStatusResponse.
57
75
  private _config!: Config;
58
76
  private _signalMetadataTags: any = { runtime: 'worker-runtime' };
59
77
  private _signalTelemetryEnabled: boolean = false;
78
+ private _runtime!: ManagedRuntime.ManagedRuntime<
79
+ SqlTransaction.SqlTransaction | SqlClient.SqlClient | SqlExport.SqlExport,
80
+ never
81
+ >;
60
82
 
61
83
  constructor({
62
84
  channel = DEFAULT_WORKER_BROADCAST_CHANNEL,
@@ -64,26 +86,47 @@ export class WorkerRuntime {
64
86
  acquireLock,
65
87
  releaseLock,
66
88
  onStop,
89
+ automaticallyConnectWebrtc = true,
90
+ enableSqlite,
67
91
  }: WorkerRuntimeOptions) {
68
92
  this._configProvider = configProvider;
69
93
  this._acquireLock = acquireLock;
70
94
  this._releaseLock = releaseLock;
71
95
  this._onStop = onStop;
72
96
  this._channel = channel;
97
+ this._runtime = ManagedRuntime.make(
98
+ SqlTransaction.layer
99
+ .pipe(Layer.provideMerge(LocalSqliteOpfsLayer), Layer.provideMerge(Reactivity.layer))
100
+ .pipe(Layer.orDie),
101
+ );
73
102
  this._clientServices = new ClientServicesHost({
74
103
  callbacks: {
75
104
  onReset: async () => this.stop(),
76
105
  },
106
+ runtime: this._runtime.runtimeEffect,
107
+ runtimeProps: {
108
+ enableSqlite,
109
+ // Auto-activate spaces that were previously active after leader changeover.
110
+ autoActivateSpaces: true,
111
+ },
77
112
  });
113
+ this._automaticallyConnectWebrtc = automaticallyConnectWebrtc;
78
114
  }
79
115
 
80
116
  get host() {
81
117
  return this._clientServices;
82
118
  }
83
119
 
120
+ get livenessLockKey(): string {
121
+ return this._livenessLock.key;
122
+ }
123
+
84
124
  async start(): Promise<void> {
85
125
  log('starting...');
86
126
  try {
127
+ void this._livenessLock.acquire();
128
+
129
+ // Steal the lock from the other worker.
87
130
  this._broadcastChannel = new BroadcastChannel(this._channel);
88
131
  this._broadcastChannel.postMessage({ action: 'stop' });
89
132
  this._broadcastChannel.onmessage = async (event) => {
@@ -127,13 +170,15 @@ export class WorkerRuntime {
127
170
  this._broadcastChannel?.close();
128
171
  this._broadcastChannel = undefined;
129
172
  await this._clientServices.close();
173
+ await this._runtime.dispose();
130
174
  await this._onStop?.();
175
+ await this._livenessLock.release();
131
176
  }
132
177
 
133
178
  /**
134
179
  * Create a new session.
135
180
  */
136
- async createSession({ appPort, systemPort, shellPort }: CreateSessionParams): Promise<void> {
181
+ async createSession({ appPort, systemPort, shellPort }: CreateSessionProps): Promise<WorkerSession> {
137
182
  const session = new WorkerSession({
138
183
  serviceHost: this._clientServices,
139
184
  appPort,
@@ -149,7 +194,9 @@ export class WorkerRuntime {
149
194
  // Terminate the worker when all sessions are closed.
150
195
  await this.stop();
151
196
  } else {
152
- this._reconnectWebrtc();
197
+ if (this._automaticallyConnectWebrtc) {
198
+ this._reconnectWebrtc();
199
+ }
153
200
  }
154
201
  });
155
202
 
@@ -166,7 +213,24 @@ export class WorkerRuntime {
166
213
  this._signalMetadataTags.origin = session.origin;
167
214
  this._sessions.add(session);
168
215
 
169
- this._reconnectWebrtc();
216
+ if (this._automaticallyConnectWebrtc) {
217
+ this._reconnectWebrtc();
218
+ }
219
+
220
+ return session;
221
+ }
222
+
223
+ /**
224
+ * Connects the WebRTC bridge to the specified session.
225
+ * If no session is provided, disconnects the WebRTC bridge.
226
+ *
227
+ * Called automatically if `automaticallyConnectWebrtc` is true.
228
+ *
229
+ * @param session The session to connect the WebRTC bridge to.
230
+ */
231
+ connectWebrtcBridge(session: WorkerSession | undefined): void {
232
+ this._sessionForNetworking = session;
233
+ this._transportFactory.setBridgeService(session?.bridgeService);
170
234
  }
171
235
 
172
236
  /**
@@ -184,12 +248,78 @@ export class WorkerRuntime {
184
248
  // Select existing session.
185
249
  if (!this._sessionForNetworking) {
186
250
  const selected = Array.from(this._sessions).find((session) => session.bridgeService);
187
- if (selected) {
188
- this._sessionForNetworking = selected;
189
- this._transportFactory.setBridgeService(selected.bridgeService);
190
- } else {
191
- this._transportFactory.setBridgeService(undefined);
192
- }
251
+ this.connectWebrtcBridge(selected);
193
252
  }
194
253
  }
195
254
  }
255
+
256
+ const DB_NAME = 'DXOS';
257
+
258
+ /**
259
+ * SqlExport layer that wraps SqliteClient to provide export functionality.
260
+ */
261
+ const SqlExportLayer: Layer.Layer<SqlExport.SqlExport, never, SqliteClient.SqliteClient> = Layer.effect(
262
+ SqlExport.SqlExport,
263
+ Effect.gen(function* () {
264
+ const sql = yield* SqliteClient.SqliteClient;
265
+ return {
266
+ export: sql.export,
267
+ } satisfies SqlExport.Service;
268
+ }),
269
+ );
270
+
271
+ /**
272
+ * Local SQLite layer for the worker.
273
+ * Uses OPFS sync API as an FS backend.
274
+ * Does NOT spawn a new worker.
275
+ * NOTE: Only usable within a worker.
276
+ * TODO(mykola): This does not work right now. Fix.
277
+ */
278
+ const LocalSqliteOpfsLayer = Layer.unwrapScoped(
279
+ Effect.gen(function* () {
280
+ const { port1: clientPort, port2: serverPort } = new MessageChannel();
281
+ clientPort.start();
282
+ serverPort.start();
283
+ yield* Effect.addFinalizer(() =>
284
+ Effect.sync(() => {
285
+ clientPort.close();
286
+ serverPort.close();
287
+ }),
288
+ );
289
+
290
+ yield* Effect.forkScoped(OpfsWorker.run({ port: serverPort, dbName: DB_NAME }));
291
+ return SqlExportLayer.pipe(Layer.provideMerge(SqliteClient.layer({ worker: Effect.succeed(clientPort) })));
292
+ }),
293
+ );
294
+
295
+ // TODO(wittjosiah): Factor out to a separate module.
296
+ class WebLockWrapper {
297
+ readonly #key: string;
298
+ #release?: () => void;
299
+
300
+ constructor(key: string) {
301
+ this.#key = key;
302
+ }
303
+
304
+ get key(): string {
305
+ return this.#key;
306
+ }
307
+
308
+ acquire(options: LockOptions = {}) {
309
+ return navigator.locks.request(this.#key, options, async () => {
310
+ await new Promise<void>((resolve) => {
311
+ this.#release = resolve;
312
+ }); // Blocks for the duration of the worker's lifetime.
313
+ this.#release = undefined;
314
+ });
315
+ }
316
+
317
+ release() {
318
+ this.#release?.();
319
+ this.#release = undefined;
320
+ }
321
+
322
+ [Symbol.dispose]() {
323
+ this.release();
324
+ }
325
+ }
@@ -15,9 +15,9 @@ import { type BridgeService } from '@dxos/protocols/proto/dxos/mesh/bridge';
15
15
  import { type ProtoRpcPeer, type RpcPort, createProtoRpcPeer } from '@dxos/rpc';
16
16
  import { Callback, type MaybePromise } from '@dxos/util';
17
17
 
18
- import { ClientRpcServer, type ClientRpcServerParams, type ClientServicesHost } from '../services';
18
+ import { ClientRpcServer, type ClientRpcServerProps, type ClientServicesHost } from '../services';
19
19
 
20
- export type WorkerSessionParams = {
20
+ export type WorkerSessionProps = {
21
21
  serviceHost: ClientServicesHost;
22
22
  systemPort: RpcPort;
23
23
  appPort: RpcPort;
@@ -50,11 +50,11 @@ export class WorkerSession {
50
50
 
51
51
  public bridgeService?: BridgeService;
52
52
 
53
- constructor({ serviceHost, systemPort, appPort, shellPort, readySignal }: WorkerSessionParams) {
53
+ constructor({ serviceHost, systemPort, appPort, shellPort, readySignal }: WorkerSessionProps) {
54
54
  invariant(serviceHost);
55
55
  this._serviceHost = serviceHost;
56
56
 
57
- const middleware: Pick<ClientRpcServerParams, 'handleCall' | 'handleStream'> = {
57
+ const middleware: Pick<ClientRpcServerProps, 'handleCall' | 'handleStream'> = {
58
58
  handleCall: async (method, params, handler) => {
59
59
  const error = await readySignal.wait({ timeout: PROXY_CONNECTION_TIMEOUT });
60
60
  if (error) {
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const DXOS_VERSION = "0.8.4-main.7ace549";
1
+ export const DXOS_VERSION = "0.8.4-main.937b3ca";