@dxos/client-protocol 0.9.1-staging.ee54ba693a → 0.11.0
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/index.mjs +590 -0
- package/dist/lib/index.mjs.map +1 -0
- package/dist/lib/types.mjs +26 -0
- package/dist/lib/types.mjs.map +1 -0
- package/dist/types/src/Rpc.d.ts +41 -0
- package/dist/types/src/Rpc.d.ts.map +1 -0
- package/dist/types/src/bridge-rpc.d.ts +27 -0
- package/dist/types/src/bridge-rpc.d.ts.map +1 -0
- package/dist/types/src/config.d.ts +0 -1
- package/dist/types/src/config.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +3 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/service-rpc.d.ts +551 -0
- package/dist/types/src/service-rpc.d.ts.map +1 -0
- package/dist/types/src/service.d.ts +14 -18
- package/dist/types/src/service.d.ts.map +1 -1
- package/dist/types/src/types/SpaceProperties.d.ts +5 -11
- package/dist/types/src/types/SpaceProperties.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +19 -14
- package/src/Rpc.ts +200 -0
- package/src/bridge-rpc.ts +114 -0
- package/src/config.ts +0 -1
- package/src/index.ts +3 -1
- package/src/service-rpc.ts +439 -0
- package/src/service.ts +17 -45
- package/src/types/SpaceProperties.ts +4 -11
- package/dist/lib/browser/chunk-3SERD2CK.mjs +0 -40
- package/dist/lib/browser/chunk-3SERD2CK.mjs.map +0 -7
- package/dist/lib/browser/index.mjs +0 -233
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/types/index.mjs +0 -11
- package/dist/lib/browser/types/index.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-YDC7XBNG.mjs +0 -42
- package/dist/lib/node-esm/chunk-YDC7XBNG.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -234
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/types/index.mjs +0 -12
- package/dist/lib/node-esm/types/index.mjs.map +0 -7
- package/dist/types/src/client.d.ts +0 -2
- package/dist/types/src/client.d.ts.map +0 -1
- package/src/client.ts +0 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/client-protocol",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Core DXOS Client API.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -16,14 +16,12 @@
|
|
|
16
16
|
".": {
|
|
17
17
|
"source": "./src/index.ts",
|
|
18
18
|
"types": "./dist/types/src/index.d.ts",
|
|
19
|
-
"
|
|
20
|
-
"node": "./dist/lib/node-esm/index.mjs"
|
|
19
|
+
"import": "./dist/lib/index.mjs"
|
|
21
20
|
},
|
|
22
21
|
"./types": {
|
|
23
22
|
"source": "./src/types/index.ts",
|
|
24
23
|
"types": "./dist/types/src/types/index.d.ts",
|
|
25
|
-
"
|
|
26
|
-
"node": "./dist/lib/node-esm/types/index.mjs"
|
|
24
|
+
"import": "./dist/lib/types.mjs"
|
|
27
25
|
}
|
|
28
26
|
},
|
|
29
27
|
"types": "dist/types/src/index.d.ts",
|
|
@@ -32,17 +30,24 @@
|
|
|
32
30
|
"src"
|
|
33
31
|
],
|
|
34
32
|
"dependencies": {
|
|
33
|
+
"@effect/platform": "0.96.2",
|
|
34
|
+
"@effect/platform-browser": "0.76.0",
|
|
35
|
+
"@effect/rpc": "0.75.1",
|
|
35
36
|
"base-x": "~3.0.11",
|
|
36
37
|
"effect": "3.21.4",
|
|
37
|
-
"@dxos/
|
|
38
|
-
"@dxos/
|
|
39
|
-
"@dxos/
|
|
40
|
-
"@dxos/
|
|
41
|
-
"@dxos/
|
|
42
|
-
"@dxos/
|
|
43
|
-
"@dxos/
|
|
44
|
-
"@dxos/
|
|
45
|
-
"@dxos/
|
|
38
|
+
"@dxos/async": "0.11.0",
|
|
39
|
+
"@dxos/codec-protobuf": "0.11.0",
|
|
40
|
+
"@dxos/credentials": "0.11.0",
|
|
41
|
+
"@dxos/echo": "0.11.0",
|
|
42
|
+
"@dxos/echo-client": "0.11.0",
|
|
43
|
+
"@dxos/effect": "0.11.0",
|
|
44
|
+
"@dxos/invariant": "0.11.0",
|
|
45
|
+
"@dxos/keys": "0.11.0",
|
|
46
|
+
"@dxos/node-std": "0.11.0",
|
|
47
|
+
"@dxos/protocols": "0.11.0",
|
|
48
|
+
"@dxos/rpc": "0.11.0",
|
|
49
|
+
"@dxos/rpc-tunnel": "0.11.0",
|
|
50
|
+
"@dxos/worker-framework": "0.11.0"
|
|
46
51
|
},
|
|
47
52
|
"peerDependencies": {
|
|
48
53
|
"effect": "3.21.4"
|
package/src/Rpc.ts
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
// @import-as-namespace
|
|
6
|
+
|
|
7
|
+
import * as BrowserWorker from '@effect/platform-browser/BrowserWorker';
|
|
8
|
+
import * as BrowserWorkerRunner from '@effect/platform-browser/BrowserWorkerRunner';
|
|
9
|
+
import * as RpcClient from '@effect/rpc/RpcClient';
|
|
10
|
+
import * as RpcServer from '@effect/rpc/RpcServer';
|
|
11
|
+
import * as Effect from 'effect/Effect';
|
|
12
|
+
import * as Layer from 'effect/Layer';
|
|
13
|
+
import * as ManagedRuntime from 'effect/ManagedRuntime';
|
|
14
|
+
import type * as Scope from 'effect/Scope';
|
|
15
|
+
|
|
16
|
+
import { RpcTiming } from '@dxos/worker-framework';
|
|
17
|
+
|
|
18
|
+
export type ServeOptions = {
|
|
19
|
+
disableTracing?: boolean;
|
|
20
|
+
concurrency?: number | 'unbounded';
|
|
21
|
+
/**
|
|
22
|
+
* When enabled, stamps each outbound RPC with a `Date.now()` send time and logs queue-wait /
|
|
23
|
+
* service durations on the worker above {@link RpcTiming.Options.minLogMs} (default 100 ms).
|
|
24
|
+
*/
|
|
25
|
+
timing?: boolean | RpcTiming.Options;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// A worker RPC client runs over a single MessagePort that multiplexes every request by id, so there
|
|
29
|
+
// is no real per-connection concurrency limit. The `@effect/rpc` worker protocol backs the client
|
|
30
|
+
// with a `Pool` that holds one worker for a request's whole lifetime — including long-lived streams.
|
|
31
|
+
// The pool's default concurrency of 1 therefore lets a single open stream (e.g. a subscription) block
|
|
32
|
+
// every other call. Allow effectively-unbounded concurrent requests over the one worker instead.
|
|
33
|
+
const WORKER_CLIENT_CONCURRENCY = Number.MAX_SAFE_INTEGER;
|
|
34
|
+
|
|
35
|
+
// Merged rpc groups (e.g. ClientServicesRpcs) do not structurally satisfy RpcGroup<Rpc.Any>
|
|
36
|
+
// in @effect/rpc's type parameter; runtime dispatch accepts any RpcGroup instance.
|
|
37
|
+
const asRpcGroup = <G>(group: G): Parameters<typeof RpcClient.make>[0] => group as Parameters<typeof RpcClient.make>[0];
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Builds an effect-native RPC client over a caller-supplied {@link RpcClient.Protocol} layer.
|
|
41
|
+
* Transport-agnostic: consumers provide the Worker-platform protocol (see {@link makeClient}) or a
|
|
42
|
+
* byte protocol over a legacy transport (e.g. `@dxos/rpc`'s RpcPort layer for iframe/devtools bridges).
|
|
43
|
+
*/
|
|
44
|
+
export const makeClientOverProtocol = <G, ProtocolError, ProtocolRequirements>(
|
|
45
|
+
protocol: Layer.Layer<RpcClient.Protocol, ProtocolError, ProtocolRequirements>,
|
|
46
|
+
group: G,
|
|
47
|
+
options?: Pick<ServeOptions, 'disableTracing' | 'timing'>,
|
|
48
|
+
): Effect.Effect<unknown, never, Scope.Scope | ProtocolRequirements> =>
|
|
49
|
+
Effect.gen(function* () {
|
|
50
|
+
const timingEnabled = RpcTiming.isEnabled(options?.timing);
|
|
51
|
+
const rpcGroup = timingEnabled ? RpcTiming.applyMiddleware(asRpcGroup(group)) : asRpcGroup(group);
|
|
52
|
+
const protocolLayer = timingEnabled ? protocol.pipe(Layer.provideMerge(RpcTiming.clientLayer())) : protocol;
|
|
53
|
+
|
|
54
|
+
// Build the transport into the caller's scope (extended via `Scope.extend`) rather than
|
|
55
|
+
// `Effect.provide`-ing the layer directly: that would bind the transport's lifetime to this
|
|
56
|
+
// construction effect, tearing the worker connection down the instant the client is returned
|
|
57
|
+
// (the client is used later by the caller). `Layer.build` keeps it alive for the caller's scope.
|
|
58
|
+
const context = yield* Layer.build(protocolLayer);
|
|
59
|
+
return yield* RpcClient.make(asRpcGroup(rpcGroup), { disableTracing: options?.disableTracing ?? true }).pipe(
|
|
60
|
+
Effect.provide(context),
|
|
61
|
+
);
|
|
62
|
+
}).pipe(Effect.orDie);
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Builds an effect-native RPC client over a {@link MessagePort} using the native Worker platform
|
|
66
|
+
* protocol (structured-clone frames, transferables supported).
|
|
67
|
+
*/
|
|
68
|
+
export const makeClient = <G>(
|
|
69
|
+
port: MessagePort,
|
|
70
|
+
group: G,
|
|
71
|
+
options?: Pick<ServeOptions, 'disableTracing' | 'timing'>,
|
|
72
|
+
): Effect.Effect<unknown, never, Scope.Scope> =>
|
|
73
|
+
makeClientOverProtocol(
|
|
74
|
+
RpcClient.layerProtocolWorker({ size: 1, concurrency: WORKER_CLIENT_CONCURRENCY }).pipe(
|
|
75
|
+
Layer.provide(BrowserWorker.layerPlatform(() => port)),
|
|
76
|
+
),
|
|
77
|
+
group,
|
|
78
|
+
options,
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
export type GroupServer = {
|
|
82
|
+
open(): Promise<void>;
|
|
83
|
+
close(): Promise<void>;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Serves an {@link RpcGroup} on a {@link MessagePort} via the native Worker runner protocol.
|
|
88
|
+
*/
|
|
89
|
+
export const serve = <G, H extends Layer.Layer<never, never, never>>(
|
|
90
|
+
port: MessagePort,
|
|
91
|
+
group: G,
|
|
92
|
+
handlers: H,
|
|
93
|
+
options?: ServeOptions,
|
|
94
|
+
): GroupServer => {
|
|
95
|
+
let runtime: ManagedRuntime.ManagedRuntime<never, never> | undefined;
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
async open(): Promise<void> {
|
|
99
|
+
if (runtime) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const timingEnabled = RpcTiming.isEnabled(options?.timing);
|
|
104
|
+
const rpcGroup = timingEnabled ? RpcTiming.applyMiddleware(asRpcGroup(group)) : asRpcGroup(group);
|
|
105
|
+
// Merge the timing middleware layer into the handler layer (rather than a conditional
|
|
106
|
+
// `.pipe(...)` element) so the pipeline stays a fixed tuple.
|
|
107
|
+
const handlersLayer = timingEnabled
|
|
108
|
+
? Layer.merge(handlers, RpcTiming.serverLayer(RpcTiming.resolveOptions(options?.timing)))
|
|
109
|
+
: handlers;
|
|
110
|
+
const serverLayer = RpcServer.layer(asRpcGroup(rpcGroup), {
|
|
111
|
+
disableTracing: options?.disableTracing ?? true,
|
|
112
|
+
concurrency: options?.concurrency ?? 'unbounded',
|
|
113
|
+
}).pipe(
|
|
114
|
+
Layer.provide(handlersLayer),
|
|
115
|
+
Layer.provide(
|
|
116
|
+
RpcServer.layerProtocolWorkerRunner.pipe(Layer.provide(BrowserWorkerRunner.layerMessagePort(port))),
|
|
117
|
+
),
|
|
118
|
+
Layer.orDie,
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
const current = ManagedRuntime.make(serverLayer);
|
|
122
|
+
try {
|
|
123
|
+
await current.runPromise(Effect.void);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
// Leave the server un-opened on startup failure so a later open() can retry rather than
|
|
126
|
+
// returning early against a runtime that never started.
|
|
127
|
+
await current.dispose();
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
runtime = current;
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
async close(): Promise<void> {
|
|
134
|
+
const current = runtime;
|
|
135
|
+
runtime = undefined;
|
|
136
|
+
await current?.dispose();
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Serves an {@link RpcGroup} over a caller-supplied {@link RpcServer.Protocol} layer.
|
|
143
|
+
* Transport-agnostic counterpart to {@link makeClientOverProtocol}: consumers provide a byte
|
|
144
|
+
* protocol over a legacy transport (e.g. `@dxos/rpc`'s RpcPort layer for iframe/devtools bridges).
|
|
145
|
+
*/
|
|
146
|
+
export const serveOverProtocol = <G, H extends Layer.Layer<never, never, never>>(
|
|
147
|
+
protocol: Layer.Layer<RpcServer.Protocol>,
|
|
148
|
+
group: G,
|
|
149
|
+
handlers: H,
|
|
150
|
+
options?: ServeOptions,
|
|
151
|
+
): GroupServer => {
|
|
152
|
+
let runtime: ManagedRuntime.ManagedRuntime<never, never> | undefined;
|
|
153
|
+
// Cache the in-flight open so concurrent opens share one initialization and a close during open
|
|
154
|
+
// can await it before disposing — otherwise `runtime` is unset mid-open and a fast open/close
|
|
155
|
+
// (e.g. client restart) leaks the runtime.
|
|
156
|
+
let openPromise: Promise<void> | undefined;
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
async open(): Promise<void> {
|
|
160
|
+
if (openPromise) {
|
|
161
|
+
return openPromise;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
openPromise = (async () => {
|
|
165
|
+
const timingEnabled = RpcTiming.isEnabled(options?.timing);
|
|
166
|
+
const rpcGroup = timingEnabled ? RpcTiming.applyMiddleware(asRpcGroup(group)) : asRpcGroup(group);
|
|
167
|
+
const handlersLayer = timingEnabled
|
|
168
|
+
? Layer.merge(handlers, RpcTiming.serverLayer(RpcTiming.resolveOptions(options?.timing)))
|
|
169
|
+
: handlers;
|
|
170
|
+
const serverLayer = RpcServer.layer(asRpcGroup(rpcGroup), {
|
|
171
|
+
disableTracing: options?.disableTracing ?? true,
|
|
172
|
+
concurrency: options?.concurrency ?? 'unbounded',
|
|
173
|
+
}).pipe(Layer.provide(handlersLayer), Layer.provide(protocol), Layer.orDie);
|
|
174
|
+
|
|
175
|
+
const current = ManagedRuntime.make(serverLayer);
|
|
176
|
+
try {
|
|
177
|
+
await current.runPromise(Effect.void);
|
|
178
|
+
} catch (error) {
|
|
179
|
+
// Leave the server un-opened on startup failure so a later open() can retry.
|
|
180
|
+
openPromise = undefined;
|
|
181
|
+
await current.dispose();
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
runtime = current;
|
|
185
|
+
})();
|
|
186
|
+
return openPromise;
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
async close(): Promise<void> {
|
|
190
|
+
if (openPromise) {
|
|
191
|
+
// Wait for an in-flight open so we dispose the runtime it created rather than leaking it.
|
|
192
|
+
await openPromise.catch(() => {});
|
|
193
|
+
openPromise = undefined;
|
|
194
|
+
}
|
|
195
|
+
const current = runtime;
|
|
196
|
+
runtime = undefined;
|
|
197
|
+
await current?.dispose();
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as RpcClient from '@effect/rpc/RpcClient';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Exit from 'effect/Exit';
|
|
8
|
+
import * as Layer from 'effect/Layer';
|
|
9
|
+
import * as Runtime from 'effect/Runtime';
|
|
10
|
+
import * as Scope from 'effect/Scope';
|
|
11
|
+
|
|
12
|
+
import { type Stream as PbStream } from '@dxos/codec-protobuf/stream';
|
|
13
|
+
import { EffectEx } from '@dxos/effect';
|
|
14
|
+
import { type BridgeService as BridgeServiceRpc } from '@dxos/protocols/proto/dxos/mesh/bridge';
|
|
15
|
+
import { BridgeService } from '@dxos/protocols/rpc';
|
|
16
|
+
|
|
17
|
+
import * as Rpc from './Rpc';
|
|
18
|
+
import { pbStreamToStream, streamToPbStream } from './service-rpc';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The system channel runs the WebRTC {@link BridgeServiceRpc} in the worker→tab direction: the worker
|
|
22
|
+
* calls the tab's network stack to proxy RTC connections. It is served over its own {@link MessagePort}
|
|
23
|
+
* (the reverse of the app port) via effect-rpc, replacing the legacy protobuf duplex peer.
|
|
24
|
+
*
|
|
25
|
+
* `BridgeServiceRpc` is the proto-shaped interface (`Promise`/{@link PbStream}) that
|
|
26
|
+
* `RtcTransportService` implements and `RtcTransportProxyFactory` consumes; the helpers below adapt
|
|
27
|
+
* it to and from the effect-rpc surface.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
const toError = (cause: unknown): Error => (cause instanceof Error ? cause : new Error(String(cause)));
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Serves a proto-shaped {@link BridgeServiceRpc} (the tab's `RtcTransportService`) over a
|
|
34
|
+
* {@link MessagePort} via effect-rpc. The worker consumes it with {@link makeBridgeServiceClient}.
|
|
35
|
+
*/
|
|
36
|
+
export const serveBridgeService = (port: MessagePort, service: BridgeServiceRpc): Rpc.GroupServer => {
|
|
37
|
+
const unary =
|
|
38
|
+
<Req, Res>(method: (request: Req) => Promise<Res>) =>
|
|
39
|
+
(payload: Req) =>
|
|
40
|
+
Effect.tryPromise({ try: () => method(payload), catch: toError });
|
|
41
|
+
|
|
42
|
+
const handlers = {
|
|
43
|
+
'BridgeService.open': (payload: Parameters<BridgeServiceRpc['open']>[0]) =>
|
|
44
|
+
pbStreamToStream(() => service.open(payload)),
|
|
45
|
+
'BridgeService.sendSignal': unary((request: Parameters<BridgeServiceRpc['sendSignal']>[0]) =>
|
|
46
|
+
service.sendSignal(request),
|
|
47
|
+
),
|
|
48
|
+
'BridgeService.sendData': unary((request: Parameters<BridgeServiceRpc['sendData']>[0]) =>
|
|
49
|
+
service.sendData(request),
|
|
50
|
+
),
|
|
51
|
+
'BridgeService.close': unary((request: Parameters<BridgeServiceRpc['close']>[0]) => service.close(request)),
|
|
52
|
+
'BridgeService.getDetails': unary((request: Parameters<BridgeServiceRpc['getDetails']>[0]) =>
|
|
53
|
+
service.getDetails(request),
|
|
54
|
+
),
|
|
55
|
+
'BridgeService.getStats': unary((request: Parameters<BridgeServiceRpc['getStats']>[0]) =>
|
|
56
|
+
service.getStats(request),
|
|
57
|
+
),
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Dispatched dynamically across the group; per-method handler types cannot be expressed statically.
|
|
61
|
+
return Rpc.serve(port, BridgeService.Rpcs, BridgeService.Rpcs.toLayer(handlers as never), {
|
|
62
|
+
disableTracing: true,
|
|
63
|
+
concurrency: 'unbounded',
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Builds a proto-shaped {@link BridgeServiceRpc} backed by an effect-rpc client over a
|
|
69
|
+
* {@link MessagePort}. Used in the worker to hand `RtcTransportProxyFactory` a bridge that proxies to
|
|
70
|
+
* the tab. The returned `close` releases the transport scope.
|
|
71
|
+
*/
|
|
72
|
+
export const makeBridgeServiceClient = async (
|
|
73
|
+
port: MessagePort,
|
|
74
|
+
): Promise<{ bridgeService: BridgeServiceRpc; close: () => Promise<void> }> =>
|
|
75
|
+
bridgeServiceClientFromEffect((scope) => Rpc.makeClient(port, BridgeService.Rpcs).pipe(Scope.extend(scope)));
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Builds a proto-shaped {@link BridgeServiceRpc} over a pre-built {@link RpcClient.Protocol} (the
|
|
79
|
+
* value the tag resolves to — e.g. the worker→client protocol handed to a worker-framework session
|
|
80
|
+
* via effect context) rather than a raw {@link MessagePort}.
|
|
81
|
+
*/
|
|
82
|
+
export const makeBridgeServiceClientOverProtocol = async (
|
|
83
|
+
protocol: RpcClient.Protocol['Type'],
|
|
84
|
+
): Promise<{ bridgeService: BridgeServiceRpc; close: () => Promise<void> }> =>
|
|
85
|
+
bridgeServiceClientFromEffect((scope) =>
|
|
86
|
+
Rpc.makeClientOverProtocol(Layer.succeed(RpcClient.Protocol, protocol), BridgeService.Rpcs).pipe(
|
|
87
|
+
Scope.extend(scope),
|
|
88
|
+
),
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
/** Adapts an effect-rpc {@link BridgeService.Client} (built by the caller) to the proto-shaped surface. */
|
|
92
|
+
const bridgeServiceClientFromEffect = async (
|
|
93
|
+
makeClient: (scope: Scope.Scope) => Effect.Effect<unknown, never, never>,
|
|
94
|
+
): Promise<{ bridgeService: BridgeServiceRpc; close: () => Promise<void> }> => {
|
|
95
|
+
const scope = Effect.runSync(Scope.make());
|
|
96
|
+
const client = (await EffectEx.runPromise(makeClient(scope))) as BridgeService.Client;
|
|
97
|
+
|
|
98
|
+
const bridge = client.BridgeService;
|
|
99
|
+
const bridgeService: BridgeServiceRpc = {
|
|
100
|
+
open: (request) => streamToPbStream(Runtime.defaultRuntime, bridge.open(request)),
|
|
101
|
+
sendSignal: (request) => EffectEx.runPromise(bridge.sendSignal(request)),
|
|
102
|
+
sendData: (request) => EffectEx.runPromise(bridge.sendData(request)),
|
|
103
|
+
close: (request) => EffectEx.runPromise(bridge.close(request)),
|
|
104
|
+
getDetails: (request) => EffectEx.runPromise(bridge.getDetails(request)),
|
|
105
|
+
getStats: (request) => EffectEx.runPromise(bridge.getStats(request)),
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
bridgeService,
|
|
110
|
+
close: async () => {
|
|
111
|
+
await EffectEx.runPromise(Scope.close(scope, Exit.void));
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
};
|
package/src/config.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
// Copyright 2020 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
export * from './
|
|
5
|
+
export * from './bridge-rpc';
|
|
6
6
|
export * from './config';
|
|
7
|
+
export * as Rpc from './Rpc';
|
|
7
8
|
export type * from './echo';
|
|
8
9
|
export type * from './halo';
|
|
9
10
|
export * from './invitations';
|
|
10
11
|
export * from './service';
|
|
12
|
+
export * from './service-rpc';
|
|
11
13
|
export type * from './shell';
|
|
12
14
|
export * from './space';
|
|
13
15
|
export * from './timeouts';
|