@dxos/client-services 0.8.4-main.f5c0578 → 0.8.4-main.fcfe5033a5
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-WBMHLEAB.mjs → chunk-HYGNOM23.mjs} +2843 -2114
- package/dist/lib/browser/chunk-HYGNOM23.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 +512 -90
- 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 +37 -19
- 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-IPVFX6KI.mjs → chunk-GFT7MAQE.mjs} +2571 -1711
- package/dist/lib/node-esm/chunk-GFT7MAQE.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 +512 -90
- 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 +37 -19
- 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 +2 -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/diagnostics.d.ts +1 -2
- package/dist/types/src/packlets/diagnostics/diagnostics.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 +6 -10
- 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 +6 -5
- 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 +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 +7 -4
- package/dist/types/src/packlets/invitations/invitation-protocol.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-state.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/invitations-service.d.ts +3 -3
- package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts +4 -3
- 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 +5 -4
- package/dist/types/src/packlets/network/network-service.d.ts.map +1 -1
- package/dist/types/src/packlets/services/client-rpc-server.d.ts +5 -5
- 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 -7
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/archive-format.d.ts +9 -0
- package/dist/types/src/packlets/space-export/archive-format.d.ts.map +1 -0
- package/dist/types/src/packlets/space-export/index.d.ts +4 -1
- package/dist/types/src/packlets/space-export/index.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/serialized-space-reader.d.ts +23 -0
- package/dist/types/src/packlets/space-export/serialized-space-reader.d.ts.map +1 -0
- package/dist/types/src/packlets/space-export/serialized-space-writer.d.ts +36 -0
- package/dist/types/src/packlets/space-export/serialized-space-writer.d.ts.map +1 -0
- 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 +7 -1
- 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 +28 -16
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts +26 -9
- 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 +17 -7
- 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 +41 -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 -4
- 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 +10 -7
- package/src/packlets/agents/edge-agent-service.ts +15 -3
- package/src/packlets/devices/devices-service.test.ts +0 -1
- package/src/packlets/devices/devices-service.ts +1 -1
- package/src/packlets/devtools/devtools.ts +2 -3
- package/src/packlets/diagnostics/diagnostics.ts +1 -2
- 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 +13 -81
- package/src/packlets/identity/identity.test.ts +6 -6
- package/src/packlets/identity/identity.ts +11 -34
- package/src/packlets/invitations/device-invitation-protocol.ts +8 -7
- package/src/packlets/invitations/edge-invitation-handler.ts +9 -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 +7 -4
- package/src/packlets/invitations/invitation-state.ts +0 -10
- package/src/packlets/invitations/invitations-handler.test.ts +4 -5
- package/src/packlets/invitations/invitations-handler.ts +69 -13
- package/src/packlets/invitations/invitations-manager.ts +40 -15
- package/src/packlets/invitations/invitations-service.ts +9 -9
- package/src/packlets/invitations/space-invitation-protocol.test.ts +17 -16
- package/src/packlets/invitations/space-invitation-protocol.ts +11 -16
- package/src/packlets/locks/index.ts +1 -1
- package/src/packlets/logging/logging-service.ts +5 -1
- package/src/packlets/network/network-service.test.ts +0 -1
- package/src/packlets/network/network-service.ts +10 -8
- package/src/packlets/services/client-rpc-server.ts +19 -16
- 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 +141 -55
- package/src/packlets/services/service-host.test.ts +8 -8
- package/src/packlets/services/service-host.ts +77 -32
- package/src/packlets/services/service-registry.test.ts +0 -1
- package/src/packlets/space-export/archive-format.ts +42 -0
- package/src/packlets/space-export/index.ts +4 -1
- package/src/packlets/space-export/serialized-space-reader.ts +111 -0
- package/src/packlets/space-export/serialized-space-writer.ts +246 -0
- package/src/packlets/space-export/space-archive-reader.ts +65 -4
- package/src/packlets/space-export/space-archive-writer.ts +43 -5
- package/src/packlets/space-export/space-archive.test.ts +461 -0
- package/src/packlets/spaces/data-space-manager.test.ts +79 -13
- package/src/packlets/spaces/data-space-manager.ts +122 -110
- package/src/packlets/spaces/data-space.ts +58 -33
- package/src/packlets/spaces/edge-feed-replicator.test.ts +2 -2
- package/src/packlets/spaces/edge-feed-replicator.ts +12 -10
- 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 +18 -11
- package/src/packlets/spaces/spaces-service.ts +124 -25
- 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 +179 -17
- package/src/packlets/worker/worker-session.ts +12 -18
- package/src/version.ts +1 -1
- package/dist/lib/browser/chunk-WBMHLEAB.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-IPVFX6KI.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
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { describe, expect, test } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { asyncTimeout, latch } from '@dxos/async';
|
|
8
|
+
import { Context } from '@dxos/context';
|
|
8
9
|
import { createAdmissionCredentials } from '@dxos/credentials';
|
|
9
10
|
import { AuthStatus } from '@dxos/echo-pipeline';
|
|
10
11
|
import { writeMessages } from '@dxos/feed-store';
|
|
@@ -22,7 +23,7 @@ describe('DataSpaceManager', () => {
|
|
|
22
23
|
await peer.createIdentity();
|
|
23
24
|
await openAndClose(peer.echoHost, peer.dataSpaceManager);
|
|
24
25
|
|
|
25
|
-
const space = await peer.dataSpaceManager.createSpace();
|
|
26
|
+
const space = await peer.dataSpaceManager.createSpace(new Context());
|
|
26
27
|
|
|
27
28
|
// Process all written mutations.
|
|
28
29
|
await space.inner.controlPipeline.state.waitUntilTimeframe(space.inner.controlPipeline.state.endTimeframe);
|
|
@@ -45,7 +46,7 @@ describe('DataSpaceManager', () => {
|
|
|
45
46
|
await openAndClose(peer1.echoHost, peer1.dataSpaceManager, peer2.echoHost, peer2.dataSpaceManager);
|
|
46
47
|
await connectReplicators([peer1, peer2]);
|
|
47
48
|
|
|
48
|
-
const space1 = await peer1.dataSpaceManager.createSpace();
|
|
49
|
+
const space1 = await peer1.dataSpaceManager.createSpace(new Context());
|
|
49
50
|
await space1.inner.controlPipeline.state.waitUntilTimeframe(space1.inner.controlPipeline.state.endTimeframe);
|
|
50
51
|
|
|
51
52
|
// Admit peer2 to space1.
|
|
@@ -60,7 +61,7 @@ describe('DataSpaceManager', () => {
|
|
|
60
61
|
);
|
|
61
62
|
|
|
62
63
|
// Accept must be called after admission so that the peer can authenticate for notarization.
|
|
63
|
-
const space2 = await peer2.dataSpaceManager.acceptSpace({
|
|
64
|
+
const space2 = await peer2.dataSpaceManager.acceptSpace(new Context(), {
|
|
64
65
|
spaceKey: space1.key,
|
|
65
66
|
genesisFeedKey: space1.inner.genesisFeedKey,
|
|
66
67
|
});
|
|
@@ -115,7 +116,7 @@ describe('DataSpaceManager', () => {
|
|
|
115
116
|
await openAndClose(peer1.echoHost, peer1.dataSpaceManager, peer2.echoHost, peer2.dataSpaceManager);
|
|
116
117
|
await connectReplicators([peer1, peer2]);
|
|
117
118
|
|
|
118
|
-
const space1 = await peer1.dataSpaceManager.createSpace();
|
|
119
|
+
const space1 = await peer1.dataSpaceManager.createSpace(new Context());
|
|
119
120
|
await space1.inner.controlPipeline.state.waitUntilTimeframe(space1.inner.controlPipeline.state.endTimeframe);
|
|
120
121
|
|
|
121
122
|
// Admit peer2 to space1.
|
|
@@ -130,7 +131,7 @@ describe('DataSpaceManager', () => {
|
|
|
130
131
|
);
|
|
131
132
|
|
|
132
133
|
// Accept must be called after admission so that the peer can authenticate for notarization.
|
|
133
|
-
const space2 = await peer2.dataSpaceManager.acceptSpace({
|
|
134
|
+
const space2 = await peer2.dataSpaceManager.acceptSpace(new Context(), {
|
|
134
135
|
spaceKey: space1.key,
|
|
135
136
|
genesisFeedKey: space1.inner.genesisFeedKey,
|
|
136
137
|
});
|
|
@@ -149,6 +150,71 @@ describe('DataSpaceManager', () => {
|
|
|
149
150
|
await receivedMessage();
|
|
150
151
|
});
|
|
151
152
|
|
|
153
|
+
test('create space with tags', async () => {
|
|
154
|
+
const builder = new TestBuilder();
|
|
155
|
+
const peer = builder.createPeer();
|
|
156
|
+
await peer.createIdentity();
|
|
157
|
+
await openAndClose(peer.echoHost, peer.dataSpaceManager);
|
|
158
|
+
|
|
159
|
+
const space = await peer.dataSpaceManager.createSpace(new Context(), { tags: ['personal', 'test'] });
|
|
160
|
+
await space.inner.controlPipeline.state.waitUntilTimeframe(space.inner.controlPipeline.state.endTimeframe);
|
|
161
|
+
|
|
162
|
+
expect(space.inner.spaceState.tags).toEqual(['personal', 'test']);
|
|
163
|
+
expect(space.inner.spaceState.genesisCredential).to.exist;
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test('create space without tags has empty tags', async () => {
|
|
167
|
+
const builder = new TestBuilder();
|
|
168
|
+
const peer = builder.createPeer();
|
|
169
|
+
await peer.createIdentity();
|
|
170
|
+
await openAndClose(peer.echoHost, peer.dataSpaceManager);
|
|
171
|
+
|
|
172
|
+
const space = await peer.dataSpaceManager.createSpace(new Context());
|
|
173
|
+
await space.inner.controlPipeline.state.waitUntilTimeframe(space.inner.controlPipeline.state.endTimeframe);
|
|
174
|
+
|
|
175
|
+
expect(space.inner.spaceState.tags).toEqual([]);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test('tags propagate through peer admission', async () => {
|
|
179
|
+
const builder = new TestBuilder();
|
|
180
|
+
const peer1 = builder.createPeer();
|
|
181
|
+
await peer1.createIdentity();
|
|
182
|
+
const peer2 = builder.createPeer();
|
|
183
|
+
await peer2.createIdentity();
|
|
184
|
+
|
|
185
|
+
await openAndClose(peer1.echoHost, peer1.dataSpaceManager, peer2.echoHost, peer2.dataSpaceManager);
|
|
186
|
+
await connectReplicators([peer1, peer2]);
|
|
187
|
+
|
|
188
|
+
const space1 = await peer1.dataSpaceManager.createSpace(new Context(), { tags: ['personal'] });
|
|
189
|
+
await space1.inner.controlPipeline.state.waitUntilTimeframe(space1.inner.controlPipeline.state.endTimeframe);
|
|
190
|
+
|
|
191
|
+
// Admit peer2 to space1.
|
|
192
|
+
await writeMessages(
|
|
193
|
+
space1.inner.controlPipeline.writer,
|
|
194
|
+
await createAdmissionCredentials(
|
|
195
|
+
peer1.identity.credentialSigner,
|
|
196
|
+
peer2.identity.identityKey,
|
|
197
|
+
space1.key,
|
|
198
|
+
space1.inner.genesisFeedKey,
|
|
199
|
+
undefined, // role (default ADMIN)
|
|
200
|
+
undefined, // membershipChainHeads
|
|
201
|
+
undefined, // profile
|
|
202
|
+
undefined, // invitationCredentialId
|
|
203
|
+
space1.inner.spaceState.tags, // tags
|
|
204
|
+
),
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
const space2 = await peer2.dataSpaceManager.acceptSpace(new Context(), {
|
|
208
|
+
spaceKey: space1.key,
|
|
209
|
+
genesisFeedKey: space1.inner.genesisFeedKey,
|
|
210
|
+
tags: space1.inner.spaceState.tags,
|
|
211
|
+
});
|
|
212
|
+
await peer2.dataSpaceManager.waitUntilSpaceReady(space2.key);
|
|
213
|
+
|
|
214
|
+
// Peer2's space should have the same tags.
|
|
215
|
+
expect(space2.inner.spaceState.tags).toEqual(['personal']);
|
|
216
|
+
});
|
|
217
|
+
|
|
152
218
|
describe('activation', () => {
|
|
153
219
|
test('can activate and deactivate a space', async () => {
|
|
154
220
|
const builder = new TestBuilder();
|
|
@@ -157,14 +223,14 @@ describe('DataSpaceManager', () => {
|
|
|
157
223
|
await peer.createIdentity();
|
|
158
224
|
await openAndClose(peer.echoHost, peer.dataSpaceManager);
|
|
159
225
|
|
|
160
|
-
const space = await peer.dataSpaceManager.createSpace();
|
|
226
|
+
const space = await peer.dataSpaceManager.createSpace(new Context());
|
|
161
227
|
await space.inner.controlPipeline.state.waitUntilTimeframe(space.inner.controlPipeline.state.endTimeframe);
|
|
162
228
|
expect(space.state).to.equal(SpaceState.SPACE_READY);
|
|
163
229
|
|
|
164
|
-
await space.deactivate();
|
|
230
|
+
await space.deactivate(new Context());
|
|
165
231
|
expect(space.state).to.equal(SpaceState.SPACE_INACTIVE);
|
|
166
232
|
|
|
167
|
-
await space.activate();
|
|
233
|
+
await space.activate(new Context());
|
|
168
234
|
await asyncTimeout(
|
|
169
235
|
space.stateUpdate.waitForCondition(() => space.state === SpaceState.SPACE_READY),
|
|
170
236
|
500,
|
|
@@ -178,12 +244,12 @@ describe('DataSpaceManager', () => {
|
|
|
178
244
|
await peer.createIdentity();
|
|
179
245
|
await openAndClose(peer.echoHost, peer.dataSpaceManager);
|
|
180
246
|
|
|
181
|
-
await peer.dataSpaceManager.createSpace();
|
|
247
|
+
await peer.dataSpaceManager.createSpace(new Context());
|
|
182
248
|
await reloadDataSpaces(peer);
|
|
183
249
|
|
|
184
250
|
const space = getFirstSpace(peer);
|
|
185
251
|
expect(space.state).to.equal(SpaceState.SPACE_CLOSED);
|
|
186
|
-
await space.activate();
|
|
252
|
+
await space.activate(new Context());
|
|
187
253
|
await asyncTimeout(
|
|
188
254
|
space.stateUpdate.waitForCondition(() => space.state === SpaceState.SPACE_READY),
|
|
189
255
|
500,
|
|
@@ -197,10 +263,10 @@ describe('DataSpaceManager', () => {
|
|
|
197
263
|
await peer.createIdentity();
|
|
198
264
|
await openAndClose(peer.echoHost, peer.dataSpaceManager);
|
|
199
265
|
|
|
200
|
-
await peer.dataSpaceManager.createSpace();
|
|
266
|
+
await peer.dataSpaceManager.createSpace(new Context());
|
|
201
267
|
await reloadDataSpaces(peer);
|
|
202
268
|
|
|
203
|
-
await getFirstSpace(peer).deactivate();
|
|
269
|
+
await getFirstSpace(peer).deactivate(new Context());
|
|
204
270
|
|
|
205
271
|
await reloadDataSpaces(peer);
|
|
206
272
|
|
|
@@ -209,7 +275,7 @@ describe('DataSpaceManager', () => {
|
|
|
209
275
|
});
|
|
210
276
|
|
|
211
277
|
const connectReplicators = (peers: TestPeer[]) => {
|
|
212
|
-
return Promise.all(peers.map((peer) => peer.echoHost.addReplicator(peer.meshEchoReplicator)));
|
|
278
|
+
return Promise.all(peers.map((peer) => peer.echoHost.addReplicator(Context.default(), peer.meshEchoReplicator)));
|
|
213
279
|
};
|
|
214
280
|
|
|
215
281
|
const reloadDataSpaces = async (peer: TestPeer) => {
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type Doc } from '@automerge/automerge';
|
|
6
|
-
import { type AutomergeUrl, type
|
|
6
|
+
import { type AutomergeUrl, type DocumentId, interpretAsDocumentId } from '@automerge/automerge-repo';
|
|
7
7
|
|
|
8
8
|
import { Event, synchronized, trackLeaks } from '@dxos/async';
|
|
9
|
-
import {
|
|
9
|
+
import { LegacySpaceProperties, SpaceProperties } from '@dxos/client-protocol';
|
|
10
10
|
import { Context, LifecycleState, Resource, cancelWithContext } from '@dxos/context';
|
|
11
11
|
import {
|
|
12
12
|
type CredentialSigner,
|
|
@@ -15,13 +15,13 @@ import {
|
|
|
15
15
|
createAdmissionCredentials,
|
|
16
16
|
getCredentialAssertion,
|
|
17
17
|
} from '@dxos/credentials';
|
|
18
|
+
import { Type } from '@dxos/echo';
|
|
18
19
|
import {
|
|
19
20
|
AuthStatus,
|
|
20
21
|
CredentialServerExtension,
|
|
21
22
|
DatabaseRoot,
|
|
22
23
|
type EchoEdgeReplicator,
|
|
23
24
|
type EchoHost,
|
|
24
|
-
FIND_PARAMS,
|
|
25
25
|
type MeshEchoReplicator,
|
|
26
26
|
type MetadataStore,
|
|
27
27
|
type Space,
|
|
@@ -30,14 +30,7 @@ import {
|
|
|
30
30
|
type SpaceProtocolSession,
|
|
31
31
|
findInlineObjectOfType,
|
|
32
32
|
} from '@dxos/echo-pipeline';
|
|
33
|
-
import {
|
|
34
|
-
type DatabaseDirectory,
|
|
35
|
-
type ObjectStructure,
|
|
36
|
-
SpaceDocVersion,
|
|
37
|
-
createIdFromSpaceKey,
|
|
38
|
-
encodeReference,
|
|
39
|
-
} from '@dxos/echo-protocol';
|
|
40
|
-
import { ObjectId, getTypeReference } from '@dxos/echo-schema';
|
|
33
|
+
import { type DatabaseDirectory, createIdFromSpaceKey } from '@dxos/echo-protocol';
|
|
41
34
|
import type { EdgeConnection, EdgeHttpClient } from '@dxos/edge-client';
|
|
42
35
|
import { type FeedStore, writeMessages } from '@dxos/feed-store';
|
|
43
36
|
import { assertArgument, assertState, failedInvariant, invariant } from '@dxos/invariant';
|
|
@@ -49,27 +42,28 @@ import { Invitation, SpaceState } from '@dxos/protocols/proto/dxos/client/servic
|
|
|
49
42
|
import { type Runtime } from '@dxos/protocols/proto/dxos/config';
|
|
50
43
|
import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
51
44
|
import { EdgeReplicationSetting, type SpaceMetadata } from '@dxos/protocols/proto/dxos/echo/metadata';
|
|
52
|
-
import {
|
|
45
|
+
import {
|
|
46
|
+
type Credential,
|
|
47
|
+
MembershipPolicy,
|
|
48
|
+
type ProfileDocument,
|
|
49
|
+
SpaceMember,
|
|
50
|
+
} from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
53
51
|
import { type DelegateSpaceInvitation } from '@dxos/protocols/proto/dxos/halo/invitations';
|
|
54
52
|
import { type PeerState } from '@dxos/protocols/proto/dxos/mesh/presence';
|
|
55
53
|
import { type Teleport } from '@dxos/teleport';
|
|
56
54
|
import { Gossip, Presence } from '@dxos/teleport-extension-gossip';
|
|
57
55
|
import { type Timeframe } from '@dxos/timeframe';
|
|
58
56
|
import { trace } from '@dxos/tracing';
|
|
59
|
-
import { ComplexMap, deferFunction, forEachAsync
|
|
57
|
+
import { ComplexMap, deferFunction, forEachAsync } from '@dxos/util';
|
|
60
58
|
|
|
61
59
|
import { createAuthProvider } from '../identity';
|
|
62
60
|
import { type InvitationsManager } from '../invitations';
|
|
63
|
-
|
|
64
61
|
import { DataSpace } from './data-space';
|
|
65
62
|
import { spaceGenesis } from './genesis';
|
|
66
63
|
|
|
67
64
|
const PRESENCE_ANNOUNCE_INTERVAL = 10_000;
|
|
68
65
|
const PRESENCE_OFFLINE_TIMEOUT = 20_000;
|
|
69
66
|
|
|
70
|
-
// Space properties key for default metadata.
|
|
71
|
-
const DEFAULT_SPACE_KEY = '__DEFAULT__';
|
|
72
|
-
|
|
73
67
|
export interface SigningContext {
|
|
74
68
|
identityKey: PublicKey;
|
|
75
69
|
deviceKey: PublicKey;
|
|
@@ -94,6 +88,9 @@ export type AcceptSpaceOptions = {
|
|
|
94
88
|
* We will try to catch up to this timeframe before initializing the database.
|
|
95
89
|
*/
|
|
96
90
|
dataTimeframe?: Timeframe;
|
|
91
|
+
|
|
92
|
+
/** Tags assigned to the space member. */
|
|
93
|
+
tags?: string[];
|
|
97
94
|
};
|
|
98
95
|
|
|
99
96
|
export type AdmitMemberOptions = {
|
|
@@ -102,9 +99,10 @@ export type AdmitMemberOptions = {
|
|
|
102
99
|
role: SpaceMember.Role;
|
|
103
100
|
profile?: ProfileDocument;
|
|
104
101
|
delegationCredentialId?: PublicKey;
|
|
102
|
+
tags?: string[];
|
|
105
103
|
};
|
|
106
104
|
|
|
107
|
-
export type
|
|
105
|
+
export type DataSpaceManagerProps = {
|
|
108
106
|
spaceManager: SpaceManager;
|
|
109
107
|
metadataStore: MetadataStore;
|
|
110
108
|
keyring: Keyring;
|
|
@@ -116,23 +114,31 @@ export type DataSpaceManagerParams = {
|
|
|
116
114
|
edgeHttpClient?: EdgeHttpClient;
|
|
117
115
|
meshReplicator?: MeshEchoReplicator;
|
|
118
116
|
echoEdgeReplicator?: EchoEdgeReplicator;
|
|
119
|
-
|
|
117
|
+
runtimeProps?: DataSpaceManagerRuntimeProps;
|
|
120
118
|
edgeFeatures?: Runtime.Client.EdgeFeatures;
|
|
121
119
|
};
|
|
122
120
|
|
|
123
|
-
export type
|
|
121
|
+
export type DataSpaceManagerRuntimeProps = {
|
|
124
122
|
spaceMemberPresenceAnnounceInterval?: number;
|
|
125
123
|
spaceMemberPresenceOfflineTimeout?: number;
|
|
126
124
|
activeEdgeNotarizationPollingInterval?: number;
|
|
127
125
|
disableP2pReplication?: boolean;
|
|
126
|
+
/**
|
|
127
|
+
* If true, spaces that were previously SPACE_ACTIVE will be automatically activated on startup.
|
|
128
|
+
* This is used in dedicated worker mode to restore space state after leader changeover.
|
|
129
|
+
*/
|
|
130
|
+
autoActivateSpaces?: boolean;
|
|
128
131
|
};
|
|
129
132
|
|
|
130
133
|
export type CreateSpaceOptions = {
|
|
131
134
|
rootUrl?: AutomergeUrl;
|
|
132
135
|
documents?: Record<DocumentId, Uint8Array>;
|
|
136
|
+
tags?: string[];
|
|
137
|
+
membershipPolicy?: MembershipPolicy;
|
|
133
138
|
};
|
|
134
139
|
|
|
135
140
|
@trackLeaks('open', 'close')
|
|
141
|
+
@trace.resource({ lifecycle: true })
|
|
136
142
|
export class DataSpaceManager extends Resource {
|
|
137
143
|
public readonly updated = new Event();
|
|
138
144
|
|
|
@@ -152,9 +158,9 @@ export class DataSpaceManager extends Resource {
|
|
|
152
158
|
private readonly _edgeFeatures?: Runtime.Client.EdgeFeatures = undefined;
|
|
153
159
|
private readonly _meshReplicator?: MeshEchoReplicator = undefined;
|
|
154
160
|
private readonly _echoEdgeReplicator?: EchoEdgeReplicator = undefined;
|
|
155
|
-
private readonly
|
|
161
|
+
private readonly _runtimeProps?: DataSpaceManagerRuntimeProps = undefined;
|
|
156
162
|
|
|
157
|
-
constructor(params:
|
|
163
|
+
constructor(params: DataSpaceManagerProps) {
|
|
158
164
|
super();
|
|
159
165
|
|
|
160
166
|
this._spaceManager = params.spaceManager;
|
|
@@ -169,7 +175,7 @@ export class DataSpaceManager extends Resource {
|
|
|
169
175
|
this._edgeFeatures = params.edgeFeatures;
|
|
170
176
|
this._echoEdgeReplicator = params.echoEdgeReplicator;
|
|
171
177
|
this._edgeHttpClient = params.edgeHttpClient;
|
|
172
|
-
this.
|
|
178
|
+
this._runtimeProps = params.runtimeProps;
|
|
173
179
|
|
|
174
180
|
trace.diagnostic({
|
|
175
181
|
id: 'spaces',
|
|
@@ -179,12 +185,15 @@ export class DataSpaceManager extends Resource {
|
|
|
179
185
|
Array.from(this._spaces.values()).map(async (space) => {
|
|
180
186
|
const rootUrl = space.automergeSpaceState.rootUrl;
|
|
181
187
|
const rootHandle = rootUrl
|
|
182
|
-
? await this._echoHost.
|
|
188
|
+
? await this._echoHost.loadDoc<Doc<DatabaseDirectory>>(this._ctx, rootUrl as AutomergeUrl)
|
|
183
189
|
: undefined;
|
|
184
190
|
await rootHandle?.whenReady();
|
|
185
191
|
const rootDoc = rootHandle?.doc();
|
|
186
192
|
|
|
187
|
-
const properties =
|
|
193
|
+
const properties =
|
|
194
|
+
rootDoc &&
|
|
195
|
+
(findInlineObjectOfType(rootDoc, Type.getTypename(SpaceProperties)) ??
|
|
196
|
+
findInlineObjectOfType(rootDoc, Type.getTypename(LegacySpaceProperties)));
|
|
188
197
|
|
|
189
198
|
return {
|
|
190
199
|
key: space.key.toHex(),
|
|
@@ -212,30 +221,44 @@ export class DataSpaceManager extends Resource {
|
|
|
212
221
|
}
|
|
213
222
|
|
|
214
223
|
@synchronized
|
|
215
|
-
|
|
224
|
+
@trace.span({ showInBrowserTimeline: true, op: 'lifecycle' })
|
|
225
|
+
protected override async _open(ctx: Context): Promise<void> {
|
|
216
226
|
log('open');
|
|
217
227
|
log.trace('dxos.echo.data-space-manager.open', Trace.begin({ id: this._instanceId }));
|
|
218
228
|
log('metadata loaded', { spaces: this._metadataStore.spaces.length });
|
|
219
229
|
|
|
230
|
+
const spacesToActivate: DataSpace[] = [];
|
|
220
231
|
await forEachAsync(this._metadataStore.spaces, async (spaceMetadata) => {
|
|
221
232
|
try {
|
|
222
233
|
log('load space', { spaceMetadata });
|
|
223
|
-
await this._constructSpace(spaceMetadata);
|
|
234
|
+
const space = await this._constructSpace(ctx, spaceMetadata);
|
|
235
|
+
// Track spaces that were previously active for auto-activation (used in dedicated worker mode).
|
|
236
|
+
if (this._runtimeProps?.autoActivateSpaces && spaceMetadata.state === SpaceState.SPACE_ACTIVE) {
|
|
237
|
+
spacesToActivate.push(space);
|
|
238
|
+
}
|
|
224
239
|
} catch (err) {
|
|
225
240
|
log.error('Error loading space', { spaceMetadata, err });
|
|
226
241
|
}
|
|
227
242
|
});
|
|
228
243
|
|
|
244
|
+
// Auto-activate spaces that were previously active (used in dedicated worker mode after leader changeover).
|
|
245
|
+
for (const space of spacesToActivate) {
|
|
246
|
+
log('auto-activating space', { spaceKey: space.key });
|
|
247
|
+
space.activate(ctx).catch((err) => {
|
|
248
|
+
log.error('Error auto-activating space', { spaceKey: space.key, err });
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
229
252
|
this.updated.emit();
|
|
230
253
|
|
|
231
254
|
log.trace('dxos.echo.data-space-manager.open', Trace.end({ id: this._instanceId }));
|
|
232
255
|
}
|
|
233
256
|
|
|
234
257
|
@synchronized
|
|
235
|
-
protected override async _close(): Promise<void> {
|
|
258
|
+
protected override async _close(ctx: Context): Promise<void> {
|
|
236
259
|
log('close');
|
|
237
260
|
for (const space of this._spaces.values()) {
|
|
238
|
-
await space.close();
|
|
261
|
+
await space.close(ctx);
|
|
239
262
|
}
|
|
240
263
|
this._spaces.clear();
|
|
241
264
|
}
|
|
@@ -244,10 +267,17 @@ export class DataSpaceManager extends Resource {
|
|
|
244
267
|
* Creates a new space writing the genesis credentials to the control feed.
|
|
245
268
|
*/
|
|
246
269
|
@synchronized
|
|
247
|
-
|
|
248
|
-
|
|
270
|
+
@trace.span({ showInBrowserTimeline: true, op: 'lifecycle' })
|
|
271
|
+
async createSpace(ctx: Context, options: CreateSpaceOptions = {}): Promise<DataSpace> {
|
|
272
|
+
assertArgument(
|
|
273
|
+
!!options.rootUrl === !!options.documents,
|
|
274
|
+
'options',
|
|
275
|
+
'root url must be required when providing documents',
|
|
276
|
+
);
|
|
249
277
|
|
|
250
278
|
assertState(this._lifecycleState === LifecycleState.OPEN, 'Not open.');
|
|
279
|
+
|
|
280
|
+
const tags = options.tags ? Array.from(options.tags) : [];
|
|
251
281
|
const spaceKey = await this._keyring.createKey();
|
|
252
282
|
const controlFeedKey = await this._keyring.createKey();
|
|
253
283
|
const dataFeedKey = await this._keyring.createKey();
|
|
@@ -260,6 +290,7 @@ export class DataSpaceManager extends Resource {
|
|
|
260
290
|
controlFeedKey,
|
|
261
291
|
dataFeedKey,
|
|
262
292
|
state: SpaceState.SPACE_ACTIVE,
|
|
293
|
+
tags,
|
|
263
294
|
};
|
|
264
295
|
|
|
265
296
|
log('creating space...', { spaceId, spaceKey });
|
|
@@ -275,7 +306,18 @@ export class DataSpaceManager extends Resource {
|
|
|
275
306
|
await Promise.all(
|
|
276
307
|
Object.entries(options.documents).map(async ([documentId, data]) => {
|
|
277
308
|
log('creating document...', { documentId });
|
|
278
|
-
|
|
309
|
+
// TODO(dmaretskyi): Broken types -- the bytes get interpreted as CRDT data.
|
|
310
|
+
const newDoc = await this._echoHost.createDoc(data as any as DatabaseDirectory, {
|
|
311
|
+
preserveHistory: true,
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// The archived documents might have the spaceKey from the space they were expored from, we need to update it to the new spaceKey.
|
|
315
|
+
if (newDoc.doc().access !== undefined && newDoc.doc().access!.spaceKey !== spaceKey.toHex()) {
|
|
316
|
+
newDoc.change((doc) => {
|
|
317
|
+
doc.access!.spaceKey = spaceKey.toHex();
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
|
|
279
321
|
documentIdMapping[documentId as DocumentId] = newDoc.documentId;
|
|
280
322
|
}),
|
|
281
323
|
);
|
|
@@ -286,29 +328,37 @@ export class DataSpaceManager extends Resource {
|
|
|
286
328
|
let root: DatabaseRoot;
|
|
287
329
|
if (options.rootUrl) {
|
|
288
330
|
const newRootDocId = documentIdMapping[interpretAsDocumentId(options.rootUrl)] ?? failedInvariant();
|
|
289
|
-
const rootDocHandle = await this._echoHost.loadDoc<DatabaseDirectory>(
|
|
331
|
+
const rootDocHandle = await this._echoHost.loadDoc<DatabaseDirectory>(ctx, newRootDocId);
|
|
290
332
|
DatabaseRoot.mapLinks(rootDocHandle, documentIdMapping);
|
|
291
333
|
|
|
292
|
-
root = await this._echoHost.openSpaceRoot(spaceId, `automerge:${newRootDocId}` as AutomergeUrl);
|
|
334
|
+
root = await this._echoHost.openSpaceRoot(ctx, spaceId, `automerge:${newRootDocId}` as AutomergeUrl);
|
|
293
335
|
} else {
|
|
294
|
-
root = await this._echoHost.createSpaceRoot(spaceKey);
|
|
336
|
+
root = await this._echoHost.createSpaceRoot(ctx, spaceKey);
|
|
295
337
|
}
|
|
338
|
+
await this._echoHost.flush(ctx);
|
|
296
339
|
|
|
297
340
|
log('constructing space...', { spaceKey });
|
|
298
341
|
|
|
299
|
-
const space = await this._constructSpace(metadata);
|
|
300
|
-
await space.open();
|
|
342
|
+
const space = await this._constructSpace(ctx, metadata);
|
|
343
|
+
await space.open(ctx);
|
|
301
344
|
|
|
302
345
|
log('adding space...', { spaceKey });
|
|
303
346
|
|
|
304
|
-
const credentials = await spaceGenesis(
|
|
347
|
+
const credentials = await spaceGenesis(
|
|
348
|
+
this._keyring,
|
|
349
|
+
this._signingContext,
|
|
350
|
+
space.inner,
|
|
351
|
+
root.url,
|
|
352
|
+
tags,
|
|
353
|
+
options.membershipPolicy,
|
|
354
|
+
);
|
|
305
355
|
await this._metadataStore.addSpace(metadata);
|
|
306
356
|
|
|
307
357
|
const memberCredential = credentials[1];
|
|
308
358
|
invariant(getCredentialAssertion(memberCredential)['@type'] === 'dxos.halo.credentials.SpaceMember');
|
|
309
359
|
await this._signingContext.recordCredential(memberCredential);
|
|
310
360
|
|
|
311
|
-
await space.initializeDataPipeline();
|
|
361
|
+
await space.initializeDataPipeline(ctx);
|
|
312
362
|
|
|
313
363
|
log('space ready.', { spaceId, spaceKey });
|
|
314
364
|
|
|
@@ -316,81 +366,36 @@ export class DataSpaceManager extends Resource {
|
|
|
316
366
|
return space;
|
|
317
367
|
}
|
|
318
368
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
case SpaceDocVersion.CURRENT: {
|
|
325
|
-
if (!space.databaseRoot.handle.isReady()) {
|
|
326
|
-
log.warn('waiting for space root to be ready', { spaceId: space.id });
|
|
327
|
-
await space.databaseRoot.handle.whenReady();
|
|
328
|
-
}
|
|
329
|
-
const [_, properties] = findInlineObjectOfType(space.databaseRoot.doc()!, TYPE_PROPERTIES) ?? [];
|
|
330
|
-
return properties?.data?.[DEFAULT_SPACE_KEY] === this._signingContext.identityKey.toHex();
|
|
331
|
-
}
|
|
332
|
-
case SpaceDocVersion.LEGACY: {
|
|
333
|
-
throw new Error('Legacy space version is not supported');
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
default:
|
|
337
|
-
log.warn('unknown space version', { version: space.databaseRoot.getVersion(), spaceId: space.id });
|
|
338
|
-
return false;
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
async createDefaultSpace(): Promise<DataSpace> {
|
|
343
|
-
const space = await this.createSpace();
|
|
344
|
-
const document = await this._getSpaceRootDocument(space);
|
|
345
|
-
|
|
346
|
-
// TODO(dmaretskyi): Better API for low-level data access.
|
|
347
|
-
const properties: ObjectStructure = {
|
|
348
|
-
system: {
|
|
349
|
-
type: encodeReference(getTypeReference(PropertiesType)!),
|
|
350
|
-
},
|
|
351
|
-
data: {
|
|
352
|
-
[DEFAULT_SPACE_KEY]: this._signingContext.identityKey.toHex(),
|
|
353
|
-
},
|
|
354
|
-
meta: {
|
|
355
|
-
keys: [],
|
|
356
|
-
},
|
|
357
|
-
};
|
|
358
|
-
|
|
359
|
-
const propertiesId = ObjectId.random();
|
|
360
|
-
document.change((doc: DatabaseDirectory) => {
|
|
361
|
-
setDeep(doc, ['objects', propertiesId], properties);
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
await this._echoHost.flush();
|
|
365
|
-
return space;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
private async _getSpaceRootDocument(space: DataSpace): Promise<DocHandle<DatabaseDirectory>> {
|
|
369
|
-
const automergeIndex = space.automergeSpaceState.rootUrl;
|
|
370
|
-
invariant(automergeIndex);
|
|
371
|
-
const document = await this._echoHost.automergeRepo.find<DatabaseDirectory>(automergeIndex as any, FIND_PARAMS);
|
|
372
|
-
await document.whenReady();
|
|
373
|
-
return document;
|
|
374
|
-
}
|
|
375
|
-
|
|
369
|
+
/**
|
|
370
|
+
* Accepts an existing space by joining its swarm and initializing the data pipeline.
|
|
371
|
+
* @param ctx - Caller context for cancellation and tracing.
|
|
372
|
+
* @param opts - Space keys and optional timeframes for catch-up.
|
|
373
|
+
*/
|
|
376
374
|
// TODO(burdon): Rename join space.
|
|
377
375
|
@synchronized
|
|
378
|
-
|
|
376
|
+
@trace.span({ showInBrowserTimeline: true, op: 'lifecycle' })
|
|
377
|
+
async acceptSpace(ctx: Context, opts: AcceptSpaceOptions): Promise<DataSpace> {
|
|
379
378
|
log('accept space', { opts });
|
|
380
379
|
invariant(this._lifecycleState === LifecycleState.OPEN, 'Not open.');
|
|
381
380
|
invariant(!this._spaces.has(opts.spaceKey), 'Space already exists.');
|
|
382
381
|
|
|
382
|
+
const tags = opts.tags ? Array.from(opts.tags) : [];
|
|
383
383
|
const metadata: SpaceMetadata = {
|
|
384
384
|
key: opts.spaceKey,
|
|
385
385
|
genesisFeedKey: opts.genesisFeedKey,
|
|
386
386
|
controlTimeframe: opts.controlTimeframe,
|
|
387
387
|
dataTimeframe: opts.dataTimeframe,
|
|
388
|
+
tags,
|
|
388
389
|
};
|
|
389
390
|
|
|
390
|
-
const space = await this._constructSpace(metadata);
|
|
391
|
-
await space.open();
|
|
391
|
+
const space = await this._constructSpace(ctx, metadata);
|
|
392
|
+
await space.open(ctx);
|
|
392
393
|
await this._metadataStore.addSpace(metadata);
|
|
393
|
-
|
|
394
|
+
// Use DSM lifecycle ctx: the invitation accept flow disposes `ctx` as soon as
|
|
395
|
+
// `acceptSpace` returns (guardedState.complete -> ctx.dispose). Detached data-pipeline
|
|
396
|
+
// initialization must outlive the invitation flow, and its span must be parented to a
|
|
397
|
+
// long-lived context.
|
|
398
|
+
space.initializeDataPipelineAsync(this._ctx);
|
|
394
399
|
|
|
395
400
|
this.updated.emit();
|
|
396
401
|
return space;
|
|
@@ -414,6 +419,7 @@ export class DataSpaceManager extends Resource {
|
|
|
414
419
|
space.spaceState.membershipChainHeads,
|
|
415
420
|
options.profile,
|
|
416
421
|
options.delegationCredentialId,
|
|
422
|
+
space.spaceState.tags,
|
|
417
423
|
);
|
|
418
424
|
|
|
419
425
|
// TODO(dmaretskyi): Refactor.
|
|
@@ -440,8 +446,8 @@ export class DataSpaceManager extends Resource {
|
|
|
440
446
|
);
|
|
441
447
|
}
|
|
442
448
|
|
|
443
|
-
public async requestSpaceAdmissionCredential(spaceKey: PublicKey): Promise<Credential> {
|
|
444
|
-
return this._spaceManager.requestSpaceAdmissionCredential({
|
|
449
|
+
public async requestSpaceAdmissionCredential(ctx: Context, spaceKey: PublicKey): Promise<Credential> {
|
|
450
|
+
return this._spaceManager.requestSpaceAdmissionCredential(ctx, {
|
|
445
451
|
spaceKey,
|
|
446
452
|
identityKey: this._signingContext.identityKey,
|
|
447
453
|
timeout: 15_000,
|
|
@@ -454,7 +460,11 @@ export class DataSpaceManager extends Resource {
|
|
|
454
460
|
});
|
|
455
461
|
}
|
|
456
462
|
|
|
457
|
-
async setSpaceEdgeReplicationSetting(
|
|
463
|
+
async setSpaceEdgeReplicationSetting(
|
|
464
|
+
ctx: Context,
|
|
465
|
+
spaceKey: PublicKey,
|
|
466
|
+
setting: EdgeReplicationSetting,
|
|
467
|
+
): Promise<void> {
|
|
458
468
|
const space = this._spaces.get(spaceKey);
|
|
459
469
|
invariant(space, 'Space not found.');
|
|
460
470
|
|
|
@@ -466,7 +476,7 @@ export class DataSpaceManager extends Resource {
|
|
|
466
476
|
await this._echoEdgeReplicator?.disconnectFromSpace(space.id);
|
|
467
477
|
break;
|
|
468
478
|
case EdgeReplicationSetting.ENABLED:
|
|
469
|
-
await this._echoEdgeReplicator?.connectToSpace(space.id);
|
|
479
|
+
await this._echoEdgeReplicator?.connectToSpace(ctx, space.id);
|
|
470
480
|
break;
|
|
471
481
|
}
|
|
472
482
|
}
|
|
@@ -474,14 +484,14 @@ export class DataSpaceManager extends Resource {
|
|
|
474
484
|
space.stateUpdate.emit();
|
|
475
485
|
}
|
|
476
486
|
|
|
477
|
-
private async _constructSpace(metadata: SpaceMetadata): Promise<DataSpace> {
|
|
487
|
+
private async _constructSpace(ctx: Context, metadata: SpaceMetadata): Promise<DataSpace> {
|
|
478
488
|
log('construct space', { metadata });
|
|
479
489
|
const gossip = new Gossip({
|
|
480
490
|
localPeerId: this._signingContext.deviceKey,
|
|
481
491
|
});
|
|
482
492
|
const presence = new Presence({
|
|
483
|
-
announceInterval: this.
|
|
484
|
-
offlineTimeout: this.
|
|
493
|
+
announceInterval: this._runtimeProps?.spaceMemberPresenceAnnounceInterval ?? PRESENCE_ANNOUNCE_INTERVAL,
|
|
494
|
+
offlineTimeout: this._runtimeProps?.spaceMemberPresenceOfflineTimeout ?? PRESENCE_OFFLINE_TIMEOUT,
|
|
485
495
|
identityKey: this._signingContext.identityKey,
|
|
486
496
|
gossip,
|
|
487
497
|
});
|
|
@@ -564,15 +574,17 @@ export class DataSpaceManager extends Resource {
|
|
|
564
574
|
},
|
|
565
575
|
},
|
|
566
576
|
cache: metadata.cache,
|
|
577
|
+
tags: metadata.tags,
|
|
567
578
|
edgeConnection: this._edgeConnection,
|
|
568
579
|
edgeHttpClient: this._edgeHttpClient,
|
|
569
580
|
edgeFeatures: this._edgeFeatures,
|
|
570
|
-
activeEdgeNotarizationPollingInterval: this.
|
|
581
|
+
activeEdgeNotarizationPollingInterval: this._runtimeProps?.activeEdgeNotarizationPollingInterval,
|
|
571
582
|
});
|
|
572
583
|
dataSpace.postOpen.append(async () => {
|
|
573
584
|
const setting = dataSpace.getEdgeReplicationSetting();
|
|
574
585
|
if (!setting || setting === EdgeReplicationSetting.ENABLED) {
|
|
575
|
-
|
|
586
|
+
// Use lifecycle ctx: the caller ctx from _constructSpace may be disposed by the time postOpen fires.
|
|
587
|
+
await this._echoEdgeReplicator?.connectToSpace(this._ctx, dataSpace.id);
|
|
576
588
|
} else if (this._echoEdgeReplicator) {
|
|
577
589
|
log('not connecting EchoEdgeReplicator because of EdgeReplicationSetting', { spaceId: dataSpace.id });
|
|
578
590
|
}
|
|
@@ -669,7 +681,7 @@ export class DataSpaceManager extends Resource {
|
|
|
669
681
|
invitations: Array<[PublicKey, DelegateSpaceInvitation]>,
|
|
670
682
|
): Promise<void> {
|
|
671
683
|
const tasks = invitations.map(([credentialId, invitation]) => {
|
|
672
|
-
return this._invitationsManager.createInvitation({
|
|
684
|
+
return this._invitationsManager.createInvitation(this._ctx, {
|
|
673
685
|
type: Invitation.Type.DELEGATED,
|
|
674
686
|
kind: Invitation.Kind.SPACE,
|
|
675
687
|
spaceKey: space.key,
|