@dxos/client-services 0.4.9 → 0.4.10-main.06ef97a
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-RQ33OGAG.mjs → chunk-XCFXYSCO.mjs} +788 -531
- package/dist/lib/browser/chunk-XCFXYSCO.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +58 -20
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/packlets/testing/index.mjs +6 -4
- package/dist/lib/browser/packlets/testing/index.mjs.map +3 -3
- package/dist/lib/node/{chunk-CBSM4HU4.cjs → chunk-ENGA4MHO.cjs} +726 -556
- package/dist/lib/node/chunk-ENGA4MHO.cjs.map +7 -0
- package/dist/lib/node/index.cjs +95 -57
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/packlets/testing/index.cjs +10 -8
- package/dist/lib/node/packlets/testing/index.cjs.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/diagnostics/browser-diagnostics-broadcast.d.ts +5 -0
- package/dist/types/src/packlets/diagnostics/browser-diagnostics-broadcast.d.ts.map +1 -0
- package/dist/types/src/packlets/diagnostics/diagnostics-broadcast.d.ts +5 -0
- package/dist/types/src/packlets/diagnostics/diagnostics-broadcast.d.ts.map +1 -0
- package/dist/types/src/packlets/diagnostics/diagnostics-collector.d.ts +15 -0
- package/dist/types/src/packlets/diagnostics/diagnostics-collector.d.ts.map +1 -0
- package/dist/types/src/packlets/{services → diagnostics}/diagnostics.d.ts +1 -1
- package/dist/types/src/packlets/diagnostics/diagnostics.d.ts.map +1 -0
- package/dist/types/src/packlets/diagnostics/index.d.ts +4 -0
- package/dist/types/src/packlets/diagnostics/index.d.ts.map +1 -0
- package/dist/types/src/packlets/indexing/util.d.ts +2 -2
- package/dist/types/src/packlets/indexing/util.d.ts.map +1 -1
- package/dist/types/src/packlets/services/index.d.ts +1 -1
- package/dist/types/src/packlets/services/index.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts +7 -5
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +2 -0
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/services/util.d.ts +1 -0
- package/dist/types/src/packlets/services/util.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/storage/index.d.ts +1 -0
- package/dist/types/src/packlets/storage/index.d.ts.map +1 -1
- package/dist/types/src/packlets/storage/level.d.ts +4 -0
- package/dist/types/src/packlets/storage/level.d.ts.map +1 -0
- package/dist/types/src/packlets/storage/storage.d.ts.map +1 -1
- package/dist/types/src/packlets/storage/util.d.ts +4 -0
- package/dist/types/src/packlets/storage/util.d.ts.map +1 -0
- package/dist/types/src/packlets/system/system-service.d.ts +1 -1
- package/dist/types/src/packlets/system/system-service.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts +1 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/shared-worker-connection.d.ts +5 -5
- package/dist/types/src/packlets/vault/shared-worker-connection.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/worker-runtime.d.ts +2 -0
- package/dist/types/src/packlets/vault/worker-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/worker-session.d.ts +2 -0
- package/dist/types/src/packlets/vault/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/package.json +36 -34
- package/src/index.ts +1 -0
- package/src/packlets/devices/devices-service.test.ts +1 -1
- package/src/packlets/diagnostics/browser-diagnostics-broadcast.ts +94 -0
- package/src/packlets/diagnostics/diagnostics-broadcast.ts +20 -0
- package/src/packlets/diagnostics/diagnostics-collector.ts +65 -0
- package/src/packlets/{services → diagnostics}/diagnostics.ts +2 -2
- package/src/packlets/diagnostics/index.ts +7 -0
- package/src/packlets/identity/identity-service.test.ts +1 -1
- package/src/packlets/indexing/util.ts +4 -4
- package/src/packlets/invitations/device-invitation-protocol.test.ts +1 -1
- package/src/packlets/network/network-service.test.ts +1 -1
- package/src/packlets/services/index.ts +1 -1
- package/src/packlets/services/service-context.test.ts +5 -5
- package/src/packlets/services/service-context.ts +13 -8
- package/src/packlets/services/service-host.ts +41 -9
- package/src/packlets/services/service-registry.test.ts +1 -1
- package/src/packlets/services/util.ts +2 -0
- package/src/packlets/spaces/data-space.ts +51 -2
- package/src/packlets/spaces/spaces-service.test.ts +1 -1
- package/src/packlets/storage/index.ts +1 -0
- package/src/packlets/storage/level.ts +19 -0
- package/src/packlets/storage/storage.ts +3 -9
- package/src/packlets/storage/util.ts +19 -0
- package/src/packlets/system/system-service.ts +1 -1
- package/src/packlets/testing/test-builder.ts +5 -3
- package/src/packlets/vault/shared-worker-connection.ts +3 -8
- package/src/packlets/vault/worker-runtime.ts +27 -2
- package/src/packlets/vault/worker-session.ts +6 -0
- package/src/version.ts +1 -5
- package/dist/lib/browser/chunk-RQ33OGAG.mjs.map +0 -7
- package/dist/lib/node/chunk-CBSM4HU4.cjs.map +0 -7
- package/dist/types/src/packlets/services/diagnostics.d.ts.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/client-services",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.10-main.06ef97a",
|
|
4
4
|
"description": "DXOS client services implementation",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"browser": {
|
|
11
11
|
"jsondown": false,
|
|
12
12
|
"./src/packlets/locks/node.ts": "./src/packlets/locks/browser.ts",
|
|
13
|
+
"./src/packlets/diagnostics/diagnostics-broadcast.ts": "./src/packlets/diagnostics/browser-diagnostics-broadcast.ts",
|
|
13
14
|
"./dist/lib/node/index.cjs": "./dist/lib/browser/index.mjs",
|
|
14
15
|
"./testing.js": "./dist/lib/browser/packlets/testing/index.mjs"
|
|
15
16
|
},
|
|
@@ -21,44 +22,45 @@
|
|
|
21
22
|
"src"
|
|
22
23
|
],
|
|
23
24
|
"dependencies": {
|
|
25
|
+
"level": "^8.0.1",
|
|
24
26
|
"platform": "^1.3.6",
|
|
25
|
-
"@dxos/automerge": "0.4.
|
|
26
|
-
"@dxos/
|
|
27
|
-
"@dxos/codec-protobuf": "0.4.
|
|
28
|
-
"@dxos/
|
|
29
|
-
"@dxos/config": "0.4.
|
|
30
|
-
"@dxos/credentials": "0.4.
|
|
31
|
-
"@dxos/
|
|
32
|
-
"@dxos/crypto": "0.4.
|
|
33
|
-
"@dxos/echo-db": "0.4.
|
|
34
|
-
"@dxos/
|
|
35
|
-
"@dxos/
|
|
36
|
-
"@dxos/
|
|
37
|
-
"@dxos/
|
|
38
|
-
"@dxos/
|
|
39
|
-
"@dxos/
|
|
40
|
-
"@dxos/
|
|
41
|
-
"@dxos/
|
|
42
|
-
"@dxos/
|
|
43
|
-
"@dxos/
|
|
44
|
-
"@dxos/messaging": "0.4.
|
|
45
|
-
"@dxos/
|
|
46
|
-
"@dxos/
|
|
47
|
-
"@dxos/
|
|
48
|
-
"@dxos/
|
|
49
|
-
"@dxos/rpc": "0.4.
|
|
50
|
-
"@dxos/teleport": "0.4.
|
|
51
|
-
"@dxos/teleport-extension-gossip": "0.4.
|
|
52
|
-
"@dxos/
|
|
53
|
-
"@dxos/
|
|
54
|
-
"@dxos/
|
|
55
|
-
"@dxos/
|
|
56
|
-
"@dxos/
|
|
27
|
+
"@dxos/automerge": "0.4.10-main.06ef97a",
|
|
28
|
+
"@dxos/async": "0.4.10-main.06ef97a",
|
|
29
|
+
"@dxos/codec-protobuf": "0.4.10-main.06ef97a",
|
|
30
|
+
"@dxos/client-protocol": "0.4.10-main.06ef97a",
|
|
31
|
+
"@dxos/config": "0.4.10-main.06ef97a",
|
|
32
|
+
"@dxos/credentials": "0.4.10-main.06ef97a",
|
|
33
|
+
"@dxos/context": "0.4.10-main.06ef97a",
|
|
34
|
+
"@dxos/crypto": "0.4.10-main.06ef97a",
|
|
35
|
+
"@dxos/echo-db": "0.4.10-main.06ef97a",
|
|
36
|
+
"@dxos/debug": "0.4.10-main.06ef97a",
|
|
37
|
+
"@dxos/echo-pipeline": "0.4.10-main.06ef97a",
|
|
38
|
+
"@dxos/echo-schema": "0.4.10-main.06ef97a",
|
|
39
|
+
"@dxos/feed-store": "0.4.10-main.06ef97a",
|
|
40
|
+
"@dxos/invariant": "0.4.10-main.06ef97a",
|
|
41
|
+
"@dxos/indexing": "0.4.10-main.06ef97a",
|
|
42
|
+
"@dxos/keyring": "0.4.10-main.06ef97a",
|
|
43
|
+
"@dxos/lock-file": "0.4.10-main.06ef97a",
|
|
44
|
+
"@dxos/keys": "0.4.10-main.06ef97a",
|
|
45
|
+
"@dxos/log": "0.4.10-main.06ef97a",
|
|
46
|
+
"@dxos/messaging": "0.4.10-main.06ef97a",
|
|
47
|
+
"@dxos/protocols": "0.4.10-main.06ef97a",
|
|
48
|
+
"@dxos/network-manager": "0.4.10-main.06ef97a",
|
|
49
|
+
"@dxos/random-access-storage": "0.4.10-main.06ef97a",
|
|
50
|
+
"@dxos/node-std": "0.4.10-main.06ef97a",
|
|
51
|
+
"@dxos/rpc": "0.4.10-main.06ef97a",
|
|
52
|
+
"@dxos/teleport": "0.4.10-main.06ef97a",
|
|
53
|
+
"@dxos/teleport-extension-gossip": "0.4.10-main.06ef97a",
|
|
54
|
+
"@dxos/timeframe": "0.4.10-main.06ef97a",
|
|
55
|
+
"@dxos/teleport-extension-object-sync": "0.4.10-main.06ef97a",
|
|
56
|
+
"@dxos/tracing": "0.4.10-main.06ef97a",
|
|
57
|
+
"@dxos/util": "0.4.10-main.06ef97a",
|
|
58
|
+
"@dxos/websocket-rpc": "0.4.10-main.06ef97a"
|
|
57
59
|
},
|
|
58
60
|
"devDependencies": {
|
|
59
61
|
"@types/platform": "^1.3.4",
|
|
60
62
|
"@types/readable-stream": "^2.3.9",
|
|
61
|
-
"@dxos/signal": "0.4.
|
|
63
|
+
"@dxos/signal": "0.4.10-main.06ef97a"
|
|
62
64
|
},
|
|
63
65
|
"publishConfig": {
|
|
64
66
|
"access": "public"
|
package/src/index.ts
CHANGED
|
@@ -19,7 +19,7 @@ describe('DevicesService', () => {
|
|
|
19
19
|
let devicesService: DevicesService;
|
|
20
20
|
|
|
21
21
|
beforeEach(async () => {
|
|
22
|
-
serviceContext = createServiceContext();
|
|
22
|
+
serviceContext = await createServiceContext();
|
|
23
23
|
await serviceContext.open(new Context());
|
|
24
24
|
devicesService = new DevicesServiceImpl(serviceContext.identityManager);
|
|
25
25
|
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Trigger } from '@dxos/async';
|
|
6
|
+
import { log } from '@dxos/log';
|
|
7
|
+
import { type SystemService } from '@dxos/protocols/proto/dxos/client/services';
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
type CollectDiagnosticsBroadcastSender,
|
|
11
|
+
type CollectDiagnosticsBroadcastHandler,
|
|
12
|
+
} from './diagnostics-collector';
|
|
13
|
+
|
|
14
|
+
const CHANNEL_NAME = 'dxos.diagnostics.broadcast';
|
|
15
|
+
|
|
16
|
+
enum MessageType {
|
|
17
|
+
PROBE = 'probe',
|
|
18
|
+
PROBE_ACK = 'probe-ack',
|
|
19
|
+
REQUEST_DIAGNOSTICS = 'request-diagnostics',
|
|
20
|
+
RECEIVE_DIAGNOSTICS = 'receive-diagnostics',
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface Message {
|
|
24
|
+
type: MessageType;
|
|
25
|
+
payload?: any;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const createCollectDiagnosticsBroadcastSender = (): CollectDiagnosticsBroadcastSender => {
|
|
29
|
+
return {
|
|
30
|
+
broadcastDiagnosticsRequest: async () => {
|
|
31
|
+
let expectedResponse = MessageType.PROBE_ACK;
|
|
32
|
+
let channel: BroadcastChannel | undefined;
|
|
33
|
+
try {
|
|
34
|
+
const trigger = new Trigger<Message>();
|
|
35
|
+
channel = new BroadcastChannel(CHANNEL_NAME);
|
|
36
|
+
channel.onmessage = (msg) => {
|
|
37
|
+
if (expectedResponse === msg.data.type) {
|
|
38
|
+
trigger.wake(msg.data);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
channel.postMessage({ type: MessageType.PROBE });
|
|
42
|
+
await trigger.wait({ timeout: 200 });
|
|
43
|
+
expectedResponse = MessageType.RECEIVE_DIAGNOSTICS;
|
|
44
|
+
trigger.reset();
|
|
45
|
+
channel.postMessage({ type: MessageType.REQUEST_DIAGNOSTICS });
|
|
46
|
+
const diagnostics = await trigger.wait({ timeout: 5000 });
|
|
47
|
+
return diagnostics.payload;
|
|
48
|
+
} catch (e) {
|
|
49
|
+
const errorDescription = e instanceof Error ? e.message : JSON.stringify(e);
|
|
50
|
+
return { expectedResponse, errorDescription };
|
|
51
|
+
} finally {
|
|
52
|
+
safeClose(channel);
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const createCollectDiagnosticsBroadcastHandler = (
|
|
59
|
+
systemService: SystemService,
|
|
60
|
+
): CollectDiagnosticsBroadcastHandler => {
|
|
61
|
+
let channel: BroadcastChannel | undefined;
|
|
62
|
+
return {
|
|
63
|
+
start: () => {
|
|
64
|
+
channel = new BroadcastChannel(CHANNEL_NAME);
|
|
65
|
+
channel.onmessage = async (message) => {
|
|
66
|
+
try {
|
|
67
|
+
if (message.data.type === MessageType.PROBE) {
|
|
68
|
+
channel?.postMessage({ type: MessageType.PROBE_ACK });
|
|
69
|
+
} else if (message.data.type === MessageType.REQUEST_DIAGNOSTICS) {
|
|
70
|
+
const diagnostics = await systemService.getDiagnostics({});
|
|
71
|
+
channel?.postMessage({
|
|
72
|
+
type: MessageType.RECEIVE_DIAGNOSTICS,
|
|
73
|
+
payload: diagnostics,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
} catch (error) {
|
|
77
|
+
log.catch(error);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
},
|
|
81
|
+
stop: () => {
|
|
82
|
+
safeClose(channel);
|
|
83
|
+
channel = undefined;
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const safeClose = (channel?: BroadcastChannel) => {
|
|
89
|
+
try {
|
|
90
|
+
channel?.close();
|
|
91
|
+
} catch (e) {
|
|
92
|
+
// ignored
|
|
93
|
+
}
|
|
94
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
import { type SystemService } from '@dxos/protocols/proto/dxos/client/services';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
type CollectDiagnosticsBroadcastSender,
|
|
8
|
+
type CollectDiagnosticsBroadcastHandler,
|
|
9
|
+
} from './diagnostics-collector';
|
|
10
|
+
|
|
11
|
+
export const createCollectDiagnosticsBroadcastSender = (): CollectDiagnosticsBroadcastSender => {
|
|
12
|
+
return { broadcastDiagnosticsRequest: async () => undefined };
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const createCollectDiagnosticsBroadcastHandler = (_: SystemService): CollectDiagnosticsBroadcastHandler => {
|
|
16
|
+
return {
|
|
17
|
+
start: () => {},
|
|
18
|
+
stop: () => {},
|
|
19
|
+
};
|
|
20
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type ClientServicesProvider } from '@dxos/client-protocol';
|
|
6
|
+
import { type Config, ConfigResource } from '@dxos/config';
|
|
7
|
+
import { GetDiagnosticsRequest } from '@dxos/protocols/proto/dxos/client/services';
|
|
8
|
+
import { TRACE_PROCESSOR } from '@dxos/tracing';
|
|
9
|
+
import { type JsonKeyOptions, jsonKeyReplacer, nonNullable } from '@dxos/util';
|
|
10
|
+
|
|
11
|
+
import { createCollectDiagnosticsBroadcastSender } from './diagnostics-broadcast';
|
|
12
|
+
import { ClientServicesProviderResource } from '../services';
|
|
13
|
+
|
|
14
|
+
export interface CollectDiagnosticsBroadcastSender {
|
|
15
|
+
broadcastDiagnosticsRequest(): any;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface CollectDiagnosticsBroadcastHandler {
|
|
19
|
+
start(): void;
|
|
20
|
+
stop(): void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class DiagnosticsCollector {
|
|
24
|
+
private static broadcastSender = createCollectDiagnosticsBroadcastSender();
|
|
25
|
+
|
|
26
|
+
public static async collect(
|
|
27
|
+
config: Config | Config[] = findConfigs(),
|
|
28
|
+
services: ClientServicesProvider | null = findSystemServiceProvider(),
|
|
29
|
+
options: JsonKeyOptions = {},
|
|
30
|
+
): Promise<any> {
|
|
31
|
+
const serviceDiagnostics = await services?.services?.SystemService?.getDiagnostics({
|
|
32
|
+
keys: options.humanize
|
|
33
|
+
? GetDiagnosticsRequest.KEY_OPTION.HUMANIZE
|
|
34
|
+
: options.truncate
|
|
35
|
+
? GetDiagnosticsRequest.KEY_OPTION.TRUNCATE
|
|
36
|
+
: undefined,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const clientDiagnostics = {
|
|
40
|
+
config,
|
|
41
|
+
trace: TRACE_PROCESSOR.getDiagnostics(),
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const diagnostics =
|
|
45
|
+
serviceDiagnostics != null
|
|
46
|
+
? { client: clientDiagnostics, services: serviceDiagnostics }
|
|
47
|
+
: {
|
|
48
|
+
client: clientDiagnostics,
|
|
49
|
+
broadcast: await this.broadcastSender.broadcastDiagnosticsRequest(),
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return JSON.parse(JSON.stringify(diagnostics, jsonKeyReplacer(options)));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const findSystemServiceProvider = (): ClientServicesProvider | null => {
|
|
57
|
+
const serviceProviders = TRACE_PROCESSOR.findByAnnotation(ClientServicesProviderResource);
|
|
58
|
+
const providerResource = serviceProviders.find((r) => r.instance.deref()?.services?.SystemService != null);
|
|
59
|
+
return providerResource?.instance?.deref() ?? null;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const findConfigs = (): Config[] => {
|
|
63
|
+
const configs = TRACE_PROCESSOR.findByAnnotation(ConfigResource);
|
|
64
|
+
return configs.map((r) => r.instance.deref()).filter(nonNullable);
|
|
65
|
+
};
|
|
@@ -25,9 +25,9 @@ import { type Epoch } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
|
25
25
|
import { type Resource, type Span } from '@dxos/protocols/proto/dxos/tracing';
|
|
26
26
|
import { TRACE_PROCESSOR } from '@dxos/tracing';
|
|
27
27
|
|
|
28
|
-
import { getPlatform } from './platform';
|
|
29
|
-
import { type ServiceContext } from './service-context';
|
|
30
28
|
import { DXOS_VERSION } from '../../version';
|
|
29
|
+
import { type ServiceContext } from '../services';
|
|
30
|
+
import { getPlatform } from '../services/platform';
|
|
31
31
|
import { type DataSpace } from '../spaces';
|
|
32
32
|
|
|
33
33
|
const DEFAULT_TIMEOUT = 1_000;
|
|
@@ -22,7 +22,7 @@ describe('IdentityService', () => {
|
|
|
22
22
|
let identityService: IdentityService;
|
|
23
23
|
|
|
24
24
|
beforeEach(async () => {
|
|
25
|
-
serviceContext = createServiceContext();
|
|
25
|
+
serviceContext = await createServiceContext();
|
|
26
26
|
await serviceContext.open(new Context());
|
|
27
27
|
identityService = new IdentityServiceImpl(
|
|
28
28
|
(options) => serviceContext.createIdentity(options),
|
|
@@ -12,7 +12,7 @@ import { idCodec } from '@dxos/protocols';
|
|
|
12
12
|
/**
|
|
13
13
|
* Factory for `loadDocuments` iterator.
|
|
14
14
|
*/
|
|
15
|
-
export const
|
|
15
|
+
export const createSelectedDocumentsIterator = (automergeHost: AutomergeHost) =>
|
|
16
16
|
/**
|
|
17
17
|
* Get object data blobs from Automerge Repo by ids.
|
|
18
18
|
* @param ids
|
|
@@ -25,14 +25,14 @@ export const createLoadDocuments = (automergeHost: AutomergeHost) =>
|
|
|
25
25
|
await warnAfterTimeout(5000, 'to long to load doc', () => handle.whenReady());
|
|
26
26
|
const doc = handle.docSync();
|
|
27
27
|
const hash = getHeads(doc).join('');
|
|
28
|
-
yield [{ id, object: doc.objects[objectId], currentHash: hash }];
|
|
28
|
+
yield doc.objects?.[objectId] ? [{ id, object: doc.objects[objectId], currentHash: hash }] : [];
|
|
29
29
|
}
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Factory for `getAllDocuments` iterator.
|
|
34
34
|
*/
|
|
35
|
-
export const
|
|
35
|
+
export const createDocumentsIterator = (automergeHost: AutomergeHost) =>
|
|
36
36
|
/**
|
|
37
37
|
* Recursively get all object data blobs from Automerge Repo.
|
|
38
38
|
* @param ids
|
|
@@ -57,7 +57,7 @@ export const createGetAllDocuments = (automergeHost: AutomergeHost) =>
|
|
|
57
57
|
return {
|
|
58
58
|
id: idCodec.encode({ documentId: handle.documentId, objectId }),
|
|
59
59
|
object,
|
|
60
|
-
currentHash: heads.
|
|
60
|
+
currentHash: heads.join(''),
|
|
61
61
|
};
|
|
62
62
|
});
|
|
63
63
|
}
|
|
@@ -20,7 +20,7 @@ const closeAfterTest = async (peer: ServiceContext) => {
|
|
|
20
20
|
|
|
21
21
|
describe('services/device', () => {
|
|
22
22
|
test('creates identity', async () => {
|
|
23
|
-
const peer = createServiceContext();
|
|
23
|
+
const peer = await createServiceContext();
|
|
24
24
|
await peer.open(new Context());
|
|
25
25
|
afterTest(() => peer.close());
|
|
26
26
|
|
|
@@ -18,7 +18,7 @@ describe('NetworkService', () => {
|
|
|
18
18
|
let networkService: NetworkService;
|
|
19
19
|
|
|
20
20
|
beforeEach(async () => {
|
|
21
|
-
serviceContext = createServiceContext();
|
|
21
|
+
serviceContext = await createServiceContext();
|
|
22
22
|
await serviceContext.open(new Context());
|
|
23
23
|
networkService = new NetworkServiceImpl(serviceContext.networkManager, serviceContext.signalManager);
|
|
24
24
|
});
|
|
@@ -12,10 +12,10 @@ import { performInvitation } from '../testing/invitation-utils';
|
|
|
12
12
|
describe('services/ServiceContext', () => {
|
|
13
13
|
test('new space is synchronized on device invitations', async () => {
|
|
14
14
|
const networkContext = new MemorySignalManagerContext();
|
|
15
|
-
const device1 = createServiceContext({ signalContext: networkContext });
|
|
15
|
+
const device1 = await createServiceContext({ signalContext: networkContext });
|
|
16
16
|
await device1.createIdentity();
|
|
17
17
|
|
|
18
|
-
const device2 = createServiceContext({ signalContext: networkContext });
|
|
18
|
+
const device2 = await createServiceContext({ signalContext: networkContext });
|
|
19
19
|
await Promise.all(performInvitation({ host: device1, guest: device2, options: { kind: Invitation.Kind.DEVICE } }));
|
|
20
20
|
|
|
21
21
|
const space1 = await device1.dataSpaceManager!.createSpace();
|
|
@@ -26,13 +26,13 @@ describe('services/ServiceContext', () => {
|
|
|
26
26
|
|
|
27
27
|
test('joined space is synchronized on device invitations', async () => {
|
|
28
28
|
const networkContext = new MemorySignalManagerContext();
|
|
29
|
-
const device1 = createServiceContext({ signalContext: networkContext });
|
|
29
|
+
const device1 = await createServiceContext({ signalContext: networkContext });
|
|
30
30
|
await device1.createIdentity();
|
|
31
31
|
|
|
32
|
-
const device2 = createServiceContext({ signalContext: networkContext });
|
|
32
|
+
const device2 = await createServiceContext({ signalContext: networkContext });
|
|
33
33
|
await Promise.all(performInvitation({ host: device1, guest: device2, options: { kind: Invitation.Kind.DEVICE } }));
|
|
34
34
|
|
|
35
|
-
const identity2 = createServiceContext({ signalContext: networkContext });
|
|
35
|
+
const identity2 = await createServiceContext({ signalContext: networkContext });
|
|
36
36
|
await identity2.createIdentity();
|
|
37
37
|
const space1 = await identity2.dataSpaceManager!.createSpace();
|
|
38
38
|
await Promise.all(
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { type Level } from 'level';
|
|
6
|
+
|
|
5
7
|
import { Trigger } from '@dxos/async';
|
|
6
|
-
import { Context } from '@dxos/context';
|
|
8
|
+
import { Context, Resource } from '@dxos/context';
|
|
7
9
|
import { getCredentialAssertion, type CredentialProcessor } from '@dxos/credentials';
|
|
8
10
|
import { failUndefined } from '@dxos/debug';
|
|
9
11
|
import { AutomergeHost, MetadataStore, SnapshotStore, SpaceManager, valueEncoding } from '@dxos/echo-pipeline';
|
|
@@ -30,7 +32,7 @@ import {
|
|
|
30
32
|
type IdentityManagerRuntimeParams,
|
|
31
33
|
type JoinIdentityParams,
|
|
32
34
|
} from '../identity';
|
|
33
|
-
import {
|
|
35
|
+
import { createDocumentsIterator, createSelectedDocumentsIterator } from '../indexing';
|
|
34
36
|
import {
|
|
35
37
|
DeviceInvitationProtocol,
|
|
36
38
|
InvitationsHandler,
|
|
@@ -47,7 +49,7 @@ export type ServiceContextRuntimeParams = IdentityManagerRuntimeParams & DataSpa
|
|
|
47
49
|
// TODO(dmaretskyi): Gets duplicated in CJS build between normal and testing bundles.
|
|
48
50
|
@safeInstanceof('dxos.client-services.ServiceContext')
|
|
49
51
|
@Trace.resource()
|
|
50
|
-
export class ServiceContext {
|
|
52
|
+
export class ServiceContext extends Resource {
|
|
51
53
|
public readonly initialized = new Trigger();
|
|
52
54
|
public readonly metadataStore: MetadataStore;
|
|
53
55
|
/**
|
|
@@ -78,10 +80,13 @@ export class ServiceContext {
|
|
|
78
80
|
|
|
79
81
|
constructor(
|
|
80
82
|
public readonly storage: Storage,
|
|
83
|
+
public readonly level: Level<string, string>,
|
|
81
84
|
public readonly networkManager: NetworkManager,
|
|
82
85
|
public readonly signalManager: SignalManager,
|
|
83
86
|
public readonly _runtimeParams?: IdentityManagerRuntimeParams & DataSpaceManagerRuntimeParams,
|
|
84
87
|
) {
|
|
88
|
+
super();
|
|
89
|
+
|
|
85
90
|
// TODO(burdon): Move strings to constants.
|
|
86
91
|
this.metadataStore = new MetadataStore(storage.createDirectory('metadata'));
|
|
87
92
|
this.snapshotStore = new SnapshotStore(storage.createDirectory('snapshots'));
|
|
@@ -115,7 +120,7 @@ export class ServiceContext {
|
|
|
115
120
|
this._runtimeParams as IdentityManagerRuntimeParams,
|
|
116
121
|
);
|
|
117
122
|
|
|
118
|
-
this.indexMetadata = new IndexMetadataStore({
|
|
123
|
+
this.indexMetadata = new IndexMetadataStore({ db: level.sublevel('index-metadata') });
|
|
119
124
|
|
|
120
125
|
this.automergeHost = new AutomergeHost({
|
|
121
126
|
directory: storage.createDirectory('automerge'),
|
|
@@ -125,8 +130,8 @@ export class ServiceContext {
|
|
|
125
130
|
this.indexer = new Indexer({
|
|
126
131
|
indexStore: new IndexStore({ directory: storage.createDirectory('index-store') }),
|
|
127
132
|
metadataStore: this.indexMetadata,
|
|
128
|
-
loadDocuments:
|
|
129
|
-
getAllDocuments:
|
|
133
|
+
loadDocuments: createSelectedDocumentsIterator(this.automergeHost),
|
|
134
|
+
getAllDocuments: createDocumentsIterator(this.automergeHost),
|
|
130
135
|
});
|
|
131
136
|
|
|
132
137
|
this.invitations = new InvitationsHandler(this.networkManager);
|
|
@@ -145,7 +150,7 @@ export class ServiceContext {
|
|
|
145
150
|
}
|
|
146
151
|
|
|
147
152
|
@Trace.span()
|
|
148
|
-
async
|
|
153
|
+
protected override async _open(ctx: Context) {
|
|
149
154
|
await this._checkStorageVersion();
|
|
150
155
|
|
|
151
156
|
log('opening...');
|
|
@@ -163,7 +168,7 @@ export class ServiceContext {
|
|
|
163
168
|
log('opened');
|
|
164
169
|
}
|
|
165
170
|
|
|
166
|
-
async
|
|
171
|
+
protected override async _close() {
|
|
167
172
|
log('closing...');
|
|
168
173
|
if (this._deviceSpaceSync && this.identityManager.identity) {
|
|
169
174
|
await this.identityManager.identity.space.spaceState.removeCredentialProcessor(this._deviceSpaceSync);
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
// Copyright 2021 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { type Level } from 'level';
|
|
6
|
+
|
|
5
7
|
import { Event, synchronized } from '@dxos/async';
|
|
6
|
-
import {
|
|
8
|
+
import { clientServiceBundle, defaultKey, type ClientServices, Properties } from '@dxos/client-protocol';
|
|
7
9
|
import { type Config } from '@dxos/config';
|
|
8
10
|
import { Context } from '@dxos/context';
|
|
9
|
-
import { DataServiceImpl } from '@dxos/echo-pipeline';
|
|
10
|
-
import
|
|
11
|
+
import { DataServiceImpl, type ObjectStructure, encodeReference, type SpaceDoc } from '@dxos/echo-pipeline';
|
|
12
|
+
import * as E from '@dxos/echo-schema';
|
|
11
13
|
import { IndexServiceImpl } from '@dxos/indexing';
|
|
12
14
|
import { invariant } from '@dxos/invariant';
|
|
13
15
|
import { PublicKey } from '@dxos/keys';
|
|
@@ -21,18 +23,22 @@ import { TRACE_PROCESSOR, trace as Trace } from '@dxos/tracing';
|
|
|
21
23
|
import { assignDeep } from '@dxos/util';
|
|
22
24
|
import { WebsocketRpcClient } from '@dxos/websocket-rpc';
|
|
23
25
|
|
|
24
|
-
import { createDiagnostics } from './diagnostics';
|
|
25
26
|
import { ServiceContext, type ServiceContextRuntimeParams } from './service-context';
|
|
26
27
|
import { ServiceRegistry } from './service-registry';
|
|
27
28
|
import { DevicesServiceImpl } from '../devices';
|
|
28
29
|
import { DevtoolsHostEvents, DevtoolsServiceImpl } from '../devtools';
|
|
30
|
+
import {
|
|
31
|
+
type CollectDiagnosticsBroadcastHandler,
|
|
32
|
+
createCollectDiagnosticsBroadcastHandler,
|
|
33
|
+
createDiagnostics,
|
|
34
|
+
} from '../diagnostics';
|
|
29
35
|
import { IdentityServiceImpl, type CreateIdentityOptions } from '../identity';
|
|
30
36
|
import { InvitationsServiceImpl } from '../invitations';
|
|
31
37
|
import { Lock, type ResourceLock } from '../locks';
|
|
32
38
|
import { LoggingServiceImpl } from '../logging';
|
|
33
39
|
import { NetworkServiceImpl } from '../network';
|
|
34
40
|
import { SpacesServiceImpl } from '../spaces';
|
|
35
|
-
import { createStorageObjects } from '../storage';
|
|
41
|
+
import { createLevel, createStorageObjects } from '../storage';
|
|
36
42
|
import { SystemServiceImpl } from '../system';
|
|
37
43
|
|
|
38
44
|
export type ClientServicesHostParams = {
|
|
@@ -76,11 +82,13 @@ export class ClientServicesHost {
|
|
|
76
82
|
private _signalManager?: SignalManager;
|
|
77
83
|
private _networkManager?: NetworkManager;
|
|
78
84
|
private _storage?: Storage;
|
|
85
|
+
private _level?: Level<string, string>;
|
|
79
86
|
private _callbacks?: ClientServicesHostCallbacks;
|
|
80
87
|
private _devtoolsProxy?: WebsocketRpcClient<{}, ClientServices>;
|
|
81
88
|
|
|
82
89
|
private _serviceContext!: ServiceContext;
|
|
83
90
|
private readonly _runtimeParams?: ServiceContextRuntimeParams;
|
|
91
|
+
private diagnosticsBroadcastHandler: CollectDiagnosticsBroadcastHandler;
|
|
84
92
|
|
|
85
93
|
@Trace.info()
|
|
86
94
|
private _opening = false;
|
|
@@ -138,6 +146,7 @@ export class ClientServicesHost {
|
|
|
138
146
|
},
|
|
139
147
|
});
|
|
140
148
|
|
|
149
|
+
this.diagnosticsBroadcastHandler = createCollectDiagnosticsBroadcastHandler(this._systemService);
|
|
141
150
|
this._loggingService = new LoggingServiceImpl();
|
|
142
151
|
|
|
143
152
|
this._serviceRegistry = new ServiceRegistry<ClientServices>(clientServiceBundle, {
|
|
@@ -187,6 +196,9 @@ export class ClientServicesHost {
|
|
|
187
196
|
}
|
|
188
197
|
}
|
|
189
198
|
|
|
199
|
+
if (!options.signalManager) {
|
|
200
|
+
log.warn('running signaling without telemetry metadata.');
|
|
201
|
+
}
|
|
190
202
|
const {
|
|
191
203
|
connectionLog = true,
|
|
192
204
|
transportFactory = createSimplePeerTransportFactory({
|
|
@@ -223,12 +235,17 @@ export class ClientServicesHost {
|
|
|
223
235
|
|
|
224
236
|
this._opening = true;
|
|
225
237
|
log('opening...', { lockKey: this._resourceLock?.lockKey });
|
|
238
|
+
|
|
239
|
+
if (!this._level) {
|
|
240
|
+
this._level = await createLevel(this._config.get('runtime.client.storage', {})!);
|
|
241
|
+
}
|
|
226
242
|
await this._resourceLock?.acquire();
|
|
227
243
|
|
|
228
244
|
await this._loggingService.open();
|
|
229
245
|
|
|
230
246
|
this._serviceContext = new ServiceContext(
|
|
231
247
|
this._storage,
|
|
248
|
+
this._level,
|
|
232
249
|
this._networkManager,
|
|
233
250
|
this._signalManager,
|
|
234
251
|
this._runtimeParams,
|
|
@@ -298,6 +315,7 @@ export class ClientServicesHost {
|
|
|
298
315
|
});
|
|
299
316
|
void this._devtoolsProxy.open();
|
|
300
317
|
}
|
|
318
|
+
this.diagnosticsBroadcastHandler.start();
|
|
301
319
|
|
|
302
320
|
this._opening = false;
|
|
303
321
|
this._open = true;
|
|
@@ -316,10 +334,12 @@ export class ClientServicesHost {
|
|
|
316
334
|
|
|
317
335
|
const deviceKey = this._serviceContext.identityManager.identity?.deviceKey;
|
|
318
336
|
log('closing...', { deviceKey });
|
|
337
|
+
this.diagnosticsBroadcastHandler.stop();
|
|
319
338
|
await this._devtoolsProxy?.close();
|
|
320
339
|
this._serviceRegistry.setServices({ SystemService: this._systemService });
|
|
321
340
|
await this._loggingService.close();
|
|
322
341
|
await this._serviceContext.close();
|
|
342
|
+
await this._level?.close();
|
|
323
343
|
this._open = false;
|
|
324
344
|
this._statusUpdate.emit();
|
|
325
345
|
log('closed', { deviceKey });
|
|
@@ -344,18 +364,30 @@ export class ClientServicesHost {
|
|
|
344
364
|
await this._serviceContext.initialized.wait();
|
|
345
365
|
const space = await this._serviceContext.dataSpaceManager!.createSpace();
|
|
346
366
|
|
|
347
|
-
const obj: TypedObject = new Properties(undefined);
|
|
348
|
-
obj[defaultKey] = identity.identityKey.toHex();
|
|
349
|
-
|
|
350
367
|
const automergeIndex = space.automergeSpaceState.rootUrl;
|
|
351
368
|
invariant(automergeIndex);
|
|
352
369
|
const document = await this._serviceContext.automergeHost.repo.find<SpaceDoc>(automergeIndex as any);
|
|
353
370
|
await document.whenReady();
|
|
354
371
|
|
|
372
|
+
// TODO(dmaretskyi): Better API for low-level data access.
|
|
373
|
+
const properties: ObjectStructure = {
|
|
374
|
+
system: {
|
|
375
|
+
type: encodeReference(E.getTypeReference(Properties)!),
|
|
376
|
+
},
|
|
377
|
+
data: {
|
|
378
|
+
[defaultKey]: identity.identityKey.toHex(),
|
|
379
|
+
},
|
|
380
|
+
meta: {
|
|
381
|
+
keys: [],
|
|
382
|
+
},
|
|
383
|
+
};
|
|
384
|
+
const propertiesId = PublicKey.random().toHex();
|
|
355
385
|
document.change((doc: SpaceDoc) => {
|
|
356
|
-
assignDeep(doc, ['objects',
|
|
386
|
+
assignDeep(doc, ['objects', propertiesId], properties);
|
|
357
387
|
});
|
|
358
388
|
|
|
389
|
+
await this._serviceContext.automergeHost.repo.flush();
|
|
390
|
+
|
|
359
391
|
return identity;
|
|
360
392
|
}
|
|
361
393
|
}
|
|
@@ -31,7 +31,7 @@ const serviceBundle = createServiceBundle<TestServices>({
|
|
|
31
31
|
describe('service registry', () => {
|
|
32
32
|
test('builds a service registry', async () => {
|
|
33
33
|
const remoteSource = 'https://remote.source';
|
|
34
|
-
const serviceContext = createServiceContext();
|
|
34
|
+
const serviceContext = await createServiceContext();
|
|
35
35
|
await serviceContext.open(new Context());
|
|
36
36
|
|
|
37
37
|
const serviceRegistry = new ServiceRegistry(serviceBundle, {
|