@fuzdev/fuz_app 0.44.0 → 0.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/actions/CLAUDE.md +65 -39
  2. package/dist/actions/action_event.d.ts +10 -1
  3. package/dist/actions/action_event.d.ts.map +1 -1
  4. package/dist/actions/action_event.js +7 -0
  5. package/dist/actions/action_event_helpers.d.ts.map +1 -1
  6. package/dist/actions/action_event_helpers.js +14 -4
  7. package/dist/actions/broadcast_api.d.ts +1 -1
  8. package/dist/actions/broadcast_api.d.ts.map +1 -1
  9. package/dist/actions/frontend_rpc_client.d.ts +95 -23
  10. package/dist/actions/frontend_rpc_client.d.ts.map +1 -1
  11. package/dist/actions/frontend_rpc_client.js +48 -23
  12. package/dist/actions/rpc_client.d.ts +56 -86
  13. package/dist/actions/rpc_client.d.ts.map +1 -1
  14. package/dist/actions/rpc_client.js +51 -106
  15. package/dist/testing/ws_round_trip.d.ts +1 -1
  16. package/dist/testing/ws_round_trip.d.ts.map +1 -1
  17. package/dist/ui/CLAUDE.md +10 -11
  18. package/dist/ui/admin_accounts_state.svelte.d.ts +20 -41
  19. package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
  20. package/dist/ui/admin_invites_state.svelte.d.ts +9 -18
  21. package/dist/ui/admin_invites_state.svelte.d.ts.map +1 -1
  22. package/dist/ui/admin_rpc_adapters.d.ts +41 -29
  23. package/dist/ui/admin_rpc_adapters.d.ts.map +1 -1
  24. package/dist/ui/admin_rpc_adapters.js +28 -31
  25. package/dist/ui/admin_sessions_state.svelte.d.ts +3 -2
  26. package/dist/ui/admin_sessions_state.svelte.d.ts.map +1 -1
  27. package/dist/ui/app_settings_state.svelte.d.ts +5 -10
  28. package/dist/ui/app_settings_state.svelte.d.ts.map +1 -1
  29. package/dist/ui/audit_log_state.svelte.d.ts +6 -18
  30. package/dist/ui/audit_log_state.svelte.d.ts.map +1 -1
  31. package/package.json +1 -1
@@ -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
- * Consumers cast the return to their generated `ActionsApi` interface for full type safety.
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
- /** Optional action history tracking (duck-typed Actions cell). */
41
- actions?: RpcClientActionHistory;
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
- * @param options - client options (peer, environment, optional action history)
59
- * @returns a Proxy that responds to any method name found in the environment's specs
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) => Record<string, (...args: Array<any>) => any>;
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
  *
@@ -124,15 +89,23 @@ export declare const create_throwing_rpc_call: <TApi extends Record<keyof TApi,
124
89
  * as `=> void`, sync `local_call` methods) pass through unchanged — there
125
90
  * is nothing to unwrap.
126
91
  *
127
- * Input + options parameters are preserved verbatim so generics, branded
128
- * Uuids, and per-call `RpcClientCallOptions` keep working.
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.
129
102
  */
130
103
  export type ThrowingApi<TApi> = {
131
- [K in keyof TApi]: TApi[K] extends (input?: infer TInput, options?: infer TOptions) => Promise<Result<{
104
+ [K in keyof TApi]: TApi[K] extends (...args: infer TArgs) => Promise<Result<{
132
105
  value: infer TValue;
133
106
  }, {
134
107
  error: JsonrpcErrorObject;
135
- }>> ? (input?: TInput, options?: TOptions) => Promise<TValue> : TApi[K];
108
+ }>> ? (...args: TArgs) => Promise<TValue> : TApi[K];
136
109
  };
137
110
  /**
138
111
  * Wrap a typed RPC client so every call resolves to its unwrapped value or
@@ -151,30 +124,27 @@ export type ThrowingApi<TApi> = {
151
124
  *
152
125
  * Only `{code, data}` cross onto the thrown Error — `name` / `stack` are
153
126
  * left as the Error's own properties so attacker-shaped `result.error`
154
- * payloads cannot overwrite them. Same hardening as
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`).
127
+ * payloads cannot overwrite them.
160
128
  *
161
- * Recommended consumer convention: bind the throwing wrapper to `api`
162
- * (the common case at call sites) and the underlying Result-returning
163
- * Proxy to `api_raw` (the composable escape hatch for callers that
164
- * want to inspect `error.data.reason` without try/catch).
129
+ * Recommended consumer convention: `create_frontend_rpc_client` ships
130
+ * both shapes by default `api` (throwing) for hot-path call sites and
131
+ * `api_result` (Result) for sites that inspect `error.data.reason`
132
+ * without try/catch. Result is the protocol primitive; this wrapper is
133
+ * the ergonomic layer over it. Picking is per call site — both Proxies
134
+ * share the same underlying transport.
165
135
  *
166
136
  * Catch blocks read `err.data?.reason` — optional chaining required
167
137
  * because JSON-RPC `data` is spec-level optional.
168
138
  *
169
139
  * On unknown string-keyed methods, the get trap returns a function that
170
- * throws `"rpc method not found: <prop>"` on invocation — symmetric with
171
- * `create_throwing_rpc_call` and clearer than the JS default
172
- * `"api.foo is not a function"`. Symbol props and `then` stay
173
- * undefined so the Proxy isn't accidentally treated as a thenable
140
+ * throws `"rpc method not found: <prop>"` on invocation — clearer than
141
+ * the JS default `"api.foo is not a function"`. Symbol props and `then`
142
+ * stay undefined so the Proxy isn't accidentally treated as a thenable
174
143
  * (`await api` would otherwise probe `then` and trip the thrower).
175
144
  *
176
- * @param api_raw - typed RPC client from `create_rpc_client`, cast
177
- * to a consumer-generated `ActionsApi` interface
145
+ * @param api_result - typed Result-returning RPC client from
146
+ * `create_rpc_client<ActionsApi>(...)`. The "_result" suffix names
147
+ * what the underlying calls return (`Result<{value}, {error}>`).
178
148
  */
179
- export declare const create_throwing_api: <TApi extends object>(api_raw: TApi) => ThrowingApi<TApi>;
149
+ export declare const create_throwing_api: <TApi extends object>(api_result: TApi) => ThrowingApi<TApi>;
180
150
  //# sourceMappingURL=rpc_client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rpc_client.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/rpc_client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,4BAA4B,CAAC;AAQvD,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,yBAAyB,CAAC;AAOpE,OAAO,KAAK,EAAC,UAAU,EAAE,qBAAqB,EAAC,MAAM,kBAAkB,CAAC;AACxE,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,wBAAwB,CAAC;AACjE,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,8EAA8E;AAC9E,MAAM,WAAW,sBAAsB;IACtC,aAAa,EAAE,CAAC,IAAI,EAAE;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,oBAAoB,CAAA;KAAC,KAC5E;QACA,sBAAsB,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;KAC5C,GACD,SAAS,CAAC;CACb;AAED,uCAAuC;AACvC,MAAM,WAAW,sBAAsB;IACtC,IAAI,EAAE,UAAU,CAAC;IACjB,WAAW,EAAE,sBAAsB,CAAC;IACpC,kEAAkE;IAClE,OAAO,CAAC,EAAE,sBAAsB,CAAC;IACjC;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,kBAAkB,CAAC;CAC1C;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,GAC7B,SAAS,sBAAsB,KAC7B,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,CAgB7C,CAAC;AA2DF;;;;;GAKG;AACH,MAAM,WAAW,oBAAqB,SAAQ,qBAAqB;CAAG;AAgItE;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,GAAG,OAAO,EAC/C,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,OAAO,KACX,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,eAAO,MAAM,wBAAwB,GACpC,IAAI,SAAS,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,EAErE,KAAK,IAAI,KACP,eAcF,CAAC;AAEF;;;;;;;;;;;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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,eAAO,MAAM,mBAAmB,GAAI,IAAI,SAAS,MAAM,EAAE,SAAS,IAAI,KAAG,WAAW,CAAC,IAAI,CA8BxF,CAAC"}
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"}
@@ -5,7 +5,8 @@
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
- * Consumers cast the return to their generated `ActionsApi` interface for full type safety.
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
  */
@@ -20,18 +21,35 @@ import { jsonrpc_error_messages } from '../http/jsonrpc_errors.js';
20
21
  * - `remote_notification` → send notification, return Result
21
22
  * - `local_call` → execute locally (sync or async), return Result or throw
22
23
  *
23
- * @param options - client options (peer, environment, optional action history)
24
- * @returns a Proxy that responds to any method name found in the environment's specs
24
+ * Generic `TApi` is the consumer's typed Proxy interface (typically a
25
+ * codegen-derived `ActionsApi`). Required no default, so forgetting it
26
+ * is a type error rather than a silent slide into `any`. The `as unknown
27
+ * as TApi` coercion lives inside this function so call sites get a typed
28
+ * return without a cast at the seam. `TApi` is a type-layer promise about
29
+ * what the Proxy responds to; the runtime walks `specs` (kept in sync by
30
+ * the consumer, codegen recommended).
31
+ *
32
+ * ```ts
33
+ * const api_result = create_rpc_client<MyActionsApi>({peer, environment});
34
+ * ```
35
+ *
36
+ * @param options - client options (peer, environment, optional callbacks)
37
+ * @returns a Proxy typed as `TApi` that responds to any method name found in the environment's specs
25
38
  */
26
39
  export const create_rpc_client = (options) => {
27
- const { peer, environment, actions, transport_for_method } = options;
40
+ const { peer, environment, on_action_event, transport_for_method } = options;
41
+ // Internal factories construct broadly-typed `ActionEvent` instances; the
42
+ // public callback narrows `event.spec.method` to `keyof TApi & string`.
43
+ // Cast once here — function parameters are contravariant, so the narrow
44
+ // callback isn't directly assignable to the broad slot the helpers take.
45
+ const broad_on_action_event = on_action_event;
28
46
  return new Proxy({}, {
29
47
  get(_target, method) {
30
48
  const spec = environment.lookup_action_spec(method);
31
49
  if (!spec) {
32
50
  return undefined;
33
51
  }
34
- return create_action_method(peer, environment, spec, actions, transport_for_method);
52
+ return create_action_method(peer, environment, spec, broad_on_action_event, transport_for_method);
35
53
  },
36
54
  has(_target, method) {
37
55
  return environment.lookup_action_spec(method) !== undefined;
@@ -41,30 +59,26 @@ export const create_rpc_client = (options) => {
41
59
  /**
42
60
  * Creates a method that executes an action through its complete lifecycle.
43
61
  */
44
- const create_action_method = (peer, environment, spec, actions, transport_for_method) => {
62
+ const create_action_method = (peer, environment, spec, on_action_event, transport_for_method) => {
45
63
  switch (spec.kind) {
46
64
  case 'local_call':
47
65
  return spec.async
48
- ? create_async_local_call_method(environment, spec, actions)
49
- : create_sync_local_call_method(environment, spec, actions);
66
+ ? create_async_local_call_method(environment, spec, on_action_event)
67
+ : create_sync_local_call_method(environment, spec, on_action_event);
50
68
  case 'request_response':
51
- return create_request_response_method(peer, environment, spec, actions, transport_for_method);
69
+ return create_request_response_method(peer, environment, spec, on_action_event, transport_for_method);
52
70
  case 'remote_notification':
53
- return create_remote_notification_method(peer, environment, spec, actions, transport_for_method);
71
+ return create_remote_notification_method(peer, environment, spec, on_action_event, transport_for_method);
54
72
  }
55
73
  };
56
74
  /**
57
75
  * Creates a synchronous local call method.
58
76
  * Returns value directly - can throw on error (sync methods cannot return Result).
59
77
  */
60
- const create_sync_local_call_method = (environment, spec, actions) => {
78
+ const create_sync_local_call_method = (environment, spec, on_action_event) => {
61
79
  return (input) => {
62
80
  const event = create_action_event(environment, spec, input);
63
- const action = actions?.add_from_json({
64
- method: spec.method,
65
- action_event_data: event.toJSON(),
66
- });
67
- action?.listen_to_action_event(event);
81
+ on_action_event?.(event);
68
82
  event.parse().handle_sync();
69
83
  const result = extract_action_result(event);
70
84
  if (result.ok) {
@@ -84,7 +98,7 @@ const create_sync_local_call_method = (environment, spec, actions) => {
84
98
  * `signal` can only short-circuit before the synchronous handler runs (no
85
99
  * cooperative interrupt mid-handler).
86
100
  */
87
- const create_async_local_call_method = (environment, spec, actions) => {
101
+ const create_async_local_call_method = (environment, spec, on_action_event) => {
88
102
  return async (input, options) => {
89
103
  if (options?.signal?.aborted) {
90
104
  return {
@@ -93,11 +107,7 @@ const create_async_local_call_method = (environment, spec, actions) => {
93
107
  };
94
108
  }
95
109
  const event = create_action_event(environment, spec, input);
96
- const action = actions?.add_from_json({
97
- method: spec.method,
98
- action_event_data: event.toJSON(),
99
- });
100
- action?.listen_to_action_event(event);
110
+ on_action_event?.(event);
101
111
  await event.parse().handle_async();
102
112
  return extract_action_result(event);
103
113
  };
@@ -105,14 +115,10 @@ const create_async_local_call_method = (environment, spec, actions) => {
105
115
  /**
106
116
  * Creates a request/response method that communicates over the network.
107
117
  */
108
- const create_request_response_method = (peer, environment, spec, actions, transport_for_method) => {
118
+ const create_request_response_method = (peer, environment, spec, on_action_event, transport_for_method) => {
109
119
  return async (input, options) => {
110
120
  const event = create_action_event(environment, spec, input);
111
- const action = actions?.add_from_json({
112
- method: spec.method,
113
- action_event_data: event.toJSON(),
114
- });
115
- action?.listen_to_action_event(event);
121
+ on_action_event?.(event);
116
122
  await event.parse().handle_async();
117
123
  // Check if we're in send_error phase before type narrowing
118
124
  if (event.data.kind === 'request_response' && event.data.phase === 'send_error') {
@@ -141,14 +147,10 @@ const create_request_response_method = (peer, environment, spec, actions, transp
141
147
  * Creates a remote notification method (fire and forget).
142
148
  * Returns Result<{value: void}> for consistency.
143
149
  */
144
- const create_remote_notification_method = (peer, environment, spec, actions, transport_for_method) => {
150
+ const create_remote_notification_method = (peer, environment, spec, on_action_event, transport_for_method) => {
145
151
  return async (input, options) => {
146
152
  const event = create_action_event(environment, spec, input);
147
- const action = actions?.add_from_json({
148
- method: spec.method,
149
- action_event_data: event.toJSON(),
150
- });
151
- action?.listen_to_action_event(event);
153
+ on_action_event?.(event);
152
154
  await event.parse().handle_async();
153
155
  if (!is_notification_send(event.data))
154
156
  throw Error(); // TODO @many maybe make this an assertion helper?
@@ -168,60 +170,6 @@ const create_remote_notification_method = (peer, environment, spec, actions, tra
168
170
  return extract_action_result(event);
169
171
  };
170
172
  };
171
- /**
172
- * Wrap a typed RPC client so every call returns its unwrapped value or throws.
173
- *
174
- * On `{ok: false}`, throws an `Error` whose `message` comes from the
175
- * JSON-RPC error object, plus `{code, data}` as own properties — so
176
- * catch blocks reading `err.message` / `err.code` / `err.data?.reason`
177
- * all work. On unknown method, throws a clear "rpc method not found"
178
- * error instead of the cryptic `undefined is not a function` that
179
- * would otherwise surface.
180
- *
181
- * Invariant upheld by `create_rpc_client`: every `{ok: false}` return
182
- * carries a well-formed `JsonrpcErrorObject` with `code` + `message`.
183
- * Callers must still use optional chaining on `err.data` because the
184
- * JSON-RPC `data` field is spec-level optional — a handler that throws
185
- * `jsonrpc_errors.forbidden()` without a `data` argument produces
186
- * `err.data === undefined`.
187
- *
188
- * Only `{code, data}` cross onto the thrown Error — `message` flows
189
- * through the `Error` constructor argument, and `name` / `stack` are
190
- * left as the Error's own so attacker-shaped `result.error` payloads
191
- * cannot overwrite them.
192
- *
193
- * The mapped-type generic constraint accepts both shapes without a cast:
194
- * a codegen-derived typed `ActionsApi` (named-method interface, e.g.
195
- * `{account_verify: (input) => Promise<Result<...>>, ...}`) and a loose
196
- * `Record<string, (input?: any) => Promise<any> | void>`. Using `keyof TApi`
197
- * in the constraint avoids the index-signature requirement that would
198
- * otherwise force consumers to `as unknown as Record<string, …>` their
199
- * generated client. The `| void` arm tolerates `remote_notification`
200
- * methods, whose `ActionsApi` signature is `(input) => void` even though
201
- * `create_remote_notification_method` returns a Promise at runtime — the
202
- * throwing wrapper is intended for `request_response` calls but must
203
- * accept mixed `ActionsApi` shapes without forcing a cast at the seam.
204
- *
205
- * @param api - typed RPC client from `create_rpc_client` (or any object
206
- * whose values are all `(input?) => Promise<...> | void` functions —
207
- * notably the consumer's generated `ActionsApi` interface)
208
- */
209
- export const create_throwing_rpc_call = (api) => {
210
- const rec = api;
211
- return async (method, input) => {
212
- const fn = rec[method];
213
- if (!fn)
214
- throw new Error(`rpc method not found: ${method}`);
215
- const result = await fn(input);
216
- if (!result.ok) {
217
- throw Object.assign(new Error(result.error?.message ?? 'rpc error'), {
218
- code: result.error?.code,
219
- data: result.error?.data,
220
- });
221
- }
222
- return result.value;
223
- };
224
- };
225
173
  /**
226
174
  * Wrap a typed RPC client so every call resolves to its unwrapped value or
227
175
  * throws an `Error` carrying the JSON-RPC `{code, message, data?}` shape.
@@ -239,33 +187,30 @@ export const create_throwing_rpc_call = (api) => {
239
187
  *
240
188
  * Only `{code, data}` cross onto the thrown Error — `name` / `stack` are
241
189
  * left as the Error's own properties so attacker-shaped `result.error`
242
- * payloads cannot overwrite them. Same hardening as
243
- * `create_throwing_rpc_call`.
244
- *
245
- * Composable with `create_throwing_rpc_call` — same typed underlying
246
- * client feeds both: the Proxy form for direct call sites, the loose
247
- * method-keyed form for adapter wiring (`ui/admin_rpc_adapters.ts`).
190
+ * payloads cannot overwrite them.
248
191
  *
249
- * Recommended consumer convention: bind the throwing wrapper to `api`
250
- * (the common case at call sites) and the underlying Result-returning
251
- * Proxy to `api_raw` (the composable escape hatch for callers that
252
- * want to inspect `error.data.reason` without try/catch).
192
+ * Recommended consumer convention: `create_frontend_rpc_client` ships
193
+ * both shapes by default `api` (throwing) for hot-path call sites and
194
+ * `api_result` (Result) for sites that inspect `error.data.reason`
195
+ * without try/catch. Result is the protocol primitive; this wrapper is
196
+ * the ergonomic layer over it. Picking is per call site — both Proxies
197
+ * share the same underlying transport.
253
198
  *
254
199
  * Catch blocks read `err.data?.reason` — optional chaining required
255
200
  * because JSON-RPC `data` is spec-level optional.
256
201
  *
257
202
  * On unknown string-keyed methods, the get trap returns a function that
258
- * throws `"rpc method not found: <prop>"` on invocation — symmetric with
259
- * `create_throwing_rpc_call` and clearer than the JS default
260
- * `"api.foo is not a function"`. Symbol props and `then` stay
261
- * undefined so the Proxy isn't accidentally treated as a thenable
203
+ * throws `"rpc method not found: <prop>"` on invocation — clearer than
204
+ * the JS default `"api.foo is not a function"`. Symbol props and `then`
205
+ * stay undefined so the Proxy isn't accidentally treated as a thenable
262
206
  * (`await api` would otherwise probe `then` and trip the thrower).
263
207
  *
264
- * @param api_raw - typed RPC client from `create_rpc_client`, cast
265
- * to a consumer-generated `ActionsApi` interface
208
+ * @param api_result - typed Result-returning RPC client from
209
+ * `create_rpc_client<ActionsApi>(...)`. The "_result" suffix names
210
+ * what the underlying calls return (`Result<{value}, {error}>`).
266
211
  */
267
- export const create_throwing_api = (api_raw) => {
268
- return new Proxy(api_raw, {
212
+ export const create_throwing_api = (api_result) => {
213
+ return new Proxy(api_result, {
269
214
  get(target, prop) {
270
215
  const fn = target[prop];
271
216
  if (typeof fn === 'function') {
@@ -267,7 +267,7 @@ export declare const keeper_identity: () => WsConnectIdentity;
267
267
  * await client.wait_for(is_notification('tx_run_created'));
268
268
  * ```
269
269
  */
270
- export declare const build_broadcast_api: <TApi>(options: {
270
+ export declare const build_broadcast_api: <TApi extends object>(options: {
271
271
  harness: WsTestHarness;
272
272
  specs: ReadonlyArray<ActionSpecUnion>;
273
273
  }) => TApi;
@@ -1 +1 @@
1
- {"version":3,"file":"ws_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/ws_round_trip.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ws_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/ws_round_trip.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,KAAK,EAAC,OAAO,EAAO,MAAM,MAAM,CAAC;AACxC,OAAO,EACN,SAAS,EAET,KAAK,gBAAgB,EAErB,KAAK,QAAQ,EACb,MAAM,SAAS,CAAC;AACjB,OAAO,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAC/C,OAAO,EAAc,KAAK,IAAI,EAAC,MAAM,wBAAwB,CAAC;AAE9D,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,4BAA4B,CAAC;AAEvD,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,kCAAkC,CAAC;AAE7E,OAAO,EAEN,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAC,yBAAyB,EAAC,MAAM,qCAAqC,CAAC;AAC9E,OAAO,EAAsB,KAAK,cAAc,EAAC,MAAM,4BAA4B,CAAC;AAEpF,OAAO,EAA6C,KAAK,cAAc,EAAC,MAAM,oBAAoB,CAAC;AACnG,OAAO,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAC;AAanD;;;GAGG;AACH,MAAM,WAAW,MAAM;IACtB,EAAE,EAAE,SAAS,CAAC;IACd,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACrB,MAAM,EAAE,KAAK,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;CAChD;AAED;;;;GAIG;AACH,eAAO,MAAM,cAAc,QAAO,MAajC,CAAC;AAEF,8CAA8C;AAC9C,MAAM,WAAW,sBAAsB;IACtC,eAAe,EAAE,cAAc,CAAC;IAChC,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B;;;OAGG;IACH,eAAe,CAAC,EAAE,cAAc,CAAC;CACjC;AAED;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GAAI,MAAM,sBAAsB,KAAG,OAWvE,CAAC;AAEF,uFAAuF;AACvF,MAAM,WAAW,WAAW;IAC3B,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,iBAAiB,EAAE,MAAM,CAAC,CAAC,EAAE,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACtE;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,QAAO,WAatC,CAAC;AAEF;;;;GAIG;AACH,qBAAa,wBAAyB,YAAW,sBAAsB;;IACtE,QAAQ,EAAE,UAAU,GAAG,SAAS,CAAa;gBAEjC,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC;IAGjD,qBAAqB,IAAI,SAAS;IAGlC,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;CAG/D;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAC/B,YAAY,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,EAC9C,OAAO,YAAY,EACnB,IAAI,SAAS,KACX,OAAO,CAAC,IAAI,CAId,CAAC;AAMF,2CAA2C;AAC3C,MAAM,WAAW,iBAAiB;IACjC,wEAAwE;IACxE,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,yFAAyF;IACzF,eAAe,CAAC,EAAE,cAAc,CAAC;IACjC,mFAAmF;IACnF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,kFAAkF;IAClF,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACtB;AAED,wEAAwE;AACxE,MAAM,WAAW,YAAY;IAC5B,uEAAuE;IACvE,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C;;;;;;;;OAQG;IACH,OAAO,EAAE,CAAC,CAAC,GAAG,OAAO,EACpB,EAAE,EAAE,MAAM,GAAG,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,EACf,UAAU,CAAC,EAAE,MAAM,KACf,OAAO,CAAC,CAAC,CAAC,CAAC;IAChB;;;;OAIG;IACH,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAC1C;;;;;;;;OAQG;IACH,QAAQ,EAAE;QACT,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,GAAG,IAAI,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAE5E,CAAC,CAAC,GAAG,OAAO,EAAE,SAAS,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;KACrF,CAAC;CACF;AAkBD,MAAM,WAAW,wBAAwB,CAAC,CAAC,GAAG,OAAO;IACpD,OAAO,EAAE,OAAO,eAAe,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,CAAC,CAAC;CACV;AAED,MAAM,WAAW,2BAA2B,CAAC,CAAC,GAAG,OAAO;IACvD,OAAO,EAAE,OAAO,eAAe,CAAC;IAChC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,MAAM,EAAE,CAAC,CAAC;CACV;AAED,MAAM,WAAW,yBAAyB,CAAC,CAAC,GAAG,OAAO;IACrD,OAAO,EAAE,OAAO,eAAe,CAAC;IAChC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,KAAK,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,CAAA;KAAC,CAAC;CACjD;AAED,6EAA6E;AAC7E,eAAO,MAAM,eAAe,GAC1B,QAAQ,MAAM,MACd,KAAK,OAAO,KAAG,OACsC,CAAC;AAExD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,oBAAoB,GAC/B,CAAC,EAAE,QAAQ,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,MAChD,KAAK,OAAO,KAAG,GAAG,IAAI,wBAAwB,CAAC,CAAC,CAGE,CAAC;AAErD,gGAAgG;AAChG,eAAO,MAAM,eAAe,GAC1B,IAAI,MAAM,GAAG,MAAM,MACnB,KAAK,OAAO,KAAG,OAC8D,CAAC;AAEhF,4CAA4C;AAC5C,MAAM,WAAW,0BAA0B,CAAC,IAAI,SAAS,kBAAkB;IAC1E;;;;;OAKG;IACH,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IACrC,cAAc,CAAC,EAAE,uBAAuB,CAAC,IAAI,CAAC,CAAC,gBAAgB,CAAC,CAAC;IACjE,kEAAkE;IAClE,SAAS,CAAC,EAAE,yBAAyB,CAAC;IACtC;;;;OAIG;IACH,SAAS,CAAC,EAAE,uBAAuB,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,CAAC;IACvD,gEAAgE;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,cAAc,CAAC,EAAE,uBAAuB,CAAC,IAAI,CAAC,CAAC,gBAAgB,CAAC,CAAC;IACjE,yDAAyD;IACzD,eAAe,CAAC,EAAE,uBAAuB,CAAC,IAAI,CAAC,CAAC,iBAAiB,CAAC,CAAC;CACnE;AAED,kEAAkE;AAClE,MAAM,WAAW,aAAa;IAC7B,SAAS,EAAE,yBAAyB,CAAC;IACrC;;;;;;OAMG;IACH,OAAO,EAAE,CAAC,QAAQ,CAAC,EAAE,iBAAiB,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;CACjE;AA8DD;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,GAAI,IAAI,SAAS,kBAAkB,EACrE,SAAS,0BAA0B,CAAC,IAAI,CAAC,KACvC,aA6KF,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,eAAe,QAAO,iBAGjC,CAAC;AAYH;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,mBAAmB,GAAI,IAAI,SAAS,MAAM,EAAE,SAAS;IACjE,OAAO,EAAE,aAAa,CAAC;IACvB,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;CACtC,KAAG,IAIH,CAAC"}
package/dist/ui/CLAUDE.md CHANGED
@@ -267,17 +267,16 @@ destructive actions.
267
267
  (`get`, `update`). Fields: `settings`, `updating`. Single mutation
268
268
  `update_open_signup(boolean)`.
269
269
  - `admin_rpc_adapters.ts` (plain `.ts`, no reactive state) — bundled
270
- wiring for the four admin RPC contexts. `create_admin_rpc_adapters(rpc_call)`
271
- takes a single `AdminRpcCall` closure (alias of `ThrowingRpcCall` from
272
- `../actions/rpc_client.ts`) and returns `{admin_accounts, admin_invites,
273
- audit_log, app_settings}` adapter objects. `provide_admin_rpc_contexts(adapters)`
274
- calls `set` on all four contexts in one shot. Pair with
275
- `create_throwing_rpc_call(api)` from `../actions/rpc_client.ts` to turn a
276
- typed `create_rpc_client` Proxy into the throw-on-error `rpc_call`
277
- signature two lines at the admin shell layout. Method-name mapping is
278
- in the module TSDoc (`grant_permit` → `permit_offer_create`,
279
- `retract_offer` `permit_offer_retract`, etc.) and the
280
- `admin_rpc_adapters.test.ts` fixtures.
270
+ wiring for the four admin RPC contexts. `create_admin_rpc_adapters(api)`
271
+ takes the typed throwing Proxy from `create_frontend_rpc_client` (or
272
+ any object satisfying the `AdminRpcApi` interface) and returns
273
+ `{admin_accounts, admin_invites, audit_log, app_settings}` adapter
274
+ objects. `provide_admin_rpc_contexts(adapters)` calls `set` on all
275
+ four contexts in one shot. One line at the admin shell layout:
276
+ `provide_admin_rpc_contexts(create_admin_rpc_adapters(api))`.
277
+ Method-name mapping is in the module TSDoc (`grant_permit`
278
+ `permit_offer_create`, `retract_offer` → `permit_offer_retract`, etc.)
279
+ and the `admin_rpc_adapters.test.ts` fixtures.
281
280
 
282
281
  ## RPC adapter contexts
283
282
 
@@ -4,10 +4,13 @@
4
4
  * @module
5
5
  */
6
6
  import { SvelteSet } from 'svelte/reactivity';
7
+ import type { Uuid } from '@fuzdev/fuz_util/id.js';
7
8
  import { Loadable } from './loadable.svelte.js';
8
9
  import type { AdminAccountEntryJson } from '../auth/account_schema.js';
9
- import type { AdminSessionJson } from '../auth/audit_log_schema.js';
10
+ import type { RoleName } from '../auth/role_schema.js';
10
11
  import type { PermitOfferJson } from '../auth/permit_offer_schema.js';
12
+ import type { AdminAccountListOutput, AdminSessionListOutput, AdminSessionRevokeAllInput, AdminSessionRevokeAllOutput, AdminTokenRevokeAllInput, AdminTokenRevokeAllOutput } from '../auth/admin_action_specs.js';
13
+ import type { PermitOfferCreateInput, PermitOfferCreateOutput, PermitOfferOkOutput, PermitRevokeInput, PermitRevokeOutput } from '../auth/permit_offer_action_specs.js';
11
14
  /**
12
15
  * Narrow RPC surface consumed by `AdminAccountsState`. Consumers adapt their
13
16
  * typed RPC client (e.g. a `create_rpc_client` Proxy) to this shape — the
@@ -21,44 +24,20 @@ import type { PermitOfferJson } from '../auth/permit_offer_schema.js';
21
24
  * `admin_session_revoke_all` and `admin_token_revoke_all`. Without the
22
25
  * adapter the state class cannot fetch, grant, revoke, retract, or
23
26
  * revoke-all sessions/tokens.
27
+ *
28
+ * Method signatures track the underlying action specs — `Uuid`-branded ids
29
+ * propagate from the wire through the state class to the components. The
30
+ * adapter built by `create_admin_rpc_adapters` therefore needs zero casts
31
+ * to bridge to the typed throwing Proxy.
24
32
  */
25
33
  export interface AdminAccountsRpc {
26
- list_accounts: () => Promise<{
27
- accounts: Array<AdminAccountEntryJson>;
28
- grantable_roles: Array<string>;
29
- }>;
30
- list_sessions: () => Promise<{
31
- sessions: Array<AdminSessionJson>;
32
- }>;
33
- grant_permit: (params: {
34
- to_account_id: string;
35
- role: string;
36
- }) => Promise<{
37
- offer: PermitOfferJson;
38
- }>;
39
- revoke_permit: (params: {
40
- actor_id: string;
41
- permit_id: string;
42
- reason?: string | null;
43
- }) => Promise<{
44
- ok: true;
45
- revoked: true;
46
- }>;
47
- retract_offer: (offer_id: string) => Promise<{
48
- ok: true;
49
- }>;
50
- session_revoke_all: (params: {
51
- account_id: string;
52
- }) => Promise<{
53
- ok: true;
54
- count: number;
55
- }>;
56
- token_revoke_all: (params: {
57
- account_id: string;
58
- }) => Promise<{
59
- ok: true;
60
- count: number;
61
- }>;
34
+ list_accounts: () => Promise<AdminAccountListOutput>;
35
+ list_sessions: () => Promise<AdminSessionListOutput>;
36
+ grant_permit: (params: PermitOfferCreateInput) => Promise<PermitOfferCreateOutput>;
37
+ revoke_permit: (params: PermitRevokeInput) => Promise<PermitRevokeOutput>;
38
+ retract_offer: (offer_id: Uuid) => Promise<PermitOfferOkOutput>;
39
+ session_revoke_all: (params: AdminSessionRevokeAllInput) => Promise<AdminSessionRevokeAllOutput>;
40
+ token_revoke_all: (params: AdminTokenRevokeAllInput) => Promise<AdminTokenRevokeAllOutput>;
62
41
  }
63
42
  /**
64
43
  * Svelte context carrying the reactive `AdminAccountsRpc` accessor. The
@@ -86,7 +65,7 @@ export interface AdminAccountsStateOptions {
86
65
  export declare class AdminAccountsState extends Loadable {
87
66
  #private;
88
67
  accounts: Array<AdminAccountEntryJson>;
89
- grantable_roles: Array<string>;
68
+ grantable_roles: Array<RoleName>;
90
69
  readonly granting_keys: SvelteSet<string>;
91
70
  readonly revoking_ids: SvelteSet<string>;
92
71
  readonly retracting_ids: SvelteSet<string>;
@@ -111,7 +90,7 @@ export declare class AdminAccountsState extends Loadable {
111
90
  * No-op when the rpc adapter is absent; `error` is set to a descriptive
112
91
  * message so the UI surfaces the misconfiguration.
113
92
  */
114
- grant_permit(account_id: string, role: string): Promise<PermitOfferJson | undefined>;
93
+ grant_permit(account_id: Uuid, role: RoleName): Promise<PermitOfferJson | undefined>;
115
94
  /**
116
95
  * Revoke an active permit via the `permit_revoke` RPC.
117
96
  *
@@ -121,7 +100,7 @@ export declare class AdminAccountsState extends Loadable {
121
100
  * The optional `reason` is stamped on `permit.revoked_reason` and
122
101
  * surfaced on the revokee's WS notification.
123
102
  */
124
- revoke_permit(actor_id: string, permit_id: string, reason?: string | null): Promise<void>;
103
+ revoke_permit(actor_id: Uuid, permit_id: Uuid, reason?: string | null): Promise<void>;
125
104
  /**
126
105
  * Retract a pending offer the admin issued via the `permit_offer_retract`
127
106
  * RPC. The action handles auth, audit, and the
@@ -130,6 +109,6 @@ export declare class AdminAccountsState extends Loadable {
130
109
  * After success, refetches the listing so `pending_offers` drops the
131
110
  * row and the "+ {role}" button un-hides.
132
111
  */
133
- retract_offer(offer_id: string): Promise<void>;
112
+ retract_offer(offer_id: Uuid): Promise<void>;
134
113
  }
135
114
  //# sourceMappingURL=admin_accounts_state.svelte.d.ts.map