@dxos/client-services 0.8.0 → 0.8.1-main.81238a8
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/{node-esm/chunk-ORQYMDJN.mjs → browser/chunk-35TJRMUI.mjs} +1306 -853
- package/dist/lib/browser/chunk-35TJRMUI.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +1 -1
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +1 -1
- package/dist/lib/node/{chunk-FELZPQQE.cjs → chunk-V7LWQ25J.cjs} +1016 -712
- package/dist/lib/node/chunk-V7LWQ25J.cjs.map +7 -0
- package/dist/lib/node/index.cjs +47 -47
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +8 -8
- package/dist/lib/{browser/chunk-25OL3JVO.mjs → node-esm/chunk-CT42KAJ2.mjs} +721 -554
- package/dist/lib/node-esm/chunk-CT42KAJ2.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +1 -1
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +1 -1
- package/dist/types/src/packlets/network/network-service.d.ts +2 -1
- package/dist/types/src/packlets/network/network-service.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/index.d.ts +3 -0
- package/dist/types/src/packlets/space-export/index.d.ts.map +1 -0
- package/dist/types/src/packlets/space-export/space-archive-reader.d.ts +9 -0
- package/dist/types/src/packlets/space-export/space-archive-reader.d.ts.map +1 -0
- package/dist/types/src/packlets/space-export/space-archive-writer.d.ts +23 -0
- package/dist/types/src/packlets/space-export/space-archive-writer.d.ts.map +1 -0
- package/dist/types/src/packlets/space-export/tar.test.d.ts +2 -0
- package/dist/types/src/packlets/space-export/tar.test.d.ts.map +1 -0
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts +8 -2
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts +1 -0
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts +3 -1
- package/dist/types/src/packlets/spaces/spaces-service.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/package.json +39 -38
- package/src/packlets/network/network-service.ts +10 -1
- package/src/packlets/space-export/index.ts +6 -0
- package/src/packlets/space-export/space-archive-reader.ts +33 -0
- package/src/packlets/space-export/space-archive-writer.ts +83 -0
- package/src/packlets/space-export/tar.test.ts +25 -0
- package/src/packlets/spaces/data-space-manager.ts +70 -9
- package/src/packlets/spaces/data-space.ts +14 -1
- package/src/packlets/spaces/spaces-service.ts +39 -1
- package/src/version.ts +1 -5
- package/dist/lib/browser/chunk-25OL3JVO.mjs.map +0 -7
- package/dist/lib/node/chunk-FELZPQQE.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-ORQYMDJN.mjs.map +0 -7
|
@@ -4,9 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
import { Event, synchronized, trackLeaks } from '@dxos/async';
|
|
6
6
|
import { type Doc } from '@dxos/automerge/automerge';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
interpretAsDocumentId,
|
|
9
|
+
type AutomergeUrl,
|
|
10
|
+
type DocHandle,
|
|
11
|
+
type DocumentId,
|
|
12
|
+
} from '@dxos/automerge/automerge-repo';
|
|
8
13
|
import { PropertiesType, TYPE_PROPERTIES } from '@dxos/client-protocol';
|
|
9
|
-
import { LifecycleState, Resource, cancelWithContext } from '@dxos/context';
|
|
14
|
+
import { Context, LifecycleState, Resource, cancelWithContext } from '@dxos/context';
|
|
10
15
|
import {
|
|
11
16
|
createAdmissionCredentials,
|
|
12
17
|
getCredentialAssertion,
|
|
@@ -15,6 +20,7 @@ import {
|
|
|
15
20
|
type MemberInfo,
|
|
16
21
|
} from '@dxos/credentials';
|
|
17
22
|
import {
|
|
23
|
+
DatabaseRoot,
|
|
18
24
|
findInlineObjectOfType,
|
|
19
25
|
type EchoEdgeReplicator,
|
|
20
26
|
type EchoHost,
|
|
@@ -27,13 +33,19 @@ import {
|
|
|
27
33
|
type SpaceProtocol,
|
|
28
34
|
type SpaceProtocolSession,
|
|
29
35
|
} from '@dxos/echo-pipeline';
|
|
30
|
-
import {
|
|
36
|
+
import {
|
|
37
|
+
SpaceDocVersion,
|
|
38
|
+
createIdFromSpaceKey,
|
|
39
|
+
encodeReference,
|
|
40
|
+
type ObjectStructure,
|
|
41
|
+
type SpaceDoc,
|
|
42
|
+
} from '@dxos/echo-protocol';
|
|
31
43
|
import { createObjectId, getTypeReference } from '@dxos/echo-schema';
|
|
32
44
|
import type { EdgeConnection, EdgeHttpClient } from '@dxos/edge-client';
|
|
33
45
|
import { writeMessages, type FeedStore } from '@dxos/feed-store';
|
|
34
|
-
import { invariant } from '@dxos/invariant';
|
|
46
|
+
import { assertArgument, assertState, failedInvariant, invariant } from '@dxos/invariant';
|
|
35
47
|
import { type Keyring } from '@dxos/keyring';
|
|
36
|
-
import { PublicKey } from '@dxos/keys';
|
|
48
|
+
import { PublicKey, type SpaceId } from '@dxos/keys';
|
|
37
49
|
import { log } from '@dxos/log';
|
|
38
50
|
import { AlreadyJoinedError, trace as Trace } from '@dxos/protocols';
|
|
39
51
|
import { Invitation, SpaceState } from '@dxos/protocols/proto/dxos/client/services';
|
|
@@ -117,6 +129,11 @@ export type DataSpaceManagerRuntimeParams = {
|
|
|
117
129
|
disableP2pReplication?: boolean;
|
|
118
130
|
};
|
|
119
131
|
|
|
132
|
+
export type CreateSpaceOptions = {
|
|
133
|
+
rootUrl?: AutomergeUrl;
|
|
134
|
+
documents?: Record<DocumentId, Uint8Array>;
|
|
135
|
+
};
|
|
136
|
+
|
|
120
137
|
@trackLeaks('open', 'close')
|
|
121
138
|
export class DataSpaceManager extends Resource {
|
|
122
139
|
public readonly updated = new Event();
|
|
@@ -187,6 +204,10 @@ export class DataSpaceManager extends Resource {
|
|
|
187
204
|
return this._spaces;
|
|
188
205
|
}
|
|
189
206
|
|
|
207
|
+
getSpaceById(spaceId: SpaceId): DataSpace | undefined {
|
|
208
|
+
return [...this._spaces.values()].find((space) => space.id === spaceId);
|
|
209
|
+
}
|
|
210
|
+
|
|
190
211
|
@synchronized
|
|
191
212
|
protected override async _open() {
|
|
192
213
|
log('open');
|
|
@@ -220,11 +241,16 @@ export class DataSpaceManager extends Resource {
|
|
|
220
241
|
* Creates a new space writing the genesis credentials to the control feed.
|
|
221
242
|
*/
|
|
222
243
|
@synchronized
|
|
223
|
-
async createSpace() {
|
|
224
|
-
|
|
244
|
+
async createSpace(options: CreateSpaceOptions = {}) {
|
|
245
|
+
assertArgument(!!options.rootUrl === !!options.documents, 'root url must be required when providing documents');
|
|
246
|
+
|
|
247
|
+
assertState(this._lifecycleState === LifecycleState.OPEN, 'Not open.');
|
|
225
248
|
const spaceKey = await this._keyring.createKey();
|
|
226
249
|
const controlFeedKey = await this._keyring.createKey();
|
|
227
250
|
const dataFeedKey = await this._keyring.createKey();
|
|
251
|
+
|
|
252
|
+
const spaceId = await createIdFromSpaceKey(spaceKey);
|
|
253
|
+
|
|
228
254
|
const metadata: SpaceMetadata = {
|
|
229
255
|
key: spaceKey,
|
|
230
256
|
genesisFeedKey: controlFeedKey,
|
|
@@ -233,12 +259,45 @@ export class DataSpaceManager extends Resource {
|
|
|
233
259
|
state: SpaceState.SPACE_ACTIVE,
|
|
234
260
|
};
|
|
235
261
|
|
|
236
|
-
log('creating space...', { spaceKey });
|
|
262
|
+
log.info('creating space...', { spaceId, spaceKey });
|
|
263
|
+
|
|
264
|
+
// New document IDs for the space.
|
|
265
|
+
const documentIdMapping: Record<DocumentId, DocumentId> = {};
|
|
266
|
+
if (options.documents) {
|
|
267
|
+
invariant(
|
|
268
|
+
Object.keys(options.documents).every((documentId) => /^[a-zA-Z0-9]+$/.test(documentId)),
|
|
269
|
+
'Invalid document IDs',
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
await Promise.all(
|
|
273
|
+
Object.entries(options.documents).map(async ([documentId, data]) => {
|
|
274
|
+
log('creating document...', { documentId });
|
|
275
|
+
const newDoc = await this._echoHost.createDoc(data, { preserveHistory: true });
|
|
276
|
+
documentIdMapping[documentId as DocumentId] = newDoc.documentId;
|
|
277
|
+
}),
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
log('opening space...', { spaceKey });
|
|
282
|
+
|
|
283
|
+
let root: DatabaseRoot;
|
|
284
|
+
if (options.rootUrl) {
|
|
285
|
+
const newRootDocId = documentIdMapping[interpretAsDocumentId(options.rootUrl)] ?? failedInvariant();
|
|
286
|
+
const rootDocHandle = await this._echoHost.loadDoc<SpaceDoc>(Context.default(), newRootDocId);
|
|
287
|
+
DatabaseRoot.mapLinks(rootDocHandle, documentIdMapping);
|
|
288
|
+
|
|
289
|
+
root = await this._echoHost.openSpaceRoot(spaceId, `automerge:${newRootDocId}` as AutomergeUrl);
|
|
290
|
+
} else {
|
|
291
|
+
root = await this._echoHost.createSpaceRoot(spaceKey);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
log('constructing space...', { spaceKey });
|
|
237
295
|
|
|
238
|
-
const root = await this._echoHost.createSpaceRoot(spaceKey);
|
|
239
296
|
const space = await this._constructSpace(metadata);
|
|
240
297
|
await space.open();
|
|
241
298
|
|
|
299
|
+
log('adding space...', { spaceKey });
|
|
300
|
+
|
|
242
301
|
const credentials = await spaceGenesis(this._keyring, this._signingContext, space.inner, root.url);
|
|
243
302
|
await this._metadataStore.addSpace(metadata);
|
|
244
303
|
|
|
@@ -248,6 +307,8 @@ export class DataSpaceManager extends Resource {
|
|
|
248
307
|
|
|
249
308
|
await space.initializeDataPipeline();
|
|
250
309
|
|
|
310
|
+
log('space ready.', { spaceId, spaceKey });
|
|
311
|
+
|
|
251
312
|
this.updated.emit();
|
|
252
313
|
return space;
|
|
253
314
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { Event, Mutex, scheduleTask, sleep, synchronized, trackLeaks } from '@dxos/async';
|
|
6
|
+
import { save } from '@dxos/automerge/automerge';
|
|
6
7
|
import { AUTH_TIMEOUT } from '@dxos/client-protocol';
|
|
7
8
|
import { Context, ContextDisposedError, cancelWithContext } from '@dxos/context';
|
|
8
9
|
import type { SpecificCredential } from '@dxos/credentials';
|
|
@@ -17,7 +18,7 @@ import {
|
|
|
17
18
|
import { SpaceDocVersion, type SpaceDoc } from '@dxos/echo-protocol';
|
|
18
19
|
import type { EdgeConnection, EdgeHttpClient } from '@dxos/edge-client';
|
|
19
20
|
import { type FeedStore, type FeedWrapper } from '@dxos/feed-store';
|
|
20
|
-
import { failedInvariant } from '@dxos/invariant';
|
|
21
|
+
import { failedInvariant, invariant } from '@dxos/invariant';
|
|
21
22
|
import { type Keyring } from '@dxos/keyring';
|
|
22
23
|
import { PublicKey } from '@dxos/keys';
|
|
23
24
|
import { log } from '@dxos/log';
|
|
@@ -349,6 +350,18 @@ export class DataSpace {
|
|
|
349
350
|
log('space is ready');
|
|
350
351
|
}
|
|
351
352
|
|
|
353
|
+
async *getAllDocuments(): AsyncIterable<[string, Uint8Array]> {
|
|
354
|
+
invariant(this._databaseRoot, 'Space is not ready');
|
|
355
|
+
const doc = this._databaseRoot.docSync() ?? failedInvariant();
|
|
356
|
+
const root = save(doc);
|
|
357
|
+
yield [this._databaseRoot.documentId, root];
|
|
358
|
+
|
|
359
|
+
for (const documentUrl of this._databaseRoot.getAllLinkedDocuments()) {
|
|
360
|
+
const data = await this._echoHost.exportDoc(Context.default(), documentUrl);
|
|
361
|
+
yield [documentUrl.replace(/^automerge:/, ''), data];
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
352
365
|
private async _enterReadyState() {
|
|
353
366
|
await this._callbacks.beforeReady?.();
|
|
354
367
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { EventSubscriptions, UpdateScheduler, scheduleTask } from '@dxos/async';
|
|
6
|
+
import type { AutomergeUrl } from '@dxos/automerge/automerge-repo';
|
|
6
7
|
import { Stream } from '@dxos/codec-protobuf/stream';
|
|
7
8
|
import {
|
|
8
9
|
createAdmissionCredentials,
|
|
@@ -13,7 +14,8 @@ import {
|
|
|
13
14
|
import { raise } from '@dxos/debug';
|
|
14
15
|
import { type SpaceManager } from '@dxos/echo-pipeline';
|
|
15
16
|
import { writeMessages } from '@dxos/feed-store';
|
|
16
|
-
import { invariant } from '@dxos/invariant';
|
|
17
|
+
import { assertArgument, assertState, invariant } from '@dxos/invariant';
|
|
18
|
+
import { SpaceId } from '@dxos/keys';
|
|
17
19
|
import { log } from '@dxos/log';
|
|
18
20
|
import {
|
|
19
21
|
ApiError,
|
|
@@ -40,6 +42,10 @@ import {
|
|
|
40
42
|
type JoinSpaceResponse,
|
|
41
43
|
type JoinBySpaceKeyRequest,
|
|
42
44
|
type CreateEpochResponse,
|
|
45
|
+
type ExportSpaceResponse,
|
|
46
|
+
type ExportSpaceRequest,
|
|
47
|
+
type ImportSpaceRequest,
|
|
48
|
+
type ImportSpaceResponse,
|
|
43
49
|
} from '@dxos/protocols/proto/dxos/client/services';
|
|
44
50
|
import { type Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
45
51
|
import { type GossipMessage } from '@dxos/protocols/proto/dxos/mesh/teleport/gossip';
|
|
@@ -49,6 +55,7 @@ import { type Provider } from '@dxos/util';
|
|
|
49
55
|
import { type DataSpace } from './data-space';
|
|
50
56
|
import { type DataSpaceManager } from './data-space-manager';
|
|
51
57
|
import { type IdentityManager } from '../identity';
|
|
58
|
+
import { extractSpaceArchive, SpaceArchiveWriter } from '../space-export';
|
|
52
59
|
|
|
53
60
|
export class SpacesServiceImpl implements SpacesService {
|
|
54
61
|
constructor(
|
|
@@ -256,6 +263,37 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
256
263
|
return this._joinByAdmission({ credential });
|
|
257
264
|
}
|
|
258
265
|
|
|
266
|
+
async exportSpace(request: ExportSpaceRequest): Promise<ExportSpaceResponse> {
|
|
267
|
+
await using writer = await new SpaceArchiveWriter().open();
|
|
268
|
+
assertArgument(SpaceId.isValid(request.spaceId), 'Invalid space ID');
|
|
269
|
+
|
|
270
|
+
const dataSpaceManager = await this._getDataSpaceManager();
|
|
271
|
+
const space = dataSpaceManager.getSpaceById(request.spaceId) ?? raise(new Error('Space not found'));
|
|
272
|
+
await writer.begin({ spaceId: space.id });
|
|
273
|
+
const rootUrl = space.automergeSpaceState.lastEpoch?.subject.assertion.automergeRoot;
|
|
274
|
+
assertState(rootUrl, 'Space does not have a root URL');
|
|
275
|
+
await writer.setCurrentRootUrl(rootUrl);
|
|
276
|
+
|
|
277
|
+
for await (const [documentId, data] of space.getAllDocuments()) {
|
|
278
|
+
await writer.writeDocument(documentId, data);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const archive = await writer.finish();
|
|
282
|
+
return { archive };
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
async importSpace(request: ImportSpaceRequest): Promise<ImportSpaceResponse> {
|
|
286
|
+
const dataSpaceManager = await this._getDataSpaceManager();
|
|
287
|
+
const extracted = await extractSpaceArchive(request.archive);
|
|
288
|
+
invariant(extracted.metadata.echo?.currentRootUrl, 'Space archive does not contain a root URL');
|
|
289
|
+
const space = await dataSpaceManager.createSpace({
|
|
290
|
+
documents: extracted.documents,
|
|
291
|
+
rootUrl: extracted.metadata.echo?.currentRootUrl as AutomergeUrl,
|
|
292
|
+
});
|
|
293
|
+
await this._updateMetrics();
|
|
294
|
+
return { newSpaceId: space.id };
|
|
295
|
+
}
|
|
296
|
+
|
|
259
297
|
private async _joinByAdmission({ credential }: ContactAdmission): Promise<JoinSpaceResponse> {
|
|
260
298
|
const assertion = getCredentialAssertion(credential);
|
|
261
299
|
invariant(assertion['@type'] === 'dxos.halo.credentials.SpaceMember', 'Invalid credential');
|
package/src/version.ts
CHANGED