@fuzdev/fuz_app 0.106.1 → 0.107.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 (64) hide show
  1. package/dist/actions/CLAUDE.md +42 -23
  2. package/dist/actions/action_bridge.d.ts +34 -3
  3. package/dist/actions/action_bridge.d.ts.map +1 -1
  4. package/dist/actions/action_bridge.js +32 -1
  5. package/dist/actions/action_rpc.d.ts +5 -4
  6. package/dist/actions/action_rpc.d.ts.map +1 -1
  7. package/dist/actions/action_rpc.js +4 -3
  8. package/dist/actions/action_spec.d.ts +8 -2
  9. package/dist/actions/action_spec.d.ts.map +1 -1
  10. package/dist/actions/action_spec.js +5 -2
  11. package/dist/actions/compile_action_registry.d.ts +26 -14
  12. package/dist/actions/compile_action_registry.d.ts.map +1 -1
  13. package/dist/actions/compile_action_registry.js +29 -14
  14. package/dist/actions/perform_action.d.ts +26 -16
  15. package/dist/actions/perform_action.d.ts.map +1 -1
  16. package/dist/actions/perform_action.js +69 -44
  17. package/dist/actions/register_action_ws.d.ts +4 -4
  18. package/dist/actions/register_action_ws.js +5 -5
  19. package/dist/actions/register_ws_endpoint.d.ts +13 -5
  20. package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
  21. package/dist/actions/register_ws_endpoint.js +15 -6
  22. package/dist/auth/CLAUDE.md +16 -9
  23. package/dist/auth/audit_log_route_schema.d.ts.map +1 -1
  24. package/dist/auth/audit_log_route_schema.js +11 -1
  25. package/dist/auth/audit_log_routes.d.ts.map +1 -1
  26. package/dist/auth/audit_log_routes.js +4 -9
  27. package/dist/auth/auth_guard_resolver.d.ts +48 -21
  28. package/dist/auth/auth_guard_resolver.d.ts.map +1 -1
  29. package/dist/auth/auth_guard_resolver.js +60 -26
  30. package/dist/auth/bearer_auth.d.ts +1 -1
  31. package/dist/auth/bearer_auth.js +1 -1
  32. package/dist/auth/middleware.js +1 -1
  33. package/dist/auth/request_context.d.ts +54 -24
  34. package/dist/auth/request_context.d.ts.map +1 -1
  35. package/dist/auth/request_context.js +117 -39
  36. package/dist/auth/token_scope.d.ts +109 -21
  37. package/dist/auth/token_scope.d.ts.map +1 -1
  38. package/dist/auth/token_scope.js +106 -21
  39. package/dist/http/CLAUDE.md +23 -11
  40. package/dist/http/auth_shape.d.ts +58 -3
  41. package/dist/http/auth_shape.d.ts.map +1 -1
  42. package/dist/http/auth_shape.js +63 -5
  43. package/dist/http/error_schemas.d.ts +24 -1
  44. package/dist/http/error_schemas.d.ts.map +1 -1
  45. package/dist/http/error_schemas.js +36 -14
  46. package/dist/http/route_spec.d.ts +29 -26
  47. package/dist/http/route_spec.d.ts.map +1 -1
  48. package/dist/http/route_spec.js +12 -16
  49. package/dist/http/surface_query.d.ts +2 -2
  50. package/dist/http/surface_query.js +2 -2
  51. package/dist/server/serve_fact_route.d.ts.map +1 -1
  52. package/dist/server/serve_fact_route.js +12 -10
  53. package/dist/testing/CLAUDE.md +39 -3
  54. package/dist/testing/cross_backend/conformance_case.js +1 -1
  55. package/dist/testing/cross_backend/testing_backdoor.d.ts.map +1 -1
  56. package/dist/testing/cross_backend/testing_backdoor.js +6 -5
  57. package/dist/testing/cross_backend/token_scope_surface.d.ts +9 -0
  58. package/dist/testing/cross_backend/token_scope_surface.d.ts.map +1 -0
  59. package/dist/testing/cross_backend/token_scope_surface.js +170 -0
  60. package/dist/testing/integration.d.ts.map +1 -1
  61. package/dist/testing/integration.js +3 -2
  62. package/dist/testing/rpc_attack_surface.d.ts.map +1 -1
  63. package/dist/testing/rpc_attack_surface.js +4 -2
  64. package/package.json +1 -1
@@ -29,14 +29,16 @@ Canonical source of truth. Three concrete kinds discriminate on `kind`:
29
29
  - `remote_notification` — `auth: null`, `side_effects: true`, `output: z.ZodVoid`, `async: true`.
30
30
  - `local_call` — `auth: null`, `side_effects` arbitrary, `output` arbitrary, `async` boolean.
31
31
 
32
- `RouteAuth` is the flat record `{account, actor, roles?, credential_types?}`
33
- from `http/auth_shape.ts` — same shape governs `RouteSpec.auth` so the four
34
- axes drive one auth surface across REST and SAES. Cross-axis invariants:
35
- roles imply `actor: 'required'`; `account: 'none'` implies `actor: 'none'`
36
- (no accountless actors in v1); the unrestricted leaf
32
+ `RouteAuth` is the flat record
33
+ `{account, actor, roles?, credential_types?, required_scope?}` from
34
+ `http/auth_shape.ts` — same shape governs `RouteSpec.auth` so one auth
35
+ surface drives REST and SAES. Cross-axis invariants: roles imply
36
+ `actor: 'required'`; `account: 'none'` implies `actor: 'none'` (no
37
+ accountless actors in v1); the unrestricted leaf
37
38
  (`account: 'none', actor: 'none'`) cannot declare roles or credential
38
39
  gates. The biconditional `actor !== 'none' ⟺ input declares acting?: ActingActor`
39
40
  is enforced at registration time via `assert_route_auth_acting_biconditional`.
41
+ `required_scope` is the one axis actions cannot use — see §Registry compile.
40
42
 
41
43
  Optional fields:
42
44
 
@@ -73,14 +75,14 @@ non-`remote_notification` kind.
73
75
  ## Registry compile (`actions/compile_action_registry.ts`)
74
76
 
75
77
  `compile_action_registry` is the shared registration loop called by both
76
- `create_rpc_endpoint` and `register_action_ws`. Validates four
77
- registry-time invariants and returns the `Map<method, RpcAction>` the
78
- dispatchers use:
78
+ `create_rpc_endpoint` and `register_action_ws`. Validates these checks in
79
+ order and returns the `Map<method, RpcAction>` the dispatchers use:
79
80
 
80
- 1. **Auth-shape biconditional** — `actor !== 'none' ⟺ input declares acting?: ActingActor` (via `assert_route_auth_acting_biconditional`).
81
- 2. **Rate-limit account axis** — `rate_limit: 'account' | 'both'` requires `auth.account === 'required'`.
82
- 3. **JSON-RPC §4.2 wire validity** — `request_response` specs with a handler may not use `z.null()` for input (use `z.void()` for nullary).
83
- 4. **Unique method names** across the array.
81
+ - **Auth-shape biconditional** — `actor !== 'none' ⟺ input declares acting?: ActingActor` (via `assert_route_auth_acting_biconditional`).
82
+ - **No `auth.required_scope`** — the slot is route-spec-only; nothing mounts a guard from it on an action, so declaring it would be a control that silently does nothing. Narrowed tokens are gated per method by the scope check in `perform_action`, which derives the `rpc:<method>` capability from `spec.method` rather than trusting a hand-written one.
83
+ - **Rate-limit account axis** — `rate_limit: 'account' | 'both'` requires `auth.account === 'required'`.
84
+ - **JSON-RPC §4.2 wire validity** — `request_response` specs with a handler may not use `z.null()` for input (use `z.void()` for nullary).
85
+ - **Unique method names** across the array.
84
86
 
85
87
  Only `request_response` specs with a handler reach the dispatch map;
86
88
  `remote_notification` / handler-less specs (e.g. WS `cancel`) stay
@@ -174,7 +176,25 @@ and `FrontendActionHandlers`.
174
176
  Derives transport-specific specs from action specs. HTTP-specific concerns
175
177
  (path, handler, errors) come from options, not the action spec.
176
178
 
177
- - `create_action_route_spec(spec, options)` — one action → one `RouteSpec`. HTTP method defaults by `side_effects` (`true` → POST, `false` → GET; override via `options.http_method`). `route.auth` is `spec.auth` verbatim. `transaction: spec.side_effects`. Throws if `spec.auth` is null.
179
+ - `create_action_route_spec(spec, options)` — one action → one `RouteSpec`. HTTP method defaults by `side_effects` (`true` → POST, `false` → GET; override via `options.http_method`). `route.auth` is `spec.auth` plus a derived `required_scope`. `transaction: spec.side_effects`. Throws if `spec.auth` is null.
180
+
181
+ **The bridge carries the token-scope gate across.** A bridged route runs
182
+ `options.handler` through the REST pipeline and never reaches
183
+ `perform_action`, so the dispatcher's per-method scope check cannot fire on it
184
+ — leaving a bearer-reachable surface a **narrowed** token walks through, which
185
+ is what the RPC-only rule exists to prevent. So the derived spec declares
186
+ `auth.required_scope: 'rpc:<method>'` and `fuz_auth_guard_resolver` mounts the
187
+ refusal ahead of the role gate. Per-method rather than a blanket refusal
188
+ because a bridged route _has_ a method identity, which the non-RPC surfaces
189
+ the RPC-only rule covers do not.
190
+
191
+ Bridge something with no request/response shape — an SSE stream, a file
192
+ download — and the whole-surface rule applies instead: pass `options.auth` with
193
+ `required_scope: 'surface:<name>'`, naming your own surface (the vocabulary is
194
+ open on the identifier). An `options.auth` that omits `required_scope` still
195
+ gets the derived one; public actions get none (the guard would enforce
196
+ nothing). fuz_app mounts no bridged routes itself; this is consumer-facing.
197
+
178
198
  - `create_action_event_spec(spec, {channel?})` — one notification action → one `EventSpec` for SSE surface + `create_validated_broadcaster`. Throws on non-`remote_notification` kind.
179
199
  - `derive_http_method(side_effects)` — exported for custom bridges.
180
200
 
@@ -190,11 +210,10 @@ The HTTP RPC dispatcher is a thin shim around `perform_action`
190
210
  parsing, GET vs POST split, `c.json` binding); the
191
211
  auth/validation/dispatch pipeline is shared with the WebSocket dispatcher.
192
212
 
193
- **Phase order: 401 → 400 → 403 → handler.** Validate first, authorize
194
- after. Trade-off: an unauthorized caller sees the validation step. The
195
- alternative ordering (403-before-400) was rejected because
196
- defense-in-depth via attack-surface obscurity is illusory when the surface
197
- is published in `library.json` codegen anyway.
213
+ **Phase order: 401 → authz → 403 → 400 → handler.** Authorize first,
214
+ validate after — a caller the authority gates refuse never learns the
215
+ action's input shape, and the coarse authority facts settle before the fine
216
+ ones. Matches the Rust spine, which validates handler-side.
198
217
 
199
218
  Shim responsibilities (per-request):
200
219
 
@@ -267,12 +286,12 @@ The transport-agnostic post-parse pipeline. Each transport assembles a
267
286
  `perform_action(input, deps)`, and binds the discriminated
268
287
  `PerformActionResult` to its wire shape.
269
288
 
270
- Pipeline (401 → 400 → 403 → handler):
289
+ Pipeline (401 → authz → 403 → 400 → handler):
271
290
 
272
- 1. Pre-validation auth (401)
273
- 2. Validate params (400) — `spec.input.safeParse` with `z.void()` / `?? {}` rules
274
- 3. Authorization phase — `apply_authorization_phase` against `account_id` + `validated_input.acting`. Test escape hatch via `preset.request_context`
275
- 4. Post-authorization auth (403) — credential-type gate first, role gate second
291
+ 1. Pre-authorization auth (401)
292
+ 2. Authorization phase — `apply_authorization_phase` against `account_id` + `read_acting(auth, raw_params)`, which takes the selector off the raw params (malformed reads as omitted) since validation now runs later. Test escape hatch via `preset.request_context`
293
+ 3. Post-authorization auth (403) — credential-type gate, then token scope, then role
294
+ 4. Validate params (400) — `spec.input.safeParse` with `z.void()` / `?? {}` rules
276
295
  5. Rate limit (429) — throttle-requests semantics
277
296
  6. Dispatch + DEV output validation + error normalization — `spec.side_effects` picks transaction vs pool. `ThrownJsonrpcError` preserves code + data; generic throws become `internal_error`
278
297
 
@@ -10,7 +10,7 @@
10
10
  import type { z } from 'zod';
11
11
  import type { ActionSpec, ActionSideEffects } from './action_spec.js';
12
12
  import type { RouteSpec, RouteMethod, RouteHandler } from '../http/route_spec.js';
13
- import type { RouteAuth } from '../http/auth_shape.js';
13
+ import { type RouteAuth } from '../http/auth_shape.js';
14
14
  import type { EventSpec } from '../realtime/sse.js';
15
15
  import type { RouteErrorSchemas } from '../http/error_schemas.js';
16
16
  /** Options for deriving a `RouteSpec` from an `ActionSpec`. */
@@ -25,8 +25,17 @@ export interface ActionRouteOptions {
25
25
  http_method?: RouteMethod;
26
26
  /**
27
27
  * Override the route's auth shape — defaults to the action spec's `auth`
28
- * (the canonical four-axis shape from `http/auth_shape.ts` is shared
29
- * verbatim between action specs and route specs, so no mapping is needed).
28
+ * (the canonical shape from `http/auth_shape.ts` is shared verbatim between
29
+ * action specs and route specs, so no mapping is needed).
30
+ *
31
+ * The bridge fills in `required_scope` on whichever shape it ends up with,
32
+ * so an override still gets the token-scope gate; declare `required_scope`
33
+ * here to name a different capability (e.g. `surface:<name>` when the
34
+ * bridged route is a stream rather than a request/response call — see the
35
+ * token-scope note on `create_action_route_spec`).
36
+ *
37
+ * Overriding to *widen* (admitting a credential the action's own gate
38
+ * refused) makes this route the consumer's to audit, not the spine's.
30
39
  */
31
40
  auth?: RouteAuth;
32
41
  /** Handler-specific error schemas (HTTP status code → Zod schema). Transport-specific — not on ActionSpec. */
@@ -49,6 +58,28 @@ export declare const derive_http_method: (side_effects: ActionSideEffects) => Ro
49
58
  * on the options, not the action spec. Action specs define the contract;
50
59
  * transport concerns like HTTP error codes are added at the bridge layer.
51
60
  *
61
+ * **The bridge carries the token-scope gate across for you.** A bridged route
62
+ * runs `options.handler` through the REST pipeline and never reaches
63
+ * `perform_action`, so the dispatcher's per-method scope check cannot fire on
64
+ * it — which would leave a bearer-reachable route that a **narrowed** api token
65
+ * walks straight through. So the derived spec declares
66
+ * `auth.required_scope: 'rpc:<method>'`, and `fuz_auth_guard_resolver` mounts
67
+ * the same refusal ahead of the role gate. A token that lists the method
68
+ * reaches the bridged route; one that doesn't gets the 403 it would have gotten
69
+ * over RPC.
70
+ *
71
+ * Per-method rather than rule 3's blanket refusal because a bridged route
72
+ * *has* a method identity — which is exactly what the non-RPC surfaces rule 3
73
+ * covers (the db browser, a bare-hash read, a stream) do not, and why that rule
74
+ * is all-or-nothing there. **Bridge something with no request/response shape —
75
+ * an SSE stream, a file download — and rule 3's reasoning applies instead**:
76
+ * pass `options.auth` with `required_scope: 'surface:<name>'`, naming your own
77
+ * surface. See `docs/security.md` §Token scoping.
78
+ *
79
+ * Skipped for a public action (`account: 'none', actor: 'none'`), where the
80
+ * same holder reaches the route by dropping the credential, so the guard would
81
+ * enforce nothing — the shape `fuz_auth_guard_resolver` refuses outright.
82
+ *
52
83
  * @param spec - the action spec (must have non-null `auth`)
53
84
  * @param options - HTTP-specific options (path, handler, optional overrides)
54
85
  * @returns a `RouteSpec` ready for `apply_route_specs`
@@ -1 +1 @@
1
- {"version":3,"file":"action_bridge.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAElE,+DAA+D;AAC/D,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,YAAY,CAAC;IACtB,uGAAuG;IACvG,MAAM,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACrB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACpB,mFAAmF;IACnF,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;;OAIG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,8GAA8G;IAC9G,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC3B;AAED,gEAAgE;AAChE,MAAM,WAAW,kBAAkB;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wDAAwD;AACxD,eAAO,MAAM,kBAAkB,GAAI,cAAc,iBAAiB,KAAG,WAEpE,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,wBAAwB,GACpC,MAAM,UAAU,EAChB,SAAS,kBAAkB,KACzB,SAqBF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,GACpC,MAAM,UAAU,EAChB,UAAU,kBAAkB,KAC1B,SAcF,CAAC"}
1
+ {"version":3,"file":"action_bridge.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAEtE,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EAAkB,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAElE,+DAA+D;AAC/D,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,YAAY,CAAC;IACtB,uGAAuG;IACvG,MAAM,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACrB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACpB,mFAAmF;IACnF,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;;;;;;;;;;;OAaG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,8GAA8G;IAC9G,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC3B;AAED,gEAAgE;AAChE,MAAM,WAAW,kBAAkB;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wDAAwD;AACxD,eAAO,MAAM,kBAAkB,GAAI,cAAc,iBAAiB,KAAG,WAEpE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,wBAAwB,GACpC,MAAM,UAAU,EAChB,SAAS,kBAAkB,KACzB,SA4BF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,GACpC,MAAM,UAAU,EAChB,UAAU,kBAAkB,KAC1B,SAcF,CAAC"}
@@ -7,6 +7,8 @@
7
7
  *
8
8
  * @module
9
9
  */
10
+ import { token_scope_method_capability } from '../auth/token_scope.js';
11
+ import { is_public_auth } from '../http/auth_shape.js';
10
12
  /** Derive the default HTTP method from side effects. */
11
13
  export const derive_http_method = (side_effects) => {
12
14
  return side_effects ? 'POST' : 'GET';
@@ -22,6 +24,28 @@ export const derive_http_method = (side_effects) => {
22
24
  * on the options, not the action spec. Action specs define the contract;
23
25
  * transport concerns like HTTP error codes are added at the bridge layer.
24
26
  *
27
+ * **The bridge carries the token-scope gate across for you.** A bridged route
28
+ * runs `options.handler` through the REST pipeline and never reaches
29
+ * `perform_action`, so the dispatcher's per-method scope check cannot fire on
30
+ * it — which would leave a bearer-reachable route that a **narrowed** api token
31
+ * walks straight through. So the derived spec declares
32
+ * `auth.required_scope: 'rpc:<method>'`, and `fuz_auth_guard_resolver` mounts
33
+ * the same refusal ahead of the role gate. A token that lists the method
34
+ * reaches the bridged route; one that doesn't gets the 403 it would have gotten
35
+ * over RPC.
36
+ *
37
+ * Per-method rather than rule 3's blanket refusal because a bridged route
38
+ * *has* a method identity — which is exactly what the non-RPC surfaces rule 3
39
+ * covers (the db browser, a bare-hash read, a stream) do not, and why that rule
40
+ * is all-or-nothing there. **Bridge something with no request/response shape —
41
+ * an SSE stream, a file download — and rule 3's reasoning applies instead**:
42
+ * pass `options.auth` with `required_scope: 'surface:<name>'`, naming your own
43
+ * surface. See `docs/security.md` §Token scoping.
44
+ *
45
+ * Skipped for a public action (`account: 'none', actor: 'none'`), where the
46
+ * same holder reaches the route by dropping the credential, so the guard would
47
+ * enforce nothing — the shape `fuz_auth_guard_resolver` refuses outright.
48
+ *
25
49
  * @param spec - the action spec (must have non-null `auth`)
26
50
  * @param options - HTTP-specific options (path, handler, optional overrides)
27
51
  * @returns a `RouteSpec` ready for `apply_route_specs`
@@ -32,10 +56,17 @@ export const create_action_route_spec = (spec, options) => {
32
56
  if (spec.auth === null) {
33
57
  throw new Error(`Cannot derive route spec from action '${spec.method}': auth is null (only request_response actions with non-null auth can become routes)`);
34
58
  }
59
+ const auth = options.auth ?? spec.auth;
60
+ // Carry the dispatcher's per-method scope gate across — see the token-scope
61
+ // note above. An explicit capability wins; a public route has no credential
62
+ // to narrow, and the resolver rejects the gate on that shape anyway.
63
+ const derives_scope_gate = auth.required_scope === undefined && !is_public_auth(auth);
35
64
  return {
36
65
  method: options.http_method ?? derive_http_method(spec.side_effects),
37
66
  path: options.path,
38
- auth: options.auth ?? spec.auth,
67
+ auth: derives_scope_gate
68
+ ? { ...auth, required_scope: token_scope_method_capability(spec.method) }
69
+ : auth,
39
70
  handler: options.handler,
40
71
  description: spec.description,
41
72
  ...(options.params ? { params: options.params } : {}),
@@ -122,7 +122,7 @@ export type ActionHandler<TInput = any, TOutput = any> = (input: TInput, ctx: Ac
122
122
  * `ActionContext` narrowed to a non-null `RequestContext`.
123
123
  *
124
124
  * Used by handlers whose spec declares `auth.account === 'required'`
125
- * (with `auth.actor === 'none'`) — the dispatcher's pre-validation 401
125
+ * (with `auth.actor === 'none'`) — the dispatcher's pre-authorization 401
126
126
  * gate guarantees `request_context` is populated before the handler
127
127
  * runs, but the actor slot stays null because no `acting` resolution
128
128
  * happened. Selected automatically by `rpc_action`'s conditional return
@@ -263,13 +263,14 @@ export interface CreateRpcEndpointOptions {
263
263
  * 1. **Parse envelope** — POST: JSON body as `JsonrpcRequest`. GET: `method`
264
264
  * and `params` from query string.
265
265
  * 2. **Lookup method** — find the `RpcAction` by method name.
266
- * 3. **Pre-validation auth** — short-circuit `unauthenticated` when no
267
- * account is on the request, before input validation runs.
266
+ * 3. **Pre-authorization auth** — short-circuit `unauthenticated` when no
267
+ * account is on the request, before any later phase runs.
268
268
  * 4. **Authorization phase** — resolve the acting actor (when the action's
269
269
  * auth requires role_grants or its input declares `acting?: ActingActor`)
270
270
  * and build the request context. Runs before input validation so
271
271
  * role-grant-grain auth checks return 403 before 400 invalid_params;
272
- * `acting` is read from raw params via a string typeguard.
272
+ * `acting` is read from raw params by `read_acting`, which parses it as
273
+ * a UUID and treats anything else as omitted.
273
274
  * 5. **Post-authorization auth** — enforce role / keeper requirements
274
275
  * against the request context.
275
276
  * 6. **Validate params** — parse input against the action's `input` schema.
@@ -1 +1 @@
1
- {"version":3,"file":"action_rpc.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_rpc.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"action_rpc.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_rpc.ts"],"names":[],"mappings":"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"}
@@ -92,13 +92,14 @@ const jsonrpc_error_envelope = (id, error) => ({
92
92
  * 1. **Parse envelope** — POST: JSON body as `JsonrpcRequest`. GET: `method`
93
93
  * and `params` from query string.
94
94
  * 2. **Lookup method** — find the `RpcAction` by method name.
95
- * 3. **Pre-validation auth** — short-circuit `unauthenticated` when no
96
- * account is on the request, before input validation runs.
95
+ * 3. **Pre-authorization auth** — short-circuit `unauthenticated` when no
96
+ * account is on the request, before any later phase runs.
97
97
  * 4. **Authorization phase** — resolve the acting actor (when the action's
98
98
  * auth requires role_grants or its input declares `acting?: ActingActor`)
99
99
  * and build the request context. Runs before input validation so
100
100
  * role-grant-grain auth checks return 403 before 400 invalid_params;
101
- * `acting` is read from raw params via a string typeguard.
101
+ * `acting` is read from raw params by `read_acting`, which parses it as
102
+ * a UUID and treats anything else as omitted.
102
103
  * 5. **Post-authorization auth** — enforce role / keeper requirements
103
104
  * against the request context.
104
105
  * 6. **Validate params** — parse input against the action's `input` schema.
@@ -38,13 +38,16 @@ export declare const ActionSpec: z.ZodObject<{
38
38
  backend: "backend";
39
39
  }>;
40
40
  /**
41
- * The four-axis auth shape (canonical schema in `http/auth_shape.ts`).
41
+ * The flat auth shape (canonical schema in `http/auth_shape.ts`).
42
42
  * `null` for `remote_notification` and `local_call` — those don't
43
43
  * dispatch through the request/response auth gate.
44
44
  *
45
45
  * See `http/auth_shape.ts` for the design rationale (orthogonal
46
46
  * authentication / account-resolution / actor-resolution / role-and-
47
- * credential authorization axes).
47
+ * credential authorization axes). `required_scope` is the one field an
48
+ * action may not set — `compile_action_registry` rejects it, since
49
+ * nothing on the RPC path mounts a guard from it; the dispatcher derives
50
+ * the same `rpc:<method>` capability from `spec.method` instead.
48
51
  */
49
52
  auth: z.ZodNullable<z.ZodObject<{
50
53
  account: z.ZodEnum<{
@@ -59,6 +62,7 @@ export declare const ActionSpec: z.ZodObject<{
59
62
  }>;
60
63
  roles: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
61
64
  credential_types: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
65
+ required_scope: z.ZodOptional<z.ZodString>;
62
66
  }, z.core.$strict>>;
63
67
  side_effects: z.ZodBoolean;
64
68
  input: z.ZodCustom<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
@@ -142,6 +146,7 @@ export declare const RequestResponseActionSpec: z.ZodObject<{
142
146
  }>;
143
147
  roles: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
144
148
  credential_types: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
149
+ required_scope: z.ZodOptional<z.ZodString>;
145
150
  }, z.core.$strict>;
146
151
  async: z.ZodDefault<z.ZodLiteral<true>>;
147
152
  }, z.core.$strict>;
@@ -228,6 +233,7 @@ export declare const ActionSpecUnion: z.ZodUnion<readonly [z.ZodObject<{
228
233
  }>;
229
234
  roles: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
230
235
  credential_types: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
236
+ required_scope: z.ZodOptional<z.ZodString>;
231
237
  }, z.core.$strict>;
232
238
  async: z.ZodDefault<z.ZodLiteral<true>>;
233
239
  }, z.core.$strict>, z.ZodObject<{
@@ -1 +1 @@
1
- {"version":3,"file":"action_spec.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_spec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,UAAU;;;;EAAoE,CAAC;AAC5F,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD,eAAO,MAAM,eAAe;;;;EAA0C,CAAC;AACvE,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAC7C,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAElE,eAAO,MAAM,UAAU;;;;;;;;;;;;IAItB;;;;;;;;OAQG;;;;;;;;;;;;;;;;;;;;IAOH;;;;;;OAMG;;IAEH;;;;;;;;OAQG;;IAEH;;;;;;;;;;;;;;;;;;;OAmBG;;;;;;kBAEF,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAIpC,CAAC;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAElF,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;kBAMvC,CAAC;AACH,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAExF;;;GAGG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;kBAG9B,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEtE,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBAI1B,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,gHAAgH;AAChH,eAAO,MAAM,cAAc,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,eAKoB,CAAC;AAE9E,eAAO,MAAM,gBAAgB;;;;;;;;;;EAU3B,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
1
+ {"version":3,"file":"action_spec.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_spec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,UAAU;;;;EAAoE,CAAC;AAC5F,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD,eAAO,MAAM,eAAe;;;;EAA0C,CAAC;AACvE,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAC7C,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAElE,eAAO,MAAM,UAAU;;;;;;;;;;;;IAItB;;;;;;;;;;;OAWG;;;;;;;;;;;;;;;;;;;;;IAOH;;;;;;OAMG;;IAEH;;;;;;;;OAQG;;IAEH;;;;;;;;;;;;;;;;;;;OAmBG;;;;;;kBAEF,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAIpC,CAAC;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAElF,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;kBAMvC,CAAC;AACH,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAExF;;;GAGG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;kBAG9B,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEtE,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBAI1B,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,gHAAgH;AAChH,eAAO,MAAM,cAAc,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,eAKoB,CAAC;AAE9E,eAAO,MAAM,gBAAgB;;;;;;;;;;EAU3B,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
@@ -21,13 +21,16 @@ export const ActionSpec = z.strictObject({
21
21
  kind: ActionKind,
22
22
  initiator: ActionInitiator,
23
23
  /**
24
- * The four-axis auth shape (canonical schema in `http/auth_shape.ts`).
24
+ * The flat auth shape (canonical schema in `http/auth_shape.ts`).
25
25
  * `null` for `remote_notification` and `local_call` — those don't
26
26
  * dispatch through the request/response auth gate.
27
27
  *
28
28
  * See `http/auth_shape.ts` for the design rationale (orthogonal
29
29
  * authentication / account-resolution / actor-resolution / role-and-
30
- * credential authorization axes).
30
+ * credential authorization axes). `required_scope` is the one field an
31
+ * action may not set — `compile_action_registry` rejects it, since
32
+ * nothing on the RPC path mounts a guard from it; the dispatcher derives
33
+ * the same `rpc:<method>` capability from `spec.method` instead.
31
34
  */
32
35
  auth: RouteAuth.nullable(),
33
36
  side_effects: ActionSideEffects,
@@ -3,21 +3,33 @@
3
3
  *
4
4
  * `create_rpc_endpoint` (HTTP RPC) and `register_action_ws` (WebSocket)
5
5
  * both build a `Map<method, RpcAction>` from a list of action specs and
6
- * gate the build on the same registry-time invariants:
6
+ * gate the build on the same checks, in this order (named rather than
7
+ * numbered — "registry-time invariant N" elsewhere in the codebase refers to
8
+ * the `RouteAuth` cross-axis set in `http/auth_shape.ts`, a different list):
7
9
  *
8
- * 1. **Auth-shape biconditional** — per `assert_route_auth_acting_biconditional`
9
- * in `http/auth_shape.ts`: `auth.actor !== 'none' ⟺ input declares
10
- * acting?: ActingActor`. Fires for every spec with non-null auth.
11
- * 2. **Rate-limit / account axis** — `rate_limit: 'account' | 'both'`
12
- * requires `auth.account === 'required'`; without an account on the
13
- * request there is no key for the per-account bucket.
14
- * 3. **JSON-RPC §4.2 wire validity** — `request_response` specs whose
15
- * handler will reach the dispatch map must not use `z.null()` for
16
- * input (the wire format forbids `"params": null`; use `z.void()`
17
- * for parameterless methods).
18
- * 4. **Duplicate method names** — JSON-RPC keys on `method`, so every
19
- * spec in the array must declare a unique `method` regardless of
20
- * kind / handler presence.
10
+ * - **Auth-shape biconditional** — per `assert_route_auth_acting_biconditional`
11
+ * in `http/auth_shape.ts`: `auth.actor !== 'none' ⟺ input declares
12
+ * acting?: ActingActor` (that set's invariant 2). Fires for every spec with
13
+ * non-null auth.
14
+ * - **No `auth.required_scope` on an action** — `ActionSpec.auth` is the same
15
+ * `RouteAuth` a route spec carries, so the field parses here, but only
16
+ * `apply_route_specs` mounts a guard from it and `perform_action` never
17
+ * reads it. Declaring it on an action would be a security control that
18
+ * silently does nothing, which is the exact shape token scoping was built
19
+ * to refuse. Rejected loudly instead; actions are governed by the
20
+ * per-method scope gate inside `perform_action`, which derives the same
21
+ * `rpc:<method>` capability from `spec.method` rather than trusting a
22
+ * hand-written one.
23
+ * - **Rate-limit / account axis** — `rate_limit: 'account' | 'both'`
24
+ * requires `auth.account === 'required'`; without an account on the
25
+ * request there is no key for the per-account bucket.
26
+ * - **JSON-RPC §4.2 wire validity** — `request_response` specs whose
27
+ * handler will reach the dispatch map must not use `z.null()` for
28
+ * input (the wire format forbids `"params": null`; use `z.void()`
29
+ * for parameterless methods).
30
+ * - **Duplicate method names** — JSON-RPC keys on `method`, so every
31
+ * spec in the array must declare a unique `method` regardless of
32
+ * kind / handler presence.
21
33
  *
22
34
  * Pre-consolidation each dispatcher inlined these checks; the comment
23
35
  * in `actions/register_action_ws.ts` literally said "mirrors the HTTP RPC
@@ -1 +1 @@
1
- {"version":3,"file":"compile_action_registry.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/compile_action_registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAIjD,oDAAoD;AACpD,MAAM,WAAW,2BAA2B;IAC3C;;;;;OAKG;IACH,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACnC;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,GACnC,SAAS,aAAa,CAAC,MAAM,CAAC,EAC9B,WAAW,MAAM,KACf,2BAwCF,CAAC"}
1
+ {"version":3,"file":"compile_action_registry.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/compile_action_registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAIjD,oDAAoD;AACpD,MAAM,WAAW,2BAA2B;IAC3C;;;;;OAKG;IACH,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACnC;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,GACnC,SAAS,aAAa,CAAC,MAAM,CAAC,EAC9B,WAAW,MAAM,KACf,2BA6CF,CAAC"}
@@ -3,21 +3,33 @@
3
3
  *
4
4
  * `create_rpc_endpoint` (HTTP RPC) and `register_action_ws` (WebSocket)
5
5
  * both build a `Map<method, RpcAction>` from a list of action specs and
6
- * gate the build on the same registry-time invariants:
6
+ * gate the build on the same checks, in this order (named rather than
7
+ * numbered — "registry-time invariant N" elsewhere in the codebase refers to
8
+ * the `RouteAuth` cross-axis set in `http/auth_shape.ts`, a different list):
7
9
  *
8
- * 1. **Auth-shape biconditional** — per `assert_route_auth_acting_biconditional`
9
- * in `http/auth_shape.ts`: `auth.actor !== 'none' ⟺ input declares
10
- * acting?: ActingActor`. Fires for every spec with non-null auth.
11
- * 2. **Rate-limit / account axis** — `rate_limit: 'account' | 'both'`
12
- * requires `auth.account === 'required'`; without an account on the
13
- * request there is no key for the per-account bucket.
14
- * 3. **JSON-RPC §4.2 wire validity** — `request_response` specs whose
15
- * handler will reach the dispatch map must not use `z.null()` for
16
- * input (the wire format forbids `"params": null`; use `z.void()`
17
- * for parameterless methods).
18
- * 4. **Duplicate method names** — JSON-RPC keys on `method`, so every
19
- * spec in the array must declare a unique `method` regardless of
20
- * kind / handler presence.
10
+ * - **Auth-shape biconditional** — per `assert_route_auth_acting_biconditional`
11
+ * in `http/auth_shape.ts`: `auth.actor !== 'none' ⟺ input declares
12
+ * acting?: ActingActor` (that set's invariant 2). Fires for every spec with
13
+ * non-null auth.
14
+ * - **No `auth.required_scope` on an action** — `ActionSpec.auth` is the same
15
+ * `RouteAuth` a route spec carries, so the field parses here, but only
16
+ * `apply_route_specs` mounts a guard from it and `perform_action` never
17
+ * reads it. Declaring it on an action would be a security control that
18
+ * silently does nothing, which is the exact shape token scoping was built
19
+ * to refuse. Rejected loudly instead; actions are governed by the
20
+ * per-method scope gate inside `perform_action`, which derives the same
21
+ * `rpc:<method>` capability from `spec.method` rather than trusting a
22
+ * hand-written one.
23
+ * - **Rate-limit / account axis** — `rate_limit: 'account' | 'both'`
24
+ * requires `auth.account === 'required'`; without an account on the
25
+ * request there is no key for the per-account bucket.
26
+ * - **JSON-RPC §4.2 wire validity** — `request_response` specs whose
27
+ * handler will reach the dispatch map must not use `z.null()` for
28
+ * input (the wire format forbids `"params": null`; use `z.void()`
29
+ * for parameterless methods).
30
+ * - **Duplicate method names** — JSON-RPC keys on `method`, so every
31
+ * spec in the array must declare a unique `method` regardless of
32
+ * kind / handler presence.
21
33
  *
22
34
  * Pre-consolidation each dispatcher inlined these checks; the comment
23
35
  * in `actions/register_action_ws.ts` literally said "mirrors the HTTP RPC
@@ -50,6 +62,9 @@ export const compile_action_registry = (actions, ctx_label) => {
50
62
  // per the spec union means `kind === 'request_response'`).
51
63
  if (spec.auth !== null) {
52
64
  assert_route_auth_acting_biconditional(spec.auth, { input: spec.input }, ctx);
65
+ if (spec.auth.required_scope !== undefined) {
66
+ throw new Error(`${ctx} declares auth.required_scope: '${spec.auth.required_scope}' — that slot is for route specs only. Actions dispatch through the RPC endpoint, where a narrowed token is gated per method by the scope check in perform_action, which derives the capability from the method name. Remove the field.`);
67
+ }
53
68
  if ((spec.rate_limit === 'account' || spec.rate_limit === 'both') &&
54
69
  spec.auth.account !== 'required') {
55
70
  throw new Error(`${ctx} declares rate_limit: '${spec.rate_limit}' but auth.account !== 'required' — no account guaranteed for account-keyed limiting. Use 'ip' or set auth.account: 'required'.`);
@@ -5,22 +5,32 @@
5
5
  * `perform_action` runs the post-parse pipeline that every action-spec
6
6
  * handler must traverse:
7
7
  *
8
- * 1. **Pre-validation auth (401)** — short-circuits unauthenticated callers
9
- * on `'required'` axes before input validation runs, so callers never
10
- * see `invalid_params` for methods with required input.
11
- * 2. **Validate params (400)** — `spec.input.safeParse(raw_params)` with
12
- * `z.void()` / `?? {}` rules. The validated input lands inside the
13
- * function so the authorization phase reads `acting` as a typed Zod
14
- * field.
15
- * 3. **Authorization phase** — when `auth.actor !== 'none'` (or
8
+ * 1. **Pre-authorization auth (401)** — short-circuits unauthenticated callers
9
+ * on `'required'` axes.
10
+ * 2. **Authorization phase** — when `auth.actor !== 'none'` (or
16
11
  * `auth.account !== 'none' && actor === 'none'`), resolves the actor
17
12
  * via `apply_authorization_phase` against the supplied `account_id`
18
- * plus `validated_input.acting`. Failures fold into a JSON-RPC error
19
- * envelope. The test-harness escape hatch lives in the caller — pass
13
+ * plus the request's `acting` selector, read off the raw params by
14
+ * `read_acting`. Failures fold into a JSON-RPC error envelope. The
15
+ * test-harness escape hatch lives in the caller — pass
20
16
  * `preset.request_context` to skip the live phase and use a pre-baked
21
17
  * context instead.
22
- * 4. **Post-authorization auth (403)** — gates `auth.credential_types` and
23
- * `auth.roles` against the resolved context.
18
+ * 3. **Post-authorization auth (403)** — gates `auth.credential_types`,
19
+ * the credential's `token_scope`, and `auth.roles` against the resolved
20
+ * context.
21
+ * 4. **Validate params (400)** — `spec.input.safeParse(raw_params)` with
22
+ * `z.void()` / `?? {}` rules. Runs **after** the authority gates: a
23
+ * 400 describing the action's input shape to a caller those gates
24
+ * refuse would confirm the method exists and describe how to call it,
25
+ * to a channel that should have learned nothing. Coarse authority
26
+ * facts before fine ones, and no shape disclosure before authority is
27
+ * settled — the same argument that puts the credential gate ahead of
28
+ * the scope gate. The cost: a malformed request from an *authenticated*
29
+ * caller now pays for the authorization phase's actor + role_grant reads
30
+ * before being rejected, where validation used to turn it away first.
31
+ * Not a new DoS lever — the same caller reaches that work anyway by
32
+ * sending well-formed params — but it does remove a cheap-rejection path
33
+ * that buggy clients used to hit.
24
34
  * 5. **Rate limit (429)** — per-action IP / account throttling, throttle-
25
35
  * requests semantics (every invocation records, regardless of outcome).
26
36
  * 6. **Dispatch + DEV-only output validation + error normalization** —
@@ -140,10 +150,10 @@ export type PerformActionResult = {
140
150
  * transport calls into this with pre-parsed inputs and binds the result
141
151
  * to its wire shape.
142
152
  *
143
- * Phase order: 401 → 400 → 403 → handler. On the test-preset path the
144
- * dispatcher skips the live authorization phase and uses the supplied
145
- * pre-baked context for post-authorization checks; pre-validation 401
146
- * still fires when the harness omits `account_id`.
153
+ * Phase order: 401 → authz → 403 → 400 → handler. On the test-preset path
154
+ * the dispatcher skips the live authorization phase and uses the supplied
155
+ * pre-baked context for post-authorization checks; the 401 still fires when
156
+ * the harness omits `account_id`.
147
157
  */
148
158
  export declare const perform_action: (input: PerformActionInput, deps: PerformActionDeps) => Promise<PerformActionResult>;
149
159
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"perform_action.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/perform_action.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"perform_action.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/perform_action.ts"],"names":[],"mappings":"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"}