@fuzdev/fuz_app 0.24.0 → 0.25.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 (54) hide show
  1. package/dist/actions/action_codegen.d.ts +25 -0
  2. package/dist/actions/action_codegen.d.ts.map +1 -1
  3. package/dist/actions/action_codegen.js +39 -0
  4. package/dist/actions/action_peer.d.ts +7 -0
  5. package/dist/actions/action_peer.d.ts.map +1 -1
  6. package/dist/actions/action_peer.js +1 -1
  7. package/dist/actions/action_types.d.ts +16 -1
  8. package/dist/actions/action_types.d.ts.map +1 -1
  9. package/dist/actions/cancel.d.ts +78 -0
  10. package/dist/actions/cancel.d.ts.map +1 -0
  11. package/dist/actions/cancel.js +79 -0
  12. package/dist/actions/register_action_ws.d.ts.map +1 -1
  13. package/dist/actions/register_action_ws.js +50 -17
  14. package/dist/actions/rpc_client.d.ts +10 -0
  15. package/dist/actions/rpc_client.d.ts.map +1 -1
  16. package/dist/actions/rpc_client.js +22 -7
  17. package/dist/actions/socket.svelte.d.ts +22 -10
  18. package/dist/actions/socket.svelte.d.ts.map +1 -1
  19. package/dist/actions/socket.svelte.js +46 -12
  20. package/dist/actions/transports.d.ts +14 -3
  21. package/dist/actions/transports.d.ts.map +1 -1
  22. package/dist/actions/transports_http.d.ts +3 -3
  23. package/dist/actions/transports_http.d.ts.map +1 -1
  24. package/dist/actions/transports_http.js +4 -3
  25. package/dist/actions/transports_ws.d.ts +33 -6
  26. package/dist/actions/transports_ws.d.ts.map +1 -1
  27. package/dist/actions/transports_ws.js +43 -46
  28. package/dist/actions/transports_ws_backend.d.ts +12 -3
  29. package/dist/actions/transports_ws_backend.d.ts.map +1 -1
  30. package/dist/actions/transports_ws_backend.js +12 -1
  31. package/dist/auth/bearer_auth.js +0 -1
  32. package/dist/auth/keyring.d.ts.map +1 -1
  33. package/dist/auth/keyring.js +0 -2
  34. package/dist/auth/migrations.js +4 -4
  35. package/dist/db/migrate.d.ts +12 -2
  36. package/dist/db/migrate.d.ts.map +1 -1
  37. package/dist/db/migrate.js +25 -16
  38. package/dist/db/status.d.ts.map +1 -1
  39. package/dist/db/status.js +0 -2
  40. package/dist/dev/setup.js +2 -2
  41. package/dist/http/db_routes.d.ts.map +1 -1
  42. package/dist/http/db_routes.js +0 -1
  43. package/dist/testing/admin_integration.d.ts.map +1 -1
  44. package/dist/testing/admin_integration.js +0 -3
  45. package/dist/testing/app_server.js +1 -1
  46. package/dist/testing/data_exposure.js +6 -8
  47. package/dist/testing/db.js +1 -1
  48. package/dist/testing/integration.js +0 -1
  49. package/dist/testing/rate_limiting.d.ts.map +1 -1
  50. package/dist/testing/rate_limiting.js +0 -6
  51. package/dist/testing/rpc_round_trip.js +4 -4
  52. package/dist/testing/sse_round_trip.d.ts.map +1 -1
  53. package/dist/testing/sse_round_trip.js +1 -2
  54. package/package.json +2 -2
@@ -110,5 +110,30 @@ export declare const to_action_spec_output_identifier: (method: string) => strin
110
110
  */
111
111
  export declare const get_innermost_type: (schema: z.ZodType) => z.ZodType;
112
112
  export declare const get_innermost_type_name: (schema: z.ZodType) => string;
113
+ /**
114
+ * Generates one method line of the typed `ActionsApi` interface for a single
115
+ * spec. Encapsulates the input/options/return-type signature shape so the
116
+ * surface evolves in one place when fields like `signal` or `transport_name`
117
+ * are added to per-call options.
118
+ *
119
+ * Async methods (request_response, async local_call) get an optional second
120
+ * `options?: RpcClientCallOptions` arg (`{signal?, transport_name?}`). Sync
121
+ * local_call methods omit the options arg — `signal` can't cooperatively
122
+ * interrupt a synchronous handler and there's no transport to select.
123
+ *
124
+ * Consumers must import `ActionInputs`, `ActionOutputs`, `Result`,
125
+ * `JsonrpcErrorObject`, and (for async) `RpcClientCallOptions` into the
126
+ * generated module — the helper only emits the type references.
127
+ *
128
+ * @param spec - the action spec to emit
129
+ * @param options.sync_returns_value - when true (default), sync local_call
130
+ * methods return the output value directly; when false they're wrapped in
131
+ * `Result<{value, error}>` like async methods. Set to `false` if your
132
+ * ActionsApi treats every method uniformly.
133
+ * @returns one line like `foo: (input: ActionInputs['foo'], options?: RpcClientCallOptions) => Promise<Result<...>>;`
134
+ */
135
+ export declare const generate_actions_api_method_signature: (spec: ActionSpecUnion, options?: {
136
+ sync_returns_value?: boolean;
137
+ }) => string;
113
138
  export {};
114
139
  //# sourceMappingURL=action_codegen.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"action_codegen.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_codegen.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAGtB,OAAO,KAAK,EAAC,eAAe,EAAE,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAOxE;;GAEG;AACH,UAAU,UAAU;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,WAAW,CAAC;CACrC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,aAAa;;IACzB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAa;IAE1D;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAQrC;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAI1C;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI;IAOrD;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI;IAgCtD;;;OAGG;IACH,KAAK,IAAI,MAAM;IAIf;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED;;;OAGG;IACH,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC;IAIxB;;OAEG;IACH,KAAK,IAAI,IAAI;CAqDb;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAC/B,MAAM,eAAe,EACrB,UAAU,UAAU,GAAG,SAAS,KAC9B,KAAK,CAAC,gBAAgB,CA4DxB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,uBAAuB,GACnC,MAAM,eAAe,EACrB,OAAO,gBAAgB,EACvB,SAAS,aAAa,EACtB,aAAa,MAAM,KACjB,MAkBF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,GACnC,MAAM,eAAe,EACrB,UAAU,UAAU,GAAG,SAAS,EAChC,SAAS,aAAa,EACtB,UAAU;IAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAC,KACpC,MA4BF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,aAAa,MAAM,KAAG,MACU,CAAC;AAG/D,eAAO,MAAM,yBAAyB,GAAI,QAAQ,MAAM,KAAG,MAAiC,CAAC;AAC7F,eAAO,MAAM,+BAA+B,GAAI,QAAQ,MAAM,KAAG,MACpB,CAAC;AAC9C,eAAO,MAAM,gCAAgC,GAAI,QAAQ,MAAM,KAAG,MACpB,CAAC;AAE/C;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,CAAC,CAAC,OAwBxD,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,MAI3D,CAAC"}
1
+ {"version":3,"file":"action_codegen.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_codegen.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAGtB,OAAO,KAAK,EAAC,eAAe,EAAE,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAOxE;;GAEG;AACH,UAAU,UAAU;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,WAAW,CAAC;CACrC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,aAAa;;IACzB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAa;IAE1D;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAQrC;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAI1C;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI;IAOrD;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI;IAgCtD;;;OAGG;IACH,KAAK,IAAI,MAAM;IAIf;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED;;;OAGG;IACH,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC;IAIxB;;OAEG;IACH,KAAK,IAAI,IAAI;CAqDb;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAC/B,MAAM,eAAe,EACrB,UAAU,UAAU,GAAG,SAAS,KAC9B,KAAK,CAAC,gBAAgB,CA4DxB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,uBAAuB,GACnC,MAAM,eAAe,EACrB,OAAO,gBAAgB,EACvB,SAAS,aAAa,EACtB,aAAa,MAAM,KACjB,MAkBF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,GACnC,MAAM,eAAe,EACrB,UAAU,UAAU,GAAG,SAAS,EAChC,SAAS,aAAa,EACtB,UAAU;IAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAC,KACpC,MA4BF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,aAAa,MAAM,KAAG,MACU,CAAC;AAG/D,eAAO,MAAM,yBAAyB,GAAI,QAAQ,MAAM,KAAG,MAAiC,CAAC;AAC7F,eAAO,MAAM,+BAA+B,GAAI,QAAQ,MAAM,KAAG,MACpB,CAAC;AAC9C,eAAO,MAAM,gCAAgC,GAAI,QAAQ,MAAM,KAAG,MACpB,CAAC;AAE/C;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,CAAC,CAAC,OAwBxD,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,MAI3D,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,qCAAqC,GACjD,MAAM,eAAe,EACrB,UAAU;IAAC,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAAC,KACtC,MAmBF,CAAC"}
@@ -316,3 +316,42 @@ export const get_innermost_type_name = (schema) => {
316
316
  const def = innermost.def;
317
317
  return def.type;
318
318
  };
319
+ /**
320
+ * Generates one method line of the typed `ActionsApi` interface for a single
321
+ * spec. Encapsulates the input/options/return-type signature shape so the
322
+ * surface evolves in one place when fields like `signal` or `transport_name`
323
+ * are added to per-call options.
324
+ *
325
+ * Async methods (request_response, async local_call) get an optional second
326
+ * `options?: RpcClientCallOptions` arg (`{signal?, transport_name?}`). Sync
327
+ * local_call methods omit the options arg — `signal` can't cooperatively
328
+ * interrupt a synchronous handler and there's no transport to select.
329
+ *
330
+ * Consumers must import `ActionInputs`, `ActionOutputs`, `Result`,
331
+ * `JsonrpcErrorObject`, and (for async) `RpcClientCallOptions` into the
332
+ * generated module — the helper only emits the type references.
333
+ *
334
+ * @param spec - the action spec to emit
335
+ * @param options.sync_returns_value - when true (default), sync local_call
336
+ * methods return the output value directly; when false they're wrapped in
337
+ * `Result<{value, error}>` like async methods. Set to `false` if your
338
+ * ActionsApi treats every method uniformly.
339
+ * @returns one line like `foo: (input: ActionInputs['foo'], options?: RpcClientCallOptions) => Promise<Result<...>>;`
340
+ */
341
+ export const generate_actions_api_method_signature = (spec, options) => {
342
+ const sync_returns_value = options?.sync_returns_value ?? true;
343
+ const innermost_type_name = get_innermost_type_name(spec.input);
344
+ const has_input = innermost_type_name !== 'null' && innermost_type_name !== 'void';
345
+ const input_param = has_input
346
+ ? `input${spec.input.safeParse(undefined).success ? '?' : ''}: ActionInputs['${spec.method}']`
347
+ : 'input?: void';
348
+ const is_async = spec.kind === 'request_response' || (spec.kind === 'local_call' && spec.async);
349
+ const options_param = is_async ? ', options?: RpcClientCallOptions' : '';
350
+ const result_return = `Result<{value: ActionOutputs['${spec.method}']}, {error: JsonrpcErrorObject}>`;
351
+ const return_type = is_async
352
+ ? `Promise<${result_return}>`
353
+ : sync_returns_value
354
+ ? `ActionOutputs['${spec.method}']`
355
+ : result_return;
356
+ return `${spec.method}: (${input_param}${options_param}) => ${return_type};`;
357
+ };
@@ -11,6 +11,13 @@ import { Transports, type TransportName } from './transports.js';
11
11
  import type { ActionEventEnvironment } from './action_event_types.js';
12
12
  export interface ActionPeerSendOptions {
13
13
  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;
14
21
  }
15
22
  export interface ActionPeerOptions {
16
23
  environment: ActionEventEnvironment;
@@ -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;CAC/B;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,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"}
@@ -33,7 +33,7 @@ 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);
36
+ const result = await transport.send(message, { signal: options?.signal });
37
37
  if (result && 'error' in result) {
38
38
  this.environment.log?.error(`[peer] send ${message_type} failed:`, message.method, result.error.message);
39
39
  }
@@ -9,6 +9,7 @@
9
9
  * @module
10
10
  */
11
11
  import type { JsonrpcRequestId } from '../http/jsonrpc.js';
12
+ import type { Uuid } from '../uuid.js';
12
13
  import type { ActionSpecUnion } from './action_spec.js';
13
14
  /**
14
15
  * Minimum per-request context every server-side WS handler receives.
@@ -20,13 +21,27 @@ import type { ActionSpecUnion } from './action_spec.js';
20
21
  export interface BaseHandlerContext {
21
22
  /** JSON-RPC envelope request id — echoed back on the response. */
22
23
  request_id: JsonrpcRequestId;
24
+ /**
25
+ * Stable per-socket connection id assigned by
26
+ * `BackendWebsocketTransport.add_connection` — same reference across every
27
+ * message on this socket, also passed to `on_socket_open` /
28
+ * `on_socket_close`. Consumers key per-connection domain state on this
29
+ * directly instead of trying to derive it from signals (which are
30
+ * per-message composites of `AbortSignal.any([socket, request])`).
31
+ */
32
+ connection_id: Uuid;
23
33
  /**
24
34
  * Send a request-scoped JSON-RPC notification to the originating socket.
25
35
  * Not a broadcast — the message only reaches the client whose request
26
36
  * triggered this handler.
27
37
  */
28
38
  notify: (method: string, params: unknown) => void;
29
- /** Fires on socket close; streaming handlers poll for early termination. */
39
+ /**
40
+ * Fires on socket close OR on a client-initiated `cancel` notification
41
+ * matching this request's id. Streaming handlers poll for early
42
+ * termination; per-message composite (`AbortSignal.any([socket, request])`)
43
+ * — not stable across messages.
44
+ */
30
45
  signal: AbortSignal;
31
46
  }
32
47
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"action_types.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEtD;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IAClC,kEAAkE;IAClE,UAAU,EAAE,gBAAgB,CAAC;IAC7B;;;;OAIG;IACH,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,4EAA4E;IAC5E,MAAM,EAAE,WAAW,CAAC;CACpB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,CAAC,IAAI,SAAS,kBAAkB,GAAG,kBAAkB,IAAI,CACnF,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,IAAI,KACL,OAAO,CAAC;AAEb;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,MAAM,CAAC,IAAI,SAAS,kBAAkB,GAAG,kBAAkB;IAC3E,IAAI,EAAE,eAAe,CAAC;IACtB,8EAA8E;IAC9E,OAAO,CAAC,EAAE,eAAe,CAAC,IAAI,CAAC,CAAC;CAChC"}
1
+ {"version":3,"file":"action_types.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,YAAY,CAAC;AACrC,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEtD;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IAClC,kEAAkE;IAClE,UAAU,EAAE,gBAAgB,CAAC;IAC7B;;;;;;;OAOG;IACH,aAAa,EAAE,IAAI,CAAC;IACpB;;;;OAIG;IACH,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD;;;;;OAKG;IACH,MAAM,EAAE,WAAW,CAAC;CACpB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,CAAC,IAAI,SAAS,kBAAkB,GAAG,kBAAkB,IAAI,CACnF,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,IAAI,KACL,OAAO,CAAC;AAEb;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,MAAM,CAAC,IAAI,SAAS,kBAAkB,GAAG,kBAAkB;IAC3E,IAAI,EAAE,eAAe,CAAC;IACtB,8EAA8E;IAC9E,OAAO,CAAC,EAAE,eAAe,CAAC,IAAI,CAAC,CAAC;CAChC"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Shared cancel action — the second composable fuz_app primitive, validating
3
+ * the spec+handler tuple pattern on a notification-kind action.
4
+ *
5
+ * Semantics: the client sends `{jsonrpc, method: 'cancel', params:
6
+ * {request_id}}` to abort an in-flight request on the same socket.
7
+ * {@link register_action_ws} intercepts this notification and aborts the
8
+ * matching pending request's `ctx.signal`. Unknown ids are no-ops by design —
9
+ * races between response arrival and cancel delivery are safe without extra
10
+ * coordination.
11
+ *
12
+ * The handler field is an empty stub: cancel semantics are dispatcher-owned
13
+ * (the dispatcher has the `{request_id → AbortController}` map, not the
14
+ * handler). The handler exists for symmetry with other composable primitives
15
+ * like {@link heartbeat_action}; the dispatcher never calls it. Consumers
16
+ * spread {@link cancel_action} into their server's `actions` array so
17
+ * `spec_by_method` knows about it (enabling input validation on incoming
18
+ * cancels) and so `create_rpc_client` codegen produces `app.api.cancel()`
19
+ * when desired — though `FrontendWebsocketClient.request({signal})` sends
20
+ * the cancel on abort without needing the typed API.
21
+ *
22
+ * Wire format is snake_case `cancel` with `{request_id}`, not MCP's
23
+ * `$/cancelRequest` with `{requestId}` — fuz_app's WS transport isn't MCP,
24
+ * and adopting MCP's convention would leak protocol-specific framing into
25
+ * the base transport. When MCP elicitation (Phase 5) lands, a translation
26
+ * layer at the MCP adapter is the right seam.
27
+ *
28
+ * @module
29
+ */
30
+ import { z } from 'zod';
31
+ import type { Action } from './action_types.js';
32
+ /** Method name on the wire — shared across every fuz_app consumer. */
33
+ export declare const CANCEL_METHOD = "cancel";
34
+ /**
35
+ * Params for a {@link CANCEL_METHOD} notification. `request_id` is the id of
36
+ * the pending request to abort. Must match the id of a request sent on the
37
+ * same socket; cancels from other sockets (or for unknown ids) are ignored.
38
+ */
39
+ export declare const CancelNotificationParams: z.ZodObject<{
40
+ request_id: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
41
+ }, z.core.$strict>;
42
+ export type CancelNotificationParams = z.infer<typeof CancelNotificationParams>;
43
+ /**
44
+ * `ActionSpec` for the shared cancel. `auth: null` matches every other
45
+ * remote-notification spec — upgrade-time auth has already admitted the
46
+ * socket, so per-action auth on a fire-and-forget notification is moot. The
47
+ * per-connection `{request_id → AbortController}` map enforces socket-scoped
48
+ * ownership naturally: a different socket's cancel for the same id misses
49
+ * in its own map.
50
+ */
51
+ export declare const cancel_action_spec: {
52
+ method: string;
53
+ initiator: "both" | "frontend" | "backend";
54
+ input: z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
55
+ description: string;
56
+ kind: "remote_notification";
57
+ auth: null;
58
+ side_effects: true;
59
+ output: z.ZodVoid;
60
+ async: true;
61
+ streams?: string | undefined;
62
+ };
63
+ /**
64
+ * Placeholder handler — cancel semantics are owned by {@link register_action_ws},
65
+ * not invoked per-handler. Exported for symmetry with the {@link Action}
66
+ * tuple shape; the dispatcher short-circuits cancel notifications before any
67
+ * handler lookup happens.
68
+ */
69
+ export declare const cancel_handler: () => void;
70
+ /**
71
+ * Composable tuple — spread into the server's `actions` array so the
72
+ * dispatcher registers the spec for input validation and so `create_rpc_client`
73
+ * codegen sees the method. The client doesn't need to call it directly;
74
+ * `FrontendWebsocketClient.request({signal})` sends the cancel notification
75
+ * automatically when the signal fires.
76
+ */
77
+ export declare const cancel_action: Action;
78
+ //# sourceMappingURL=cancel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cancel.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/cancel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAItB,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,mBAAmB,CAAC;AAE9C,sEAAsE;AACtE,eAAO,MAAM,aAAa,WAAW,CAAC;AAEtC;;;;GAIG;AACH,eAAO,MAAM,wBAAwB;;kBAEnC,CAAC;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAEhF;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;CAW7B,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,cAAc,QAAO,IAAU,CAAC;AAE7C;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,EAAE,MAG3B,CAAC"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Shared cancel action — the second composable fuz_app primitive, validating
3
+ * the spec+handler tuple pattern on a notification-kind action.
4
+ *
5
+ * Semantics: the client sends `{jsonrpc, method: 'cancel', params:
6
+ * {request_id}}` to abort an in-flight request on the same socket.
7
+ * {@link register_action_ws} intercepts this notification and aborts the
8
+ * matching pending request's `ctx.signal`. Unknown ids are no-ops by design —
9
+ * races between response arrival and cancel delivery are safe without extra
10
+ * coordination.
11
+ *
12
+ * The handler field is an empty stub: cancel semantics are dispatcher-owned
13
+ * (the dispatcher has the `{request_id → AbortController}` map, not the
14
+ * handler). The handler exists for symmetry with other composable primitives
15
+ * like {@link heartbeat_action}; the dispatcher never calls it. Consumers
16
+ * spread {@link cancel_action} into their server's `actions` array so
17
+ * `spec_by_method` knows about it (enabling input validation on incoming
18
+ * cancels) and so `create_rpc_client` codegen produces `app.api.cancel()`
19
+ * when desired — though `FrontendWebsocketClient.request({signal})` sends
20
+ * the cancel on abort without needing the typed API.
21
+ *
22
+ * Wire format is snake_case `cancel` with `{request_id}`, not MCP's
23
+ * `$/cancelRequest` with `{requestId}` — fuz_app's WS transport isn't MCP,
24
+ * and adopting MCP's convention would leak protocol-specific framing into
25
+ * the base transport. When MCP elicitation (Phase 5) lands, a translation
26
+ * layer at the MCP adapter is the right seam.
27
+ *
28
+ * @module
29
+ */
30
+ import { z } from 'zod';
31
+ import { JsonrpcRequestId } from '../http/jsonrpc.js';
32
+ import { RemoteNotificationActionSpec } from './action_spec.js';
33
+ /** Method name on the wire — shared across every fuz_app consumer. */
34
+ export const CANCEL_METHOD = 'cancel';
35
+ /**
36
+ * Params for a {@link CANCEL_METHOD} notification. `request_id` is the id of
37
+ * the pending request to abort. Must match the id of a request sent on the
38
+ * same socket; cancels from other sockets (or for unknown ids) are ignored.
39
+ */
40
+ export const CancelNotificationParams = z.strictObject({
41
+ request_id: JsonrpcRequestId,
42
+ });
43
+ /**
44
+ * `ActionSpec` for the shared cancel. `auth: null` matches every other
45
+ * remote-notification spec — upgrade-time auth has already admitted the
46
+ * socket, so per-action auth on a fire-and-forget notification is moot. The
47
+ * per-connection `{request_id → AbortController}` map enforces socket-scoped
48
+ * ownership naturally: a different socket's cancel for the same id misses
49
+ * in its own map.
50
+ */
51
+ export const cancel_action_spec = RemoteNotificationActionSpec.parse({
52
+ method: CANCEL_METHOD,
53
+ kind: 'remote_notification',
54
+ initiator: 'frontend',
55
+ auth: null,
56
+ side_effects: true,
57
+ input: CancelNotificationParams,
58
+ output: z.void(),
59
+ async: true,
60
+ description: 'Client-initiated cancellation of an in-flight request by id. Dispatcher-handled: aborts the ctx.signal of the matching pending request on the same socket. Unknown or completed ids no-op.',
61
+ });
62
+ /**
63
+ * Placeholder handler — cancel semantics are owned by {@link register_action_ws},
64
+ * not invoked per-handler. Exported for symmetry with the {@link Action}
65
+ * tuple shape; the dispatcher short-circuits cancel notifications before any
66
+ * handler lookup happens.
67
+ */
68
+ export const cancel_handler = () => { }; // eslint-disable-line @typescript-eslint/no-empty-function
69
+ /**
70
+ * Composable tuple — spread into the server's `actions` array so the
71
+ * dispatcher registers the spec for input validation and so `create_rpc_client`
72
+ * codegen sees the method. The client doesn't need to call it directly;
73
+ * `FrontendWebsocketClient.request({signal})` sends the cancel notification
74
+ * automatically when the signal fires.
75
+ */
76
+ export const cancel_action = {
77
+ spec: cancel_action_spec,
78
+ handler: cancel_handler,
79
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"register_action_ws.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/register_action_ws.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,KAAK,EAAC,OAAO,EAAE,IAAI,EAAC,MAAM,MAAM,CAAC;AACxC,OAAO,KAAK,EAAC,gBAAgB,EAAE,SAAS,EAAC,MAAM,SAAS,CAAC;AAEzD,OAAO,EAAS,KAAK,MAAM,IAAI,UAAU,EAAC,MAAM,yBAAyB,CAAC;AAgB1E,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,YAAY,CAAC;AAErC,OAAO,EAAC,KAAK,MAAM,EAAE,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAC,MAAM,mBAAmB,CAAC;AAE7F,OAAO,EAAC,yBAAyB,EAAE,KAAK,kBAAkB,EAAC,MAAM,4BAA4B,CAAC;AAE9F,YAAY,EAAC,MAAM,EAAE,kBAAkB,EAAE,eAAe,EAAC,CAAC;AAE1D,0EAA0E;AAC1E,eAAO,MAAM,gCAAgC,QAAS,CAAC;AAEvD;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IACjC,qFAAqF;IACrF,EAAE,EAAE,SAAS,CAAC;IACd,4EAA4E;IAC5E,aAAa,EAAE,IAAI,CAAC;IACpB,oDAAoD;IACpD,QAAQ,EAAE,kBAAkB,CAAC;IAC7B;;;OAGG;IACH,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,wFAAwF;IACxF,MAAM,EAAE,WAAW,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IAClC,+CAA+C;IAC/C,EAAE,EAAE,SAAS,CAAC;IACd,2CAA2C;IAC3C,aAAa,EAAE,IAAI,CAAC;IACpB,kGAAkG;IAClG,QAAQ,EAAE,kBAAkB,CAAC;CAC7B;AAED,MAAM,WAAW,sBAAsB;IACtC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wCAAwC;AACxC,MAAM,WAAW,uBAAuB,CAAC,IAAI,SAAS,kBAAkB;IACvE,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,GAAG,EAAE,IAAI,CAAC;IACV,iEAAiE;IACjE,gBAAgB,EAAE,gBAAgB,CAAC;IACnC;;;;;;OAMG;IACH,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IACrC;;;;;OAKG;IACH,cAAc,EAAE,CAAC,IAAI,EAAE,kBAAkB,EAAE,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC/D;;;;OAIG;IACH,SAAS,CAAC,EAAE,yBAAyB,CAAC;IACtC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,sBAAsB,CAAC;IAC7C,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,qDAAqD;IACrD,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,kBAAkB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpE;AAED,sCAAsC;AACtC,MAAM,WAAW,sBAAsB;IACtC,yEAAyE;IACzE,SAAS,EAAE,yBAAyB,CAAC;CACrC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,kBAAkB,GAAI,IAAI,SAAS,kBAAkB,EACjE,SAAS,uBAAuB,CAAC,IAAI,CAAC,KACpC,sBA0UF,CAAC"}
1
+ {"version":3,"file":"register_action_ws.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/register_action_ws.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,KAAK,EAAC,OAAO,EAAE,IAAI,EAAC,MAAM,MAAM,CAAC;AACxC,OAAO,KAAK,EAAC,gBAAgB,EAAE,SAAS,EAAC,MAAM,SAAS,CAAC;AAEzD,OAAO,EAAS,KAAK,MAAM,IAAI,UAAU,EAAC,MAAM,yBAAyB,CAAC;AAgB1E,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,YAAY,CAAC;AAErC,OAAO,EAAC,KAAK,MAAM,EAAE,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAC,MAAM,mBAAmB,CAAC;AAG7F,OAAO,EAAC,yBAAyB,EAAE,KAAK,kBAAkB,EAAC,MAAM,4BAA4B,CAAC;AAE9F,YAAY,EAAC,MAAM,EAAE,kBAAkB,EAAE,eAAe,EAAC,CAAC;AAE1D,0EAA0E;AAC1E,eAAO,MAAM,gCAAgC,QAAS,CAAC;AAEvD;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IACjC,qFAAqF;IACrF,EAAE,EAAE,SAAS,CAAC;IACd,4EAA4E;IAC5E,aAAa,EAAE,IAAI,CAAC;IACpB,oDAAoD;IACpD,QAAQ,EAAE,kBAAkB,CAAC;IAC7B;;;OAGG;IACH,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,wFAAwF;IACxF,MAAM,EAAE,WAAW,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IAClC,+CAA+C;IAC/C,EAAE,EAAE,SAAS,CAAC;IACd,2CAA2C;IAC3C,aAAa,EAAE,IAAI,CAAC;IACpB,kGAAkG;IAClG,QAAQ,EAAE,kBAAkB,CAAC;CAC7B;AAED,MAAM,WAAW,sBAAsB;IACtC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wCAAwC;AACxC,MAAM,WAAW,uBAAuB,CAAC,IAAI,SAAS,kBAAkB;IACvE,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,GAAG,EAAE,IAAI,CAAC;IACV,iEAAiE;IACjE,gBAAgB,EAAE,gBAAgB,CAAC;IACnC;;;;;;OAMG;IACH,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IACrC;;;;;OAKG;IACH,cAAc,EAAE,CAAC,IAAI,EAAE,kBAAkB,EAAE,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC/D;;;;OAIG;IACH,SAAS,CAAC,EAAE,yBAAyB,CAAC;IACtC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,sBAAsB,CAAC;IAC7C,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,qDAAqD;IACrD,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,kBAAkB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpE;AAED,sCAAsC;AACtC,MAAM,WAAW,sBAAsB;IACtC,yEAAyE;IACzE,SAAS,EAAE,yBAAyB,CAAC;CACrC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,kBAAkB,GAAI,IAAI,SAAS,kBAAkB,EACjE,SAAS,uBAAuB,CAAC,IAAI,CAAC,KACpC,sBAwWF,CAAC"}
@@ -32,6 +32,7 @@ import { jsonrpc_error_messages } from '../http/jsonrpc_errors.js';
32
32
  import { create_jsonrpc_error_response, create_jsonrpc_error_response_from_thrown, create_jsonrpc_notification, to_jsonrpc_message_id, to_jsonrpc_params, is_jsonrpc_request, } from '../http/jsonrpc_helpers.js';
33
33
  import { CREDENTIAL_TYPE_KEY, AUTH_API_TOKEN_ID_KEY } from '../hono_context.js';
34
34
  import {} from './action_types.js';
35
+ import { CANCEL_METHOD, CancelNotificationParams } from './cancel.js';
35
36
  import { WS_CLOSE_SERVER_HEARTBEAT_TIMEOUT } from './transports.js';
36
37
  import { BackendWebsocketTransport } from './transports_ws_backend.js';
37
38
  /** Default inactivity window before the server closes a silent socket. */
@@ -88,12 +89,19 @@ export const register_action_ws = (options) => {
88
89
  // `close_sockets_for_token` to tear down just this socket on
89
90
  // `token_revoke` without affecting the account's other sockets.
90
91
  const api_token_id = c.get(AUTH_API_TOKEN_ID_KEY);
91
- // Per-socket abort controller — fires on socket close, threaded into
92
- // every in-flight handler's ctx.signal on this connection. A
93
- // dedicated per-request controller linked to this is future work;
94
- // a single socket-scoped signal is sufficient today since cancel
95
- // granularity tracks connection lifetime, not individual requests.
92
+ // Per-socket abort controller — fires on socket close, chained into
93
+ // every in-flight handler's per-request controller via
94
+ // `AbortSignal.any`. Keeping both signals lets the client
95
+ // cancel-one-request-by-id (via the `cancel` notification) without
96
+ // tearing down the whole socket.
96
97
  const socket_abort_controller = new AbortController();
98
+ // Per-request controllers keyed by JSON-RPC request id — lets an
99
+ // incoming `cancel` notification abort just the matching handler.
100
+ // Populated on request dispatch, cleared in the handler's `finally`
101
+ // so a late-arriving cancel for a completed id (or a reused id)
102
+ // can't null-abort a freshly-arrived request. Idempotent: cancel
103
+ // for unknown ids no-ops.
104
+ const pending_controllers = new Map();
97
105
  // Identity is assembled at upgrade time so `on_socket_close` can
98
106
  // still read it after the audit guard tears the transport record
99
107
  // down; `BackendWebsocketTransport.#revoke_connection` clears the
@@ -185,9 +193,26 @@ export const register_action_ws = (options) => {
185
193
  ws.send(JSON.stringify(create_jsonrpc_error_response(null, jsonrpc_error_messages.invalid_request('batch JSON-RPC requests are not supported on WebSocket'))));
186
194
  return;
187
195
  }
188
- // Only handle requests (method + id). Notifications (no id) are silenced per JSON-RPC spec.
196
+ // Notifications (method + no id) `cancel` is intercepted
197
+ // for request-scoped cancellation; other notifications are
198
+ // silenced per JSON-RPC spec (consumer notification handlers
199
+ // are not a feature yet).
189
200
  if (!is_jsonrpc_request(json)) {
190
201
  if (typeof json === 'object' && json !== null && 'method' in json && !('id' in json)) {
202
+ if (json.method === CANCEL_METHOD) {
203
+ const parsed = CancelNotificationParams.safeParse(json.params);
204
+ if (!parsed.success) {
205
+ log.debug('cancel: invalid params, ignoring', parsed.error.issues);
206
+ return;
207
+ }
208
+ const controller = pending_controllers.get(parsed.data.request_id);
209
+ if (controller) {
210
+ controller.abort();
211
+ }
212
+ else {
213
+ log.debug('cancel: no pending request for id', parsed.data.request_id);
214
+ }
215
+ }
191
216
  return;
192
217
  }
193
218
  ws.send(JSON.stringify(create_jsonrpc_error_response(to_jsonrpc_message_id(json), jsonrpc_error_messages.invalid_request())));
@@ -233,22 +258,27 @@ export const register_action_ws = (options) => {
233
258
  await wait(artificial_delay);
234
259
  }
235
260
  // Socket-scoped notification — routes to originator only, not
236
- // broadcast. Future work: other audiences account-scoped,
261
+ // broadcast. Same helper used in `on_socket_open` so both
262
+ // paths share one code path for send-and-log-on-failure.
263
+ // Future work: other audiences — account-scoped,
237
264
  // ACL-filtered, broadcast — likely via a transport-level
238
265
  // policy hook.
239
- const notify = (notify_method, notify_params) => {
240
- try {
241
- const notification = create_jsonrpc_notification(notify_method, to_jsonrpc_params(notify_params));
242
- ws.send(JSON.stringify(notification));
243
- }
244
- catch (error) {
245
- log.error('notify send failed:', notify_method, error);
246
- }
247
- };
266
+ const notify = notify_socket(ws);
267
+ // Per-request controller — fires on explicit `cancel` or on
268
+ // socket close (via the socket_abort_controller chain below).
269
+ // Registered before dispatch so a cancel arriving mid-handler
270
+ // finds it; cleared in `finally` so late cancels for a
271
+ // completed id (or a future request that reuses the id) can't
272
+ // null-abort the wrong handler.
273
+ const request_controller = new AbortController();
274
+ pending_controllers.set(id, request_controller);
248
275
  const base = {
249
276
  request_id: id,
277
+ // Populated in `onOpen` before any message can dispatch —
278
+ // non-null assertion is safe.
279
+ connection_id: captured_connection_id,
250
280
  notify,
251
- signal: socket_abort_controller.signal,
281
+ signal: AbortSignal.any([socket_abort_controller.signal, request_controller.signal]),
252
282
  };
253
283
  const ctx = extend_context(base, c);
254
284
  try {
@@ -267,6 +297,9 @@ export const register_action_ws = (options) => {
267
297
  log.error('handler error:', method, error);
268
298
  ws.send(JSON.stringify(create_jsonrpc_error_response_from_thrown(id, error)));
269
299
  }
300
+ finally {
301
+ pending_controllers.delete(id);
302
+ }
270
303
  },
271
304
  onClose: async (event, ws) => {
272
305
  stop_heartbeat_timer();
@@ -57,4 +57,14 @@ export interface CreateRpcClientOptions {
57
57
  * @returns a Proxy that responds to any method name found in the environment's specs
58
58
  */
59
59
  export declare const create_rpc_client: (options: CreateRpcClientOptions) => Record<string, (...args: Array<any>) => any>;
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.
65
+ */
66
+ export interface RpcClientCallOptions {
67
+ signal?: AbortSignal;
68
+ transport_name?: TransportName;
69
+ }
60
70
  //# 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;AAEnD;;;;;;;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"}
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"}
@@ -11,6 +11,7 @@
11
11
  */
12
12
  import { create_action_event } from './action_event.js';
13
13
  import { is_send_request, is_notification_send, extract_action_result, } from './action_event_helpers.js';
14
+ import { jsonrpc_error_messages } from '../http/jsonrpc_errors.js';
14
15
  /**
15
16
  * Creates a Proxy-based API from action specs.
16
17
  *
@@ -78,9 +79,19 @@ const create_sync_local_call_method = (environment, spec, actions) => {
78
79
  /**
79
80
  * Creates an asynchronous local call method.
80
81
  * Returns Result for type-safe error handling.
82
+ *
83
+ * Local calls don't traverse a transport, so `transport_name` is ignored and
84
+ * `signal` can only short-circuit before the synchronous handler runs (no
85
+ * cooperative interrupt mid-handler).
81
86
  */
82
87
  const create_async_local_call_method = (environment, spec, actions) => {
83
- return async (input) => {
88
+ return async (input, options) => {
89
+ if (options?.signal?.aborted) {
90
+ return {
91
+ ok: false,
92
+ error: jsonrpc_error_messages.internal_error(`${spec.method} aborted before execution`),
93
+ };
94
+ }
84
95
  const event = create_action_event(environment, spec, input);
85
96
  const action = actions?.add_from_json({
86
97
  method: spec.method,
@@ -95,7 +106,7 @@ const create_async_local_call_method = (environment, spec, actions) => {
95
106
  * Creates a request/response method that communicates over the network.
96
107
  */
97
108
  const create_request_response_method = (peer, environment, spec, actions, transport_for_method) => {
98
- return async (input) => {
109
+ return async (input, options) => {
99
110
  const event = create_action_event(environment, spec, input);
100
111
  const action = actions?.add_from_json({
101
112
  method: spec.method,
@@ -113,8 +124,10 @@ const create_request_response_method = (peer, environment, spec, actions, transp
113
124
  if (event.data.step !== 'handled') {
114
125
  return extract_action_result(event);
115
126
  }
116
- const transport_name = transport_for_method?.(spec.method);
117
- const response = await peer.send(event.data.request, transport_name ? { transport_name } : undefined);
127
+ const response = await peer.send(event.data.request, {
128
+ transport_name: options?.transport_name ?? transport_for_method?.(spec.method),
129
+ signal: options?.signal,
130
+ });
118
131
  event.transition('receive_response');
119
132
  // TODO @api shouldn't this happen in the peer like the other method calls?
120
133
  event.set_response(response);
@@ -128,7 +141,7 @@ const create_request_response_method = (peer, environment, spec, actions, transp
128
141
  * Returns Result<{value: void}> for consistency.
129
142
  */
130
143
  const create_remote_notification_method = (peer, environment, spec, actions, transport_for_method) => {
131
- return async (input) => {
144
+ return async (input, options) => {
132
145
  const event = create_action_event(environment, spec, input);
133
146
  const action = actions?.add_from_json({
134
147
  method: spec.method,
@@ -139,8 +152,10 @@ const create_remote_notification_method = (peer, environment, spec, actions, tra
139
152
  if (!is_notification_send(event.data))
140
153
  throw Error(); // TODO @many maybe make this an assertion helper?
141
154
  if (event.data.step === 'handled') {
142
- const transport_name = transport_for_method?.(spec.method);
143
- const send_result = await peer.send(event.data.notification, transport_name ? { transport_name } : undefined);
155
+ const send_result = await peer.send(event.data.notification, {
156
+ transport_name: options?.transport_name ?? transport_for_method?.(spec.method),
157
+ signal: options?.signal,
158
+ });
144
159
  // Check if notification failed to send
145
160
  if (send_result !== null) {
146
161
  environment.log?.error('notification send failed:', send_result.error);
@@ -24,6 +24,7 @@
24
24
  * @module
25
25
  */
26
26
  import type { Logger } from '@fuzdev/fuz_util/log.js';
27
+ import { type JsonrpcRequestId } from '../http/jsonrpc.js';
27
28
  import type { WebsocketConnection } from './transports_ws.js';
28
29
  /** Default WebSocket close code (normal closure). */
29
30
  export declare const DEFAULT_CLOSE_CODE = 1000;
@@ -186,23 +187,34 @@ export declare class FrontendWebsocketClient implements WebsocketConnection, Dis
186
187
  send(data: object): boolean;
187
188
  /**
188
189
  * Promise-based JSON-RPC over the socket. Auto-assigns a monotonic request
189
- * id, tracks the pending promise, and resolves when the server sends a
190
- * matching response (or rejects on error frame, socket close, or aborted
191
- * signal).
190
+ * id (or uses an explicit one supplied via `options.id` used by
191
+ * `FrontendWebsocketTransport` which delegates to this method and has its
192
+ * own peer-minted UUID), tracks the pending promise, and resolves when the
193
+ * server sends a matching response (or rejects on error frame, socket
194
+ * close, or aborted signal).
195
+ *
196
+ * Callers supplying an explicit `options.id` are responsible for
197
+ * uniqueness — the pending map is keyed by id, and a duplicate silently
198
+ * overwrites the prior entry. Auto-minted ids are monotonic and never
199
+ * collide with themselves or with peer-minted UUIDs (the types differ:
200
+ * integer vs string).
192
201
  *
193
202
  * While the socket is disconnected, the request is buffered in a bounded
194
- * queue (default-on, {@link DEFAULT_QUEUE_MAX_SIZE}) and flushed on
195
- * reopen. Pass `{queue: false}` to reject immediately when disconnected
196
- * — used internally by the heartbeat, which must not fight the queue for
197
- * the disconnect-detection slot.
203
+ * queue (default-on, `DEFAULT_QUEUE_MAX_SIZE`) and flushed on reopen. Pass
204
+ * `{queue: false}` to reject immediately when disconnected — used
205
+ * internally by the heartbeat, which must not fight the queue for the
206
+ * disconnect-detection slot.
198
207
  *
199
- * `AbortSignal` integration today rejects the local promise; the
200
- * server-side cancel protocol (sending a `cancel` notification to abort
201
- * the in-flight handler) lands in Phase 3c as a follow-up PR.
208
+ * On `AbortSignal` fire: rejects the local promise *and* sends the shared
209
+ * `cancel` notification (`CANCEL_METHOD`) so the server-side dispatcher
210
+ * can abort the matching handler's `ctx.signal`. Suppressed for
211
+ * queued-but-never-sent (server doesn't know about it) and
212
+ * response-beat-cancel races.
202
213
  */
203
214
  request<R = unknown>(method: string, params?: unknown, options?: {
204
215
  signal?: AbortSignal;
205
216
  queue?: boolean;
217
+ id?: JsonrpcRequestId;
206
218
  }): Promise<R>;
207
219
  add_message_handler(handler: SocketMessageHandler): () => void;
208
220
  add_error_handler(handler: SocketErrorHandler): () => void;
@@ -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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"}