@fuzdev/fuz_app 0.49.0 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/CLAUDE.md +54 -19
- package/dist/actions/action_codegen.d.ts +33 -28
- package/dist/actions/action_codegen.d.ts.map +1 -1
- package/dist/actions/action_codegen.js +40 -34
- package/dist/actions/action_types.d.ts +2 -2
- package/dist/actions/action_types.js +2 -2
- package/dist/actions/cancel.d.ts +13 -11
- package/dist/actions/cancel.d.ts.map +1 -1
- package/dist/actions/cancel.js +13 -11
- package/dist/actions/frontend_rpc_client.d.ts +9 -0
- package/dist/actions/frontend_rpc_client.d.ts.map +1 -1
- package/dist/actions/heartbeat.d.ts +11 -8
- package/dist/actions/heartbeat.d.ts.map +1 -1
- package/dist/actions/heartbeat.js +11 -8
- package/dist/actions/protocol.d.ts +47 -0
- package/dist/actions/protocol.d.ts.map +1 -0
- package/dist/actions/protocol.js +46 -0
- package/dist/actions/register_action_ws.d.ts +4 -3
- package/dist/actions/register_action_ws.d.ts.map +1 -1
- package/dist/actions/register_action_ws.js +1 -1
- package/dist/auth/account_action_specs.d.ts +1 -1
- package/dist/auth/account_action_specs.js +1 -1
- package/dist/auth/account_actions.d.ts +2 -2
- package/dist/auth/account_actions.js +2 -2
- package/dist/auth/admin_action_specs.d.ts +1 -1
- package/dist/auth/admin_action_specs.js +1 -1
- package/dist/auth/admin_actions.d.ts +2 -2
- package/dist/auth/admin_actions.js +2 -2
- package/dist/auth/permit_offer_action_specs.d.ts +1 -1
- package/dist/auth/permit_offer_action_specs.js +1 -1
- package/dist/auth/permit_offer_actions.d.ts +1 -1
- package/dist/auth/permit_offer_actions.js +1 -1
- package/dist/auth/standard_action_specs.d.ts +1 -1
- package/dist/auth/standard_action_specs.js +1 -1
- package/package.json +1 -1
package/dist/actions/CLAUDE.md
CHANGED
|
@@ -120,8 +120,8 @@ not the runtime):
|
|
|
120
120
|
- `generate_actions_api_method_signature(spec, {sync_returns_value?})` — single source of truth for the typed `FrontendActionsApi` method shape. Threads `options?: RpcClientCallOptions` (`{signal?, transport_name?, queue?}`) onto every async method — `request_response`, `remote_notification`, and async `local_call` — and wraps the return in `Promise<Result<...>>`. Notifications were previously emitted as `=> void`, mismatching the runtime (`create_remote_notification_method` returns a Promise that resolves to `Result<{value: void}>`); regenerate consumer typed clients to pick up the corrected shape.
|
|
121
121
|
- `create_banner(origin_path)` — gen banner comment.
|
|
122
122
|
- `to_action_spec_identifier(method)` / `to_action_spec_input_identifier` / `to_action_spec_output_identifier` — naming convention helpers (emit `foo_action_spec` / `foo_action_spec.input` / `foo_action_spec.output`).
|
|
123
|
-
- `
|
|
124
|
-
- `
|
|
123
|
+
- `PROTOCOL_ACTION_METHODS` (+ `ProtocolActionMethod` type) — readonly tuple `['heartbeat', 'cancel']`. Pairs with `protocol_actions` / `protocol_action_specs` in `actions/protocol.ts` (the runtime bundles). Consumers spread when filtering backend `request_response` methods so dispatcher-owned protocol actions don't leak into `BackendRequestResponseMethod` / handler maps.
|
|
124
|
+
- `is_protocol_action_method(method)` — type predicate paired with `PROTOCOL_ACTION_METHODS`; use this in `method_filter` callbacks instead of `PROTOCOL_ACTION_METHODS.includes(s.method as never)`.
|
|
125
125
|
- `DEFAULT_COLLECTIONS_PATH = './action_collections.js'` — shared default for every helper that takes a `collections_path?`.
|
|
126
126
|
- `DEFAULT_SPECS_MODULE = './action_specs.js'` — shared default for helpers that emit `specs.{method}_action_spec` and need a `* as specs` namespace import.
|
|
127
127
|
- `DEFAULT_METATYPES_PATH = './action_metatypes.js'` — shared default for the sibling module carrying the generated `ActionMethod` enum.
|
|
@@ -133,14 +133,15 @@ Composed by consumer `*.gen.ts` producers; outputs do not include the banner or
|
|
|
133
133
|
surrounding `imports.build()`. Use `compose_gen_file` to assemble the block
|
|
134
134
|
list + banner + imports into the final file body in one call.
|
|
135
135
|
|
|
136
|
-
**
|
|
137
|
-
`{
|
|
138
|
-
`cancel` from the emitted output.
|
|
139
|
-
spread into each consumer's `actions` array at
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
`
|
|
143
|
-
|
|
136
|
+
**Protocol actions are filtered by default.** Every spec-iterating helper
|
|
137
|
+
accepts `{include_protocol_actions?: boolean}` (default `false`) and drops
|
|
138
|
+
`heartbeat` / `cancel` from the emitted output. Protocol actions ship from
|
|
139
|
+
fuz_app and are spread into each consumer's `actions` array at
|
|
140
|
+
registration time (via `protocol_actions` from `actions/protocol.ts`) —
|
|
141
|
+
they should not appear in consumer-owned typed surfaces (`ActionMethod`,
|
|
142
|
+
`FrontendActionsApi`, `ActionInputs`, `FrontendActionHandlers`, etc.).
|
|
143
|
+
Pass `include_protocol_actions: true` only if a consumer genuinely owns
|
|
144
|
+
protocol actions in their typed API.
|
|
144
145
|
|
|
145
146
|
**Consumer tiers and namespace handling.** Single-source consumers (zzz,
|
|
146
147
|
undying — every spec lives in one local `action_specs.ts`) drop straight
|
|
@@ -167,15 +168,15 @@ interfaces — and never calls `generate_typed_action_event_alias` or
|
|
|
167
168
|
zzz) emits the full set including `ActionEventDatas`, `TypedActionEvent`,
|
|
168
169
|
and `FrontendActionHandlers`.
|
|
169
170
|
|
|
170
|
-
- `generate_action_method_enums(specs, imports, {emit?,
|
|
171
|
-
- `generate_action_method_enum_block(specs, imports, {name, jsdoc, predicate,
|
|
171
|
+
- `generate_action_method_enums(specs, imports, {emit?, include_protocol_actions?})` — up to nine `z.enum` + `z.infer` pairs (`ActionMethod`, `RequestResponseActionMethod`, `RemoteNotificationActionMethod`, `LocalCallActionMethod`, `FrontendActionMethod`, `BackendActionMethod`, `FrontendRequestResponseMethod`, `BackendRequestResponseMethod`, `BroadcastActionMethod`). `emit: ReadonlySet<ActionMethodEnumKind>` restricts to a subset (Tier 1 HTTP-only consumers don't need all nine). Skips kinds whose method list is empty (`z.enum([])` is invalid) and skips the `zod` import when no blocks are emitted. Adds `import {z} from 'zod'` only when at least one block is produced. The `frontend_handled` / `backend_handled` / `broadcast` kinds use the registry's narrow handler-side / streams-aware getters; the loose `frontend` / `backend` kinds preserve the everything-relevant-to-this-side semantic for the typed-Proxy method enum.
|
|
172
|
+
- `generate_action_method_enum_block(specs, imports, {name, jsdoc, predicate, include_protocol_actions?})` — lower-level escape hatch for genuinely cross-product enums the discriminator doesn't cover. Caller owns the predicate, name, and jsdoc.
|
|
172
173
|
- `generate_typed_action_event_alias(imports, {collections_path?, metatypes_path?})` — fixed-shape `TypedActionEvent<TMethod, TPhase, TStep>` alias narrowing `ActionEvent.data` against `ActionEventDatas`. Adds the three fuz_app type imports + `ActionEventDatas` (from `collections_path`) + `ActionMethod` (from `metatypes_path`).
|
|
173
|
-
- `generate_action_specs_record(specs, imports, {specs_module?, qualify_spec?,
|
|
174
|
-
- `generate_action_inputs_outputs(specs, imports, {specs_module?, qualify_spec?,
|
|
175
|
-
- `generate_action_event_datas(specs, imports, {same_file?, collections_path?,
|
|
176
|
-
- `generate_frontend_actions_api(specs, imports, {interface_name?, method_filter?, collections_path?, sync_returns_value?,
|
|
177
|
-
- `generate_frontend_action_handlers(specs, imports, {collections_path?,
|
|
178
|
-
- `generate_backend_actions_api(specs, imports, {interface_name?, spec_array_name?, specs_module?, collections_path?, qualify_spec?,
|
|
174
|
+
- `generate_action_specs_record(specs, imports, {specs_module?, qualify_spec?, include_protocol_actions?})` — `ActionSpecs` runtime const + interface + `action_specs: Array<ActionSpecUnion>` value. Adds `* as specs` from `specs_module` unless `qualify_spec` is set (then `specs_module` is ignored and the consumer owns namespace imports).
|
|
175
|
+
- `generate_action_inputs_outputs(specs, imports, {specs_module?, qualify_spec?, include_protocol_actions?})` — `ActionInputs` and `ActionOutputs` runtime consts + interfaces. Same `qualify_spec` semantics as `generate_action_specs_record`; the helper appends `.input` / `.output` to the qualified identifier.
|
|
176
|
+
- `generate_action_event_datas(specs, imports, {same_file?, collections_path?, include_protocol_actions?})` — `ActionEventDatas` interface; per-spec variant by kind (`ActionEventRequestResponseData` / `ActionEventRemoteNotificationData` / `ActionEventLocalCallData`). `same_file` (default `true`) is the file-layout switch: when `true`, assumes `ActionInputs` / `ActionOutputs` are in the same module and adds no import (the zzz pattern); when `false`, adds the type imports from `collections_path` (default `'./action_collections.js'`). `collections_path` alone is a no-op — the surprising omit-vs-default behavior of earlier versions has been replaced.
|
|
177
|
+
- `generate_frontend_actions_api(specs, imports, {interface_name?, method_filter?, collections_path?, sync_returns_value?, include_protocol_actions?})` — emits the typed `FrontendActionsApi` interface (configurable via `interface_name`, default `'FrontendActionsApi'`). One method signature per spec via `generate_actions_api_method_signature`. Protocol actions filtered by default; `method_filter: (spec) => boolean` runs after the protocol-action filter. Renamed from `generate_actions_api` in API review III to make the side-of-the-wire intent visible at every consumer site.
|
|
178
|
+
- `generate_frontend_action_handlers(specs, imports, {collections_path?, include_protocol_actions?})` — `FrontendActionHandlers` interface (Tier 2 only — wraps `generate_phase_handlers` with `action_event_type: 'TypedActionEvent'`). Pair with `generate_typed_action_event_alias`.
|
|
179
|
+
- `generate_backend_actions_api(specs, imports, {interface_name?, spec_array_name?, specs_module?, collections_path?, qualify_spec?, include_protocol_actions?})` — `BackendActionsApi` interface AND `broadcast_action_specs: ReadonlyArray<ActionSpecUnion>` array (both names configurable). Filter: `kind === 'remote_notification' && initiator !== 'frontend'`, with `streams`-target methods (request-scoped progress notifications invoked via `ctx.notify`) excluded — the discriminator is `ActionSpec.streams`, not a manual list. Adds `ActionInputs` (from `collections_path`) + `ActionSpecUnion`, plus `* as specs` from `specs_module` unless `qualify_spec` is set. Method shape today is `(input) => Promise<void>` (matches `create_broadcast_api`'s fire-and-forget runtime); generalizing to per-kind shapes via `generate_actions_api_method_signature` is deferred until a second backend runtime constructor lands (see SAES quest § API review III deferred set).
|
|
179
180
|
- `generate_backend_action_handlers_map(imports, options?)` — emits the `BackendActionHandlers` mapped type (`{[K in BackendRequestResponseMethod]: (input: ActionInputs[K], ctx: BackendHandlerContext) => ActionOutputs[K] | Promise<ActionOutputs[K]>}`). Replaces the hand-maintained `Exclude<>` + parallel mapped-type pattern (zzz had this at `zzz/src/lib/server/zzz_action_handlers.ts:42-66`). Configurable type name, method enum name, and context type name; configurable `collections_path` / `metatypes_path` for the type imports.
|
|
180
181
|
|
|
181
182
|
### Wrapper + multi-source helper
|
|
@@ -578,12 +579,46 @@ interface ActionPeerSendOptions extends TransportSendOptions {
|
|
|
578
579
|
Currently partial: `#receive_request`'s `send_response` transition step has
|
|
579
580
|
a known sharp edge ("shouldn't need the guard" TODO).
|
|
580
581
|
|
|
581
|
-
##
|
|
582
|
+
## Protocol actions (`heartbeat.ts`, `cancel.ts`, `protocol.ts`)
|
|
582
583
|
|
|
583
584
|
Two shared `{spec, handler}` tuples that every consumer spreads into both
|
|
584
585
|
sides' `actions` arrays — disconnect detection and per-request cancel work
|
|
585
586
|
identically across every repo without per-consumer ping plumbing.
|
|
586
587
|
|
|
588
|
+
The category is wire-protocol concerns shipped by fuz_app, not consumer
|
|
589
|
+
domain logic. The contrast that matters is protocol vs domain: a future
|
|
590
|
+
clock-skew probe or reconnect-resume token belongs in this bundle; a
|
|
591
|
+
`payment_charge` action does not. Avoid the framing "composable vs
|
|
592
|
+
non-composable" — every `Action` is composable by the same mechanism
|
|
593
|
+
(spread into the `actions` array), so the distinction would not carve
|
|
594
|
+
nature at the joints.
|
|
595
|
+
|
|
596
|
+
### Canonical bundles (`protocol.ts`)
|
|
597
|
+
|
|
598
|
+
Two const arrays declare the canonical protocol-action set so consumers
|
|
599
|
+
spread one symbol per side instead of importing each primitive
|
|
600
|
+
individually:
|
|
601
|
+
|
|
602
|
+
- `protocol_actions: ReadonlyArray<Action>` — for the server's
|
|
603
|
+
`register_action_ws` `actions` array. Spread before consumer-owned
|
|
604
|
+
actions: `actions: [...protocol_actions, ...consumer_actions]`.
|
|
605
|
+
- `protocol_action_specs: ReadonlyArray<ActionSpecUnion>` — derived via
|
|
606
|
+
`.map(a => a.spec)` so the two arrays cannot drift. For the frontend
|
|
607
|
+
`ActionRegistry`. Spread before consumer-owned specs:
|
|
608
|
+
`new ActionRegistry([...protocol_action_specs, ...action_specs])`.
|
|
609
|
+
|
|
610
|
+
The asymmetry is intentional — the server runs handlers (heartbeat echo +
|
|
611
|
+
cancel stub), the frontend registry only stores specs. Both bundles plus
|
|
612
|
+
the codegen `include_protocol_actions: false` default form a three-leg
|
|
613
|
+
contract: codegen excludes protocol actions from generated typed surfaces
|
|
614
|
+
because consumers spread these bundles in at registration time.
|
|
615
|
+
|
|
616
|
+
The bundles are **not** auto-spread by `create_frontend_rpc_client` or
|
|
617
|
+
`register_ws_endpoint` — bundled helpers stay pure factories so the
|
|
618
|
+
dispatch surface stays grep-traceable at every consumer registration site
|
|
619
|
+
and consumers can override individual protocol actions (custom heartbeat,
|
|
620
|
+
etc.) without an opt-out flag.
|
|
621
|
+
|
|
587
622
|
### `heartbeat_action`
|
|
588
623
|
|
|
589
624
|
Method `'heartbeat'`, `request_response`, `initiator: 'frontend'`, `auth:
|
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
import type { ActionSpecUnion, ActionEventPhase } from './action_spec.js';
|
|
2
2
|
/**
|
|
3
|
-
* Method names of
|
|
4
|
-
*
|
|
5
|
-
* this list when filtering backend request_response methods so the
|
|
6
|
-
*
|
|
3
|
+
* Method names of fuz_app's protocol actions — `heartbeat` (auth-aware client
|
|
4
|
+
* liveness probe) and `cancel` (request-scoped abort signal). Consumers spread
|
|
5
|
+
* this list when filtering backend request_response methods so the
|
|
6
|
+
* dispatcher-owned protocol actions don't show up in
|
|
7
|
+
* `BackendRequestResponseMethod` / handler maps. Pairs with `protocol_actions`
|
|
8
|
+
* / `protocol_action_specs` from `actions/protocol.ts` (the runtime bundles).
|
|
7
9
|
*/
|
|
8
|
-
export declare const
|
|
10
|
+
export declare const PROTOCOL_ACTION_METHODS: readonly ["heartbeat", "cancel"];
|
|
9
11
|
/** Methods that ship from fuz_app, kept out of consumer-owned method enums + handler maps. */
|
|
10
|
-
export type
|
|
12
|
+
export type ProtocolActionMethod = (typeof PROTOCOL_ACTION_METHODS)[number];
|
|
11
13
|
/**
|
|
12
|
-
* Type predicate for filtering
|
|
13
|
-
* `method_filter`. Avoids the `(... as never)` cast
|
|
14
|
-
* `Array.prototype.includes` on the readonly tuple at narrow
|
|
14
|
+
* Type predicate for filtering protocol-action methods out of a typed
|
|
15
|
+
* `FrontendActionsApi` `method_filter`. Avoids the `(... as never)` cast
|
|
16
|
+
* required to call `Array.prototype.includes` on the readonly tuple at narrow
|
|
17
|
+
* string types.
|
|
15
18
|
*
|
|
16
19
|
* @example
|
|
17
20
|
* generate_frontend_actions_api(specs, imports, {
|
|
18
|
-
* method_filter: (s) => !
|
|
21
|
+
* method_filter: (s) => !is_protocol_action_method(s.method),
|
|
19
22
|
* });
|
|
20
23
|
*/
|
|
21
|
-
export declare const
|
|
24
|
+
export declare const is_protocol_action_method: (method: string) => method is ProtocolActionMethod;
|
|
22
25
|
/**
|
|
23
26
|
* Represents an import item with its kind (type, value, or namespace).
|
|
24
27
|
*/
|
|
@@ -174,10 +177,10 @@ export declare const ACTION_METHOD_ENUM_KINDS_ALL: ReadonlySet<ActionMethodEnumK
|
|
|
174
177
|
* `BroadcastActionMethod`. Pairs each runtime const with a `z.infer` type
|
|
175
178
|
* alias under the same identifier.
|
|
176
179
|
*
|
|
177
|
-
*
|
|
178
|
-
* pass `
|
|
179
|
-
* their typed surface. Empty kinds are skipped so the helper
|
|
180
|
-
* `z.enum([])` (zod runtime-throws on that).
|
|
180
|
+
* Protocol-action methods (`heartbeat`, `cancel`) are filtered out by
|
|
181
|
+
* default — pass `include_protocol_actions: true` if a consumer genuinely
|
|
182
|
+
* wants them on their typed surface. Empty kinds are skipped so the helper
|
|
183
|
+
* never emits `z.enum([])` (zod runtime-throws on that).
|
|
181
184
|
*
|
|
182
185
|
* Adds `import {z} from 'zod';` to `imports` only when at least one block
|
|
183
186
|
* is emitted (idempotent).
|
|
@@ -187,12 +190,12 @@ export declare const ACTION_METHOD_ENUM_KINDS_ALL: ReadonlySet<ActionMethodEnumK
|
|
|
187
190
|
* and jsdoc.
|
|
188
191
|
*
|
|
189
192
|
* @param options.emit - subset of enums to emit; defaults to all nine.
|
|
190
|
-
* @param options.
|
|
193
|
+
* @param options.include_protocol_actions - when true, retains `heartbeat` /
|
|
191
194
|
* `cancel` in the emitted enums. Default `false`.
|
|
192
195
|
*/
|
|
193
196
|
export declare const generate_action_method_enums: (specs: ReadonlyArray<ActionSpecUnion>, imports: ImportBuilder, options?: {
|
|
194
197
|
emit?: ReadonlySet<ActionMethodEnumKind>;
|
|
195
|
-
|
|
198
|
+
include_protocol_actions?: boolean;
|
|
196
199
|
}) => string;
|
|
197
200
|
/**
|
|
198
201
|
* Emit a single named `z.enum([...])` + `z.infer` block for an arbitrary
|
|
@@ -200,9 +203,10 @@ export declare const generate_action_method_enums: (specs: ReadonlyArray<ActionS
|
|
|
200
203
|
* for cross-product or domain-specific enums the built-in discriminator
|
|
201
204
|
* doesn't cover.
|
|
202
205
|
*
|
|
203
|
-
* Mirrors the built-in helper's contract:
|
|
204
|
-
* empty subsets return `''` (skip rather than emit `z.enum([])`),
|
|
205
|
-
* import registered idempotently only when at least one method
|
|
206
|
+
* Mirrors the built-in helper's contract: protocol actions filtered by
|
|
207
|
+
* default, empty subsets return `''` (skip rather than emit `z.enum([])`),
|
|
208
|
+
* `zod` import registered idempotently only when at least one method
|
|
209
|
+
* qualifies.
|
|
206
210
|
*
|
|
207
211
|
* The cross-product space is open-ended; rather than grow the
|
|
208
212
|
* `ActionMethodEnumKind` discriminator one cross-product at a time, callers
|
|
@@ -212,7 +216,7 @@ export declare const generate_action_method_enum_block: (specs: ReadonlyArray<Ac
|
|
|
212
216
|
name: string;
|
|
213
217
|
jsdoc: string;
|
|
214
218
|
predicate: (spec: ActionSpecUnion) => boolean;
|
|
215
|
-
|
|
219
|
+
include_protocol_actions?: boolean;
|
|
216
220
|
}) => string;
|
|
217
221
|
/**
|
|
218
222
|
* Emit the fixed-shape `TypedActionEvent` alias used by `FrontendActionHandlers`
|
|
@@ -245,7 +249,7 @@ export declare const generate_typed_action_event_alias: (imports: ImportBuilder,
|
|
|
245
249
|
export declare const generate_action_specs_record: (specs: ReadonlyArray<ActionSpecUnion>, imports: ImportBuilder, options?: {
|
|
246
250
|
specs_module?: string;
|
|
247
251
|
qualify_spec?: (spec: ActionSpecUnion) => string;
|
|
248
|
-
|
|
252
|
+
include_protocol_actions?: boolean;
|
|
249
253
|
}) => string;
|
|
250
254
|
/**
|
|
251
255
|
* Emit `ActionInputs` + `ActionOutputs` runtime consts and matching interfaces.
|
|
@@ -263,7 +267,7 @@ export declare const generate_action_specs_record: (specs: ReadonlyArray<ActionS
|
|
|
263
267
|
export declare const generate_action_inputs_outputs: (specs: ReadonlyArray<ActionSpecUnion>, imports: ImportBuilder, options?: {
|
|
264
268
|
specs_module?: string;
|
|
265
269
|
qualify_spec?: (spec: ActionSpecUnion) => string;
|
|
266
|
-
|
|
270
|
+
include_protocol_actions?: boolean;
|
|
267
271
|
}) => string;
|
|
268
272
|
/**
|
|
269
273
|
* Emit the `ActionEventDatas` interface — one `ActionEvent*Data` variant per
|
|
@@ -288,12 +292,13 @@ export declare const generate_action_inputs_outputs: (specs: ReadonlyArray<Actio
|
|
|
288
292
|
export declare const generate_action_event_datas: (specs: ReadonlyArray<ActionSpecUnion>, imports: ImportBuilder, options?: {
|
|
289
293
|
same_file?: boolean;
|
|
290
294
|
collections_path?: string;
|
|
291
|
-
|
|
295
|
+
include_protocol_actions?: boolean;
|
|
292
296
|
}) => string;
|
|
293
297
|
/**
|
|
294
298
|
* Emit the `FrontendActionsApi` interface — one method signature per spec via
|
|
295
299
|
* `generate_actions_api_method_signature`. Optionally filter the spec set
|
|
296
|
-
* (e.g. omit
|
|
300
|
+
* (e.g. omit additional methods alongside the default protocol-action
|
|
301
|
+
* filter) via `method_filter`.
|
|
297
302
|
*
|
|
298
303
|
* Adds the `Result`, `JsonrpcErrorObject`, and `RpcClientCallOptions` type
|
|
299
304
|
* imports plus `ActionInputs` / `ActionOutputs` (sourced from `collections_path`).
|
|
@@ -308,7 +313,7 @@ export declare const generate_frontend_actions_api: (specs: ReadonlyArray<Action
|
|
|
308
313
|
method_filter?: (spec: ActionSpecUnion) => boolean;
|
|
309
314
|
collections_path?: string;
|
|
310
315
|
sync_returns_value?: boolean;
|
|
311
|
-
|
|
316
|
+
include_protocol_actions?: boolean;
|
|
312
317
|
}) => string;
|
|
313
318
|
/**
|
|
314
319
|
* Emit the `FrontendActionHandlers` interface — wraps `generate_phase_handlers`
|
|
@@ -318,7 +323,7 @@ export declare const generate_frontend_actions_api: (specs: ReadonlyArray<Action
|
|
|
318
323
|
*/
|
|
319
324
|
export declare const generate_frontend_action_handlers: (specs: ReadonlyArray<ActionSpecUnion>, imports: ImportBuilder, options?: {
|
|
320
325
|
collections_path?: string;
|
|
321
|
-
|
|
326
|
+
include_protocol_actions?: boolean;
|
|
322
327
|
}) => string;
|
|
323
328
|
/**
|
|
324
329
|
* Emit BOTH the typed `BackendActionsApi` interface AND the
|
|
@@ -355,7 +360,7 @@ export declare const generate_backend_actions_api: (specs: ReadonlyArray<ActionS
|
|
|
355
360
|
specs_module?: string;
|
|
356
361
|
collections_path?: string;
|
|
357
362
|
qualify_spec?: (spec: ActionSpecUnion) => string;
|
|
358
|
-
|
|
363
|
+
include_protocol_actions?: boolean;
|
|
359
364
|
}) => string;
|
|
360
365
|
/**
|
|
361
366
|
* Emit the `BackendActionHandlers` mapped type — one entry per
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action_codegen.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_codegen.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,eAAe,EAAE,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAGxE
|
|
1
|
+
{"version":3,"file":"action_codegen.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_codegen.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,24 +2,27 @@ import { UnreachableError } from '@fuzdev/fuz_util/error.js';
|
|
|
2
2
|
import { zod_get_base_type } from '@fuzdev/fuz_util/zod.js';
|
|
3
3
|
import { ActionRegistry } from './action_registry.js';
|
|
4
4
|
/**
|
|
5
|
-
* Method names of
|
|
6
|
-
*
|
|
7
|
-
* this list when filtering backend request_response methods so the
|
|
8
|
-
*
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
* Method names of fuz_app's protocol actions — `heartbeat` (auth-aware client
|
|
6
|
+
* liveness probe) and `cancel` (request-scoped abort signal). Consumers spread
|
|
7
|
+
* this list when filtering backend request_response methods so the
|
|
8
|
+
* dispatcher-owned protocol actions don't show up in
|
|
9
|
+
* `BackendRequestResponseMethod` / handler maps. Pairs with `protocol_actions`
|
|
10
|
+
* / `protocol_action_specs` from `actions/protocol.ts` (the runtime bundles).
|
|
11
|
+
*/
|
|
12
|
+
export const PROTOCOL_ACTION_METHODS = ['heartbeat', 'cancel'];
|
|
13
|
+
const PROTOCOL_METHOD_SET = new Set(PROTOCOL_ACTION_METHODS);
|
|
12
14
|
/**
|
|
13
|
-
* Type predicate for filtering
|
|
14
|
-
* `method_filter`. Avoids the `(... as never)` cast
|
|
15
|
-
* `Array.prototype.includes` on the readonly tuple at narrow
|
|
15
|
+
* Type predicate for filtering protocol-action methods out of a typed
|
|
16
|
+
* `FrontendActionsApi` `method_filter`. Avoids the `(... as never)` cast
|
|
17
|
+
* required to call `Array.prototype.includes` on the readonly tuple at narrow
|
|
18
|
+
* string types.
|
|
16
19
|
*
|
|
17
20
|
* @example
|
|
18
21
|
* generate_frontend_actions_api(specs, imports, {
|
|
19
|
-
* method_filter: (s) => !
|
|
22
|
+
* method_filter: (s) => !is_protocol_action_method(s.method),
|
|
20
23
|
* });
|
|
21
24
|
*/
|
|
22
|
-
export const
|
|
25
|
+
export const is_protocol_action_method = (method) => PROTOCOL_METHOD_SET.has(method);
|
|
23
26
|
/**
|
|
24
27
|
* Manages imports for generated code, building them on demand.
|
|
25
28
|
* Automatically optimizes type-only imports to use `import type` syntax.
|
|
@@ -404,12 +407,13 @@ export const ACTION_METHOD_ENUM_KINDS_ALL = new Set([
|
|
|
404
407
|
]);
|
|
405
408
|
/**
|
|
406
409
|
* Filter `heartbeat` / `cancel` out of `specs` unless the consumer opts back in.
|
|
407
|
-
*
|
|
408
|
-
* array at registration time
|
|
410
|
+
* Protocol actions ship from fuz_app and are spread into every consumer's
|
|
411
|
+
* `actions` array at registration time (via `protocol_actions` from
|
|
412
|
+
* `actions/protocol.ts`) — they should not appear in consumer-owned typed
|
|
409
413
|
* surfaces (`ActionMethod`, `FrontendActionsApi`, `ActionInputs`, etc.) by
|
|
410
414
|
* default.
|
|
411
415
|
*/
|
|
412
|
-
const
|
|
416
|
+
const filter_protocol_actions = (specs, include_protocol_actions) => include_protocol_actions ? specs : specs.filter((s) => !is_protocol_action_method(s.method));
|
|
413
417
|
/**
|
|
414
418
|
* Resolve the per-spec identifier qualifier used by the multi-source helpers
|
|
415
419
|
* (`generate_action_specs_record`, `generate_action_inputs_outputs`,
|
|
@@ -434,10 +438,10 @@ const resolve_spec_qualifier = (imports, options) => {
|
|
|
434
438
|
* `BroadcastActionMethod`. Pairs each runtime const with a `z.infer` type
|
|
435
439
|
* alias under the same identifier.
|
|
436
440
|
*
|
|
437
|
-
*
|
|
438
|
-
* pass `
|
|
439
|
-
* their typed surface. Empty kinds are skipped so the helper
|
|
440
|
-
* `z.enum([])` (zod runtime-throws on that).
|
|
441
|
+
* Protocol-action methods (`heartbeat`, `cancel`) are filtered out by
|
|
442
|
+
* default — pass `include_protocol_actions: true` if a consumer genuinely
|
|
443
|
+
* wants them on their typed surface. Empty kinds are skipped so the helper
|
|
444
|
+
* never emits `z.enum([])` (zod runtime-throws on that).
|
|
441
445
|
*
|
|
442
446
|
* Adds `import {z} from 'zod';` to `imports` only when at least one block
|
|
443
447
|
* is emitted (idempotent).
|
|
@@ -447,12 +451,12 @@ const resolve_spec_qualifier = (imports, options) => {
|
|
|
447
451
|
* and jsdoc.
|
|
448
452
|
*
|
|
449
453
|
* @param options.emit - subset of enums to emit; defaults to all nine.
|
|
450
|
-
* @param options.
|
|
454
|
+
* @param options.include_protocol_actions - when true, retains `heartbeat` /
|
|
451
455
|
* `cancel` in the emitted enums. Default `false`.
|
|
452
456
|
*/
|
|
453
457
|
export const generate_action_method_enums = (specs, imports, options) => {
|
|
454
458
|
const emit = options?.emit ?? ACTION_METHOD_ENUM_KINDS_ALL;
|
|
455
|
-
const filtered =
|
|
459
|
+
const filtered = filter_protocol_actions(specs, options?.include_protocol_actions);
|
|
456
460
|
const registry = new ActionRegistry([...filtered]);
|
|
457
461
|
const blocks = [];
|
|
458
462
|
const emit_block = (kind, name, methods, jsdoc) => {
|
|
@@ -488,16 +492,17 @@ export const generate_action_method_enums = (specs, imports, options) => {
|
|
|
488
492
|
* for cross-product or domain-specific enums the built-in discriminator
|
|
489
493
|
* doesn't cover.
|
|
490
494
|
*
|
|
491
|
-
* Mirrors the built-in helper's contract:
|
|
492
|
-
* empty subsets return `''` (skip rather than emit `z.enum([])`),
|
|
493
|
-
* import registered idempotently only when at least one method
|
|
495
|
+
* Mirrors the built-in helper's contract: protocol actions filtered by
|
|
496
|
+
* default, empty subsets return `''` (skip rather than emit `z.enum([])`),
|
|
497
|
+
* `zod` import registered idempotently only when at least one method
|
|
498
|
+
* qualifies.
|
|
494
499
|
*
|
|
495
500
|
* The cross-product space is open-ended; rather than grow the
|
|
496
501
|
* `ActionMethodEnumKind` discriminator one cross-product at a time, callers
|
|
497
502
|
* own the subset shape — name, jsdoc, predicate.
|
|
498
503
|
*/
|
|
499
504
|
export const generate_action_method_enum_block = (specs, imports, options) => {
|
|
500
|
-
const filtered =
|
|
505
|
+
const filtered = filter_protocol_actions(specs, options.include_protocol_actions);
|
|
501
506
|
const methods = filtered.filter(options.predicate).map((s) => s.method);
|
|
502
507
|
if (methods.length === 0)
|
|
503
508
|
return '';
|
|
@@ -544,7 +549,7 @@ type TypedActionEvent<
|
|
|
544
549
|
* is ignored when `qualify_spec` is set. Single-source consumers omit it.
|
|
545
550
|
*/
|
|
546
551
|
export const generate_action_specs_record = (specs, imports, options) => {
|
|
547
|
-
const filtered =
|
|
552
|
+
const filtered = filter_protocol_actions(specs, options?.include_protocol_actions);
|
|
548
553
|
imports.add_type('@fuzdev/fuz_app/actions/action_spec.js', 'ActionSpecUnion');
|
|
549
554
|
if (filtered.length === 0) {
|
|
550
555
|
// Empty spec list — emit minimal valid output and skip the `* as specs`
|
|
@@ -588,7 +593,7 @@ export const action_specs: Array<ActionSpecUnion> = Object.values(ActionSpecs);`
|
|
|
588
593
|
* and `specs_module` is ignored. Single-source consumers omit it.
|
|
589
594
|
*/
|
|
590
595
|
export const generate_action_inputs_outputs = (specs, imports, options) => {
|
|
591
|
-
const filtered =
|
|
596
|
+
const filtered = filter_protocol_actions(specs, options?.include_protocol_actions);
|
|
592
597
|
if (filtered.length === 0) {
|
|
593
598
|
// Empty spec list — emit minimal valid output and skip the `zod` /
|
|
594
599
|
// `* as specs` imports that would have nothing to reference.
|
|
@@ -663,7 +668,7 @@ ${outputs_type}
|
|
|
663
668
|
* path the import resolves to.
|
|
664
669
|
*/
|
|
665
670
|
export const generate_action_event_datas = (specs, imports, options) => {
|
|
666
|
-
const filtered =
|
|
671
|
+
const filtered = filter_protocol_actions(specs, options?.include_protocol_actions);
|
|
667
672
|
if (filtered.length === 0) {
|
|
668
673
|
// Empty spec list — emit `interface ActionEventDatas {}` and skip
|
|
669
674
|
// the optional collections-path import that would be unused.
|
|
@@ -703,7 +708,8 @@ ${lines.join('\n')}
|
|
|
703
708
|
/**
|
|
704
709
|
* Emit the `FrontendActionsApi` interface — one method signature per spec via
|
|
705
710
|
* `generate_actions_api_method_signature`. Optionally filter the spec set
|
|
706
|
-
* (e.g. omit
|
|
711
|
+
* (e.g. omit additional methods alongside the default protocol-action
|
|
712
|
+
* filter) via `method_filter`.
|
|
707
713
|
*
|
|
708
714
|
* Adds the `Result`, `JsonrpcErrorObject`, and `RpcClientCallOptions` type
|
|
709
715
|
* imports plus `ActionInputs` / `ActionOutputs` (sourced from `collections_path`).
|
|
@@ -715,9 +721,9 @@ ${lines.join('\n')}
|
|
|
715
721
|
* hand-roll the interface (the helper's job is the standard symmetric shape).
|
|
716
722
|
*/
|
|
717
723
|
export const generate_frontend_actions_api = (specs, imports, options) => {
|
|
718
|
-
const
|
|
724
|
+
const protocol_filtered = filter_protocol_actions(specs, options?.include_protocol_actions);
|
|
719
725
|
const filter = options?.method_filter;
|
|
720
|
-
const filtered = filter ?
|
|
726
|
+
const filtered = filter ? protocol_filtered.filter((s) => filter(s)) : protocol_filtered;
|
|
721
727
|
const interface_doc = `/**
|
|
722
728
|
* Typed dispatch surface for the frontend's RPC client. Symmetric counterpart
|
|
723
729
|
* of \`BackendActionsApi\`. Async methods (request_response, remote_notification,
|
|
@@ -755,7 +761,7 @@ ${lines}
|
|
|
755
761
|
* matching `TypedActionEvent` alias) — call both in the same gen producer.
|
|
756
762
|
*/
|
|
757
763
|
export const generate_frontend_action_handlers = (specs, imports, options) => {
|
|
758
|
-
const filtered =
|
|
764
|
+
const filtered = filter_protocol_actions(specs, options?.include_protocol_actions);
|
|
759
765
|
const interface_doc = `/**
|
|
760
766
|
* Frontend action handlers organized by method and phase.
|
|
761
767
|
* Generated using spec.initiator to determine valid phases:
|
|
@@ -815,8 +821,8 @@ ${lines};
|
|
|
815
821
|
* Single-source consumers omit it.
|
|
816
822
|
*/
|
|
817
823
|
export const generate_backend_actions_api = (specs, imports, options) => {
|
|
818
|
-
const
|
|
819
|
-
const registry = new ActionRegistry([...
|
|
824
|
+
const protocol_filtered = filter_protocol_actions(specs, options?.include_protocol_actions);
|
|
825
|
+
const registry = new ActionRegistry([...protocol_filtered]);
|
|
820
826
|
const broadcast = registry.broadcast_specs;
|
|
821
827
|
imports.add_type('@fuzdev/fuz_app/actions/action_spec.js', 'ActionSpecUnion');
|
|
822
828
|
const interface_doc = `/**
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* These types sit above `action_spec.ts` (pure Zod schemas) and below the
|
|
5
5
|
* dispatchers (`register_action_ws.ts`, `action_rpc.ts`). Extracted so the
|
|
6
|
-
* shared
|
|
7
|
-
*
|
|
6
|
+
* shared protocol actions (e.g. `heartbeat_action`) can name them without
|
|
7
|
+
* pulling in server-only modules.
|
|
8
8
|
*
|
|
9
9
|
* @module
|
|
10
10
|
*/
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* These types sit above `action_spec.ts` (pure Zod schemas) and below the
|
|
5
5
|
* dispatchers (`register_action_ws.ts`, `action_rpc.ts`). Extracted so the
|
|
6
|
-
* shared
|
|
7
|
-
*
|
|
6
|
+
* shared protocol actions (e.g. `heartbeat_action`) can name them without
|
|
7
|
+
* pulling in server-only modules.
|
|
8
8
|
*
|
|
9
9
|
* @module
|
|
10
10
|
*/
|
package/dist/actions/cancel.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared cancel action —
|
|
3
|
-
*
|
|
2
|
+
* Shared cancel action — a fuz_app protocol action validating the
|
|
3
|
+
* spec+handler tuple pattern on a notification-kind action.
|
|
4
4
|
*
|
|
5
5
|
* Semantics: the client sends `{jsonrpc, method: 'cancel', params:
|
|
6
6
|
* {request_id}}` to abort an in-flight request on the same socket.
|
|
@@ -11,13 +11,14 @@
|
|
|
11
11
|
*
|
|
12
12
|
* The handler field is an empty stub: cancel semantics are dispatcher-owned
|
|
13
13
|
* (the dispatcher has the `{request_id → AbortController}` map, not the
|
|
14
|
-
* handler). The handler exists for symmetry with other
|
|
14
|
+
* handler). The handler exists for symmetry with other protocol actions
|
|
15
15
|
* like `heartbeat_action`; the dispatcher never calls it. Consumers
|
|
16
|
-
* spread `cancel_action`
|
|
17
|
-
* `
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
16
|
+
* spread `cancel_action` (or the `protocol_actions` bundle from
|
|
17
|
+
* `./protocol.js`) into their server's `actions` array so `spec_by_method`
|
|
18
|
+
* knows about it (enabling input validation on incoming cancels) and so
|
|
19
|
+
* `create_rpc_client` codegen produces `app.api.cancel()` when desired —
|
|
20
|
+
* though `FrontendWebsocketClient.request({signal})` sends the cancel on
|
|
21
|
+
* abort without needing the typed API.
|
|
21
22
|
*
|
|
22
23
|
* Wire format is snake_case `cancel` with `{request_id}`, not MCP's
|
|
23
24
|
* `$/cancelRequest` with `{requestId}` — fuz_app's WS transport isn't MCP,
|
|
@@ -67,9 +68,10 @@ export declare const cancel_action_spec: {
|
|
|
67
68
|
*/
|
|
68
69
|
export declare const cancel_handler: () => void;
|
|
69
70
|
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
71
|
+
* Protocol-action tuple — spread into the server's `actions` array (or via
|
|
72
|
+
* `protocol_actions` from `./protocol.js`) so the dispatcher registers the
|
|
73
|
+
* spec for input validation and so `create_rpc_client` codegen sees the
|
|
74
|
+
* method. The client doesn't need to call it directly;
|
|
73
75
|
* `FrontendWebsocketClient.request({signal})` sends the cancel notification
|
|
74
76
|
* automatically when the signal fires.
|
|
75
77
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cancel.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/cancel.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"cancel.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/cancel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAItB,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,mBAAmB,CAAC;AAE9C;;;;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;;;;;;;;;;;;CAWS,CAAC;AAEzC;;;;;GAKG;AACH,eAAO,MAAM,cAAc,QAAO,IAAU,CAAC;AAE7C;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,EAAE,MAG3B,CAAC"}
|
package/dist/actions/cancel.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared cancel action —
|
|
3
|
-
*
|
|
2
|
+
* Shared cancel action — a fuz_app protocol action validating the
|
|
3
|
+
* spec+handler tuple pattern on a notification-kind action.
|
|
4
4
|
*
|
|
5
5
|
* Semantics: the client sends `{jsonrpc, method: 'cancel', params:
|
|
6
6
|
* {request_id}}` to abort an in-flight request on the same socket.
|
|
@@ -11,13 +11,14 @@
|
|
|
11
11
|
*
|
|
12
12
|
* The handler field is an empty stub: cancel semantics are dispatcher-owned
|
|
13
13
|
* (the dispatcher has the `{request_id → AbortController}` map, not the
|
|
14
|
-
* handler). The handler exists for symmetry with other
|
|
14
|
+
* handler). The handler exists for symmetry with other protocol actions
|
|
15
15
|
* like `heartbeat_action`; the dispatcher never calls it. Consumers
|
|
16
|
-
* spread `cancel_action`
|
|
17
|
-
* `
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
16
|
+
* spread `cancel_action` (or the `protocol_actions` bundle from
|
|
17
|
+
* `./protocol.js`) into their server's `actions` array so `spec_by_method`
|
|
18
|
+
* knows about it (enabling input validation on incoming cancels) and so
|
|
19
|
+
* `create_rpc_client` codegen produces `app.api.cancel()` when desired —
|
|
20
|
+
* though `FrontendWebsocketClient.request({signal})` sends the cancel on
|
|
21
|
+
* abort without needing the typed API.
|
|
21
22
|
*
|
|
22
23
|
* Wire format is snake_case `cancel` with `{request_id}`, not MCP's
|
|
23
24
|
* `$/cancelRequest` with `{requestId}` — fuz_app's WS transport isn't MCP,
|
|
@@ -64,9 +65,10 @@ export const cancel_action_spec = {
|
|
|
64
65
|
*/
|
|
65
66
|
export const cancel_handler = () => { }; // eslint-disable-line @typescript-eslint/no-empty-function
|
|
66
67
|
/**
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
68
|
+
* Protocol-action tuple — spread into the server's `actions` array (or via
|
|
69
|
+
* `protocol_actions` from `./protocol.js`) so the dispatcher registers the
|
|
70
|
+
* spec for input validation and so `create_rpc_client` codegen sees the
|
|
71
|
+
* method. The client doesn't need to call it directly;
|
|
70
72
|
* `FrontendWebsocketClient.request({signal})` sends the cancel notification
|
|
71
73
|
* automatically when the signal fires.
|
|
72
74
|
*/
|
|
@@ -58,6 +58,15 @@ export interface CreateFrontendRpcClientOptions<TApi extends object = object> {
|
|
|
58
58
|
* list silently return `undefined` from the Proxy — the generic `TApi`
|
|
59
59
|
* cannot constrain runtime membership, so consumers must keep this list
|
|
60
60
|
* in sync with the typed surface (codegen recommended).
|
|
61
|
+
*
|
|
62
|
+
* Protocol actions (`heartbeat`, `cancel`) are **not** auto-spread —
|
|
63
|
+
* they're filtered out of generated `action_specs` by codegen's
|
|
64
|
+
* `include_protocol_actions: false` default and consumers spread them
|
|
65
|
+
* in explicitly so the contract stays visible at every registration
|
|
66
|
+
* site. For WS-using consumers, spread `protocol_action_specs` from
|
|
67
|
+
* `actions/protocol.ts` here:
|
|
68
|
+
* `specs: [...protocol_action_specs, ...action_specs]`. HTTP-only
|
|
69
|
+
* consumers can omit them.
|
|
61
70
|
*/
|
|
62
71
|
specs: ReadonlyArray<ActionSpecUnion>;
|
|
63
72
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frontend_rpc_client.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/frontend_rpc_client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAGH,OAAO,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAa,KAAK,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAE3D,OAAO,EAGN,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,yBAAyB,CAAC;AACpE,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEtD,gDAAgD;AAChD,MAAM,WAAW,8BAA8B,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IAC3E
|
|
1
|
+
{"version":3,"file":"frontend_rpc_client.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/frontend_rpc_client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAGH,OAAO,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAa,KAAK,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAE3D,OAAO,EAGN,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,yBAAyB,CAAC;AACpE,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEtD,gDAAgD;AAChD,MAAM,WAAW,8BAA8B,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IAC3E;;;;;;;;;;;;;;OAcG;IACH,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IACtC;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,UAAU,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IACtC;;;;;;;;;OASG;IACH,oBAAoB,CAAC,EAAE,kBAAkB,CAAC;IAC1C;;;;;;;;;OASG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC;IACpE;;;;;;;;;;;;;;;;OAgBG;IACH,qBAAqB,CAAC,EAAE,sBAAsB,CAAC,uBAAuB,CAAC,CAAC;CACxE;AAED,uDAAuD;AACvD,MAAM,WAAW,iBAAiB,CAAC,IAAI;IACtC;;;;OAIG;IACH,GAAG,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;IACvB;;;;;OAKG;IACH,UAAU,EAAE,IAAI,CAAC;IACjB,0GAA0G;IAC1G,IAAI,EAAE,UAAU,CAAC;IACjB,sHAAsH;IACtH,WAAW,EAAE,sBAAsB,CAAC;CACpC;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B,GAAI,IAAI,SAAS,MAAM,EAC7D,SAAS,8BAA8B,CAAC,IAAI,CAAC,KAC3C,iBAAiB,CAAC,IAAI,CAsBxB,CAAC"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared heartbeat action —
|
|
3
|
-
*
|
|
4
|
-
* `
|
|
5
|
-
* array so disconnect detection works identically across every
|
|
6
|
-
* per-consumer ping plumbing.
|
|
2
|
+
* Shared heartbeat action — a fuz_app protocol action carrying both a spec
|
|
3
|
+
* and a handler in one tuple. Consumers spread `heartbeat_action` (or the
|
|
4
|
+
* `protocol_actions` bundle from `./protocol.js`) into the server's
|
|
5
|
+
* `actions` array so disconnect detection works identically across every
|
|
6
|
+
* repo without per-consumer ping plumbing.
|
|
7
7
|
*
|
|
8
8
|
* The client's activity-aware heartbeat timer (in
|
|
9
9
|
* `FrontendWebsocketClient`) issues a `heartbeat` request whenever the
|
|
@@ -38,9 +38,12 @@ export declare const heartbeat_action_spec: {
|
|
|
38
38
|
/** Handler — nullary echo. Stateless, suitable for high-frequency pings. */
|
|
39
39
|
export declare const heartbeat_handler: () => Record<string, never>;
|
|
40
40
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
41
|
+
* Protocol-action tuple — spread into the server's `actions` array for
|
|
42
|
+
* dispatch (or via `protocol_actions` from `./protocol.js`) so the
|
|
43
|
+
* dispatcher resolves the heartbeat handler. The frontend-side spread
|
|
44
|
+
* happens via `protocol_action_specs` — the client doesn't run the echo
|
|
45
|
+
* handler, but the spec must be in `ActionRegistry` so `create_rpc_client`
|
|
46
|
+
* types `app.api.heartbeat()` against the shared spec.
|
|
44
47
|
*/
|
|
45
48
|
export declare const heartbeat_action: Action;
|
|
46
49
|
//# sourceMappingURL=heartbeat.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heartbeat.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/heartbeat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAGtB,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,mBAAmB,CAAC;AAE9C;;;;GAIG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;CAUG,CAAC;AAEtC,4EAA4E;AAC5E,eAAO,MAAM,iBAAiB,QAAO,MAAM,CAAC,MAAM,EAAE,KAAK,CAAS,CAAC;AAEnE
|
|
1
|
+
{"version":3,"file":"heartbeat.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/heartbeat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAGtB,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,mBAAmB,CAAC;AAE9C;;;;GAIG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;CAUG,CAAC;AAEtC,4EAA4E;AAC5E,eAAO,MAAM,iBAAiB,QAAO,MAAM,CAAC,MAAM,EAAE,KAAK,CAAS,CAAC;AAEnE;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAG9B,CAAC"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared heartbeat action —
|
|
3
|
-
*
|
|
4
|
-
* `
|
|
5
|
-
* array so disconnect detection works identically across every
|
|
6
|
-
* per-consumer ping plumbing.
|
|
2
|
+
* Shared heartbeat action — a fuz_app protocol action carrying both a spec
|
|
3
|
+
* and a handler in one tuple. Consumers spread `heartbeat_action` (or the
|
|
4
|
+
* `protocol_actions` bundle from `./protocol.js`) into the server's
|
|
5
|
+
* `actions` array so disconnect detection works identically across every
|
|
6
|
+
* repo without per-consumer ping plumbing.
|
|
7
7
|
*
|
|
8
8
|
* The client's activity-aware heartbeat timer (in
|
|
9
9
|
* `FrontendWebsocketClient`) issues a `heartbeat` request whenever the
|
|
@@ -37,9 +37,12 @@ export const heartbeat_action_spec = {
|
|
|
37
37
|
/** Handler — nullary echo. Stateless, suitable for high-frequency pings. */
|
|
38
38
|
export const heartbeat_handler = () => ({});
|
|
39
39
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
40
|
+
* Protocol-action tuple — spread into the server's `actions` array for
|
|
41
|
+
* dispatch (or via `protocol_actions` from `./protocol.js`) so the
|
|
42
|
+
* dispatcher resolves the heartbeat handler. The frontend-side spread
|
|
43
|
+
* happens via `protocol_action_specs` — the client doesn't run the echo
|
|
44
|
+
* handler, but the spec must be in `ActionRegistry` so `create_rpc_client`
|
|
45
|
+
* types `app.api.heartbeat()` against the shared spec.
|
|
43
46
|
*/
|
|
44
47
|
export const heartbeat_action = {
|
|
45
48
|
spec: heartbeat_action_spec,
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical bundles of fuz_app's protocol actions — `heartbeat` and
|
|
3
|
+
* `cancel`. Spread these into consumer registrations on both sides of the
|
|
4
|
+
* wire so the registries stay symmetric without per-consumer plumbing.
|
|
5
|
+
*
|
|
6
|
+
* Protocol actions are wire-protocol concerns (liveness, abort) shipped by
|
|
7
|
+
* fuz_app, not consumer domain logic. The split is intentional: the server
|
|
8
|
+
* needs `{spec, handler}` tuples to drive dispatch; the frontend
|
|
9
|
+
* `ActionRegistry` only stores specs. The codegen
|
|
10
|
+
* `include_protocol_actions: false` default (in `action_codegen.ts`) is the
|
|
11
|
+
* third leg of this contract — protocol actions are excluded from
|
|
12
|
+
* generated typed surfaces because consumers spread them in at
|
|
13
|
+
* registration time.
|
|
14
|
+
*
|
|
15
|
+
* Adding a future protocol action (e.g. clock-skew probe, reconnect-resume
|
|
16
|
+
* token) means appending to these arrays in one place; no consumer
|
|
17
|
+
* migration required.
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
import type { ActionSpecUnion } from './action_spec.js';
|
|
22
|
+
import type { Action } from './action_types.js';
|
|
23
|
+
/**
|
|
24
|
+
* Canonical protocol `{spec, handler}` tuples for the server's
|
|
25
|
+
* `register_action_ws` `actions` array. Spread before consumer-owned actions
|
|
26
|
+
* so disconnect detection and per-request cancel work uniformly:
|
|
27
|
+
*
|
|
28
|
+
* ```ts
|
|
29
|
+
* register_action_ws({actions: [...protocol_actions, ...consumer_actions], ...})
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare const protocol_actions: ReadonlyArray<Action>;
|
|
33
|
+
/**
|
|
34
|
+
* Canonical protocol specs for `ActionRegistry` construction on the
|
|
35
|
+
* frontend. Spread before consumer-owned specs so dispatcher-owned methods
|
|
36
|
+
* are present in the lookup map even though codegen excludes them from the
|
|
37
|
+
* generated `action_specs` array:
|
|
38
|
+
*
|
|
39
|
+
* ```ts
|
|
40
|
+
* new ActionRegistry([...protocol_action_specs, ...action_specs])
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* Derived from `protocol_actions` so a future protocol action lands in one
|
|
44
|
+
* place — the two arrays cannot drift.
|
|
45
|
+
*/
|
|
46
|
+
export declare const protocol_action_specs: ReadonlyArray<ActionSpecUnion>;
|
|
47
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,mBAAmB,CAAC;AAI9C;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,EAAE,aAAa,CAAC,MAAM,CAAqC,CAAC;AAEzF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,qBAAqB,EAAE,aAAa,CAAC,eAAe,CAEhE,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical bundles of fuz_app's protocol actions — `heartbeat` and
|
|
3
|
+
* `cancel`. Spread these into consumer registrations on both sides of the
|
|
4
|
+
* wire so the registries stay symmetric without per-consumer plumbing.
|
|
5
|
+
*
|
|
6
|
+
* Protocol actions are wire-protocol concerns (liveness, abort) shipped by
|
|
7
|
+
* fuz_app, not consumer domain logic. The split is intentional: the server
|
|
8
|
+
* needs `{spec, handler}` tuples to drive dispatch; the frontend
|
|
9
|
+
* `ActionRegistry` only stores specs. The codegen
|
|
10
|
+
* `include_protocol_actions: false` default (in `action_codegen.ts`) is the
|
|
11
|
+
* third leg of this contract — protocol actions are excluded from
|
|
12
|
+
* generated typed surfaces because consumers spread them in at
|
|
13
|
+
* registration time.
|
|
14
|
+
*
|
|
15
|
+
* Adding a future protocol action (e.g. clock-skew probe, reconnect-resume
|
|
16
|
+
* token) means appending to these arrays in one place; no consumer
|
|
17
|
+
* migration required.
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
import { cancel_action } from './cancel.js';
|
|
22
|
+
import { heartbeat_action } from './heartbeat.js';
|
|
23
|
+
/**
|
|
24
|
+
* Canonical protocol `{spec, handler}` tuples for the server's
|
|
25
|
+
* `register_action_ws` `actions` array. Spread before consumer-owned actions
|
|
26
|
+
* so disconnect detection and per-request cancel work uniformly:
|
|
27
|
+
*
|
|
28
|
+
* ```ts
|
|
29
|
+
* register_action_ws({actions: [...protocol_actions, ...consumer_actions], ...})
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export const protocol_actions = [heartbeat_action, cancel_action];
|
|
33
|
+
/**
|
|
34
|
+
* Canonical protocol specs for `ActionRegistry` construction on the
|
|
35
|
+
* frontend. Spread before consumer-owned specs so dispatcher-owned methods
|
|
36
|
+
* are present in the lookup map even though codegen excludes them from the
|
|
37
|
+
* generated `action_specs` array:
|
|
38
|
+
*
|
|
39
|
+
* ```ts
|
|
40
|
+
* new ActionRegistry([...protocol_action_specs, ...action_specs])
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* Derived from `protocol_actions` so a future protocol action lands in one
|
|
44
|
+
* place — the two arrays cannot drift.
|
|
45
|
+
*/
|
|
46
|
+
export const protocol_action_specs = protocol_actions.map((a) => a.spec);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* WebSocket JSON-RPC dispatch — the low-level WS transport binding.
|
|
3
3
|
*
|
|
4
4
|
* Most consumers should mount WS endpoints via `register_ws_endpoint`
|
|
5
|
-
* (
|
|
5
|
+
* (`actions/register_ws_endpoint.ts`), which wraps this function with the standard
|
|
6
6
|
* upgrade stack (origin check + auth + optional role). This module stays
|
|
7
7
|
* exported as the lower-level entry point for tests that drive the
|
|
8
8
|
* dispatcher directly via `create_ws_test_harness`.
|
|
@@ -97,8 +97,9 @@ export interface RegisterActionWsOptions<TCtx extends BaseHandlerContext> {
|
|
|
97
97
|
* The actions registered on this endpoint — each carries a spec (drives
|
|
98
98
|
* method lookup, per-action auth, input/output validation) and an
|
|
99
99
|
* optional handler (omit for client-only specs like inbound
|
|
100
|
-
* notifications).
|
|
101
|
-
* complete the disconnect-detection
|
|
100
|
+
* notifications). Spread `protocol_actions` from `actions/protocol.ts`
|
|
101
|
+
* here to complete the disconnect-detection + per-request cancel
|
|
102
|
+
* pairing with the frontend client.
|
|
102
103
|
*/
|
|
103
104
|
actions: ReadonlyArray<Action<TCtx>>;
|
|
104
105
|
/**
|
|
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;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;AAC1E,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,wBAAwB,CAAC;AAiBjD,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
|
|
1
|
+
{"version":3,"file":"register_action_ws.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/register_action_ws.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;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;AAC1E,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,wBAAwB,CAAC;AAiBjD,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;;;;;;;OAOG;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,sBA8WF,CAAC"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* WebSocket JSON-RPC dispatch — the low-level WS transport binding.
|
|
3
3
|
*
|
|
4
4
|
* Most consumers should mount WS endpoints via `register_ws_endpoint`
|
|
5
|
-
* (
|
|
5
|
+
* (`actions/register_ws_endpoint.ts`), which wraps this function with the standard
|
|
6
6
|
* upgrade stack (origin check + auth + optional role). This module stays
|
|
7
7
|
* exported as the lower-level entry point for tests that drive the
|
|
8
8
|
* dispatcher directly via `create_ws_test_harness`.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Account RPC action specs — declarative contract for self-service account
|
|
3
3
|
* operations. Import this module for the specs, Input/Output schemas, and
|
|
4
4
|
* the `all_account_action_specs` registry. Handlers live in
|
|
5
|
-
*
|
|
5
|
+
* `auth/account_actions.ts` so consumers doing typed-client codegen or surface
|
|
6
6
|
* reporting don't transitively drag in server-only query code.
|
|
7
7
|
*
|
|
8
8
|
* @module
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Account RPC action specs — declarative contract for self-service account
|
|
3
3
|
* operations. Import this module for the specs, Input/Output schemas, and
|
|
4
4
|
* the `all_account_action_specs` registry. Handlers live in
|
|
5
|
-
*
|
|
5
|
+
* `auth/account_actions.ts` so consumers doing typed-client codegen or surface
|
|
6
6
|
* reporting don't transitively drag in server-only query code.
|
|
7
7
|
*
|
|
8
8
|
* @module
|
|
@@ -9,14 +9,14 @@
|
|
|
9
9
|
* - API token management: `account_token_create`, `account_token_list`,
|
|
10
10
|
* `account_token_revoke`.
|
|
11
11
|
*
|
|
12
|
-
* The action specs themselves live in
|
|
12
|
+
* The action specs themselves live in `auth/account_action_specs.ts`. Every spec
|
|
13
13
|
* declares `auth: 'authenticated'` so the dispatcher enforces auth before the
|
|
14
14
|
* handler runs. Revoke operations are account-scoped (via
|
|
15
15
|
* `query_session_revoke_for_account` / `query_revoke_api_token_for_account`)
|
|
16
16
|
* so passing another account's session or token id returns `revoked: false`
|
|
17
17
|
* rather than revealing whether the id exists.
|
|
18
18
|
*
|
|
19
|
-
* Counterpart to `account_routes.ts`, which keeps the cookie-lifecycle flows
|
|
19
|
+
* Counterpart to `auth/account_routes.ts`, which keeps the cookie-lifecycle flows
|
|
20
20
|
* (`login`, `logout`, `password`, `signup`, `bootstrap`) on REST.
|
|
21
21
|
*
|
|
22
22
|
* @module
|
|
@@ -9,14 +9,14 @@
|
|
|
9
9
|
* - API token management: `account_token_create`, `account_token_list`,
|
|
10
10
|
* `account_token_revoke`.
|
|
11
11
|
*
|
|
12
|
-
* The action specs themselves live in
|
|
12
|
+
* The action specs themselves live in `auth/account_action_specs.ts`. Every spec
|
|
13
13
|
* declares `auth: 'authenticated'` so the dispatcher enforces auth before the
|
|
14
14
|
* handler runs. Revoke operations are account-scoped (via
|
|
15
15
|
* `query_session_revoke_for_account` / `query_revoke_api_token_for_account`)
|
|
16
16
|
* so passing another account's session or token id returns `revoked: false`
|
|
17
17
|
* rather than revealing whether the id exists.
|
|
18
18
|
*
|
|
19
|
-
* Counterpart to `account_routes.ts`, which keeps the cookie-lifecycle flows
|
|
19
|
+
* Counterpart to `auth/account_routes.ts`, which keeps the cookie-lifecycle flows
|
|
20
20
|
* (`login`, `logout`, `password`, `signup`, `bootstrap`) on REST.
|
|
21
21
|
*
|
|
22
22
|
* @module
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Admin RPC action specs — declarative contract for admin-only operations.
|
|
3
3
|
*
|
|
4
4
|
* Import this module for the specs, Input/Output schemas, and the
|
|
5
|
-
* `all_admin_action_specs` registry. Handlers live in
|
|
5
|
+
* `all_admin_action_specs` registry. Handlers live in `auth/admin_actions.ts`.
|
|
6
6
|
*
|
|
7
7
|
* Authorization is declared at the spec level (`auth: {role: ROLE_ADMIN}`)
|
|
8
8
|
* so the RPC dispatcher enforces admin before the handler runs and the
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Admin RPC action specs — declarative contract for admin-only operations.
|
|
3
3
|
*
|
|
4
4
|
* Import this module for the specs, Input/Output schemas, and the
|
|
5
|
-
* `all_admin_action_specs` registry. Handlers live in
|
|
5
|
+
* `all_admin_action_specs` registry. Handlers live in `auth/admin_actions.ts`.
|
|
6
6
|
*
|
|
7
7
|
* Authorization is declared at the spec level (`auth: {role: ROLE_ADMIN}`)
|
|
8
8
|
* so the RPC dispatcher enforces admin before the handler runs and the
|
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
* when `AdminActionOptions.app_settings` is provided — the mutable ref is
|
|
12
12
|
* owned by the server context and shared with signup middleware).
|
|
13
13
|
*
|
|
14
|
-
* The action specs themselves live in
|
|
14
|
+
* The action specs themselves live in `auth/admin_action_specs.ts`. Mutations
|
|
15
15
|
* emit matching audit events via `audit_log_fire_and_forget`.
|
|
16
16
|
*
|
|
17
17
|
* Authorization is declared at the spec level (`auth: {role: 'admin'}`) so
|
|
18
18
|
* the RPC dispatcher enforces it before the handler runs and the generated
|
|
19
19
|
* surface accurately reports the requirement. `permit_revoke` in
|
|
20
|
-
* `permit_offer_actions.ts` uses the same spec-level pattern even though its
|
|
20
|
+
* `auth/permit_offer_actions.ts` uses the same spec-level pattern even though its
|
|
21
21
|
* sibling methods are authenticated-but-not-admin — the dispatcher checks
|
|
22
22
|
* auth per-spec, so mixed-auth endpoints compose cleanly. Handler-level
|
|
23
23
|
* gates are reserved for input-dependent elevation (e.g.
|
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
* when `AdminActionOptions.app_settings` is provided — the mutable ref is
|
|
12
12
|
* owned by the server context and shared with signup middleware).
|
|
13
13
|
*
|
|
14
|
-
* The action specs themselves live in
|
|
14
|
+
* The action specs themselves live in `auth/admin_action_specs.ts`. Mutations
|
|
15
15
|
* emit matching audit events via `audit_log_fire_and_forget`.
|
|
16
16
|
*
|
|
17
17
|
* Authorization is declared at the spec level (`auth: {role: 'admin'}`) so
|
|
18
18
|
* the RPC dispatcher enforces it before the handler runs and the generated
|
|
19
19
|
* surface accurately reports the requirement. `permit_revoke` in
|
|
20
|
-
* `permit_offer_actions.ts` uses the same spec-level pattern even though its
|
|
20
|
+
* `auth/permit_offer_actions.ts` uses the same spec-level pattern even though its
|
|
21
21
|
* sibling methods are authenticated-but-not-admin — the dispatcher checks
|
|
22
22
|
* auth per-spec, so mixed-auth endpoints compose cleanly. Handler-level
|
|
23
23
|
* gates are reserved for input-dependent elevation (e.g.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Import this module for the specs, Input/Output schemas, `ERROR_OFFER_*`
|
|
6
6
|
* reason constants, and the `all_permit_offer_action_specs` registry.
|
|
7
|
-
* Handlers live in
|
|
7
|
+
* Handlers live in `auth/permit_offer_actions.ts`.
|
|
8
8
|
*
|
|
9
9
|
* Authorization enforcement: offer-lifecycle specs declare
|
|
10
10
|
* `auth: 'authenticated'` and rely on `query_*` IDOR guards or in-handler
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Import this module for the specs, Input/Output schemas, `ERROR_OFFER_*`
|
|
6
6
|
* reason constants, and the `all_permit_offer_action_specs` registry.
|
|
7
|
-
* Handlers live in
|
|
7
|
+
* Handlers live in `auth/permit_offer_actions.ts`.
|
|
8
8
|
*
|
|
9
9
|
* Authorization enforcement: offer-lifecycle specs declare
|
|
10
10
|
* `auth: 'authenticated'` and rely on `query_*` IDOR guards or in-handler
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Seven actions: six offer-lifecycle methods (create / accept / decline /
|
|
5
5
|
* retract / list / history) plus `permit_revoke` (admin-only). All mount
|
|
6
6
|
* on a consumer's JSON-RPC endpoint via `create_rpc_endpoint`. The action
|
|
7
|
-
* specs themselves live in
|
|
7
|
+
* specs themselves live in `auth/permit_offer_action_specs.ts`. Mutations
|
|
8
8
|
* declare `side_effects: true` so the RPC dispatcher wraps the handler in
|
|
9
9
|
* a DB transaction; `permit_offer_list` and `permit_offer_history` declare
|
|
10
10
|
* `side_effects: false` so they are addressable via GET.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Seven actions: six offer-lifecycle methods (create / accept / decline /
|
|
5
5
|
* retract / list / history) plus `permit_revoke` (admin-only). All mount
|
|
6
6
|
* on a consumer's JSON-RPC endpoint via `create_rpc_endpoint`. The action
|
|
7
|
-
* specs themselves live in
|
|
7
|
+
* specs themselves live in `auth/permit_offer_action_specs.ts`. Mutations
|
|
8
8
|
* declare `side_effects: true` so the RPC dispatcher wraps the handler in
|
|
9
9
|
* a DB transaction; `permit_offer_list` and `permit_offer_history` declare
|
|
10
10
|
* `side_effects: false` so they are addressable via GET.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Aggregate spec list mirroring `create_standard_rpc_actions` on the backend.
|
|
3
3
|
*
|
|
4
|
-
* `create_standard_rpc_actions` (in
|
|
4
|
+
* `create_standard_rpc_actions` (in `auth/standard_rpc_actions.ts`) bundles three
|
|
5
5
|
* action registries into one mounted RPC surface: admin + permit_offer +
|
|
6
6
|
* account. Frontends mounting that surface need the matching spec list to
|
|
7
7
|
* feed `create_rpc_client` so the typed Proxy knows about every standard
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Aggregate spec list mirroring `create_standard_rpc_actions` on the backend.
|
|
3
3
|
*
|
|
4
|
-
* `create_standard_rpc_actions` (in
|
|
4
|
+
* `create_standard_rpc_actions` (in `auth/standard_rpc_actions.ts`) bundles three
|
|
5
5
|
* action registries into one mounted RPC surface: admin + permit_offer +
|
|
6
6
|
* account. Frontends mounting that surface need the matching spec list to
|
|
7
7
|
* feed `create_rpc_client` so the typed Proxy knows about every standard
|