@dxos/client-services 0.8.4-main.72ec0f3 → 0.8.4-main.74a063c4e0
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.
- package/dist/lib/browser/{chunk-HJH6BNTN.mjs → chunk-3LSLNVKQ.mjs} +2102 -1870
- package/dist/lib/browser/chunk-3LSLNVKQ.mjs.map +7 -0
- package/dist/lib/browser/chunk-NQSC7HOE.mjs +22 -0
- package/dist/lib/browser/chunk-NQSC7HOE.mjs.map +7 -0
- package/dist/lib/browser/chunk-QCWEHHJW.mjs +24 -0
- package/dist/lib/browser/chunk-QCWEHHJW.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +451 -67
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/packlets/diagnostics/browser-diagnostics-broadcast.mjs +93 -0
- package/dist/lib/browser/packlets/diagnostics/browser-diagnostics-broadcast.mjs.map +7 -0
- package/dist/lib/browser/packlets/diagnostics/diagnostics-broadcast.mjs +11 -0
- package/dist/lib/browser/packlets/diagnostics/diagnostics-broadcast.mjs.map +7 -0
- package/dist/lib/browser/packlets/locks/browser.mjs +126 -0
- package/dist/lib/browser/packlets/locks/browser.mjs.map +7 -0
- package/dist/lib/browser/packlets/locks/node.mjs +66 -0
- package/dist/lib/browser/packlets/locks/node.mjs.map +7 -0
- package/dist/lib/browser/testing/index.mjs +36 -17
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/chunk-2SZHAWBN.mjs +24 -0
- package/dist/lib/node-esm/chunk-2SZHAWBN.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-ONQM6RQH.mjs → chunk-5S7PIHLS.mjs} +1942 -1579
- package/dist/lib/node-esm/chunk-5S7PIHLS.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-PKEGMOQ4.mjs +22 -0
- package/dist/lib/node-esm/chunk-PKEGMOQ4.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +451 -67
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/packlets/diagnostics/browser-diagnostics-broadcast.mjs +93 -0
- package/dist/lib/node-esm/packlets/diagnostics/browser-diagnostics-broadcast.mjs.map +7 -0
- package/dist/lib/node-esm/packlets/diagnostics/diagnostics-broadcast.mjs +11 -0
- package/dist/lib/node-esm/packlets/diagnostics/diagnostics-broadcast.mjs.map +7 -0
- package/dist/lib/node-esm/packlets/locks/browser.mjs +126 -0
- package/dist/lib/node-esm/packlets/locks/browser.mjs.map +7 -0
- package/dist/lib/node-esm/packlets/locks/node.mjs +66 -0
- package/dist/lib/node-esm/packlets/locks/node.mjs.map +7 -0
- package/dist/lib/node-esm/testing/index.mjs +36 -17
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/packlets/agents/edge-agent-manager.d.ts +3 -2
- package/dist/types/src/packlets/agents/edge-agent-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/agents/edge-agent-service.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/devtools.d.ts +2 -2
- package/dist/types/src/packlets/devtools/devtools.d.ts.map +1 -1
- package/dist/types/src/packlets/diagnostics/index.d.ts +1 -1
- package/dist/types/src/packlets/diagnostics/index.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/authenticator.d.ts +2 -2
- package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/contacts-service.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-manager.d.ts +6 -6
- package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts +7 -6
- package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-service.d.ts +1 -6
- package/dist/types/src/packlets/identity/identity-service.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity.d.ts +8 -11
- package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts +4 -4
- package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/edge-invitation-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-guest-extenstion.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-host-extension.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-protocol.d.ts +2 -3
- package/dist/types/src/packlets/invitations/invitation-protocol.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts +4 -4
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-manager.d.ts +3 -3
- package/dist/types/src/packlets/invitations/invitations-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts +2 -2
- package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts.map +1 -1
- package/dist/types/src/packlets/locks/index.d.ts +1 -1
- package/dist/types/src/packlets/locks/index.d.ts.map +1 -1
- package/dist/types/src/packlets/logging/logging-service.d.ts +4 -0
- package/dist/types/src/packlets/logging/logging-service.d.ts.map +1 -1
- package/dist/types/src/packlets/network/network-service.d.ts.map +1 -1
- package/dist/types/src/packlets/services/client-rpc-server.d.ts +2 -2
- package/dist/types/src/packlets/services/client-rpc-server.d.ts.map +1 -1
- package/dist/types/src/packlets/services/feed-syncer.d.ts +59 -0
- package/dist/types/src/packlets/services/feed-syncer.d.ts.map +1 -0
- package/dist/types/src/packlets/services/feed-syncer.test.d.ts +2 -0
- package/dist/types/src/packlets/services/feed-syncer.test.d.ts.map +1 -0
- package/dist/types/src/packlets/services/platform.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts +13 -8
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +20 -6
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/space-archive-reader.d.ts +9 -1
- package/dist/types/src/packlets/space-export/space-archive-reader.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/space-archive-writer.d.ts +6 -0
- package/dist/types/src/packlets/space-export/space-archive-writer.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/space-archive.test.d.ts +2 -0
- package/dist/types/src/packlets/space-export/space-archive.test.d.ts.map +1 -0
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts +27 -15
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts +24 -8
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts +2 -2
- package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/genesis.d.ts +2 -1
- package/dist/types/src/packlets/spaces/genesis.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +6 -6
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts +2 -2
- package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/invitation-utils.d.ts +6 -3
- package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts +6 -5
- package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/packlets/worker/worker-runtime.d.ts +31 -4
- package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/worker/worker-session.d.ts +2 -2
- package/dist/types/src/packlets/worker/worker-session.d.ts.map +1 -1
- package/dist/types/src/version.d.ts +1 -1
- package/dist/types/src/version.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +70 -48
- package/src/index.ts +1 -0
- package/src/packlets/agents/edge-agent-manager.ts +8 -5
- package/src/packlets/agents/edge-agent-service.ts +2 -1
- package/src/packlets/devices/devices-service.test.ts +0 -1
- package/src/packlets/devtools/devtools.ts +2 -3
- package/src/packlets/diagnostics/index.ts +1 -1
- package/src/packlets/identity/authenticator.ts +2 -2
- package/src/packlets/identity/contacts-service.ts +0 -1
- package/src/packlets/identity/identity-manager.test.ts +5 -5
- package/src/packlets/identity/identity-manager.ts +21 -18
- package/src/packlets/identity/identity-recovery-manager.ts +22 -18
- package/src/packlets/identity/identity-service.test.ts +6 -27
- package/src/packlets/identity/identity-service.ts +5 -76
- package/src/packlets/identity/identity.test.ts +2 -2
- package/src/packlets/identity/identity.ts +9 -32
- package/src/packlets/invitations/device-invitation-protocol.ts +5 -6
- package/src/packlets/invitations/edge-invitation-handler.ts +4 -3
- package/src/packlets/invitations/invitation-guest-extenstion.ts +6 -4
- package/src/packlets/invitations/invitation-host-extension.ts +6 -4
- package/src/packlets/invitations/invitation-protocol.ts +2 -3
- package/src/packlets/invitations/invitations-handler.test.ts +4 -5
- package/src/packlets/invitations/invitations-handler.ts +10 -10
- package/src/packlets/invitations/invitations-manager.ts +37 -14
- package/src/packlets/invitations/invitations-service.ts +4 -4
- package/src/packlets/invitations/space-invitation-protocol.test.ts +17 -16
- package/src/packlets/invitations/space-invitation-protocol.ts +10 -15
- package/src/packlets/locks/index.ts +1 -1
- package/src/packlets/logging/logging-service.ts +4 -0
- package/src/packlets/network/network-service.test.ts +0 -1
- package/src/packlets/network/network-service.ts +5 -4
- package/src/packlets/services/client-rpc-server.ts +4 -4
- package/src/packlets/services/feed-syncer.test.ts +340 -0
- package/src/packlets/services/feed-syncer.ts +337 -0
- package/src/packlets/services/platform.ts +7 -1
- package/src/packlets/services/service-context.test.ts +3 -2
- package/src/packlets/services/service-context.ts +129 -44
- package/src/packlets/services/service-host.test.ts +8 -8
- package/src/packlets/services/service-host.ts +63 -22
- package/src/packlets/services/service-registry.test.ts +0 -1
- package/src/packlets/space-export/space-archive-reader.ts +64 -3
- package/src/packlets/space-export/space-archive-writer.ts +39 -2
- package/src/packlets/space-export/space-archive.test.ts +287 -0
- package/src/packlets/spaces/data-space-manager.test.ts +79 -13
- package/src/packlets/spaces/data-space-manager.ts +97 -107
- package/src/packlets/spaces/data-space.ts +52 -29
- package/src/packlets/spaces/edge-feed-replicator.test.ts +1 -1
- package/src/packlets/spaces/edge-feed-replicator.ts +10 -9
- package/src/packlets/spaces/epoch-migrations.ts +5 -5
- package/src/packlets/spaces/genesis.ts +6 -1
- package/src/packlets/spaces/notarization-plugin.test.ts +2 -2
- package/src/packlets/spaces/notarization-plugin.ts +10 -9
- package/src/packlets/spaces/spaces-service.test.ts +9 -7
- package/src/packlets/spaces/spaces-service.ts +40 -16
- package/src/packlets/storage/storage.ts +4 -4
- package/src/packlets/testing/invitation-utils.ts +10 -6
- package/src/packlets/testing/test-builder.ts +36 -10
- package/src/packlets/worker/worker-runtime.ts +150 -13
- package/src/packlets/worker/worker-session.ts +8 -8
- package/src/version.ts +1 -1
- package/dist/lib/browser/chunk-HJH6BNTN.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-ONQM6RQH.mjs.map +0 -7
- package/dist/types/src/packlets/identity/default-space-state-machine.d.ts +0 -19
- package/dist/types/src/packlets/identity/default-space-state-machine.d.ts.map +0 -1
- package/src/packlets/identity/default-space-state-machine.ts +0 -44
|
@@ -6,6 +6,7 @@ import type { AutomergeUrl } from '@automerge/automerge-repo';
|
|
|
6
6
|
|
|
7
7
|
import { SubscriptionList, UpdateScheduler, scheduleTask } from '@dxos/async';
|
|
8
8
|
import { Stream } from '@dxos/codec-protobuf/stream';
|
|
9
|
+
import { Context } from '@dxos/context';
|
|
9
10
|
import {
|
|
10
11
|
type CredentialProcessor,
|
|
11
12
|
createAdmissionCredentials,
|
|
@@ -45,6 +46,7 @@ import {
|
|
|
45
46
|
type SpacesService,
|
|
46
47
|
type SubscribeMessagesRequest,
|
|
47
48
|
type UpdateMemberRoleRequest,
|
|
49
|
+
type CreateSpaceRequest,
|
|
48
50
|
type UpdateSpaceRequest,
|
|
49
51
|
type WriteCredentialsRequest,
|
|
50
52
|
} from '@dxos/protocols/proto/dxos/client/services';
|
|
@@ -55,7 +57,6 @@ import { type Provider } from '@dxos/util';
|
|
|
55
57
|
|
|
56
58
|
import { type IdentityManager } from '../identity';
|
|
57
59
|
import { SpaceArchiveWriter, extractSpaceArchive } from '../space-export';
|
|
58
|
-
|
|
59
60
|
import { type DataSpace } from './data-space';
|
|
60
61
|
import { type DataSpaceManager } from './data-space-manager';
|
|
61
62
|
|
|
@@ -66,10 +67,13 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
66
67
|
private readonly _getDataSpaceManager: Provider<Promise<DataSpaceManager>>,
|
|
67
68
|
) {}
|
|
68
69
|
|
|
69
|
-
async createSpace(): Promise<Space> {
|
|
70
|
+
async createSpace(request: CreateSpaceRequest): Promise<Space> {
|
|
70
71
|
this._requireIdentity();
|
|
71
72
|
const dataSpaceManager = await this._getDataSpaceManager();
|
|
72
|
-
const space = await dataSpaceManager.createSpace()
|
|
73
|
+
const space = await dataSpaceManager.createSpace(new Context(), {
|
|
74
|
+
tags: request?.tags,
|
|
75
|
+
membershipPolicy: request?.membershipPolicy,
|
|
76
|
+
});
|
|
73
77
|
await this._updateMetrics();
|
|
74
78
|
return this._serializeSpace(space);
|
|
75
79
|
}
|
|
@@ -81,19 +85,19 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
81
85
|
if (state) {
|
|
82
86
|
switch (state) {
|
|
83
87
|
case SpaceState.SPACE_ACTIVE:
|
|
84
|
-
await space.activate();
|
|
88
|
+
await space.activate(Context.default());
|
|
85
89
|
break;
|
|
86
90
|
|
|
87
91
|
case SpaceState.SPACE_INACTIVE:
|
|
88
|
-
await space.deactivate();
|
|
92
|
+
await space.deactivate(Context.default());
|
|
89
93
|
break;
|
|
90
94
|
default:
|
|
91
|
-
throw new ApiError('Invalid space state');
|
|
95
|
+
throw new ApiError({ message: 'Invalid space state' });
|
|
92
96
|
}
|
|
93
97
|
}
|
|
94
98
|
|
|
95
99
|
if (edgeReplication !== undefined) {
|
|
96
|
-
await dataSpaceManager.setSpaceEdgeReplicationSetting(spaceKey, edgeReplication);
|
|
100
|
+
await dataSpaceManager.setSpaceEdgeReplicationSetting(Context.default(), spaceKey, edgeReplication);
|
|
97
101
|
}
|
|
98
102
|
}
|
|
99
103
|
|
|
@@ -104,9 +108,12 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
104
108
|
throw new SpaceNotFoundError(request.spaceKey);
|
|
105
109
|
}
|
|
106
110
|
if (!space.spaceState.hasMembershipManagementPermission(identity.identityKey)) {
|
|
107
|
-
throw new AuthorizationError(
|
|
108
|
-
|
|
109
|
-
|
|
111
|
+
throw new AuthorizationError({
|
|
112
|
+
message: 'No member management permission.',
|
|
113
|
+
context: {
|
|
114
|
+
spaceKey: space.key,
|
|
115
|
+
role: space.spaceState.getMemberRole(identity.identityKey),
|
|
116
|
+
},
|
|
110
117
|
});
|
|
111
118
|
}
|
|
112
119
|
const credentials = await createAdmissionCredentials(
|
|
@@ -261,7 +268,7 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
261
268
|
|
|
262
269
|
async joinBySpaceKey({ spaceKey }: JoinBySpaceKeyRequest): Promise<JoinSpaceResponse> {
|
|
263
270
|
const dataSpaceManager = await this._getDataSpaceManager();
|
|
264
|
-
const credential = await dataSpaceManager.requestSpaceAdmissionCredential(spaceKey);
|
|
271
|
+
const credential = await dataSpaceManager.requestSpaceAdmissionCredential(Context.default(), spaceKey);
|
|
265
272
|
return this._joinByAdmission({ credential });
|
|
266
273
|
}
|
|
267
274
|
|
|
@@ -280,6 +287,20 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
280
287
|
await writer.writeDocument(documentId, data);
|
|
281
288
|
}
|
|
282
289
|
|
|
290
|
+
const feeds = await space.getAllFeeds();
|
|
291
|
+
for (const feed of feeds) {
|
|
292
|
+
const archiveBlocks = feed.blocks.map((block) => ({
|
|
293
|
+
actorId: block.actorId,
|
|
294
|
+
sequence: block.sequence,
|
|
295
|
+
prevActorId: block.prevActorId,
|
|
296
|
+
prevSequence: block.prevSequence,
|
|
297
|
+
position: block.position,
|
|
298
|
+
timestamp: block.timestamp,
|
|
299
|
+
data: Buffer.from(block.data).toString('base64'),
|
|
300
|
+
}));
|
|
301
|
+
await writer.writeFeed(feed.feedId, feed.feedNamespace, archiveBlocks);
|
|
302
|
+
}
|
|
303
|
+
|
|
283
304
|
const archive = await writer.finish();
|
|
284
305
|
return { archive };
|
|
285
306
|
}
|
|
@@ -288,7 +309,7 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
288
309
|
const dataSpaceManager = await this._getDataSpaceManager();
|
|
289
310
|
const extracted = await extractSpaceArchive(request.archive);
|
|
290
311
|
invariant(extracted.metadata.echo?.currentRootUrl, 'Space archive does not contain a root URL');
|
|
291
|
-
const space = await dataSpaceManager.createSpace({
|
|
312
|
+
const space = await dataSpaceManager.createSpace(Context.default(), {
|
|
292
313
|
documents: extracted.documents,
|
|
293
314
|
rootUrl: extracted.metadata.echo?.currentRootUrl as AutomergeUrl,
|
|
294
315
|
});
|
|
@@ -305,9 +326,10 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
305
326
|
const dataSpaceManager = await this._getDataSpaceManager();
|
|
306
327
|
let dataSpace = dataSpaceManager.spaces.get(assertion.spaceKey);
|
|
307
328
|
if (!dataSpace) {
|
|
308
|
-
dataSpace = await dataSpaceManager.acceptSpace({
|
|
329
|
+
dataSpace = await dataSpaceManager.acceptSpace(Context.default(), {
|
|
309
330
|
spaceKey: assertion.spaceKey,
|
|
310
331
|
genesisFeedKey: assertion.genesisFeedKey,
|
|
332
|
+
tags: assertion.tags,
|
|
311
333
|
});
|
|
312
334
|
await myIdentity.controlPipeline.writer.write({ credential: { credential } });
|
|
313
335
|
}
|
|
@@ -360,6 +382,8 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
360
382
|
}),
|
|
361
383
|
),
|
|
362
384
|
creator: space.inner.spaceState.creator?.key,
|
|
385
|
+
tags: space.tags,
|
|
386
|
+
membershipPolicy: space.membershipPolicy,
|
|
363
387
|
cache: space.cache,
|
|
364
388
|
metrics: space.metrics,
|
|
365
389
|
edgeReplication: space.getEdgeReplicationSetting(),
|
|
@@ -368,9 +392,9 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
368
392
|
|
|
369
393
|
private _requireIdentity() {
|
|
370
394
|
if (!this._identityManager.identity) {
|
|
371
|
-
throw new IdentityNotInitializedError(
|
|
372
|
-
'This device has no HALO identity available. See https://docs.dxos.org/guide/platform/halo',
|
|
373
|
-
);
|
|
395
|
+
throw new IdentityNotInitializedError({
|
|
396
|
+
message: 'This device has no HALO identity available. See https://docs.dxos.org/guide/platform/halo',
|
|
397
|
+
});
|
|
374
398
|
}
|
|
375
399
|
return this._identityManager.identity;
|
|
376
400
|
}
|
|
@@ -14,16 +14,16 @@ import StorageDriver = Runtime.Client.Storage.StorageDriver;
|
|
|
14
14
|
export const createStorageObjects = (config: Runtime.Client.Storage) => {
|
|
15
15
|
const { persistent = false, keyStore, dataStore } = config ?? {};
|
|
16
16
|
if (persistent && dataStore === StorageDriver.RAM) {
|
|
17
|
-
throw new InvalidConfigError('RAM storage cannot be used in persistent mode.');
|
|
17
|
+
throw new InvalidConfigError({ message: 'RAM storage cannot be used in persistent mode.' });
|
|
18
18
|
}
|
|
19
19
|
if (!persistent && dataStore !== undefined && dataStore !== StorageDriver.RAM) {
|
|
20
|
-
throw new InvalidConfigError('Cannot use a persistent storage in not persistent mode.');
|
|
20
|
+
throw new InvalidConfigError({ message: 'Cannot use a persistent storage in not persistent mode.' });
|
|
21
21
|
}
|
|
22
22
|
if (persistent && keyStore === StorageDriver.RAM) {
|
|
23
|
-
throw new InvalidConfigError('RAM key storage cannot be used in persistent mode.');
|
|
23
|
+
throw new InvalidConfigError({ message: 'RAM key storage cannot be used in persistent mode.' });
|
|
24
24
|
}
|
|
25
25
|
if (!persistent && keyStore !== StorageDriver.RAM && keyStore !== undefined) {
|
|
26
|
-
throw new InvalidConfigError('Cannot use a persistent key storage in not persistent mode.');
|
|
26
|
+
throw new InvalidConfigError({ message: 'Cannot use a persistent key storage in not persistent mode.' });
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
return {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { Trigger } from '@dxos/async';
|
|
6
6
|
import { type AuthenticatingInvitation, type CancellableInvitation, InvitationEncoder } from '@dxos/client-protocol';
|
|
7
|
+
import { Context } from '@dxos/context';
|
|
7
8
|
import { invariant } from '@dxos/invariant';
|
|
8
9
|
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
9
10
|
import { type DeviceProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
@@ -36,15 +37,15 @@ export type PerformInvitationCallbacks<T> = {
|
|
|
36
37
|
onError?: (value: T) => boolean | void;
|
|
37
38
|
};
|
|
38
39
|
|
|
39
|
-
export type
|
|
40
|
+
export type PerformInvitationProps = {
|
|
40
41
|
host: ServiceContext | InvitationHost;
|
|
41
42
|
guest: ServiceContext | InvitationGuest;
|
|
43
|
+
guestDeviceProfile?: DeviceProfileDocument;
|
|
42
44
|
options?: Partial<Invitation>;
|
|
43
45
|
hooks?: {
|
|
44
46
|
host?: PerformInvitationCallbacks<CancellableInvitation>;
|
|
45
47
|
guest?: PerformInvitationCallbacks<AuthenticatingInvitation>;
|
|
46
48
|
};
|
|
47
|
-
guestDeviceProfile?: DeviceProfileDocument;
|
|
48
49
|
codeInputDelay?: number;
|
|
49
50
|
};
|
|
50
51
|
|
|
@@ -52,14 +53,17 @@ export type Result = { invitation?: Invitation; error?: Error };
|
|
|
52
53
|
|
|
53
54
|
// TODO(burdon): Make async.
|
|
54
55
|
// TODO(burdon): Rename startInvitation.
|
|
56
|
+
/**
|
|
57
|
+
*
|
|
58
|
+
*/
|
|
55
59
|
export const performInvitation = ({
|
|
56
60
|
host,
|
|
57
61
|
guest,
|
|
62
|
+
guestDeviceProfile,
|
|
58
63
|
options,
|
|
59
64
|
hooks,
|
|
60
|
-
guestDeviceProfile,
|
|
61
65
|
codeInputDelay,
|
|
62
|
-
}:
|
|
66
|
+
}: PerformInvitationProps): [Promise<Result>, Promise<Result>] => {
|
|
63
67
|
let guestError = false;
|
|
64
68
|
let guestConnected = false;
|
|
65
69
|
let wereConnected = false;
|
|
@@ -226,7 +230,7 @@ export const createInvitation = async (
|
|
|
226
230
|
};
|
|
227
231
|
|
|
228
232
|
if (host instanceof ServiceContext) {
|
|
229
|
-
return host.invitationsManager.createInvitation({
|
|
233
|
+
return host.invitationsManager.createInvitation(new Context(), {
|
|
230
234
|
kind: Invitation.Kind.SPACE,
|
|
231
235
|
...options,
|
|
232
236
|
});
|
|
@@ -243,7 +247,7 @@ export const acceptInvitation = (
|
|
|
243
247
|
invitation = sanitizeInvitation(invitation);
|
|
244
248
|
|
|
245
249
|
if (guest instanceof ServiceContext) {
|
|
246
|
-
return guest.invitationsManager.acceptInvitation({
|
|
250
|
+
return guest.invitationsManager.acceptInvitation(new Context(), {
|
|
247
251
|
invitation,
|
|
248
252
|
deviceProfile: guestDeviceProfile,
|
|
249
253
|
});
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import * as Reactivity from '@effect/experimental/Reactivity';
|
|
6
|
+
import * as Layer from 'effect/Layer';
|
|
7
|
+
import * as ManagedRuntime from 'effect/ManagedRuntime';
|
|
8
|
+
|
|
5
9
|
import { type Config } from '@dxos/config';
|
|
6
10
|
import { Context } from '@dxos/context';
|
|
7
11
|
import { CredentialGenerator, createCredentialSignerWithChain } from '@dxos/credentials';
|
|
@@ -15,11 +19,13 @@ import { MemorySignalManager, MemorySignalManagerContext, type SignalManager } f
|
|
|
15
19
|
import { MemoryTransportFactory, SwarmNetworkManager } from '@dxos/network-manager';
|
|
16
20
|
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
17
21
|
import { type Storage, StorageType, createStorage } from '@dxos/random-access-storage';
|
|
22
|
+
import { layerMemory as sqliteLayerMemory } from '@dxos/sql-sqlite/platform';
|
|
23
|
+
import * as SqlTransaction from '@dxos/sql-sqlite/SqlTransaction';
|
|
18
24
|
import { BlobStore } from '@dxos/teleport-extension-object-sync';
|
|
19
25
|
|
|
20
26
|
import { InvitationsHandler, InvitationsManager, SpaceInvitationProtocol } from '../invitations';
|
|
21
|
-
import { ClientServicesHost, ServiceContext, type
|
|
22
|
-
import { DataSpaceManager, type
|
|
27
|
+
import { ClientServicesHost, ServiceContext, type ServiceContextRuntimeProps } from '../services';
|
|
28
|
+
import { DataSpaceManager, type DataSpaceManagerRuntimeProps, type SigningContext } from '../spaces';
|
|
23
29
|
|
|
24
30
|
//
|
|
25
31
|
// TODO(burdon): Replace with test builder.
|
|
@@ -30,6 +36,11 @@ export const createServiceHost = (config: Config, signalManagerContext: MemorySi
|
|
|
30
36
|
config,
|
|
31
37
|
signalManager: new MemorySignalManager(signalManagerContext),
|
|
32
38
|
transportFactory: MemoryTransportFactory,
|
|
39
|
+
runtime: ManagedRuntime.make(
|
|
40
|
+
SqlTransaction.layer
|
|
41
|
+
.pipe(Layer.provideMerge(sqliteLayerMemory), Layer.provideMerge(Reactivity.layer))
|
|
42
|
+
.pipe(Layer.orDie),
|
|
43
|
+
).runtimeEffect,
|
|
33
44
|
});
|
|
34
45
|
};
|
|
35
46
|
|
|
@@ -39,11 +50,11 @@ export const createServiceContext = async ({
|
|
|
39
50
|
return new MemorySignalManager(signalContext);
|
|
40
51
|
},
|
|
41
52
|
storage = createStorage({ type: StorageType.RAM }),
|
|
42
|
-
|
|
53
|
+
runtimeProps,
|
|
43
54
|
}: {
|
|
44
55
|
signalManagerFactory?: () => Promise<SignalManager>;
|
|
45
56
|
storage?: Storage;
|
|
46
|
-
|
|
57
|
+
runtimeProps?: ServiceContextRuntimeProps;
|
|
47
58
|
} = {}) => {
|
|
48
59
|
const signalManager = await signalManagerFactory();
|
|
49
60
|
const networkManager = new SwarmNetworkManager({
|
|
@@ -53,9 +64,15 @@ export const createServiceContext = async ({
|
|
|
53
64
|
const level = createTestLevel();
|
|
54
65
|
await level.open();
|
|
55
66
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
67
|
+
const runtime = ManagedRuntime.make(
|
|
68
|
+
SqlTransaction.layer
|
|
69
|
+
.pipe(Layer.provideMerge(sqliteLayerMemory), Layer.provideMerge(Reactivity.layer))
|
|
70
|
+
.pipe(Layer.orDie),
|
|
71
|
+
).runtimeEffect;
|
|
72
|
+
|
|
73
|
+
return new ServiceContext(storage, level, networkManager, signalManager, undefined, undefined, runtime, {
|
|
74
|
+
invitationConnectionDefaultProps: { teleport: { controlHeartbeatInterval: 200 } },
|
|
75
|
+
...runtimeProps,
|
|
59
76
|
});
|
|
60
77
|
};
|
|
61
78
|
|
|
@@ -95,7 +112,7 @@ export class TestBuilder {
|
|
|
95
112
|
|
|
96
113
|
export type TestPeerOpts = {
|
|
97
114
|
dataStore?: StorageType;
|
|
98
|
-
|
|
115
|
+
dataSpaceProps?: DataSpaceManagerRuntimeProps;
|
|
99
116
|
};
|
|
100
117
|
|
|
101
118
|
export type TestPeerProps = {
|
|
@@ -116,6 +133,11 @@ export type TestPeerProps = {
|
|
|
116
133
|
|
|
117
134
|
export class TestPeer {
|
|
118
135
|
private _props: TestPeerProps = {};
|
|
136
|
+
private readonly _runtime = ManagedRuntime.make(
|
|
137
|
+
SqlTransaction.layer
|
|
138
|
+
.pipe(Layer.provideMerge(sqliteLayerMemory), Layer.provideMerge(Reactivity.layer))
|
|
139
|
+
.pipe(Layer.orDie),
|
|
140
|
+
);
|
|
119
141
|
|
|
120
142
|
constructor(
|
|
121
143
|
private readonly _signalContext: MemorySignalManagerContext,
|
|
@@ -179,7 +201,10 @@ export class TestPeer {
|
|
|
179
201
|
}
|
|
180
202
|
|
|
181
203
|
get echoHost() {
|
|
182
|
-
return (this._props.echoHost ??= new EchoHost({
|
|
204
|
+
return (this._props.echoHost ??= new EchoHost({
|
|
205
|
+
kv: this.level,
|
|
206
|
+
runtime: this._runtime.runtimeEffect,
|
|
207
|
+
}));
|
|
183
208
|
}
|
|
184
209
|
|
|
185
210
|
get meshEchoReplicator() {
|
|
@@ -198,7 +223,7 @@ export class TestPeer {
|
|
|
198
223
|
edgeConnection: undefined,
|
|
199
224
|
meshReplicator: this.meshEchoReplicator,
|
|
200
225
|
echoEdgeReplicator: undefined,
|
|
201
|
-
|
|
226
|
+
runtimeProps: this._opts.dataSpaceProps,
|
|
202
227
|
}));
|
|
203
228
|
}
|
|
204
229
|
|
|
@@ -227,6 +252,7 @@ export class TestPeer {
|
|
|
227
252
|
async destroy(): Promise<void> {
|
|
228
253
|
await this.level.close();
|
|
229
254
|
await this.storage.reset();
|
|
255
|
+
await this._runtime.dispose();
|
|
230
256
|
}
|
|
231
257
|
}
|
|
232
258
|
|
|
@@ -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,17 +22,21 @@ 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';
|
|
22
|
-
|
|
23
32
|
import { WorkerSession } from './worker-session';
|
|
24
33
|
|
|
25
34
|
// NOTE: Keep as RpcPorts to avoid dependency on @dxos/rpc-tunnel so we don't depend on browser-specific apis.
|
|
26
|
-
export type
|
|
35
|
+
export type CreateSessionProps = {
|
|
27
36
|
appPort: RpcPort;
|
|
28
37
|
systemPort: RpcPort;
|
|
29
38
|
shellPort?: RpcPort;
|
|
39
|
+
onClose?: () => Promise<void>;
|
|
30
40
|
};
|
|
31
41
|
|
|
32
42
|
export type WorkerRuntimeOptions = {
|
|
@@ -35,10 +45,20 @@ 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
|
+
/**
|
|
54
|
+
* Optional SQLite layer for Effect. Defaults to LocalSqliteOpfsLayer.
|
|
55
|
+
* For testing in Node.js, use `sqliteLayerMemory` from `@dxos/sql-sqlite/platform`.
|
|
56
|
+
*/
|
|
57
|
+
sqliteLayer?: Layer.Layer<SqlClient.SqlClient | SqlExport.SqlExport, unknown>;
|
|
38
58
|
};
|
|
39
59
|
|
|
40
60
|
/**
|
|
41
|
-
* Runtime for the shared worker.
|
|
61
|
+
* Runtime for the shared and dedciated worker.
|
|
42
62
|
* Manages connections from proxies (in tabs).
|
|
43
63
|
* Tabs make requests to the `ClientServicesHost`, and provide a WebRTC gateway.
|
|
44
64
|
*/
|
|
@@ -52,11 +72,17 @@ export class WorkerRuntime {
|
|
|
52
72
|
private readonly _sessions = new Set<WorkerSession>();
|
|
53
73
|
private readonly _clientServices!: ClientServicesHost;
|
|
54
74
|
private readonly _channel: string;
|
|
75
|
+
private readonly _automaticallyConnectWebrtc: boolean;
|
|
76
|
+
private readonly _livenessLock = new WebLockWrapper(`@dxos/client-services/WorkerRuntime/${crypto.randomUUID()}`);
|
|
55
77
|
private _broadcastChannel?: BroadcastChannel;
|
|
56
78
|
private _sessionForNetworking?: WorkerSession; // TODO(burdon): Expose to client QueryStatusResponse.
|
|
57
79
|
private _config!: Config;
|
|
58
80
|
private _signalMetadataTags: any = { runtime: 'worker-runtime' };
|
|
59
81
|
private _signalTelemetryEnabled: boolean = false;
|
|
82
|
+
private _runtime!: ManagedRuntime.ManagedRuntime<
|
|
83
|
+
SqlTransaction.SqlTransaction | SqlClient.SqlClient | SqlExport.SqlExport,
|
|
84
|
+
never
|
|
85
|
+
>;
|
|
60
86
|
|
|
61
87
|
constructor({
|
|
62
88
|
channel = DEFAULT_WORKER_BROADCAST_CHANNEL,
|
|
@@ -64,26 +90,49 @@ export class WorkerRuntime {
|
|
|
64
90
|
acquireLock,
|
|
65
91
|
releaseLock,
|
|
66
92
|
onStop,
|
|
93
|
+
automaticallyConnectWebrtc = true,
|
|
94
|
+
sqliteLayer,
|
|
67
95
|
}: WorkerRuntimeOptions) {
|
|
68
96
|
this._configProvider = configProvider;
|
|
69
97
|
this._acquireLock = acquireLock;
|
|
70
98
|
this._releaseLock = releaseLock;
|
|
71
99
|
this._onStop = onStop;
|
|
72
100
|
this._channel = channel;
|
|
101
|
+
if (sqliteLayer) {
|
|
102
|
+
log.warn('Using testing SQLite layer');
|
|
103
|
+
}
|
|
104
|
+
this._runtime = ManagedRuntime.make(
|
|
105
|
+
SqlTransaction.layer
|
|
106
|
+
.pipe(Layer.provideMerge(sqliteLayer ?? LocalSqliteOpfsLayer), Layer.provideMerge(Reactivity.layer))
|
|
107
|
+
.pipe(Layer.orDie),
|
|
108
|
+
);
|
|
73
109
|
this._clientServices = new ClientServicesHost({
|
|
74
110
|
callbacks: {
|
|
75
111
|
onReset: async () => this.stop(),
|
|
76
112
|
},
|
|
113
|
+
runtime: this._runtime.runtimeEffect,
|
|
114
|
+
runtimeProps: {
|
|
115
|
+
// Auto-activate spaces that were previously active after leader changeover.
|
|
116
|
+
autoActivateSpaces: true,
|
|
117
|
+
},
|
|
77
118
|
});
|
|
119
|
+
this._automaticallyConnectWebrtc = automaticallyConnectWebrtc;
|
|
78
120
|
}
|
|
79
121
|
|
|
80
122
|
get host() {
|
|
81
123
|
return this._clientServices;
|
|
82
124
|
}
|
|
83
125
|
|
|
126
|
+
get livenessLockKey(): string {
|
|
127
|
+
return this._livenessLock.key;
|
|
128
|
+
}
|
|
129
|
+
|
|
84
130
|
async start(): Promise<void> {
|
|
85
131
|
log('starting...');
|
|
86
132
|
try {
|
|
133
|
+
void this._livenessLock.acquire();
|
|
134
|
+
|
|
135
|
+
// Steal the lock from the other worker.
|
|
87
136
|
this._broadcastChannel = new BroadcastChannel(this._channel);
|
|
88
137
|
this._broadcastChannel.postMessage({ action: 'stop' });
|
|
89
138
|
this._broadcastChannel.onmessage = async (event) => {
|
|
@@ -126,14 +175,16 @@ export class WorkerRuntime {
|
|
|
126
175
|
this._releaseLock();
|
|
127
176
|
this._broadcastChannel?.close();
|
|
128
177
|
this._broadcastChannel = undefined;
|
|
129
|
-
await this._clientServices.close();
|
|
178
|
+
await this._clientServices.close(Context.default());
|
|
179
|
+
await this._runtime.dispose();
|
|
130
180
|
await this._onStop?.();
|
|
181
|
+
await this._livenessLock.release();
|
|
131
182
|
}
|
|
132
183
|
|
|
133
184
|
/**
|
|
134
185
|
* Create a new session.
|
|
135
186
|
*/
|
|
136
|
-
async createSession({ appPort, systemPort, shellPort }:
|
|
187
|
+
async createSession({ appPort, systemPort, shellPort, onClose }: CreateSessionProps): Promise<WorkerSession> {
|
|
137
188
|
const session = new WorkerSession({
|
|
138
189
|
serviceHost: this._clientServices,
|
|
139
190
|
appPort,
|
|
@@ -149,8 +200,11 @@ export class WorkerRuntime {
|
|
|
149
200
|
// Terminate the worker when all sessions are closed.
|
|
150
201
|
await this.stop();
|
|
151
202
|
} else {
|
|
152
|
-
this.
|
|
203
|
+
if (this._automaticallyConnectWebrtc) {
|
|
204
|
+
this._reconnectWebrtc();
|
|
205
|
+
}
|
|
153
206
|
}
|
|
207
|
+
await onClose?.();
|
|
154
208
|
});
|
|
155
209
|
|
|
156
210
|
await session.open();
|
|
@@ -166,7 +220,24 @@ export class WorkerRuntime {
|
|
|
166
220
|
this._signalMetadataTags.origin = session.origin;
|
|
167
221
|
this._sessions.add(session);
|
|
168
222
|
|
|
169
|
-
this.
|
|
223
|
+
if (this._automaticallyConnectWebrtc) {
|
|
224
|
+
this._reconnectWebrtc();
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return session;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Connects the WebRTC bridge to the specified session.
|
|
232
|
+
* If no session is provided, disconnects the WebRTC bridge.
|
|
233
|
+
*
|
|
234
|
+
* Called automatically if `automaticallyConnectWebrtc` is true.
|
|
235
|
+
*
|
|
236
|
+
* @param session The session to connect the WebRTC bridge to.
|
|
237
|
+
*/
|
|
238
|
+
connectWebrtcBridge(session: WorkerSession | undefined): void {
|
|
239
|
+
this._sessionForNetworking = session;
|
|
240
|
+
this._transportFactory.setBridgeService(session?.bridgeService);
|
|
170
241
|
}
|
|
171
242
|
|
|
172
243
|
/**
|
|
@@ -184,12 +255,78 @@ export class WorkerRuntime {
|
|
|
184
255
|
// Select existing session.
|
|
185
256
|
if (!this._sessionForNetworking) {
|
|
186
257
|
const selected = Array.from(this._sessions).find((session) => session.bridgeService);
|
|
187
|
-
|
|
188
|
-
this._sessionForNetworking = selected;
|
|
189
|
-
this._transportFactory.setBridgeService(selected.bridgeService);
|
|
190
|
-
} else {
|
|
191
|
-
this._transportFactory.setBridgeService(undefined);
|
|
192
|
-
}
|
|
258
|
+
this.connectWebrtcBridge(selected);
|
|
193
259
|
}
|
|
194
260
|
}
|
|
195
261
|
}
|
|
262
|
+
|
|
263
|
+
const DB_NAME = 'DXOS';
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* SqlExport layer that wraps SqliteClient to provide export functionality.
|
|
267
|
+
*/
|
|
268
|
+
const SqlExportLayer: Layer.Layer<SqlExport.SqlExport, never, SqliteClient.SqliteClient> = Layer.effect(
|
|
269
|
+
SqlExport.SqlExport,
|
|
270
|
+
Effect.gen(function* () {
|
|
271
|
+
const sql = yield* SqliteClient.SqliteClient;
|
|
272
|
+
return {
|
|
273
|
+
export: sql.export,
|
|
274
|
+
} satisfies SqlExport.Service;
|
|
275
|
+
}),
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Local SQLite layer for the worker.
|
|
280
|
+
* Uses OPFS sync API as an FS backend.
|
|
281
|
+
* Does NOT spawn a new worker.
|
|
282
|
+
* NOTE: Only usable within a worker.
|
|
283
|
+
* TODO(mykola): This does not work right now. Fix.
|
|
284
|
+
*/
|
|
285
|
+
const LocalSqliteOpfsLayer = Layer.unwrapScoped(
|
|
286
|
+
Effect.gen(function* () {
|
|
287
|
+
const { port1: clientPort, port2: serverPort } = new MessageChannel();
|
|
288
|
+
clientPort.start();
|
|
289
|
+
serverPort.start();
|
|
290
|
+
yield* Effect.addFinalizer(() =>
|
|
291
|
+
Effect.sync(() => {
|
|
292
|
+
clientPort.close();
|
|
293
|
+
serverPort.close();
|
|
294
|
+
}),
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
yield* Effect.forkScoped(OpfsWorker.run({ port: serverPort, dbName: DB_NAME }));
|
|
298
|
+
return SqlExportLayer.pipe(Layer.provideMerge(SqliteClient.layer({ worker: Effect.succeed(clientPort) })));
|
|
299
|
+
}),
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
// TODO(wittjosiah): Factor out to a separate module.
|
|
303
|
+
class WebLockWrapper {
|
|
304
|
+
readonly #key: string;
|
|
305
|
+
#release?: () => void;
|
|
306
|
+
|
|
307
|
+
constructor(key: string) {
|
|
308
|
+
this.#key = key;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
get key(): string {
|
|
312
|
+
return this.#key;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
acquire(options: LockOptions = {}) {
|
|
316
|
+
return navigator.locks.request(this.#key, options, async () => {
|
|
317
|
+
await new Promise<void>((resolve) => {
|
|
318
|
+
this.#release = resolve;
|
|
319
|
+
}); // Blocks for the duration of the worker's lifetime.
|
|
320
|
+
this.#release = undefined;
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
release() {
|
|
325
|
+
this.#release?.();
|
|
326
|
+
this.#release = undefined;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
[Symbol.dispose]() {
|
|
330
|
+
this.release();
|
|
331
|
+
}
|
|
332
|
+
}
|
|
@@ -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
|
|
18
|
+
import { ClientRpcServer, type ClientRpcServerProps, type ClientServicesHost } from '../services';
|
|
19
19
|
|
|
20
|
-
export type
|
|
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 }:
|
|
53
|
+
constructor({ serviceHost, systemPort, appPort, shellPort, readySignal }: WorkerSessionProps) {
|
|
54
54
|
invariant(serviceHost);
|
|
55
55
|
this._serviceHost = serviceHost;
|
|
56
56
|
|
|
57
|
-
const middleware: Pick<
|
|
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) {
|
|
@@ -119,7 +119,7 @@ export class WorkerSession {
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
async open(): Promise<void> {
|
|
122
|
-
log
|
|
122
|
+
log('opening...');
|
|
123
123
|
await Promise.all([this._clientRpc.open(), this._iframeRpc.open(), this._maybeOpenShell()]);
|
|
124
124
|
|
|
125
125
|
// Wait until the worker's RPC service has started.
|
|
@@ -130,11 +130,11 @@ export class WorkerSession {
|
|
|
130
130
|
void this._afterLockReleases(this.lockKey, () => this.close());
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
log
|
|
133
|
+
log('opened');
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
async close(): Promise<void> {
|
|
137
|
-
log.
|
|
137
|
+
log.debug('closing...');
|
|
138
138
|
try {
|
|
139
139
|
await this.onClose.callIfSet();
|
|
140
140
|
} catch (err: any) {
|
|
@@ -142,7 +142,7 @@ export class WorkerSession {
|
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
await Promise.all([this._clientRpc.close(), this._iframeRpc.close()]);
|
|
145
|
-
log.
|
|
145
|
+
log.debug('closed');
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
private async _maybeOpenShell(): Promise<void> {
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const DXOS_VERSION = "0.8.4-main.
|
|
1
|
+
export const DXOS_VERSION = "0.8.4-main.74a063c4e0";
|