@dxos/client-services 0.4.10-main.c42bfdb → 0.4.10-main.c5e8686
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-W7UANCHR.mjs → chunk-FUEOAPLA.mjs} +216 -149
- package/dist/lib/browser/chunk-FUEOAPLA.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/packlets/testing/index.mjs +9 -4
- package/dist/lib/browser/packlets/testing/index.mjs.map +3 -3
- package/dist/lib/node/{chunk-JSVLZGJM.cjs → chunk-VRSCM2WE.cjs} +230 -163
- package/dist/lib/node/chunk-VRSCM2WE.cjs.map +7 -0
- package/dist/lib/node/index.cjs +43 -43
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/packlets/testing/index.cjs +14 -9
- package/dist/lib/node/packlets/testing/index.cjs.map +3 -3
- package/dist/types/src/packlets/indexing/util.d.ts +2 -1
- package/dist/types/src/packlets/indexing/util.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-extension.d.ts +1 -0
- package/dist/types/src/packlets/invitations/invitation-extension.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts +4 -2
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +3 -1
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts +3 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/version.d.ts +1 -1
- package/package.json +34 -34
- package/src/packlets/indexing/util.ts +2 -2
- package/src/packlets/invitations/invitation-extension.ts +28 -1
- package/src/packlets/invitations/invitations-handler.ts +73 -32
- package/src/packlets/invitations/invitations-service.ts +5 -5
- package/src/packlets/services/automerge-host.test.ts +9 -3
- package/src/packlets/services/service-context.test.ts +4 -1
- package/src/packlets/services/service-context.ts +5 -3
- package/src/packlets/services/service-host.ts +14 -3
- package/src/packlets/spaces/data-space-manager.test.ts +4 -4
- package/src/packlets/storage/level.ts +1 -1
- package/src/packlets/testing/test-builder.ts +20 -4
- package/src/version.ts +1 -1
- package/dist/lib/browser/chunk-W7UANCHR.mjs.map +0 -7
- package/dist/lib/node/chunk-JSVLZGJM.cjs.map +0 -7
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from '@dxos/client-protocol';
|
|
12
12
|
import { Context } from '@dxos/context';
|
|
13
13
|
import { generatePasscode } from '@dxos/credentials';
|
|
14
|
+
import { createKeyPair, sign } from '@dxos/crypto';
|
|
14
15
|
import { invariant } from '@dxos/invariant';
|
|
15
16
|
import { PublicKey } from '@dxos/keys';
|
|
16
17
|
import { log } from '@dxos/log';
|
|
@@ -21,9 +22,9 @@ import {
|
|
|
21
22
|
type SwarmConnection,
|
|
22
23
|
} from '@dxos/network-manager';
|
|
23
24
|
import { InvalidInvitationExtensionRoleError, trace } from '@dxos/protocols';
|
|
24
|
-
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
25
|
+
import { type AdmissionKeypair, Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
25
26
|
import { type DeviceProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
26
|
-
import { AuthenticationResponse } from '@dxos/protocols/proto/dxos/halo/invitations';
|
|
27
|
+
import { AuthenticationResponse, type IntroductionResponse } from '@dxos/protocols/proto/dxos/halo/invitations';
|
|
27
28
|
|
|
28
29
|
import {
|
|
29
30
|
InvitationGuestExtension,
|
|
@@ -74,9 +75,11 @@ export class InvitationsHandler {
|
|
|
74
75
|
state = Invitation.State.INIT,
|
|
75
76
|
timeout = INVITATION_TIMEOUT,
|
|
76
77
|
swarmKey = PublicKey.random(),
|
|
77
|
-
persistent =
|
|
78
|
+
persistent = options?.authMethod !== Invitation.AuthMethod.KNOWN_PUBLIC_KEY, // default no not storing keypairs
|
|
78
79
|
created = new Date(),
|
|
79
|
-
|
|
80
|
+
guestKeypair = undefined,
|
|
81
|
+
lifetime = 86400, // 1 day,
|
|
82
|
+
multiUse = false,
|
|
80
83
|
} = options ?? {};
|
|
81
84
|
const authCode =
|
|
82
85
|
options?.authCode ??
|
|
@@ -91,9 +94,12 @@ export class InvitationsHandler {
|
|
|
91
94
|
swarmKey,
|
|
92
95
|
authCode,
|
|
93
96
|
timeout,
|
|
94
|
-
persistent,
|
|
97
|
+
persistent: persistent && type !== Invitation.Type.DELEGATED, // delegated invitations are persisted in control feed
|
|
98
|
+
guestKeypair:
|
|
99
|
+
guestKeypair ?? (authMethod === Invitation.AuthMethod.KNOWN_PUBLIC_KEY ? createAdmissionKeypair() : undefined),
|
|
95
100
|
created,
|
|
96
101
|
lifetime,
|
|
102
|
+
multiUse,
|
|
97
103
|
...protocol.getInvitationContext(),
|
|
98
104
|
};
|
|
99
105
|
|
|
@@ -162,7 +168,7 @@ export class InvitationsHandler {
|
|
|
162
168
|
}
|
|
163
169
|
log.trace('dxos.sdk.invitations-handler.host.onOpen', trace.error({ id: traceId, error: err }));
|
|
164
170
|
} finally {
|
|
165
|
-
if (
|
|
171
|
+
if (!multiUse) {
|
|
166
172
|
// Wait for graceful close before disposing.
|
|
167
173
|
await swarmConnection.close();
|
|
168
174
|
await ctx.dispose();
|
|
@@ -317,26 +323,13 @@ export class InvitationsHandler {
|
|
|
317
323
|
|
|
318
324
|
// 2. Get authentication code.
|
|
319
325
|
if (isAuthenticationRequired(invitation)) {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
setState({ state: Invitation.State.AUTHENTICATING });
|
|
327
|
-
const response = await extension.rpc.InvitationHostService.authenticate({ authCode });
|
|
328
|
-
if (response.status === undefined || response.status === AuthenticationResponse.Status.OK) {
|
|
326
|
+
switch (invitation.authMethod) {
|
|
327
|
+
case Invitation.AuthMethod.SHARED_SECRET:
|
|
328
|
+
await this._handleGuestOtpAuth(extension, setState, authenticated, { timeout });
|
|
329
|
+
break;
|
|
330
|
+
case Invitation.AuthMethod.KNOWN_PUBLIC_KEY:
|
|
331
|
+
await this._handleGuestKpkAuth(extension, setState, invitation, introductionResponse);
|
|
329
332
|
break;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
if (response.status === AuthenticationResponse.Status.INVALID_OTP) {
|
|
333
|
-
if (attempt === MAX_OTP_ATTEMPTS) {
|
|
334
|
-
throw new Error(`Maximum retry attempts: ${MAX_OTP_ATTEMPTS}`);
|
|
335
|
-
} else {
|
|
336
|
-
log('retrying invalid code', { attempt });
|
|
337
|
-
authenticated.reset();
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
333
|
}
|
|
341
334
|
}
|
|
342
335
|
|
|
@@ -423,13 +416,61 @@ export class InvitationsHandler {
|
|
|
423
416
|
|
|
424
417
|
return observable;
|
|
425
418
|
}
|
|
419
|
+
|
|
420
|
+
private async _handleGuestOtpAuth(
|
|
421
|
+
extension: InvitationGuestExtension,
|
|
422
|
+
setState: (newState: Partial<Invitation>) => void,
|
|
423
|
+
authenticated: Trigger<string>,
|
|
424
|
+
options: { timeout: number },
|
|
425
|
+
) {
|
|
426
|
+
for (let attempt = 1; attempt <= MAX_OTP_ATTEMPTS; attempt++) {
|
|
427
|
+
log('guest waiting for authentication code...');
|
|
428
|
+
setState({ state: Invitation.State.READY_FOR_AUTHENTICATION });
|
|
429
|
+
const authCode = await authenticated.wait(options);
|
|
430
|
+
|
|
431
|
+
log('sending authentication request');
|
|
432
|
+
setState({ state: Invitation.State.AUTHENTICATING });
|
|
433
|
+
const response = await extension.rpc.InvitationHostService.authenticate({ authCode });
|
|
434
|
+
if (response.status === undefined || response.status === AuthenticationResponse.Status.OK) {
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (response.status === AuthenticationResponse.Status.INVALID_OTP) {
|
|
439
|
+
if (attempt === MAX_OTP_ATTEMPTS) {
|
|
440
|
+
throw new Error(`Maximum retry attempts: ${MAX_OTP_ATTEMPTS}`);
|
|
441
|
+
} else {
|
|
442
|
+
log('retrying invalid code', { attempt });
|
|
443
|
+
authenticated.reset();
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
private async _handleGuestKpkAuth(
|
|
450
|
+
extension: InvitationGuestExtension,
|
|
451
|
+
setState: (newState: Partial<Invitation>) => void,
|
|
452
|
+
invitation: Invitation,
|
|
453
|
+
introductionResponse: IntroductionResponse,
|
|
454
|
+
) {
|
|
455
|
+
if (invitation.guestKeypair?.privateKey == null) {
|
|
456
|
+
throw new Error('keypair missing in the invitation');
|
|
457
|
+
}
|
|
458
|
+
if (introductionResponse.challenge == null) {
|
|
459
|
+
throw new Error('challenge missing in the introduction');
|
|
460
|
+
}
|
|
461
|
+
log('sending authentication request');
|
|
462
|
+
setState({ state: Invitation.State.AUTHENTICATING });
|
|
463
|
+
const signature = sign(Buffer.from(introductionResponse.challenge), invitation.guestKeypair.privateKey);
|
|
464
|
+
const response = await extension.rpc.InvitationHostService.authenticate({
|
|
465
|
+
signedChallenge: signature,
|
|
466
|
+
});
|
|
467
|
+
if (response.status !== AuthenticationResponse.Status.OK) {
|
|
468
|
+
throw new Error(`Authentication failed with code: ${response.status}`);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
426
471
|
}
|
|
427
472
|
|
|
428
|
-
export const
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
invitation.lifetime &&
|
|
432
|
-
invitation.lifetime !== 0 &&
|
|
433
|
-
invitation.created.getTime() + invitation.lifetime * 1000 < Date.now()
|
|
434
|
-
);
|
|
473
|
+
export const createAdmissionKeypair = (): AdmissionKeypair => {
|
|
474
|
+
const keypair = createKeyPair();
|
|
475
|
+
return { publicKey: PublicKey.from(keypair.publicKey), privateKey: keypair.secretKey };
|
|
435
476
|
};
|
|
@@ -6,7 +6,7 @@ import { Event, scheduleTask } from '@dxos/async';
|
|
|
6
6
|
import { type AuthenticatingInvitation, type CancellableInvitation } from '@dxos/client-protocol';
|
|
7
7
|
import { Stream } from '@dxos/codec-protobuf';
|
|
8
8
|
import { Context } from '@dxos/context';
|
|
9
|
-
import { type MetadataStore } from '@dxos/echo-pipeline';
|
|
9
|
+
import { hasInvitationExpired, type MetadataStore } from '@dxos/echo-pipeline';
|
|
10
10
|
import { invariant } from '@dxos/invariant';
|
|
11
11
|
import { log } from '@dxos/log';
|
|
12
12
|
import {
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
} from '@dxos/protocols/proto/dxos/client/services';
|
|
19
19
|
|
|
20
20
|
import { type InvitationProtocol } from './invitation-protocol';
|
|
21
|
-
import {
|
|
21
|
+
import { type InvitationsHandler } from './invitations-handler';
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Adapts invitation service observable to client/service stream.
|
|
@@ -91,7 +91,7 @@ export class InvitationsServiceImpl implements InvitationsService {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
this._createInvitations.delete(invitation.get().invitationId);
|
|
94
|
-
if (invitation.get().
|
|
94
|
+
if (!invitation.get().multiUse) {
|
|
95
95
|
this._removedCreated.emit(invitation.get());
|
|
96
96
|
}
|
|
97
97
|
},
|
|
@@ -103,7 +103,7 @@ export class InvitationsServiceImpl implements InvitationsService {
|
|
|
103
103
|
const persistentInvitations = this._metadataStore.getInvitations();
|
|
104
104
|
|
|
105
105
|
// get saved persistent invitations, filter and remove from storage those that have expired.
|
|
106
|
-
const freshInvitations = persistentInvitations.filter(async (invitation) => !
|
|
106
|
+
const freshInvitations = persistentInvitations.filter(async (invitation) => !hasInvitationExpired(invitation));
|
|
107
107
|
|
|
108
108
|
const cInvitations = freshInvitations.map((persistentInvitation) => {
|
|
109
109
|
invariant(!this._createInvitations.get(persistentInvitation.invitationId), 'invitation already exists');
|
|
@@ -148,7 +148,7 @@ export class InvitationsServiceImpl implements InvitationsService {
|
|
|
148
148
|
() => {
|
|
149
149
|
close();
|
|
150
150
|
this._acceptInvitations.delete(invitation.get().invitationId);
|
|
151
|
-
if (invitation.get().
|
|
151
|
+
if (!invitation.get().multiUse) {
|
|
152
152
|
this._removedAccepted.emit(invitation.get());
|
|
153
153
|
}
|
|
154
154
|
},
|
|
@@ -6,8 +6,8 @@ import { expect } from 'chai';
|
|
|
6
6
|
|
|
7
7
|
import { asyncTimeout, sleep } from '@dxos/async';
|
|
8
8
|
import { AutomergeHost, DataServiceImpl } from '@dxos/echo-pipeline';
|
|
9
|
+
import { createTestLevel } from '@dxos/echo-pipeline/testing';
|
|
9
10
|
import { AutomergeContext } from '@dxos/echo-schema';
|
|
10
|
-
import { StorageType, createStorage } from '@dxos/random-access-storage';
|
|
11
11
|
import { afterTest, describe, test } from '@dxos/test';
|
|
12
12
|
|
|
13
13
|
describe('AutomergeHost', () => {
|
|
@@ -19,10 +19,16 @@ describe('AutomergeHost', () => {
|
|
|
19
19
|
// creates repo and document | replicates repo | finds document in repo
|
|
20
20
|
//
|
|
21
21
|
|
|
22
|
-
const
|
|
22
|
+
const level = createTestLevel();
|
|
23
|
+
await level.open();
|
|
24
|
+
afterTest(() => level.close());
|
|
23
25
|
|
|
24
|
-
const host = new AutomergeHost({
|
|
26
|
+
const host = new AutomergeHost({
|
|
27
|
+
db: level.sublevel('automerge'),
|
|
28
|
+
});
|
|
29
|
+
await host.open();
|
|
25
30
|
afterTest(() => host.close());
|
|
31
|
+
|
|
26
32
|
const dataService = new DataServiceImpl(host);
|
|
27
33
|
const client = new AutomergeContext(dataService);
|
|
28
34
|
afterTest(() => client.close());
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { MemorySignalManagerContext } from '@dxos/messaging';
|
|
6
6
|
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
7
|
-
import { describe, test } from '@dxos/test';
|
|
7
|
+
import { describe, openAndClose, test } from '@dxos/test';
|
|
8
8
|
|
|
9
9
|
import { createServiceContext } from '../testing';
|
|
10
10
|
import { performInvitation } from '../testing/invitation-utils';
|
|
@@ -27,12 +27,15 @@ describe('services/ServiceContext', () => {
|
|
|
27
27
|
test('joined space is synchronized on device invitations', async () => {
|
|
28
28
|
const networkContext = new MemorySignalManagerContext();
|
|
29
29
|
const device1 = await createServiceContext({ signalContext: networkContext });
|
|
30
|
+
await openAndClose(device1.automergeHost);
|
|
30
31
|
await device1.createIdentity();
|
|
31
32
|
|
|
32
33
|
const device2 = await createServiceContext({ signalContext: networkContext });
|
|
34
|
+
await openAndClose(device2.automergeHost);
|
|
33
35
|
await Promise.all(performInvitation({ host: device1, guest: device2, options: { kind: Invitation.Kind.DEVICE } }));
|
|
34
36
|
|
|
35
37
|
const identity2 = await createServiceContext({ signalContext: networkContext });
|
|
38
|
+
await openAndClose(identity2.automergeHost);
|
|
36
39
|
await identity2.createIdentity();
|
|
37
40
|
const space1 = await identity2.dataSpaceManager!.createSpace();
|
|
38
41
|
await Promise.all(
|
|
@@ -10,7 +10,7 @@ import { getCredentialAssertion, type CredentialProcessor } from '@dxos/credenti
|
|
|
10
10
|
import { failUndefined } from '@dxos/debug';
|
|
11
11
|
import { AutomergeHost, MetadataStore, SnapshotStore, SpaceManager, valueEncoding } from '@dxos/echo-pipeline';
|
|
12
12
|
import { FeedFactory, FeedStore } from '@dxos/feed-store';
|
|
13
|
-
import { IndexMetadataStore, IndexStore, Indexer } from '@dxos/indexing';
|
|
13
|
+
import { IndexMetadataStore, IndexStore, Indexer, createStorageCallbacks } from '@dxos/indexing';
|
|
14
14
|
import { invariant } from '@dxos/invariant';
|
|
15
15
|
import { Keyring } from '@dxos/keyring';
|
|
16
16
|
import { PublicKey } from '@dxos/keys';
|
|
@@ -124,11 +124,12 @@ export class ServiceContext extends Resource {
|
|
|
124
124
|
|
|
125
125
|
this.automergeHost = new AutomergeHost({
|
|
126
126
|
directory: storage.createDirectory('automerge'),
|
|
127
|
-
|
|
127
|
+
db: level.sublevel('automerge'),
|
|
128
|
+
storageCallbacks: createStorageCallbacks({ host: () => this.automergeHost, metadata: this.indexMetadata }),
|
|
128
129
|
});
|
|
129
130
|
|
|
130
131
|
this.indexer = new Indexer({
|
|
131
|
-
indexStore: new IndexStore({
|
|
132
|
+
indexStore: new IndexStore({ db: level.sublevel('index-storage') }),
|
|
132
133
|
metadataStore: this.indexMetadata,
|
|
133
134
|
loadDocuments: createSelectedDocumentsIterator(this.automergeHost),
|
|
134
135
|
getAllDocuments: createDocumentsIterator(this.automergeHost),
|
|
@@ -158,6 +159,7 @@ export class ServiceContext extends Resource {
|
|
|
158
159
|
await this.signalManager.open();
|
|
159
160
|
await this.networkManager.open();
|
|
160
161
|
|
|
162
|
+
await this.automergeHost.open();
|
|
161
163
|
await this.metadataStore.load();
|
|
162
164
|
await this.spaceManager.open();
|
|
163
165
|
await this.identityManager.open(ctx);
|
|
@@ -8,8 +8,14 @@ import { Event, synchronized } from '@dxos/async';
|
|
|
8
8
|
import { clientServiceBundle, defaultKey, type ClientServices, Properties } from '@dxos/client-protocol';
|
|
9
9
|
import { type Config } from '@dxos/config';
|
|
10
10
|
import { Context } from '@dxos/context';
|
|
11
|
-
import {
|
|
12
|
-
|
|
11
|
+
import {
|
|
12
|
+
DataServiceImpl,
|
|
13
|
+
type ObjectStructure,
|
|
14
|
+
encodeReference,
|
|
15
|
+
type SpaceDoc,
|
|
16
|
+
type LevelDB,
|
|
17
|
+
} from '@dxos/echo-pipeline';
|
|
18
|
+
import { getTypeReference } from '@dxos/echo-schema';
|
|
13
19
|
import { IndexServiceImpl } from '@dxos/indexing';
|
|
14
20
|
import { invariant } from '@dxos/invariant';
|
|
15
21
|
import { PublicKey } from '@dxos/keys';
|
|
@@ -50,6 +56,7 @@ export type ClientServicesHostParams = {
|
|
|
50
56
|
signalManager?: SignalManager;
|
|
51
57
|
connectionLog?: boolean;
|
|
52
58
|
storage?: Storage;
|
|
59
|
+
level?: LevelDB;
|
|
53
60
|
lockKey?: string;
|
|
54
61
|
callbacks?: ClientServicesHostCallbacks;
|
|
55
62
|
runtimeParams?: ServiceContextRuntimeParams;
|
|
@@ -101,12 +108,14 @@ export class ClientServicesHost {
|
|
|
101
108
|
transportFactory,
|
|
102
109
|
signalManager,
|
|
103
110
|
storage,
|
|
111
|
+
level,
|
|
104
112
|
// TODO(wittjosiah): Turn this on by default.
|
|
105
113
|
lockKey,
|
|
106
114
|
callbacks,
|
|
107
115
|
runtimeParams,
|
|
108
116
|
}: ClientServicesHostParams = {}) {
|
|
109
117
|
this._storage = storage;
|
|
118
|
+
this._level = level;
|
|
110
119
|
this._callbacks = callbacks;
|
|
111
120
|
this._runtimeParams = runtimeParams;
|
|
112
121
|
|
|
@@ -239,6 +248,8 @@ export class ClientServicesHost {
|
|
|
239
248
|
if (!this._level) {
|
|
240
249
|
this._level = await createLevel(this._config.get('runtime.client.storage', {})!);
|
|
241
250
|
}
|
|
251
|
+
await this._level.open();
|
|
252
|
+
|
|
242
253
|
await this._resourceLock?.acquire();
|
|
243
254
|
|
|
244
255
|
await this._loggingService.open();
|
|
@@ -372,7 +383,7 @@ export class ClientServicesHost {
|
|
|
372
383
|
// TODO(dmaretskyi): Better API for low-level data access.
|
|
373
384
|
const properties: ObjectStructure = {
|
|
374
385
|
system: {
|
|
375
|
-
type: encodeReference(
|
|
386
|
+
type: encodeReference(getTypeReference(Properties)!),
|
|
376
387
|
},
|
|
377
388
|
data: {
|
|
378
389
|
[defaultKey]: identity.identityKey.toHex(),
|
|
@@ -20,7 +20,7 @@ describe('DataSpaceManager', () => {
|
|
|
20
20
|
|
|
21
21
|
const peer = builder.createPeer();
|
|
22
22
|
await peer.createIdentity();
|
|
23
|
-
await openAndClose(peer.dataSpaceManager);
|
|
23
|
+
await openAndClose(peer.automergeHost, peer.dataSpaceManager);
|
|
24
24
|
|
|
25
25
|
const space = await peer.dataSpaceManager.createSpace();
|
|
26
26
|
|
|
@@ -42,7 +42,7 @@ describe('DataSpaceManager', () => {
|
|
|
42
42
|
const peer2 = builder.createPeer();
|
|
43
43
|
await peer2.createIdentity();
|
|
44
44
|
|
|
45
|
-
await openAndClose(peer1.dataSpaceManager, peer2.dataSpaceManager);
|
|
45
|
+
await openAndClose(peer1.automergeHost, peer1.dataSpaceManager, peer2.automergeHost, peer2.dataSpaceManager);
|
|
46
46
|
|
|
47
47
|
const space1 = await peer1.dataSpaceManager.createSpace();
|
|
48
48
|
await space1.inner.controlPipeline.state.waitUntilTimeframe(space1.inner.controlPipeline.state.endTimeframe);
|
|
@@ -111,7 +111,7 @@ describe('DataSpaceManager', () => {
|
|
|
111
111
|
await peer2.createIdentity();
|
|
112
112
|
await peer2.dataSpaceManager.open();
|
|
113
113
|
|
|
114
|
-
await openAndClose(peer1.dataSpaceManager, peer2.dataSpaceManager);
|
|
114
|
+
await openAndClose(peer1.automergeHost, peer1.dataSpaceManager, peer2.automergeHost, peer2.dataSpaceManager);
|
|
115
115
|
|
|
116
116
|
const space1 = await peer1.dataSpaceManager.createSpace();
|
|
117
117
|
await space1.inner.controlPipeline.state.waitUntilTimeframe(space1.inner.controlPipeline.state.endTimeframe);
|
|
@@ -153,7 +153,7 @@ describe('DataSpaceManager', () => {
|
|
|
153
153
|
|
|
154
154
|
const peer = builder.createPeer();
|
|
155
155
|
await peer.createIdentity();
|
|
156
|
-
await openAndClose(peer.dataSpaceManager);
|
|
156
|
+
await openAndClose(peer.automergeHost, peer.dataSpaceManager);
|
|
157
157
|
|
|
158
158
|
const space = await peer.dataSpaceManager.createSpace();
|
|
159
159
|
await space.inner.controlPipeline.state.waitUntilTimeframe(space.inner.controlPipeline.state.endTimeframe);
|
|
@@ -12,7 +12,7 @@ import { getRootPath, isPersistent } from './util';
|
|
|
12
12
|
|
|
13
13
|
export const createLevel = async (config: Runtime.Client.Storage) => {
|
|
14
14
|
const persistent = isPersistent(config);
|
|
15
|
-
const storagePath = persistent ? getRootPath(config)
|
|
15
|
+
const storagePath = persistent ? path.join(getRootPath(config), 'level') : `/tmp/dxos-${PublicKey.random().toHex()}`;
|
|
16
16
|
const level = new Level<string, string>(storagePath);
|
|
17
17
|
await level.open();
|
|
18
18
|
return level;
|
|
@@ -6,9 +6,16 @@ import { type Config } from '@dxos/config';
|
|
|
6
6
|
import { Context } from '@dxos/context';
|
|
7
7
|
import { createCredentialSignerWithChain, CredentialGenerator } from '@dxos/credentials';
|
|
8
8
|
import { failUndefined } from '@dxos/debug';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
AutomergeHost,
|
|
11
|
+
MetadataStore,
|
|
12
|
+
type LevelDB,
|
|
13
|
+
SnapshotStore,
|
|
14
|
+
SpaceManager,
|
|
15
|
+
valueEncoding,
|
|
16
|
+
} from '@dxos/echo-pipeline';
|
|
17
|
+
import { createTestLevel } from '@dxos/echo-pipeline/testing';
|
|
10
18
|
import { FeedFactory, FeedStore } from '@dxos/feed-store';
|
|
11
|
-
import { createTestLevel } from '@dxos/indexing/testing';
|
|
12
19
|
import { Keyring } from '@dxos/keyring';
|
|
13
20
|
import { MemorySignalManager, MemorySignalManagerContext } from '@dxos/messaging';
|
|
14
21
|
import { MemoryTransportFactory, NetworkManager } from '@dxos/network-manager';
|
|
@@ -42,7 +49,8 @@ export const createServiceContext = async ({
|
|
|
42
49
|
signalManager,
|
|
43
50
|
transportFactory: MemoryTransportFactory,
|
|
44
51
|
});
|
|
45
|
-
const level =
|
|
52
|
+
const level = createTestLevel();
|
|
53
|
+
await level.open();
|
|
46
54
|
|
|
47
55
|
return new ServiceContext(storage, level, networkManager, signalManager);
|
|
48
56
|
};
|
|
@@ -85,6 +93,7 @@ export type TestPeerOpts = {
|
|
|
85
93
|
|
|
86
94
|
export type TestPeerProps = {
|
|
87
95
|
storage?: Storage;
|
|
96
|
+
level?: LevelDB;
|
|
88
97
|
feedStore?: FeedStore<any>;
|
|
89
98
|
metadataStore?: MetadataStore;
|
|
90
99
|
keyring?: Keyring;
|
|
@@ -117,6 +126,10 @@ export class TestPeer {
|
|
|
117
126
|
return (this._props.keyring ??= new Keyring(this.storage.createDirectory('keyring')));
|
|
118
127
|
}
|
|
119
128
|
|
|
129
|
+
get level() {
|
|
130
|
+
return (this._props.level ??= createTestLevel());
|
|
131
|
+
}
|
|
132
|
+
|
|
120
133
|
get feedStore() {
|
|
121
134
|
return (this._props.feedStore ??= new FeedStore({
|
|
122
135
|
factory: new FeedFactory({
|
|
@@ -163,7 +176,9 @@ export class TestPeer {
|
|
|
163
176
|
}
|
|
164
177
|
|
|
165
178
|
get automergeHost() {
|
|
166
|
-
return (this._props.automergeHost ??= new AutomergeHost({
|
|
179
|
+
return (this._props.automergeHost ??= new AutomergeHost({
|
|
180
|
+
db: this.level.sublevel('automerge'),
|
|
181
|
+
}));
|
|
167
182
|
}
|
|
168
183
|
|
|
169
184
|
get dataSpaceManager() {
|
|
@@ -182,6 +197,7 @@ export class TestPeer {
|
|
|
182
197
|
}
|
|
183
198
|
|
|
184
199
|
async destroy() {
|
|
200
|
+
await this.level.close();
|
|
185
201
|
await this.storage.reset();
|
|
186
202
|
}
|
|
187
203
|
}
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const DXOS_VERSION = "0.4.10-main.
|
|
1
|
+
export const DXOS_VERSION = "0.4.10-main.c5e8686";
|