@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.
Files changed (44) hide show
  1. package/dist/lib/index.mjs +590 -0
  2. package/dist/lib/index.mjs.map +1 -0
  3. package/dist/lib/types.mjs +26 -0
  4. package/dist/lib/types.mjs.map +1 -0
  5. package/dist/types/src/Rpc.d.ts +41 -0
  6. package/dist/types/src/Rpc.d.ts.map +1 -0
  7. package/dist/types/src/bridge-rpc.d.ts +27 -0
  8. package/dist/types/src/bridge-rpc.d.ts.map +1 -0
  9. package/dist/types/src/config.d.ts +0 -1
  10. package/dist/types/src/config.d.ts.map +1 -1
  11. package/dist/types/src/index.d.ts +3 -1
  12. package/dist/types/src/index.d.ts.map +1 -1
  13. package/dist/types/src/service-rpc.d.ts +551 -0
  14. package/dist/types/src/service-rpc.d.ts.map +1 -0
  15. package/dist/types/src/service.d.ts +14 -18
  16. package/dist/types/src/service.d.ts.map +1 -1
  17. package/dist/types/src/types/SpaceProperties.d.ts +5 -11
  18. package/dist/types/src/types/SpaceProperties.d.ts.map +1 -1
  19. package/dist/types/tsconfig.tsbuildinfo +1 -1
  20. package/package.json +19 -14
  21. package/src/Rpc.ts +200 -0
  22. package/src/bridge-rpc.ts +114 -0
  23. package/src/config.ts +0 -1
  24. package/src/index.ts +3 -1
  25. package/src/service-rpc.ts +439 -0
  26. package/src/service.ts +17 -45
  27. package/src/types/SpaceProperties.ts +4 -11
  28. package/dist/lib/browser/chunk-3SERD2CK.mjs +0 -40
  29. package/dist/lib/browser/chunk-3SERD2CK.mjs.map +0 -7
  30. package/dist/lib/browser/index.mjs +0 -233
  31. package/dist/lib/browser/index.mjs.map +0 -7
  32. package/dist/lib/browser/meta.json +0 -1
  33. package/dist/lib/browser/types/index.mjs +0 -11
  34. package/dist/lib/browser/types/index.mjs.map +0 -7
  35. package/dist/lib/node-esm/chunk-YDC7XBNG.mjs +0 -42
  36. package/dist/lib/node-esm/chunk-YDC7XBNG.mjs.map +0 -7
  37. package/dist/lib/node-esm/index.mjs +0 -234
  38. package/dist/lib/node-esm/index.mjs.map +0 -7
  39. package/dist/lib/node-esm/meta.json +0 -1
  40. package/dist/lib/node-esm/types/index.mjs +0 -12
  41. package/dist/lib/node-esm/types/index.mjs.map +0 -7
  42. package/dist/types/src/client.d.ts +0 -2
  43. package/dist/types/src/client.d.ts.map +0 -1
  44. package/src/client.ts +0 -5
@@ -0,0 +1,590 @@
1
+ import { SpaceProperties, SpacePropertiesSchema } from "./types.mjs";
2
+ import * as RpcClient from "@effect/rpc/RpcClient";
3
+ import * as Effect from "effect/Effect";
4
+ import * as Exit from "effect/Exit";
5
+ import * as Layer from "effect/Layer";
6
+ import * as Runtime from "effect/Runtime";
7
+ import * as Scope from "effect/Scope";
8
+ import { EffectEx } from "@dxos/effect";
9
+ import { BridgeService, ContactsService, DataService, DevicesService, DevtoolsHost, EdgeAgentService, FeedService, IdentityService, InvitationsService, LoggingService, NetworkService, QueryService, SpacesService, SystemService, WorkerService } from "@dxos/protocols/rpc";
10
+ import * as BrowserWorker from "@effect/platform-browser/BrowserWorker";
11
+ import * as BrowserWorkerRunner from "@effect/platform-browser/BrowserWorkerRunner";
12
+ import * as RpcServer from "@effect/rpc/RpcServer";
13
+ import * as ManagedRuntime from "effect/ManagedRuntime";
14
+ import { RpcTiming } from "@dxos/worker-framework";
15
+ import * as RpcGroup from "@effect/rpc/RpcGroup";
16
+ import * as RpcSchema from "@effect/rpc/RpcSchema";
17
+ import * as RpcTest from "@effect/rpc/RpcTest";
18
+ import * as Cause from "effect/Cause";
19
+ import * as Stream$1 from "effect/Stream";
20
+ import { Stream } from "@dxos/codec-protobuf/stream";
21
+ import { invariant } from "@dxos/invariant";
22
+ import { runServiceCall } from "@dxos/protocols";
23
+ import { layerProtocolRpcPortClient, layerProtocolRpcPortServer } from "@dxos/rpc";
24
+ import { createIFramePort } from "@dxos/rpc-tunnel";
25
+ import base from "base-x";
26
+ import { schema } from "@dxos/protocols/proto";
27
+ import { Invitation } from "@dxos/protocols/proto/dxos/client/services";
28
+ import { MulticastObservable } from "@dxos/async";
29
+ import * as Schema from "effect/Schema";
30
+ //#region \0rolldown/runtime.js
31
+ var __defProp = Object.defineProperty;
32
+ var __exportAll = (all, no_symbols) => {
33
+ let target = {};
34
+ for (var name in all) __defProp(target, name, {
35
+ get: all[name],
36
+ enumerable: true
37
+ });
38
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
39
+ return target;
40
+ };
41
+ //#endregion
42
+ //#region src/Rpc.ts
43
+ var Rpc_exports = /* @__PURE__ */ __exportAll({
44
+ makeClient: () => makeClient,
45
+ makeClientOverProtocol: () => makeClientOverProtocol,
46
+ serve: () => serve,
47
+ serveOverProtocol: () => serveOverProtocol
48
+ });
49
+ var WORKER_CLIENT_CONCURRENCY = Number.MAX_SAFE_INTEGER;
50
+ var asRpcGroup = (group) => group;
51
+ /**
52
+ * Builds an effect-native RPC client over a caller-supplied {@link RpcClient.Protocol} layer.
53
+ * Transport-agnostic: consumers provide the Worker-platform protocol (see {@link makeClient}) or a
54
+ * byte protocol over a legacy transport (e.g. `@dxos/rpc`'s RpcPort layer for iframe/devtools bridges).
55
+ */
56
+ var makeClientOverProtocol = (protocol, group, options) => Effect.gen(function* () {
57
+ const timingEnabled = RpcTiming.isEnabled(options?.timing);
58
+ const rpcGroup = timingEnabled ? RpcTiming.applyMiddleware(asRpcGroup(group)) : asRpcGroup(group);
59
+ const protocolLayer = timingEnabled ? protocol.pipe(Layer.provideMerge(RpcTiming.clientLayer())) : protocol;
60
+ const context = yield* Layer.build(protocolLayer);
61
+ return yield* RpcClient.make(asRpcGroup(rpcGroup), { disableTracing: options?.disableTracing ?? true }).pipe(Effect.provide(context));
62
+ }).pipe(Effect.orDie);
63
+ /**
64
+ * Builds an effect-native RPC client over a {@link MessagePort} using the native Worker platform
65
+ * protocol (structured-clone frames, transferables supported).
66
+ */
67
+ var makeClient = (port, group, options) => makeClientOverProtocol(RpcClient.layerProtocolWorker({
68
+ size: 1,
69
+ concurrency: WORKER_CLIENT_CONCURRENCY
70
+ }).pipe(Layer.provide(BrowserWorker.layerPlatform(() => port))), group, options);
71
+ /**
72
+ * Serves an {@link RpcGroup} on a {@link MessagePort} via the native Worker runner protocol.
73
+ */
74
+ var serve = (port, group, handlers, options) => {
75
+ let runtime;
76
+ return {
77
+ async open() {
78
+ if (runtime) return;
79
+ const timingEnabled = RpcTiming.isEnabled(options?.timing);
80
+ const rpcGroup = timingEnabled ? RpcTiming.applyMiddleware(asRpcGroup(group)) : asRpcGroup(group);
81
+ const handlersLayer = timingEnabled ? Layer.merge(handlers, RpcTiming.serverLayer(RpcTiming.resolveOptions(options?.timing))) : handlers;
82
+ const serverLayer = RpcServer.layer(asRpcGroup(rpcGroup), {
83
+ disableTracing: options?.disableTracing ?? true,
84
+ concurrency: options?.concurrency ?? "unbounded"
85
+ }).pipe(Layer.provide(handlersLayer), Layer.provide(RpcServer.layerProtocolWorkerRunner.pipe(Layer.provide(BrowserWorkerRunner.layerMessagePort(port)))), Layer.orDie);
86
+ const current = ManagedRuntime.make(serverLayer);
87
+ try {
88
+ await current.runPromise(Effect.void);
89
+ } catch (error) {
90
+ await current.dispose();
91
+ throw error;
92
+ }
93
+ runtime = current;
94
+ },
95
+ async close() {
96
+ const current = runtime;
97
+ runtime = void 0;
98
+ await current?.dispose();
99
+ }
100
+ };
101
+ };
102
+ /**
103
+ * Serves an {@link RpcGroup} over a caller-supplied {@link RpcServer.Protocol} layer.
104
+ * Transport-agnostic counterpart to {@link makeClientOverProtocol}: consumers provide a byte
105
+ * protocol over a legacy transport (e.g. `@dxos/rpc`'s RpcPort layer for iframe/devtools bridges).
106
+ */
107
+ var serveOverProtocol = (protocol, group, handlers, options) => {
108
+ let runtime;
109
+ let openPromise;
110
+ return {
111
+ async open() {
112
+ if (openPromise) return openPromise;
113
+ openPromise = (async () => {
114
+ const timingEnabled = RpcTiming.isEnabled(options?.timing);
115
+ const rpcGroup = timingEnabled ? RpcTiming.applyMiddleware(asRpcGroup(group)) : asRpcGroup(group);
116
+ const handlersLayer = timingEnabled ? Layer.merge(handlers, RpcTiming.serverLayer(RpcTiming.resolveOptions(options?.timing))) : handlers;
117
+ const serverLayer = RpcServer.layer(asRpcGroup(rpcGroup), {
118
+ disableTracing: options?.disableTracing ?? true,
119
+ concurrency: options?.concurrency ?? "unbounded"
120
+ }).pipe(Layer.provide(handlersLayer), Layer.provide(protocol), Layer.orDie);
121
+ const current = ManagedRuntime.make(serverLayer);
122
+ try {
123
+ await current.runPromise(Effect.void);
124
+ } catch (error) {
125
+ openPromise = void 0;
126
+ await current.dispose();
127
+ throw error;
128
+ }
129
+ runtime = current;
130
+ })();
131
+ return openPromise;
132
+ },
133
+ async close() {
134
+ if (openPromise) {
135
+ await openPromise.catch(() => {});
136
+ openPromise = void 0;
137
+ }
138
+ const current = runtime;
139
+ runtime = void 0;
140
+ await current?.dispose();
141
+ }
142
+ };
143
+ };
144
+ //#endregion
145
+ //#region src/config.ts
146
+ var DEFAULT_CLIENT_CHANNEL = "dxos:app";
147
+ var DEFAULT_INTERNAL_CHANNEL = "dxos:vault";
148
+ var DEFAULT_SHELL_CHANNEL = "dxos:shell";
149
+ /**
150
+ * @deprecated
151
+ */
152
+ var DEFAULT_VAULT_URL = "https://halo.dxos.org/vault.html";
153
+ /**
154
+ * @deprecated
155
+ */
156
+ var DEFAULT_PROFILE = "default";
157
+ var EXPECTED_CONFIG_VERSION = 1;
158
+ var defaultConfig = { version: 1 };
159
+ var HOME = typeof process !== "undefined" ? process?.env?.HOME ?? "" : "";
160
+ var DX_CONFIG = `${HOME}/.config/dx`;
161
+ var DX_CACHE = `${HOME}/.cache/dx`;
162
+ var DX_DATA = `${HOME}/.local/share/dx`;
163
+ var DX_STATE = `${HOME}/.local/state/dx`;
164
+ var DX_RUNTIME = "/tmp/dx/run";
165
+ var DXEnv = /* @__PURE__ */ function(DXEnv) {
166
+ DXEnv["CONFIG"] = "DX_CONFIG";
167
+ DXEnv["DEBUG"] = "DX_DEBUG";
168
+ DXEnv["NO_AGENT"] = "DX_NO_AGENT";
169
+ DXEnv["PROFILE"] = "DX_PROFILE";
170
+ return DXEnv;
171
+ }({});
172
+ (function(_DXEnv) {
173
+ function get(variable, defaultValue) {
174
+ return process.env[variable] ?? defaultValue;
175
+ }
176
+ _DXEnv.get = get;
177
+ })(DXEnv || (DXEnv = {}));
178
+ var getProfilePath = (root, profile, file) => `${root}/profile/${profile}` + (file ? `/${file}` : "");
179
+ /** Path to the profile config file (profile/<name>.yml). */
180
+ var getProfileConfigPath = (root, profile) => `${getProfilePath(root, profile)}.yml`;
181
+ //#endregion
182
+ //#region src/service-rpc.ts
183
+ var __dxlog_file$1 = "/__w/dxos/dxos/packages/sdk/client-protocol/src/service-rpc.ts";
184
+ /**
185
+ * All client service RPCs served over a single connection.
186
+ * Rpc tags are prefixed with the {@link ClientServices} key (e.g. `DataService.subscribe`).
187
+ *
188
+ * {@link WorkerService} (the tab→worker control channel: `start`/`stop`) is merged in here rather
189
+ * than served over a second port: it runs in the same tab→worker direction as the service RPCs, so
190
+ * it multiplexes over the same app {@link MessagePort}. Only the reverse-direction `BridgeService`
191
+ * (worker→tab) needs its own port.
192
+ */
193
+ var ClientServicesRpcs = class extends RpcGroup.make().merge(SystemService.Rpcs, NetworkService.Rpcs, LoggingService.Rpcs, IdentityService.Rpcs, InvitationsService.Rpcs, DevicesService.Rpcs, SpacesService.Rpcs, DataService.Rpcs, QueryService.Rpcs, FeedService.Rpcs, ContactsService.Rpcs, EdgeAgentService.Rpcs, DevtoolsHost.Rpcs, WorkerService.Rpcs) {};
194
+ var toError$1 = (cause) => cause instanceof Error ? cause : new Error(String(cause));
195
+ var isVoidSchema = (schema) => schema.ast._tag === "VoidKeyword";
196
+ /** Splits an rpc tag into the {@link ClientServices} key and the service method name. */
197
+ var parseTag = (tag) => {
198
+ const index = tag.indexOf(".");
199
+ return [tag.slice(0, index), tag.slice(index + 1)];
200
+ };
201
+ /** Resolves a bound service method from a services provider, throwing if the service/method is absent. */
202
+ var resolveServiceMethod = (services, serviceKey, methodName, tag) => {
203
+ const service = services[serviceKey];
204
+ if (!service) throw new Error(`Service not available: ${serviceKey}`);
205
+ const method = service[methodName];
206
+ if (typeof method !== "function") throw new Error(`Method not available: ${tag}`);
207
+ return method.bind(service);
208
+ };
209
+ /**
210
+ * Serves {@link ClientServices} implementations over a {@link MessagePort} via effect-rpc.
211
+ */
212
+ var ClientRpcServer = class {
213
+ #params;
214
+ #server;
215
+ constructor(params) {
216
+ this.#params = params;
217
+ }
218
+ async open() {
219
+ if (this.#server) return;
220
+ const handlers = makeClientServicesHandlers(this.#params);
221
+ const options = {
222
+ disableTracing: true,
223
+ concurrency: "unbounded"
224
+ };
225
+ if (this.#params.protocol) this.#server = serveOverProtocol(Layer.succeed(RpcServer.Protocol, this.#params.protocol), ClientServicesRpcs, handlers, options);
226
+ else {
227
+ invariant(this.#params.port, "ClientRpcServer requires a port or a protocol.", {
228
+ "~LogMeta": "~LogMeta",
229
+ F: __dxlog_file$1,
230
+ L: 182,
231
+ S: this,
232
+ A: ["this.#params.port", "'ClientRpcServer requires a port or a protocol.'"]
233
+ });
234
+ this.#server = serve(this.#params.port, ClientServicesRpcs, handlers, options);
235
+ }
236
+ await this.#server.open();
237
+ }
238
+ async close() {
239
+ const server = this.#server;
240
+ this.#server = void 0;
241
+ await server?.close();
242
+ }
243
+ };
244
+ /**
245
+ * Serves {@link ClientServices} to a child iframe (e.g. the shell) over the effect-rpc byte protocol
246
+ * and opens the connection. The iframe uses a byte {@link RpcPort} transport (not a `MessagePort`),
247
+ * matching the shell's {@link ClientServicesProxy} consumer, so this serves over
248
+ * {@link layerProtocolRpcPortServer} rather than the Worker-runner protocol used by
249
+ * {@link ClientRpcServer}. Kept here — alongside the rpc definitions — so the `RpcPort` binding is
250
+ * resolved in this package's type universe rather than in `@dxos/client`, whose merged-with-`main`
251
+ * build resolves `ClientRpcServer.port` as a `MessagePort`.
252
+ */
253
+ var serveClientServicesOverIFrame = async ({ iframe, origin, channel = DEFAULT_CLIENT_CHANNEL, services }) => {
254
+ const server = serveOverProtocol(layerProtocolRpcPortServer(createIFramePort({
255
+ channel,
256
+ iframe,
257
+ origin
258
+ })), ClientServicesRpcs, makeClientServicesHandlers({ services }), {
259
+ disableTracing: true,
260
+ concurrency: "unbounded"
261
+ });
262
+ await server.open();
263
+ return server;
264
+ };
265
+ /**
266
+ * Builds handler layers for every client service RPC, dispatching to the service implementations
267
+ * resolved from `services` on each call.
268
+ */
269
+ var makeClientServicesHandlers = ({ services, onRequest }) => {
270
+ const gate = onRequest ? Effect.tryPromise({
271
+ try: onRequest,
272
+ catch: toError$1
273
+ }) : Effect.void;
274
+ const handlers = {};
275
+ for (const [tag, rpc] of ClientServicesRpcs.requests) {
276
+ const [serviceKey] = parseTag(tag);
277
+ const invoke = (payload) => {
278
+ const service = services()[serviceKey];
279
+ const handler = service?.[tag];
280
+ if (typeof handler !== "function") throw new Error(`Service handler not available: ${tag}`);
281
+ return handler.call(service, payload);
282
+ };
283
+ if (RpcSchema.isStreamSchema(rpc.successSchema)) handlers[tag] = (payload) => gate.pipe(Effect.map(() => invoke(payload)), Stream$1.unwrap);
284
+ else handlers[tag] = (payload) => gate.pipe(Effect.flatMap(() => invoke(payload)));
285
+ }
286
+ return ClientServicesRpcs.toLayer(handlers);
287
+ };
288
+ /**
289
+ * Builds the effect-native {@link ClientServicesRpc} over a {@link MessagePort}.
290
+ * The returned scope owns the connection; closing it releases the transport.
291
+ */
292
+ var makeClientServicesRpc = (port) => ("send" in port ? makeClientOverProtocol(layerProtocolRpcPortClient(port), ClientServicesRpcs, { disableTracing: true }) : makeClient(port, ClientServicesRpcs, { disableTracing: true })).pipe(Effect.map((client) => client));
293
+ /**
294
+ * Builds an in-process {@link ClientServicesRpc} backed directly by host {@link ClientServicesHandlers}
295
+ * (no wire hop or serialization). Used by host-internal consumers (diagnostics, devtools) that need
296
+ * the client surface without a transport.
297
+ */
298
+ var makeInProcessClientServicesRpc = (services) => RpcTest.makeClient(ClientServicesRpcs).pipe(Effect.provide(makeClientServicesHandlers({ services })));
299
+ /**
300
+ * Derives host {@link ClientServicesHandlers} from an effect-native {@link ClientServicesRpc}, so a
301
+ * client-side rpc surface can be re-served (e.g. the devtools bridge). Each handler delegates to the
302
+ * corresponding client method.
303
+ */
304
+ var makeHandlersFromRpc = (rpc) => {
305
+ const rpcRecord = rpc;
306
+ const handlers = {};
307
+ for (const [tag] of ClientServicesRpcs.requests) {
308
+ const [serviceKey, methodName] = parseTag(tag);
309
+ const service = handlers[serviceKey] ??= {};
310
+ service[tag] = (payload) => rpcRecord[serviceKey][methodName](payload);
311
+ }
312
+ return handlers;
313
+ };
314
+ /**
315
+ * Derives the Promise/{@link PbStream} shaped {@link ClientServices} from an effect-native
316
+ * {@link ClientServicesRpc}. Retained for consumers not yet migrated to the effect surface.
317
+ */
318
+ var makeServicesFromRpc = (rpc, runtime) => {
319
+ const rpcRecord = rpc;
320
+ const services = {};
321
+ for (const [tag, rpcDef] of ClientServicesRpcs.requests) {
322
+ const [serviceKey, methodName] = parseTag(tag);
323
+ const service = services[serviceKey] ??= {};
324
+ const hasPayload = !isVoidSchema(rpcDef.payloadSchema);
325
+ const invoke = (request) => rpcRecord[serviceKey][methodName](hasPayload ? request ?? {} : void 0);
326
+ if (RpcSchema.isStreamSchema(rpcDef.successSchema)) service[methodName] = (request) => streamToPbStream(runtime, invoke(request));
327
+ else service[methodName] = (request, options) => runServiceCall(runtime, invoke(request), {
328
+ timeout: options?.timeout,
329
+ label: tag
330
+ });
331
+ }
332
+ return services;
333
+ };
334
+ /**
335
+ * Builds an effect-native {@link ClientServicesRpc} from Promise/{@link PbStream} shaped
336
+ * {@link ClientServices} implementations, without a wire hop. Used by in-process providers
337
+ * (e.g. `LocalClientServices`) so their consumers use the same effect surface as remote proxies.
338
+ */
339
+ var makeRpcFromServices = (services) => {
340
+ const rpc = {};
341
+ for (const [tag, rpcDef] of ClientServicesRpcs.requests) {
342
+ const [serviceKey, methodName] = parseTag(tag);
343
+ const service = rpc[serviceKey] ??= {};
344
+ const resolveMethod = () => resolveServiceMethod(services(), serviceKey, methodName, tag);
345
+ if (RpcSchema.isStreamSchema(rpcDef.successSchema)) service[methodName] = (request) => pbStreamToStream(() => resolveMethod()(request));
346
+ else service[methodName] = (request) => Effect.tryPromise({
347
+ try: async () => resolveMethod()(request),
348
+ catch: toError$1
349
+ });
350
+ }
351
+ return rpc;
352
+ };
353
+ /**
354
+ * Adapts a protobuf service stream to an effect stream.
355
+ * Unbounded buffering matches the push semantics of the source stream.
356
+ */
357
+ var pbStreamToStream = (open) => Stream$1.asyncScoped((emit) => Effect.acquireRelease(Effect.try({
358
+ try: open,
359
+ catch: toError$1
360
+ }), (stream) => Effect.promise(async () => stream.close())).pipe(Effect.tap((stream) => Effect.sync(() => {
361
+ stream.subscribe((data) => void emit.single(data), (err) => void (err ? emit.fail(toError$1(err)) : emit.end()));
362
+ }))), "unbounded");
363
+ /**
364
+ * Adapts an effect stream to a protobuf service stream.
365
+ * Consumer close interrupts the underlying rpc subscription.
366
+ */
367
+ var streamToPbStream = (runtime, stream) => new Stream(({ ready, next, close }) => {
368
+ const fiber = stream.pipe(Stream$1.onStart(Effect.sync(ready)), Stream$1.runForEach((item) => Effect.sync(() => next(item))), Effect.matchCauseEffect({
369
+ onFailure: (cause) => Effect.sync(() => close(Cause.isInterruptedOnly(cause) ? void 0 : toError$1(Cause.squash(cause)))),
370
+ onSuccess: () => Effect.sync(() => close())
371
+ }), Runtime.runFork(runtime));
372
+ return () => {
373
+ fiber.unsafeInterruptAsFork(fiber.id());
374
+ };
375
+ });
376
+ //#endregion
377
+ //#region src/bridge-rpc.ts
378
+ /**
379
+ * The system channel runs the WebRTC {@link BridgeServiceRpc} in the worker→tab direction: the worker
380
+ * calls the tab's network stack to proxy RTC connections. It is served over its own {@link MessagePort}
381
+ * (the reverse of the app port) via effect-rpc, replacing the legacy protobuf duplex peer.
382
+ *
383
+ * `BridgeServiceRpc` is the proto-shaped interface (`Promise`/{@link PbStream}) that
384
+ * `RtcTransportService` implements and `RtcTransportProxyFactory` consumes; the helpers below adapt
385
+ * it to and from the effect-rpc surface.
386
+ */
387
+ var toError = (cause) => cause instanceof Error ? cause : new Error(String(cause));
388
+ /**
389
+ * Serves a proto-shaped {@link BridgeServiceRpc} (the tab's `RtcTransportService`) over a
390
+ * {@link MessagePort} via effect-rpc. The worker consumes it with {@link makeBridgeServiceClient}.
391
+ */
392
+ var serveBridgeService = (port, service) => {
393
+ const unary = (method) => (payload) => Effect.tryPromise({
394
+ try: () => method(payload),
395
+ catch: toError
396
+ });
397
+ const handlers = {
398
+ "BridgeService.open": (payload) => pbStreamToStream(() => service.open(payload)),
399
+ "BridgeService.sendSignal": unary((request) => service.sendSignal(request)),
400
+ "BridgeService.sendData": unary((request) => service.sendData(request)),
401
+ "BridgeService.close": unary((request) => service.close(request)),
402
+ "BridgeService.getDetails": unary((request) => service.getDetails(request)),
403
+ "BridgeService.getStats": unary((request) => service.getStats(request))
404
+ };
405
+ return serve(port, BridgeService.Rpcs, BridgeService.Rpcs.toLayer(handlers), {
406
+ disableTracing: true,
407
+ concurrency: "unbounded"
408
+ });
409
+ };
410
+ /**
411
+ * Builds a proto-shaped {@link BridgeServiceRpc} backed by an effect-rpc client over a
412
+ * {@link MessagePort}. Used in the worker to hand `RtcTransportProxyFactory` a bridge that proxies to
413
+ * the tab. The returned `close` releases the transport scope.
414
+ */
415
+ var makeBridgeServiceClient = async (port) => bridgeServiceClientFromEffect((scope) => makeClient(port, BridgeService.Rpcs).pipe(Scope.extend(scope)));
416
+ /**
417
+ * Builds a proto-shaped {@link BridgeServiceRpc} over a pre-built {@link RpcClient.Protocol} (the
418
+ * value the tag resolves to — e.g. the worker→client protocol handed to a worker-framework session
419
+ * via effect context) rather than a raw {@link MessagePort}.
420
+ */
421
+ var makeBridgeServiceClientOverProtocol = async (protocol) => bridgeServiceClientFromEffect((scope) => makeClientOverProtocol(Layer.succeed(RpcClient.Protocol, protocol), BridgeService.Rpcs).pipe(Scope.extend(scope)));
422
+ /** Adapts an effect-rpc {@link BridgeService.Client} (built by the caller) to the proto-shaped surface. */
423
+ var bridgeServiceClientFromEffect = async (makeClient) => {
424
+ const scope = Effect.runSync(Scope.make());
425
+ const bridge = (await EffectEx.runPromise(makeClient(scope))).BridgeService;
426
+ return {
427
+ bridgeService: {
428
+ open: (request) => streamToPbStream(Runtime.defaultRuntime, bridge.open(request)),
429
+ sendSignal: (request) => EffectEx.runPromise(bridge.sendSignal(request)),
430
+ sendData: (request) => EffectEx.runPromise(bridge.sendData(request)),
431
+ close: (request) => EffectEx.runPromise(bridge.close(request)),
432
+ getDetails: (request) => EffectEx.runPromise(bridge.getDetails(request)),
433
+ getStats: (request) => EffectEx.runPromise(bridge.getStats(request))
434
+ },
435
+ close: async () => {
436
+ await EffectEx.runPromise(Scope.close(scope, Exit.void));
437
+ }
438
+ };
439
+ };
440
+ //#endregion
441
+ //#region src/invitations/encoder.ts
442
+ var base62 = base("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
443
+ var codec = schema.getCodecForType("dxos.client.services.Invitation");
444
+ /**
445
+ * Encodes and decodes an invitation proto into/from alphanumeric chars.
446
+ */
447
+ var InvitationEncoder = class {
448
+ static decode(text) {
449
+ const decodedInvitation = codec.decode(base62.decode(text));
450
+ if (decodedInvitation.type === Invitation.Type.MULTIUSE) {
451
+ decodedInvitation.type = Invitation.Type.INTERACTIVE;
452
+ decodedInvitation.multiUse = true;
453
+ }
454
+ return decodedInvitation;
455
+ }
456
+ static encode(invitation) {
457
+ return base62.encode(codec.encode({
458
+ invitationId: invitation.invitationId,
459
+ type: invitation.type,
460
+ kind: invitation.kind,
461
+ authMethod: invitation.authMethod,
462
+ swarmKey: invitation.swarmKey,
463
+ state: invitation.state,
464
+ timeout: invitation.timeout,
465
+ guestKeypair: invitation.guestKeypair,
466
+ spaceId: invitation.spaceId,
467
+ lifetime: invitation.lifetime,
468
+ created: invitation.created,
469
+ ...invitation.spaceKey ? { spaceKey: invitation.spaceKey } : {},
470
+ ...invitation.target ? { target: invitation.target } : {}
471
+ }));
472
+ }
473
+ };
474
+ //#endregion
475
+ //#region src/invitations/invitations.ts
476
+ var __dxlog_file = "/__w/dxos/dxos/packages/sdk/client-protocol/src/invitations/invitations.ts";
477
+ var AUTHENTICATION_CODE_LENGTH = 6;
478
+ var INVITATION_TIMEOUT = 3 * 6e4;
479
+ /**
480
+ * Base class for all invitation observables and providers.
481
+ */
482
+ var CancellableInvitation = class extends MulticastObservable {
483
+ _onCancel;
484
+ constructor({ subscriber, initialInvitation, onCancel }) {
485
+ super(subscriber, initialInvitation);
486
+ this._onCancel = onCancel;
487
+ }
488
+ cancel() {
489
+ return this._onCancel();
490
+ }
491
+ get expired() {
492
+ const expiration = getExpirationTime(this.get());
493
+ return expiration && expiration.getTime() < Date.now();
494
+ }
495
+ get expiry() {
496
+ return getExpirationTime(this.get());
497
+ }
498
+ };
499
+ /**
500
+ * Cancelable observer that relays authentication requests.
501
+ */
502
+ var AuthenticatingInvitation = class extends CancellableInvitation {
503
+ _onAuthenticate;
504
+ constructor({ subscriber, initialInvitation, onCancel, onAuthenticate }) {
505
+ super({
506
+ subscriber,
507
+ initialInvitation,
508
+ onCancel
509
+ });
510
+ this._onAuthenticate = onAuthenticate;
511
+ }
512
+ async authenticate(authCode) {
513
+ return this._onAuthenticate(authCode);
514
+ }
515
+ };
516
+ /**
517
+ * Testing util to wrap non-authenticating observable with promise.
518
+ * Don't use this in production code.
519
+ * @deprecated
520
+ */
521
+ var wrapObservable = async (observable) => {
522
+ return new Promise((resolve, reject) => {
523
+ const subscription = observable.subscribe((invitation) => {
524
+ invariant(invitation?.state === Invitation.State.SUCCESS, void 0, {
525
+ "~LogMeta": "~LogMeta",
526
+ F: __dxlog_file,
527
+ L: 90,
528
+ S: void 0,
529
+ A: ["invitation?.state === Invitation.State.SUCCESS", ""]
530
+ });
531
+ subscription.unsubscribe();
532
+ resolve(invitation);
533
+ }, (err) => {
534
+ subscription.unsubscribe();
535
+ reject(err);
536
+ });
537
+ });
538
+ };
539
+ var getExpirationTime = (invitation) => {
540
+ if (!(invitation.created && invitation.lifetime)) return;
541
+ return new Date(invitation.created.getTime() + invitation.lifetime * 1e3);
542
+ };
543
+ //#endregion
544
+ //#region src/service.ts
545
+ var appServiceBundle = { AppService: schema.getService("dxos.iframe.AppService") };
546
+ var shellServiceBundle = { ShellService: schema.getService("dxos.iframe.ShellService") };
547
+ //#endregion
548
+ //#region src/space.ts
549
+ var SPACE_TAG = Symbol("dxos.client.protocol.Space");
550
+ var isSpace = (object) => typeof object === "object" && object != null && object[SPACE_TAG] === true;
551
+ var SpaceSchema = Schema.Any.pipe(Schema.filter((space) => isSpace(space)), Schema.annotations({ title: "Space" }));
552
+ //#endregion
553
+ //#region src/timeouts.ts
554
+ /**
555
+ * Timeout for making rpc connections from remote proxies.
556
+ */
557
+ var PROXY_CONNECTION_TIMEOUT = 3e4;
558
+ /**
559
+ * Timeout for the device to be added to the trusted set during auth.
560
+ */
561
+ var AUTH_TIMEOUT = 3e4;
562
+ /**
563
+ * Timeout for how long the remote client will wait before assuming the connection is lost.
564
+ */
565
+ var STATUS_TIMEOUT = 1e4;
566
+ /**
567
+ * Timeout for waiting before stealing resource lock.
568
+ */
569
+ var RESOURCE_LOCK_TIMEOUT = 3e3;
570
+ /**
571
+ * Timeout for space properties to be loaded in the set of tracked items.
572
+ * Accounts for latency between SpaceService reporting the space as READY and DataService streaming the item states.
573
+ */
574
+ var LOAD_PROPERTIES_TIMEOUT = 3e3;
575
+ /**
576
+ * Timeout for creating new spaces.
577
+ */
578
+ var CREATE_SPACE_TIMEOUT = 5e3;
579
+ /**
580
+ * Timeout for creating new spaces.
581
+ */
582
+ var IMPORT_SPACE_TIMEOUT = 3e4;
583
+ /**
584
+ * Timeout for loading of control feeds.
585
+ */
586
+ var LOAD_CONTROL_FEEDS_TIMEOUT = 3e3;
587
+ //#endregion
588
+ export { AUTHENTICATION_CODE_LENGTH, AUTH_TIMEOUT, AuthenticatingInvitation, CREATE_SPACE_TIMEOUT, CancellableInvitation, ClientRpcServer, ClientServicesRpcs, DEFAULT_CLIENT_CHANNEL, DEFAULT_INTERNAL_CHANNEL, DEFAULT_PROFILE, DEFAULT_SHELL_CHANNEL, DEFAULT_VAULT_URL, DXEnv, DX_CACHE, DX_CONFIG, DX_DATA, DX_RUNTIME, DX_STATE, EXPECTED_CONFIG_VERSION, IMPORT_SPACE_TIMEOUT, INVITATION_TIMEOUT, InvitationEncoder, LOAD_CONTROL_FEEDS_TIMEOUT, LOAD_PROPERTIES_TIMEOUT, PROXY_CONNECTION_TIMEOUT, RESOURCE_LOCK_TIMEOUT, Rpc_exports as Rpc, SPACE_TAG, STATUS_TIMEOUT, SpaceProperties, SpacePropertiesSchema, SpaceSchema, appServiceBundle, defaultConfig, getExpirationTime, getProfileConfigPath, getProfilePath, isSpace, makeBridgeServiceClient, makeBridgeServiceClientOverProtocol, makeClientServicesHandlers, makeClientServicesRpc, makeHandlersFromRpc, makeInProcessClientServicesRpc, makeRpcFromServices, makeServicesFromRpc, pbStreamToStream, serveBridgeService, serveClientServicesOverIFrame, shellServiceBundle, streamToPbStream, wrapObservable };
589
+
590
+ //# sourceMappingURL=index.mjs.map