@fuzdev/fuz_app 0.45.0 → 0.47.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 +56 -4
- package/dist/actions/action_codegen.d.ts +169 -3
- package/dist/actions/action_codegen.d.ts.map +1 -1
- package/dist/actions/action_codegen.js +417 -8
- package/dist/actions/action_event_helpers.d.ts.map +1 -1
- package/dist/actions/action_event_helpers.js +16 -8
- package/dist/actions/action_event_types.d.ts.map +1 -1
- package/dist/actions/action_event_types.js +6 -0
- package/dist/actions/frontend_rpc_client.d.ts +25 -7
- package/dist/actions/frontend_rpc_client.d.ts.map +1 -1
- package/dist/actions/frontend_rpc_client.js +8 -8
- package/dist/actions/rpc_client.d.ts +12 -4
- package/dist/actions/rpc_client.d.ts.map +1 -1
- package/dist/ui/admin_rpc_adapters.d.ts +2 -2
- package/dist/ui/admin_rpc_adapters.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/actions/CLAUDE.md
CHANGED
|
@@ -77,14 +77,66 @@ the system matures.
|
|
|
77
77
|
`action_codegen.ts` provides gen helpers (used by consumer `*.gen.ts` files,
|
|
78
78
|
not the runtime):
|
|
79
79
|
|
|
80
|
+
### Primitives
|
|
81
|
+
|
|
80
82
|
- `ImportBuilder` — tracks value / type / namespace imports; emits `import type` when every entry on a module is a type (tree-shaking). Namespace (`* as specs`) entries are emitted verbatim. Public surface: `add`, `add_type`, `add_many`, `add_types`, `build`, `preview`, `has_imports`, `import_count`, `clear`.
|
|
81
83
|
- `get_executor_phases(spec, executor)` — phases a given executor (`'frontend' | 'backend'`) participates in for the spec. Deduplicates via `Set` (handles `initiator: 'both'` overlap).
|
|
82
|
-
- `get_handler_return_type(spec, phase, imports,
|
|
83
|
-
- `generate_phase_handlers(spec, executor, imports, {action_event_type?})` — emits the typed handler-map fragment for one action; consumers compose these into `ActionHandlers` types.
|
|
84
|
-
- `generate_actions_api_method_signature(spec, {sync_returns_value?})` — single source of truth for the typed `ActionsApi` 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.
|
|
84
|
+
- `get_handler_return_type(spec, phase, imports, collections_path?)` — the TS type a phase handler must return; triggers the `ActionOutputs` import (sourced from `collections_path`, default `'./action_collections.js'`) as a side effect.
|
|
85
|
+
- `generate_phase_handlers(spec, executor, imports, {action_event_type?, collections_path?})` — emits the typed handler-map fragment for one action; consumers compose these into `ActionHandlers` types.
|
|
86
|
+
- `generate_actions_api_method_signature(spec, {sync_returns_value?})` — single source of truth for the typed `ActionsApi` 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.
|
|
85
87
|
- `create_banner(origin_path)` — gen banner comment.
|
|
86
88
|
- `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`).
|
|
87
|
-
- `
|
|
89
|
+
- `COMPOSABLE_ACTION_METHODS` (+ `ComposableActionMethod` type) — readonly tuple `['heartbeat', 'cancel']`. Consumers spread when filtering backend `request_response` methods so dispatcher-owned composables don't leak into `BackendRequestResponseMethod` / handler maps.
|
|
90
|
+
- `is_composable_action_method(method)` — type predicate paired with `COMPOSABLE_ACTION_METHODS`; use this in `method_filter` callbacks instead of `COMPOSABLE_ACTION_METHODS.includes(s.method as never)`.
|
|
91
|
+
- `DEFAULT_COLLECTIONS_PATH = './action_collections.js'` — shared default for every helper that takes a `collections_path?`.
|
|
92
|
+
- `DEFAULT_SPECS_MODULE = './action_specs.js'` — shared default for helpers that emit `specs.{method}_action_spec` and need a `* as specs` namespace import.
|
|
93
|
+
- `DEFAULT_METATYPES_PATH = './action_metatypes.js'` — shared default for the sibling module carrying the generated `ActionMethod` enum.
|
|
94
|
+
|
|
95
|
+
### High-level helpers (Step 1 of codegen orchestration upstream — 2026-04-26)
|
|
96
|
+
|
|
97
|
+
Each accepts `(specs, imports, options?)` and returns one block of declarations.
|
|
98
|
+
Composed by consumer `*.gen.ts` producers; outputs do not include the banner or
|
|
99
|
+
surrounding `imports.build()`.
|
|
100
|
+
|
|
101
|
+
**Composables are filtered by default.** Every spec-iterating helper accepts
|
|
102
|
+
`{include_composables?: boolean}` (default `false`) and drops `heartbeat` /
|
|
103
|
+
`cancel` from the emitted output. Composables ship from fuz_app and are
|
|
104
|
+
spread into each consumer's `actions` array at registration time — they
|
|
105
|
+
should not appear in consumer-owned typed surfaces (`ActionMethod`,
|
|
106
|
+
`ActionsApi`, `ActionInputs`, `FrontendActionHandlers`, etc.). Pass
|
|
107
|
+
`include_composables: true` only if a consumer genuinely owns composables
|
|
108
|
+
in their typed API.
|
|
109
|
+
|
|
110
|
+
**Consumer tiers and the single-namespace assumption.** Single-source consumers
|
|
111
|
+
(zzz, undying — every spec lives in one local `action_specs.ts`) drop straight
|
|
112
|
+
into the helpers. Multi-source consumers (tx, visiones — which stitch local
|
|
113
|
+
specs together with `all_admin_action_specs` / `all_permit_offer_action_specs` /
|
|
114
|
+
`all_account_action_specs` / `all_self_service_role_action_specs` from fuz_app)
|
|
115
|
+
need a per-method namespace lookup, and the helpers that emit
|
|
116
|
+
`specs.{method}_action_spec` (`generate_action_specs_record`,
|
|
117
|
+
`generate_action_inputs_outputs`, `generate_backend_actions_api`) currently
|
|
118
|
+
assume one `* as specs from specs_module` import covers everything. Multi-source
|
|
119
|
+
consumers keep using the lower-level primitives directly
|
|
120
|
+
(`to_action_spec_input_identifier`, `to_action_spec_output_identifier`,
|
|
121
|
+
`ActionRegistry`) — see tx's `action_collections.gen.ts` for the current
|
|
122
|
+
pattern. A `qualify_spec?: (spec) => string` callback is the planned extension
|
|
123
|
+
point; design it against the Step 3 (tx parity) consumer.
|
|
124
|
+
|
|
125
|
+
Tier 1 (HTTP-only, e.g. tx/visiones) emits a smaller surface — typically just
|
|
126
|
+
`ActionMethod` + `ActionsApi` + `ActionInputs` / `ActionOutputs` interfaces —
|
|
127
|
+
and never calls `generate_typed_action_event_alias` or
|
|
128
|
+
`generate_frontend_action_handlers`. Tier 2 (`TypedActionEvent`-aware, e.g.
|
|
129
|
+
zzz) emits the full set including `ActionEventDatas`, `TypedActionEvent`, and
|
|
130
|
+
`FrontendActionHandlers`.
|
|
131
|
+
|
|
132
|
+
- `generate_action_method_enums(specs, imports, {emit?})` — up to six `z.enum` + `z.infer` pairs (`ActionMethod`, `RequestResponseActionMethod`, `RemoteNotificationActionMethod`, `LocalCallActionMethod`, `FrontendActionMethod`, `BackendActionMethod`). `emit: ReadonlySet<ActionMethodEnumKind>` restricts to a subset (Tier 1 HTTP-only consumers don't need all six). 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.
|
|
133
|
+
- `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`).
|
|
134
|
+
- `generate_action_specs_record(specs, imports, {specs_module?})` — `ActionSpecs` runtime const + interface + `action_specs: Array<ActionSpecUnion>` value. Adds `* as specs` from `specs_module`.
|
|
135
|
+
- `generate_action_inputs_outputs(specs, imports, {specs_module?})` — `ActionInputs` and `ActionOutputs` runtime consts + interfaces. Adds `* as specs` from `specs_module`.
|
|
136
|
+
- `generate_action_event_datas(specs, imports, {collections_path?})` — `ActionEventDatas` interface; per-spec variant by kind (`ActionEventRequestResponseData` / `ActionEventRemoteNotificationData` / `ActionEventLocalCallData`). When `collections_path` is set, adds `ActionInputs` / `ActionOutputs` type imports from that path; default (unset) assumes same-file scope, the zzz pattern where this helper feeds the same `action_collections.ts` output as `generate_action_inputs_outputs`.
|
|
137
|
+
- `generate_actions_api(specs, imports, {method_filter?, collections_path?, sync_returns_value?})` — `ActionsApi` interface. Composables filtered by default; `method_filter: (spec) => boolean` runs after the composable filter for tx-style additional subsets.
|
|
138
|
+
- `generate_frontend_action_handlers(specs, imports, {collections_path?})` — `FrontendActionHandlers` interface (Tier 2 only — wraps `generate_phase_handlers` with `action_event_type: 'TypedActionEvent'`). Pair with `generate_typed_action_event_alias`.
|
|
139
|
+
- `generate_backend_actions_api(specs, imports, {specs_module?, collections_path?})` — `BackendActionsApi` interface AND `broadcast_action_specs: ReadonlyArray<ActionSpecUnion>` array. Filter: `kind === 'remote_notification' && initiator !== 'frontend'`. Adds the `* as specs` namespace import + `ActionInputs` (from `collections_path`) + `ActionSpecUnion`.
|
|
88
140
|
|
|
89
141
|
## HTTP bridge (`action_bridge.ts`)
|
|
90
142
|
|
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
import type { ActionSpecUnion, ActionEventPhase } from './action_spec.js';
|
|
2
|
+
/**
|
|
3
|
+
* Method names of composable actions exported from fuz_app — `heartbeat` (auth-aware
|
|
4
|
+
* client liveness probe) and `cancel` (request-scoped abort signal). Consumers spread
|
|
5
|
+
* this list when filtering backend request_response methods so the dispatcher-owned
|
|
6
|
+
* composables don't show up in `BackendRequestResponseMethod` / handler maps.
|
|
7
|
+
*/
|
|
8
|
+
export declare const COMPOSABLE_ACTION_METHODS: readonly ["heartbeat", "cancel"];
|
|
9
|
+
/** Methods that ship from fuz_app, kept out of consumer-owned method enums + handler maps. */
|
|
10
|
+
export type ComposableActionMethod = (typeof COMPOSABLE_ACTION_METHODS)[number];
|
|
11
|
+
/**
|
|
12
|
+
* Type predicate for filtering composable methods out of a typed `ActionsApi`
|
|
13
|
+
* `method_filter`. Avoids the `(... as never)` cast required to call
|
|
14
|
+
* `Array.prototype.includes` on the readonly tuple at narrow string types.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* generate_actions_api(specs, imports, {
|
|
18
|
+
* method_filter: (s) => !is_composable_action_method(s.method),
|
|
19
|
+
* });
|
|
20
|
+
*/
|
|
21
|
+
export declare const is_composable_action_method: (method: string) => method is ComposableActionMethod;
|
|
2
22
|
/**
|
|
3
23
|
* Represents an import item with its kind (type, value, or namespace).
|
|
4
24
|
*/
|
|
@@ -79,20 +99,30 @@ export declare class ImportBuilder {
|
|
|
79
99
|
* Determines which phases an executor can handle based on the action spec.
|
|
80
100
|
*/
|
|
81
101
|
export declare const get_executor_phases: (spec: ActionSpecUnion, executor: "frontend" | "backend") => Array<ActionEventPhase>;
|
|
102
|
+
/** Default `collections_path` — every consumer's gen producers point at the sibling `action_collections.js`. */
|
|
103
|
+
export declare const DEFAULT_COLLECTIONS_PATH = "./action_collections.js";
|
|
104
|
+
/** Default `specs_module` — sibling `action_specs.js` namespace bundled by the consumer. */
|
|
105
|
+
export declare const DEFAULT_SPECS_MODULE = "./action_specs.js";
|
|
106
|
+
/** Default `metatypes_path` — sibling `action_metatypes.js` carrying the generated `ActionMethod`. */
|
|
107
|
+
export declare const DEFAULT_METATYPES_PATH = "./action_metatypes.js";
|
|
82
108
|
/**
|
|
83
|
-
* Gets the handler return type for a specific phase and spec.
|
|
84
|
-
*
|
|
109
|
+
* Gets the handler return type for a specific phase and spec. Adds an
|
|
110
|
+
* `ActionOutputs` import (from `collections_path`) when the phase carries an
|
|
111
|
+
* output (request_response `receive_request`, local_call `execute`).
|
|
85
112
|
*/
|
|
86
|
-
export declare const get_handler_return_type: (spec: ActionSpecUnion, phase: ActionEventPhase, imports: ImportBuilder,
|
|
113
|
+
export declare const get_handler_return_type: (spec: ActionSpecUnion, phase: ActionEventPhase, imports: ImportBuilder, collections_path?: string) => string;
|
|
87
114
|
/**
|
|
88
115
|
* Generates the phase handlers for an action spec using the unified ActionEvent type
|
|
89
116
|
* with the new phase/step type parameters.
|
|
90
117
|
*
|
|
91
118
|
* @param options.action_event_type - custom type name to use instead of `ActionEvent`
|
|
92
119
|
* (consumers can define a narrowed type that carries typed input/output via their codegen maps)
|
|
120
|
+
* @param options.collections_path - import path the side-effect `ActionOutputs` import
|
|
121
|
+
* resolves to. Defaults to `'./action_collections.js'`.
|
|
93
122
|
*/
|
|
94
123
|
export declare const generate_phase_handlers: (spec: ActionSpecUnion, executor: "frontend" | "backend", imports: ImportBuilder, options?: {
|
|
95
124
|
action_event_type?: string;
|
|
125
|
+
collections_path?: string;
|
|
96
126
|
}) => string;
|
|
97
127
|
/**
|
|
98
128
|
* Creates a file banner comment.
|
|
@@ -132,5 +162,141 @@ export declare const to_action_spec_output_identifier: (method: string) => strin
|
|
|
132
162
|
export declare const generate_actions_api_method_signature: (spec: ActionSpecUnion, options?: {
|
|
133
163
|
sync_returns_value?: boolean;
|
|
134
164
|
}) => string;
|
|
165
|
+
/** Discriminator for `generate_action_method_enums` — which method-set enums to emit. */
|
|
166
|
+
export type ActionMethodEnumKind = 'all' | 'request_response' | 'remote_notification' | 'local_call' | 'frontend' | 'backend';
|
|
167
|
+
/** Default emit set — every enum kind. */
|
|
168
|
+
export declare const ACTION_METHOD_ENUM_KINDS_ALL: ReadonlySet<ActionMethodEnumKind>;
|
|
169
|
+
/**
|
|
170
|
+
* Emit one or more `z.enum([...])` declarations for action method names —
|
|
171
|
+
* `ActionMethod`, `RequestResponseActionMethod`, `RemoteNotificationActionMethod`,
|
|
172
|
+
* `LocalCallActionMethod`, `FrontendActionMethod`, `BackendActionMethod`. Pairs
|
|
173
|
+
* each runtime const with a `z.infer` type alias under the same identifier.
|
|
174
|
+
*
|
|
175
|
+
* Composable methods (`heartbeat`, `cancel`) are filtered out by default —
|
|
176
|
+
* pass `include_composables: true` if a consumer genuinely wants them on
|
|
177
|
+
* their typed surface. Empty kinds are skipped so the helper never emits
|
|
178
|
+
* `z.enum([])` (zod runtime-throws on that).
|
|
179
|
+
*
|
|
180
|
+
* Adds `import {z} from 'zod';` to `imports` only when at least one block
|
|
181
|
+
* is emitted (idempotent).
|
|
182
|
+
*
|
|
183
|
+
* @param options.emit - subset of enums to emit; defaults to all six.
|
|
184
|
+
* @param options.include_composables - when true, retains `heartbeat` /
|
|
185
|
+
* `cancel` in the emitted enums. Default `false`.
|
|
186
|
+
*/
|
|
187
|
+
export declare const generate_action_method_enums: (specs: ReadonlyArray<ActionSpecUnion>, imports: ImportBuilder, options?: {
|
|
188
|
+
emit?: ReadonlySet<ActionMethodEnumKind>;
|
|
189
|
+
include_composables?: boolean;
|
|
190
|
+
}) => string;
|
|
191
|
+
/**
|
|
192
|
+
* Emit the fixed-shape `TypedActionEvent` alias used by `FrontendActionHandlers`
|
|
193
|
+
* to narrow `ActionEvent.data` against the consumer's generated `ActionEventDatas`
|
|
194
|
+
* map. Registers the four fuz_app type imports it needs (`ActionEvent`,
|
|
195
|
+
* `ActionEventPhase`, `ActionEventStep`, `ActionEventDatas`) plus the
|
|
196
|
+
* `ActionMethod` type import — sourced from `collections_path` and
|
|
197
|
+
* `metatypes_path` respectively.
|
|
198
|
+
*
|
|
199
|
+
* Pair with `generate_action_method_enums` (emits `ActionMethod` into
|
|
200
|
+
* `metatypes_path`) and `generate_action_event_datas` (emits
|
|
201
|
+
* `ActionEventDatas` into `collections_path`).
|
|
202
|
+
*/
|
|
203
|
+
export declare const generate_typed_action_event_alias: (imports: ImportBuilder, options?: {
|
|
204
|
+
collections_path?: string;
|
|
205
|
+
metatypes_path?: string;
|
|
206
|
+
}) => string;
|
|
207
|
+
/**
|
|
208
|
+
* Emit the `ActionSpecs` runtime const + interface + the `action_specs:
|
|
209
|
+
* Array<ActionSpecUnion>` value bundling every spec. Adds the `* as specs`
|
|
210
|
+
* namespace import + the `ActionSpecUnion` type import.
|
|
211
|
+
*
|
|
212
|
+
* **Single-namespace.** Every spec is referenced as `specs.{method}_action_spec`.
|
|
213
|
+
* Multi-source consumers (tx, visiones) need a per-method namespace lookup
|
|
214
|
+
* and currently use lower-level primitives instead — see the `--- High-level
|
|
215
|
+
* codegen helpers ---` banner above for the rationale and the planned
|
|
216
|
+
* `qualify_spec?` extension point.
|
|
217
|
+
*/
|
|
218
|
+
export declare const generate_action_specs_record: (specs: ReadonlyArray<ActionSpecUnion>, imports: ImportBuilder, options?: {
|
|
219
|
+
specs_module?: string;
|
|
220
|
+
include_composables?: boolean;
|
|
221
|
+
}) => string;
|
|
222
|
+
/**
|
|
223
|
+
* Emit `ActionInputs` + `ActionOutputs` runtime consts and matching interfaces.
|
|
224
|
+
* The runtime consts reference `specs.{method}_action_spec.input` /
|
|
225
|
+
* `.output`; the interfaces use `z.infer`.
|
|
226
|
+
*
|
|
227
|
+
* Adds `import {z} from 'zod';` and the `* as specs` namespace import.
|
|
228
|
+
*
|
|
229
|
+
* **Single-namespace.** Same caveat as `generate_action_specs_record` —
|
|
230
|
+
* multi-source consumers use the lower-level primitives.
|
|
231
|
+
*/
|
|
232
|
+
export declare const generate_action_inputs_outputs: (specs: ReadonlyArray<ActionSpecUnion>, imports: ImportBuilder, options?: {
|
|
233
|
+
specs_module?: string;
|
|
234
|
+
include_composables?: boolean;
|
|
235
|
+
}) => string;
|
|
236
|
+
/**
|
|
237
|
+
* Emit the `ActionEventDatas` interface — one `ActionEvent*Data` variant per
|
|
238
|
+
* method, parameterized by the spec's kind:
|
|
239
|
+
* - `request_response` → `ActionEventRequestResponseData<method, input, output>`
|
|
240
|
+
* - `remote_notification` → `ActionEventRemoteNotificationData<method, input>`
|
|
241
|
+
* - `local_call` → `ActionEventLocalCallData<method, input, output>`
|
|
242
|
+
*
|
|
243
|
+
* Adds the per-kind data type imports (only the kinds that appear in `specs`).
|
|
244
|
+
*
|
|
245
|
+
* @param options.collections_path - when set, adds `ActionInputs` /
|
|
246
|
+
* `ActionOutputs` type imports from this path. Leave unset (default) when
|
|
247
|
+
* the producer emits `ActionEventDatas` in the same file as
|
|
248
|
+
* `ActionInputs` / `ActionOutputs` — same-file scope means no imports
|
|
249
|
+
* needed (the zzz pattern, where `generate_action_inputs_outputs` and
|
|
250
|
+
* this helper feed the same `action_collections.ts` output).
|
|
251
|
+
*/
|
|
252
|
+
export declare const generate_action_event_datas: (specs: ReadonlyArray<ActionSpecUnion>, imports: ImportBuilder, options?: {
|
|
253
|
+
collections_path?: string;
|
|
254
|
+
include_composables?: boolean;
|
|
255
|
+
}) => string;
|
|
256
|
+
/**
|
|
257
|
+
* Emit the `ActionsApi` interface — one method signature per spec via
|
|
258
|
+
* `generate_actions_api_method_signature`. Optionally filter the spec set
|
|
259
|
+
* (e.g. omit composable methods) via `method_filter`.
|
|
260
|
+
*
|
|
261
|
+
* Adds the `Result`, `JsonrpcErrorObject`, and `RpcClientCallOptions` type
|
|
262
|
+
* imports plus `ActionInputs` / `ActionOutputs` (sourced from `collections_path`).
|
|
263
|
+
*/
|
|
264
|
+
export declare const generate_actions_api: (specs: ReadonlyArray<ActionSpecUnion>, imports: ImportBuilder, options?: {
|
|
265
|
+
method_filter?: (spec: ActionSpecUnion) => boolean;
|
|
266
|
+
collections_path?: string;
|
|
267
|
+
sync_returns_value?: boolean;
|
|
268
|
+
include_composables?: boolean;
|
|
269
|
+
}) => string;
|
|
270
|
+
/**
|
|
271
|
+
* Emit the `FrontendActionHandlers` interface — wraps `generate_phase_handlers`
|
|
272
|
+
* with the `TypedActionEvent` action-event type and standard 1-tab per-method
|
|
273
|
+
* indentation. Pairs with `generate_typed_action_event_alias` (emits the
|
|
274
|
+
* matching `TypedActionEvent` alias) — call both in the same gen producer.
|
|
275
|
+
*/
|
|
276
|
+
export declare const generate_frontend_action_handlers: (specs: ReadonlyArray<ActionSpecUnion>, imports: ImportBuilder, options?: {
|
|
277
|
+
collections_path?: string;
|
|
278
|
+
include_composables?: boolean;
|
|
279
|
+
}) => string;
|
|
280
|
+
/**
|
|
281
|
+
* Emit BOTH the typed `BackendActionsApi` interface AND the
|
|
282
|
+
* `broadcast_action_specs` runtime array. The interface is shaped for
|
|
283
|
+
* `create_broadcast_api`: backend-initiated `remote_notification` methods,
|
|
284
|
+
* each `(input) => Promise<void>`. The array bundles the matching specs as a
|
|
285
|
+
* `ReadonlyArray<ActionSpecUnion>`.
|
|
286
|
+
*
|
|
287
|
+
* Filter: `kind === 'remote_notification' && initiator !== 'frontend'`.
|
|
288
|
+
*
|
|
289
|
+
* Adds the `* as specs` namespace import (from `specs_module`), the
|
|
290
|
+
* `ActionInputs` type import (from `collections_path`), and the
|
|
291
|
+
* `ActionSpecUnion` type import.
|
|
292
|
+
*
|
|
293
|
+
* **Single-namespace.** Same caveat as `generate_action_specs_record` —
|
|
294
|
+
* multi-source consumers use the lower-level primitives.
|
|
295
|
+
*/
|
|
296
|
+
export declare const generate_backend_actions_api: (specs: ReadonlyArray<ActionSpecUnion>, imports: ImportBuilder, options?: {
|
|
297
|
+
specs_module?: string;
|
|
298
|
+
collections_path?: string;
|
|
299
|
+
include_composables?: boolean;
|
|
300
|
+
}) => string;
|
|
135
301
|
export {};
|
|
136
302
|
//# 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":"AAGA,OAAO,KAAK,EAAC,eAAe,EAAE,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"action_codegen.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_codegen.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
import { UnreachableError } from '@fuzdev/fuz_util/error.js';
|
|
2
2
|
import { zod_get_base_type } from '@fuzdev/fuz_util/zod.js';
|
|
3
|
+
import { ActionRegistry } from './action_registry.js';
|
|
4
|
+
/**
|
|
5
|
+
* Method names of composable actions exported from fuz_app — `heartbeat` (auth-aware
|
|
6
|
+
* client liveness probe) and `cancel` (request-scoped abort signal). Consumers spread
|
|
7
|
+
* this list when filtering backend request_response methods so the dispatcher-owned
|
|
8
|
+
* composables don't show up in `BackendRequestResponseMethod` / handler maps.
|
|
9
|
+
*/
|
|
10
|
+
export const COMPOSABLE_ACTION_METHODS = ['heartbeat', 'cancel'];
|
|
11
|
+
const COMPOSABLE_METHOD_SET = new Set(COMPOSABLE_ACTION_METHODS);
|
|
12
|
+
/**
|
|
13
|
+
* Type predicate for filtering composable methods out of a typed `ActionsApi`
|
|
14
|
+
* `method_filter`. Avoids the `(... as never)` cast required to call
|
|
15
|
+
* `Array.prototype.includes` on the readonly tuple at narrow string types.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* generate_actions_api(specs, imports, {
|
|
19
|
+
* method_filter: (s) => !is_composable_action_method(s.method),
|
|
20
|
+
* });
|
|
21
|
+
*/
|
|
22
|
+
export const is_composable_action_method = (method) => COMPOSABLE_METHOD_SET.has(method);
|
|
3
23
|
/**
|
|
4
24
|
* Manages imports for generated code, building them on demand.
|
|
5
25
|
* Automatically optimizes type-only imports to use `import type` syntax.
|
|
@@ -223,21 +243,28 @@ export const get_executor_phases = (spec, executor) => {
|
|
|
223
243
|
// Deduplicate phases (e.g., send_error added twice for initiator:'both' backend actions)
|
|
224
244
|
return Array.from(new Set(phases));
|
|
225
245
|
};
|
|
246
|
+
/** Default `collections_path` — every consumer's gen producers point at the sibling `action_collections.js`. */
|
|
247
|
+
export const DEFAULT_COLLECTIONS_PATH = './action_collections.js';
|
|
248
|
+
/** Default `specs_module` — sibling `action_specs.js` namespace bundled by the consumer. */
|
|
249
|
+
export const DEFAULT_SPECS_MODULE = './action_specs.js';
|
|
250
|
+
/** Default `metatypes_path` — sibling `action_metatypes.js` carrying the generated `ActionMethod`. */
|
|
251
|
+
export const DEFAULT_METATYPES_PATH = './action_metatypes.js';
|
|
226
252
|
/**
|
|
227
|
-
* Gets the handler return type for a specific phase and spec.
|
|
228
|
-
*
|
|
253
|
+
* Gets the handler return type for a specific phase and spec. Adds an
|
|
254
|
+
* `ActionOutputs` import (from `collections_path`) when the phase carries an
|
|
255
|
+
* output (request_response `receive_request`, local_call `execute`).
|
|
229
256
|
*/
|
|
230
|
-
export const get_handler_return_type = (spec, phase, imports,
|
|
257
|
+
export const get_handler_return_type = (spec, phase, imports, collections_path = DEFAULT_COLLECTIONS_PATH) => {
|
|
231
258
|
// For request_response receive_request, handler returns the output
|
|
232
259
|
if (spec.kind === 'request_response' && phase === 'receive_request') {
|
|
233
|
-
imports.add_type(
|
|
260
|
+
imports.add_type(collections_path, 'ActionOutputs');
|
|
234
261
|
const base_type = `ActionOutputs['${spec.method}']`;
|
|
235
262
|
// Request/response actions are always async
|
|
236
263
|
return `${base_type} | Promise<${base_type}>`;
|
|
237
264
|
}
|
|
238
265
|
// For local_call execute, handler returns the output
|
|
239
266
|
if (spec.kind === 'local_call' && phase === 'execute') {
|
|
240
|
-
imports.add_type(
|
|
267
|
+
imports.add_type(collections_path, 'ActionOutputs');
|
|
241
268
|
const base_type = `ActionOutputs['${spec.method}']`;
|
|
242
269
|
return spec.async ? `${base_type} | Promise<${base_type}>` : base_type;
|
|
243
270
|
}
|
|
@@ -250,6 +277,8 @@ export const get_handler_return_type = (spec, phase, imports, path_prefix) => {
|
|
|
250
277
|
*
|
|
251
278
|
* @param options.action_event_type - custom type name to use instead of `ActionEvent`
|
|
252
279
|
* (consumers can define a narrowed type that carries typed input/output via their codegen maps)
|
|
280
|
+
* @param options.collections_path - import path the side-effect `ActionOutputs` import
|
|
281
|
+
* resolves to. Defaults to `'./action_collections.js'`.
|
|
253
282
|
*/
|
|
254
283
|
export const generate_phase_handlers = (spec, executor, imports, options) => {
|
|
255
284
|
const { method } = spec;
|
|
@@ -258,16 +287,15 @@ export const generate_phase_handlers = (spec, executor, imports, options) => {
|
|
|
258
287
|
return `${method}?: never`;
|
|
259
288
|
}
|
|
260
289
|
const action_event_type = options?.action_event_type ?? 'ActionEvent';
|
|
290
|
+
const collections_path = options?.collections_path ?? DEFAULT_COLLECTIONS_PATH;
|
|
261
291
|
// Only add the default ActionEvent import if using the default type name
|
|
262
292
|
if (action_event_type === 'ActionEvent') {
|
|
263
293
|
imports.add_type('@fuzdev/fuz_app/actions/action_event.js', 'ActionEvent');
|
|
264
294
|
}
|
|
265
|
-
// Generate handler definitions for each phase
|
|
266
|
-
const path_prefix = executor === 'frontend' ? './' : '../';
|
|
267
295
|
const phase_handlers = phases
|
|
268
296
|
.map((phase) => {
|
|
269
297
|
// Pass imports to get_handler_return_type so it can add necessary imports
|
|
270
|
-
const return_type = get_handler_return_type(spec, phase, imports,
|
|
298
|
+
const return_type = get_handler_return_type(spec, phase, imports, collections_path);
|
|
271
299
|
return `${phase}?: (
|
|
272
300
|
action_event: ${action_event_type}<'${method}', '${phase}', 'handling'>
|
|
273
301
|
) => ${return_type}`;
|
|
@@ -328,3 +356,384 @@ export const generate_actions_api_method_signature = (spec, options) => {
|
|
|
328
356
|
: result_return;
|
|
329
357
|
return `${spec.method}: (${input_param}${options_param}) => ${return_type};`;
|
|
330
358
|
};
|
|
359
|
+
/** Default emit set — every enum kind. */
|
|
360
|
+
export const ACTION_METHOD_ENUM_KINDS_ALL = new Set([
|
|
361
|
+
'all',
|
|
362
|
+
'request_response',
|
|
363
|
+
'remote_notification',
|
|
364
|
+
'local_call',
|
|
365
|
+
'frontend',
|
|
366
|
+
'backend',
|
|
367
|
+
]);
|
|
368
|
+
/**
|
|
369
|
+
* Filter `heartbeat` / `cancel` out of `specs` unless the consumer opts back in.
|
|
370
|
+
* Composables ship from fuz_app and are spread into every consumer's `actions`
|
|
371
|
+
* array at registration time — they should not appear in consumer-owned typed
|
|
372
|
+
* surfaces (`ActionMethod`, `ActionsApi`, `ActionInputs`, etc.) by default.
|
|
373
|
+
*/
|
|
374
|
+
const filter_composables = (specs, include_composables) => include_composables ? specs : specs.filter((s) => !is_composable_action_method(s.method));
|
|
375
|
+
/**
|
|
376
|
+
* Emit one or more `z.enum([...])` declarations for action method names —
|
|
377
|
+
* `ActionMethod`, `RequestResponseActionMethod`, `RemoteNotificationActionMethod`,
|
|
378
|
+
* `LocalCallActionMethod`, `FrontendActionMethod`, `BackendActionMethod`. Pairs
|
|
379
|
+
* each runtime const with a `z.infer` type alias under the same identifier.
|
|
380
|
+
*
|
|
381
|
+
* Composable methods (`heartbeat`, `cancel`) are filtered out by default —
|
|
382
|
+
* pass `include_composables: true` if a consumer genuinely wants them on
|
|
383
|
+
* their typed surface. Empty kinds are skipped so the helper never emits
|
|
384
|
+
* `z.enum([])` (zod runtime-throws on that).
|
|
385
|
+
*
|
|
386
|
+
* Adds `import {z} from 'zod';` to `imports` only when at least one block
|
|
387
|
+
* is emitted (idempotent).
|
|
388
|
+
*
|
|
389
|
+
* @param options.emit - subset of enums to emit; defaults to all six.
|
|
390
|
+
* @param options.include_composables - when true, retains `heartbeat` /
|
|
391
|
+
* `cancel` in the emitted enums. Default `false`.
|
|
392
|
+
*/
|
|
393
|
+
export const generate_action_method_enums = (specs, imports, options) => {
|
|
394
|
+
const emit = options?.emit ?? ACTION_METHOD_ENUM_KINDS_ALL;
|
|
395
|
+
const filtered = filter_composables(specs, options?.include_composables);
|
|
396
|
+
const registry = new ActionRegistry([...filtered]);
|
|
397
|
+
const blocks = [];
|
|
398
|
+
const emit_block = (kind, name, methods, jsdoc) => {
|
|
399
|
+
if (!emit.has(kind))
|
|
400
|
+
return;
|
|
401
|
+
// `z.enum([])` is invalid — skip empty kinds rather than emit broken code.
|
|
402
|
+
// Consumers that need a kind to exist should check their spec set, not the helper.
|
|
403
|
+
if (methods.length === 0)
|
|
404
|
+
return;
|
|
405
|
+
const lines = methods.map((m) => `\t'${m}',`).join('\n');
|
|
406
|
+
blocks.push(`/**\n * ${jsdoc}\n */\nexport const ${name} = z.enum([\n${lines}\n]);
|
|
407
|
+
export type ${name} = z.infer<typeof ${name}>;`);
|
|
408
|
+
};
|
|
409
|
+
emit_block('all', 'ActionMethod', registry.methods, 'All action method names. Request/response actions have two types per method.');
|
|
410
|
+
emit_block('request_response', 'RequestResponseActionMethod', registry.request_response_methods, 'Names of all request_response actions.');
|
|
411
|
+
emit_block('remote_notification', 'RemoteNotificationActionMethod', registry.remote_notification_methods, 'Names of all remote_notification actions.');
|
|
412
|
+
emit_block('local_call', 'LocalCallActionMethod', registry.local_call_methods, 'Names of all local_call actions.');
|
|
413
|
+
emit_block('frontend', 'FrontendActionMethod', registry.frontend_methods, 'Names of all actions that may be handled on the client.');
|
|
414
|
+
emit_block('backend', 'BackendActionMethod', registry.backend_methods, 'Names of all actions that may be handled on the server.');
|
|
415
|
+
if (blocks.length === 0)
|
|
416
|
+
return '';
|
|
417
|
+
imports.add('zod', 'z');
|
|
418
|
+
return blocks.join('\n\n');
|
|
419
|
+
};
|
|
420
|
+
/**
|
|
421
|
+
* Emit the fixed-shape `TypedActionEvent` alias used by `FrontendActionHandlers`
|
|
422
|
+
* to narrow `ActionEvent.data` against the consumer's generated `ActionEventDatas`
|
|
423
|
+
* map. Registers the four fuz_app type imports it needs (`ActionEvent`,
|
|
424
|
+
* `ActionEventPhase`, `ActionEventStep`, `ActionEventDatas`) plus the
|
|
425
|
+
* `ActionMethod` type import — sourced from `collections_path` and
|
|
426
|
+
* `metatypes_path` respectively.
|
|
427
|
+
*
|
|
428
|
+
* Pair with `generate_action_method_enums` (emits `ActionMethod` into
|
|
429
|
+
* `metatypes_path`) and `generate_action_event_datas` (emits
|
|
430
|
+
* `ActionEventDatas` into `collections_path`).
|
|
431
|
+
*/
|
|
432
|
+
export const generate_typed_action_event_alias = (imports, options) => {
|
|
433
|
+
const collections_path = options?.collections_path ?? DEFAULT_COLLECTIONS_PATH;
|
|
434
|
+
const metatypes_path = options?.metatypes_path ?? DEFAULT_METATYPES_PATH;
|
|
435
|
+
imports.add_type('@fuzdev/fuz_app/actions/action_event.js', 'ActionEvent');
|
|
436
|
+
imports.add_type('@fuzdev/fuz_app/actions/action_spec.js', 'ActionEventPhase');
|
|
437
|
+
imports.add_type('@fuzdev/fuz_app/actions/action_event_types.js', 'ActionEventStep');
|
|
438
|
+
imports.add_type(collections_path, 'ActionEventDatas');
|
|
439
|
+
imports.add_type(metatypes_path, 'ActionMethod');
|
|
440
|
+
return `/** ActionEvent narrowed with the generated ActionEventDatas for typed input/output. */
|
|
441
|
+
type TypedActionEvent<
|
|
442
|
+
TMethod extends ActionMethod,
|
|
443
|
+
TPhase extends ActionEventPhase,
|
|
444
|
+
TStep extends ActionEventStep,
|
|
445
|
+
> = ActionEvent<TMethod, TPhase, TStep> & {readonly data: ActionEventDatas[TMethod]};`;
|
|
446
|
+
};
|
|
447
|
+
/**
|
|
448
|
+
* Emit the `ActionSpecs` runtime const + interface + the `action_specs:
|
|
449
|
+
* Array<ActionSpecUnion>` value bundling every spec. Adds the `* as specs`
|
|
450
|
+
* namespace import + the `ActionSpecUnion` type import.
|
|
451
|
+
*
|
|
452
|
+
* **Single-namespace.** Every spec is referenced as `specs.{method}_action_spec`.
|
|
453
|
+
* Multi-source consumers (tx, visiones) need a per-method namespace lookup
|
|
454
|
+
* and currently use lower-level primitives instead — see the `--- High-level
|
|
455
|
+
* codegen helpers ---` banner above for the rationale and the planned
|
|
456
|
+
* `qualify_spec?` extension point.
|
|
457
|
+
*/
|
|
458
|
+
export const generate_action_specs_record = (specs, imports, options) => {
|
|
459
|
+
const filtered = filter_composables(specs, options?.include_composables);
|
|
460
|
+
imports.add_type('@fuzdev/fuz_app/actions/action_spec.js', 'ActionSpecUnion');
|
|
461
|
+
if (filtered.length === 0) {
|
|
462
|
+
// Empty spec list — emit minimal valid output and skip the `* as specs`
|
|
463
|
+
// import that would have nothing to reference.
|
|
464
|
+
return `/**
|
|
465
|
+
* Action specifications indexed by method name.
|
|
466
|
+
* These represent the complete action spec definitions.
|
|
467
|
+
*/
|
|
468
|
+
export const ActionSpecs = {} as const;
|
|
469
|
+
export interface ActionSpecs {}
|
|
470
|
+
|
|
471
|
+
export const action_specs: Array<ActionSpecUnion> = Object.values(ActionSpecs);`;
|
|
472
|
+
}
|
|
473
|
+
const specs_module = options?.specs_module ?? DEFAULT_SPECS_MODULE;
|
|
474
|
+
imports.add(specs_module, '* as specs');
|
|
475
|
+
const value_lines = filtered
|
|
476
|
+
.map((s) => `\t${s.method}: specs.${s.method}_action_spec,`)
|
|
477
|
+
.join('\n');
|
|
478
|
+
const type_lines = filtered
|
|
479
|
+
.map((s) => `\t${s.method}: typeof specs.${s.method}_action_spec;`)
|
|
480
|
+
.join('\n');
|
|
481
|
+
return `/**
|
|
482
|
+
* Action specifications indexed by method name.
|
|
483
|
+
* These represent the complete action spec definitions.
|
|
484
|
+
*/
|
|
485
|
+
export const ActionSpecs = {
|
|
486
|
+
${value_lines}
|
|
487
|
+
} as const;
|
|
488
|
+
export interface ActionSpecs {
|
|
489
|
+
${type_lines}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
export const action_specs: Array<ActionSpecUnion> = Object.values(ActionSpecs);`;
|
|
493
|
+
};
|
|
494
|
+
/**
|
|
495
|
+
* Emit `ActionInputs` + `ActionOutputs` runtime consts and matching interfaces.
|
|
496
|
+
* The runtime consts reference `specs.{method}_action_spec.input` /
|
|
497
|
+
* `.output`; the interfaces use `z.infer`.
|
|
498
|
+
*
|
|
499
|
+
* Adds `import {z} from 'zod';` and the `* as specs` namespace import.
|
|
500
|
+
*
|
|
501
|
+
* **Single-namespace.** Same caveat as `generate_action_specs_record` —
|
|
502
|
+
* multi-source consumers use the lower-level primitives.
|
|
503
|
+
*/
|
|
504
|
+
export const generate_action_inputs_outputs = (specs, imports, options) => {
|
|
505
|
+
const filtered = filter_composables(specs, options?.include_composables);
|
|
506
|
+
if (filtered.length === 0) {
|
|
507
|
+
// Empty spec list — emit minimal valid output and skip the `zod` /
|
|
508
|
+
// `* as specs` imports that would have nothing to reference.
|
|
509
|
+
return `/**
|
|
510
|
+
* Action parameter schemas indexed by method name.
|
|
511
|
+
* These represent the input data for each action,
|
|
512
|
+
* e.g. JSON-RPC request/notification params and local call arguments.
|
|
513
|
+
*/
|
|
514
|
+
export const ActionInputs = {} as const;
|
|
515
|
+
export interface ActionInputs {}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Action result schemas indexed by method name.
|
|
519
|
+
* These represent the output data for each action,
|
|
520
|
+
* e.g. JSON-RPC response results and local call return values.
|
|
521
|
+
*/
|
|
522
|
+
export const ActionOutputs = {} as const;
|
|
523
|
+
export interface ActionOutputs {}`;
|
|
524
|
+
}
|
|
525
|
+
imports.add('zod', 'z');
|
|
526
|
+
const specs_module = options?.specs_module ?? DEFAULT_SPECS_MODULE;
|
|
527
|
+
imports.add(specs_module, '* as specs');
|
|
528
|
+
const inputs_value = filtered
|
|
529
|
+
.map((s) => `\t${s.method}: specs.${s.method}_action_spec.input,`)
|
|
530
|
+
.join('\n');
|
|
531
|
+
const inputs_type = filtered
|
|
532
|
+
.map((s) => `\t${s.method}: z.infer<typeof specs.${s.method}_action_spec.input>;`)
|
|
533
|
+
.join('\n');
|
|
534
|
+
const outputs_value = filtered
|
|
535
|
+
.map((s) => `\t${s.method}: specs.${s.method}_action_spec.output,`)
|
|
536
|
+
.join('\n');
|
|
537
|
+
const outputs_type = filtered
|
|
538
|
+
.map((s) => `\t${s.method}: z.infer<typeof specs.${s.method}_action_spec.output>;`)
|
|
539
|
+
.join('\n');
|
|
540
|
+
return `/**
|
|
541
|
+
* Action parameter schemas indexed by method name.
|
|
542
|
+
* These represent the input data for each action,
|
|
543
|
+
* e.g. JSON-RPC request/notification params and local call arguments.
|
|
544
|
+
*/
|
|
545
|
+
export const ActionInputs = {
|
|
546
|
+
${inputs_value}
|
|
547
|
+
} as const;
|
|
548
|
+
export interface ActionInputs {
|
|
549
|
+
${inputs_type}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Action result schemas indexed by method name.
|
|
554
|
+
* These represent the output data for each action,
|
|
555
|
+
* e.g. JSON-RPC response results and local call return values.
|
|
556
|
+
*/
|
|
557
|
+
export const ActionOutputs = {
|
|
558
|
+
${outputs_value}
|
|
559
|
+
} as const;
|
|
560
|
+
export interface ActionOutputs {
|
|
561
|
+
${outputs_type}
|
|
562
|
+
}`;
|
|
563
|
+
};
|
|
564
|
+
/**
|
|
565
|
+
* Emit the `ActionEventDatas` interface — one `ActionEvent*Data` variant per
|
|
566
|
+
* method, parameterized by the spec's kind:
|
|
567
|
+
* - `request_response` → `ActionEventRequestResponseData<method, input, output>`
|
|
568
|
+
* - `remote_notification` → `ActionEventRemoteNotificationData<method, input>`
|
|
569
|
+
* - `local_call` → `ActionEventLocalCallData<method, input, output>`
|
|
570
|
+
*
|
|
571
|
+
* Adds the per-kind data type imports (only the kinds that appear in `specs`).
|
|
572
|
+
*
|
|
573
|
+
* @param options.collections_path - when set, adds `ActionInputs` /
|
|
574
|
+
* `ActionOutputs` type imports from this path. Leave unset (default) when
|
|
575
|
+
* the producer emits `ActionEventDatas` in the same file as
|
|
576
|
+
* `ActionInputs` / `ActionOutputs` — same-file scope means no imports
|
|
577
|
+
* needed (the zzz pattern, where `generate_action_inputs_outputs` and
|
|
578
|
+
* this helper feed the same `action_collections.ts` output).
|
|
579
|
+
*/
|
|
580
|
+
export const generate_action_event_datas = (specs, imports, options) => {
|
|
581
|
+
const filtered = filter_composables(specs, options?.include_composables);
|
|
582
|
+
if (filtered.length === 0) {
|
|
583
|
+
// Empty spec list — emit `interface ActionEventDatas {}` and skip
|
|
584
|
+
// the optional collections-path import that would be unused.
|
|
585
|
+
return `/**
|
|
586
|
+
* Action event data types indexed by method name.
|
|
587
|
+
* These represent the full discriminated union of all possible states
|
|
588
|
+
* for each action's event data, properly typed with inputs and outputs.
|
|
589
|
+
*/
|
|
590
|
+
export interface ActionEventDatas {}`;
|
|
591
|
+
}
|
|
592
|
+
if (options?.collections_path) {
|
|
593
|
+
imports.add_types(options.collections_path, 'ActionInputs', 'ActionOutputs');
|
|
594
|
+
}
|
|
595
|
+
const lines = filtered.map((spec) => {
|
|
596
|
+
const data_type = spec.kind === 'request_response'
|
|
597
|
+
? 'ActionEventRequestResponseData'
|
|
598
|
+
: spec.kind === 'remote_notification'
|
|
599
|
+
? 'ActionEventRemoteNotificationData'
|
|
600
|
+
: 'ActionEventLocalCallData';
|
|
601
|
+
imports.add_type('@fuzdev/fuz_app/actions/action_event_data.js', data_type);
|
|
602
|
+
const type_args = spec.kind === 'remote_notification'
|
|
603
|
+
? `<'${spec.method}', ActionInputs['${spec.method}']>`
|
|
604
|
+
: `<'${spec.method}', ActionInputs['${spec.method}'], ActionOutputs['${spec.method}']>`;
|
|
605
|
+
return `\t${spec.method}: ${data_type}${type_args};`;
|
|
606
|
+
});
|
|
607
|
+
return `/**
|
|
608
|
+
* Action event data types indexed by method name.
|
|
609
|
+
* These represent the full discriminated union of all possible states
|
|
610
|
+
* for each action's event data, properly typed with inputs and outputs.
|
|
611
|
+
*/
|
|
612
|
+
export interface ActionEventDatas {
|
|
613
|
+
${lines.join('\n')}
|
|
614
|
+
}`;
|
|
615
|
+
};
|
|
616
|
+
/**
|
|
617
|
+
* Emit the `ActionsApi` interface — one method signature per spec via
|
|
618
|
+
* `generate_actions_api_method_signature`. Optionally filter the spec set
|
|
619
|
+
* (e.g. omit composable methods) via `method_filter`.
|
|
620
|
+
*
|
|
621
|
+
* Adds the `Result`, `JsonrpcErrorObject`, and `RpcClientCallOptions` type
|
|
622
|
+
* imports plus `ActionInputs` / `ActionOutputs` (sourced from `collections_path`).
|
|
623
|
+
*/
|
|
624
|
+
export const generate_actions_api = (specs, imports, options) => {
|
|
625
|
+
const composable_filtered = filter_composables(specs, options?.include_composables);
|
|
626
|
+
const filter = options?.method_filter;
|
|
627
|
+
const filtered = filter ? composable_filtered.filter((s) => filter(s)) : composable_filtered;
|
|
628
|
+
const interface_doc = `/**
|
|
629
|
+
* Interface for action dispatch functions.
|
|
630
|
+
* Async methods (request_response, remote_notification, async local_call)
|
|
631
|
+
* return \`Promise<Result<...>>\` and accept an optional \`RpcClientCallOptions\`
|
|
632
|
+
* second arg that threads \`signal\`, \`transport_name\`, and \`queue\` through to
|
|
633
|
+
* the peer. Sync local_call methods return values directly.
|
|
634
|
+
*/`;
|
|
635
|
+
if (filtered.length === 0) {
|
|
636
|
+
// Empty spec list — emit `ActionsApi {}` and skip every import. None
|
|
637
|
+
// of the symbols would be referenced by the empty body.
|
|
638
|
+
return `${interface_doc}
|
|
639
|
+
export interface ActionsApi {}`;
|
|
640
|
+
}
|
|
641
|
+
const collections_path = options?.collections_path ?? DEFAULT_COLLECTIONS_PATH;
|
|
642
|
+
imports.add_type('@fuzdev/fuz_util/result.js', 'Result');
|
|
643
|
+
imports.add_type('@fuzdev/fuz_app/http/jsonrpc.js', 'JsonrpcErrorObject');
|
|
644
|
+
imports.add_type('@fuzdev/fuz_app/actions/rpc_client.js', 'RpcClientCallOptions');
|
|
645
|
+
imports.add_types(collections_path, 'ActionInputs', 'ActionOutputs');
|
|
646
|
+
const lines = filtered
|
|
647
|
+
.map((spec) => generate_actions_api_method_signature(spec, {
|
|
648
|
+
sync_returns_value: options?.sync_returns_value,
|
|
649
|
+
}))
|
|
650
|
+
.map((line) => `\t${line}`)
|
|
651
|
+
.join('\n');
|
|
652
|
+
return `${interface_doc}
|
|
653
|
+
export interface ActionsApi {
|
|
654
|
+
${lines}
|
|
655
|
+
}`;
|
|
656
|
+
};
|
|
657
|
+
/**
|
|
658
|
+
* Emit the `FrontendActionHandlers` interface — wraps `generate_phase_handlers`
|
|
659
|
+
* with the `TypedActionEvent` action-event type and standard 1-tab per-method
|
|
660
|
+
* indentation. Pairs with `generate_typed_action_event_alias` (emits the
|
|
661
|
+
* matching `TypedActionEvent` alias) — call both in the same gen producer.
|
|
662
|
+
*/
|
|
663
|
+
export const generate_frontend_action_handlers = (specs, imports, options) => {
|
|
664
|
+
const filtered = filter_composables(specs, options?.include_composables);
|
|
665
|
+
const interface_doc = `/**
|
|
666
|
+
* Frontend action handlers organized by method and phase.
|
|
667
|
+
* Generated using spec.initiator to determine valid phases:
|
|
668
|
+
* - initiator: 'frontend' → send/execute phases
|
|
669
|
+
* - initiator: 'backend' → receive phases
|
|
670
|
+
* - initiator: 'both' → all valid phases
|
|
671
|
+
*/`;
|
|
672
|
+
if (filtered.length === 0) {
|
|
673
|
+
// Empty spec list — emit `FrontendActionHandlers {}` and skip the
|
|
674
|
+
// dangling `;` that the body template would otherwise produce.
|
|
675
|
+
return `${interface_doc}
|
|
676
|
+
export interface FrontendActionHandlers {}`;
|
|
677
|
+
}
|
|
678
|
+
const handler_options = {
|
|
679
|
+
action_event_type: 'TypedActionEvent',
|
|
680
|
+
collections_path: options?.collections_path,
|
|
681
|
+
};
|
|
682
|
+
const lines = filtered
|
|
683
|
+
.map((spec) => generate_phase_handlers(spec, 'frontend', imports, handler_options))
|
|
684
|
+
.filter(Boolean)
|
|
685
|
+
.map((block) => `\t${block}`)
|
|
686
|
+
.join(';\n');
|
|
687
|
+
return `${interface_doc}
|
|
688
|
+
export interface FrontendActionHandlers {
|
|
689
|
+
${lines};
|
|
690
|
+
}`;
|
|
691
|
+
};
|
|
692
|
+
/**
|
|
693
|
+
* Emit BOTH the typed `BackendActionsApi` interface AND the
|
|
694
|
+
* `broadcast_action_specs` runtime array. The interface is shaped for
|
|
695
|
+
* `create_broadcast_api`: backend-initiated `remote_notification` methods,
|
|
696
|
+
* each `(input) => Promise<void>`. The array bundles the matching specs as a
|
|
697
|
+
* `ReadonlyArray<ActionSpecUnion>`.
|
|
698
|
+
*
|
|
699
|
+
* Filter: `kind === 'remote_notification' && initiator !== 'frontend'`.
|
|
700
|
+
*
|
|
701
|
+
* Adds the `* as specs` namespace import (from `specs_module`), the
|
|
702
|
+
* `ActionInputs` type import (from `collections_path`), and the
|
|
703
|
+
* `ActionSpecUnion` type import.
|
|
704
|
+
*
|
|
705
|
+
* **Single-namespace.** Same caveat as `generate_action_specs_record` —
|
|
706
|
+
* multi-source consumers use the lower-level primitives.
|
|
707
|
+
*/
|
|
708
|
+
export const generate_backend_actions_api = (specs, imports, options) => {
|
|
709
|
+
const composable_filtered = filter_composables(specs, options?.include_composables);
|
|
710
|
+
const broadcast = composable_filtered.filter((s) => s.kind === 'remote_notification' && s.initiator !== 'frontend');
|
|
711
|
+
imports.add_type('@fuzdev/fuz_app/actions/action_spec.js', 'ActionSpecUnion');
|
|
712
|
+
const interface_doc = `/**
|
|
713
|
+
* Broadcast-style notifications from the backend to all connected clients.
|
|
714
|
+
* Request-scoped streaming goes through \`ctx.notify\` instead — it's
|
|
715
|
+
* socket-scoped, not a broadcast.
|
|
716
|
+
*/`;
|
|
717
|
+
if (broadcast.length === 0) {
|
|
718
|
+
// No backend-initiated remote_notifications — skip `* as specs` and
|
|
719
|
+
// `ActionInputs` imports that would have nothing to reference.
|
|
720
|
+
return `${interface_doc}
|
|
721
|
+
export interface BackendActionsApi {}
|
|
722
|
+
|
|
723
|
+
export const broadcast_action_specs: ReadonlyArray<ActionSpecUnion> = [];`;
|
|
724
|
+
}
|
|
725
|
+
const specs_module = options?.specs_module ?? DEFAULT_SPECS_MODULE;
|
|
726
|
+
const collections_path = options?.collections_path ?? DEFAULT_COLLECTIONS_PATH;
|
|
727
|
+
imports.add(specs_module, '* as specs');
|
|
728
|
+
imports.add_type(collections_path, 'ActionInputs');
|
|
729
|
+
const interface_body = '\n' +
|
|
730
|
+
broadcast
|
|
731
|
+
.map((s) => `\t${s.method}: (input: ActionInputs['${s.method}']) => Promise<void>;`)
|
|
732
|
+
.join('\n') +
|
|
733
|
+
'\n';
|
|
734
|
+
const array_body = '\n' + broadcast.map((s) => `\tspecs.${s.method}_action_spec,`).join('\n') + '\n';
|
|
735
|
+
return `${interface_doc}
|
|
736
|
+
export interface BackendActionsApi {${interface_body}}
|
|
737
|
+
|
|
738
|
+
export const broadcast_action_specs: ReadonlyArray<ActionSpecUnion> = [${array_body}];`;
|
|
739
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action_event_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_event_helpers.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"action_event_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_event_helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -29,14 +29,12 @@ export const is_send_request_with_parsed_input = (data) => is_send_request(data)
|
|
|
29
29
|
export const is_notification_send_with_parsed_input = (data) => is_notification_send(data) && (data.step === 'parsed' || data.step === 'handling');
|
|
30
30
|
// Validation helpers
|
|
31
31
|
export const validate_step_transition = (from, to) => {
|
|
32
|
-
|
|
33
|
-
if (!valid_transitions.includes(to)) {
|
|
32
|
+
if (!ACTION_EVENT_STEP_TRANSITIONS[from].includes(to)) {
|
|
34
33
|
throw new Error(`Invalid step transition from '${from}' to '${to}'`);
|
|
35
34
|
}
|
|
36
35
|
};
|
|
37
36
|
export const validate_phase_for_kind = (kind, phase) => {
|
|
38
|
-
|
|
39
|
-
if (!valid_phases.includes(phase)) {
|
|
37
|
+
if (!ACTION_EVENT_PHASE_BY_KIND[kind].includes(phase)) {
|
|
40
38
|
throw new Error(`Invalid phase '${phase}' for ${kind} action`);
|
|
41
39
|
}
|
|
42
40
|
};
|
|
@@ -85,12 +83,22 @@ export const create_initial_data = (kind, phase, method, executor, input) => ({
|
|
|
85
83
|
});
|
|
86
84
|
export const extract_action_result = (event) => {
|
|
87
85
|
const { data } = event;
|
|
86
|
+
// `data.error` populated → error path. This covers two cases:
|
|
87
|
+
// 1. `step === 'failed'` — explicit terminal failure.
|
|
88
|
+
// 2. `phase === 'receive_error' | 'send_error'` reached `step === 'handled'`
|
|
89
|
+
// because no handler was registered for the error phase. The dispatcher
|
|
90
|
+
// silently transitions to `handled` in that case but leaves `data.error`
|
|
91
|
+
// populated. Reading `step === 'handled'` first would return
|
|
92
|
+
// `{ok: true, value: null}` and surprise every caller that doesn't
|
|
93
|
+
// register an error-phase handler. Preferring `data.error` lets
|
|
94
|
+
// consumers skip the boilerplate `receive_error` rethrow stub.
|
|
95
|
+
if (data.error) {
|
|
96
|
+
return { ok: false, error: data.error };
|
|
97
|
+
}
|
|
88
98
|
if (data.step === 'handled') {
|
|
89
99
|
return { ok: true, value: data.output };
|
|
90
100
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
// Programming error - event not in terminal state
|
|
101
|
+
// `step === 'failed'` with `data.error === null` is a malformed event;
|
|
102
|
+
// type narrowing accepts it, runtime never produces it.
|
|
95
103
|
throw new Error(`cannot extract result: event in non-terminal state (step: ${data.step})`);
|
|
96
104
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action_event_types.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_event_types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAC,gBAAgB,EAAE,UAAU,EAAE,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEpF,eAAO,MAAM,cAAc;;;EAAkC,CAAC;AAC9D,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D,eAAO,MAAM,eAAe;;;;;;EAAiE,CAAC;AAC9F,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"action_event_types.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_event_types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAC,gBAAgB,EAAE,UAAU,EAAE,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEpF,eAAO,MAAM,cAAc;;;EAAkC,CAAC;AAC9D,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D,eAAO,MAAM,eAAe;;;;;;EAAiE,CAAC;AAC9F,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAS9D,eAAO,MAAM,6BAA6B,EAAE,MAAM,CACjD,eAAe,EACf,aAAa,CAAC,eAAe,CAAC,CAO9B,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAW1F,CAAC;AAEF,eAAO,MAAM,8BAA8B,EAAE,MAAM,CAAC,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAU5F,CAAC;AAEF,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,qBAAqB,EAAE,CACtB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,gBAAgB,KACnB,CAAC,CAAC,KAAK,EAAE,GAAG,KAAK,GAAG,CAAC,GAAG,SAAS,CAAC;IACvC,kBAAkB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,eAAe,GAAG,SAAS,CAAC;IACpE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B"}
|
|
@@ -6,6 +6,12 @@
|
|
|
6
6
|
import { z } from 'zod';
|
|
7
7
|
export const ActionExecutor = z.enum(['frontend', 'backend']);
|
|
8
8
|
export const ActionEventStep = z.enum(['initial', 'parsed', 'handling', 'handled', 'failed']);
|
|
9
|
+
// The constants below use `Record<K, V> = {...}` rather than
|
|
10
|
+
// `as const satisfies Record<K, V>`. The typed annotation gives full
|
|
11
|
+
// completeness checking (TS rejects missing keys, excess keys, and wrong
|
|
12
|
+
// value types on the object literal) without narrowing lookups to literal
|
|
13
|
+
// tuple types — a `satisfies` shape forces every `X[k]` reader to widen
|
|
14
|
+
// back to `ReadonlyArray<V>` themselves to call `.includes(...)`.
|
|
9
15
|
export const ACTION_EVENT_STEP_TRANSITIONS = {
|
|
10
16
|
initial: ['parsed', 'failed'],
|
|
11
17
|
parsed: ['handling', 'failed'],
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Bundles the `ActionRegistry + ActionEventEnvironment + Transports +
|
|
5
5
|
* ActionPeer + create_rpc_client + create_throwing_api` boilerplate every
|
|
6
|
-
* consumer repeats
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* consumer repeats. `lookup_action_handler` defaults to `() => undefined`
|
|
7
|
+
* (HTTP-only frontends rarely need handlers); pass `options.lookup_action_handler`
|
|
8
|
+
* to wire WS-pushed `remote_notification` dispatch or a `receive_error` /
|
|
9
|
+
* `local_call` hook.
|
|
9
10
|
*
|
|
10
11
|
* Returns both Proxy shapes from one factory call:
|
|
11
12
|
*
|
|
@@ -38,10 +39,9 @@
|
|
|
38
39
|
* transports / WS notification handlers / action-history wiring) can
|
|
39
40
|
* extend without recreating the bundle.
|
|
40
41
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* factory
|
|
44
|
-
* needs a different wiring shape (custom `environment.lookup_action_handler`).
|
|
42
|
+
* `local_call` specs in `specs` no-op unless `lookup_action_handler`
|
|
43
|
+
* resolves a handler for the `'execute'` phase. Frontend-side `local_call`
|
|
44
|
+
* is uncommon; the factory targets wire-dispatched actions by default.
|
|
45
45
|
*
|
|
46
46
|
* @module
|
|
47
47
|
*/
|
|
@@ -94,6 +94,24 @@ export interface CreateFrontendRpcClientOptions<TApi extends object = object> {
|
|
|
94
94
|
* site when `TApi` is a generated `ActionsApi` interface.
|
|
95
95
|
*/
|
|
96
96
|
on_action_event?: (event: ActionEvent<keyof TApi & string>) => void;
|
|
97
|
+
/**
|
|
98
|
+
* Optional handler resolver. Wired onto `environment.lookup_action_handler`
|
|
99
|
+
* — the registry the dispatcher uses to find handlers for inbound
|
|
100
|
+
* messages and lifecycle phases. Defaults to `() => undefined`, which
|
|
101
|
+
* is fine for HTTP-only frontends that never receive a server-pushed
|
|
102
|
+
* notification or register a `receive_error` recovery hook.
|
|
103
|
+
*
|
|
104
|
+
* Common reasons to provide this:
|
|
105
|
+
* - **Server-pushed notifications over WS** — return a handler for
|
|
106
|
+
* `(method, 'receive')` so a `remote_notification` arriving on the
|
|
107
|
+
* socket dispatches to your subscriber bus (tx-style).
|
|
108
|
+
* - **Per-method retry / telemetry on errors** — return a handler for
|
|
109
|
+
* `(method, 'receive_error')`. Note that as of the
|
|
110
|
+
* `extract_action_result` fix, a missing handler already produces
|
|
111
|
+
* `{ok: false, error}` — the stub is no longer required just to
|
|
112
|
+
* surface server errors.
|
|
113
|
+
*/
|
|
114
|
+
lookup_action_handler?: ActionEventEnvironment['lookup_action_handler'];
|
|
97
115
|
}
|
|
98
116
|
/** Bundle returned by `create_frontend_rpc_client`. */
|
|
99
117
|
export interface FrontendRpcClient<TApi> {
|
|
@@ -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;;;;;OAKG;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;
|
|
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;;;;;OAKG;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"}
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Bundles the `ActionRegistry + ActionEventEnvironment + Transports +
|
|
5
5
|
* ActionPeer + create_rpc_client + create_throwing_api` boilerplate every
|
|
6
|
-
* consumer repeats
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* consumer repeats. `lookup_action_handler` defaults to `() => undefined`
|
|
7
|
+
* (HTTP-only frontends rarely need handlers); pass `options.lookup_action_handler`
|
|
8
|
+
* to wire WS-pushed `remote_notification` dispatch or a `receive_error` /
|
|
9
|
+
* `local_call` hook.
|
|
9
10
|
*
|
|
10
11
|
* Returns both Proxy shapes from one factory call:
|
|
11
12
|
*
|
|
@@ -38,10 +39,9 @@
|
|
|
38
39
|
* transports / WS notification handlers / action-history wiring) can
|
|
39
40
|
* extend without recreating the bundle.
|
|
40
41
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* factory
|
|
44
|
-
* needs a different wiring shape (custom `environment.lookup_action_handler`).
|
|
42
|
+
* `local_call` specs in `specs` no-op unless `lookup_action_handler`
|
|
43
|
+
* resolves a handler for the `'execute'` phase. Frontend-side `local_call`
|
|
44
|
+
* is uncommon; the factory targets wire-dispatched actions by default.
|
|
45
45
|
*
|
|
46
46
|
* @module
|
|
47
47
|
*/
|
|
@@ -64,7 +64,7 @@ export const create_frontend_rpc_client = (options) => {
|
|
|
64
64
|
const environment = {
|
|
65
65
|
executor: 'frontend',
|
|
66
66
|
lookup_action_spec: (method) => registry.spec_by_method.get(method),
|
|
67
|
-
lookup_action_handler: () => undefined,
|
|
67
|
+
lookup_action_handler: options.lookup_action_handler ?? (() => undefined),
|
|
68
68
|
};
|
|
69
69
|
const transports = new Transports();
|
|
70
70
|
if (options.transports) {
|
|
@@ -89,15 +89,23 @@ export interface RpcClientCallOptions extends ActionPeerSendOptions {
|
|
|
89
89
|
* as `=> void`, sync `local_call` methods) pass through unchanged — there
|
|
90
90
|
* is nothing to unwrap.
|
|
91
91
|
*
|
|
92
|
-
* Input + options parameters are preserved verbatim
|
|
93
|
-
*
|
|
92
|
+
* Input + options parameters are preserved verbatim via `...args: infer TArgs`
|
|
93
|
+
* so the conditional matches both required-input (`input: T`) and
|
|
94
|
+
* optional-input (`input?: T` / nullary) signatures uniformly. Required-input
|
|
95
|
+
* shapes (e.g. `admin_session_revoke_all(input: AdminSessionRevokeAllInput)`)
|
|
96
|
+
* are not assignable to a `(input?: TInput) => …` pattern under
|
|
97
|
+
* `--strictFunctionTypes`, so an earlier `(input?, options?) =>` form
|
|
98
|
+
* silently fell through to `TApi[K]` and left those methods Result-shaped —
|
|
99
|
+
* `create_admin_rpc_adapters(api)` would then reject the typed throwing
|
|
100
|
+
* Proxy because half its surface still returned `Result<...>`. The rest-args
|
|
101
|
+
* form preserves both required and optional parameters and resolves the gap.
|
|
94
102
|
*/
|
|
95
103
|
export type ThrowingApi<TApi> = {
|
|
96
|
-
[K in keyof TApi]: TApi[K] extends (
|
|
104
|
+
[K in keyof TApi]: TApi[K] extends (...args: infer TArgs) => Promise<Result<{
|
|
97
105
|
value: infer TValue;
|
|
98
106
|
}, {
|
|
99
107
|
error: JsonrpcErrorObject;
|
|
100
|
-
}>> ? (
|
|
108
|
+
}>> ? (...args: TArgs) => Promise<TValue> : TApi[K];
|
|
101
109
|
};
|
|
102
110
|
/**
|
|
103
111
|
* Wrap a typed RPC client so every call resolves to its unwrapped value or
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc_client.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/rpc_client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,4BAA4B,CAAC;AAQvD,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAsB,KAAK,WAAW,EAAC,MAAM,mBAAmB,CAAC;AAMxE,OAAO,KAAK,EAAC,UAAU,EAAE,qBAAqB,EAAC,MAAM,kBAAkB,CAAC;AACxE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAEnD,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,oBAAoB,CAAC;AAE3D;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,aAAa,GAAG,SAAS,CAAC;AAM/E,uCAAuC;AACvC,MAAM,WAAW,sBAAsB,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IACnE,IAAI,EAAE,UAAU,CAAC;IACjB,WAAW,EAAE,sBAAsB,CAAC;IACpC;;;;;;;;;OASG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC;IACpE;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,kBAAkB,CAAC;CAC1C;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,iBAAiB,GAAI,IAAI,SAAS,MAAM,EACpD,SAAS,sBAAsB,CAAC,IAAI,CAAC,KACnC,IA4BF,CAAC;AA6DF;;;;;GAKG;AACH,MAAM,WAAW,oBAAqB,SAAQ,qBAAqB;CAAG;AAoHtE
|
|
1
|
+
{"version":3,"file":"rpc_client.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/rpc_client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,4BAA4B,CAAC;AAQvD,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAsB,KAAK,WAAW,EAAC,MAAM,mBAAmB,CAAC;AAMxE,OAAO,KAAK,EAAC,UAAU,EAAE,qBAAqB,EAAC,MAAM,kBAAkB,CAAC;AACxE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAEnD,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,oBAAoB,CAAC;AAE3D;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,aAAa,GAAG,SAAS,CAAC;AAM/E,uCAAuC;AACvC,MAAM,WAAW,sBAAsB,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IACnE,IAAI,EAAE,UAAU,CAAC;IACjB,WAAW,EAAE,sBAAsB,CAAC;IACpC;;;;;;;;;OASG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC;IACpE;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,kBAAkB,CAAC;CAC1C;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,iBAAiB,GAAI,IAAI,SAAS,MAAM,EACpD,SAAS,sBAAsB,CAAC,IAAI,CAAC,KACnC,IA4BF,CAAC;AA6DF;;;;;GAKG;AACH,MAAM,WAAW,oBAAqB,SAAQ,qBAAqB;CAAG;AAoHtE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,WAAW,CAAC,IAAI,IAAI;KAC9B,CAAC,IAAI,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAClC,GAAG,IAAI,EAAE,MAAM,KAAK,KAChB,OAAO,CAAC,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,MAAM,CAAA;KAAC,EAAE;QAAC,KAAK,EAAE,kBAAkB,CAAA;KAAC,CAAC,CAAC,GACrE,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,MAAM,CAAC,GACnC,IAAI,CAAC,CAAC,CAAC;CACV,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,mBAAmB,GAAI,IAAI,SAAS,MAAM,EAAE,YAAY,IAAI,KAAG,WAAW,CAAC,IAAI,CA8B3F,CAAC"}
|
|
@@ -55,8 +55,8 @@ export interface AdminRpcApi {
|
|
|
55
55
|
admin_session_list: () => Promise<AdminSessionListOutput>;
|
|
56
56
|
admin_session_revoke_all: (input: AdminSessionRevokeAllInput) => Promise<AdminSessionRevokeAllOutput>;
|
|
57
57
|
admin_token_revoke_all: (input: AdminTokenRevokeAllInput) => Promise<AdminTokenRevokeAllOutput>;
|
|
58
|
-
audit_log_list: (input
|
|
59
|
-
audit_log_permit_history: (input
|
|
58
|
+
audit_log_list: (input: AuditLogListInput) => Promise<AuditLogListOutput>;
|
|
59
|
+
audit_log_permit_history: (input: AuditLogPermitHistoryInput) => Promise<AuditLogPermitHistoryOutput>;
|
|
60
60
|
invite_list: () => Promise<InviteListOutput>;
|
|
61
61
|
invite_create: (input: InviteCreateInput) => Promise<InviteCreateOutput>;
|
|
62
62
|
invite_delete: (input: InviteDeleteInput) => Promise<InviteDeleteOutput>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin_rpc_adapters.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/admin_rpc_adapters.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,KAAK,EACX,sBAAsB,EACtB,sBAAsB,EACtB,0BAA0B,EAC1B,2BAA2B,EAC3B,wBAAwB,EACxB,yBAAyB,EACzB,iBAAiB,EACjB,kBAAkB,EAClB,0BAA0B,EAC1B,2BAA2B,EAC3B,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,sBAAsB,EACtB,uBAAuB,EACvB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EACX,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAA6B,KAAK,gBAAgB,EAAC,MAAM,kCAAkC,CAAC;AACnG,OAAO,EAA4B,KAAK,eAAe,EAAC,MAAM,iCAAiC,CAAC;AAChG,OAAO,EAAwB,KAAK,WAAW,EAAC,MAAM,6BAA6B,CAAC;AACpF,OAAO,EAA2B,KAAK,cAAc,EAAC,MAAM,gCAAgC,CAAC;AAC7F,OAAO,EAAuB,KAAK,WAAW,EAAC,MAAM,mBAAmB,CAAC;AAEzE;;;;;;;;;;GAUG;AACH,MAAM,WAAW,WAAW;IAC3B,kBAAkB,EAAE,MAAM,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAC1D,kBAAkB,EAAE,MAAM,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAC1D,wBAAwB,EAAE,CACzB,KAAK,EAAE,0BAA0B,KAC7B,OAAO,CAAC,2BAA2B,CAAC,CAAC;IAC1C,sBAAsB,EAAE,CAAC,KAAK,EAAE,wBAAwB,KAAK,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAChG,cAAc,EAAE,CAAC,KAAK,
|
|
1
|
+
{"version":3,"file":"admin_rpc_adapters.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/admin_rpc_adapters.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,KAAK,EACX,sBAAsB,EACtB,sBAAsB,EACtB,0BAA0B,EAC1B,2BAA2B,EAC3B,wBAAwB,EACxB,yBAAyB,EACzB,iBAAiB,EACjB,kBAAkB,EAClB,0BAA0B,EAC1B,2BAA2B,EAC3B,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,sBAAsB,EACtB,uBAAuB,EACvB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EACX,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAA6B,KAAK,gBAAgB,EAAC,MAAM,kCAAkC,CAAC;AACnG,OAAO,EAA4B,KAAK,eAAe,EAAC,MAAM,iCAAiC,CAAC;AAChG,OAAO,EAAwB,KAAK,WAAW,EAAC,MAAM,6BAA6B,CAAC;AACpF,OAAO,EAA2B,KAAK,cAAc,EAAC,MAAM,gCAAgC,CAAC;AAC7F,OAAO,EAAuB,KAAK,WAAW,EAAC,MAAM,mBAAmB,CAAC;AAEzE;;;;;;;;;;GAUG;AACH,MAAM,WAAW,WAAW;IAC3B,kBAAkB,EAAE,MAAM,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAC1D,kBAAkB,EAAE,MAAM,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAC1D,wBAAwB,EAAE,CACzB,KAAK,EAAE,0BAA0B,KAC7B,OAAO,CAAC,2BAA2B,CAAC,CAAC;IAC1C,sBAAsB,EAAE,CAAC,KAAK,EAAE,wBAAwB,KAAK,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAChG,cAAc,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC1E,wBAAwB,EAAE,CACzB,KAAK,EAAE,0BAA0B,KAC7B,OAAO,CAAC,2BAA2B,CAAC,CAAC;IAC1C,WAAW,EAAE,MAAM,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC7C,aAAa,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACzE,aAAa,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACzE,gBAAgB,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACtD,mBAAmB,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAC;IACzF,mBAAmB,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAC;IACzF,oBAAoB,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACvF,aAAa,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACzE;AAED,iEAAiE;AACjE,MAAM,WAAW,gBAAgB;IAChC,cAAc,EAAE,gBAAgB,CAAC;IACjC,aAAa,EAAE,eAAe,CAAC;IAC/B,SAAS,EAAE,WAAW,CAAC;IACvB,YAAY,EAAE,cAAc,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,yBAAyB,GAAI,KAAK,WAAW,KAAG,gBAuB3D,CAAC;AAEH,wEAAwE;AACxE,MAAM,WAAW,8BAA8B;IAC9C;;;OAGG;IACH,YAAY,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,0BAA0B,GACtC,UAAU,gBAAgB,EAC1B,UAAU,8BAA8B,KACtC,IASF,CAAC"}
|