@fuzdev/fuz_app 0.28.0 → 0.30.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.
@@ -7,28 +7,29 @@
7
7
  * @module
8
8
  */
9
9
  import { JsonrpcMessageFromServerToClient, JsonrpcNotification, JsonrpcRequest, JsonrpcResponseOrError, JsonrpcErrorResponse } from '../http/jsonrpc.js';
10
- import { Transports, type TransportName } from './transports.js';
10
+ import { Transports, type TransportName, type TransportSendOptions } from './transports.js';
11
11
  import type { ActionEventEnvironment } from './action_event_types.js';
12
- export interface ActionPeerSendOptions {
12
+ /**
13
+ * Per-call options for `ActionPeer.send`. Extends `TransportSendOptions`
14
+ * with `transport_name` for per-call transport selection. The peer-wide
15
+ * default for any field lives on `ActionPeerOptions.default_send_options` —
16
+ * set `queue: true` there once for client-authoritative peers and override
17
+ * per-call for exceptions (e.g. high-frequency position sync where stale
18
+ * replays are wrong).
19
+ */
20
+ export interface ActionPeerSendOptions extends TransportSendOptions {
13
21
  transport_name?: TransportName;
14
- /**
15
- * Per-call `AbortSignal`. Forwarded into the chosen transport's `send`,
16
- * which bottoms out at `FrontendWebsocketClient.request({signal})` for WS
17
- * (sends the shared `cancel` notification on abort) and at
18
- * `fetch({signal})` for HTTP. Backend transport ignores it.
19
- */
20
- signal?: AbortSignal;
21
22
  }
22
23
  export interface ActionPeerOptions {
23
24
  environment: ActionEventEnvironment;
24
25
  transports?: Transports;
25
- default_send_options?: Partial<ActionPeerSendOptions>;
26
+ default_send_options?: Omit<ActionPeerSendOptions, 'signal'>;
26
27
  }
27
28
  export declare class ActionPeer {
28
29
  #private;
29
30
  readonly environment: ActionEventEnvironment;
30
31
  readonly transports: Transports;
31
- default_send_options: ActionPeerSendOptions;
32
+ default_send_options: Omit<ActionPeerSendOptions, 'signal'>;
32
33
  constructor(options: ActionPeerOptions);
33
34
  send(message: JsonrpcRequest, options?: ActionPeerSendOptions): Promise<JsonrpcResponseOrError>;
34
35
  send(message: JsonrpcNotification, options?: ActionPeerSendOptions): Promise<JsonrpcErrorResponse | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"action_peer.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_peer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAEN,gCAAgC,EAChC,mBAAmB,EACnB,cAAc,EACd,sBAAsB,EACtB,oBAAoB,EACpB,MAAM,oBAAoB,CAAC;AAU5B,OAAO,EAAC,UAAU,EAAE,KAAK,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAC/D,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,yBAAyB,CAAC;AAOpE,MAAM,WAAW,qBAAqB;IACrC,cAAc,CAAC,EAAE,aAAa,CAAC;IAC/B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IACjC,WAAW,EAAE,sBAAsB,CAAC;IAGpC,UAAU,CAAC,EAAE,UAAU,CAAC;IAGxB,oBAAoB,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACtD;AAED,qBAAa,UAAU;;IACtB,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAC;IAC7C,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAMhC,oBAAoB,EAAE,qBAAqB,CAAC;gBAEhC,OAAO,EAAE,iBAAiB;IAOhC,IAAI,CACT,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE,qBAAqB,GAC7B,OAAO,CAAC,sBAAsB,CAAC;IAC5B,IAAI,CACT,OAAO,EAAE,mBAAmB,EAC5B,OAAO,CAAC,EAAE,qBAAqB,GAC7B,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IA2CjC,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,gCAAgC,GAAG,IAAI,CAAC;CAyIjF"}
1
+ {"version":3,"file":"action_peer.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_peer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAEN,gCAAgC,EAChC,mBAAmB,EACnB,cAAc,EACd,sBAAsB,EACtB,oBAAoB,EACpB,MAAM,oBAAoB,CAAC;AAU5B,OAAO,EAAC,UAAU,EAAE,KAAK,aAAa,EAAE,KAAK,oBAAoB,EAAC,MAAM,iBAAiB,CAAC;AAC1F,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,yBAAyB,CAAC;AAOpE;;;;;;;GAOG;AACH,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB;IAClE,cAAc,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IACjC,WAAW,EAAE,sBAAsB,CAAC;IAGpC,UAAU,CAAC,EAAE,UAAU,CAAC;IAKxB,oBAAoB,CAAC,EAAE,IAAI,CAAC,qBAAqB,EAAE,QAAQ,CAAC,CAAC;CAC7D;AAED,qBAAa,UAAU;;IACtB,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAC;IAC7C,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAMhC,oBAAoB,EAAE,IAAI,CAAC,qBAAqB,EAAE,QAAQ,CAAC,CAAC;gBAEhD,OAAO,EAAE,iBAAiB;IAOhC,IAAI,CACT,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE,qBAAqB,GAC7B,OAAO,CAAC,sBAAsB,CAAC;IAC5B,IAAI,CACT,OAAO,EAAE,mBAAmB,EAC5B,OAAO,CAAC,EAAE,qBAAqB,GAC7B,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IA8CjC,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,gCAAgC,GAAG,IAAI,CAAC;CAyIjF"}
@@ -33,7 +33,10 @@ export class ActionPeer {
33
33
  }
34
34
  const message_type = is_jsonrpc_request(message) ? 'request' : 'notification';
35
35
  this.environment.log?.debug(`[peer] send ${message_type}:`, message.method, `via ${transport.transport_name}`);
36
- const result = await transport.send(message, { signal: options?.signal });
36
+ const result = await transport.send(message, {
37
+ signal: options?.signal,
38
+ queue: options?.queue ?? this.default_send_options.queue,
39
+ });
37
40
  if (result && 'error' in result) {
38
41
  this.environment.log?.error(`[peer] send ${message_type} failed:`, message.method, result.error.message);
39
42
  }
@@ -10,7 +10,7 @@
10
10
  * @module
11
11
  */
12
12
  import type { ActionEventEnvironment } from './action_event_types.js';
13
- import type { ActionPeer } from './action_peer.js';
13
+ import type { ActionPeer, ActionPeerSendOptions } from './action_peer.js';
14
14
  import type { ActionEventDataUnion } from './action_event_data.js';
15
15
  import type { TransportName } from './transports.js';
16
16
  /**
@@ -58,13 +58,11 @@ export interface CreateRpcClientOptions {
58
58
  */
59
59
  export declare const create_rpc_client: (options: CreateRpcClientOptions) => Record<string, (...args: Array<any>) => any>;
60
60
  /**
61
- * Per-call options accepted by every typed Proxy method. `signal` lets the
62
- * caller cancel an in-flight request (sends the shared `cancel` notification
63
- * on the WS path, aborts `fetch` on HTTP). `transport_name` overrides the
64
- * per-method `transport_for_method` selector for this call.
61
+ * Per-call options accepted by every typed Proxy method. Same shape as
62
+ * `ActionPeerSendOptions` the client threads these through unchanged
63
+ * to the underlying peer. `transport_name` overrides the per-method
64
+ * `transport_for_method` selector for this call.
65
65
  */
66
- export interface RpcClientCallOptions {
67
- signal?: AbortSignal;
68
- transport_name?: TransportName;
66
+ export interface RpcClientCallOptions extends ActionPeerSendOptions {
69
67
  }
70
68
  //# sourceMappingURL=rpc_client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rpc_client.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/rpc_client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,yBAAyB,CAAC;AAOpE,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAGnD;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,aAAa,GAAG,SAAS,CAAC;AAM/E,8EAA8E;AAC9E,MAAM,WAAW,sBAAsB;IACtC,aAAa,EAAE,CAAC,IAAI,EAAE;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,oBAAoB,CAAA;KAAC,KAC5E;QACA,sBAAsB,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;KAC5C,GACD,SAAS,CAAC;CACb;AAED,uCAAuC;AACvC,MAAM,WAAW,sBAAsB;IACtC,IAAI,EAAE,UAAU,CAAC;IACjB,WAAW,EAAE,sBAAsB,CAAC;IACpC,kEAAkE;IAClE,OAAO,CAAC,EAAE,sBAAsB,CAAC;IACjC;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,kBAAkB,CAAC;CAC1C;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,GAC7B,SAAS,sBAAsB,KAC7B,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,CAgB7C,CAAC;AA2DF;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACpC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,cAAc,CAAC,EAAE,aAAa,CAAC;CAC/B"}
1
+ {"version":3,"file":"rpc_client.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/rpc_client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,yBAAyB,CAAC;AAOpE,OAAO,KAAK,EAAC,UAAU,EAAE,qBAAqB,EAAC,MAAM,kBAAkB,CAAC;AACxE,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAGnD;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,aAAa,GAAG,SAAS,CAAC;AAM/E,8EAA8E;AAC9E,MAAM,WAAW,sBAAsB;IACtC,aAAa,EAAE,CAAC,IAAI,EAAE;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,oBAAoB,CAAA;KAAC,KAC5E;QACA,sBAAsB,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;KAC5C,GACD,SAAS,CAAC;CACb;AAED,uCAAuC;AACvC,MAAM,WAAW,sBAAsB;IACtC,IAAI,EAAE,UAAU,CAAC;IACjB,WAAW,EAAE,sBAAsB,CAAC;IACpC,kEAAkE;IAClE,OAAO,CAAC,EAAE,sBAAsB,CAAC;IACjC;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,kBAAkB,CAAC;CAC1C;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,GAC7B,SAAS,sBAAsB,KAC7B,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,CAgB7C,CAAC;AA2DF;;;;;GAKG;AACH,MAAM,WAAW,oBAAqB,SAAQ,qBAAqB;CAAG"}
@@ -127,6 +127,7 @@ const create_request_response_method = (peer, environment, spec, actions, transp
127
127
  const response = await peer.send(event.data.request, {
128
128
  transport_name: options?.transport_name ?? transport_for_method?.(spec.method),
129
129
  signal: options?.signal,
130
+ queue: options?.queue,
130
131
  });
131
132
  event.transition('receive_response');
132
133
  // TODO @api shouldn't this happen in the peer like the other method calls?
@@ -155,6 +156,7 @@ const create_remote_notification_method = (peer, environment, spec, actions, tra
155
156
  const send_result = await peer.send(event.data.notification, {
156
157
  transport_name: options?.transport_name ?? transport_for_method?.(spec.method),
157
158
  signal: options?.signal,
159
+ queue: options?.queue,
158
160
  });
159
161
  // Check if notification failed to send
160
162
  if (send_result !== null) {
@@ -218,8 +218,7 @@ export declare class FrontendWebsocketClient implements WebsocketConnection, Dis
218
218
  * id (or uses an explicit one supplied via `options.id` — used by
219
219
  * `FrontendWebsocketTransport` which delegates to this method and has its
220
220
  * own peer-minted UUID), tracks the pending promise, and resolves when the
221
- * server sends a matching response (or rejects on error frame, socket
222
- * close, or aborted signal).
221
+ * server sends a matching response.
223
222
  *
224
223
  * Callers supplying an explicit `options.id` are responsible for
225
224
  * uniqueness — the pending map is keyed by id, and a duplicate silently
@@ -234,10 +233,22 @@ export declare class FrontendWebsocketClient implements WebsocketConnection, Dis
234
233
  * disconnect-detection slot.
235
234
  *
236
235
  * On `AbortSignal` fire: rejects the local promise *and* sends the shared
237
- * `cancel` notification (`CANCEL_METHOD`) so the server-side dispatcher
238
- * can abort the matching handler's `ctx.signal`. Suppressed for
239
- * queued-but-never-sent (server doesn't know about it) and
236
+ * `cancel` notification ({@link CANCEL_METHOD}) so the server-side
237
+ * dispatcher can abort the matching handler's `ctx.signal`. Suppressed
238
+ * for queued-but-never-sent (server doesn't know about it) and
240
239
  * response-beat-cancel races.
240
+ *
241
+ * Rejections throw `ThrownJsonrpcError` with a specific code so
242
+ * `FrontendWebsocketTransport` can preserve the code verbatim in its
243
+ * error envelope rather than collapsing every rejection to
244
+ * `internal_error`:
245
+ * - `unauthenticated` — session revoked (entry check or close code);
246
+ * - `request_cancelled` — caller's `AbortSignal` fired;
247
+ * - `queue_overflow` — durable queue full;
248
+ * - `service_unavailable` — socket not connected / closed / torn down
249
+ * mid-flight;
250
+ * - `internal_error` — `ws.send` threw (serialization, buffer full);
251
+ * - server's wire code verbatim — JSON-RPC error frame from peer.
241
252
  */
242
253
  request<R = unknown>(method: string, params?: unknown, options?: {
243
254
  signal?: AbortSignal;
@@ -1 +1 @@
1
- {"version":3,"file":"socket.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/socket.svelte.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"socket.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/socket.svelte.ts"],"names":[],"mappings":"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"}
@@ -25,6 +25,7 @@
25
25
  */
26
26
  import { BROWSER } from 'esm-env';
27
27
  import { JSONRPC_VERSION } from '../http/jsonrpc.js';
28
+ import { JSONRPC_ERROR_CODES, ThrownJsonrpcError, jsonrpc_errors } from '../http/jsonrpc_errors.js';
28
29
  import { WS_CLOSE_CLIENT_HEARTBEAT_TIMEOUT, WS_CLOSE_SESSION_REVOKED } from './transports.js';
29
30
  import { CANCEL_METHOD } from './cancel.js';
30
31
  import { HEARTBEAT_METHOD } from './heartbeat.js';
@@ -273,7 +274,7 @@ export class FrontendWebsocketClient {
273
274
  this.#teardown(code);
274
275
  this.status = 'closed';
275
276
  this.#reset_reconnect_counters();
276
- this.#reject_all('client disconnected');
277
+ this.#reject_all('client disconnected', jsonrpc_errors.service_unavailable);
277
278
  }
278
279
  /** Explicit-resource-management hook — supports `using client = new FrontendWebsocketClient(url)`. */
279
280
  [Symbol.dispose]() {
@@ -299,8 +300,7 @@ export class FrontendWebsocketClient {
299
300
  * id (or uses an explicit one supplied via `options.id` — used by
300
301
  * `FrontendWebsocketTransport` which delegates to this method and has its
301
302
  * own peer-minted UUID), tracks the pending promise, and resolves when the
302
- * server sends a matching response (or rejects on error frame, socket
303
- * close, or aborted signal).
303
+ * server sends a matching response.
304
304
  *
305
305
  * Callers supplying an explicit `options.id` are responsible for
306
306
  * uniqueness — the pending map is keyed by id, and a duplicate silently
@@ -315,17 +315,29 @@ export class FrontendWebsocketClient {
315
315
  * disconnect-detection slot.
316
316
  *
317
317
  * On `AbortSignal` fire: rejects the local promise *and* sends the shared
318
- * `cancel` notification (`CANCEL_METHOD`) so the server-side dispatcher
319
- * can abort the matching handler's `ctx.signal`. Suppressed for
320
- * queued-but-never-sent (server doesn't know about it) and
318
+ * `cancel` notification ({@link CANCEL_METHOD}) so the server-side
319
+ * dispatcher can abort the matching handler's `ctx.signal`. Suppressed
320
+ * for queued-but-never-sent (server doesn't know about it) and
321
321
  * response-beat-cancel races.
322
+ *
323
+ * Rejections throw `ThrownJsonrpcError` with a specific code so
324
+ * `FrontendWebsocketTransport` can preserve the code verbatim in its
325
+ * error envelope rather than collapsing every rejection to
326
+ * `internal_error`:
327
+ * - `unauthenticated` — session revoked (entry check or close code);
328
+ * - `request_cancelled` — caller's `AbortSignal` fired;
329
+ * - `queue_overflow` — durable queue full;
330
+ * - `service_unavailable` — socket not connected / closed / torn down
331
+ * mid-flight;
332
+ * - `internal_error` — `ws.send` threw (serialization, buffer full);
333
+ * - server's wire code verbatim — JSON-RPC error frame from peer.
322
334
  */
323
335
  request(method, params = {}, options = {}) {
324
336
  return new Promise((resolve, reject) => {
325
337
  const resolve_typed = resolve;
326
338
  const reject_typed = reject;
327
339
  if (this.#revoked) {
328
- reject_typed(new Error('[socket] session revoked'));
340
+ reject_typed(jsonrpc_errors.unauthenticated('[socket] session revoked'));
329
341
  return;
330
342
  }
331
343
  const { signal = null } = options;
@@ -378,7 +390,7 @@ export class FrontendWebsocketClient {
378
390
  return;
379
391
  }
380
392
  this.#detach_signal(pending);
381
- reject_typed(new Error(`[socket] send failed for ${method}`));
393
+ reject_typed(jsonrpc_errors.internal_error(`[socket] send failed for ${method}`));
382
394
  return;
383
395
  }
384
396
  if (should_queue) {
@@ -386,7 +398,7 @@ export class FrontendWebsocketClient {
386
398
  return;
387
399
  }
388
400
  this.#detach_signal(pending);
389
- reject_typed(new Error(`[socket] not connected (method=${method})`));
401
+ reject_typed(jsonrpc_errors.service_unavailable(`[socket] not connected (method=${method})`));
390
402
  });
391
403
  }
392
404
  add_message_handler(handler) {
@@ -398,7 +410,7 @@ export class FrontendWebsocketClient {
398
410
  return () => this.#error_handlers.delete(handler);
399
411
  }
400
412
  #build_abort_error(method) {
401
- return new Error(`[socket] request aborted (method=${method})`);
413
+ return jsonrpc_errors.request_cancelled(`[socket] request aborted (method=${method})`);
402
414
  }
403
415
  /**
404
416
  * Fire-and-forget cancel notification to the server. The dispatcher
@@ -421,7 +433,7 @@ export class FrontendWebsocketClient {
421
433
  #enqueue(queued) {
422
434
  if (this.#queue.length >= this.#queue_max_size) {
423
435
  this.#detach_signal(queued);
424
- queued.reject(new Error(`[socket] request queue overflow (method=${queued.method}, max=${this.#queue_max_size})`));
436
+ queued.reject(jsonrpc_errors.queue_overflow(`[socket] request queue overflow (method=${queued.method}, max=${this.#queue_max_size})`));
425
437
  return;
426
438
  }
427
439
  this.#queue.push(queued);
@@ -454,25 +466,25 @@ export class FrontendWebsocketClient {
454
466
  }
455
467
  else {
456
468
  this.#detach_signal(q);
457
- q.reject(new Error(`[socket] queued request send failed (method=${q.method})`));
469
+ q.reject(jsonrpc_errors.internal_error(`[socket] queued request send failed (method=${q.method})`));
458
470
  }
459
471
  }
460
472
  }
461
- #reject_all(reason) {
473
+ #reject_all(reason, make_error) {
462
474
  const pending = this.#pending;
463
475
  this.#pending = new Map();
464
476
  for (const [id, p] of pending) {
465
477
  this.#detach_signal(p);
466
- p.reject(new Error(`[socket] ${reason} (method=${p.method}, id=${id})`));
478
+ p.reject(make_error(`[socket] ${reason} (method=${p.method}, id=${id})`));
467
479
  }
468
480
  const queued = this.#queue;
469
481
  this.#queue = [];
470
482
  for (const q of queued) {
471
483
  this.#detach_signal(q);
472
- q.reject(new Error(`[socket] ${reason} (method=${q.method})`));
484
+ q.reject(make_error(`[socket] ${reason} (method=${q.method})`));
473
485
  }
474
486
  }
475
- #reject_pending_only(reason) {
487
+ #reject_pending_only(reason, make_error) {
476
488
  // Socket closed but auto-reconnect will try again — pending requests were
477
489
  // in flight on the old socket so we can't correlate them after reopen;
478
490
  // queued requests haven't been sent yet and stay buffered for the flush.
@@ -480,7 +492,7 @@ export class FrontendWebsocketClient {
480
492
  this.#pending = new Map();
481
493
  for (const [id, p] of pending) {
482
494
  this.#detach_signal(p);
483
- p.reject(new Error(`[socket] ${reason} (method=${p.method}, id=${id})`));
495
+ p.reject(make_error(`[socket] ${reason} (method=${p.method}, id=${id})`));
484
496
  }
485
497
  }
486
498
  #start_heartbeat() {
@@ -547,7 +559,7 @@ export class FrontendWebsocketClient {
547
559
  // record it here so the client-initiated close is still observable,
548
560
  // and reject any pending requests that can never resolve now.
549
561
  this.#record_close(close_code, '');
550
- this.#reject_pending_only(`socket torn down (code ${close_code})`);
562
+ this.#reject_pending_only(`socket torn down (code ${close_code})`, jsonrpc_errors.service_unavailable);
551
563
  }
552
564
  this.ws = null;
553
565
  }
@@ -603,12 +615,12 @@ export class FrontendWebsocketClient {
603
615
  this.status = 'closed';
604
616
  this.#cancel_reconnect();
605
617
  this.#reset_reconnect_counters();
606
- this.#reject_all('session revoked');
618
+ this.#reject_all('session revoked', jsonrpc_errors.unauthenticated);
607
619
  return;
608
620
  }
609
621
  // Pending in-flight requests can't be correlated post-reconnect; reject
610
622
  // them. Queue stays so the flush on reopen replays unsent work.
611
- this.#reject_pending_only(`connection closed (code ${event.code})`);
623
+ this.#reject_pending_only(`connection closed (code ${event.code})`, jsonrpc_errors.service_unavailable);
612
624
  // Let `#schedule_reconnect` set `status: 'reconnecting'` directly to avoid
613
625
  // a transient `'closed'` flicker; only set `'closed'` when reconnect is off.
614
626
  if (this.#auto_reconnect) {
@@ -616,7 +628,7 @@ export class FrontendWebsocketClient {
616
628
  }
617
629
  else {
618
630
  this.status = 'closed';
619
- this.#reject_all('connection closed, auto-reconnect disabled');
631
+ this.#reject_all('connection closed, auto-reconnect disabled', jsonrpc_errors.service_unavailable);
620
632
  }
621
633
  };
622
634
  #handle_error = (event) => {
@@ -656,7 +668,16 @@ export class FrontendWebsocketClient {
656
668
  this.#detach_signal(pending);
657
669
  if ('error' in json && json.error) {
658
670
  const err = json.error;
659
- pending.reject(new Error(`[rpc ${pending.method} #${id}] ${err.code ?? '?'} ${err.message ?? 'unknown error'}`));
671
+ // Preserve the server's wire code verbatim so the transport's
672
+ // catch block re-emits the same code in its envelope. Fall
673
+ // back to `internal_error` only when the frame is malformed.
674
+ const wire_code = typeof err.code === 'number'
675
+ ? err.code
676
+ : JSONRPC_ERROR_CODES.internal_error;
677
+ const wire_message = typeof err.message === 'string' && err.message.length > 0
678
+ ? err.message
679
+ : 'unknown error';
680
+ pending.reject(new ThrownJsonrpcError(wire_code, wire_message, err.data));
660
681
  }
661
682
  else {
662
683
  pending.resolve(json.result);
@@ -18,14 +18,31 @@ export declare const TransportName: z.ZodString;
18
18
  export type TransportName = z.infer<typeof TransportName>;
19
19
  /**
20
20
  * Per-call options accepted by every transport's `send`. Optional and
21
- * extensible — adding a field is non-breaking. Today: an `AbortSignal`
22
- * for cancellation that bottoms out at `FrontendWebsocketClient.request`
23
- * (which sends the shared `cancel` notification on abort) and at
24
- * `fetch({signal})` for HTTP. Backend transport receives the option but
25
- * has no per-call abort surface to honor.
21
+ * extensible — adding a field is non-breaking. Source of truth for the
22
+ * shared option shape; `ActionPeerSendOptions` and `RpcClientCallOptions`
23
+ * extend it.
26
24
  */
27
25
  export interface TransportSendOptions {
26
+ /**
27
+ * Per-call cancellation. Bottoms out at
28
+ * `FrontendWebsocketClient.request({signal})` on the WS path (sends the
29
+ * shared `cancel` notification on abort) and at `fetch({signal})` on
30
+ * HTTP. Backend transport has no per-call abort surface to honor.
31
+ */
28
32
  signal?: AbortSignal;
33
+ /**
34
+ * Per-call durable-queue opt-in. Names the **client-authoritative vs
35
+ * server-authoritative** distinction — server-authoritative consumers
36
+ * (e.g. zzz completion calls) fail fast with `service_unavailable` when
37
+ * the transport is down; client-authoritative consumers (games,
38
+ * real-time apps) buffer and replay on reconnect because the user
39
+ * already committed to the action at click time. Honored only by
40
+ * `FrontendWebsocketTransport` on the `request_response` path (default
41
+ * `false`). HTTP and backend transports ignore it; WS notifications
42
+ * also ignore it and always fail-fast when disconnected (fire-and-forget
43
+ * `connection.send` has no queue semantic).
44
+ */
45
+ queue?: boolean;
29
46
  }
30
47
  export interface Transport {
31
48
  transport_name: TransportName;
@@ -1 +1 @@
1
- {"version":3,"file":"transports.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/transports.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EACX,gCAAgC,EAChC,gCAAgC,EAChC,mBAAmB,EACnB,cAAc,EACd,sBAAsB,EACtB,oBAAoB,EACpB,MAAM,oBAAoB,CAAC;AAE5B,mDAAmD;AACnD,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAC7C,sEAAsE;AACtE,eAAO,MAAM,iCAAiC,OAAO,CAAC;AACtD,yEAAyE;AACzE,eAAO,MAAM,iCAAiC,OAAO,CAAC;AAKtD,eAAO,MAAM,aAAa,aAAa,CAAC;AACxC,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAE1D;;;;;;;GAOG;AACH,MAAM,WAAW,oBAAoB;IACpC,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACzB,cAAc,EAAE,aAAa,CAAC;IAE9B,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAC/F,IAAI,CACH,OAAO,EAAE,mBAAmB,EAC5B,OAAO,CAAC,EAAE,oBAAoB,GAC5B,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;IACxC,IAAI,CACH,OAAO,EAAE,gCAAgC,EACzC,OAAO,CAAC,EAAE,oBAAoB,GAC5B,OAAO,CAAC,gCAAgC,GAAG,IAAI,CAAC,CAAC;IACpD,QAAQ,EAAE,MAAM,OAAO,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,qBAAa,UAAU;;IAItB;;;OAGG;IACH,cAAc,EAAE,OAAO,CAAQ;IAE/B;;OAEG;IACH,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAS9C,qBAAqB,CAAC,cAAc,EAAE,aAAa,GAAG,IAAI;IAM1D;;;;;OAKG;IACH,aAAa,CAAC,cAAc,CAAC,EAAE,aAAa,GAAG,SAAS,GAAG,IAAI;IAO/D,QAAQ,IAAI,OAAO,GAAG,IAAI;IAM1B,qBAAqB,IAAI,SAAS,GAAG,IAAI;IAIzC,0BAA0B,IAAI,aAAa,GAAG,IAAI;IAIlD,qBAAqB,CAAC,cAAc,EAAE,aAAa,GAAG,SAAS,GAAG,IAAI;CAqDtE"}
1
+ {"version":3,"file":"transports.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/transports.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EACX,gCAAgC,EAChC,gCAAgC,EAChC,mBAAmB,EACnB,cAAc,EACd,sBAAsB,EACtB,oBAAoB,EACpB,MAAM,oBAAoB,CAAC;AAE5B,mDAAmD;AACnD,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAC7C,sEAAsE;AACtE,eAAO,MAAM,iCAAiC,OAAO,CAAC;AACtD,yEAAyE;AACzE,eAAO,MAAM,iCAAiC,OAAO,CAAC;AAKtD,eAAO,MAAM,aAAa,aAAa,CAAC;AACxC,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAE1D;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACpC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IACzB,cAAc,EAAE,aAAa,CAAC;IAE9B,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAC/F,IAAI,CACH,OAAO,EAAE,mBAAmB,EAC5B,OAAO,CAAC,EAAE,oBAAoB,GAC5B,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;IACxC,IAAI,CACH,OAAO,EAAE,gCAAgC,EACzC,OAAO,CAAC,EAAE,oBAAoB,GAC5B,OAAO,CAAC,gCAAgC,GAAG,IAAI,CAAC,CAAC;IACpD,QAAQ,EAAE,MAAM,OAAO,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,qBAAa,UAAU;;IAItB;;;OAGG;IACH,cAAc,EAAE,OAAO,CAAQ;IAE/B;;OAEG;IACH,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAS9C,qBAAqB,CAAC,cAAc,EAAE,aAAa,GAAG,IAAI;IAM1D;;;;;OAKG;IACH,aAAa,CAAC,cAAc,CAAC,EAAE,aAAa,GAAG,SAAS,GAAG,IAAI;IAO/D,QAAQ,IAAI,OAAO,GAAG,IAAI;IAM1B,qBAAqB,IAAI,SAAS,GAAG,IAAI;IAIzC,0BAA0B,IAAI,aAAa,GAAG,IAAI;IAIlD,qBAAqB,CAAC,cAAc,EAAE,aAAa,GAAG,SAAS,GAAG,IAAI;CAqDtE"}
@@ -1 +1 @@
1
- {"version":3,"file":"transports_ws.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/transports_ws.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAWH,OAAO,KAAK,EAGX,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,oBAAoB,EACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAC,SAAS,EAAE,oBAAoB,EAAC,MAAM,iBAAiB,CAAC;AAIrE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,mBAAmB,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IAC5E,iBAAiB,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;CACnE;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,sBAAuB,SAAQ,mBAAmB;IAClE,OAAO,EAAE,CACR,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,EACf,OAAO,CAAC,EAAE;QAAC,MAAM,CAAC,EAAE,WAAW,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,EAAE,CAAC,EAAE,gBAAgB,CAAA;KAAC,KACpE,OAAO,CAAC,OAAO,CAAC,CAAC;CACtB;AAED,qBAAa,0BAA2B,YAAW,SAAS;;IAC3D,QAAQ,CAAC,cAAc,EAAG,wBAAwB,CAAU;gBAOhD,UAAU,EAAE,sBAAsB,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC;IAyBtF,IAAI,CACT,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE,oBAAoB,GAC5B,OAAO,CAAC,sBAAsB,CAAC;IAC5B,IAAI,CACT,OAAO,EAAE,mBAAmB,EAC5B,OAAO,CAAC,EAAE,oBAAoB,GAC5B,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IAoDvC,QAAQ,IAAI,OAAO;IAInB,OAAO,IAAI,IAAI;CAUf"}
1
+ {"version":3,"file":"transports_ws.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/transports_ws.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAWH,OAAO,KAAK,EAGX,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,oBAAoB,EACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAC,SAAS,EAAE,oBAAoB,EAAC,MAAM,iBAAiB,CAAC;AAIrE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,mBAAmB,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IAC5E,iBAAiB,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;CACnE;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,sBAAuB,SAAQ,mBAAmB;IAClE,OAAO,EAAE,CACR,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,EACf,OAAO,CAAC,EAAE;QAAC,MAAM,CAAC,EAAE,WAAW,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,EAAE,CAAC,EAAE,gBAAgB,CAAA;KAAC,KACpE,OAAO,CAAC,OAAO,CAAC,CAAC;CACtB;AAED,qBAAa,0BAA2B,YAAW,SAAS;;IAC3D,QAAQ,CAAC,cAAc,EAAG,wBAAwB,CAAU;gBAOhD,UAAU,EAAE,sBAAsB,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC;IAyBtF,IAAI,CACT,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE,oBAAoB,GAC5B,OAAO,CAAC,sBAAsB,CAAC;IAC5B,IAAI,CACT,OAAO,EAAE,mBAAmB,EAC5B,OAAO,CAAC,EAAE,oBAAoB,GAC5B,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IA4DvC,QAAQ,IAAI,OAAO;IAInB,OAAO,IAAI,IAAI;CAUf"}
@@ -42,11 +42,19 @@ export class FrontendWebsocketTransport {
42
42
  });
43
43
  }
44
44
  async send(message, options) {
45
- // Fail-fast at the transport boundary. The connection's own queue
46
- // would buffer the request and flush on reconnect; that's the right
47
- // default for direct `client.request()` callers but the typed Proxy
48
- // path expects "service unavailable" semantics when the WS is down.
49
- if (!this.is_ready()) {
45
+ // Notifications fail-fast when disconnected regardless of `queue`
46
+ // `connection.send()` is fire-and-forget with no queue semantic, so
47
+ // silently dropping would masquerade as success at the rpc_client
48
+ // layer (caller would see `{ok: true}` for a lost message).
49
+ //
50
+ // Requests have no such gate here: `connection.request()` throws
51
+ // `ThrownJsonrpcError` with the right code (`service_unavailable`
52
+ // when not connected, `queue_overflow` when the durable queue is
53
+ // full, `request_cancelled` on abort, server's wire code for peer
54
+ // error frames), and the catch block below preserves that code
55
+ // verbatim in the error envelope. Queuing is routed via `queue`.
56
+ const queue = options?.queue ?? false;
57
+ if (is_jsonrpc_notification(message) && !this.is_ready()) {
50
58
  return create_jsonrpc_error_response(to_jsonrpc_message_id(message), jsonrpc_error_messages.service_unavailable('WebSocket not connected'));
51
59
  }
52
60
  if (is_jsonrpc_request(message)) {
@@ -54,7 +62,7 @@ export class FrontendWebsocketTransport {
54
62
  const result = await this.#connection.request(message.method, message.params, {
55
63
  id: message.id,
56
64
  signal: options?.signal,
57
- queue: false,
65
+ queue,
58
66
  });
59
67
  return create_jsonrpc_response(message.id, to_jsonrpc_result(result));
60
68
  }
@@ -91,6 +91,21 @@ export declare class BackendWebsocketTransport implements FilterableBroadcastTra
91
91
  * @returns the number of sockets the message was sent to
92
92
  */
93
93
  broadcast_filtered(message: JsonrpcMessageFromServerToClient, predicate: (identity: ConnectionIdentity) => boolean): number;
94
+ /**
95
+ * Send a message to every socket bound to a specific account.
96
+ *
97
+ * Targeted per-account fan-out for any flow where the delivery target
98
+ * is a single known account. Prefer this over `broadcast_filtered` when
99
+ * the filter is exactly "this account_id"; reach for `broadcast_filtered`
100
+ * when the ACL is an arbitrary predicate over `ConnectionIdentity`.
101
+ *
102
+ * Mirrors `close_sockets_for_account` on the send side: every connection
103
+ * for the account (session, bearer, and daemon-token) receives the
104
+ * message.
105
+ *
106
+ * @returns the number of sockets the message was sent to
107
+ */
108
+ send_to_account(account_id: Uuid, message: JsonrpcMessageFromServerToClient): number;
94
109
  is_ready(): boolean;
95
110
  /**
96
111
  * Number of currently tracked WebSocket connections.
@@ -1 +1 @@
1
- {"version":3,"file":"transports_ws_backend.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/transports_ws_backend.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,SAAS,CAAC;AAEvC,OAAO,KAAK,EAEX,gCAAgC,EAChC,mBAAmB,EACnB,cAAc,EACd,sBAAsB,EACtB,oBAAoB,EACpB,MAAM,oBAAoB,CAAC;AAO5B,OAAO,EAAc,KAAK,IAAI,EAAC,MAAM,YAAY,CAAC;AAClD,OAAO,EAA2B,KAAK,SAAS,EAAE,KAAK,oBAAoB,EAAC,MAAM,iBAAiB,CAAC;AAIpG;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IAClC,sEAAsE;IACtE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,4CAA4C;IAC5C,UAAU,EAAE,IAAI,CAAC;IACjB,sEAAsE;IACtE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,4BAA6B,SAAQ,SAAS;IAC9D,kBAAkB,EAAE,CACnB,OAAO,EAAE,gCAAgC,EACzC,SAAS,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,OAAO,KAChD,MAAM,CAAC;CACZ;AAED,qDAAqD;AACrD,eAAO,MAAM,iCAAiC,GAC7C,WAAW,SAAS,KAClB,SAAS,IAAI,4BAEqE,CAAC;AAEtF,qBAAa,yBAA0B,YAAW,4BAA4B;;IAC7E,QAAQ,CAAC,cAAc,EAAG,uBAAuB,CAAU;IAY3D;;;;;;;;OAQG;IACH,cAAc,CACb,EAAE,EAAE,SAAS,EACb,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,UAAU,EAAE,IAAI,EAChB,YAAY,GAAE,MAAM,GAAG,IAAW,GAChC,IAAI;IAQP;;;OAGG;IACH,iBAAiB,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI;IA0BtC;;;;OAIG;IACH,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAIrD;;;;OAIG;IACH,yBAAyB,CAAC,UAAU,EAAE,IAAI,GAAG,MAAM;IAInD;;;;;;;;OAQG;IACH,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAsB/C,IAAI,CACT,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE,oBAAoB,GAC5B,OAAO,CAAC,sBAAsB,CAAC;IAC5B,IAAI,CACT,OAAO,EAAE,mBAAmB,EAC5B,OAAO,CAAC,EAAE,oBAAoB,GAC5B,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IA6CvC;;;;;;;;;OASG;IACH,kBAAkB,CACjB,OAAO,EAAE,gCAAgC,EACzC,SAAS,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,OAAO,GAClD,MAAM;IAoBT,QAAQ,IAAI,OAAO;IAInB;;;;;;;OAOG;IACH,oBAAoB,IAAI,MAAM;CAG9B"}
1
+ {"version":3,"file":"transports_ws_backend.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/transports_ws_backend.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,SAAS,CAAC;AAEvC,OAAO,KAAK,EAEX,gCAAgC,EAChC,mBAAmB,EACnB,cAAc,EACd,sBAAsB,EACtB,oBAAoB,EACpB,MAAM,oBAAoB,CAAC;AAO5B,OAAO,EAAc,KAAK,IAAI,EAAC,MAAM,YAAY,CAAC;AAClD,OAAO,EAA2B,KAAK,SAAS,EAAE,KAAK,oBAAoB,EAAC,MAAM,iBAAiB,CAAC;AAIpG;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IAClC,sEAAsE;IACtE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,4CAA4C;IAC5C,UAAU,EAAE,IAAI,CAAC;IACjB,sEAAsE;IACtE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,4BAA6B,SAAQ,SAAS;IAC9D,kBAAkB,EAAE,CACnB,OAAO,EAAE,gCAAgC,EACzC,SAAS,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,OAAO,KAChD,MAAM,CAAC;CACZ;AAED,qDAAqD;AACrD,eAAO,MAAM,iCAAiC,GAC7C,WAAW,SAAS,KAClB,SAAS,IAAI,4BAEqE,CAAC;AAEtF,qBAAa,yBAA0B,YAAW,4BAA4B;;IAC7E,QAAQ,CAAC,cAAc,EAAG,uBAAuB,CAAU;IAY3D;;;;;;;;OAQG;IACH,cAAc,CACb,EAAE,EAAE,SAAS,EACb,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,UAAU,EAAE,IAAI,EAChB,YAAY,GAAE,MAAM,GAAG,IAAW,GAChC,IAAI;IAQP;;;OAGG;IACH,iBAAiB,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI;IA0BtC;;;;OAIG;IACH,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAIrD;;;;OAIG;IACH,yBAAyB,CAAC,UAAU,EAAE,IAAI,GAAG,MAAM;IAInD;;;;;;;;OAQG;IACH,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAsB/C,IAAI,CACT,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE,oBAAoB,GAC5B,OAAO,CAAC,sBAAsB,CAAC;IAC5B,IAAI,CACT,OAAO,EAAE,mBAAmB,EAC5B,OAAO,CAAC,EAAE,oBAAoB,GAC5B,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IA6CvC;;;;;;;;;OASG;IACH,kBAAkB,CACjB,OAAO,EAAE,gCAAgC,EACzC,SAAS,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,OAAO,GAClD,MAAM;IAoBT;;;;;;;;;;;;;OAaG;IACH,eAAe,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,gCAAgC,GAAG,MAAM;IAIpF,QAAQ,IAAI,OAAO;IAInB;;;;;;;OAOG;IACH,oBAAoB,IAAI,MAAM;CAG9B"}
@@ -167,6 +167,23 @@ export class BackendWebsocketTransport {
167
167
  }
168
168
  return count;
169
169
  }
170
+ /**
171
+ * Send a message to every socket bound to a specific account.
172
+ *
173
+ * Targeted per-account fan-out for any flow where the delivery target
174
+ * is a single known account. Prefer this over `broadcast_filtered` when
175
+ * the filter is exactly "this account_id"; reach for `broadcast_filtered`
176
+ * when the ACL is an arbitrary predicate over `ConnectionIdentity`.
177
+ *
178
+ * Mirrors `close_sockets_for_account` on the send side: every connection
179
+ * for the account (session, bearer, and daemon-token) receives the
180
+ * message.
181
+ *
182
+ * @returns the number of sockets the message was sent to
183
+ */
184
+ send_to_account(account_id, message) {
185
+ return this.broadcast_filtered(message, (id) => id.account_id === account_id);
186
+ }
170
187
  is_ready() {
171
188
  return this.#connections.size > 0;
172
189
  }
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Provides error types, named constructors, and HTTP status mapping
5
5
  * for the throw/catch error pattern used by `apply_route_specs`.
6
- * Core error codes (5 standard + 8 general application). Domain-specific
6
+ * Core error codes (5 standard + 10 general application). Domain-specific
7
7
  * codes stay in consumers — add by casting `as JsonrpcErrorCode`.
8
8
  *
9
9
  * `JsonrpcErrorCode` and `JsonrpcErrorObject` types are Zod-inferred
@@ -20,9 +20,9 @@ import { type JsonrpcErrorCode, type JsonrpcErrorObject } from './jsonrpc.js';
20
20
  /** Default message for unknown errors. */
21
21
  export declare const UNKNOWN_ERROR_MESSAGE = "unknown error";
22
22
  /** Names of standard and general application JSON-RPC error codes. */
23
- export type JsonrpcErrorName = 'parse_error' | 'invalid_request' | 'method_not_found' | 'invalid_params' | 'internal_error' | 'unauthenticated' | 'forbidden' | 'not_found' | 'conflict' | 'validation_error' | 'rate_limited' | 'service_unavailable' | 'timeout';
23
+ export type JsonrpcErrorName = 'parse_error' | 'invalid_request' | 'method_not_found' | 'invalid_params' | 'internal_error' | 'unauthenticated' | 'forbidden' | 'not_found' | 'conflict' | 'validation_error' | 'rate_limited' | 'service_unavailable' | 'timeout' | 'queue_overflow' | 'request_cancelled';
24
24
  /**
25
- * Standard JSON-RPC error codes (5) plus general application codes (8).
25
+ * Standard JSON-RPC error codes (5) plus general application codes (10).
26
26
  *
27
27
  * Extensible — consumers add domain-specific codes to their own objects
28
28
  * by casting `as JsonrpcErrorCode`. Application codes use the -32000 to
@@ -55,6 +55,18 @@ export declare const JSONRPC_ERROR_CODES: {
55
55
  readonly rate_limited: JsonrpcErrorCode;
56
56
  readonly service_unavailable: JsonrpcErrorCode;
57
57
  readonly timeout: JsonrpcErrorCode;
58
+ /**
59
+ * Client-side backpressure — an outbound buffer (e.g. `FrontendWebsocketClient`'s
60
+ * disconnected request queue) refused a new request because it was full.
61
+ * Distinct from `rate_limited`, which signals a server-side policy.
62
+ */
63
+ readonly queue_overflow: JsonrpcErrorCode;
64
+ /**
65
+ * Caller-initiated cancellation (e.g. `AbortSignal` fired). Cooperative,
66
+ * not a failure — the request did not complete because the caller asked
67
+ * for it to stop.
68
+ */
69
+ readonly request_cancelled: JsonrpcErrorCode;
58
70
  };
59
71
  /**
60
72
  * Named constructors for `JsonrpcErrorObject` values.
@@ -77,6 +89,8 @@ export declare const jsonrpc_error_messages: {
77
89
  readonly rate_limited: (message?: string, data?: unknown) => JsonrpcErrorObject;
78
90
  readonly service_unavailable: (message?: string, data?: unknown) => JsonrpcErrorObject;
79
91
  readonly timeout: (message?: string, data?: unknown) => JsonrpcErrorObject;
92
+ readonly queue_overflow: (message?: string, data?: unknown) => JsonrpcErrorObject;
93
+ readonly request_cancelled: (message?: string, data?: unknown) => JsonrpcErrorObject;
80
94
  };
81
95
  /**
82
96
  * Error class carrying a JSON-RPC error code — thrown by handlers,
@@ -108,6 +122,8 @@ export declare const jsonrpc_errors: {
108
122
  readonly rate_limited: (message?: string | undefined, data?: unknown) => ThrownJsonrpcError;
109
123
  readonly service_unavailable: (message?: string | undefined, data?: unknown) => ThrownJsonrpcError;
110
124
  readonly timeout: (message?: string | undefined, data?: unknown) => ThrownJsonrpcError;
125
+ readonly queue_overflow: (message?: string | undefined, data?: unknown) => ThrownJsonrpcError;
126
+ readonly request_cancelled: (message?: string | undefined, data?: unknown) => ThrownJsonrpcError;
111
127
  };
112
128
  /**
113
129
  * Maps JSON-RPC error codes to HTTP status codes.
@@ -1 +1 @@
1
- {"version":3,"file":"jsonrpc_errors.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/jsonrpc_errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAMN,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,MAAM,cAAc,CAAC;AAEtB,0CAA0C;AAC1C,eAAO,MAAM,qBAAqB,kBAAkB,CAAC;AAErD,sEAAsE;AACtE,MAAM,MAAM,gBAAgB,GACzB,aAAa,GACb,iBAAiB,GACjB,kBAAkB,GAClB,gBAAgB,GAChB,gBAAgB,GAChB,iBAAiB,GACjB,WAAW,GACX,WAAW,GACX,UAAU,GACV,kBAAkB,GAClB,cAAc,GACd,qBAAqB,GACrB,SAAS,CAAC;AAEb;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB;0BAEK,gBAAgB;8BACR,gBAAgB;+BACd,gBAAgB;6BACpB,gBAAgB;6BAChB,gBAAgB;IAG1D;;;;OAIG;8BACwB,gBAAgB;IAC3C;;;OAGG;wBACkB,gBAAgB;wBAChB,gBAAgB;uBACjB,gBAAgB;IACpC;;;OAGG;+BACyB,gBAAgB;2BACpB,gBAAgB;kCACT,gBAAgB;sBAC5B,gBAAgB;CAC2B,CAAC;AAEhE;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB;kCACb,OAAO,KAAG,kBAAkB;sCAMxB,OAAO,KAAG,kBAAkB;yCAMzB,MAAM,SAAS,OAAO,KAAG,kBAAkB;wCAM5C,MAAM,SAAS,OAAO,KAAG,kBAAkB;wCAO5D,MAAM,SACR,OAAO,KACZ,kBAAkB;yCAMM,MAAM,SAA6B,OAAO,KAAG,kBAAkB;mCAMrE,MAAM,SAAuB,OAAO,KAAG,kBAAkB;oCAMvD,MAAM,SAAS,OAAO,KAAG,kBAAkB;kCAM9C,MAAM,SAAsB,OAAO,KAAG,kBAAkB;0CAMhD,MAAM,SAA8B,OAAO,KAAG,kBAAkB;sCAMpE,MAAM,SAA0B,OAAO,KAAG,kBAAkB;6CAO1E,MAAM,SACR,OAAO,KACZ,kBAAkB;iCAMF,MAAM,SAAqB,OAAO,KAAG,kBAAkB;CAKe,CAAC;AAE3F;;;;;GAKG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAC5C,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,CAAC,EAAE,OAAO,CAAC;gBAEH,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,YAAY;CAK3F;AAWD;;;;GAIG;AACH,eAAO,MAAM,cAAc;8CAXQ,kBAAkB;kDAAlB,kBAAkB;gFAAlB,kBAAkB;+EAAlB,kBAAkB;+EAAlB,kBAAkB;gFAAlB,kBAAkB;0EAAlB,kBAAkB;2EAAlB,kBAAkB;yEAAlB,kBAAkB;iFAAlB,kBAAkB;6EAAlB,kBAAkB;oFAAlB,kBAAkB;wEAAlB,kBAAkB;CAyBqC,CAAC;AAI3F;;;;;GAKG;AACH,eAAO,MAAM,iCAAiC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAcpE,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,iCAAiC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAMzC,CAAC;AAEvC;;;;;;;;GAQG;AACH,eAAO,MAAM,iCAAiC,GAAI,MAAM,gBAAgB,KAAG,MAClB,CAAC;AAE1D;;;;;;;GAOG;AACH,eAAO,MAAM,iCAAiC,GAAI,QAAQ,MAAM,KAAG,gBACa,CAAC"}
1
+ {"version":3,"file":"jsonrpc_errors.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/jsonrpc_errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAMN,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,MAAM,cAAc,CAAC;AAEtB,0CAA0C;AAC1C,eAAO,MAAM,qBAAqB,kBAAkB,CAAC;AAErD,sEAAsE;AACtE,MAAM,MAAM,gBAAgB,GACzB,aAAa,GACb,iBAAiB,GACjB,kBAAkB,GAClB,gBAAgB,GAChB,gBAAgB,GAChB,iBAAiB,GACjB,WAAW,GACX,WAAW,GACX,UAAU,GACV,kBAAkB,GAClB,cAAc,GACd,qBAAqB,GACrB,SAAS,GACT,gBAAgB,GAChB,mBAAmB,CAAC;AAEvB;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB;0BAEK,gBAAgB;8BACR,gBAAgB;+BACd,gBAAgB;6BACpB,gBAAgB;6BAChB,gBAAgB;IAG1D;;;;OAIG;8BACwB,gBAAgB;IAC3C;;;OAGG;wBACkB,gBAAgB;wBAChB,gBAAgB;uBACjB,gBAAgB;IACpC;;;OAGG;+BACyB,gBAAgB;2BACpB,gBAAgB;kCACT,gBAAgB;sBAC5B,gBAAgB;IACnC;;;;OAIG;6BACuB,gBAAgB;IAC1C;;;;OAIG;gCAC0B,gBAAgB;CACiB,CAAC;AAEhE;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB;kCACb,OAAO,KAAG,kBAAkB;sCAMxB,OAAO,KAAG,kBAAkB;yCAMzB,MAAM,SAAS,OAAO,KAAG,kBAAkB;wCAM5C,MAAM,SAAS,OAAO,KAAG,kBAAkB;wCAO5D,MAAM,SACR,OAAO,KACZ,kBAAkB;yCAMM,MAAM,SAA6B,OAAO,KAAG,kBAAkB;mCAMrE,MAAM,SAAuB,OAAO,KAAG,kBAAkB;oCAMvD,MAAM,SAAS,OAAO,KAAG,kBAAkB;kCAM9C,MAAM,SAAsB,OAAO,KAAG,kBAAkB;0CAMhD,MAAM,SAA8B,OAAO,KAAG,kBAAkB;sCAMpE,MAAM,SAA0B,OAAO,KAAG,kBAAkB;6CAO1E,MAAM,SACR,OAAO,KACZ,kBAAkB;iCAMF,MAAM,SAAqB,OAAO,KAAG,kBAAkB;wCAMhD,MAAM,SAA4B,OAAO,KAAG,kBAAkB;2CAO9E,MAAM,SACR,OAAO,KACZ,kBAAkB;CAKoE,CAAC;AAE3F;;;;;GAKG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAC5C,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,CAAC,EAAE,OAAO,CAAC;gBAEH,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,YAAY;CAK3F;AAWD;;;;GAIG;AACH,eAAO,MAAM,cAAc;8CAXQ,kBAAkB;kDAAlB,kBAAkB;gFAAlB,kBAAkB;+EAAlB,kBAAkB;+EAAlB,kBAAkB;gFAAlB,kBAAkB;0EAAlB,kBAAkB;2EAAlB,kBAAkB;yEAAlB,kBAAkB;iFAAlB,kBAAkB;6EAAlB,kBAAkB;oFAAlB,kBAAkB;wEAAlB,kBAAkB;+EAAlB,kBAAkB;kFAAlB,kBAAkB;CA2BqC,CAAC;AAI3F;;;;;GAKG;AACH,eAAO,MAAM,iCAAiC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAkBpE,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,iCAAiC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAMzC,CAAC;AAEvC;;;;;;;;GAQG;AACH,eAAO,MAAM,iCAAiC,GAAI,MAAM,gBAAgB,KAAG,MAClB,CAAC;AAE1D;;;;;;;GAOG;AACH,eAAO,MAAM,iCAAiC,GAAI,QAAQ,MAAM,KAAG,gBACa,CAAC"}
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Provides error types, named constructors, and HTTP status mapping
5
5
  * for the throw/catch error pattern used by `apply_route_specs`.
6
- * Core error codes (5 standard + 8 general application). Domain-specific
6
+ * Core error codes (5 standard + 10 general application). Domain-specific
7
7
  * codes stay in consumers — add by casting `as JsonrpcErrorCode`.
8
8
  *
9
9
  * `JsonrpcErrorCode` and `JsonrpcErrorObject` types are Zod-inferred
@@ -20,7 +20,7 @@ import { JSONRPC_PARSE_ERROR, JSONRPC_INVALID_REQUEST, JSONRPC_METHOD_NOT_FOUND,
20
20
  /** Default message for unknown errors. */
21
21
  export const UNKNOWN_ERROR_MESSAGE = 'unknown error';
22
22
  /**
23
- * Standard JSON-RPC error codes (5) plus general application codes (8).
23
+ * Standard JSON-RPC error codes (5) plus general application codes (10).
24
24
  *
25
25
  * Extensible — consumers add domain-specific codes to their own objects
26
26
  * by casting `as JsonrpcErrorCode`. Application codes use the -32000 to
@@ -55,6 +55,18 @@ export const JSONRPC_ERROR_CODES = {
55
55
  rate_limited: -32006,
56
56
  service_unavailable: -32007,
57
57
  timeout: -32008,
58
+ /**
59
+ * Client-side backpressure — an outbound buffer (e.g. `FrontendWebsocketClient`'s
60
+ * disconnected request queue) refused a new request because it was full.
61
+ * Distinct from `rate_limited`, which signals a server-side policy.
62
+ */
63
+ queue_overflow: -32009,
64
+ /**
65
+ * Caller-initiated cancellation (e.g. `AbortSignal` fired). Cooperative,
66
+ * not a failure — the request did not complete because the caller asked
67
+ * for it to stop.
68
+ */
69
+ request_cancelled: -32010,
58
70
  };
59
71
  /**
60
72
  * Named constructors for `JsonrpcErrorObject` values.
@@ -129,6 +141,16 @@ export const jsonrpc_error_messages = {
129
141
  message,
130
142
  data,
131
143
  }),
144
+ queue_overflow: (message = 'queue overflow', data) => ({
145
+ code: JSONRPC_ERROR_CODES.queue_overflow,
146
+ message,
147
+ data,
148
+ }),
149
+ request_cancelled: (message = 'request cancelled', data) => ({
150
+ code: JSONRPC_ERROR_CODES.request_cancelled,
151
+ message,
152
+ data,
153
+ }),
132
154
  };
133
155
  /**
134
156
  * Error class carrying a JSON-RPC error code — thrown by handlers,
@@ -168,6 +190,8 @@ export const jsonrpc_errors = {
168
190
  rate_limited: create_error_thrower(jsonrpc_error_messages.rate_limited),
169
191
  service_unavailable: create_error_thrower(jsonrpc_error_messages.service_unavailable),
170
192
  timeout: create_error_thrower(jsonrpc_error_messages.timeout),
193
+ queue_overflow: create_error_thrower(jsonrpc_error_messages.queue_overflow),
194
+ request_cancelled: create_error_thrower(jsonrpc_error_messages.request_cancelled),
171
195
  };
172
196
  // --- HTTP status mapping ---
173
197
  /**
@@ -187,9 +211,13 @@ export const JSONRPC_ERROR_CODE_TO_HTTP_STATUS = {
187
211
  [-32003]: 404, // not_found
188
212
  [-32004]: 409, // conflict
189
213
  [-32005]: 422, // validation_error
214
+ // queue_overflow shares 429 with rate_limited — listed first so reverse
215
+ // map wins with rate_limited (server-side) rather than client-side overflow.
216
+ [-32009]: 429, // queue_overflow (client-side backpressure)
190
217
  [-32006]: 429, // rate_limited
191
218
  [-32007]: 503, // service_unavailable
192
219
  [-32008]: 504, // timeout
220
+ [-32010]: 499, // request_cancelled (nginx "client closed request")
193
221
  };
194
222
  /**
195
223
  * Maps HTTP status codes to JSON-RPC error codes (reverse mapping).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fuzdev/fuz_app",
3
- "version": "0.28.0",
3
+ "version": "0.30.0",
4
4
  "description": "fullstack app library",
5
5
  "glyph": "🗝",
6
6
  "logo": "logo.svg",