@dxos/client-services 0.8.4-main.e8ec1fe → 0.8.4-main.ef1bc66f44
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-NQSC7HOE.mjs +22 -0
- package/dist/lib/browser/chunk-NQSC7HOE.mjs.map +7 -0
- package/dist/lib/browser/{chunk-CZSLDMSL.mjs → chunk-NTZOEM4P.mjs} +1197 -1338
- package/dist/lib/browser/chunk-NTZOEM4P.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 +441 -66
- 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 +24 -12
- 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-EUNILIU5.mjs → chunk-DQWA5ILA.mjs} +689 -699
- package/dist/lib/node-esm/chunk-DQWA5ILA.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 +441 -66
- 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 +24 -12
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- 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/default-space-state-machine.d.ts +2 -2
- package/dist/types/src/packlets/identity/default-space-state-machine.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-manager.d.ts +4 -4
- package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts +2 -2
- package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity.d.ts +2 -2
- 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/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/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/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 +41 -0
- package/dist/types/src/packlets/services/feed-syncer.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 -7
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +19 -5
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/space-archive-writer.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts +10 -5
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts +2 -2
- 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/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.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/packlets/devtools/devtools.ts +2 -2
- package/src/packlets/diagnostics/index.ts +1 -1
- package/src/packlets/identity/authenticator.ts +2 -2
- package/src/packlets/identity/default-space-state-machine.ts +2 -2
- package/src/packlets/identity/identity-manager.ts +6 -6
- package/src/packlets/identity/identity-recovery-manager.ts +2 -2
- package/src/packlets/identity/identity.ts +2 -2
- package/src/packlets/invitations/device-invitation-protocol.ts +5 -5
- 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.ts +7 -7
- package/src/packlets/invitations/space-invitation-protocol.ts +7 -13
- package/src/packlets/locks/index.ts +1 -1
- package/src/packlets/logging/logging-service.ts +4 -0
- package/src/packlets/services/client-rpc-server.ts +4 -4
- package/src/packlets/services/feed-syncer.ts +227 -0
- package/src/packlets/services/platform.ts +7 -1
- package/src/packlets/services/service-context.ts +47 -21
- package/src/packlets/services/service-host.ts +56 -16
- package/src/packlets/space-export/space-archive-reader.ts +1 -1
- package/src/packlets/space-export/space-archive-writer.ts +3 -2
- package/src/packlets/spaces/data-space-manager.ts +43 -20
- package/src/packlets/spaces/data-space.ts +10 -6
- package/src/packlets/spaces/edge-feed-replicator.ts +2 -2
- package/src/packlets/spaces/epoch-migrations.ts +2 -2
- package/src/packlets/spaces/notarization-plugin.test.ts +2 -2
- package/src/packlets/spaces/notarization-plugin.ts +8 -8
- package/src/packlets/spaces/spaces-service.ts +10 -7
- package/src/packlets/storage/storage.ts +4 -4
- package/src/packlets/testing/invitation-utils.ts +7 -4
- package/src/packlets/testing/test-builder.ts +36 -10
- package/src/packlets/worker/worker-runtime.ts +149 -11
- package/src/packlets/worker/worker-session.ts +4 -4
- package/src/version.ts +1 -1
- package/dist/lib/browser/chunk-CZSLDMSL.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-EUNILIU5.mjs.map +0 -7
|
@@ -6,7 +6,7 @@ import { type Doc } from '@automerge/automerge';
|
|
|
6
6
|
import { type AutomergeUrl, type DocHandle, type DocumentId, interpretAsDocumentId } from '@automerge/automerge-repo';
|
|
7
7
|
|
|
8
8
|
import { Event, synchronized, trackLeaks } from '@dxos/async';
|
|
9
|
-
import {
|
|
9
|
+
import { SpaceProperties } from '@dxos/client-protocol';
|
|
10
10
|
import { Context, LifecycleState, Resource, cancelWithContext } from '@dxos/context';
|
|
11
11
|
import {
|
|
12
12
|
type CredentialSigner,
|
|
@@ -15,14 +15,14 @@ import {
|
|
|
15
15
|
createAdmissionCredentials,
|
|
16
16
|
getCredentialAssertion,
|
|
17
17
|
} from '@dxos/credentials';
|
|
18
|
-
import {
|
|
18
|
+
import { Type } from '@dxos/echo';
|
|
19
|
+
import { getSchemaDXN } from '@dxos/echo/internal';
|
|
19
20
|
import {
|
|
20
21
|
AuthStatus,
|
|
21
22
|
CredentialServerExtension,
|
|
22
23
|
DatabaseRoot,
|
|
23
24
|
type EchoEdgeReplicator,
|
|
24
25
|
type EchoHost,
|
|
25
|
-
FIND_PARAMS,
|
|
26
26
|
type MeshEchoReplicator,
|
|
27
27
|
type MetadataStore,
|
|
28
28
|
type Space,
|
|
@@ -33,16 +33,16 @@ import {
|
|
|
33
33
|
} from '@dxos/echo-pipeline';
|
|
34
34
|
import {
|
|
35
35
|
type DatabaseDirectory,
|
|
36
|
+
EncodedReference,
|
|
36
37
|
type ObjectStructure,
|
|
37
38
|
SpaceDocVersion,
|
|
38
39
|
createIdFromSpaceKey,
|
|
39
|
-
encodeReference,
|
|
40
40
|
} from '@dxos/echo-protocol';
|
|
41
41
|
import type { EdgeConnection, EdgeHttpClient } from '@dxos/edge-client';
|
|
42
42
|
import { type FeedStore, writeMessages } from '@dxos/feed-store';
|
|
43
43
|
import { assertArgument, assertState, failedInvariant, invariant } from '@dxos/invariant';
|
|
44
44
|
import { type Keyring } from '@dxos/keyring';
|
|
45
|
-
import { PublicKey, type SpaceId } from '@dxos/keys';
|
|
45
|
+
import { ObjectId, PublicKey, type SpaceId } from '@dxos/keys';
|
|
46
46
|
import { log } from '@dxos/log';
|
|
47
47
|
import { AlreadyJoinedError, trace as Trace } from '@dxos/protocols';
|
|
48
48
|
import { Invitation, SpaceState } from '@dxos/protocols/proto/dxos/client/services';
|
|
@@ -104,7 +104,7 @@ export type AdmitMemberOptions = {
|
|
|
104
104
|
delegationCredentialId?: PublicKey;
|
|
105
105
|
};
|
|
106
106
|
|
|
107
|
-
export type
|
|
107
|
+
export type DataSpaceManagerProps = {
|
|
108
108
|
spaceManager: SpaceManager;
|
|
109
109
|
metadataStore: MetadataStore;
|
|
110
110
|
keyring: Keyring;
|
|
@@ -116,15 +116,20 @@ export type DataSpaceManagerParams = {
|
|
|
116
116
|
edgeHttpClient?: EdgeHttpClient;
|
|
117
117
|
meshReplicator?: MeshEchoReplicator;
|
|
118
118
|
echoEdgeReplicator?: EchoEdgeReplicator;
|
|
119
|
-
|
|
119
|
+
runtimeProps?: DataSpaceManagerRuntimeProps;
|
|
120
120
|
edgeFeatures?: Runtime.Client.EdgeFeatures;
|
|
121
121
|
};
|
|
122
122
|
|
|
123
|
-
export type
|
|
123
|
+
export type DataSpaceManagerRuntimeProps = {
|
|
124
124
|
spaceMemberPresenceAnnounceInterval?: number;
|
|
125
125
|
spaceMemberPresenceOfflineTimeout?: number;
|
|
126
126
|
activeEdgeNotarizationPollingInterval?: number;
|
|
127
127
|
disableP2pReplication?: boolean;
|
|
128
|
+
/**
|
|
129
|
+
* If true, spaces that were previously SPACE_ACTIVE will be automatically activated on startup.
|
|
130
|
+
* This is used in dedicated worker mode to restore space state after leader changeover.
|
|
131
|
+
*/
|
|
132
|
+
autoActivateSpaces?: boolean;
|
|
128
133
|
};
|
|
129
134
|
|
|
130
135
|
export type CreateSpaceOptions = {
|
|
@@ -152,9 +157,9 @@ export class DataSpaceManager extends Resource {
|
|
|
152
157
|
private readonly _edgeFeatures?: Runtime.Client.EdgeFeatures = undefined;
|
|
153
158
|
private readonly _meshReplicator?: MeshEchoReplicator = undefined;
|
|
154
159
|
private readonly _echoEdgeReplicator?: EchoEdgeReplicator = undefined;
|
|
155
|
-
private readonly
|
|
160
|
+
private readonly _runtimeProps?: DataSpaceManagerRuntimeProps = undefined;
|
|
156
161
|
|
|
157
|
-
constructor(params:
|
|
162
|
+
constructor(params: DataSpaceManagerProps) {
|
|
158
163
|
super();
|
|
159
164
|
|
|
160
165
|
this._spaceManager = params.spaceManager;
|
|
@@ -169,7 +174,7 @@ export class DataSpaceManager extends Resource {
|
|
|
169
174
|
this._edgeFeatures = params.edgeFeatures;
|
|
170
175
|
this._echoEdgeReplicator = params.echoEdgeReplicator;
|
|
171
176
|
this._edgeHttpClient = params.edgeHttpClient;
|
|
172
|
-
this.
|
|
177
|
+
this._runtimeProps = params.runtimeProps;
|
|
173
178
|
|
|
174
179
|
trace.diagnostic({
|
|
175
180
|
id: 'spaces',
|
|
@@ -179,12 +184,12 @@ export class DataSpaceManager extends Resource {
|
|
|
179
184
|
Array.from(this._spaces.values()).map(async (space) => {
|
|
180
185
|
const rootUrl = space.automergeSpaceState.rootUrl;
|
|
181
186
|
const rootHandle = rootUrl
|
|
182
|
-
? await this._echoHost.
|
|
187
|
+
? await this._echoHost.loadDoc<Doc<DatabaseDirectory>>(Context.default(), rootUrl as AutomergeUrl)
|
|
183
188
|
: undefined;
|
|
184
189
|
await rootHandle?.whenReady();
|
|
185
190
|
const rootDoc = rootHandle?.doc();
|
|
186
191
|
|
|
187
|
-
const properties = rootDoc && findInlineObjectOfType(rootDoc,
|
|
192
|
+
const properties = rootDoc && findInlineObjectOfType(rootDoc, Type.getTypename(SpaceProperties));
|
|
188
193
|
|
|
189
194
|
return {
|
|
190
195
|
key: space.key.toHex(),
|
|
@@ -217,15 +222,28 @@ export class DataSpaceManager extends Resource {
|
|
|
217
222
|
log.trace('dxos.echo.data-space-manager.open', Trace.begin({ id: this._instanceId }));
|
|
218
223
|
log('metadata loaded', { spaces: this._metadataStore.spaces.length });
|
|
219
224
|
|
|
225
|
+
const spacesToActivate: DataSpace[] = [];
|
|
220
226
|
await forEachAsync(this._metadataStore.spaces, async (spaceMetadata) => {
|
|
221
227
|
try {
|
|
222
228
|
log('load space', { spaceMetadata });
|
|
223
|
-
await this._constructSpace(spaceMetadata);
|
|
229
|
+
const space = await this._constructSpace(spaceMetadata);
|
|
230
|
+
// Track spaces that were previously active for auto-activation (used in dedicated worker mode).
|
|
231
|
+
if (this._runtimeProps?.autoActivateSpaces && spaceMetadata.state === SpaceState.SPACE_ACTIVE) {
|
|
232
|
+
spacesToActivate.push(space);
|
|
233
|
+
}
|
|
224
234
|
} catch (err) {
|
|
225
235
|
log.error('Error loading space', { spaceMetadata, err });
|
|
226
236
|
}
|
|
227
237
|
});
|
|
228
238
|
|
|
239
|
+
// Auto-activate spaces that were previously active (used in dedicated worker mode after leader changeover).
|
|
240
|
+
for (const space of spacesToActivate) {
|
|
241
|
+
log('auto-activating space', { spaceKey: space.key });
|
|
242
|
+
space.activate().catch((err) => {
|
|
243
|
+
log.error('Error auto-activating space', { spaceKey: space.key, err });
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
229
247
|
this.updated.emit();
|
|
230
248
|
|
|
231
249
|
log.trace('dxos.echo.data-space-manager.open', Trace.end({ id: this._instanceId }));
|
|
@@ -342,9 +360,12 @@ export class DataSpaceManager extends Resource {
|
|
|
342
360
|
log.warn('waiting for space root to be ready', { spaceId: space.id });
|
|
343
361
|
await space.databaseRoot.handle.whenReady();
|
|
344
362
|
}
|
|
345
|
-
|
|
363
|
+
|
|
364
|
+
const [_, properties] =
|
|
365
|
+
findInlineObjectOfType(space.databaseRoot.doc()!, Type.getTypename(SpaceProperties)) ?? [];
|
|
346
366
|
return properties?.data?.[DEFAULT_SPACE_KEY] === this._signingContext.identityKey.toHex();
|
|
347
367
|
}
|
|
368
|
+
|
|
348
369
|
case SpaceDocVersion.LEGACY: {
|
|
349
370
|
throw new Error('Legacy space version is not supported');
|
|
350
371
|
}
|
|
@@ -362,7 +383,7 @@ export class DataSpaceManager extends Resource {
|
|
|
362
383
|
// TODO(dmaretskyi): Better API for low-level data access.
|
|
363
384
|
const properties: ObjectStructure = {
|
|
364
385
|
system: {
|
|
365
|
-
type:
|
|
386
|
+
type: EncodedReference.fromDXN(getSchemaDXN(SpaceProperties)!),
|
|
366
387
|
},
|
|
367
388
|
data: {
|
|
368
389
|
[DEFAULT_SPACE_KEY]: this._signingContext.identityKey.toHex(),
|
|
@@ -384,7 +405,9 @@ export class DataSpaceManager extends Resource {
|
|
|
384
405
|
private async _getSpaceRootDocument(space: DataSpace): Promise<DocHandle<DatabaseDirectory>> {
|
|
385
406
|
const automergeIndex = space.automergeSpaceState.rootUrl;
|
|
386
407
|
invariant(automergeIndex);
|
|
387
|
-
const document = await this._echoHost.
|
|
408
|
+
const document = await this._echoHost.loadDoc<DatabaseDirectory>(Context.default(), automergeIndex as any, {
|
|
409
|
+
fetchFromNetwork: true,
|
|
410
|
+
});
|
|
388
411
|
await document.whenReady();
|
|
389
412
|
return document;
|
|
390
413
|
}
|
|
@@ -496,8 +519,8 @@ export class DataSpaceManager extends Resource {
|
|
|
496
519
|
localPeerId: this._signingContext.deviceKey,
|
|
497
520
|
});
|
|
498
521
|
const presence = new Presence({
|
|
499
|
-
announceInterval: this.
|
|
500
|
-
offlineTimeout: this.
|
|
522
|
+
announceInterval: this._runtimeProps?.spaceMemberPresenceAnnounceInterval ?? PRESENCE_ANNOUNCE_INTERVAL,
|
|
523
|
+
offlineTimeout: this._runtimeProps?.spaceMemberPresenceOfflineTimeout ?? PRESENCE_OFFLINE_TIMEOUT,
|
|
501
524
|
identityKey: this._signingContext.identityKey,
|
|
502
525
|
gossip,
|
|
503
526
|
});
|
|
@@ -583,7 +606,7 @@ export class DataSpaceManager extends Resource {
|
|
|
583
606
|
edgeConnection: this._edgeConnection,
|
|
584
607
|
edgeHttpClient: this._edgeHttpClient,
|
|
585
608
|
edgeFeatures: this._edgeFeatures,
|
|
586
|
-
activeEdgeNotarizationPollingInterval: this.
|
|
609
|
+
activeEdgeNotarizationPollingInterval: this._runtimeProps?.activeEdgeNotarizationPollingInterval,
|
|
587
610
|
});
|
|
588
611
|
dataSpace.postOpen.append(async () => {
|
|
589
612
|
const setting = dataSpace.getEdgeReplicationSetting();
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { save } from '@automerge/automerge';
|
|
6
|
-
import { type DocHandle } from '@automerge/automerge-repo';
|
|
6
|
+
import { type AutomergeUrl, type DocHandle } from '@automerge/automerge-repo';
|
|
7
7
|
|
|
8
8
|
import { Event, Mutex, scheduleTask, sleep, synchronized, trackLeaks } from '@dxos/async';
|
|
9
9
|
import { AUTH_TIMEOUT } from '@dxos/client-protocol';
|
|
@@ -13,7 +13,6 @@ import { timed, warnAfterTimeout } from '@dxos/debug';
|
|
|
13
13
|
import {
|
|
14
14
|
type DatabaseRoot,
|
|
15
15
|
type EchoHost,
|
|
16
|
-
FIND_PARAMS,
|
|
17
16
|
type MetadataStore,
|
|
18
17
|
type Space,
|
|
19
18
|
createMappedFeedWriter,
|
|
@@ -72,7 +71,7 @@ export type DataSpaceCallbacks = {
|
|
|
72
71
|
beforeClose?: () => Promise<void>;
|
|
73
72
|
};
|
|
74
73
|
|
|
75
|
-
export type
|
|
74
|
+
export type DataSpaceProps = {
|
|
76
75
|
initialState: SpaceState;
|
|
77
76
|
inner: Space;
|
|
78
77
|
metadataStore: MetadataStore;
|
|
@@ -136,7 +135,7 @@ export class DataSpace {
|
|
|
136
135
|
|
|
137
136
|
public metrics: SpaceProto.Metrics = {};
|
|
138
137
|
|
|
139
|
-
constructor(params:
|
|
138
|
+
constructor(params: DataSpaceProps) {
|
|
140
139
|
this._inner = params.inner;
|
|
141
140
|
this._inner.stateUpdate.on(this._ctx, () => this.stateUpdate.emit());
|
|
142
141
|
|
|
@@ -331,7 +330,7 @@ export class DataSpace {
|
|
|
331
330
|
@trace.span({ showInBrowserTimeline: true })
|
|
332
331
|
async initializeDataPipeline(): Promise<void> {
|
|
333
332
|
if (this._state !== SpaceState.SPACE_CONTROL_ONLY) {
|
|
334
|
-
throw new SystemError('Invalid operation');
|
|
333
|
+
throw new SystemError({ message: 'Invalid operation' });
|
|
335
334
|
}
|
|
336
335
|
|
|
337
336
|
this._state = SpaceState.SPACE_INITIALIZING;
|
|
@@ -451,6 +450,9 @@ export class DataSpace {
|
|
|
451
450
|
|
|
452
451
|
log('credentials notarized');
|
|
453
452
|
} catch (err) {
|
|
453
|
+
if (err instanceof ContextDisposedError) {
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
454
456
|
log.error('error notarizing credentials for feed admission', err);
|
|
455
457
|
throw err;
|
|
456
458
|
}
|
|
@@ -471,7 +473,9 @@ export class DataSpace {
|
|
|
471
473
|
await warnAfterTimeout(5_000, 'Automerge root doc load timeout (DataSpace)', async () => {
|
|
472
474
|
handle = await cancelWithContext(
|
|
473
475
|
this._ctx,
|
|
474
|
-
this._echoHost.
|
|
476
|
+
this._echoHost.loadDoc<DatabaseDirectory>(Context.default(), rootUrl as AutomergeUrl, {
|
|
477
|
+
fetchFromNetwork: true,
|
|
478
|
+
}),
|
|
475
479
|
);
|
|
476
480
|
await cancelWithContext(this._ctx, handle.whenReady());
|
|
477
481
|
});
|
|
@@ -22,7 +22,7 @@ import type { FeedBlock, ProtocolMessage } from '@dxos/protocols/feed-replicatio
|
|
|
22
22
|
import { EdgeStatus } from '@dxos/protocols/proto/dxos/client/services';
|
|
23
23
|
import { ComplexMap, arrayToBuffer, bufferToArray, defaultMap, rangeFromTo } from '@dxos/util';
|
|
24
24
|
|
|
25
|
-
export type
|
|
25
|
+
export type EdgeFeedReplicatorProps = {
|
|
26
26
|
messenger: EdgeConnection;
|
|
27
27
|
spaceId: SpaceId;
|
|
28
28
|
};
|
|
@@ -47,7 +47,7 @@ export class EdgeFeedReplicator extends Resource {
|
|
|
47
47
|
*/
|
|
48
48
|
private _pushMutex = new ComplexMap<PublicKey, Mutex>(PublicKey.hash);
|
|
49
49
|
|
|
50
|
-
constructor({ messenger, spaceId }:
|
|
50
|
+
constructor({ messenger, spaceId }: EdgeFeedReplicatorProps) {
|
|
51
51
|
super();
|
|
52
52
|
this._messenger = messenger;
|
|
53
53
|
this._spaceId = spaceId;
|
|
@@ -36,7 +36,7 @@ const LOAD_DOC_TIMEOUT = 10_000;
|
|
|
36
36
|
export const runEpochMigration = async (ctx: Context, context: MigrationContext): Promise<MigrationResult> => {
|
|
37
37
|
switch (context.migration) {
|
|
38
38
|
case CreateEpochRequest.Migration.INIT_AUTOMERGE: {
|
|
39
|
-
const document = context.echoHost.createDoc();
|
|
39
|
+
const document = await context.echoHost.createDoc();
|
|
40
40
|
await context.echoHost.flush();
|
|
41
41
|
return { newRoot: document.url };
|
|
42
42
|
}
|
|
@@ -48,7 +48,7 @@ export const runEpochMigration = async (ctx: Context, context: MigrationContext)
|
|
|
48
48
|
timeout: LOAD_DOC_TIMEOUT,
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
-
const newRoot = context.echoHost.createDoc(rootHandle.doc());
|
|
51
|
+
const newRoot = await context.echoHost.createDoc(rootHandle.doc());
|
|
52
52
|
await context.echoHost.flush();
|
|
53
53
|
return { newRoot: newRoot.url };
|
|
54
54
|
}
|
|
@@ -13,7 +13,7 @@ import { log } from '@dxos/log';
|
|
|
13
13
|
import { AdmittedFeed, type Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
14
14
|
import { TestBuilder, type TestConnection, TestPeer } from '@dxos/teleport/testing';
|
|
15
15
|
|
|
16
|
-
import { NotarizationPlugin, type
|
|
16
|
+
import { NotarizationPlugin, type NotarizationPluginProps } from './notarization-plugin';
|
|
17
17
|
|
|
18
18
|
class TestAgent extends TestPeer {
|
|
19
19
|
private readonly _ctx = new Context();
|
|
@@ -21,7 +21,7 @@ class TestAgent extends TestPeer {
|
|
|
21
21
|
feed = new MockFeedWriter<Credential>();
|
|
22
22
|
notarizationPlugin: NotarizationPlugin;
|
|
23
23
|
|
|
24
|
-
constructor(params:
|
|
24
|
+
constructor(params: NotarizationPluginProps) {
|
|
25
25
|
super();
|
|
26
26
|
this.notarizationPlugin = new NotarizationPlugin(params);
|
|
27
27
|
this.feed.written.on(this._ctx, async ([credential]) => {
|
|
@@ -33,14 +33,14 @@ const WRITER_NOT_SET_ERROR_CODE = 'WRITER_NOT_SET';
|
|
|
33
33
|
|
|
34
34
|
const credentialCodec = schema.getCodecForType('dxos.halo.credentials.Credential');
|
|
35
35
|
|
|
36
|
-
export type
|
|
36
|
+
export type NotarizationPluginProps = {
|
|
37
37
|
spaceId: SpaceId;
|
|
38
38
|
edgeClient?: EdgeHttpClient;
|
|
39
39
|
edgeFeatures?: Runtime.Client.EdgeFeatures;
|
|
40
40
|
activeEdgePollingInterval?: number;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
export type
|
|
43
|
+
export type NotarizeProps = {
|
|
44
44
|
/**
|
|
45
45
|
* For cancellation.
|
|
46
46
|
*/
|
|
@@ -97,7 +97,7 @@ export class NotarizationPlugin extends Resource implements CredentialProcessor
|
|
|
97
97
|
|
|
98
98
|
private readonly _edgeClient: EdgeHttpClient | undefined;
|
|
99
99
|
|
|
100
|
-
constructor(params:
|
|
100
|
+
constructor(params: NotarizationPluginProps) {
|
|
101
101
|
super();
|
|
102
102
|
this._spaceId = params.spaceId;
|
|
103
103
|
this._activeEdgePollingInterval = params.activeEdgePollingInterval ?? DEFAULT_ACTIVE_EDGE_POLLING_INTERVAL;
|
|
@@ -149,7 +149,7 @@ export class NotarizationPlugin extends Resource implements CredentialProcessor
|
|
|
149
149
|
retryTimeout = DEFAULT_RETRY_TIMEOUT,
|
|
150
150
|
successDelay = DEFAULT_SUCCESS_DELAY,
|
|
151
151
|
edgeRetryJitter,
|
|
152
|
-
}:
|
|
152
|
+
}: NotarizeProps): Promise<void> {
|
|
153
153
|
log('notarize', { credentials });
|
|
154
154
|
invariant(
|
|
155
155
|
credentials.every((credential) => credential.id),
|
|
@@ -392,21 +392,21 @@ export class NotarizationPlugin extends Resource implements CredentialProcessor
|
|
|
392
392
|
}
|
|
393
393
|
|
|
394
394
|
const handleEdgeError = (error: any) => {
|
|
395
|
-
if (!(error instanceof EdgeCallFailedError) || error.
|
|
395
|
+
if (!(error instanceof EdgeCallFailedError) || error.data) {
|
|
396
396
|
log.catch(error);
|
|
397
397
|
} else {
|
|
398
|
-
log.info('Edge notarization failure', {
|
|
398
|
+
log.info('Edge notarization failure', { message: error.message });
|
|
399
399
|
}
|
|
400
400
|
};
|
|
401
401
|
|
|
402
|
-
export type
|
|
402
|
+
export type NotarizationTeleportExtensionProps = {
|
|
403
403
|
onOpen: () => Promise<void>;
|
|
404
404
|
onClose: () => Promise<void>;
|
|
405
405
|
onNotarize: (request: NotarizeRequest) => Promise<void>;
|
|
406
406
|
};
|
|
407
407
|
|
|
408
408
|
export class NotarizationTeleportExtension extends RpcExtension<Services, Services> {
|
|
409
|
-
constructor(private readonly _params:
|
|
409
|
+
constructor(private readonly _params: NotarizationTeleportExtensionProps) {
|
|
410
410
|
super({
|
|
411
411
|
requested: {
|
|
412
412
|
NotarizationService: schema.getService('dxos.mesh.teleport.notarization.NotarizationService'),
|
|
@@ -88,7 +88,7 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
88
88
|
await space.deactivate();
|
|
89
89
|
break;
|
|
90
90
|
default:
|
|
91
|
-
throw new ApiError('Invalid space state');
|
|
91
|
+
throw new ApiError({ message: 'Invalid space state' });
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
|
|
@@ -104,9 +104,12 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
104
104
|
throw new SpaceNotFoundError(request.spaceKey);
|
|
105
105
|
}
|
|
106
106
|
if (!space.spaceState.hasMembershipManagementPermission(identity.identityKey)) {
|
|
107
|
-
throw new AuthorizationError(
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
throw new AuthorizationError({
|
|
108
|
+
message: 'No member management permission.',
|
|
109
|
+
context: {
|
|
110
|
+
spaceKey: space.key,
|
|
111
|
+
role: space.spaceState.getMemberRole(identity.identityKey),
|
|
112
|
+
},
|
|
110
113
|
});
|
|
111
114
|
}
|
|
112
115
|
const credentials = await createAdmissionCredentials(
|
|
@@ -368,9 +371,9 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
368
371
|
|
|
369
372
|
private _requireIdentity() {
|
|
370
373
|
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
|
-
);
|
|
374
|
+
throw new IdentityNotInitializedError({
|
|
375
|
+
message: 'This device has no HALO identity available. See https://docs.dxos.org/guide/platform/halo',
|
|
376
|
+
});
|
|
374
377
|
}
|
|
375
378
|
return this._identityManager.identity;
|
|
376
379
|
}
|
|
@@ -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 {
|
|
@@ -36,15 +36,15 @@ export type PerformInvitationCallbacks<T> = {
|
|
|
36
36
|
onError?: (value: T) => boolean | void;
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
export type
|
|
39
|
+
export type PerformInvitationProps = {
|
|
40
40
|
host: ServiceContext | InvitationHost;
|
|
41
41
|
guest: ServiceContext | InvitationGuest;
|
|
42
|
+
guestDeviceProfile?: DeviceProfileDocument;
|
|
42
43
|
options?: Partial<Invitation>;
|
|
43
44
|
hooks?: {
|
|
44
45
|
host?: PerformInvitationCallbacks<CancellableInvitation>;
|
|
45
46
|
guest?: PerformInvitationCallbacks<AuthenticatingInvitation>;
|
|
46
47
|
};
|
|
47
|
-
guestDeviceProfile?: DeviceProfileDocument;
|
|
48
48
|
codeInputDelay?: number;
|
|
49
49
|
};
|
|
50
50
|
|
|
@@ -52,14 +52,17 @@ export type Result = { invitation?: Invitation; error?: Error };
|
|
|
52
52
|
|
|
53
53
|
// TODO(burdon): Make async.
|
|
54
54
|
// TODO(burdon): Rename startInvitation.
|
|
55
|
+
/**
|
|
56
|
+
*
|
|
57
|
+
*/
|
|
55
58
|
export const performInvitation = ({
|
|
56
59
|
host,
|
|
57
60
|
guest,
|
|
61
|
+
guestDeviceProfile,
|
|
58
62
|
options,
|
|
59
63
|
hooks,
|
|
60
|
-
guestDeviceProfile,
|
|
61
64
|
codeInputDelay,
|
|
62
|
-
}:
|
|
65
|
+
}: PerformInvitationProps): [Promise<Result>, Promise<Result>] => {
|
|
63
66
|
let guestError = false;
|
|
64
67
|
let guestConnected = false;
|
|
65
68
|
let wereConnected = false;
|
|
@@ -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
|
|