@dxos/client-services 0.1.28 → 0.1.29-next.1bc50d4
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-OTSGRZZI.mjs → chunk-ILMYW75X.mjs} +740 -1043
- package/dist/lib/browser/chunk-ILMYW75X.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +7 -41
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/packlets/testing/index.mjs +163 -50
- package/dist/lib/browser/packlets/testing/index.mjs.map +4 -4
- package/dist/lib/node/index.cjs +645 -969
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/packlets/testing/index.cjs +2686 -2637
- package/dist/lib/node/packlets/testing/index.cjs.map +4 -4
- package/dist/types/src/packlets/devices/devices-service.test.d.ts +2 -0
- package/dist/types/src/packlets/devices/devices-service.test.d.ts.map +1 -0
- package/dist/types/src/packlets/identity/identity-service.test.d.ts +2 -0
- package/dist/types/src/packlets/identity/identity-service.test.d.ts.map +1 -0
- package/dist/types/src/packlets/invitations/device-invitations-handler.d.ts +1 -2
- package/dist/types/src/packlets/invitations/device-invitations-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/device-invitations-service.d.ts +1 -1
- package/dist/types/src/packlets/invitations/device-invitations-service.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/index.d.ts +0 -6
- package/dist/types/src/packlets/invitations/index.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-service.d.ts +2 -3
- package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/space-invitations-handler.d.ts +2 -4
- package/dist/types/src/packlets/invitations/space-invitations-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/space-invitations-service.d.ts +2 -3
- package/dist/types/src/packlets/invitations/space-invitations-service.d.ts.map +1 -1
- package/dist/types/src/packlets/network/network-service.test.d.ts +2 -0
- package/dist/types/src/packlets/network/network-service.test.d.ts.map +1 -0
- package/dist/types/src/packlets/services/index.d.ts +2 -2
- package/dist/types/src/packlets/services/index.d.ts.map +1 -1
- package/dist/types/src/packlets/services/local-client-services.d.ts +15 -0
- package/dist/types/src/packlets/services/local-client-services.d.ts.map +1 -0
- package/dist/types/src/packlets/services/service-context.d.ts +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 -5
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/services/utils.d.ts +7 -0
- package/dist/types/src/packlets/services/utils.d.ts.map +1 -0
- package/dist/types/src/packlets/spaces/index.d.ts +2 -0
- package/dist/types/src/packlets/spaces/index.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.test.d.ts +2 -0
- package/dist/types/src/packlets/spaces/spaces-service.test.d.ts.map +1 -0
- package/dist/types/src/packlets/testing/host-test-builder.d.ts +43 -0
- package/dist/types/src/packlets/testing/host-test-builder.d.ts.map +1 -0
- package/dist/types/src/packlets/testing/index.d.ts +1 -0
- package/dist/types/src/packlets/testing/index.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/invitation-utils.d.ts +1 -1
- package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts +30 -34
- package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/packlets/tests/client-services.test.d.ts +2 -0
- package/dist/types/src/packlets/tests/client-services.test.d.ts.map +1 -0
- package/dist/types/src/packlets/tests/client.test.d.ts +2 -0
- package/dist/types/src/packlets/tests/client.test.d.ts.map +1 -0
- package/dist/types/src/packlets/tests/halo-credentials.test.d.ts +2 -0
- package/dist/types/src/packlets/tests/halo-credentials.test.d.ts.map +1 -0
- package/dist/types/src/packlets/tests/halo-persistent.test.d.ts +2 -0
- package/dist/types/src/packlets/tests/halo-persistent.test.d.ts.map +1 -0
- package/dist/types/src/packlets/tests/halo-profile.test.d.ts +2 -0
- package/dist/types/src/packlets/tests/halo-profile.test.d.ts.map +1 -0
- package/dist/types/src/packlets/tests/shared-worker.test.d.ts +2 -0
- package/dist/types/src/packlets/tests/shared-worker.test.d.ts.map +1 -0
- package/dist/types/src/packlets/tests/spaces-invitations.test.d.ts +2 -0
- package/dist/types/src/packlets/tests/spaces-invitations.test.d.ts.map +1 -0
- package/dist/types/src/packlets/tests/spaces.test.d.ts +2 -0
- package/dist/types/src/packlets/tests/spaces.test.d.ts.map +1 -0
- package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts +2 -2
- package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/index.d.ts +0 -2
- package/dist/types/src/packlets/vault/index.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/shell-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/worker-session.d.ts +1 -1
- package/dist/types/src/packlets/vault/worker-session.d.ts.map +1 -1
- package/package.json +30 -30
- package/src/packlets/devices/devices-service.test.ts +56 -0
- package/src/packlets/identity/identity-service.test.ts +82 -0
- package/src/packlets/invitations/device-invitations-handler.ts +10 -9
- package/src/packlets/invitations/device-invitations-service.test.ts +1 -1
- package/src/packlets/invitations/device-invitations-service.ts +1 -1
- package/src/packlets/invitations/index.ts +0 -6
- package/src/packlets/invitations/invitations-service.ts +7 -2
- package/src/packlets/invitations/space-invitations-handler.test.ts +3 -3
- package/src/packlets/invitations/space-invitations-handler.ts +11 -11
- package/src/packlets/invitations/space-invitations-service.test.ts +1 -1
- package/src/packlets/invitations/space-invitations-service.ts +2 -3
- package/src/packlets/network/network-service.test.ts +52 -0
- package/src/packlets/services/index.ts +2 -2
- package/src/packlets/services/local-client-services.ts +35 -0
- package/src/packlets/services/service-context.test.ts +4 -4
- package/src/packlets/services/service-context.ts +1 -1
- package/src/packlets/services/service-host.ts +3 -11
- package/src/packlets/services/service-registry.test.ts +2 -2
- package/src/packlets/services/utils.ts +53 -0
- package/src/packlets/spaces/data-space-manager.test.ts +4 -4
- package/src/packlets/spaces/data-space-manager.ts +1 -1
- package/src/packlets/spaces/index.ts +2 -0
- package/src/packlets/spaces/spaces-service.test.ts +107 -0
- package/src/packlets/testing/host-test-builder.ts +163 -0
- package/src/packlets/testing/index.ts +1 -0
- package/src/packlets/testing/invitation-utils.ts +1 -2
- package/src/packlets/testing/test-builder.ts +118 -140
- package/src/packlets/tests/client-services.test.ts +252 -0
- package/src/packlets/tests/client.test.ts +143 -0
- package/src/packlets/tests/halo-credentials.test.ts +94 -0
- package/src/packlets/tests/halo-persistent.test.ts +53 -0
- package/src/packlets/tests/halo-profile.test.ts +74 -0
- package/src/packlets/tests/shared-worker.test.ts +96 -0
- package/src/packlets/tests/spaces-invitations.test.ts +24 -0
- package/src/packlets/tests/spaces.test.ts +68 -0
- package/src/packlets/vault/iframe-host-runtime.ts +6 -3
- package/src/packlets/vault/iframe-proxy-runtime.ts +1 -1
- package/src/packlets/vault/index.ts +0 -2
- package/src/packlets/vault/shell-runtime.ts +1 -2
- package/src/packlets/vault/worker-session.ts +7 -3
- package/dist/lib/browser/chunk-OTSGRZZI.mjs.map +0 -7
- package/dist/types/src/packlets/invitations/device-invitations-proxy.d.ts +0 -8
- package/dist/types/src/packlets/invitations/device-invitations-proxy.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/encoder.d.ts +0 -9
- package/dist/types/src/packlets/invitations/encoder.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/encoder.test.d.ts +0 -2
- package/dist/types/src/packlets/invitations/encoder.test.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts +0 -56
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/invitations-proxy.d.ts +0 -18
- package/dist/types/src/packlets/invitations/invitations-proxy.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/invitations.d.ts +0 -55
- package/dist/types/src/packlets/invitations/invitations.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/space-invitations-proxy.d.ts +0 -11
- package/dist/types/src/packlets/invitations/space-invitations-proxy.d.ts.map +0 -1
- package/dist/types/src/packlets/services/service-definitions.d.ts +0 -30
- package/dist/types/src/packlets/services/service-definitions.d.ts.map +0 -1
- package/dist/types/src/packlets/services/service-proxy.d.ts +0 -17
- package/dist/types/src/packlets/services/service-proxy.d.ts.map +0 -1
- package/dist/types/src/packlets/vault/services.d.ts +0 -21
- package/dist/types/src/packlets/vault/services.d.ts.map +0 -1
- package/dist/types/src/packlets/vault/shell-controller.d.ts +0 -18
- package/dist/types/src/packlets/vault/shell-controller.d.ts.map +0 -1
- package/src/packlets/invitations/device-invitations-proxy.ts +0 -14
- package/src/packlets/invitations/encoder.test.ts +0 -23
- package/src/packlets/invitations/encoder.ts +0 -26
- package/src/packlets/invitations/invitations-handler.ts +0 -68
- package/src/packlets/invitations/invitations-proxy.ts +0 -159
- package/src/packlets/invitations/invitations.ts +0 -113
- package/src/packlets/invitations/space-invitations-proxy.ts +0 -16
- package/src/packlets/services/service-definitions.ts +0 -68
- package/src/packlets/services/service-proxy.ts +0 -54
- package/src/packlets/vault/services.ts +0 -42
- package/src/packlets/vault/shell-controller.ts +0 -56
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { ClientServicesProvider } from '@dxos/client';
|
|
6
|
+
import { Config } from '@dxos/config';
|
|
7
|
+
import { log } from '@dxos/log';
|
|
8
|
+
import { MemorySignalManager, MemorySignalManagerContext, WebsocketSignalManager } from '@dxos/messaging';
|
|
9
|
+
import {
|
|
10
|
+
createWebRTCTransportFactory,
|
|
11
|
+
MemoryTransportFactory,
|
|
12
|
+
NetworkManager,
|
|
13
|
+
NetworkManagerOptions
|
|
14
|
+
} from '@dxos/network-manager';
|
|
15
|
+
|
|
16
|
+
import { LocalClientServices } from './local-client-services';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Creates stand-alone services without rpc.
|
|
20
|
+
*/
|
|
21
|
+
export const fromHost = (config: Config = new Config()): ClientServicesProvider => {
|
|
22
|
+
return new LocalClientServices({
|
|
23
|
+
config,
|
|
24
|
+
networkManager: createNetworkManager(config)
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Creates a WebRTC network manager connected to the specified signal server.
|
|
30
|
+
*/
|
|
31
|
+
// TODO(burdon): Move to client-services and remove dependencies from here.
|
|
32
|
+
const createNetworkManager = (config: Config, options: Partial<NetworkManagerOptions> = {}): NetworkManager => {
|
|
33
|
+
const signalServer = config.get('runtime.services.signal.server');
|
|
34
|
+
if (signalServer) {
|
|
35
|
+
const {
|
|
36
|
+
log = true,
|
|
37
|
+
signalManager = new WebsocketSignalManager([signalServer]),
|
|
38
|
+
transportFactory = createWebRTCTransportFactory({
|
|
39
|
+
iceServers: config.get('runtime.services.ice')
|
|
40
|
+
})
|
|
41
|
+
} = options;
|
|
42
|
+
|
|
43
|
+
return new NetworkManager({ log, signalManager, transportFactory });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// TODO(burdon): Should not provide a memory signal manager since no shared context.
|
|
47
|
+
// Use TestClientBuilder for shared memory tests.
|
|
48
|
+
log.warn('P2P network is not configured.');
|
|
49
|
+
return new NetworkManager({
|
|
50
|
+
signalManager: new MemorySignalManager(new MemorySignalManagerContext()),
|
|
51
|
+
transportFactory: MemoryTransportFactory
|
|
52
|
+
});
|
|
53
|
+
};
|
|
@@ -12,12 +12,12 @@ import { log } from '@dxos/log';
|
|
|
12
12
|
import { ModelFactory } from '@dxos/model-factory';
|
|
13
13
|
import { test, describe } from '@dxos/test';
|
|
14
14
|
|
|
15
|
-
import { createSigningContext,
|
|
15
|
+
import { createSigningContext, HostTestBuilder, syncItemsLocal } from '../testing';
|
|
16
16
|
import { DataSpaceManager } from './data-space-manager';
|
|
17
17
|
|
|
18
18
|
describe('DataSpaceManager', () => {
|
|
19
19
|
test('create space', async () => {
|
|
20
|
-
const builder = new
|
|
20
|
+
const builder = new HostTestBuilder();
|
|
21
21
|
|
|
22
22
|
const peer = builder.createPeer();
|
|
23
23
|
const identity = await createSigningContext(peer.keyring);
|
|
@@ -43,7 +43,7 @@ describe('DataSpaceManager', () => {
|
|
|
43
43
|
});
|
|
44
44
|
|
|
45
45
|
test('sync between peers', async () => {
|
|
46
|
-
const builder = new
|
|
46
|
+
const builder = new HostTestBuilder();
|
|
47
47
|
|
|
48
48
|
const peer1 = builder.createPeer();
|
|
49
49
|
const identity1 = await createSigningContext(peer1.keyring);
|
|
@@ -121,7 +121,7 @@ describe('DataSpaceManager', () => {
|
|
|
121
121
|
});
|
|
122
122
|
log.break();
|
|
123
123
|
|
|
124
|
-
await
|
|
124
|
+
await syncItemsLocal(space1.dataPipelineController, space2.dataPipelineController);
|
|
125
125
|
|
|
126
126
|
expect(space1.inner.protocol.sessions.get(identity2.deviceKey)).to.exist;
|
|
127
127
|
expect(space1.inner.protocol.sessions.get(identity2.deviceKey)?.authStatus).to.equal(AuthStatus.SUCCESS);
|
|
@@ -153,7 +153,7 @@ export class DataSpaceManager {
|
|
|
153
153
|
const presence = new Presence({
|
|
154
154
|
localPeerId: this._signingContext.deviceKey,
|
|
155
155
|
announceInterval: 1_000,
|
|
156
|
-
offlineTimeout:
|
|
156
|
+
offlineTimeout: 10_000, // TODO(burdon): Config.
|
|
157
157
|
identityKey: this._signingContext.identityKey
|
|
158
158
|
});
|
|
159
159
|
const snapshotManager = new SnapshotManager(this._snapshotStore);
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import chai, { expect } from 'chai';
|
|
6
|
+
import chaiAsPromised from 'chai-as-promised';
|
|
7
|
+
|
|
8
|
+
import { Trigger } from '@dxos/async';
|
|
9
|
+
import { PublicKey } from '@dxos/keys';
|
|
10
|
+
import { Space, SpacesService } from '@dxos/protocols/proto/dxos/client/services';
|
|
11
|
+
import { afterEach, afterTest, beforeEach, describe, test } from '@dxos/test';
|
|
12
|
+
|
|
13
|
+
import { ServiceContext } from '../services';
|
|
14
|
+
import { createServiceContext } from '../testing';
|
|
15
|
+
import { SpacesServiceImpl } from './spaces-service';
|
|
16
|
+
|
|
17
|
+
chai.use(chaiAsPromised);
|
|
18
|
+
|
|
19
|
+
describe('SpacesService', () => {
|
|
20
|
+
let serviceContext: ServiceContext;
|
|
21
|
+
let spacesService: SpacesService;
|
|
22
|
+
|
|
23
|
+
beforeEach(async () => {
|
|
24
|
+
serviceContext = createServiceContext();
|
|
25
|
+
await serviceContext.open();
|
|
26
|
+
spacesService = new SpacesServiceImpl(
|
|
27
|
+
serviceContext.identityManager,
|
|
28
|
+
serviceContext.spaceManager,
|
|
29
|
+
serviceContext.dataServiceSubscriptions,
|
|
30
|
+
async () => {
|
|
31
|
+
await serviceContext.initialized.wait();
|
|
32
|
+
return serviceContext.dataSpaceManager!;
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
afterEach(async () => {
|
|
38
|
+
await serviceContext.close();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe('createSpace', () => {
|
|
42
|
+
test('fails if no identity is available', async () => {
|
|
43
|
+
await expect(spacesService.createSpace()).to.be.rejectedWith();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('creates a new space', async () => {
|
|
47
|
+
await serviceContext.createIdentity();
|
|
48
|
+
const space = await spacesService.createSpace();
|
|
49
|
+
expect(space).to.exist;
|
|
50
|
+
expect(space.spaceKey).to.be.instanceof(PublicKey);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe.skip('updateSpace', () => {});
|
|
55
|
+
|
|
56
|
+
describe('querySpaces', () => {
|
|
57
|
+
test('returns empty list if no identity is available', async () => {
|
|
58
|
+
const query = spacesService.querySpaces();
|
|
59
|
+
const result = new Trigger<Space[] | undefined>();
|
|
60
|
+
query.subscribe(({ spaces }) => {
|
|
61
|
+
result.wake(spaces);
|
|
62
|
+
});
|
|
63
|
+
afterTest(() => query.close());
|
|
64
|
+
expect(await result.wait()).to.be.length(0);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('returns list of existing spaces', async () => {
|
|
68
|
+
await serviceContext.createIdentity();
|
|
69
|
+
const existingSpaces = [
|
|
70
|
+
await spacesService.createSpace(),
|
|
71
|
+
await spacesService.createSpace(),
|
|
72
|
+
await spacesService.createSpace()
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
const query = spacesService.querySpaces();
|
|
76
|
+
const result = new Trigger<Space[] | undefined>();
|
|
77
|
+
query.subscribe(({ spaces }) => {
|
|
78
|
+
result.wake(spaces);
|
|
79
|
+
});
|
|
80
|
+
afterTest(() => query.close());
|
|
81
|
+
|
|
82
|
+
const spaces = await result.wait();
|
|
83
|
+
expect(spaces).to.be.length(3);
|
|
84
|
+
expect(spaces).to.deep.equal(existingSpaces);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('updates when new space is added', async () => {
|
|
88
|
+
await serviceContext.createIdentity();
|
|
89
|
+
const query = spacesService.querySpaces();
|
|
90
|
+
let result = new Trigger<Space[] | undefined>();
|
|
91
|
+
query.subscribe(({ spaces }) => {
|
|
92
|
+
result.wake(spaces);
|
|
93
|
+
});
|
|
94
|
+
afterTest(() => query.close());
|
|
95
|
+
expect(await result.wait()).to.be.length(0);
|
|
96
|
+
|
|
97
|
+
result = new Trigger<Space[] | undefined>();
|
|
98
|
+
const space = await spacesService.createSpace();
|
|
99
|
+
expect(await result.wait()).to.deep.equal([space]);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test.skip('updates when space is updated', async () => {});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe.skip('writeCrendentials', () => {});
|
|
106
|
+
describe.skip('queryCrendentials', () => {});
|
|
107
|
+
});
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { createDefaultModelFactory } from '@dxos/client';
|
|
6
|
+
import { Config } from '@dxos/config';
|
|
7
|
+
import { createCredentialSignerWithChain, CredentialGenerator } from '@dxos/credentials';
|
|
8
|
+
import {
|
|
9
|
+
SnapshotStore,
|
|
10
|
+
DataPipelineControllerImpl,
|
|
11
|
+
MetadataStore,
|
|
12
|
+
SigningContext,
|
|
13
|
+
SpaceManager,
|
|
14
|
+
valueEncoding
|
|
15
|
+
} from '@dxos/echo-pipeline';
|
|
16
|
+
import { testLocalDatabase } from '@dxos/echo-pipeline/testing';
|
|
17
|
+
import { FeedFactory, FeedStore } from '@dxos/feed-store';
|
|
18
|
+
import { Keyring } from '@dxos/keyring';
|
|
19
|
+
import { MemorySignalManager, MemorySignalManagerContext } from '@dxos/messaging';
|
|
20
|
+
import { MemoryTransportFactory, NetworkManager } from '@dxos/network-manager';
|
|
21
|
+
import { createStorage, Storage, StorageType } from '@dxos/random-access-storage';
|
|
22
|
+
|
|
23
|
+
import { ClientServicesHost, ServiceContext } from '../services';
|
|
24
|
+
|
|
25
|
+
//
|
|
26
|
+
// TODO(burdon): Replace with test builder.
|
|
27
|
+
//
|
|
28
|
+
|
|
29
|
+
export const createServiceHost = (config: Config, signalManagerContext: MemorySignalManagerContext) => {
|
|
30
|
+
const networkManager = new NetworkManager({
|
|
31
|
+
signalManager: new MemorySignalManager(signalManagerContext),
|
|
32
|
+
transportFactory: MemoryTransportFactory
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return new ClientServicesHost({
|
|
36
|
+
config,
|
|
37
|
+
networkManager
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const createServiceContext = ({
|
|
42
|
+
signalContext = new MemorySignalManagerContext(),
|
|
43
|
+
storage = createStorage({ type: StorageType.RAM })
|
|
44
|
+
}: {
|
|
45
|
+
signalContext?: MemorySignalManagerContext;
|
|
46
|
+
storage?: Storage;
|
|
47
|
+
} = {}) => {
|
|
48
|
+
const networkManager = new NetworkManager({
|
|
49
|
+
signalManager: new MemorySignalManager(signalContext),
|
|
50
|
+
transportFactory: MemoryTransportFactory
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const modelFactory = createDefaultModelFactory();
|
|
54
|
+
return new ServiceContext(storage, networkManager, modelFactory);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const createPeers = async (numPeers: number) => {
|
|
58
|
+
const signalContext = new MemorySignalManagerContext();
|
|
59
|
+
|
|
60
|
+
return await Promise.all(
|
|
61
|
+
Array.from(Array(numPeers)).map(async () => {
|
|
62
|
+
const peer = createServiceContext({ signalContext });
|
|
63
|
+
await peer.open();
|
|
64
|
+
return peer;
|
|
65
|
+
})
|
|
66
|
+
);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const createIdentity = async (peer: ServiceContext) => {
|
|
70
|
+
await peer.createIdentity();
|
|
71
|
+
return peer;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// TODO(burdon): Remove @dxos/client-testing.
|
|
75
|
+
// TODO(burdon): Create builder and make configurable.
|
|
76
|
+
export const syncItemsLocal = async (db1: DataPipelineControllerImpl, db2: DataPipelineControllerImpl) => {
|
|
77
|
+
await testLocalDatabase(db1, db2);
|
|
78
|
+
await testLocalDatabase(db2, db1);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export class HostTestBuilder {
|
|
82
|
+
public readonly signalContext = new MemorySignalManagerContext();
|
|
83
|
+
|
|
84
|
+
createPeer(): TestPeer {
|
|
85
|
+
return new TestPeer(this.signalContext);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export type TestPeerProps = {
|
|
90
|
+
storage?: Storage;
|
|
91
|
+
feedStore?: FeedStore<any>;
|
|
92
|
+
metadataStore?: MetadataStore;
|
|
93
|
+
keyring?: Keyring;
|
|
94
|
+
networkManager?: NetworkManager;
|
|
95
|
+
spaceManager?: SpaceManager;
|
|
96
|
+
snapshotStore?: SnapshotStore;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export class TestPeer {
|
|
100
|
+
private _props: TestPeerProps = {};
|
|
101
|
+
|
|
102
|
+
constructor(private readonly signalContext: MemorySignalManagerContext) {}
|
|
103
|
+
|
|
104
|
+
get storage() {
|
|
105
|
+
return (this._props.storage ??= createStorage({ type: StorageType.RAM }));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
get keyring() {
|
|
109
|
+
return (this._props.keyring ??= new Keyring(this.storage.createDirectory('keyring')));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
get feedStore() {
|
|
113
|
+
return (this._props.feedStore ??= new FeedStore({
|
|
114
|
+
factory: new FeedFactory({
|
|
115
|
+
root: this.storage.createDirectory('feeds'),
|
|
116
|
+
signer: this.keyring,
|
|
117
|
+
hypercore: {
|
|
118
|
+
valueEncoding
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
get metadataStore() {
|
|
125
|
+
return (this._props.metadataStore ??= new MetadataStore(this.storage.createDirectory('metadata')));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
get snapshotStore() {
|
|
129
|
+
return (this._props.snapshotStore ??= new SnapshotStore(this.storage.createDirectory('snapshots')));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
get networkManager() {
|
|
133
|
+
return (this._props.networkManager ??= new NetworkManager({
|
|
134
|
+
signalManager: new MemorySignalManager(this.signalContext),
|
|
135
|
+
transportFactory: MemoryTransportFactory
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
get spaceManager() {
|
|
140
|
+
return (this._props.spaceManager ??= new SpaceManager({
|
|
141
|
+
feedStore: this.feedStore,
|
|
142
|
+
networkManager: this.networkManager
|
|
143
|
+
}));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export const createSigningContext = async (keyring: Keyring): Promise<SigningContext> => {
|
|
148
|
+
const identityKey = await keyring.createKey();
|
|
149
|
+
const deviceKey = await keyring.createKey();
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
identityKey,
|
|
153
|
+
deviceKey,
|
|
154
|
+
credentialSigner: createCredentialSignerWithChain(
|
|
155
|
+
keyring,
|
|
156
|
+
{
|
|
157
|
+
credential: await new CredentialGenerator(keyring, identityKey, deviceKey).createDeviceAuthorization(deviceKey)
|
|
158
|
+
},
|
|
159
|
+
deviceKey
|
|
160
|
+
),
|
|
161
|
+
recordCredential: async () => {} // No-op.
|
|
162
|
+
};
|
|
163
|
+
};
|
|
@@ -5,11 +5,10 @@
|
|
|
5
5
|
import assert from 'node:assert';
|
|
6
6
|
|
|
7
7
|
import { Trigger } from '@dxos/async';
|
|
8
|
+
import { InvitationsHandler } from '@dxos/client';
|
|
8
9
|
import { raise } from '@dxos/debug';
|
|
9
10
|
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
10
11
|
|
|
11
|
-
import { InvitationsHandler } from '../invitations';
|
|
12
|
-
|
|
13
12
|
export const performInvitation = async <T>(host: InvitationsHandler<T>, guest: InvitationsHandler<T>, context: T) => {
|
|
14
13
|
const done1 = new Trigger<Invitation>(); // peer 1 connected.
|
|
15
14
|
const done2 = new Trigger<Invitation>(); // peer 2 connected.
|
|
@@ -1,162 +1,140 @@
|
|
|
1
1
|
//
|
|
2
|
-
// Copyright
|
|
2
|
+
// Copyright 2020 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import { createCredentialSignerWithChain, CredentialGenerator } from '@dxos/credentials';
|
|
7
|
-
import {
|
|
8
|
-
SnapshotStore,
|
|
9
|
-
DataPipelineControllerImpl,
|
|
10
|
-
MetadataStore,
|
|
11
|
-
SigningContext,
|
|
12
|
-
SpaceManager,
|
|
13
|
-
valueEncoding
|
|
14
|
-
} from '@dxos/echo-pipeline';
|
|
15
|
-
import { testLocalDatabase } from '@dxos/echo-pipeline/testing';
|
|
16
|
-
import { FeedFactory, FeedStore } from '@dxos/feed-store';
|
|
17
|
-
import { Keyring } from '@dxos/keyring';
|
|
18
|
-
import { MemorySignalManager, MemorySignalManagerContext } from '@dxos/messaging';
|
|
19
|
-
import { MemoryTransportFactory, NetworkManager } from '@dxos/network-manager';
|
|
20
|
-
import { createStorage, Storage, StorageType } from '@dxos/random-access-storage';
|
|
21
|
-
|
|
22
|
-
import { createDefaultModelFactory, ClientServicesHost, ServiceContext } from '../services';
|
|
23
|
-
|
|
24
|
-
//
|
|
25
|
-
// TODO(burdon): Replace with test builder.
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
export const createServiceHost = (config: Config, signalManagerContext: MemorySignalManagerContext) => {
|
|
29
|
-
const networkManager = new NetworkManager({
|
|
30
|
-
signalManager: new MemorySignalManager(signalManagerContext),
|
|
31
|
-
transportFactory: MemoryTransportFactory
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
return new ClientServicesHost({
|
|
35
|
-
config,
|
|
36
|
-
networkManager
|
|
37
|
-
});
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export const createServiceContext = ({
|
|
41
|
-
signalContext = new MemorySignalManagerContext(),
|
|
42
|
-
storage = createStorage({ type: StorageType.RAM })
|
|
43
|
-
}: {
|
|
44
|
-
signalContext?: MemorySignalManagerContext;
|
|
45
|
-
storage?: Storage;
|
|
46
|
-
} = {}) => {
|
|
47
|
-
const networkManager = new NetworkManager({
|
|
48
|
-
signalManager: new MemorySignalManager(signalContext),
|
|
49
|
-
transportFactory: MemoryTransportFactory
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const modelFactory = createDefaultModelFactory();
|
|
53
|
-
return new ServiceContext(storage, networkManager, modelFactory);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
export const createPeers = async (numPeers: number) => {
|
|
57
|
-
const signalContext = new MemorySignalManagerContext();
|
|
58
|
-
|
|
59
|
-
return await Promise.all(
|
|
60
|
-
Array.from(Array(numPeers)).map(async () => {
|
|
61
|
-
const peer = createServiceContext({ signalContext });
|
|
62
|
-
await peer.open();
|
|
63
|
-
return peer;
|
|
64
|
-
})
|
|
65
|
-
);
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
export const createIdentity = async (peer: ServiceContext) => {
|
|
69
|
-
await peer.createIdentity();
|
|
70
|
-
return peer;
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
// TODO(burdon): Remove @dxos/client-testing.
|
|
74
|
-
// TODO(burdon): Create builder and make configurable.
|
|
75
|
-
export const syncItems = async (db1: DataPipelineControllerImpl, db2: DataPipelineControllerImpl) => {
|
|
76
|
-
await testLocalDatabase(db1, db2);
|
|
77
|
-
await testLocalDatabase(db2, db1);
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
export class TestBuilder {
|
|
81
|
-
public readonly signalContext = new MemorySignalManagerContext();
|
|
5
|
+
import assert from 'node:assert';
|
|
82
6
|
|
|
83
|
-
|
|
84
|
-
|
|
7
|
+
import { asyncTimeout } from '@dxos/async';
|
|
8
|
+
import { Client, ClientServices, ClientServicesProxy, createDefaultModelFactory } from '@dxos/client';
|
|
9
|
+
import { Config } from '@dxos/config';
|
|
10
|
+
import { DocumentModel } from '@dxos/document-model';
|
|
11
|
+
import { DatabaseBackendProxy, genesisMutation } from '@dxos/echo-db';
|
|
12
|
+
import { PublicKey } from '@dxos/keys';
|
|
13
|
+
import { MemorySignalManager, MemorySignalManagerContext, WebsocketSignalManager } from '@dxos/messaging';
|
|
14
|
+
import { createWebRTCTransportFactory, MemoryTransportFactory, NetworkManager } from '@dxos/network-manager';
|
|
15
|
+
import { Storage } from '@dxos/random-access-storage';
|
|
16
|
+
import { createLinkedPorts, createProtoRpcPeer, ProtoRpcPeer } from '@dxos/rpc';
|
|
17
|
+
|
|
18
|
+
import { ClientServicesHost, LocalClientServices } from '../services';
|
|
19
|
+
|
|
20
|
+
export const testConfigWithLocalSignal = new Config({
|
|
21
|
+
version: 1,
|
|
22
|
+
runtime: {
|
|
23
|
+
services: {
|
|
24
|
+
signal: {
|
|
25
|
+
// TODO(burdon): Port numbers and global consts?
|
|
26
|
+
server: 'ws://localhost:4000/.well-known/dx/signal'
|
|
27
|
+
}
|
|
28
|
+
}
|
|
85
29
|
}
|
|
86
|
-
}
|
|
30
|
+
});
|
|
87
31
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
networkManager?: NetworkManager;
|
|
94
|
-
spaceManager?: SpaceManager;
|
|
95
|
-
snapshotStore?: SnapshotStore;
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
export class TestPeer {
|
|
99
|
-
private _props: TestPeerProps = {};
|
|
32
|
+
/**
|
|
33
|
+
* Client builder supports different configurations, incl. signaling, transports, storage.
|
|
34
|
+
*/
|
|
35
|
+
export class TestBuilder {
|
|
36
|
+
private readonly _config: Config;
|
|
100
37
|
|
|
101
|
-
|
|
38
|
+
public storage?: Storage;
|
|
102
39
|
|
|
103
|
-
|
|
104
|
-
|
|
40
|
+
// prettier-ignore
|
|
41
|
+
constructor (
|
|
42
|
+
config?: Config,
|
|
43
|
+
private readonly _modelFactory = createDefaultModelFactory(),
|
|
44
|
+
private readonly _signalManagerContext = new MemorySignalManagerContext()
|
|
45
|
+
) {
|
|
46
|
+
this._config = config ?? new Config();
|
|
105
47
|
}
|
|
106
48
|
|
|
107
|
-
get
|
|
108
|
-
return
|
|
49
|
+
get config(): Config {
|
|
50
|
+
return this._config;
|
|
109
51
|
}
|
|
110
52
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Get network manager using local shared memory or remote signal manager.
|
|
55
|
+
*/
|
|
56
|
+
get networkManager() {
|
|
57
|
+
const signalServer = this._config.get('runtime.services.signal.server');
|
|
58
|
+
if (signalServer) {
|
|
59
|
+
return new NetworkManager({
|
|
60
|
+
log: true,
|
|
61
|
+
signalManager: new WebsocketSignalManager([signalServer]),
|
|
62
|
+
transportFactory: createWebRTCTransportFactory({
|
|
63
|
+
iceServers: this._config.get('runtime.services.ice')
|
|
64
|
+
})
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Memory transport with shared context.
|
|
69
|
+
return new NetworkManager({
|
|
70
|
+
log: true,
|
|
71
|
+
signalManager: new MemorySignalManager(this._signalManagerContext),
|
|
72
|
+
transportFactory: MemoryTransportFactory
|
|
73
|
+
});
|
|
121
74
|
}
|
|
122
75
|
|
|
123
|
-
|
|
124
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Create backend service handlers.
|
|
78
|
+
*/
|
|
79
|
+
createClientServicesHost() {
|
|
80
|
+
return new ClientServicesHost({
|
|
81
|
+
config: this._config,
|
|
82
|
+
modelFactory: this._modelFactory,
|
|
83
|
+
networkManager: this.networkManager,
|
|
84
|
+
storage: this.storage
|
|
85
|
+
});
|
|
125
86
|
}
|
|
126
87
|
|
|
127
|
-
|
|
128
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Create local services host.
|
|
90
|
+
*/
|
|
91
|
+
createLocal() {
|
|
92
|
+
return new LocalClientServices({
|
|
93
|
+
config: this._config,
|
|
94
|
+
modelFactory: this._modelFactory,
|
|
95
|
+
networkManager: this.networkManager,
|
|
96
|
+
storage: this.storage
|
|
97
|
+
});
|
|
129
98
|
}
|
|
130
99
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Create client/server.
|
|
102
|
+
*/
|
|
103
|
+
createClientServer(host: ClientServicesHost = this.createClientServicesHost()): [Client, ProtoRpcPeer<{}>] {
|
|
104
|
+
const [proxyPort, hostPort] = createLinkedPorts();
|
|
105
|
+
const server = createProtoRpcPeer({
|
|
106
|
+
exposed: host.descriptors,
|
|
107
|
+
handlers: host.services as ClientServices,
|
|
108
|
+
port: hostPort
|
|
109
|
+
});
|
|
110
|
+
// TODO(dmaretskyi): Refactor.
|
|
111
|
+
|
|
112
|
+
const client = new Client({ services: new ClientServicesProxy(proxyPort) });
|
|
113
|
+
return [client, server];
|
|
143
114
|
}
|
|
144
115
|
}
|
|
145
116
|
|
|
146
|
-
export const
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
117
|
+
export const testSpace = async (create: DatabaseBackendProxy, check: DatabaseBackendProxy = create) => {
|
|
118
|
+
const objectId = PublicKey.random().toHex();
|
|
119
|
+
|
|
120
|
+
const result = create.mutate(genesisMutation(objectId, DocumentModel.meta.type));
|
|
121
|
+
|
|
122
|
+
await result.getReceipt();
|
|
123
|
+
// TODO(dmaretskiy): await result.waitToBeProcessed()
|
|
124
|
+
assert(create._itemManager.entities.has(result.objectsCreated[0].id));
|
|
125
|
+
|
|
126
|
+
await asyncTimeout(
|
|
127
|
+
check._itemManager.update.waitForCondition(() => check._itemManager.entities.has(objectId)),
|
|
128
|
+
1000
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
return result;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export const syncItems = async (db1: DatabaseBackendProxy, db2: DatabaseBackendProxy) => {
|
|
135
|
+
// Check item replicated from 1 => 2.
|
|
136
|
+
await testSpace(db1, db2);
|
|
137
|
+
|
|
138
|
+
// Check item replicated from 2 => 1.
|
|
139
|
+
await testSpace(db2, db1);
|
|
162
140
|
};
|