@fuzdev/fuz_app 0.44.0 → 0.45.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 -39
- package/dist/actions/action_event.d.ts +10 -1
- package/dist/actions/action_event.d.ts.map +1 -1
- package/dist/actions/action_event.js +7 -0
- package/dist/actions/broadcast_api.d.ts +1 -1
- package/dist/actions/broadcast_api.d.ts.map +1 -1
- package/dist/actions/frontend_rpc_client.d.ts +73 -19
- package/dist/actions/frontend_rpc_client.d.ts.map +1 -1
- package/dist/actions/frontend_rpc_client.js +43 -18
- package/dist/actions/rpc_client.d.ts +44 -82
- package/dist/actions/rpc_client.d.ts.map +1 -1
- package/dist/actions/rpc_client.js +51 -106
- package/dist/testing/ws_round_trip.d.ts +1 -1
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/ui/CLAUDE.md +10 -11
- package/dist/ui/admin_accounts_state.svelte.d.ts +20 -41
- package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
- package/dist/ui/admin_invites_state.svelte.d.ts +9 -18
- package/dist/ui/admin_invites_state.svelte.d.ts.map +1 -1
- package/dist/ui/admin_rpc_adapters.d.ts +41 -29
- package/dist/ui/admin_rpc_adapters.d.ts.map +1 -1
- package/dist/ui/admin_rpc_adapters.js +28 -31
- package/dist/ui/admin_sessions_state.svelte.d.ts +3 -2
- package/dist/ui/admin_sessions_state.svelte.d.ts.map +1 -1
- package/dist/ui/app_settings_state.svelte.d.ts +5 -10
- package/dist/ui/app_settings_state.svelte.d.ts.map +1 -1
- package/dist/ui/audit_log_state.svelte.d.ts +6 -18
- package/dist/ui/audit_log_state.svelte.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/actions/CLAUDE.md
CHANGED
|
@@ -581,11 +581,15 @@ per-method transport selector. Useful when methods are registered on
|
|
|
581
581
|
different backend dispatchers (e.g. streaming action on WS, rest on HTTP).
|
|
582
582
|
Returning `undefined` falls through to the peer's default selection.
|
|
583
583
|
|
|
584
|
-
`
|
|
585
|
-
|
|
586
|
-
`
|
|
587
|
-
`
|
|
588
|
-
history
|
|
584
|
+
`on_action_event: (event: ActionEvent<keyof TApi & string>) => void` —
|
|
585
|
+
optional callback fired once per dispatched action with the live
|
|
586
|
+
`ActionEvent`. Consumers wire reactive state inside the callback — e.g.
|
|
587
|
+
zzz's `Actions` cell calls its own `add_from_json` +
|
|
588
|
+
`listen_to_action_event` here so the history plumbing stays inside zzz
|
|
589
|
+
instead of leaking onto the rpc_client surface. `event.spec.method` and
|
|
590
|
+
`event.data.method` narrow to `keyof TApi & string` so consumers passing
|
|
591
|
+
a generated `ActionsApi` get the literal method-name union without an
|
|
592
|
+
`as ActionMethod` cast at the call site.
|
|
589
593
|
|
|
590
594
|
Cast the return to a generated `ActionsApi` interface for full typing:
|
|
591
595
|
codegen via `generate_actions_api_method_signature` keeps the shape
|
|
@@ -605,26 +609,39 @@ attacker-shaped `result.error` payloads cannot overwrite them.
|
|
|
605
609
|
| `create_throwing_rpc_call` | `(method, input?) => Promise<T>` | adapter wiring (e.g. `ui/admin_rpc_adapters.ts`) — method comes from a map |
|
|
606
610
|
| `create_throwing_api` | typed Proxy over `ActionsApi` | direct call sites — `await api.foo(input)` keeps full inference |
|
|
607
611
|
|
|
608
|
-
**
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
612
|
+
**Layered design.** Result is the protocol primitive — `create_rpc_client`
|
|
613
|
+
returns `Result<{value}, {error}>` per call with no Error allocation. The
|
|
614
|
+
throwing wrappers sit _above_ it as ergonomic adapters; both shapes share
|
|
615
|
+
the same underlying transport and call sites pick per-site. `Result` is
|
|
616
|
+
preferable when the call site inspects `error.data.reason` (no Error
|
|
617
|
+
allocation, no try/catch nesting) or when overhead matters (reconnect
|
|
618
|
+
storms, hot paths). Throwing is preferable when the call site doesn't
|
|
619
|
+
inspect — `await api.foo()` reads cleaner than the `if (!r.ok) throw …`
|
|
620
|
+
ritual.
|
|
621
|
+
|
|
622
|
+
`create_frontend_rpc_client` ships both shapes by default — see
|
|
623
|
+
[Frontend factory](#frontend-factory-frontend_rpc_clientts) below. Direct
|
|
624
|
+
consumers of `create_rpc_client` pass their typed `ActionsApi` as the
|
|
625
|
+
generic to get the typed Result-shaped Proxy without casts, then build
|
|
626
|
+
the throwing form on top:
|
|
613
627
|
|
|
614
628
|
```ts
|
|
615
|
-
const
|
|
616
|
-
const api = create_throwing_api(
|
|
629
|
+
const api_result = create_rpc_client<MyActionsApi>({peer, environment});
|
|
630
|
+
const api = create_throwing_api(api_result);
|
|
617
631
|
// hot path: await api.foo(input)
|
|
618
|
-
// rare branch: const r = await
|
|
632
|
+
// rare branch: const r = await api_result.foo(input); if (!r.ok) { … }
|
|
619
633
|
```
|
|
620
634
|
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
635
|
+
`create_throwing_rpc_call` is **not** a peer choice for direct call sites —
|
|
636
|
+
it's a niche primitive for method-name-mapping adapter factories
|
|
637
|
+
(`ui/admin_rpc_adapters.ts`) where the method string comes from a domain
|
|
638
|
+
mapping rather than a typed call site. Use it only at adapter boundaries.
|
|
639
|
+
|
|
640
|
+
`ThrowingApi<TApi>` (the mapped type returned by `create_throwing_api`)
|
|
641
|
+
strips `Promise<Result<{value: T}, {error: JsonrpcErrorObject}>>` to
|
|
642
|
+
`Promise<T>` on every method that matches the `request_response` /
|
|
643
|
+
async `local_call` return shape; `remote_notification` (`=> void`) and
|
|
644
|
+
sync `local_call` methods pass through. The Proxy inspects each call's
|
|
628
645
|
result shape at runtime and only unwraps when it sees a Result, so
|
|
629
646
|
non-Result returns flow through unchanged.
|
|
630
647
|
|
|
@@ -637,33 +654,42 @@ probed as a thenable by `await`.
|
|
|
637
654
|
|
|
638
655
|
### Frontend factory (`frontend_rpc_client.ts`)
|
|
639
656
|
|
|
640
|
-
`create_frontend_rpc_client<TApi>({specs, path?, transports?})`
|
|
641
|
-
the `ActionRegistry + ActionEventEnvironment + Transports +
|
|
642
|
-
create_rpc_client` boilerplate every
|
|
643
|
-
`lookup_action_handler: () => undefined`
|
|
644
|
-
`request_response` handlers; every
|
|
645
|
-
The `as unknown as TApi` cast happens
|
|
646
|
-
get a typed return without the cast
|
|
647
|
-
|
|
648
|
-
needing extra transports / WS notification handlers / action-history
|
|
649
|
-
wiring) can extend without recreating the bundle.
|
|
657
|
+
`create_frontend_rpc_client<TApi>({specs, path?, transports?, transport_for_method?, on_action_event?})`
|
|
658
|
+
bundles the `ActionRegistry + ActionEventEnvironment + Transports +
|
|
659
|
+
ActionPeer + create_rpc_client + create_throwing_api` boilerplate every
|
|
660
|
+
consumer repeats — plus the `lookup_action_handler: () => undefined`
|
|
661
|
+
stub (frontend never registers `request_response` handlers; every
|
|
662
|
+
method dispatches over the wire). The `as unknown as TApi` cast happens
|
|
663
|
+
inside the helper, so call sites get a typed return without the cast
|
|
664
|
+
hostility.
|
|
650
665
|
|
|
651
|
-
|
|
652
|
-
`transports` for WS-first or mixed setups — when supplied, the default
|
|
653
|
-
HTTP transport is **not** registered. `local_call` specs in `specs`
|
|
654
|
-
silently no-op because `lookup_action_handler` always returns
|
|
655
|
-
`undefined`; this factory targets wire-dispatched actions.
|
|
666
|
+
Returns both Proxy shapes from one factory call:
|
|
656
667
|
|
|
657
|
-
|
|
658
|
-
`
|
|
668
|
+
- `api: ThrowingApi<TApi>` — typed throwing Proxy. Default for hot-path call sites.
|
|
669
|
+
- `api_result: TApi` — typed Result-shaped Proxy. For sites that inspect `error.data.reason` without try/catch.
|
|
670
|
+
- `peer`, `environment` — exposed for advanced consumers that want to register more transports or share the environment with a separate dispatcher.
|
|
659
671
|
|
|
660
672
|
```ts
|
|
661
|
-
const {api
|
|
673
|
+
const {api, api_result} = create_frontend_rpc_client<MyActionsApi>({
|
|
662
674
|
specs: all_standard_action_specs,
|
|
663
675
|
});
|
|
664
|
-
|
|
676
|
+
// hot path: await api.account_verify()
|
|
677
|
+
// rare branch: const r = await api_result.account_verify(); if (!r.ok) { … }
|
|
665
678
|
```
|
|
666
679
|
|
|
680
|
+
Default transport is `FrontendHttpTransport(path ?? '/api/rpc')`. Pass
|
|
681
|
+
`transports` for WS-first or mixed setups — when supplied, the default
|
|
682
|
+
HTTP transport is **not** registered. `local_call` specs in `specs`
|
|
683
|
+
silently no-op because `lookup_action_handler` always returns
|
|
684
|
+
`undefined`; this factory targets wire-dispatched actions.
|
|
685
|
+
|
|
686
|
+
`transport_for_method` and `on_action_event` are pure pass-throughs to
|
|
687
|
+
`create_rpc_client` — exposed so consumers needing per-method routing
|
|
688
|
+
(tx-style WS-for-actions / HTTP-for-rest split) or per-dispatch event
|
|
689
|
+
wiring (zzz-style reactive Cells observing `ActionEvent` lifecycle)
|
|
690
|
+
don't have to drop down to manual `create_rpc_client` construction
|
|
691
|
+
(which forfeits the bundled `api` / `api_result` pair).
|
|
692
|
+
|
|
667
693
|
`all_standard_action_specs` (in `../auth/standard_action_specs.ts`) is
|
|
668
694
|
the matching aggregate spec list mirroring `create_standard_rpc_actions`
|
|
669
695
|
on the backend — see `../auth/CLAUDE.md` §`standard_rpc_actions.ts`.
|
|
@@ -17,7 +17,16 @@ export type ActionEventChangeObserver<TMethod extends string = string> = (new_da
|
|
|
17
17
|
export declare class ActionEvent<TMethod extends string = string, TPhase extends ActionEventPhase = ActionEventPhase, TStep extends ActionEventStep = ActionEventStep> {
|
|
18
18
|
#private;
|
|
19
19
|
readonly environment: ActionEventEnvironment;
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* `method` narrows to `TMethod` so consumers passing a typed `TApi` to
|
|
22
|
+
* `create_rpc_client` get `event.spec.method` typed as the union of
|
|
23
|
+
* their API's method names rather than plain `string`. The runtime
|
|
24
|
+
* value comes from `lookup_action_spec(method)` keyed off the Proxy
|
|
25
|
+
* get trap, so the narrowing matches the dispatched method.
|
|
26
|
+
*/
|
|
27
|
+
readonly spec: ActionSpecUnion & {
|
|
28
|
+
method: TMethod;
|
|
29
|
+
};
|
|
21
30
|
get data(): ActionEventDataUnion<TMethod> & {
|
|
22
31
|
phase: TPhase;
|
|
23
32
|
step: TStep;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action_event.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_event.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAC,gBAAgB,EAAc,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAWpF,OAAO,KAAK,EACX,cAAc,EACd,sBAAsB,EACtB,mBAAmB,EAEnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAC,sBAAsB,EAAE,eAAe,EAAC,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAAkB,KAAK,oBAAoB,EAAC,MAAM,wBAAwB,CAAC;AAclF,MAAM,MAAM,yBAAyB,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM,IAAI,CACxE,QAAQ,EAAE,oBAAoB,CAAC,OAAO,CAAC,EACvC,QAAQ,EAAE,oBAAoB,CAAC,OAAO,CAAC,EACvC,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,KACvB,IAAI,CAAC;AAEV;;GAEG;AACH,qBAAa,WAAW,CACvB,OAAO,SAAS,MAAM,GAAG,MAAM,EAC/B,MAAM,SAAS,gBAAgB,GAAG,gBAAgB,EAClD,KAAK,SAAS,eAAe,GAAG,eAAe;;IAK/C,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAC;IAC7C,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"action_event.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_event.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAC,gBAAgB,EAAc,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAWpF,OAAO,KAAK,EACX,cAAc,EACd,sBAAsB,EACtB,mBAAmB,EAEnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAC,sBAAsB,EAAE,eAAe,EAAC,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAAkB,KAAK,oBAAoB,EAAC,MAAM,wBAAwB,CAAC;AAclF,MAAM,MAAM,yBAAyB,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM,IAAI,CACxE,QAAQ,EAAE,oBAAoB,CAAC,OAAO,CAAC,EACvC,QAAQ,EAAE,oBAAoB,CAAC,OAAO,CAAC,EACvC,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,KACvB,IAAI,CAAC;AAEV;;GAEG;AACH,qBAAa,WAAW,CACvB,OAAO,SAAS,MAAM,GAAG,MAAM,EAC/B,MAAM,SAAS,gBAAgB,GAAG,gBAAgB,EAClD,KAAK,SAAS,eAAe,GAAG,eAAe;;IAK/C,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAC;IAC7C;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG;QAAC,MAAM,EAAE,OAAO,CAAA;KAAC,CAAC;IAEnD,IAAI,IAAI,IAAI,oBAAoB,CAAC,OAAO,CAAC,GAAG;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,KAAK,CAAA;KAAC,CAEvE;gBAGA,WAAW,EAAE,sBAAsB,EACnC,IAAI,EAAE,eAAe,EACrB,IAAI,EAAE,oBAAoB,CAAC,OAAO,CAAC;IAOpC,MAAM,IAAI,oBAAoB,CAAC,OAAO,CAAC;IAMvC,OAAO,CAAC,QAAQ,EAAE,yBAAyB,CAAC,OAAO,CAAC,GAAG,MAAM,IAAI;IAKjE,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,CAAC,OAAO,CAAC,GAAG,IAAI;IAUvD;;OAEG;IACH,KAAK,IAAI,IAAI;IA8Cb;;OAEG;IAGG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IA0CnC;;OAEG;IACH,WAAW,IAAI,IAAI;IAkCnB;;OAEG;IACH,UAAU,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAezC,WAAW,IAAI,OAAO;IAItB,eAAe,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAIxC,WAAW,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAQ1C,YAAY,CAAC,QAAQ,EAAE,sBAAsB,GAAG,IAAI;IAUpD,gBAAgB,CAAC,YAAY,EAAE,mBAAmB,GAAG,IAAI;CAyKzD;AAGD;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAO,SAAS,MAAM,GAAG,MAAM,EAClE,aAAa,sBAAsB,EACnC,MAAM,eAAe,EACrB,OAAO,OAAO,EACd,gBAAgB,gBAAgB,KAC9B,WAAW,CAAC,OAAO,CAiBrB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,6BAA6B,GAAI,OAAO,SAAS,MAAM,GAAG,MAAM,EAC5E,MAAM,oBAAoB,CAAC,OAAO,CAAC,EACnC,aAAa,sBAAsB,KACjC,WAAW,CAAC,OAAO,CAOrB,CAAC;AAIF,eAAO,MAAM,kBAAkB,GAC9B,UAAU,OAAO,EACjB,aAAa,sBAAsB,KACjC,WAGF,CAAC"}
|
|
@@ -19,6 +19,13 @@ export class ActionEvent {
|
|
|
19
19
|
#data;
|
|
20
20
|
#listeners = new Set();
|
|
21
21
|
environment;
|
|
22
|
+
/**
|
|
23
|
+
* `method` narrows to `TMethod` so consumers passing a typed `TApi` to
|
|
24
|
+
* `create_rpc_client` get `event.spec.method` typed as the union of
|
|
25
|
+
* their API's method names rather than plain `string`. The runtime
|
|
26
|
+
* value comes from `lookup_action_spec(method)` keyed off the Proxy
|
|
27
|
+
* get trap, so the narrowing matches the dispatched method.
|
|
28
|
+
*/
|
|
22
29
|
spec;
|
|
23
30
|
get data() {
|
|
24
31
|
return this.#data;
|
|
@@ -94,5 +94,5 @@ export type BroadcastApi = Record<string, (input: never) => Promise<void>>;
|
|
|
94
94
|
* array in sync. Codegen (`action_collections.gen.ts`) is a natural fit
|
|
95
95
|
* if the consumer already generates per-method type maps.
|
|
96
96
|
*/
|
|
97
|
-
export declare const create_broadcast_api: <TApi
|
|
97
|
+
export declare const create_broadcast_api: <TApi extends object>(options: CreateBroadcastApiOptions) => TApi;
|
|
98
98
|
//# sourceMappingURL=broadcast_api.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"broadcast_api.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/broadcast_api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAS,KAAK,MAAM,IAAI,UAAU,EAAC,MAAM,yBAAyB,CAAC;AAG1E,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAEN,KAAK,kBAAkB,EACvB,MAAM,4BAA4B,CAAC;AAEpC;;;;;;;;GAQG;AACH,MAAM,MAAM,eAAe,GAAG,CAC7B,UAAU,EAAE,kBAAkB,EAC9B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,KACV,OAAO,CAAC;AAEb,0CAA0C;AAC1C,MAAM,WAAW,yBAAyB;IACzC,8DAA8D;IAC9D,IAAI,EAAE,UAAU,CAAC;IACjB;;;;;OAKG;IACH,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IACtC,gFAAgF;IAChF,GAAG,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IACxB;;;;;;;;;OASG;IACH,cAAc,CAAC,EAAE,eAAe,CAAC;CACjC;AAED;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AAE3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,oBAAoB,GAAI,IAAI,
|
|
1
|
+
{"version":3,"file":"broadcast_api.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/broadcast_api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAS,KAAK,MAAM,IAAI,UAAU,EAAC,MAAM,yBAAyB,CAAC;AAG1E,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAEN,KAAK,kBAAkB,EACvB,MAAM,4BAA4B,CAAC;AAEpC;;;;;;;;GAQG;AACH,MAAM,MAAM,eAAe,GAAG,CAC7B,UAAU,EAAE,kBAAkB,EAC9B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,KACV,OAAO,CAAC;AAEb,0CAA0C;AAC1C,MAAM,WAAW,yBAAyB;IACzC,8DAA8D;IAC9D,IAAI,EAAE,UAAU,CAAC;IACjB;;;;;OAKG;IACH,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IACtC,gFAAgF;IAChF,GAAG,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IACxB;;;;;;;;;OASG;IACH,cAAc,CAAC,EAAE,eAAe,CAAC;CACjC;AAED;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AAE3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,oBAAoB,GAAI,IAAI,SAAS,MAAM,EACvD,SAAS,yBAAyB,KAChC,IAoDF,CAAC"}
|
|
@@ -2,25 +2,41 @@
|
|
|
2
2
|
* Frontend-only typed RPC client factory.
|
|
3
3
|
*
|
|
4
4
|
* Bundles the `ActionRegistry + ActionEventEnvironment + Transports +
|
|
5
|
-
* ActionPeer + create_rpc_client` boilerplate every
|
|
6
|
-
* the `lookup_action_handler: () => undefined`
|
|
7
|
-
* `request_response` handlers; every method
|
|
5
|
+
* ActionPeer + create_rpc_client + create_throwing_api` boilerplate every
|
|
6
|
+
* consumer repeats — plus the `lookup_action_handler: () => undefined`
|
|
7
|
+
* stub (frontend never registers `request_response` handlers; every method
|
|
8
|
+
* dispatches over the wire).
|
|
8
9
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* Returns both Proxy shapes from one factory call:
|
|
11
|
+
*
|
|
12
|
+
* - `api` — typed throwing Proxy. `await api.foo(input)` returns the
|
|
13
|
+
* unwrapped value or throws an `Error` carrying `{code, data}` from the
|
|
14
|
+
* JSON-RPC error. Use at hot-path call sites.
|
|
15
|
+
* - `api_result` — typed Result-shaped Proxy. `await api_result.foo(input)`
|
|
16
|
+
* returns `Result<{value}, {error: JsonrpcErrorObject}>`. Use when call
|
|
17
|
+
* sites want to inspect `error.data.reason` without try/catch — and
|
|
18
|
+
* anywhere allocating an `Error` per `{ok: false}` is wasteful (e.g.
|
|
19
|
+
* reconnect-storm `service_unavailable` paths). Result is the protocol
|
|
20
|
+
* primitive; the throwing form is a wrapper over it. Both share the
|
|
21
|
+
* same underlying transport — pick per call site, no construction cost.
|
|
12
22
|
*
|
|
13
|
-
*
|
|
23
|
+
* Generic `TApi` is the consumer's typed Proxy interface. The `as unknown
|
|
24
|
+
* as TApi` double cast happens inside the helper so call sites get a
|
|
25
|
+
* typed return value without the cast hostility. `api`'s type is
|
|
26
|
+
* `ThrowingApi<TApi>` — the mapped type strips the Result wrapper.
|
|
14
27
|
*
|
|
15
28
|
* ```ts
|
|
16
|
-
* const {api
|
|
17
|
-
*
|
|
29
|
+
* const {api, api_result} = create_frontend_rpc_client<MyActionsApi>({
|
|
30
|
+
* specs: all_specs,
|
|
31
|
+
* });
|
|
32
|
+
* // hot path: await api.account_verify()
|
|
33
|
+
* // rare branch: const r = await api_result.account_verify(); if (!r.ok) { … }
|
|
18
34
|
* ```
|
|
19
35
|
*
|
|
20
|
-
* Returns the underlying `peer` and `environment` alongside
|
|
21
|
-
* advanced consumers (zzz-style frontends needing extra
|
|
22
|
-
* notification handlers / action-history wiring) can
|
|
23
|
-
* recreating the bundle.
|
|
36
|
+
* Returns the underlying `peer` and `environment` alongside the two api
|
|
37
|
+
* shapes so advanced consumers (zzz-style frontends needing extra
|
|
38
|
+
* transports / WS notification handlers / action-history wiring) can
|
|
39
|
+
* extend without recreating the bundle.
|
|
24
40
|
*
|
|
25
41
|
* Note: `local_call` specs in `specs` will silently no-op because
|
|
26
42
|
* `lookup_action_handler` always returns `undefined` — the frontend
|
|
@@ -31,10 +47,12 @@
|
|
|
31
47
|
*/
|
|
32
48
|
import { ActionPeer } from './action_peer.js';
|
|
33
49
|
import { type Transport } from './transports.js';
|
|
50
|
+
import { type ThrowingApi, type TransportForMethod } from './rpc_client.js';
|
|
51
|
+
import type { ActionEvent } from './action_event.js';
|
|
34
52
|
import type { ActionEventEnvironment } from './action_event_types.js';
|
|
35
53
|
import type { ActionSpecUnion } from './action_spec.js';
|
|
36
54
|
/** Options for `create_frontend_rpc_client`. */
|
|
37
|
-
export interface CreateFrontendRpcClientOptions {
|
|
55
|
+
export interface CreateFrontendRpcClientOptions<TApi extends object = object> {
|
|
38
56
|
/**
|
|
39
57
|
* Action specs the typed Proxy can dispatch. Methods absent from this
|
|
40
58
|
* list silently return `undefined` from the Proxy — the generic `TApi`
|
|
@@ -54,11 +72,44 @@ export interface CreateFrontendRpcClientOptions {
|
|
|
54
72
|
* WS+HTTP mixed setups.
|
|
55
73
|
*/
|
|
56
74
|
transports?: ReadonlyArray<Transport>;
|
|
75
|
+
/**
|
|
76
|
+
* Optional per-method transport selector — pure pass-through to
|
|
77
|
+
* `create_rpc_client`. Return the transport name to use for a given
|
|
78
|
+
* method, or `undefined` to fall back to the peer's default selection.
|
|
79
|
+
*
|
|
80
|
+
* Useful when methods are registered on different backend dispatchers
|
|
81
|
+
* (e.g. streaming actions on WS, REST RPC on HTTP) — a tx-style mixed
|
|
82
|
+
* setup. Per-call `RpcClientCallOptions.transport_name` overrides this
|
|
83
|
+
* for individual dispatches.
|
|
84
|
+
*/
|
|
85
|
+
transport_for_method?: TransportForMethod;
|
|
86
|
+
/**
|
|
87
|
+
* Optional callback fired once per dispatched action — pure pass-through
|
|
88
|
+
* to `create_rpc_client`. Used by zzz-style consumers that thread the
|
|
89
|
+
* `ActionEvent` into a reactive cell (`add_from_json` + `listen_to_action_event`)
|
|
90
|
+
* for `pending` / `failed` / `value` derivations.
|
|
91
|
+
*
|
|
92
|
+
* `event.spec.method` and `event.data.method` narrow to
|
|
93
|
+
* `keyof TApi & string` — drop the `as ActionMethod` cast at the call
|
|
94
|
+
* site when `TApi` is a generated `ActionsApi` interface.
|
|
95
|
+
*/
|
|
96
|
+
on_action_event?: (event: ActionEvent<keyof TApi & string>) => void;
|
|
57
97
|
}
|
|
58
98
|
/** Bundle returned by `create_frontend_rpc_client`. */
|
|
59
99
|
export interface FrontendRpcClient<TApi> {
|
|
60
|
-
/**
|
|
61
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Typed throwing Proxy. `await api.method(input)` returns the unwrapped
|
|
102
|
+
* value or throws an `Error` with `{code, data}` from the JSON-RPC
|
|
103
|
+
* error. Default for call sites that don't inspect errors.
|
|
104
|
+
*/
|
|
105
|
+
api: ThrowingApi<TApi>;
|
|
106
|
+
/**
|
|
107
|
+
* Typed Result-shaped Proxy. `await api_result.method(input)` returns
|
|
108
|
+
* `Result<{value}, {error: JsonrpcErrorObject}>`. Use when call sites
|
|
109
|
+
* inspect `error.data.reason` without try/catch, or when Error
|
|
110
|
+
* allocation per `{ok: false}` would be wasteful.
|
|
111
|
+
*/
|
|
112
|
+
api_result: TApi;
|
|
62
113
|
/** Underlying peer — exposed for consumers that need to register more transports or send raw messages. */
|
|
63
114
|
peer: ActionPeer;
|
|
64
115
|
/** Action environment — exposed for consumers that need to share it (e.g. attach a notification handler registry). */
|
|
@@ -67,8 +118,11 @@ export interface FrontendRpcClient<TApi> {
|
|
|
67
118
|
/**
|
|
68
119
|
* Build a frontend-only typed RPC client.
|
|
69
120
|
*
|
|
70
|
-
* @param options - `specs` (required), optional `path` / `transports`
|
|
71
|
-
*
|
|
121
|
+
* @param options - `specs` (required), optional `path` / `transports` /
|
|
122
|
+
* `transport_for_method` / `on_action_event`
|
|
123
|
+
* @returns `{api, api_result, peer, environment}` — both Proxy shapes plus
|
|
124
|
+
* the underlying primitives. `api` throws on `{ok: false}`; `api_result`
|
|
125
|
+
* returns the Result.
|
|
72
126
|
*/
|
|
73
|
-
export declare const create_frontend_rpc_client: <TApi>(options: CreateFrontendRpcClientOptions) => FrontendRpcClient<TApi>;
|
|
127
|
+
export declare const create_frontend_rpc_client: <TApi extends object>(options: CreateFrontendRpcClientOptions<TApi>) => FrontendRpcClient<TApi>;
|
|
74
128
|
//# sourceMappingURL=frontend_rpc_client.d.ts.map
|
|
@@ -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
|
|
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;CACpE;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"}
|
|
@@ -2,25 +2,41 @@
|
|
|
2
2
|
* Frontend-only typed RPC client factory.
|
|
3
3
|
*
|
|
4
4
|
* Bundles the `ActionRegistry + ActionEventEnvironment + Transports +
|
|
5
|
-
* ActionPeer + create_rpc_client` boilerplate every
|
|
6
|
-
* the `lookup_action_handler: () => undefined`
|
|
7
|
-
* `request_response` handlers; every method
|
|
5
|
+
* ActionPeer + create_rpc_client + create_throwing_api` boilerplate every
|
|
6
|
+
* consumer repeats — plus the `lookup_action_handler: () => undefined`
|
|
7
|
+
* stub (frontend never registers `request_response` handlers; every method
|
|
8
|
+
* dispatches over the wire).
|
|
8
9
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* Returns both Proxy shapes from one factory call:
|
|
11
|
+
*
|
|
12
|
+
* - `api` — typed throwing Proxy. `await api.foo(input)` returns the
|
|
13
|
+
* unwrapped value or throws an `Error` carrying `{code, data}` from the
|
|
14
|
+
* JSON-RPC error. Use at hot-path call sites.
|
|
15
|
+
* - `api_result` — typed Result-shaped Proxy. `await api_result.foo(input)`
|
|
16
|
+
* returns `Result<{value}, {error: JsonrpcErrorObject}>`. Use when call
|
|
17
|
+
* sites want to inspect `error.data.reason` without try/catch — and
|
|
18
|
+
* anywhere allocating an `Error` per `{ok: false}` is wasteful (e.g.
|
|
19
|
+
* reconnect-storm `service_unavailable` paths). Result is the protocol
|
|
20
|
+
* primitive; the throwing form is a wrapper over it. Both share the
|
|
21
|
+
* same underlying transport — pick per call site, no construction cost.
|
|
12
22
|
*
|
|
13
|
-
*
|
|
23
|
+
* Generic `TApi` is the consumer's typed Proxy interface. The `as unknown
|
|
24
|
+
* as TApi` double cast happens inside the helper so call sites get a
|
|
25
|
+
* typed return value without the cast hostility. `api`'s type is
|
|
26
|
+
* `ThrowingApi<TApi>` — the mapped type strips the Result wrapper.
|
|
14
27
|
*
|
|
15
28
|
* ```ts
|
|
16
|
-
* const {api
|
|
17
|
-
*
|
|
29
|
+
* const {api, api_result} = create_frontend_rpc_client<MyActionsApi>({
|
|
30
|
+
* specs: all_specs,
|
|
31
|
+
* });
|
|
32
|
+
* // hot path: await api.account_verify()
|
|
33
|
+
* // rare branch: const r = await api_result.account_verify(); if (!r.ok) { … }
|
|
18
34
|
* ```
|
|
19
35
|
*
|
|
20
|
-
* Returns the underlying `peer` and `environment` alongside
|
|
21
|
-
* advanced consumers (zzz-style frontends needing extra
|
|
22
|
-
* notification handlers / action-history wiring) can
|
|
23
|
-
* recreating the bundle.
|
|
36
|
+
* Returns the underlying `peer` and `environment` alongside the two api
|
|
37
|
+
* shapes so advanced consumers (zzz-style frontends needing extra
|
|
38
|
+
* transports / WS notification handlers / action-history wiring) can
|
|
39
|
+
* extend without recreating the bundle.
|
|
24
40
|
*
|
|
25
41
|
* Note: `local_call` specs in `specs` will silently no-op because
|
|
26
42
|
* `lookup_action_handler` always returns `undefined` — the frontend
|
|
@@ -33,12 +49,15 @@ import { ActionRegistry } from './action_registry.js';
|
|
|
33
49
|
import { ActionPeer } from './action_peer.js';
|
|
34
50
|
import { Transports } from './transports.js';
|
|
35
51
|
import { FrontendHttpTransport } from './transports_http.js';
|
|
36
|
-
import { create_rpc_client } from './rpc_client.js';
|
|
52
|
+
import { create_rpc_client, create_throwing_api, } from './rpc_client.js';
|
|
37
53
|
/**
|
|
38
54
|
* Build a frontend-only typed RPC client.
|
|
39
55
|
*
|
|
40
|
-
* @param options - `specs` (required), optional `path` / `transports`
|
|
41
|
-
*
|
|
56
|
+
* @param options - `specs` (required), optional `path` / `transports` /
|
|
57
|
+
* `transport_for_method` / `on_action_event`
|
|
58
|
+
* @returns `{api, api_result, peer, environment}` — both Proxy shapes plus
|
|
59
|
+
* the underlying primitives. `api` throws on `{ok: false}`; `api_result`
|
|
60
|
+
* returns the Result.
|
|
42
61
|
*/
|
|
43
62
|
export const create_frontend_rpc_client = (options) => {
|
|
44
63
|
const registry = new ActionRegistry([...options.specs]);
|
|
@@ -56,6 +75,12 @@ export const create_frontend_rpc_client = (options) => {
|
|
|
56
75
|
transports.register_transport(new FrontendHttpTransport(options.path ?? '/api/rpc'));
|
|
57
76
|
}
|
|
58
77
|
const peer = new ActionPeer({ environment, transports });
|
|
59
|
-
const
|
|
60
|
-
|
|
78
|
+
const api_result = create_rpc_client({
|
|
79
|
+
peer,
|
|
80
|
+
environment,
|
|
81
|
+
on_action_event: options.on_action_event,
|
|
82
|
+
transport_for_method: options.transport_for_method,
|
|
83
|
+
});
|
|
84
|
+
const api = create_throwing_api(api_result);
|
|
85
|
+
return { api, api_result, peer, environment };
|
|
61
86
|
};
|
|
@@ -5,14 +5,15 @@
|
|
|
5
5
|
* - **Tier 1** (simple, for tx): transport send/receive, Result return. No `environment`.
|
|
6
6
|
* - **Tier 2** (full, for zzz): ActionEvent lifecycle with `environment`.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
8
|
+
* Pass the consumer's generated `ActionsApi` interface as `<TApi>` to flow
|
|
9
|
+
* full type safety through without an explicit cast at the call site.
|
|
9
10
|
*
|
|
10
11
|
* @module
|
|
11
12
|
*/
|
|
12
13
|
import type { Result } from '@fuzdev/fuz_util/result.js';
|
|
13
14
|
import type { ActionEventEnvironment } from './action_event_types.js';
|
|
15
|
+
import { type ActionEvent } from './action_event.js';
|
|
14
16
|
import type { ActionPeer, ActionPeerSendOptions } from './action_peer.js';
|
|
15
|
-
import type { ActionEventDataUnion } from './action_event_data.js';
|
|
16
17
|
import type { TransportName } from './transports.js';
|
|
17
18
|
import type { JsonrpcErrorObject } from '../http/jsonrpc.js';
|
|
18
19
|
/**
|
|
@@ -24,21 +25,21 @@ import type { JsonrpcErrorObject } from '../http/jsonrpc.js';
|
|
|
24
25
|
* RPC surface lives on HTTP.
|
|
25
26
|
*/
|
|
26
27
|
export type TransportForMethod = (method: string) => TransportName | undefined;
|
|
27
|
-
/** Duck-typed action history — consumers pass their concrete Actions cell. */
|
|
28
|
-
export interface RpcClientActionHistory {
|
|
29
|
-
add_from_json: (json: {
|
|
30
|
-
method: string;
|
|
31
|
-
action_event_data: ActionEventDataUnion;
|
|
32
|
-
}) => {
|
|
33
|
-
listen_to_action_event: (event: any) => void;
|
|
34
|
-
} | undefined;
|
|
35
|
-
}
|
|
36
28
|
/** Options for `create_rpc_client`. */
|
|
37
|
-
export interface CreateRpcClientOptions {
|
|
29
|
+
export interface CreateRpcClientOptions<TApi extends object = object> {
|
|
38
30
|
peer: ActionPeer;
|
|
39
31
|
environment: ActionEventEnvironment;
|
|
40
|
-
/**
|
|
41
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Optional callback fired once per dispatched action with the live
|
|
34
|
+
* `ActionEvent`. Consumers wire reactive state here — e.g. zzz's `Actions`
|
|
35
|
+
* cell calls `add_from_json` + `listen_to_action_event` inside the
|
|
36
|
+
* callback so its history stays decoupled from the rpc_client surface.
|
|
37
|
+
*
|
|
38
|
+
* `event.spec.method` and `event.data.method` narrow to
|
|
39
|
+
* `keyof TApi & string` — drop the `as ActionMethod` cast at the call
|
|
40
|
+
* site when `TApi` is a generated `ActionsApi` interface.
|
|
41
|
+
*/
|
|
42
|
+
on_action_event?: (event: ActionEvent<keyof TApi & string>) => void;
|
|
42
43
|
/**
|
|
43
44
|
* Optional per-method transport selector. When provided, the client calls
|
|
44
45
|
* `peer.send(msg, {transport_name})` with the returned transport for each
|
|
@@ -55,10 +56,22 @@ export interface CreateRpcClientOptions {
|
|
|
55
56
|
* - `remote_notification` → send notification, return Result
|
|
56
57
|
* - `local_call` → execute locally (sync or async), return Result or throw
|
|
57
58
|
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
59
|
+
* Generic `TApi` is the consumer's typed Proxy interface (typically a
|
|
60
|
+
* codegen-derived `ActionsApi`). Required — no default, so forgetting it
|
|
61
|
+
* is a type error rather than a silent slide into `any`. The `as unknown
|
|
62
|
+
* as TApi` coercion lives inside this function so call sites get a typed
|
|
63
|
+
* return without a cast at the seam. `TApi` is a type-layer promise about
|
|
64
|
+
* what the Proxy responds to; the runtime walks `specs` (kept in sync by
|
|
65
|
+
* the consumer, codegen recommended).
|
|
66
|
+
*
|
|
67
|
+
* ```ts
|
|
68
|
+
* const api_result = create_rpc_client<MyActionsApi>({peer, environment});
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* @param options - client options (peer, environment, optional callbacks)
|
|
72
|
+
* @returns a Proxy typed as `TApi` that responds to any method name found in the environment's specs
|
|
60
73
|
*/
|
|
61
|
-
export declare const create_rpc_client: (options: CreateRpcClientOptions
|
|
74
|
+
export declare const create_rpc_client: <TApi extends object>(options: CreateRpcClientOptions<TApi>) => TApi;
|
|
62
75
|
/**
|
|
63
76
|
* Per-call options accepted by every typed Proxy method. Same shape as
|
|
64
77
|
* `ActionPeerSendOptions` — the client threads these through unchanged
|
|
@@ -67,54 +80,6 @@ export declare const create_rpc_client: (options: CreateRpcClientOptions) => Rec
|
|
|
67
80
|
*/
|
|
68
81
|
export interface RpcClientCallOptions extends ActionPeerSendOptions {
|
|
69
82
|
}
|
|
70
|
-
/**
|
|
71
|
-
* `method, input -> unwrapped output` signature for adapter wiring.
|
|
72
|
-
*
|
|
73
|
-
* The typed `create_rpc_client` Proxy returns `Result<T, JsonrpcErrorObject>`
|
|
74
|
-
* on every call. UI adapters (e.g. `admin_rpc_adapters.ts`) want a
|
|
75
|
-
* throw-on-error shape so form components can match on `error.data.reason`
|
|
76
|
-
* via catch blocks. `create_throwing_rpc_call` bridges the two.
|
|
77
|
-
*/
|
|
78
|
-
export type ThrowingRpcCall = <TOutput = unknown>(method: string, input?: unknown) => Promise<TOutput>;
|
|
79
|
-
/**
|
|
80
|
-
* Wrap a typed RPC client so every call returns its unwrapped value or throws.
|
|
81
|
-
*
|
|
82
|
-
* On `{ok: false}`, throws an `Error` whose `message` comes from the
|
|
83
|
-
* JSON-RPC error object, plus `{code, data}` as own properties — so
|
|
84
|
-
* catch blocks reading `err.message` / `err.code` / `err.data?.reason`
|
|
85
|
-
* all work. On unknown method, throws a clear "rpc method not found"
|
|
86
|
-
* error instead of the cryptic `undefined is not a function` that
|
|
87
|
-
* would otherwise surface.
|
|
88
|
-
*
|
|
89
|
-
* Invariant upheld by `create_rpc_client`: every `{ok: false}` return
|
|
90
|
-
* carries a well-formed `JsonrpcErrorObject` with `code` + `message`.
|
|
91
|
-
* Callers must still use optional chaining on `err.data` because the
|
|
92
|
-
* JSON-RPC `data` field is spec-level optional — a handler that throws
|
|
93
|
-
* `jsonrpc_errors.forbidden()` without a `data` argument produces
|
|
94
|
-
* `err.data === undefined`.
|
|
95
|
-
*
|
|
96
|
-
* Only `{code, data}` cross onto the thrown Error — `message` flows
|
|
97
|
-
* through the `Error` constructor argument, and `name` / `stack` are
|
|
98
|
-
* left as the Error's own so attacker-shaped `result.error` payloads
|
|
99
|
-
* cannot overwrite them.
|
|
100
|
-
*
|
|
101
|
-
* The mapped-type generic constraint accepts both shapes without a cast:
|
|
102
|
-
* a codegen-derived typed `ActionsApi` (named-method interface, e.g.
|
|
103
|
-
* `{account_verify: (input) => Promise<Result<...>>, ...}`) and a loose
|
|
104
|
-
* `Record<string, (input?: any) => Promise<any> | void>`. Using `keyof TApi`
|
|
105
|
-
* in the constraint avoids the index-signature requirement that would
|
|
106
|
-
* otherwise force consumers to `as unknown as Record<string, …>` their
|
|
107
|
-
* generated client. The `| void` arm tolerates `remote_notification`
|
|
108
|
-
* methods, whose `ActionsApi` signature is `(input) => void` even though
|
|
109
|
-
* `create_remote_notification_method` returns a Promise at runtime — the
|
|
110
|
-
* throwing wrapper is intended for `request_response` calls but must
|
|
111
|
-
* accept mixed `ActionsApi` shapes without forcing a cast at the seam.
|
|
112
|
-
*
|
|
113
|
-
* @param api - typed RPC client from `create_rpc_client` (or any object
|
|
114
|
-
* whose values are all `(input?) => Promise<...> | void` functions —
|
|
115
|
-
* notably the consumer's generated `ActionsApi` interface)
|
|
116
|
-
*/
|
|
117
|
-
export declare const create_throwing_rpc_call: <TApi extends Record<keyof TApi, (input?: any) => Promise<any> | void>>(api: TApi) => ThrowingRpcCall;
|
|
118
83
|
/**
|
|
119
84
|
* Maps a typed `ActionsApi` to a throwing variant.
|
|
120
85
|
*
|
|
@@ -151,30 +116,27 @@ export type ThrowingApi<TApi> = {
|
|
|
151
116
|
*
|
|
152
117
|
* Only `{code, data}` cross onto the thrown Error — `name` / `stack` are
|
|
153
118
|
* left as the Error's own properties so attacker-shaped `result.error`
|
|
154
|
-
* payloads cannot overwrite them.
|
|
155
|
-
* `create_throwing_rpc_call`.
|
|
156
|
-
*
|
|
157
|
-
* Composable with `create_throwing_rpc_call` — same typed underlying
|
|
158
|
-
* client feeds both: the Proxy form for direct call sites, the loose
|
|
159
|
-
* method-keyed form for adapter wiring (`ui/admin_rpc_adapters.ts`).
|
|
119
|
+
* payloads cannot overwrite them.
|
|
160
120
|
*
|
|
161
|
-
* Recommended consumer convention:
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
121
|
+
* Recommended consumer convention: `create_frontend_rpc_client` ships
|
|
122
|
+
* both shapes by default — `api` (throwing) for hot-path call sites and
|
|
123
|
+
* `api_result` (Result) for sites that inspect `error.data.reason`
|
|
124
|
+
* without try/catch. Result is the protocol primitive; this wrapper is
|
|
125
|
+
* the ergonomic layer over it. Picking is per call site — both Proxies
|
|
126
|
+
* share the same underlying transport.
|
|
165
127
|
*
|
|
166
128
|
* Catch blocks read `err.data?.reason` — optional chaining required
|
|
167
129
|
* because JSON-RPC `data` is spec-level optional.
|
|
168
130
|
*
|
|
169
131
|
* On unknown string-keyed methods, the get trap returns a function that
|
|
170
|
-
* throws `"rpc method not found: <prop>"` on invocation —
|
|
171
|
-
* `
|
|
172
|
-
*
|
|
173
|
-
* undefined so the Proxy isn't accidentally treated as a thenable
|
|
132
|
+
* throws `"rpc method not found: <prop>"` on invocation — clearer than
|
|
133
|
+
* the JS default `"api.foo is not a function"`. Symbol props and `then`
|
|
134
|
+
* stay undefined so the Proxy isn't accidentally treated as a thenable
|
|
174
135
|
* (`await api` would otherwise probe `then` and trip the thrower).
|
|
175
136
|
*
|
|
176
|
-
* @param
|
|
177
|
-
*
|
|
137
|
+
* @param api_result - typed Result-returning RPC client from
|
|
138
|
+
* `create_rpc_client<ActionsApi>(...)`. The "_result" suffix names
|
|
139
|
+
* what the underlying calls return (`Result<{value}, {error}>`).
|
|
178
140
|
*/
|
|
179
|
-
export declare const create_throwing_api: <TApi extends object>(
|
|
141
|
+
export declare const create_throwing_api: <TApi extends object>(api_result: TApi) => ThrowingApi<TApi>;
|
|
180
142
|
//# sourceMappingURL=rpc_client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc_client.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/rpc_client.ts"],"names":[],"mappings":"AAAA
|
|
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;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,WAAW,CAAC,IAAI,IAAI;KAC9B,CAAC,IAAI,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAClC,KAAK,CAAC,EAAE,MAAM,MAAM,EACpB,OAAO,CAAC,EAAE,MAAM,QAAQ,KACpB,OAAO,CAAC,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,MAAM,CAAA;KAAC,EAAE;QAAC,KAAK,EAAE,kBAAkB,CAAA;KAAC,CAAC,CAAC,GACrE,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,KAAK,OAAO,CAAC,MAAM,CAAC,GACvD,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"}
|