@dxos/client-services 0.1.24 → 0.1.25-next.3c6b542
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-R2FEBB66.mjs → chunk-WF53R6F7.mjs} +325 -95
- package/dist/lib/browser/chunk-WF53R6F7.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +11 -1
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/packlets/testing/index.mjs +3 -3
- package/dist/lib/browser/packlets/testing/index.mjs.map +3 -3
- package/dist/lib/node/index.cjs +350 -111
- 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 +228 -110
- package/dist/lib/node/packlets/testing/index.cjs.map +4 -4
- package/dist/types/src/packlets/identity/authenticator.d.ts +1 -1
- package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-manager.d.ts +1 -1
- package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity.d.ts +2 -2
- package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/space-invitations-handler.d.ts +1 -1
- package/dist/types/src/packlets/invitations/space-invitations-handler.d.ts.map +1 -1
- 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/spaces/data-space-manager.d.ts +1 -1
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts +1 -1
- package/dist/types/src/packlets/spaces/spaces-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/iframe-host-runtime.d.ts +11 -4
- 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 +6 -1
- package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/index.d.ts +2 -0
- package/dist/types/src/packlets/vault/index.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/services.d.ts +9 -1
- package/dist/types/src/packlets/vault/services.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/shell-controller.d.ts +24 -0
- package/dist/types/src/packlets/vault/shell-controller.d.ts.map +1 -0
- package/dist/types/src/packlets/vault/shell-runtime.d.ts +45 -0
- package/dist/types/src/packlets/vault/shell-runtime.d.ts.map +1 -0
- package/dist/types/src/packlets/vault/worker-runtime.d.ts +2 -1
- package/dist/types/src/packlets/vault/worker-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/worker-session.d.ts +4 -1
- package/dist/types/src/packlets/vault/worker-session.d.ts.map +1 -1
- package/package.json +29 -28
- package/src/packlets/devtools/spaces.ts +1 -1
- package/src/packlets/identity/authenticator.ts +1 -1
- package/src/packlets/identity/identity-manager.test.ts +1 -1
- package/src/packlets/identity/identity-manager.ts +1 -1
- package/src/packlets/identity/identity.test.ts +1 -1
- package/src/packlets/identity/identity.ts +1 -1
- package/src/packlets/invitations/space-invitations-handler.test.ts +1 -1
- package/src/packlets/invitations/space-invitations-handler.ts +1 -1
- package/src/packlets/services/service-context.ts +2 -2
- package/src/packlets/services/service-host.ts +1 -1
- package/src/packlets/spaces/data-space-manager.test.ts +1 -1
- package/src/packlets/spaces/data-space-manager.ts +4 -4
- package/src/packlets/spaces/data-space.ts +3 -3
- package/src/packlets/spaces/spaces-service.ts +1 -1
- package/src/packlets/testing/test-builder.ts +3 -3
- package/src/packlets/vault/iframe-host-runtime.ts +26 -7
- package/src/packlets/vault/iframe-proxy-runtime.ts +16 -1
- package/src/packlets/vault/index.ts +2 -0
- package/src/packlets/vault/services.ts +17 -1
- package/src/packlets/vault/shell-controller.ts +78 -0
- package/src/packlets/vault/shell-runtime.ts +133 -0
- package/src/packlets/vault/worker-runtime.ts +3 -1
- package/src/packlets/vault/worker-session.ts +29 -19
- package/dist/lib/browser/chunk-R2FEBB66.mjs.map +0 -7
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { Config } from '@dxos/config';
|
|
6
6
|
import { raise } from '@dxos/debug';
|
|
7
7
|
import { DocumentModel } from '@dxos/document-model';
|
|
8
|
-
import { DataServiceImpl } from '@dxos/echo-
|
|
8
|
+
import { DataServiceImpl } from '@dxos/echo-pipeline';
|
|
9
9
|
import { log } from '@dxos/log';
|
|
10
10
|
import { ModelFactory } from '@dxos/model-factory';
|
|
11
11
|
import { NetworkManager } from '@dxos/network-manager';
|
|
@@ -6,7 +6,7 @@ import { expect } from 'chai';
|
|
|
6
6
|
|
|
7
7
|
import { createAdmissionCredentials } from '@dxos/credentials';
|
|
8
8
|
import { DocumentModel } from '@dxos/document-model';
|
|
9
|
-
import { AuthStatus, DataServiceSubscriptions } from '@dxos/echo-
|
|
9
|
+
import { AuthStatus, DataServiceSubscriptions } from '@dxos/echo-pipeline';
|
|
10
10
|
import { writeMessages } from '@dxos/feed-store';
|
|
11
11
|
import { log } from '@dxos/log';
|
|
12
12
|
import { ModelFactory } from '@dxos/model-factory';
|
|
@@ -8,15 +8,15 @@ import { Event, synchronized, trackLeaks } from '@dxos/async';
|
|
|
8
8
|
import { Context } from '@dxos/context';
|
|
9
9
|
import { getCredentialAssertion } from '@dxos/credentials';
|
|
10
10
|
import {
|
|
11
|
-
DataServiceSubscriptions,
|
|
12
11
|
MetadataStore,
|
|
13
12
|
SigningContext,
|
|
14
|
-
SnapshotStore,
|
|
15
13
|
Space,
|
|
16
14
|
spaceGenesis,
|
|
17
15
|
SpaceManager,
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
DataServiceSubscriptions,
|
|
17
|
+
SnapshotManager,
|
|
18
|
+
SnapshotStore
|
|
19
|
+
} from '@dxos/echo-pipeline';
|
|
20
20
|
import { FeedStore } from '@dxos/feed-store';
|
|
21
21
|
import { Keyring } from '@dxos/keyring';
|
|
22
22
|
import { PublicKey } from '@dxos/keys';
|
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
DataPipelineControllerImpl,
|
|
11
11
|
MetadataStore,
|
|
12
12
|
Space,
|
|
13
|
-
SnapshotManager,
|
|
14
13
|
SigningContext,
|
|
15
|
-
createMappedFeedWriter
|
|
16
|
-
|
|
14
|
+
createMappedFeedWriter,
|
|
15
|
+
SnapshotManager
|
|
16
|
+
} from '@dxos/echo-pipeline';
|
|
17
17
|
import { FeedStore } from '@dxos/feed-store';
|
|
18
18
|
import { Keyring } from '@dxos/keyring';
|
|
19
19
|
import { PublicKey } from '@dxos/keys';
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { scheduleTask } from '@dxos/async';
|
|
6
6
|
import { Stream } from '@dxos/codec-protobuf';
|
|
7
7
|
import { raise } from '@dxos/debug';
|
|
8
|
-
import { SpaceManager, SpaceNotFoundError } from '@dxos/echo-
|
|
8
|
+
import { SpaceManager, SpaceNotFoundError } from '@dxos/echo-pipeline';
|
|
9
9
|
import {
|
|
10
10
|
QueryCredentialsRequest,
|
|
11
11
|
QueryMembersRequest,
|
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
import { Config } from '@dxos/config';
|
|
6
6
|
import { createCredentialSignerWithChain, CredentialGenerator } from '@dxos/credentials';
|
|
7
7
|
import {
|
|
8
|
+
SnapshotStore,
|
|
8
9
|
DataPipelineControllerImpl,
|
|
9
10
|
MetadataStore,
|
|
10
11
|
SigningContext,
|
|
11
|
-
SnapshotStore,
|
|
12
12
|
SpaceManager,
|
|
13
13
|
valueEncoding
|
|
14
|
-
} from '@dxos/echo-
|
|
15
|
-
import { testLocalDatabase } from '@dxos/echo-
|
|
14
|
+
} from '@dxos/echo-pipeline';
|
|
15
|
+
import { testLocalDatabase } from '@dxos/echo-pipeline/testing';
|
|
16
16
|
import { FeedFactory, FeedStore } from '@dxos/feed-store';
|
|
17
17
|
import { Keyring } from '@dxos/keyring';
|
|
18
18
|
import { MemorySignalManager, MemorySignalManagerContext } from '@dxos/messaging';
|
|
@@ -8,15 +8,17 @@ import { log, logInfo } from '@dxos/log';
|
|
|
8
8
|
import { MemorySignalManager, MemorySignalManagerContext, WebsocketSignalManager } from '@dxos/messaging';
|
|
9
9
|
import { createWebRTCTransportFactory, NetworkManager } from '@dxos/network-manager';
|
|
10
10
|
import { createProtoRpcPeer, ProtoRpcPeer, RpcPort } from '@dxos/rpc';
|
|
11
|
-
import {
|
|
11
|
+
import { getAsyncValue, Provider } from '@dxos/util';
|
|
12
12
|
|
|
13
13
|
import { clientServiceBundle, ClientServices, ClientServicesHost } from '../services';
|
|
14
|
+
import { ShellRuntime, ShellRuntimeImpl } from './shell-runtime';
|
|
14
15
|
|
|
15
16
|
const LOCK_KEY = 'DXOS_RESOURCE_LOCK';
|
|
16
17
|
|
|
17
18
|
export type IFrameHostRuntimeParams = {
|
|
18
|
-
configProvider:
|
|
19
|
+
configProvider: Config | Provider<Promise<Config>>;
|
|
19
20
|
appPort: RpcPort;
|
|
21
|
+
shellPort?: RpcPort;
|
|
20
22
|
};
|
|
21
23
|
|
|
22
24
|
/**
|
|
@@ -26,7 +28,7 @@ export type IFrameHostRuntimeParams = {
|
|
|
26
28
|
* This should only be used when SharedWorker is not available.
|
|
27
29
|
*/
|
|
28
30
|
export class IFrameHostRuntime {
|
|
29
|
-
private readonly _configProvider:
|
|
31
|
+
private readonly _configProvider: Config | Provider<Promise<Config>>;
|
|
30
32
|
private readonly _transportFactory = createWebRTCTransportFactory();
|
|
31
33
|
private readonly _ready = new Trigger<Error | undefined>();
|
|
32
34
|
private readonly _getService: <Service>(
|
|
@@ -34,16 +36,20 @@ export class IFrameHostRuntime {
|
|
|
34
36
|
) => Promise<Service>;
|
|
35
37
|
|
|
36
38
|
private readonly _appPort: RpcPort;
|
|
39
|
+
private readonly _shellPort?: RpcPort;
|
|
40
|
+
private _config!: Config;
|
|
37
41
|
private _clientServices!: ClientServicesHost;
|
|
38
42
|
private _clientRpc!: ProtoRpcPeer<ClientServices>;
|
|
39
|
-
private
|
|
43
|
+
private _shellRuntime?: ShellRuntimeImpl;
|
|
40
44
|
|
|
41
45
|
@logInfo
|
|
42
46
|
public origin?: string;
|
|
43
47
|
|
|
44
|
-
constructor({ configProvider, appPort }: IFrameHostRuntimeParams) {
|
|
48
|
+
constructor({ configProvider, appPort, shellPort }: IFrameHostRuntimeParams) {
|
|
45
49
|
this._configProvider = configProvider;
|
|
46
50
|
this._appPort = appPort;
|
|
51
|
+
this._shellPort = shellPort;
|
|
52
|
+
|
|
47
53
|
this._getService = async (find) => {
|
|
48
54
|
const error = await this._ready.wait();
|
|
49
55
|
if (error) {
|
|
@@ -57,12 +63,24 @@ export class IFrameHostRuntime {
|
|
|
57
63
|
|
|
58
64
|
return service;
|
|
59
65
|
};
|
|
66
|
+
|
|
67
|
+
if (this._shellPort) {
|
|
68
|
+
this._shellRuntime = new ShellRuntimeImpl(this._shellPort);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get services() {
|
|
73
|
+
return this._clientServices;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get shell(): ShellRuntime | undefined {
|
|
77
|
+
return this._shellRuntime;
|
|
60
78
|
}
|
|
61
79
|
|
|
62
80
|
async start() {
|
|
63
81
|
log('starting...');
|
|
64
82
|
try {
|
|
65
|
-
this._config = await this._configProvider
|
|
83
|
+
this._config = await getAsyncValue(this._configProvider);
|
|
66
84
|
const signalServer = this._config.get('runtime.services.signal.server');
|
|
67
85
|
this._clientServices = new ClientServicesHost({
|
|
68
86
|
lockKey: LOCK_KEY,
|
|
@@ -94,7 +112,7 @@ export class IFrameHostRuntime {
|
|
|
94
112
|
port: this._appPort
|
|
95
113
|
});
|
|
96
114
|
|
|
97
|
-
await Promise.all([this._clientServices.open(), this._clientRpc.open()]);
|
|
115
|
+
await Promise.all([this._clientServices.open(), this._clientRpc.open(), this._shellRuntime?.open()]);
|
|
98
116
|
this._ready.wake(undefined);
|
|
99
117
|
log('started');
|
|
100
118
|
} catch (err: any) {
|
|
@@ -107,6 +125,7 @@ export class IFrameHostRuntime {
|
|
|
107
125
|
log('stopping...');
|
|
108
126
|
await this._clientRpc.close();
|
|
109
127
|
await this._clientServices.close();
|
|
128
|
+
await this._shellRuntime?.close();
|
|
110
129
|
log('stopped');
|
|
111
130
|
}
|
|
112
131
|
}
|
|
@@ -7,12 +7,14 @@ import { BridgeService } from '@dxos/protocols/proto/dxos/mesh/bridge';
|
|
|
7
7
|
import { createProtoRpcPeer, ProtoRpcPeer, RpcPort } from '@dxos/rpc';
|
|
8
8
|
|
|
9
9
|
import { iframeServiceBundle, WorkerServiceBundle, workerServiceBundle } from './services';
|
|
10
|
+
import { ShellRuntime, ShellRuntimeImpl } from './shell-runtime';
|
|
10
11
|
|
|
11
12
|
// NOTE: Keep as RpcPorts to avoid dependency on @dxos/rpc-tunnel so we don't depend on browser-specific apis.
|
|
12
13
|
export type IFrameProxyRuntimeParams = {
|
|
13
14
|
systemPort: RpcPort;
|
|
14
15
|
workerAppPort: RpcPort;
|
|
15
16
|
windowAppPort: RpcPort;
|
|
17
|
+
shellPort?: RpcPort;
|
|
16
18
|
};
|
|
17
19
|
|
|
18
20
|
/**
|
|
@@ -22,13 +24,16 @@ export class IFrameProxyRuntime {
|
|
|
22
24
|
private readonly _systemPort: RpcPort;
|
|
23
25
|
private readonly _windowAppPort: RpcPort;
|
|
24
26
|
private readonly _workerAppPort: RpcPort;
|
|
27
|
+
private readonly _shellPort?: RpcPort;
|
|
25
28
|
private readonly _systemRpc: ProtoRpcPeer<WorkerServiceBundle>;
|
|
29
|
+
private readonly _shellRuntime?: ShellRuntimeImpl;
|
|
26
30
|
private readonly _transportService = new WebRTCTransportService();
|
|
27
31
|
|
|
28
|
-
constructor({ systemPort, workerAppPort, windowAppPort }: IFrameProxyRuntimeParams) {
|
|
32
|
+
constructor({ systemPort, workerAppPort, windowAppPort, shellPort }: IFrameProxyRuntimeParams) {
|
|
29
33
|
this._systemPort = systemPort;
|
|
30
34
|
this._windowAppPort = windowAppPort;
|
|
31
35
|
this._workerAppPort = workerAppPort;
|
|
36
|
+
this._shellPort = shellPort;
|
|
32
37
|
|
|
33
38
|
this._systemRpc = createProtoRpcPeer({
|
|
34
39
|
requested: workerServiceBundle,
|
|
@@ -47,14 +52,24 @@ export class IFrameProxyRuntime {
|
|
|
47
52
|
|
|
48
53
|
this._workerAppPort.subscribe((msg) => this._windowAppPort.send(msg));
|
|
49
54
|
this._windowAppPort.subscribe((msg) => this._workerAppPort.send(msg));
|
|
55
|
+
|
|
56
|
+
if (this._shellPort) {
|
|
57
|
+
this._shellRuntime = new ShellRuntimeImpl(this._shellPort);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get shell(): ShellRuntime | undefined {
|
|
62
|
+
return this._shellRuntime;
|
|
50
63
|
}
|
|
51
64
|
|
|
52
65
|
async open(origin: string) {
|
|
53
66
|
await this._systemRpc.open();
|
|
54
67
|
await this._systemRpc.rpc.WorkerService.start({ origin });
|
|
68
|
+
await this._shellRuntime?.open();
|
|
55
69
|
}
|
|
56
70
|
|
|
57
71
|
async close() {
|
|
72
|
+
await this._shellRuntime?.close();
|
|
58
73
|
await this._systemRpc.rpc.WorkerService.stop();
|
|
59
74
|
await this._systemRpc.close();
|
|
60
75
|
}
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
export * from './iframe-host-runtime';
|
|
6
6
|
export * from './iframe-proxy-runtime';
|
|
7
7
|
export * from './services';
|
|
8
|
+
export * from './shell-controller';
|
|
9
|
+
export * from './shell-runtime';
|
|
8
10
|
export * from './vault-resource-lock';
|
|
9
11
|
export * from './worker-runtime';
|
|
10
12
|
export * from './worker-session';
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { schema } from '@dxos/protocols';
|
|
6
|
-
import type { IframeService, WorkerService } from '@dxos/protocols/proto/dxos/iframe';
|
|
6
|
+
import type { IframeService, AppService, ShellService, WorkerService } from '@dxos/protocols/proto/dxos/iframe';
|
|
7
7
|
import type { BridgeService } from '@dxos/protocols/proto/dxos/mesh/bridge';
|
|
8
8
|
import { ServiceBundle } from '@dxos/rpc';
|
|
9
9
|
|
|
@@ -24,3 +24,19 @@ export type WorkerServiceBundle = {
|
|
|
24
24
|
export const workerServiceBundle: ServiceBundle<WorkerServiceBundle> = {
|
|
25
25
|
WorkerService: schema.getService('dxos.iframe.WorkerService')
|
|
26
26
|
};
|
|
27
|
+
|
|
28
|
+
export type AppServiceBundle = {
|
|
29
|
+
AppService: AppService;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const appServiceBundle: ServiceBundle<AppServiceBundle> = {
|
|
33
|
+
AppService: schema.getService('dxos.iframe.AppService')
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type ShellServiceBundle = {
|
|
37
|
+
ShellService: ShellService;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const shellServiceBundle: ServiceBundle<ShellServiceBundle> = {
|
|
41
|
+
ShellService: schema.getService('dxos.iframe.ShellService')
|
|
42
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Event } from '@dxos/async';
|
|
6
|
+
import { PublicKey } from '@dxos/keys';
|
|
7
|
+
import { log } from '@dxos/log';
|
|
8
|
+
import { AppContextRequest, LayoutRequest, ShellDisplay, ShellLayout } from '@dxos/protocols/proto/dxos/iframe';
|
|
9
|
+
import { createProtoRpcPeer, ProtoRpcPeer, RpcPort } from '@dxos/rpc';
|
|
10
|
+
|
|
11
|
+
import { appServiceBundle, shellServiceBundle, ShellServiceBundle } from './services';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Provide access to the shell via RPC connection.
|
|
15
|
+
*/
|
|
16
|
+
export class ShellController {
|
|
17
|
+
readonly contextUpdate = new Event<AppContextRequest>();
|
|
18
|
+
private _shellRpc?: ProtoRpcPeer<ShellServiceBundle>;
|
|
19
|
+
private _display = ShellDisplay.NONE;
|
|
20
|
+
private _spaceKey?: PublicKey;
|
|
21
|
+
private _invitationCode?: string;
|
|
22
|
+
|
|
23
|
+
constructor(private readonly _port: RpcPort) {}
|
|
24
|
+
|
|
25
|
+
get display() {
|
|
26
|
+
return this._display;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get spaceKey() {
|
|
30
|
+
return this._spaceKey;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
setSpace(key?: PublicKey) {
|
|
34
|
+
this._spaceKey = key;
|
|
35
|
+
this._emitUpdate();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async setLayout(layout: ShellLayout, options: Omit<LayoutRequest, 'layout'> = {}) {
|
|
39
|
+
log('set layout', { layout, ...options });
|
|
40
|
+
this._display = ShellDisplay.FULLSCREEN;
|
|
41
|
+
this._emitUpdate();
|
|
42
|
+
await this._shellRpc?.rpc.ShellService.setLayout({ layout, ...options });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async open() {
|
|
46
|
+
this._shellRpc = createProtoRpcPeer({
|
|
47
|
+
requested: shellServiceBundle,
|
|
48
|
+
exposed: appServiceBundle,
|
|
49
|
+
handlers: {
|
|
50
|
+
AppService: {
|
|
51
|
+
setContext: async (request) => {
|
|
52
|
+
log('set context', request);
|
|
53
|
+
this._display = request.display;
|
|
54
|
+
this._spaceKey = request.spaceKey;
|
|
55
|
+
this._invitationCode = request.invitationCode;
|
|
56
|
+
this.contextUpdate.emit(request);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
port: this._port
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
await this._shellRpc.open();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async close() {
|
|
67
|
+
await this._shellRpc?.close();
|
|
68
|
+
this._shellRpc = undefined;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private _emitUpdate() {
|
|
72
|
+
this.contextUpdate.emit({
|
|
73
|
+
display: this._display,
|
|
74
|
+
spaceKey: this._spaceKey,
|
|
75
|
+
invitationCode: this._invitationCode
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import assert from 'node:assert';
|
|
6
|
+
|
|
7
|
+
import { Event } from '@dxos/async';
|
|
8
|
+
import { PublicKey } from '@dxos/keys';
|
|
9
|
+
import { AppContextRequest, LayoutRequest, ShellLayout } from '@dxos/protocols/proto/dxos/iframe';
|
|
10
|
+
import { createProtoRpcPeer, ProtoRpcPeer, RpcPort } from '@dxos/rpc';
|
|
11
|
+
|
|
12
|
+
import { AppServiceBundle, appServiceBundle, shellServiceBundle } from './services';
|
|
13
|
+
|
|
14
|
+
export interface ShellRuntime {
|
|
15
|
+
layoutUpdate: Event<LayoutRequest>;
|
|
16
|
+
layout: ShellLayout;
|
|
17
|
+
invitationCode?: string;
|
|
18
|
+
spaceKey?: PublicKey;
|
|
19
|
+
setLayout: (layout: ShellLayout, options?: Omit<LayoutRequest, 'layout'>) => void;
|
|
20
|
+
setAppContext: (context: AppContextRequest) => Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Endpoint that handles shell services.
|
|
25
|
+
*/
|
|
26
|
+
export class ShellRuntimeImpl implements ShellRuntime {
|
|
27
|
+
readonly layoutUpdate = new Event<LayoutRequest>();
|
|
28
|
+
private _appRpc?: ProtoRpcPeer<AppServiceBundle>;
|
|
29
|
+
private _layout = ShellLayout.DEFAULT;
|
|
30
|
+
private _invitationCode?: string;
|
|
31
|
+
private _spaceKey?: PublicKey;
|
|
32
|
+
|
|
33
|
+
constructor(private readonly _port: RpcPort) {}
|
|
34
|
+
|
|
35
|
+
get layout() {
|
|
36
|
+
return this._layout;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get invitationCode() {
|
|
40
|
+
return this._invitationCode;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get spaceKey() {
|
|
44
|
+
return this._spaceKey;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
setLayout(layout: ShellLayout, options: Omit<LayoutRequest, 'layout'> = {}) {
|
|
48
|
+
this._layout = layout;
|
|
49
|
+
this._invitationCode = options.invitationCode;
|
|
50
|
+
this._spaceKey = options.spaceKey;
|
|
51
|
+
this.layoutUpdate.emit({ layout, ...options });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async setAppContext(context: AppContextRequest) {
|
|
55
|
+
assert(this._appRpc, 'runtime not open');
|
|
56
|
+
|
|
57
|
+
if (context.spaceKey) {
|
|
58
|
+
this._spaceKey = context.spaceKey;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (context.invitationCode) {
|
|
62
|
+
this._invitationCode = context.invitationCode;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
await this._appRpc.rpc.AppService.setContext({
|
|
66
|
+
...context,
|
|
67
|
+
spaceKey: this._spaceKey,
|
|
68
|
+
invitationCode: this._invitationCode
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async open() {
|
|
73
|
+
this._appRpc = createProtoRpcPeer({
|
|
74
|
+
requested: appServiceBundle,
|
|
75
|
+
exposed: shellServiceBundle,
|
|
76
|
+
handlers: {
|
|
77
|
+
ShellService: {
|
|
78
|
+
setLayout: async (request) => {
|
|
79
|
+
this._layout = request.layout;
|
|
80
|
+
this._invitationCode = request.invitationCode;
|
|
81
|
+
this._spaceKey = request.spaceKey;
|
|
82
|
+
this.layoutUpdate.emit(request);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
port: this._port
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
await this._appRpc.open();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async close() {
|
|
93
|
+
await this._appRpc?.close();
|
|
94
|
+
this._appRpc = undefined;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export class MemoryShellRuntime implements ShellRuntime {
|
|
99
|
+
readonly layoutUpdate = new Event<LayoutRequest>();
|
|
100
|
+
readonly contextUpdate = new Event<AppContextRequest>();
|
|
101
|
+
private _layout: ShellLayout;
|
|
102
|
+
private _invitationCode?: string;
|
|
103
|
+
private _spaceKey?: PublicKey;
|
|
104
|
+
|
|
105
|
+
constructor({ layout, invitationCode, spaceKey }: Partial<LayoutRequest> & Partial<AppContextRequest> = {}) {
|
|
106
|
+
this._layout = layout ?? ShellLayout.DEFAULT;
|
|
107
|
+
this._invitationCode = invitationCode;
|
|
108
|
+
this._spaceKey = spaceKey;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
get layout() {
|
|
112
|
+
return this._layout;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
get invitationCode() {
|
|
116
|
+
return this._invitationCode;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
get spaceKey() {
|
|
120
|
+
return this._spaceKey;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
setLayout(layout: ShellLayout, options: Omit<LayoutRequest, 'layout'> = {}) {
|
|
124
|
+
this._layout = layout;
|
|
125
|
+
this._invitationCode = options.invitationCode;
|
|
126
|
+
this._spaceKey = options.spaceKey;
|
|
127
|
+
this.layoutUpdate.emit({ layout, ...options });
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async setAppContext(context: AppContextRequest) {
|
|
131
|
+
this.contextUpdate.emit(context);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -17,6 +17,7 @@ import { WorkerSession } from './worker-session';
|
|
|
17
17
|
export type CreateSessionParams = {
|
|
18
18
|
appPort: RpcPort;
|
|
19
19
|
systemPort: RpcPort;
|
|
20
|
+
shellPort: RpcPort;
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
/**
|
|
@@ -70,7 +71,7 @@ export class WorkerRuntime {
|
|
|
70
71
|
/**
|
|
71
72
|
* Create a new session.
|
|
72
73
|
*/
|
|
73
|
-
async createSession({ appPort, systemPort }: CreateSessionParams) {
|
|
74
|
+
async createSession({ appPort, systemPort, shellPort }: CreateSessionParams) {
|
|
74
75
|
const session = new WorkerSession({
|
|
75
76
|
getService: async (find) => {
|
|
76
77
|
const error = await this._ready.wait();
|
|
@@ -87,6 +88,7 @@ export class WorkerRuntime {
|
|
|
87
88
|
},
|
|
88
89
|
appPort,
|
|
89
90
|
systemPort,
|
|
91
|
+
shellPort,
|
|
90
92
|
readySignal: this._ready
|
|
91
93
|
});
|
|
92
94
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import assert from 'node:assert';
|
|
6
6
|
|
|
7
|
-
import { Trigger } from '@dxos/async';
|
|
7
|
+
import { asyncTimeout, Trigger } from '@dxos/async';
|
|
8
8
|
import { log, logInfo } from '@dxos/log';
|
|
9
9
|
import { BridgeService } from '@dxos/protocols/proto/dxos/mesh/bridge';
|
|
10
10
|
import { createProtoRpcPeer, ProtoRpcPeer, RpcPort } from '@dxos/rpc';
|
|
@@ -17,6 +17,7 @@ export type WorkerSessionParams = {
|
|
|
17
17
|
getService: <Service>(find: (services: Partial<ClientServices>) => Service | undefined) => Promise<Service>;
|
|
18
18
|
systemPort: RpcPort;
|
|
19
19
|
appPort: RpcPort;
|
|
20
|
+
shellPort: RpcPort;
|
|
20
21
|
readySignal: Trigger<Error | undefined>;
|
|
21
22
|
options?: {
|
|
22
23
|
heartbeatInterval: number;
|
|
@@ -28,6 +29,7 @@ export type WorkerSessionParams = {
|
|
|
28
29
|
*/
|
|
29
30
|
export class WorkerSession {
|
|
30
31
|
private readonly _clientRpc: ProtoRpcPeer<ClientServices>;
|
|
32
|
+
private readonly _shellClientRpc: ProtoRpcPeer<ClientServices>;
|
|
31
33
|
private readonly _iframeRpc: ProtoRpcPeer<IframeServiceBundle>;
|
|
32
34
|
private readonly _startTrigger = new Trigger();
|
|
33
35
|
private readonly _getService: WorkerSessionParams['getService'];
|
|
@@ -45,6 +47,7 @@ export class WorkerSession {
|
|
|
45
47
|
getService,
|
|
46
48
|
systemPort,
|
|
47
49
|
appPort,
|
|
50
|
+
shellPort,
|
|
48
51
|
options = {
|
|
49
52
|
heartbeatInterval: 1_000
|
|
50
53
|
}
|
|
@@ -54,23 +57,22 @@ export class WorkerSession {
|
|
|
54
57
|
this._options = options;
|
|
55
58
|
this._getService = getService;
|
|
56
59
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
});
|
|
60
|
+
const handlers = {
|
|
61
|
+
DataService: async () => await this._getService((services) => services.DataService),
|
|
62
|
+
DevicesService: async () => await this._getService((services) => services.DevicesService),
|
|
63
|
+
DevtoolsHost: async () => await this._getService((services) => services.DevtoolsHost),
|
|
64
|
+
HaloInvitationsService: async () => await this._getService((services) => services.HaloInvitationsService),
|
|
65
|
+
NetworkService: async () => await this._getService((services) => services.NetworkService),
|
|
66
|
+
ProfileService: async () => await this._getService((services) => services.ProfileService),
|
|
67
|
+
SpaceInvitationsService: async () => await this._getService((services) => services.SpaceInvitationsService),
|
|
68
|
+
SpaceService: async () => await this._getService((services) => services.SpaceService),
|
|
69
|
+
SpacesService: async () => await this._getService((services) => services.SpacesService),
|
|
70
|
+
SystemService: async () => await this._getService((services) => services.SystemService),
|
|
71
|
+
TracingService: async () => await this._getService((services) => services.TracingService)
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
this._clientRpc = createProtoRpcPeer({ exposed: clientServiceBundle, handlers, port: appPort });
|
|
75
|
+
this._shellClientRpc = createProtoRpcPeer({ exposed: clientServiceBundle, handlers, port: shellPort });
|
|
74
76
|
|
|
75
77
|
this._iframeRpc = createProtoRpcPeer({
|
|
76
78
|
requested: iframeServiceBundle,
|
|
@@ -102,7 +104,7 @@ export class WorkerSession {
|
|
|
102
104
|
|
|
103
105
|
async open() {
|
|
104
106
|
log.info('opening..');
|
|
105
|
-
await Promise.all([this._clientRpc.open(), this._iframeRpc.open()]);
|
|
107
|
+
await Promise.all([this._clientRpc.open(), this._iframeRpc.open(), this._maybeOpenShell()]);
|
|
106
108
|
|
|
107
109
|
await this._startTrigger.wait({ timeout: 3_000 });
|
|
108
110
|
|
|
@@ -137,4 +139,12 @@ export class WorkerSession {
|
|
|
137
139
|
|
|
138
140
|
await Promise.all([this._clientRpc.close(), this._iframeRpc.close()]);
|
|
139
141
|
}
|
|
142
|
+
|
|
143
|
+
private async _maybeOpenShell() {
|
|
144
|
+
try {
|
|
145
|
+
await asyncTimeout(this._shellClientRpc.open(), 1_000);
|
|
146
|
+
} catch {
|
|
147
|
+
log.info('No shell connected.');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
140
150
|
}
|