@fuzdev/fuz_app 0.65.0 → 0.66.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 +65 -86
- package/dist/actions/action_codegen.d.ts +1 -1
- package/dist/actions/action_codegen.js +1 -1
- package/dist/actions/action_event_data.d.ts +1 -1
- package/dist/auth/CLAUDE.md +83 -104
- package/dist/auth/audit_log_schema.js +2 -2
- package/dist/auth/daemon_token_middleware.d.ts +15 -5
- package/dist/auth/daemon_token_middleware.d.ts.map +1 -1
- package/dist/auth/daemon_token_middleware.js +24 -15
- package/dist/auth/invite_queries.d.ts +17 -7
- package/dist/auth/invite_queries.d.ts.map +1 -1
- package/dist/auth/invite_queries.js +19 -8
- package/dist/auth/signup_routes.d.ts +47 -1
- package/dist/auth/signup_routes.d.ts.map +1 -1
- package/dist/auth/signup_routes.js +103 -52
- package/dist/env/resolve.d.ts +44 -7
- package/dist/env/resolve.d.ts.map +1 -1
- package/dist/env/resolve.js +94 -27
- package/dist/http/CLAUDE.md +47 -52
- package/dist/http/jsonrpc.d.ts +23 -7
- package/dist/http/jsonrpc.d.ts.map +1 -1
- package/dist/http/jsonrpc.js +19 -3
- package/dist/http/surface.d.ts +9 -2
- package/dist/http/surface.d.ts.map +1 -1
- package/dist/runtime/mock.d.ts +1 -1
- package/dist/runtime/mock.js +1 -1
- package/dist/testing/CLAUDE.md +659 -511
- package/dist/testing/admin_integration.d.ts +5 -5
- package/dist/testing/admin_integration.d.ts.map +1 -1
- package/dist/testing/admin_integration.js +95 -39
- package/dist/testing/app_server.d.ts +16 -1
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/app_server.js +18 -3
- package/dist/testing/audit_completeness.d.ts +7 -5
- package/dist/testing/audit_completeness.d.ts.map +1 -1
- package/dist/testing/audit_completeness.js +5 -9
- package/dist/testing/bootstrap_success.js +2 -2
- package/dist/testing/cross_backend/backend_config.d.ts +113 -0
- package/dist/testing/cross_backend/backend_config.d.ts.map +1 -0
- package/dist/testing/cross_backend/backend_config.js +1 -0
- package/dist/testing/cross_backend/bench/bench_report.d.ts +46 -0
- package/dist/testing/cross_backend/bench/bench_report.d.ts.map +1 -0
- package/dist/testing/cross_backend/bench/bench_report.js +83 -0
- package/dist/testing/cross_backend/bench/run_cross_impl_bench.d.ts +44 -0
- package/dist/testing/cross_backend/bench/run_cross_impl_bench.d.ts.map +1 -0
- package/dist/testing/cross_backend/bench/run_cross_impl_bench.js +38 -0
- package/dist/testing/cross_backend/bench/scenario.d.ts +57 -0
- package/dist/testing/cross_backend/bench/scenario.d.ts.map +1 -0
- package/dist/testing/cross_backend/bench/scenario.js +28 -0
- package/dist/testing/cross_backend/bootstrap_backend.d.ts +41 -0
- package/dist/testing/cross_backend/bootstrap_backend.d.ts.map +1 -0
- package/dist/testing/cross_backend/bootstrap_backend.js +34 -0
- package/dist/testing/cross_backend/build_test_backend_paths.d.ts +24 -0
- package/dist/testing/cross_backend/build_test_backend_paths.d.ts.map +1 -0
- package/dist/testing/cross_backend/build_test_backend_paths.js +33 -0
- package/dist/testing/cross_backend/capabilities.d.ts +3 -2
- package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_backend_configs.d.ts +122 -0
- package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -0
- package/dist/testing/cross_backend/default_backend_configs.js +111 -0
- package/dist/testing/cross_backend/default_secrets.d.ts +40 -0
- package/dist/testing/cross_backend/default_secrets.d.ts.map +1 -0
- package/dist/testing/cross_backend/default_secrets.js +39 -0
- package/dist/testing/cross_backend/default_spine_surface.d.ts +64 -0
- package/dist/testing/cross_backend/default_spine_surface.d.ts.map +1 -0
- package/dist/testing/cross_backend/default_spine_surface.js +121 -0
- package/dist/testing/cross_backend/setup.d.ts +270 -34
- package/dist/testing/cross_backend/setup.d.ts.map +1 -1
- package/dist/testing/cross_backend/setup.js +495 -15
- package/dist/testing/cross_backend/spawn_backend.d.ts +58 -0
- package/dist/testing/cross_backend/spawn_backend.d.ts.map +1 -0
- package/dist/testing/cross_backend/spawn_backend.js +229 -0
- package/dist/testing/cross_backend/spine_stub_backend_config.d.ts +66 -0
- package/dist/testing/cross_backend/spine_stub_backend_config.d.ts.map +1 -0
- package/dist/testing/cross_backend/spine_stub_backend_config.js +49 -0
- package/dist/testing/cross_backend/sse_round_trip.d.ts +37 -0
- package/dist/testing/cross_backend/sse_round_trip.d.ts.map +1 -0
- package/dist/testing/cross_backend/sse_round_trip.js +137 -0
- package/dist/testing/cross_backend/standard.d.ts +96 -0
- package/dist/testing/cross_backend/standard.d.ts.map +1 -0
- package/dist/testing/cross_backend/standard.js +49 -0
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +171 -0
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -0
- package/dist/testing/cross_backend/testing_reset_actions.js +213 -0
- package/dist/testing/cross_backend/testing_server_bun.d.ts +5 -0
- package/dist/testing/cross_backend/testing_server_bun.d.ts.map +1 -0
- package/dist/testing/cross_backend/testing_server_bun.js +59 -0
- package/dist/testing/cross_backend/testing_server_core.d.ts +140 -0
- package/dist/testing/cross_backend/testing_server_core.d.ts.map +1 -0
- package/dist/testing/cross_backend/testing_server_core.js +68 -0
- package/dist/testing/cross_backend/testing_server_deno.d.ts +5 -0
- package/dist/testing/cross_backend/testing_server_deno.d.ts.map +1 -0
- package/dist/testing/cross_backend/testing_server_deno.js +37 -0
- package/dist/testing/cross_backend/testing_server_node.d.ts +5 -0
- package/dist/testing/cross_backend/testing_server_node.d.ts.map +1 -0
- package/dist/testing/cross_backend/testing_server_node.js +50 -0
- package/dist/testing/cross_backend/ts_spine_backend_config.d.ts +72 -0
- package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -0
- package/dist/testing/cross_backend/ts_spine_backend_config.js +112 -0
- package/dist/testing/cross_backend/ws_round_trip.d.ts +35 -0
- package/dist/testing/cross_backend/ws_round_trip.d.ts.map +1 -0
- package/dist/testing/cross_backend/ws_round_trip.js +113 -0
- package/dist/testing/data_exposure.d.ts +4 -6
- package/dist/testing/data_exposure.d.ts.map +1 -1
- package/dist/testing/data_exposure.js +1 -5
- package/dist/testing/db_entities.d.ts +18 -7
- package/dist/testing/db_entities.d.ts.map +1 -1
- package/dist/testing/db_entities.js +18 -7
- package/dist/testing/integration.d.ts +27 -6
- package/dist/testing/integration.d.ts.map +1 -1
- package/dist/testing/integration.js +93 -58
- package/dist/testing/round_trip.d.ts +4 -5
- package/dist/testing/round_trip.d.ts.map +1 -1
- package/dist/testing/round_trip.js +1 -5
- package/dist/testing/rpc_helpers.d.ts +10 -4
- package/dist/testing/rpc_helpers.d.ts.map +1 -1
- package/dist/testing/rpc_helpers.js +1 -1
- package/dist/testing/rpc_round_trip.d.ts +5 -5
- package/dist/testing/rpc_round_trip.d.ts.map +1 -1
- package/dist/testing/rpc_round_trip.js +1 -5
- package/dist/testing/sse_round_trip.d.ts.map +1 -1
- package/dist/testing/sse_round_trip.js +1 -68
- package/dist/testing/standard.d.ts +4 -5
- package/dist/testing/standard.d.ts.map +1 -1
- package/dist/testing/stubs.d.ts +10 -3
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +9 -2
- package/dist/testing/testing_rate_limiter.d.ts +59 -0
- package/dist/testing/testing_rate_limiter.d.ts.map +1 -0
- package/dist/testing/testing_rate_limiter.js +74 -0
- package/dist/testing/transports/bootstrap.d.ts +52 -0
- package/dist/testing/transports/bootstrap.d.ts.map +1 -0
- package/dist/testing/transports/bootstrap.js +70 -0
- package/dist/testing/transports/fetch_transport.d.ts +81 -0
- package/dist/testing/transports/fetch_transport.d.ts.map +1 -0
- package/dist/testing/transports/fetch_transport.js +74 -0
- package/dist/testing/transports/sse_frame_reader.d.ts +41 -0
- package/dist/testing/transports/sse_frame_reader.d.ts.map +1 -0
- package/dist/testing/transports/sse_frame_reader.js +84 -0
- package/dist/testing/transports/sse_transport.d.ts +54 -0
- package/dist/testing/transports/sse_transport.d.ts.map +1 -0
- package/dist/testing/transports/sse_transport.js +51 -0
- package/dist/testing/transports/ws_client.d.ts +108 -0
- package/dist/testing/transports/ws_client.d.ts.map +1 -0
- package/dist/testing/transports/ws_client.js +56 -0
- package/dist/testing/transports/ws_transport.d.ts +43 -0
- package/dist/testing/transports/ws_transport.d.ts.map +1 -0
- package/dist/testing/transports/ws_transport.js +169 -0
- package/dist/testing/ws_round_trip.d.ts +21 -103
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/ws_round_trip.js +42 -40
- package/dist/ui/CLAUDE.md +5 -3
- package/dist/ui/MenuLink.svelte +16 -16
- package/dist/ui/MenuLink.svelte.d.ts +13 -4
- package/dist/ui/MenuLink.svelte.d.ts.map +1 -1
- package/package.json +7 -1
- package/dist/testing/transports/surface_source.d.ts +0 -51
- package/dist/testing/transports/surface_source.d.ts.map +0 -1
- package/dist/testing/transports/surface_source.js +0 -19
package/dist/actions/CLAUDE.md
CHANGED
|
@@ -25,11 +25,9 @@ the pair invariant.
|
|
|
25
25
|
|
|
26
26
|
Canonical source of truth. Three concrete kinds discriminate on `kind`:
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
| `remote_notification` | `null` | `true` | `z.ZodVoid` | `true` |
|
|
32
|
-
| `local_call` | `null` | arbitrary | arbitrary | boolean |
|
|
28
|
+
- `request_response` — `auth: RouteAuth` (non-null), `side_effects` arbitrary, `output` arbitrary, `async: true`.
|
|
29
|
+
- `remote_notification` — `auth: null`, `side_effects: true`, `output: z.ZodVoid`, `async: true`.
|
|
30
|
+
- `local_call` — `auth: null`, `side_effects` arbitrary, `output` arbitrary, `async` boolean.
|
|
33
31
|
|
|
34
32
|
`RouteAuth` is the flat record `{account, actor, roles?, credential_types?}`
|
|
35
33
|
from `http/auth_shape.ts` — same shape governs `RouteSpec.auth` so the four
|
|
@@ -64,11 +62,9 @@ dropping per-spec `*_METHOD` constants (readers dereference `.method`). See
|
|
|
64
62
|
|
|
65
63
|
## Kind → binding matrix
|
|
66
64
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
| `remote_notification` | no | no | server push | yes (bridge) |
|
|
71
|
-
| `local_call` | no | no | no | no |
|
|
65
|
+
- `request_response` — REST `RouteSpec` via bridge; RPC `RouteSpec` via `create_rpc_endpoint`; WS dispatch yes; no SSE.
|
|
66
|
+
- `remote_notification` — no REST/RPC routes; WS server push; SSE `EventSpec` via bridge.
|
|
67
|
+
- `local_call` — none (no REST, no RPC, no WS, no SSE).
|
|
72
68
|
|
|
73
69
|
`create_action_route_spec` throws if `spec.auth` is null (notifications and
|
|
74
70
|
local calls cannot become routes). `create_action_event_spec` throws on any
|
|
@@ -93,17 +89,16 @@ registry-only.
|
|
|
93
89
|
## Registry + codegen (`actions/action_registry.ts`, `actions/action_codegen.ts`)
|
|
94
90
|
|
|
95
91
|
**Symmetric design — universal calling abstraction.** SAES is one spec
|
|
96
|
-
shape
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
broader runtime constructors will join). Remaining asymmetry
|
|
92
|
+
shape driving dispatch across (a) network boundaries (frontend ⇄ backend
|
|
93
|
+
over HTTP / WS) and (b) within the same runtime (`local_call` actions).
|
|
94
|
+
`ActionPeer` is symmetric on both sides (`send` + `receive`). Typed
|
|
95
|
+
surfaces are paired: `FrontendActionsApi` is "what the frontend can call"
|
|
96
|
+
(typed Proxy from `create_rpc_client`); `BackendActionsApi` is "what the
|
|
97
|
+
backend can call" (typed object from `create_broadcast_api` today;
|
|
98
|
+
broader runtime constructors will join). Remaining asymmetry:
|
|
103
99
|
`create_broadcast_api` returns `Promise<void>` while `FrontendActionsApi`
|
|
104
100
|
methods return `Promise<Result<...>>`. Closing those gaps is on the
|
|
105
|
-
deferred follow-up set
|
|
106
|
-
[SAES RPC closeout](https://github.com/ryanatkn/grimoire/blob/main/quests/HISTORY.md#saes-rpc-direction-2026-04)
|
|
101
|
+
deferred follow-up set from the SAES RPC closeout work
|
|
107
102
|
— wait for a second backend runtime case.
|
|
108
103
|
|
|
109
104
|
### `ActionRegistry`
|
|
@@ -111,13 +106,11 @@ deferred follow-up set in
|
|
|
111
106
|
Query/filter wrapper over `ActionSpecUnion[]`. Codegen-relevant getter
|
|
112
107
|
groups (each pairs `_specs` with matching `_methods`):
|
|
113
108
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
| `broadcast` | `remote_notification`, `initiator !== 'frontend'`, excludes streams | `BackendActionsApi` interface |
|
|
120
|
-
| `backend_initiated` | forward-looking kind-agnostic broadcast | same content today |
|
|
109
|
+
- Kind-narrow — filter by `kind`; drives `*ActionMethod` enums.
|
|
110
|
+
- `*_handled` — `request_response` + handler-side initiator; drives `BackendActionHandlers` map.
|
|
111
|
+
- `specs_relevant_to_*` — everything the side might encounter; drives typed-Proxy method enums.
|
|
112
|
+
- `broadcast` — `remote_notification`, `initiator !== 'frontend'`, excludes streams; drives `BackendActionsApi` interface.
|
|
113
|
+
- `backend_initiated` — forward-looking kind-agnostic broadcast; same content today.
|
|
121
114
|
|
|
122
115
|
Other getters (auth filters, initiator-direction filters) are pre-built API
|
|
123
116
|
surface unused by codegen today.
|
|
@@ -125,28 +118,25 @@ surface unused by codegen today.
|
|
|
125
118
|
### Codegen helpers (`actions/action_codegen.ts`)
|
|
126
119
|
|
|
127
120
|
Used by consumer `*.gen.ts` producers, not the runtime. Detailed signatures
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
| `generate_backend_action_handlers_map` | `BackendActionHandlers` mapped type |
|
|
148
|
-
| `compose_gen_file` | Wrapper: banner + `imports.build()` + blocks join |
|
|
149
|
-
| `create_namespace_qualifier(sources, imports)` | Multi-source consumer helper; registers `import * as ns` per source |
|
|
121
|
+
and options on each function's TSDoc.
|
|
122
|
+
|
|
123
|
+
- `ImportBuilder` — class managing value/type/namespace imports; auto-tree-shakes type-only.
|
|
124
|
+
- `get_executor_phases(spec, executor)` — phases an executor participates in for the spec.
|
|
125
|
+
- `get_handler_return_type` — TS type a phase handler must return; side-effect imports `ActionOutputs`.
|
|
126
|
+
- `generate_phase_handlers` — per-action typed handler-map fragment.
|
|
127
|
+
- `generate_actions_api_method_signature` — single source of truth for the typed `FrontendActionsApi` method shape.
|
|
128
|
+
- `generate_action_method_enums` — up to nine `z.enum` + `z.infer` pairs.
|
|
129
|
+
- `generate_action_method_enum_block` — lower-level escape hatch for cross-product enums.
|
|
130
|
+
- `generate_typed_action_event_alias` — fixed-shape `TypedActionEvent<TMethod, TPhase, TStep>` alias.
|
|
131
|
+
- `generate_action_specs_record` — `ActionSpecs` runtime const + interface + `action_specs` array.
|
|
132
|
+
- `generate_action_inputs_outputs` — `ActionInputs` + `ActionOutputs` runtime consts + interfaces.
|
|
133
|
+
- `generate_action_event_datas` — `ActionEventDatas` interface; per-spec variants.
|
|
134
|
+
- `generate_frontend_actions_api` — typed `FrontendActionsApi` interface.
|
|
135
|
+
- `generate_frontend_action_handlers` — `FrontendActionHandlers` interface (Tier 2 only).
|
|
136
|
+
- `generate_backend_actions_api` — `BackendActionsApi` interface + `broadcast_action_specs` array.
|
|
137
|
+
- `generate_backend_action_handlers_map` — `BackendActionHandlers` mapped type.
|
|
138
|
+
- `compose_gen_file` — wrapper: banner + `imports.build()` + blocks join.
|
|
139
|
+
- `create_namespace_qualifier(sources, imports)` — multi-source consumer helper; registers `import * as ns` per source.
|
|
150
140
|
|
|
151
141
|
Shared defaults: `DEFAULT_COLLECTIONS_PATH = './action_collections.js'`,
|
|
152
142
|
`DEFAULT_SPECS_MODULE = './action_specs.js'`,
|
|
@@ -158,14 +148,14 @@ multi-source-aware helper uses).
|
|
|
158
148
|
|
|
159
149
|
**Protocol actions filtered by default.** Every spec-iterating helper
|
|
160
150
|
accepts `{include_protocol_actions?: boolean}` (default `false`) and drops
|
|
161
|
-
`heartbeat` / `cancel`. Protocol actions ship from fuz_app and
|
|
162
|
-
|
|
151
|
+
`heartbeat` / `cancel`. Protocol actions ship from fuz_app and spread into
|
|
152
|
+
each consumer's `actions` array at registration time (via
|
|
163
153
|
`protocol_actions` from `actions/protocol.ts`); they should not appear in
|
|
164
154
|
consumer-owned typed surfaces. Pass `include_protocol_actions: true` only
|
|
165
155
|
if a consumer genuinely owns protocol actions in their typed API.
|
|
166
156
|
|
|
167
|
-
**Consumer tiers.** Single-source consumers (zzz) drop into the
|
|
168
|
-
|
|
157
|
+
**Consumer tiers.** Single-source consumers (zzz) drop into the helpers
|
|
158
|
+
and accept the default `* as specs` namespace import. Multi-source
|
|
169
159
|
consumers (zap, visiones — stitching local specs with
|
|
170
160
|
`all_admin_action_specs` / `all_role_grant_offer_action_specs` /
|
|
171
161
|
`all_account_action_specs` / `all_self_service_role_action_specs` from
|
|
@@ -201,8 +191,8 @@ parsing, GET vs POST split, `c.json` binding); the
|
|
|
201
191
|
auth/validation/dispatch pipeline is shared with the WebSocket dispatcher.
|
|
202
192
|
|
|
203
193
|
**Phase order: 401 → 400 → 403 → handler.** Validate first, authorize
|
|
204
|
-
after.
|
|
205
|
-
|
|
194
|
+
after. Trade-off: an unauthorized caller sees the validation step. The
|
|
195
|
+
alternative ordering (403-before-400) was rejected because
|
|
206
196
|
defense-in-depth via attack-surface obscurity is illusory when the surface
|
|
207
197
|
is published in `library.json` codegen anyway.
|
|
208
198
|
|
|
@@ -253,18 +243,15 @@ the handler's input / output types to `z.infer<TSpec['input']>` /
|
|
|
253
243
|
`z.infer<TSpec['output']>` and tightens `ctx.auth` per the conditional
|
|
254
244
|
`HandlerForSpec<TSpec>`:
|
|
255
245
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
| `auth.account === 'required' && auth.actor === 'none'` | `RequestContext` |
|
|
260
|
-
| else (public, optional axes) | `RequestContext \| null` |
|
|
246
|
+
- `auth.actor === 'required'` → `ctx.auth: RequestActorContext`.
|
|
247
|
+
- `auth.account === 'required' && auth.actor === 'none'` → `ctx.auth: RequestContext`.
|
|
248
|
+
- else (public, optional axes) → `ctx.auth: RequestContext | null`.
|
|
261
249
|
|
|
262
|
-
Use at every spec → handler binding site so handler-type errors surface
|
|
263
|
-
the factory call instead of at runtime. The bracketed form
|
|
250
|
+
Use at every spec → handler binding site so handler-type errors surface
|
|
251
|
+
at the factory call instead of at runtime. The bracketed form
|
|
264
252
|
`[T] extends ['required']` defeats distributive conditionals so a degraded
|
|
265
253
|
`AuthAxisState` union (when the spec was typed without preserving its
|
|
266
|
-
literal) falls through to the loosest tier instead of
|
|
267
|
-
narrowest.
|
|
254
|
+
literal) falls through to the loosest tier instead of the narrowest.
|
|
268
255
|
|
|
269
256
|
zzz uses a codegen-driven `Record<Method, Handler>` map for the same
|
|
270
257
|
narrowing — ideal when handlers are stateless free functions. fuz_app's
|
|
@@ -308,10 +295,8 @@ Critical invariant: every action-handler surface applies DEV-only output
|
|
|
308
295
|
validation and produces the **same failure mode** — log an error, return
|
|
309
296
|
the response unchanged, do not throw, do not mutate status.
|
|
310
297
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
| REST bridge | `http/route_spec.ts` — `wrap_output_validation` (applied via `apply_route_specs`; inherited by `create_action_route_spec`) | short-circuit (no parse) |
|
|
314
|
-
| HTTP RPC + WebSocket dispatch | `actions/perform_action.ts` — `if (DEV) spec.output.safeParse(output)` inside the shared dispatch core | short-circuit (no parse) |
|
|
298
|
+
- REST bridge — `http/route_spec.ts` `wrap_output_validation` (applied via `apply_route_specs`; inherited by `create_action_route_spec`). Production hot path short-circuits (no parse).
|
|
299
|
+
- HTTP RPC + WebSocket dispatch — `actions/perform_action.ts` `if (DEV) spec.output.safeParse(output)` inside the shared dispatch core. Production hot path short-circuits (no parse).
|
|
315
300
|
|
|
316
301
|
Caller-facing `input` schemas are validated **always** (DEV + production)
|
|
317
302
|
— they're the contract with external callers. Server-authored `output`
|
|
@@ -345,11 +330,9 @@ and `allow_fallback: boolean` (default `true`). Explicit
|
|
|
345
330
|
|
|
346
331
|
### Transport modules
|
|
347
332
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
| `actions/transports_ws.ts` | `frontend_websocket_rpc` | Thin adapter over `WebsocketRpcConnection` (default impl: `FrontendWebsocketClient`) |
|
|
352
|
-
| `actions/transports_ws_backend.ts` | `backend_websocket_rpc` | Server-side WS with session tracking; satisfies `FilterableBroadcastTransport` |
|
|
333
|
+
- `actions/transports_http.ts` — `frontend_http_rpc`; thin `fetch` adapter, POST default, GET on `has_side_effects(method) === false`.
|
|
334
|
+
- `actions/transports_ws.ts` — `frontend_websocket_rpc`; thin adapter over `WebsocketRpcConnection` (default impl: `FrontendWebsocketClient`).
|
|
335
|
+
- `actions/transports_ws_backend.ts` — `backend_websocket_rpc`; server-side WS with session tracking; satisfies `FilterableBroadcastTransport`.
|
|
353
336
|
|
|
354
337
|
`FrontendHttpTransport` synthesizes a JSON-RPC error envelope via
|
|
355
338
|
`http_status_to_jsonrpc_error_code` on non-OK HTTP; DEV warns on drift
|
|
@@ -547,13 +530,12 @@ Two abort signals composed via `AbortSignal.any`:
|
|
|
547
530
|
## Protocol actions (`actions/protocol.ts`)
|
|
548
531
|
|
|
549
532
|
Two shared `{spec, handler}` tuples that every consumer spreads into both
|
|
550
|
-
sides' `actions` arrays — disconnect detection and per-request cancel
|
|
551
|
-
identically across every repo without per-consumer ping plumbing.
|
|
533
|
+
sides' `actions` arrays — disconnect detection and per-request cancel
|
|
534
|
+
work identically across every repo without per-consumer ping plumbing.
|
|
552
535
|
|
|
553
536
|
The category is wire-protocol concerns shipped by fuz_app, not consumer
|
|
554
|
-
domain logic.
|
|
555
|
-
|
|
556
|
-
action does not.
|
|
537
|
+
domain logic. Protocol vs domain: a future clock-skew probe or
|
|
538
|
+
reconnect-resume token belongs here; a `payment_charge` action does not.
|
|
557
539
|
|
|
558
540
|
Two const arrays:
|
|
559
541
|
|
|
@@ -566,8 +548,8 @@ stub), frontend registry only stores specs. Both bundles plus the codegen
|
|
|
566
548
|
|
|
567
549
|
**Not auto-spread by `create_frontend_rpc_client` or `register_ws_endpoint`** —
|
|
568
550
|
bundled helpers stay pure factories so the dispatch surface stays
|
|
569
|
-
grep-traceable at every
|
|
570
|
-
|
|
551
|
+
grep-traceable at every registration site and consumers can override
|
|
552
|
+
individual protocol actions without an opt-out flag.
|
|
571
553
|
|
|
572
554
|
### Individual actions
|
|
573
555
|
|
|
@@ -645,10 +627,8 @@ the live `ActionEvent` (zzz wires reactive history here).
|
|
|
645
627
|
|
|
646
628
|
### Throwing variants
|
|
647
629
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
| `create_throwing_rpc_call` | `(method, input?) => Promise<T>` | Adapter wiring (e.g. `ui/admin_rpc_adapters.ts`) — method comes from a map |
|
|
651
|
-
| `create_throwing_api` | Typed Proxy over `FrontendActionsApi` | Direct call sites — `await api.foo(input)` keeps full inference |
|
|
630
|
+
- `create_throwing_rpc_call` — shape `(method, input?) => Promise<T>`. Use at adapter wiring (e.g. `ui/admin_rpc_adapters.ts`) — method comes from a map.
|
|
631
|
+
- `create_throwing_api` — typed Proxy over `FrontendActionsApi`. Use at direct call sites — `await api.foo(input)` keeps full inference.
|
|
652
632
|
|
|
653
633
|
**Layered design.** `Result` is the protocol primitive —
|
|
654
634
|
`create_rpc_client` returns `Result<{value}, {error}>` with no Error
|
|
@@ -657,8 +637,7 @@ both shapes share the same underlying transport and call sites pick
|
|
|
657
637
|
per-site. `Result` is preferable when the call site inspects
|
|
658
638
|
`error.data.reason` (no allocation, no try/catch) or when overhead matters
|
|
659
639
|
(reconnect storms, hot paths). Throwing is preferable when the call site
|
|
660
|
-
doesn't inspect — `await api.foo()` reads cleaner than
|
|
661
|
-
ritual.
|
|
640
|
+
doesn't inspect — `await api.foo()` reads cleaner than `if (!r.ok) throw …`.
|
|
662
641
|
|
|
663
642
|
Hardening on both: only `{code, data}` cross onto the Error, leaving
|
|
664
643
|
`name` / `stack` as the native Error's own so attacker-shaped
|
|
@@ -716,7 +695,7 @@ failure), wraps in `JsonrpcNotification`, sends via the peer's resolved
|
|
|
716
695
|
transport. `transport_name` on `peer.default_send_options` pins the target
|
|
717
696
|
deterministically — no fallback, because broadcast is 1→N over a specific
|
|
718
697
|
primary transport and "any ready transport" could reach an unexpected
|
|
719
|
-
audience. Silently skips when
|
|
698
|
+
audience. Silently skips when none ready.
|
|
720
699
|
|
|
721
700
|
`should_deliver: (identity, method, input) => boolean` — optional
|
|
722
701
|
per-connection ACL predicate. When set, fans out via
|
|
@@ -457,7 +457,7 @@ export interface SpecSource {
|
|
|
457
457
|
* @example
|
|
458
458
|
* ```ts
|
|
459
459
|
* const sources = [
|
|
460
|
-
* {ns: 'tx_specs', module: './action_specs.js', specs:
|
|
460
|
+
* {ns: 'tx_specs', module: './action_specs.js', specs: all_zap_action_specs},
|
|
461
461
|
* {ns: 'admin_specs', module: '@fuzdev/fuz_app/auth/admin_action_specs.js', specs: all_admin_action_specs},
|
|
462
462
|
* ];
|
|
463
463
|
*
|
|
@@ -943,7 +943,7 @@ export type ${type_name} = {
|
|
|
943
943
|
* @example
|
|
944
944
|
* ```ts
|
|
945
945
|
* const sources = [
|
|
946
|
-
* {ns: 'tx_specs', module: './action_specs.js', specs:
|
|
946
|
+
* {ns: 'tx_specs', module: './action_specs.js', specs: all_zap_action_specs},
|
|
947
947
|
* {ns: 'admin_specs', module: '@fuzdev/fuz_app/auth/admin_action_specs.js', specs: all_admin_action_specs},
|
|
948
948
|
* ];
|
|
949
949
|
*
|
|
@@ -56,7 +56,7 @@ export declare const ActionEventData: z.ZodObject<{
|
|
|
56
56
|
response: z.ZodNullable<z.ZodUnion<readonly [z.ZodObject<{
|
|
57
57
|
jsonrpc: z.ZodLiteral<"2.0">;
|
|
58
58
|
id: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
|
|
59
|
-
result: z.
|
|
59
|
+
result: z.ZodJSONSchema;
|
|
60
60
|
}, z.core.$loose>, z.ZodObject<{
|
|
61
61
|
jsonrpc: z.ZodLiteral<"2.0">;
|
|
62
62
|
id: z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
|