@dxos/client-protocol 0.12.0-next-73daef452f1464b62efdbca75fb0067c1066f264 → 0.13.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 (60) hide show
  1. package/dist/lib/index.mjs +285 -254
  2. package/dist/lib/index.mjs.map +1 -1
  3. package/dist/lib/types.mjs +2 -2
  4. package/dist/lib/types.mjs.map +1 -1
  5. package/dist/types/src/Rpc.d.ts +29 -2
  6. package/dist/types/src/Rpc.d.ts.map +1 -1
  7. package/dist/types/src/Rpc.test.d.ts +2 -0
  8. package/dist/types/src/Rpc.test.d.ts.map +1 -0
  9. package/dist/types/src/echo.d.ts +12 -9
  10. package/dist/types/src/echo.d.ts.map +1 -1
  11. package/dist/types/src/events.d.ts +15 -0
  12. package/dist/types/src/events.d.ts.map +1 -0
  13. package/dist/types/src/halo.d.ts +37 -4
  14. package/dist/types/src/halo.d.ts.map +1 -1
  15. package/dist/types/src/index.d.ts +13 -12
  16. package/dist/types/src/index.d.ts.map +1 -1
  17. package/dist/types/src/invitations/encoder.d.ts +1 -1
  18. package/dist/types/src/invitations/encoder.d.ts.map +1 -1
  19. package/dist/types/src/invitations/index.d.ts +2 -2
  20. package/dist/types/src/invitations/index.d.ts.map +1 -1
  21. package/dist/types/src/invitations/invitations.d.ts +1 -1
  22. package/dist/types/src/invitations/invitations.d.ts.map +1 -1
  23. package/dist/types/src/rtc-rpc.d.ts +21 -0
  24. package/dist/types/src/rtc-rpc.d.ts.map +1 -0
  25. package/dist/types/src/service-rpc.d.ts +123 -61
  26. package/dist/types/src/service-rpc.d.ts.map +1 -1
  27. package/dist/types/src/service.d.ts +20 -14
  28. package/dist/types/src/service.d.ts.map +1 -1
  29. package/dist/types/src/shell.d.ts +1 -1
  30. package/dist/types/src/shell.d.ts.map +1 -1
  31. package/dist/types/src/space.d.ts +12 -8
  32. package/dist/types/src/space.d.ts.map +1 -1
  33. package/dist/types/src/timeouts.d.ts +1 -5
  34. package/dist/types/src/timeouts.d.ts.map +1 -1
  35. package/dist/types/src/types/SpaceProperties.d.ts.map +1 -1
  36. package/dist/types/src/types/index.d.ts +1 -1
  37. package/dist/types/src/types/index.d.ts.map +1 -1
  38. package/dist/types/tsconfig.tsbuildinfo +1 -1
  39. package/package.json +17 -18
  40. package/src/Rpc.test.ts +108 -0
  41. package/src/Rpc.ts +148 -77
  42. package/src/echo.ts +13 -6
  43. package/src/events.ts +27 -0
  44. package/src/halo.ts +43 -6
  45. package/src/index.ts +13 -12
  46. package/src/invitations/encoder.test.ts +72 -38
  47. package/src/invitations/encoder.ts +24 -23
  48. package/src/invitations/index.ts +2 -2
  49. package/src/invitations/invitations.ts +4 -3
  50. package/src/rtc-rpc.ts +48 -0
  51. package/src/service-rpc.ts +72 -30
  52. package/src/service.ts +27 -22
  53. package/src/shell.ts +1 -1
  54. package/src/space.ts +13 -10
  55. package/src/timeouts.ts +1 -6
  56. package/src/types/SpaceProperties.ts +2 -2
  57. package/src/types/index.ts +1 -1
  58. package/dist/types/src/bridge-rpc.d.ts +0 -27
  59. package/dist/types/src/bridge-rpc.d.ts.map +0 -1
  60. package/src/bridge-rpc.ts +0 -113
@@ -1,31 +1,30 @@
1
1
  import { SpaceProperties, SpacePropertiesSchema } from "./types.mjs";
2
- import * as Context from "effect/Context";
3
- import * as Effect from "effect/Effect";
4
- import * as Exit from "effect/Exit";
5
2
  import * as Layer from "effect/Layer";
6
- import * as Scope from "effect/Scope";
7
- import * as RpcClient from "effect/unstable/rpc/RpcClient";
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";
3
+ import * as RpcClient from "effect/rpc/RpcClient";
4
+ import { makeInProcessClient, normalizeHandlers, runServiceCall, toServiceError } from "@dxos/protocols";
5
+ import { ContactsService, DataService, DevicesService, DevtoolsHost, EdgeAgentService, FeedService, IdentityService, InboxService, InvitationsService, LoggingService, NetworkService, QueryService, RTCService, SpacesService, SqlService, SystemService } from "@dxos/protocols/rpc";
10
6
  import * as BrowserWorker from "@effect/platform-browser/BrowserWorker";
11
7
  import * as BrowserWorkerRunner from "@effect/platform-browser/BrowserWorkerRunner";
8
+ import * as Cause from "effect/Cause";
9
+ import * as Effect from "effect/Effect";
12
10
  import * as ManagedRuntime from "effect/ManagedRuntime";
13
- import * as RpcServer from "effect/unstable/rpc/RpcServer";
11
+ import * as RpcMiddleware from "effect/rpc/RpcMiddleware";
12
+ import * as RpcServer from "effect/rpc/RpcServer";
13
+ import { log } from "@dxos/log";
14
+ import { RpcRouter, layerProtocolRpcPortClient, layerProtocolRpcPortServer } from "@dxos/rpc";
14
15
  import { RpcTiming } from "@dxos/worker-framework";
15
- import * as Cause from "effect/Cause";
16
- import * as Stream$1 from "effect/Stream";
17
- import * as RpcGroup from "effect/unstable/rpc/RpcGroup";
18
- import * as RpcSchema from "effect/unstable/rpc/RpcSchema";
19
- import * as RpcTest from "effect/unstable/rpc/RpcTest";
16
+ import { InvitationSchema, Invitation_AuthMethod, Invitation_Kind, Invitation_State, Invitation_Type } from "@dxos/protocols/buf/dxos/client/invitation_pb";
17
+ import base from "base-x";
18
+ import { buf, bufWkt } from "@dxos/protocols/buf";
20
19
  import { MulticastObservable, Stream } from "@dxos/async";
21
20
  import { invariant } from "@dxos/invariant";
22
- import { log } from "@dxos/log";
23
- import { runServiceCall } from "@dxos/protocols";
24
- import { layerProtocolRpcPortClient, layerProtocolRpcPortServer } from "@dxos/rpc";
21
+ import { getBufService } from "@dxos/protocols/buf-service";
22
+ import * as RpcGroup from "effect/rpc/RpcGroup";
23
+ import * as RpcSchema from "effect/rpc/RpcSchema";
24
+ import * as RpcTest from "effect/rpc/RpcTest";
25
+ import * as Stream$1 from "effect/Stream";
26
+ import * as EffectEx from "@dxos/effect/EffectEx";
25
27
  import { createIFramePort } from "@dxos/rpc-tunnel";
26
- import base from "base-x";
27
- import { schema } from "@dxos/protocols/proto";
28
- import { Invitation } from "@dxos/protocols/proto/dxos/client/services";
29
28
  import * as Schema from "effect/Schema";
30
29
  //#region \0rolldown/runtime.js
31
30
  var __defProp = Object.defineProperty;
@@ -44,10 +43,34 @@ var Rpc_exports = /* @__PURE__ */ __exportAll({
44
43
  makeClient: () => makeClient,
45
44
  makeClientOverProtocol: () => makeClientOverProtocol,
46
45
  serve: () => serve,
47
- serveOverProtocol: () => serveOverProtocol
46
+ serveOnRouter: () => serveOnRouter,
47
+ serveOverProtocol: () => serveOverProtocol,
48
+ serveRouterOnPort: () => serveRouterOnPort,
49
+ serverLayer: () => serverLayer
48
50
  });
51
+ var __dxlog_file$2 = "/__w/dxos/dxos/packages/sdk/client-protocol/src/Rpc.ts";
49
52
  var WORKER_CLIENT_CONCURRENCY = Number.MAX_SAFE_INTEGER;
50
53
  var asRpcGroup = (group) => group;
54
+ var DefectLogMiddleware = class extends RpcMiddleware.Service()("DxosRpcDefectLogMiddleware") {};
55
+ var defectLogLayer = Layer.succeed(DefectLogMiddleware, (handler, { rpc }) => Effect.tapCause(handler, (cause) => Cause.hasDies(cause) ? Effect.sync(() => log.error("rpc handler defect", {
56
+ rpc: rpc._tag,
57
+ cause: Cause.pretty(cause)
58
+ }, {
59
+ "~LogMeta": "~LogMeta",
60
+ F: __dxlog_file$2,
61
+ L: 51,
62
+ S: void 0
63
+ })) : Effect.void));
64
+ var makeServerLayer = (group, handlers, options) => {
65
+ const timingEnabled = RpcTiming.isEnabled(options?.timing);
66
+ const rpcGroup = asRpcGroup(timingEnabled ? RpcTiming.applyMiddleware(asRpcGroup(group)) : asRpcGroup(group)).middleware(DefectLogMiddleware);
67
+ const handlersLayer = timingEnabled ? Layer.mergeAll(handlers, defectLogLayer, RpcTiming.serverLayer(RpcTiming.resolveOptions(options?.timing))) : Layer.merge(handlers, defectLogLayer);
68
+ return RpcServer.layer(asRpcGroup(rpcGroup), {
69
+ disableTracing: options?.disableTracing ?? true,
70
+ concurrency: options?.concurrency ?? "unbounded",
71
+ disableFatalDefects: true
72
+ }).pipe(Layer.provide(handlersLayer));
73
+ };
51
74
  /**
52
75
  * Builds an effect-native RPC client over a caller-supplied {@link RpcClient.Protocol} layer.
53
76
  * Transport-agnostic: consumers provide the Worker-platform protocol (see {@link makeClient}) or a
@@ -69,56 +92,45 @@ var makeClient = (port, group, options) => makeClientOverProtocol(RpcClient.laye
69
92
  concurrency: WORKER_CLIENT_CONCURRENCY
70
93
  }).pipe(Layer.provide(BrowserWorker.layer(() => port))), group, options);
71
94
  /**
72
- * Serves an {@link RpcGroup} on a {@link MessagePort} via the native Worker runner protocol.
95
+ * Effect-native server for an {@link RpcGroup}: a layer that serves `group` with `handlers` over the
96
+ * ambient {@link RpcServer.Protocol} for the life of the layer.
73
97
  */
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
- };
98
+ var serverLayer = (group, handlers, options) => makeServerLayer(group, handlers, options);
99
+ /**
100
+ * Serves `group` with `handlers` over the ambient {@link RpcRouter.RpcRouter} for the current scope,
101
+ * under the standard server middleware. Registration is per group, so nothing has to enumerate the
102
+ * services a transport carries; {@link RpcRouter.layerTransport} serves whatever is registered.
103
+ */
104
+ var serveOnRouter = (prefix, group, handlers, options) => {
105
+ const served = RpcTiming.applyMiddleware(group).middleware(DefectLogMiddleware);
106
+ return RpcRouter.serve(prefix, served, {
107
+ disableTracing: options?.disableTracing ?? true,
108
+ concurrency: options?.concurrency ?? "unbounded",
109
+ disableFatalDefects: true,
110
+ inProcessClient: options?.inProcessClient
111
+ }).pipe(Effect.provide(Layer.mergeAll(handlerLayer(group, handlers), defectLogLayer, RpcTiming.serverLayer(RpcTiming.resolveOptions(options?.timing)))));
101
112
  };
102
113
  /**
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).
114
+ * `group`'s handlers as the handlers of {@link Served} — the same group under middleware.
115
+ *
116
+ * `Rpc.ToHandler` keys off an rpc's `_tag` alone and `AddMiddleware` preserves it, so both are the
117
+ * same services; a middleware only widens what a handler MAY require. TypeScript cannot reduce
118
+ * `AddMiddleware` through a generic parameter, so the equality is stated rather than inferred.
119
+ */
120
+ var handlerLayer = (group, handlers) => group.toLayer(handlers);
121
+ /**
122
+ * Wraps a server layer in the open/close lifecycle every transport server shares. The in-flight
123
+ * open is cached so concurrent opens share one runtime and a close during startup disposes the
124
+ * runtime that startup created rather than leaking it.
106
125
  */
107
- var serveOverProtocol = (protocol, group, handlers, options) => {
126
+ var makeGroupServer = (buildLayer) => {
108
127
  let runtime;
109
128
  let openPromise;
110
129
  return {
111
130
  async open() {
112
131
  if (openPromise) return openPromise;
113
132
  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);
133
+ const current = ManagedRuntime.make(buildLayer());
122
134
  try {
123
135
  await current.runPromise(Effect.void);
124
136
  } catch (error) {
@@ -141,6 +153,42 @@ var serveOverProtocol = (protocol, group, handlers, options) => {
141
153
  }
142
154
  };
143
155
  };
156
+ /**
157
+ * Serves an {@link RpcGroup} on a {@link MessagePort} via the native Worker runner protocol.
158
+ */
159
+ var serve = (port, group, handlers, options) => makeGroupServer(() => makeServerLayer(group, handlers, options).pipe(Layer.provide(RpcServer.layerProtocolWorkerRunner.pipe(Layer.provide(BrowserWorkerRunner.layerMessagePort(port)))), Layer.orDie));
160
+ /**
161
+ * Serves whatever is registered with the ambient router on a {@link MessagePort} via the native
162
+ * Worker runner protocol — the transport half of a worker session, without the stack around it.
163
+ * The router is resolved on `open`, so a host that builds its stack later can be served.
164
+ */
165
+ var serveRouterOnPort = (router, port) => makeGroupServer(() => RpcRouter.layerTransport.pipe(Layer.provide(Layer.succeed(RpcRouter.RpcRouter, router())), Layer.provide(RpcServer.layerProtocolWorkerRunner.pipe(Layer.provide(BrowserWorkerRunner.layerMessagePort(port)))), Layer.orDie));
166
+ /**
167
+ * Serves an {@link RpcGroup} over a caller-supplied {@link RpcServer.Protocol} layer.
168
+ * Transport-agnostic counterpart to {@link makeClientOverProtocol}: consumers provide a byte
169
+ * protocol over a legacy transport (e.g. `@dxos/rpc`'s RpcPort layer for iframe/devtools bridges).
170
+ */
171
+ var serveOverProtocol = (protocol, group, handlers, options) => makeGroupServer(() => makeServerLayer(group, handlers, options).pipe(Layer.provide(protocol), Layer.orDie));
172
+ //#endregion
173
+ //#region src/rtc-rpc.ts
174
+ /**
175
+ * The system channel runs the WebRTC {@link RTCService} in the worker→tab direction: the worker asks
176
+ * the tab to establish a peer connection, and the tab transfers the resulting `RTCDataChannel` back
177
+ * over the same {@link MessagePort} (the reverse of the app port). Only signalling and the handover
178
+ * itself cross the boundary.
179
+ */
180
+ /** Serves the tab's {@link RTCService} implementation (`RtcService`) to the worker over a {@link MessagePort}. */
181
+ var serveRtcService = (port, service) => serve(port, RTCService.Rpcs, RTCService.Rpcs.toLayer(normalizeHandlers(RTCService.Rpcs, service)), {
182
+ disableTracing: true,
183
+ concurrency: "unbounded"
184
+ });
185
+ /** Builds the worker's {@link RTCService} client for the tab's implementation, over a {@link MessagePort}. */
186
+ var makeRtcServiceClient = (port) => makeClient(port, RTCService.Rpcs);
187
+ /**
188
+ * Builds the worker's client over a pre-built {@link RpcClient.Protocol} — the value the tag resolves
189
+ * to, e.g. the worker→client protocol handed to a worker-framework session via effect context.
190
+ */
191
+ var makeRtcServiceClientOverProtocol = (protocol) => makeClientOverProtocol(Layer.succeed(RpcClient.Protocol, protocol), RTCService.Rpcs);
144
192
  //#endregion
145
193
  //#region src/config.ts
146
194
  var DEFAULT_CLIENT_CHANNEL = "dxos:app";
@@ -187,19 +235,139 @@ var getProfilePath = (root, profile, file) => `${root}/profile/${profile}` + (fi
187
235
  /** Path to the profile config file (profile/<name>.yml). */
188
236
  var getProfileConfigPath = (root, profile) => `${getProfilePath(root, profile)}.yml`;
189
237
  //#endregion
238
+ //#region src/events.ts
239
+ /**
240
+ * The trace events the client and its services emit on `trace.events` from `@dxos/tracing`. Space creation and
241
+ * invitation `create` come from the client; `admit` and `accept` from the services of the host and guest peers, which
242
+ * see every success exactly once however the invitation started.
243
+ */
244
+ var ClientTraceEvents = {
245
+ spaceCreate: "client.space.create",
246
+ invitationCreate: "client.invitation.create",
247
+ invitationAdmit: "client.invitation.admit",
248
+ invitationAccept: "client.invitation.accept"
249
+ };
250
+ /** What an invitation trace event reports about the invitation: never its keys, secrets or guest identity. */
251
+ var invitationEventAttributes = (invitation) => ({
252
+ kind: invitation.kind === Invitation_Kind.DEVICE ? "device" : "space",
253
+ spaceId: invitation.spaceId,
254
+ authMethod: Invitation_AuthMethod[invitation.authMethod]?.toLowerCase(),
255
+ multiUse: invitation.multiUse ?? false
256
+ });
257
+ //#endregion
258
+ //#region src/invitations/encoder.ts
259
+ var base62 = base("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
260
+ /**
261
+ * Encodes and decodes an invitation proto into/from alphanumeric chars.
262
+ */
263
+ var InvitationEncoder = class {
264
+ static decode(text) {
265
+ const decodedInvitation = buf.fromBinary(InvitationSchema, base62.decode(text));
266
+ if (decodedInvitation.type === Invitation_Type.MULTIUSE) {
267
+ decodedInvitation.type = Invitation_Type.INTERACTIVE;
268
+ decodedInvitation.multiUse = true;
269
+ }
270
+ return decodedInvitation;
271
+ }
272
+ static encode(invitation) {
273
+ return base62.encode(buf.toBinary(InvitationSchema, buf.create(InvitationSchema, {
274
+ invitationId: invitation.invitationId,
275
+ type: invitation.type,
276
+ kind: invitation.kind,
277
+ authMethod: invitation.authMethod,
278
+ swarmKey: invitation.swarmKey,
279
+ state: invitation.state,
280
+ timeout: invitation.timeout,
281
+ guestKeypair: invitation.guestKeypair,
282
+ spaceId: invitation.spaceId,
283
+ lifetime: invitation.lifetime,
284
+ created: invitation.created,
285
+ ...invitation.spaceKey ? { spaceKey: invitation.spaceKey } : {},
286
+ ...invitation.target ? { target: invitation.target } : {}
287
+ })));
288
+ }
289
+ };
290
+ //#endregion
291
+ //#region src/invitations/invitations.ts
292
+ var __dxlog_file$1 = "/__w/dxos/dxos/packages/sdk/client-protocol/src/invitations/invitations.ts";
293
+ var AUTHENTICATION_CODE_LENGTH = 6;
294
+ var INVITATION_TIMEOUT = 18e4;
295
+ /**
296
+ * Base class for all invitation observables and providers.
297
+ */
298
+ var CancellableInvitation = class extends MulticastObservable {
299
+ _onCancel;
300
+ constructor({ subscriber, initialInvitation, onCancel }) {
301
+ super(subscriber, initialInvitation);
302
+ this._onCancel = onCancel;
303
+ }
304
+ cancel() {
305
+ return this._onCancel();
306
+ }
307
+ get expired() {
308
+ const expiration = getExpirationTime(this.get());
309
+ return expiration && expiration.getTime() < Date.now();
310
+ }
311
+ get expiry() {
312
+ return getExpirationTime(this.get());
313
+ }
314
+ };
315
+ /**
316
+ * Cancelable observer that relays authentication requests.
317
+ */
318
+ var AuthenticatingInvitation = class extends CancellableInvitation {
319
+ _onAuthenticate;
320
+ constructor({ subscriber, initialInvitation, onCancel, onAuthenticate }) {
321
+ super({
322
+ subscriber,
323
+ initialInvitation,
324
+ onCancel
325
+ });
326
+ this._onAuthenticate = onAuthenticate;
327
+ }
328
+ async authenticate(authCode) {
329
+ return this._onAuthenticate(authCode);
330
+ }
331
+ };
332
+ /**
333
+ * Testing util to wrap non-authenticating observable with promise.
334
+ * Don't use this in production code.
335
+ * @deprecated
336
+ */
337
+ var wrapObservable = async (observable) => {
338
+ return new Promise((resolve, reject) => {
339
+ const subscription = observable.subscribe((invitation) => {
340
+ invariant(invitation?.state === Invitation_State.SUCCESS, void 0, {
341
+ "~LogMeta": "~LogMeta",
342
+ F: __dxlog_file$1,
343
+ L: 91,
344
+ S: void 0,
345
+ A: ["invitation?.state === Invitation_State.SUCCESS", ""]
346
+ });
347
+ subscription.unsubscribe();
348
+ resolve(invitation);
349
+ }, (err) => {
350
+ subscription.unsubscribe();
351
+ reject(err);
352
+ });
353
+ });
354
+ };
355
+ var getExpirationTime = (invitation) => {
356
+ if (!(invitation.created && invitation.lifetime)) return;
357
+ return new Date(Number(bufWkt.timestampMs(invitation.created)) + invitation.lifetime * 1e3);
358
+ };
359
+ //#endregion
360
+ //#region src/service.ts
361
+ var appServiceBundle = { AppService: getBufService("dxos.iframe.AppService") };
362
+ var shellServiceBundle = { ShellService: getBufService("dxos.iframe.ShellService") };
363
+ //#endregion
190
364
  //#region src/service-rpc.ts
191
- var __dxlog_file$1 = "/__w/dxos/dxos/packages/sdk/client-protocol/src/service-rpc.ts";
365
+ var __dxlog_file = "/__w/dxos/dxos/packages/sdk/client-protocol/src/service-rpc.ts";
192
366
  /**
193
367
  * All client service RPCs served over a single connection.
194
368
  * Rpc tags are prefixed with the {@link ClientServices} key (e.g. `DataService.subscribe`).
195
- *
196
- * {@link WorkerService} (the tab→worker control channel: `start`/`stop`) is merged in here rather
197
- * than served over a second port: it runs in the same tab→worker direction as the service RPCs, so
198
- * it multiplexes over the same app {@link MessagePort}. Only the reverse-direction `BridgeService`
199
- * (worker→tab) needs its own port.
200
369
  */
201
- 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) {};
202
- var toError$1 = (cause) => cause instanceof Error ? cause : new Error(String(cause));
370
+ 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, InboxService.Rpcs, EdgeAgentService.Rpcs, SqlService.Rpcs, DevtoolsHost.Rpcs) {};
203
371
  var isVoidSchema = (schema) => schema.ast._tag === "Void";
204
372
  /** Splits an rpc tag into the {@link ClientServices} key and the service method name. */
205
373
  var parseTag = (tag) => {
@@ -235,8 +403,8 @@ var ClientRpcServer = class {
235
403
  else {
236
404
  invariant(this.#params.port, "ClientRpcServer requires a port or a protocol.", {
237
405
  "~LogMeta": "~LogMeta",
238
- F: __dxlog_file$1,
239
- L: 189,
406
+ F: __dxlog_file,
407
+ L: 184,
240
408
  S: this,
241
409
  A: ["this.#params.port", "'ClientRpcServer requires a port or a protocol.'"]
242
410
  });
@@ -272,13 +440,51 @@ var serveClientServicesOverIFrame = async ({ iframe, origin, channel = DEFAULT_C
272
440
  return server;
273
441
  };
274
442
  /**
443
+ * The rpc tag prefix a group was defined with (e.g. `DataService.`), read off its requests so a
444
+ * registration carries no second copy of the service name.
445
+ */
446
+ var servicePrefix = (group) => {
447
+ const [tag] = [...group.requests.keys()];
448
+ invariant(tag, "rpc group has no requests", {
449
+ "~LogMeta": "~LogMeta",
450
+ F: __dxlog_file,
451
+ L: 235,
452
+ S: void 0,
453
+ A: ["tag", "'rpc group has no requests'"]
454
+ });
455
+ const index = tag.indexOf(".");
456
+ invariant(index > 0, `rpc tag is not service-prefixed: ${tag}`, {
457
+ "~LogMeta": "~LogMeta",
458
+ F: __dxlog_file,
459
+ L: 237,
460
+ S: void 0,
461
+ A: ["index > 0", "`rpc tag is not service-prefixed: ${tag}`"]
462
+ });
463
+ return tag.slice(0, index + 1);
464
+ };
465
+ /**
466
+ * Registers a service's handlers with the stack's {@link RpcRouter.RpcRouter}, which serves them
467
+ * over every attached transport (and in-process) for the life of the layer. Handler creation and
468
+ * registration stay separate layers: a provider merges this with the layer that supplies its tag,
469
+ * and no list of services is needed anywhere else.
470
+ */
471
+ var RegisterService = (rpc, tag) => Layer.effectDiscard(Effect.gen(function* () {
472
+ const handlers = normalizeHandlers(rpc, yield* tag);
473
+ yield* serveOnRouter(servicePrefix(rpc), rpc, handlers, { inProcessClient: makeInProcessClient(rpc, handlers) });
474
+ }));
475
+ /**
476
+ * The whole in-process {@link ClientServicesRpc}, sourced from the services registered with the
477
+ * router rather than from an enumerated handler map.
478
+ */
479
+ var makeClientServicesRpcFromRouter = RpcRouter.client.pipe(Effect.map((client) => client));
480
+ /**
275
481
  * Builds handler layers for every client service RPC, dispatching to the service implementations
276
482
  * resolved from `services` on each call.
277
483
  */
278
484
  var makeClientServicesHandlers = ({ services, onRequest }) => {
279
485
  const gate = onRequest ? Effect.tryPromise({
280
486
  try: onRequest,
281
- catch: toError$1
487
+ catch: toServiceError
282
488
  }) : Effect.void;
283
489
  const handlers = {};
284
490
  for (const [tag, rpc] of ClientServicesRpcs.requests) {
@@ -366,7 +572,7 @@ var makeRpcFromServices = (services) => {
366
572
  if (RpcSchema.isStreamSchema(rpcDef.successSchema)) service[methodName] = (request) => pbStreamToStream(() => resolveMethod()(request));
367
573
  else service[methodName] = (request) => Effect.tryPromise({
368
574
  try: async () => resolveMethod()(request),
369
- catch: toError$1
575
+ catch: toServiceError
370
576
  });
371
577
  }
372
578
  return rpc;
@@ -380,10 +586,10 @@ var pbStreamToStream = (open) => EffectEx.streamFromEmitter((emit) => {
380
586
  try {
381
587
  source = open();
382
588
  } catch (err) {
383
- emit.fail(toError$1(err));
589
+ emit.fail(toServiceError(err));
384
590
  return;
385
591
  }
386
- source.subscribe((data) => void emit.single(data), (err) => void (err ? emit.fail(toError$1(err)) : emit.end()));
592
+ source.subscribe((data) => void emit.single(data), (err) => void (err ? emit.fail(toServiceError(err)) : emit.end()));
387
593
  return Effect.promise(async () => source.close());
388
594
  });
389
595
  /**
@@ -393,7 +599,7 @@ var pbStreamToStream = (open) => EffectEx.streamFromEmitter((emit) => {
393
599
  var streamToPbStream = (runtime, stream, label) => new Stream(({ ready, next, close }) => {
394
600
  const fiber = stream.pipe(Stream$1.onStart(Effect.sync(ready)), Stream$1.runForEach((item) => Effect.sync(() => next(item))), Effect.matchCauseEffect({
395
601
  onFailure: (cause) => Effect.sync(() => {
396
- const error = toError$1(Cause.squash(cause));
602
+ const error = toServiceError(Cause.squash(cause));
397
603
  if (Cause.hasInterruptsOnly(cause)) {
398
604
  close();
399
605
  return;
@@ -403,8 +609,8 @@ var streamToPbStream = (runtime, stream, label) => new Stream(({ ready, next, cl
403
609
  error: String(error)
404
610
  }, {
405
611
  "~LogMeta": "~LogMeta",
406
- F: __dxlog_file$1,
407
- L: 467,
612
+ F: __dxlog_file,
613
+ L: 509,
408
614
  S: void 0
409
615
  });
410
616
  close(error);
@@ -416,177 +622,6 @@ var streamToPbStream = (runtime, stream, label) => new Stream(({ ready, next, cl
416
622
  };
417
623
  });
418
624
  //#endregion
419
- //#region src/bridge-rpc.ts
420
- /**
421
- * The system channel runs the WebRTC {@link BridgeServiceRpc} in the worker→tab direction: the worker
422
- * calls the tab's network stack to proxy RTC connections. It is served over its own {@link MessagePort}
423
- * (the reverse of the app port) via effect-rpc, replacing the legacy protobuf duplex peer.
424
- *
425
- * `BridgeServiceRpc` is the proto-shaped interface (`Promise`/{@link PbStream}) that
426
- * `RtcTransportService` implements and `RtcTransportProxyFactory` consumes; the helpers below adapt
427
- * it to and from the effect-rpc surface.
428
- */
429
- var toError = (cause) => cause instanceof Error ? cause : new Error(String(cause));
430
- /**
431
- * Serves a proto-shaped {@link BridgeServiceRpc} (the tab's `RtcTransportService`) over a
432
- * {@link MessagePort} via effect-rpc. The worker consumes it with {@link makeBridgeServiceClient}.
433
- */
434
- var serveBridgeService = (port, service) => {
435
- const unary = (method) => (payload) => Effect.tryPromise({
436
- try: () => method(payload),
437
- catch: toError
438
- });
439
- const handlers = {
440
- "BridgeService.open": (payload) => pbStreamToStream(() => service.open(payload)),
441
- "BridgeService.sendSignal": unary((request) => service.sendSignal(request)),
442
- "BridgeService.sendData": unary((request) => service.sendData(request)),
443
- "BridgeService.close": unary((request) => service.close(request)),
444
- "BridgeService.getDetails": unary((request) => service.getDetails(request)),
445
- "BridgeService.getStats": unary((request) => service.getStats(request))
446
- };
447
- return serve(port, BridgeService.Rpcs, BridgeService.Rpcs.toLayer(handlers), {
448
- disableTracing: true,
449
- concurrency: "unbounded"
450
- });
451
- };
452
- /**
453
- * Builds a proto-shaped {@link BridgeServiceRpc} backed by an effect-rpc client over a
454
- * {@link MessagePort}. Used in the worker to hand `RtcTransportProxyFactory` a bridge that proxies to
455
- * the tab. The returned `close` releases the transport scope.
456
- */
457
- var makeBridgeServiceClient = async (port) => bridgeServiceClientFromEffect((scope) => makeClient(port, BridgeService.Rpcs).pipe(Scope.provide(scope)));
458
- /**
459
- * Builds a proto-shaped {@link BridgeServiceRpc} over a pre-built {@link RpcClient.Protocol} (the
460
- * value the tag resolves to — e.g. the worker→client protocol handed to a worker-framework session
461
- * via effect context) rather than a raw {@link MessagePort}.
462
- */
463
- var makeBridgeServiceClientOverProtocol = async (protocol) => bridgeServiceClientFromEffect((scope) => makeClientOverProtocol(Layer.succeed(RpcClient.Protocol, protocol), BridgeService.Rpcs).pipe(Scope.provide(scope)));
464
- /** Adapts an effect-rpc {@link BridgeService.Client} (built by the caller) to the proto-shaped surface. */
465
- var bridgeServiceClientFromEffect = async (makeClient) => {
466
- const scope = Effect.runSync(Scope.make());
467
- const client = await EffectEx.runPromise(makeClient(scope));
468
- return {
469
- bridgeService: {
470
- open: (request) => streamToPbStream(Context.empty(), client["BridgeService.open"](request)),
471
- sendSignal: (request) => EffectEx.runPromise(client["BridgeService.sendSignal"](request)),
472
- sendData: (request) => EffectEx.runPromise(client["BridgeService.sendData"](request)),
473
- close: (request) => EffectEx.runPromise(client["BridgeService.close"](request)),
474
- getDetails: (request) => EffectEx.runPromise(client["BridgeService.getDetails"](request)),
475
- getStats: (request) => EffectEx.runPromise(client["BridgeService.getStats"](request))
476
- },
477
- close: async () => {
478
- await EffectEx.runPromise(Scope.close(scope, Exit.void));
479
- }
480
- };
481
- };
482
- //#endregion
483
- //#region src/invitations/encoder.ts
484
- var base62 = base("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
485
- var codec = schema.getCodecForType("dxos.client.services.Invitation");
486
- /**
487
- * Encodes and decodes an invitation proto into/from alphanumeric chars.
488
- */
489
- var InvitationEncoder = class {
490
- static decode(text) {
491
- const decodedInvitation = codec.decode(base62.decode(text));
492
- if (decodedInvitation.type === Invitation.Type.MULTIUSE) {
493
- decodedInvitation.type = Invitation.Type.INTERACTIVE;
494
- decodedInvitation.multiUse = true;
495
- }
496
- return decodedInvitation;
497
- }
498
- static encode(invitation) {
499
- return base62.encode(codec.encode({
500
- invitationId: invitation.invitationId,
501
- type: invitation.type,
502
- kind: invitation.kind,
503
- authMethod: invitation.authMethod,
504
- swarmKey: invitation.swarmKey,
505
- state: invitation.state,
506
- timeout: invitation.timeout,
507
- guestKeypair: invitation.guestKeypair,
508
- spaceId: invitation.spaceId,
509
- lifetime: invitation.lifetime,
510
- created: invitation.created,
511
- ...invitation.spaceKey ? { spaceKey: invitation.spaceKey } : {},
512
- ...invitation.target ? { target: invitation.target } : {}
513
- }));
514
- }
515
- };
516
- //#endregion
517
- //#region src/invitations/invitations.ts
518
- var __dxlog_file = "/__w/dxos/dxos/packages/sdk/client-protocol/src/invitations/invitations.ts";
519
- var AUTHENTICATION_CODE_LENGTH = 6;
520
- var INVITATION_TIMEOUT = 18e4;
521
- /**
522
- * Base class for all invitation observables and providers.
523
- */
524
- var CancellableInvitation = class extends MulticastObservable {
525
- _onCancel;
526
- constructor({ subscriber, initialInvitation, onCancel }) {
527
- super(subscriber, initialInvitation);
528
- this._onCancel = onCancel;
529
- }
530
- cancel() {
531
- return this._onCancel();
532
- }
533
- get expired() {
534
- const expiration = getExpirationTime(this.get());
535
- return expiration && expiration.getTime() < Date.now();
536
- }
537
- get expiry() {
538
- return getExpirationTime(this.get());
539
- }
540
- };
541
- /**
542
- * Cancelable observer that relays authentication requests.
543
- */
544
- var AuthenticatingInvitation = class extends CancellableInvitation {
545
- _onAuthenticate;
546
- constructor({ subscriber, initialInvitation, onCancel, onAuthenticate }) {
547
- super({
548
- subscriber,
549
- initialInvitation,
550
- onCancel
551
- });
552
- this._onAuthenticate = onAuthenticate;
553
- }
554
- async authenticate(authCode) {
555
- return this._onAuthenticate(authCode);
556
- }
557
- };
558
- /**
559
- * Testing util to wrap non-authenticating observable with promise.
560
- * Don't use this in production code.
561
- * @deprecated
562
- */
563
- var wrapObservable = async (observable) => {
564
- return new Promise((resolve, reject) => {
565
- const subscription = observable.subscribe((invitation) => {
566
- invariant(invitation?.state === Invitation.State.SUCCESS, void 0, {
567
- "~LogMeta": "~LogMeta",
568
- F: __dxlog_file,
569
- L: 90,
570
- S: void 0,
571
- A: ["invitation?.state === Invitation.State.SUCCESS", ""]
572
- });
573
- subscription.unsubscribe();
574
- resolve(invitation);
575
- }, (err) => {
576
- subscription.unsubscribe();
577
- reject(err);
578
- });
579
- });
580
- };
581
- var getExpirationTime = (invitation) => {
582
- if (!(invitation.created && invitation.lifetime)) return;
583
- return new Date(invitation.created.getTime() + invitation.lifetime * 1e3);
584
- };
585
- //#endregion
586
- //#region src/service.ts
587
- var appServiceBundle = { AppService: schema.getService("dxos.iframe.AppService") };
588
- var shellServiceBundle = { ShellService: schema.getService("dxos.iframe.ShellService") };
589
- //#endregion
590
625
  //#region src/space.ts
591
626
  var SPACE_TAG = Symbol("dxos.client.protocol.Space");
592
627
  var isSpace = (object) => typeof object === "object" && object != null && object[SPACE_TAG] === true;
@@ -619,11 +654,7 @@ var RESOURCE_LOCK_TIMEOUT = 3e3;
619
654
  */
620
655
  var LOAD_PROPERTIES_TIMEOUT = 3e3;
621
656
  /**
622
- * Timeout for creating new spaces.
623
- */
624
- var CREATE_SPACE_TIMEOUT = 5e3;
625
- /**
626
- * Timeout for creating new spaces.
657
+ * Timeout for importing a space.
627
658
  */
628
659
  var IMPORT_SPACE_TIMEOUT = 3e4;
629
660
  /**
@@ -631,6 +662,6 @@ var IMPORT_SPACE_TIMEOUT = 3e4;
631
662
  */
632
663
  var LOAD_CONTROL_FEEDS_TIMEOUT = 3e3;
633
664
  //#endregion
634
- export { AUTHENTICATION_CODE_LENGTH, AUTH_TIMEOUT, AuthenticatingInvitation, CREATE_SPACE_TIMEOUT, CancellableInvitation, ClientRpcServer, ClientServicesRpcs, DEFAULT_AUTH_URL, DEFAULT_CLIENT_CHANNEL, DEFAULT_HUB_URL, DEFAULT_INTERNAL_CHANNEL, DEFAULT_PROFILE, DEFAULT_SHELL_CHANNEL, DXEnv, DX_CACHE, DX_CONFIG, DX_DATA, DX_RUNTIME, DX_STATE, EXPECTED_CONFIG_VERSION, IMPORT_SPACE_TIMEOUT, INITIALIZE_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 };
665
+ export { AUTHENTICATION_CODE_LENGTH, AUTH_TIMEOUT, AuthenticatingInvitation, CancellableInvitation, ClientRpcServer, ClientServicesRpcs, ClientTraceEvents, DEFAULT_AUTH_URL, DEFAULT_CLIENT_CHANNEL, DEFAULT_HUB_URL, DEFAULT_INTERNAL_CHANNEL, DEFAULT_PROFILE, DEFAULT_SHELL_CHANNEL, DXEnv, DX_CACHE, DX_CONFIG, DX_DATA, DX_RUNTIME, DX_STATE, EXPECTED_CONFIG_VERSION, IMPORT_SPACE_TIMEOUT, INITIALIZE_TIMEOUT, INVITATION_TIMEOUT, InvitationEncoder, LOAD_CONTROL_FEEDS_TIMEOUT, LOAD_PROPERTIES_TIMEOUT, PROXY_CONNECTION_TIMEOUT, RESOURCE_LOCK_TIMEOUT, RegisterService, Rpc_exports as Rpc, SPACE_TAG, STATUS_TIMEOUT, SpaceProperties, SpacePropertiesSchema, SpaceSchema, appServiceBundle, defaultConfig, getExpirationTime, getProfileConfigPath, getProfilePath, invitationEventAttributes, isSpace, makeClientServicesHandlers, makeClientServicesRpc, makeClientServicesRpcFromRouter, makeHandlersFromRpc, makeInProcessClientServicesRpc, makeRpcFromServices, makeRtcServiceClient, makeRtcServiceClientOverProtocol, makeServicesFromRpc, pbStreamToStream, serveClientServicesOverIFrame, serveRtcService, shellServiceBundle, streamToPbStream, wrapObservable };
635
666
 
636
667
  //# sourceMappingURL=index.mjs.map