@fuzdev/fuz_app 0.54.0 → 0.56.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 (348) hide show
  1. package/dist/actions/CLAUDE.md +214 -103
  2. package/dist/actions/action_bridge.d.ts +8 -5
  3. package/dist/actions/action_bridge.d.ts.map +1 -1
  4. package/dist/actions/action_bridge.js +1 -11
  5. package/dist/actions/action_codegen.d.ts +32 -0
  6. package/dist/actions/action_codegen.d.ts.map +1 -1
  7. package/dist/actions/action_codegen.js +35 -15
  8. package/dist/actions/action_registry.d.ts.map +1 -1
  9. package/dist/actions/action_registry.js +5 -2
  10. package/dist/actions/action_rpc.d.ts +141 -22
  11. package/dist/actions/action_rpc.d.ts.map +1 -1
  12. package/dist/actions/action_rpc.js +106 -187
  13. package/dist/actions/action_spec.d.ts +55 -16
  14. package/dist/actions/action_spec.d.ts.map +1 -1
  15. package/dist/actions/action_spec.js +16 -11
  16. package/dist/actions/action_types.d.ts +28 -60
  17. package/dist/actions/action_types.d.ts.map +1 -1
  18. package/dist/actions/action_types.js +13 -5
  19. package/dist/actions/broadcast_api.d.ts +2 -2
  20. package/dist/actions/broadcast_api.js +2 -2
  21. package/dist/actions/compile_action_registry.d.ts +50 -0
  22. package/dist/actions/compile_action_registry.d.ts.map +1 -0
  23. package/dist/actions/compile_action_registry.js +69 -0
  24. package/dist/actions/heartbeat.d.ts +8 -4
  25. package/dist/actions/heartbeat.d.ts.map +1 -1
  26. package/dist/actions/heartbeat.js +5 -4
  27. package/dist/actions/perform_action.d.ts +145 -0
  28. package/dist/actions/perform_action.d.ts.map +1 -0
  29. package/dist/actions/perform_action.js +258 -0
  30. package/dist/actions/register_action_ws.d.ts +46 -40
  31. package/dist/actions/register_action_ws.d.ts.map +1 -1
  32. package/dist/actions/register_action_ws.js +101 -159
  33. package/dist/actions/register_ws_endpoint.d.ts +15 -10
  34. package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
  35. package/dist/actions/register_ws_endpoint.js +54 -7
  36. package/dist/actions/transports.d.ts.map +1 -1
  37. package/dist/actions/transports.js +0 -4
  38. package/dist/actions/transports_ws_auth_guard.d.ts +1 -1
  39. package/dist/actions/transports_ws_auth_guard.js +1 -1
  40. package/dist/actions/transports_ws_backend.d.ts +1 -1
  41. package/dist/actions/transports_ws_backend.js +1 -1
  42. package/dist/auth/CLAUDE.md +794 -410
  43. package/dist/auth/account_action_specs.d.ts +28 -7
  44. package/dist/auth/account_action_specs.d.ts.map +1 -1
  45. package/dist/auth/account_action_specs.js +7 -7
  46. package/dist/auth/account_actions.d.ts +7 -13
  47. package/dist/auth/account_actions.d.ts.map +1 -1
  48. package/dist/auth/account_actions.js +26 -35
  49. package/dist/auth/account_queries.d.ts +52 -16
  50. package/dist/auth/account_queries.d.ts.map +1 -1
  51. package/dist/auth/account_queries.js +87 -38
  52. package/dist/auth/account_routes.d.ts +9 -11
  53. package/dist/auth/account_routes.d.ts.map +1 -1
  54. package/dist/auth/account_routes.js +118 -46
  55. package/dist/auth/account_schema.d.ts +46 -35
  56. package/dist/auth/account_schema.d.ts.map +1 -1
  57. package/dist/auth/account_schema.js +21 -28
  58. package/dist/auth/admin_action_specs.d.ts +100 -32
  59. package/dist/auth/admin_action_specs.d.ts.map +1 -1
  60. package/dist/auth/admin_action_specs.js +64 -33
  61. package/dist/auth/admin_actions.d.ts +13 -19
  62. package/dist/auth/admin_actions.d.ts.map +1 -1
  63. package/dist/auth/admin_actions.js +37 -41
  64. package/dist/auth/audit_emitter.d.ts +160 -0
  65. package/dist/auth/audit_emitter.d.ts.map +1 -0
  66. package/dist/auth/audit_emitter.js +83 -0
  67. package/dist/auth/audit_log_queries.d.ts +17 -48
  68. package/dist/auth/audit_log_queries.d.ts.map +1 -1
  69. package/dist/auth/audit_log_queries.js +20 -56
  70. package/dist/auth/audit_log_routes.d.ts +1 -1
  71. package/dist/auth/audit_log_routes.d.ts.map +1 -1
  72. package/dist/auth/audit_log_routes.js +7 -3
  73. package/dist/auth/audit_log_schema.d.ts +92 -32
  74. package/dist/auth/audit_log_schema.d.ts.map +1 -1
  75. package/dist/auth/audit_log_schema.js +75 -46
  76. package/dist/auth/auth_guard_resolver.d.ts +44 -0
  77. package/dist/auth/auth_guard_resolver.d.ts.map +1 -0
  78. package/dist/auth/auth_guard_resolver.js +56 -0
  79. package/dist/auth/bearer_auth.d.ts +9 -7
  80. package/dist/auth/bearer_auth.d.ts.map +1 -1
  81. package/dist/auth/bearer_auth.js +13 -21
  82. package/dist/auth/bootstrap_account.d.ts +7 -7
  83. package/dist/auth/bootstrap_account.d.ts.map +1 -1
  84. package/dist/auth/bootstrap_account.js +7 -7
  85. package/dist/auth/bootstrap_routes.d.ts.map +1 -1
  86. package/dist/auth/bootstrap_routes.js +11 -10
  87. package/dist/auth/cleanup.d.ts +20 -26
  88. package/dist/auth/cleanup.d.ts.map +1 -1
  89. package/dist/auth/cleanup.js +33 -42
  90. package/dist/auth/credential_type_schema.d.ts +115 -0
  91. package/dist/auth/credential_type_schema.d.ts.map +1 -0
  92. package/dist/auth/credential_type_schema.js +127 -0
  93. package/dist/auth/daemon_token_middleware.d.ts +23 -11
  94. package/dist/auth/daemon_token_middleware.d.ts.map +1 -1
  95. package/dist/auth/daemon_token_middleware.js +28 -22
  96. package/dist/auth/ddl.d.ts +2 -2
  97. package/dist/auth/ddl.d.ts.map +1 -1
  98. package/dist/auth/ddl.js +6 -6
  99. package/dist/auth/deps.d.ts +7 -18
  100. package/dist/auth/deps.d.ts.map +1 -1
  101. package/dist/auth/grant_path_schema.d.ts +117 -0
  102. package/dist/auth/grant_path_schema.d.ts.map +1 -0
  103. package/dist/auth/grant_path_schema.js +137 -0
  104. package/dist/auth/invite_queries.d.ts +12 -1
  105. package/dist/auth/invite_queries.d.ts.map +1 -1
  106. package/dist/auth/invite_queries.js +12 -1
  107. package/dist/auth/invite_schema.d.ts +1 -1
  108. package/dist/auth/invite_schema.d.ts.map +1 -1
  109. package/dist/auth/invite_schema.js +1 -1
  110. package/dist/auth/middleware.d.ts.map +1 -1
  111. package/dist/auth/middleware.js +9 -4
  112. package/dist/auth/migrations.d.ts +37 -14
  113. package/dist/auth/migrations.d.ts.map +1 -1
  114. package/dist/auth/migrations.js +79 -32
  115. package/dist/auth/request_context.d.ts +331 -61
  116. package/dist/auth/request_context.d.ts.map +1 -1
  117. package/dist/auth/request_context.js +378 -95
  118. package/dist/auth/{permit_offer_action_specs.d.ts → role_grant_offer_action_specs.d.ts} +163 -94
  119. package/dist/auth/role_grant_offer_action_specs.d.ts.map +1 -0
  120. package/dist/auth/role_grant_offer_action_specs.js +262 -0
  121. package/dist/auth/role_grant_offer_actions.d.ts +104 -0
  122. package/dist/auth/role_grant_offer_actions.d.ts.map +1 -0
  123. package/dist/auth/role_grant_offer_actions.js +473 -0
  124. package/dist/auth/{permit_offer_notifications.d.ts → role_grant_offer_notifications.d.ts} +90 -70
  125. package/dist/auth/role_grant_offer_notifications.d.ts.map +1 -0
  126. package/dist/auth/role_grant_offer_notifications.js +182 -0
  127. package/dist/auth/role_grant_offer_queries.d.ts +242 -0
  128. package/dist/auth/role_grant_offer_queries.d.ts.map +1 -0
  129. package/dist/auth/role_grant_offer_queries.js +533 -0
  130. package/dist/auth/role_grant_offer_schema.d.ts +150 -0
  131. package/dist/auth/role_grant_offer_schema.d.ts.map +1 -0
  132. package/dist/auth/{permit_offer_schema.js → role_grant_offer_schema.js} +60 -36
  133. package/dist/auth/role_grant_queries.d.ts +231 -0
  134. package/dist/auth/role_grant_queries.d.ts.map +1 -0
  135. package/dist/auth/role_grant_queries.js +320 -0
  136. package/dist/auth/role_schema.d.ts +150 -40
  137. package/dist/auth/role_schema.d.ts.map +1 -1
  138. package/dist/auth/role_schema.js +144 -45
  139. package/dist/auth/scope_kind_schema.d.ts +96 -0
  140. package/dist/auth/scope_kind_schema.d.ts.map +1 -0
  141. package/dist/auth/scope_kind_schema.js +94 -0
  142. package/dist/auth/self_service_role_action_specs.d.ts +6 -1
  143. package/dist/auth/self_service_role_action_specs.d.ts.map +1 -1
  144. package/dist/auth/self_service_role_action_specs.js +3 -1
  145. package/dist/auth/self_service_role_actions.d.ts +34 -27
  146. package/dist/auth/self_service_role_actions.d.ts.map +1 -1
  147. package/dist/auth/self_service_role_actions.js +68 -48
  148. package/dist/auth/session_cookie.d.ts +43 -6
  149. package/dist/auth/session_cookie.d.ts.map +1 -1
  150. package/dist/auth/session_cookie.js +31 -5
  151. package/dist/auth/session_middleware.d.ts +37 -3
  152. package/dist/auth/session_middleware.d.ts.map +1 -1
  153. package/dist/auth/session_middleware.js +33 -7
  154. package/dist/auth/signup_routes.d.ts.map +1 -1
  155. package/dist/auth/signup_routes.js +48 -19
  156. package/dist/auth/standard_action_specs.d.ts +2 -2
  157. package/dist/auth/standard_action_specs.js +4 -4
  158. package/dist/auth/standard_rpc_actions.d.ts +23 -19
  159. package/dist/auth/standard_rpc_actions.d.ts.map +1 -1
  160. package/dist/auth/standard_rpc_actions.js +12 -12
  161. package/dist/db/migrate.d.ts +12 -8
  162. package/dist/db/migrate.d.ts.map +1 -1
  163. package/dist/db/migrate.js +10 -7
  164. package/dist/dev/setup.d.ts +2 -2
  165. package/dist/dev/setup.d.ts.map +1 -1
  166. package/dist/dev/setup.js +9 -7
  167. package/dist/env/load.d.ts +1 -1
  168. package/dist/env/load.js +1 -1
  169. package/dist/hono_context.d.ts +64 -5
  170. package/dist/hono_context.d.ts.map +1 -1
  171. package/dist/hono_context.js +38 -2
  172. package/dist/http/CLAUDE.md +264 -87
  173. package/dist/http/auth_shape.d.ts +191 -0
  174. package/dist/http/auth_shape.d.ts.map +1 -0
  175. package/dist/http/auth_shape.js +237 -0
  176. package/dist/http/common_routes.js +3 -3
  177. package/dist/http/db_routes.d.ts +4 -0
  178. package/dist/http/db_routes.d.ts.map +1 -1
  179. package/dist/http/db_routes.js +44 -7
  180. package/dist/http/error_schemas.d.ts +132 -19
  181. package/dist/http/error_schemas.d.ts.map +1 -1
  182. package/dist/http/error_schemas.js +132 -40
  183. package/dist/http/jsonrpc_errors.d.ts +27 -2
  184. package/dist/http/jsonrpc_errors.d.ts.map +1 -1
  185. package/dist/http/jsonrpc_errors.js +26 -2
  186. package/dist/http/pending_effects.d.ts +71 -18
  187. package/dist/http/pending_effects.d.ts.map +1 -1
  188. package/dist/http/pending_effects.js +87 -18
  189. package/dist/http/proxy.d.ts +52 -5
  190. package/dist/http/proxy.d.ts.map +1 -1
  191. package/dist/http/proxy.js +92 -14
  192. package/dist/http/route_spec.d.ts +113 -41
  193. package/dist/http/route_spec.d.ts.map +1 -1
  194. package/dist/http/route_spec.js +130 -52
  195. package/dist/http/schema_helpers.d.ts +3 -2
  196. package/dist/http/schema_helpers.d.ts.map +1 -1
  197. package/dist/http/schema_helpers.js +9 -2
  198. package/dist/http/surface.d.ts +2 -1
  199. package/dist/http/surface.d.ts.map +1 -1
  200. package/dist/http/surface.js +1 -2
  201. package/dist/http/surface_query.d.ts +39 -35
  202. package/dist/http/surface_query.d.ts.map +1 -1
  203. package/dist/http/surface_query.js +79 -36
  204. package/dist/primitive_schemas.d.ts +39 -0
  205. package/dist/primitive_schemas.d.ts.map +1 -0
  206. package/dist/primitive_schemas.js +40 -0
  207. package/dist/realtime/sse_auth_guard.d.ts +5 -5
  208. package/dist/realtime/sse_auth_guard.js +9 -9
  209. package/dist/runtime/mock.d.ts +1 -1
  210. package/dist/runtime/mock.js +1 -1
  211. package/dist/server/app_backend.d.ts +14 -11
  212. package/dist/server/app_backend.d.ts.map +1 -1
  213. package/dist/server/app_backend.js +12 -8
  214. package/dist/server/app_server.d.ts +7 -7
  215. package/dist/server/app_server.d.ts.map +1 -1
  216. package/dist/server/app_server.js +36 -31
  217. package/dist/server/validate_nginx.d.ts +1 -1
  218. package/dist/server/validate_nginx.js +1 -1
  219. package/dist/testing/CLAUDE.md +73 -55
  220. package/dist/testing/admin_integration.d.ts +5 -6
  221. package/dist/testing/admin_integration.d.ts.map +1 -1
  222. package/dist/testing/admin_integration.js +100 -96
  223. package/dist/testing/adversarial_headers.js +1 -1
  224. package/dist/testing/app_server.d.ts +11 -14
  225. package/dist/testing/app_server.d.ts.map +1 -1
  226. package/dist/testing/app_server.js +18 -17
  227. package/dist/testing/assertions.d.ts.map +1 -1
  228. package/dist/testing/assertions.js +2 -1
  229. package/dist/testing/attack_surface.d.ts.map +1 -1
  230. package/dist/testing/attack_surface.js +15 -9
  231. package/dist/testing/audit_completeness.d.ts +2 -2
  232. package/dist/testing/audit_completeness.d.ts.map +1 -1
  233. package/dist/testing/audit_completeness.js +53 -39
  234. package/dist/testing/auth_apps.d.ts +5 -4
  235. package/dist/testing/auth_apps.d.ts.map +1 -1
  236. package/dist/testing/auth_apps.js +28 -22
  237. package/dist/testing/data_exposure.d.ts.map +1 -1
  238. package/dist/testing/data_exposure.js +5 -5
  239. package/dist/testing/db.d.ts +1 -1
  240. package/dist/testing/db.d.ts.map +1 -1
  241. package/dist/testing/db.js +4 -4
  242. package/dist/testing/db_entities.d.ts +22 -0
  243. package/dist/testing/db_entities.d.ts.map +1 -0
  244. package/dist/testing/db_entities.js +28 -0
  245. package/dist/testing/entities.d.ts +10 -8
  246. package/dist/testing/entities.d.ts.map +1 -1
  247. package/dist/testing/entities.js +22 -18
  248. package/dist/testing/integration.d.ts.map +1 -1
  249. package/dist/testing/integration.js +13 -14
  250. package/dist/testing/integration_helpers.d.ts +8 -6
  251. package/dist/testing/integration_helpers.d.ts.map +1 -1
  252. package/dist/testing/integration_helpers.js +29 -23
  253. package/dist/testing/middleware.d.ts +15 -11
  254. package/dist/testing/middleware.d.ts.map +1 -1
  255. package/dist/testing/middleware.js +75 -32
  256. package/dist/testing/rpc_attack_surface.d.ts.map +1 -1
  257. package/dist/testing/rpc_attack_surface.js +40 -24
  258. package/dist/testing/rpc_helpers.d.ts.map +1 -1
  259. package/dist/testing/rpc_helpers.js +3 -1
  260. package/dist/testing/rpc_round_trip.d.ts +1 -1
  261. package/dist/testing/rpc_round_trip.d.ts.map +1 -1
  262. package/dist/testing/rpc_round_trip.js +14 -13
  263. package/dist/testing/sse_round_trip.d.ts +3 -4
  264. package/dist/testing/sse_round_trip.d.ts.map +1 -1
  265. package/dist/testing/sse_round_trip.js +7 -11
  266. package/dist/testing/standard.d.ts +1 -1
  267. package/dist/testing/stubs.d.ts +25 -0
  268. package/dist/testing/stubs.d.ts.map +1 -1
  269. package/dist/testing/stubs.js +43 -2
  270. package/dist/testing/surface_invariants.d.ts +2 -2
  271. package/dist/testing/ws_round_trip.d.ts +12 -13
  272. package/dist/testing/ws_round_trip.d.ts.map +1 -1
  273. package/dist/testing/ws_round_trip.js +24 -12
  274. package/dist/ui/AdminAccounts.svelte +23 -20
  275. package/dist/ui/AdminOverview.svelte +15 -13
  276. package/dist/ui/AdminOverview.svelte.d.ts.map +1 -1
  277. package/dist/ui/{AdminPermitHistory.svelte → AdminRoleGrantHistory.svelte} +12 -12
  278. package/dist/ui/AdminRoleGrantHistory.svelte.d.ts +4 -0
  279. package/dist/ui/AdminRoleGrantHistory.svelte.d.ts.map +1 -0
  280. package/dist/ui/BootstrapForm.svelte +1 -1
  281. package/dist/ui/CLAUDE.md +65 -59
  282. package/dist/ui/{PermitOfferForm.svelte → RoleGrantOfferForm.svelte} +37 -22
  283. package/dist/ui/RoleGrantOfferForm.svelte.d.ts +20 -0
  284. package/dist/ui/RoleGrantOfferForm.svelte.d.ts.map +1 -0
  285. package/dist/ui/{PermitOfferHistory.svelte → RoleGrantOfferHistory.svelte} +12 -12
  286. package/dist/ui/{PermitOfferHistory.svelte.d.ts → RoleGrantOfferHistory.svelte.d.ts} +4 -4
  287. package/dist/ui/RoleGrantOfferHistory.svelte.d.ts.map +1 -0
  288. package/dist/ui/{PermitOfferInbox.svelte → RoleGrantOfferInbox.svelte} +14 -14
  289. package/dist/ui/{PermitOfferInbox.svelte.d.ts → RoleGrantOfferInbox.svelte.d.ts} +4 -4
  290. package/dist/ui/RoleGrantOfferInbox.svelte.d.ts.map +1 -0
  291. package/dist/ui/SignupForm.svelte +1 -1
  292. package/dist/ui/SurfaceExplorer.svelte +35 -15
  293. package/dist/ui/SurfaceExplorer.svelte.d.ts.map +1 -1
  294. package/dist/ui/account_sessions_state.svelte.d.ts +2 -3
  295. package/dist/ui/account_sessions_state.svelte.d.ts.map +1 -1
  296. package/dist/ui/account_sessions_state.svelte.js +2 -3
  297. package/dist/ui/admin_accounts_state.svelte.d.ts +25 -18
  298. package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
  299. package/dist/ui/admin_accounts_state.svelte.js +28 -17
  300. package/dist/ui/admin_rpc_adapters.d.ts +20 -20
  301. package/dist/ui/admin_rpc_adapters.d.ts.map +1 -1
  302. package/dist/ui/admin_rpc_adapters.js +17 -17
  303. package/dist/ui/admin_sessions_state.svelte.d.ts +2 -2
  304. package/dist/ui/admin_sessions_state.svelte.js +2 -2
  305. package/dist/ui/audit_log_state.svelte.d.ts +7 -7
  306. package/dist/ui/audit_log_state.svelte.d.ts.map +1 -1
  307. package/dist/ui/audit_log_state.svelte.js +6 -6
  308. package/dist/ui/auth_state.svelte.d.ts +3 -3
  309. package/dist/ui/auth_state.svelte.d.ts.map +1 -1
  310. package/dist/ui/auth_state.svelte.js +6 -6
  311. package/dist/ui/format_scope.d.ts +2 -2
  312. package/dist/ui/format_scope.js +2 -2
  313. package/dist/ui/{permit_offers_state.svelte.d.ts → role_grant_offers_state.svelte.d.ts} +39 -31
  314. package/dist/ui/role_grant_offers_state.svelte.d.ts.map +1 -0
  315. package/dist/ui/{permit_offers_state.svelte.js → role_grant_offers_state.svelte.js} +25 -19
  316. package/dist/ui/ui_format.js +2 -2
  317. package/package.json +3 -3
  318. package/dist/auth/permit_offer_action_specs.d.ts.map +0 -1
  319. package/dist/auth/permit_offer_action_specs.js +0 -227
  320. package/dist/auth/permit_offer_actions.d.ts +0 -110
  321. package/dist/auth/permit_offer_actions.d.ts.map +0 -1
  322. package/dist/auth/permit_offer_actions.js +0 -452
  323. package/dist/auth/permit_offer_notifications.d.ts.map +0 -1
  324. package/dist/auth/permit_offer_notifications.js +0 -182
  325. package/dist/auth/permit_offer_queries.d.ts +0 -183
  326. package/dist/auth/permit_offer_queries.d.ts.map +0 -1
  327. package/dist/auth/permit_offer_queries.js +0 -408
  328. package/dist/auth/permit_offer_schema.d.ts +0 -103
  329. package/dist/auth/permit_offer_schema.d.ts.map +0 -1
  330. package/dist/auth/permit_queries.d.ts +0 -210
  331. package/dist/auth/permit_queries.d.ts.map +0 -1
  332. package/dist/auth/permit_queries.js +0 -294
  333. package/dist/auth/require_keeper.d.ts +0 -20
  334. package/dist/auth/require_keeper.d.ts.map +0 -1
  335. package/dist/auth/require_keeper.js +0 -35
  336. package/dist/auth/route_guards.d.ts +0 -21
  337. package/dist/auth/route_guards.d.ts.map +0 -1
  338. package/dist/auth/route_guards.js +0 -32
  339. package/dist/auth/session_lifecycle.d.ts +0 -37
  340. package/dist/auth/session_lifecycle.d.ts.map +0 -1
  341. package/dist/auth/session_lifecycle.js +0 -29
  342. package/dist/ui/AdminPermitHistory.svelte.d.ts +0 -4
  343. package/dist/ui/AdminPermitHistory.svelte.d.ts.map +0 -1
  344. package/dist/ui/PermitOfferForm.svelte.d.ts +0 -14
  345. package/dist/ui/PermitOfferForm.svelte.d.ts.map +0 -1
  346. package/dist/ui/PermitOfferHistory.svelte.d.ts.map +0 -1
  347. package/dist/ui/PermitOfferInbox.svelte.d.ts.map +0 -1
  348. package/dist/ui/permit_offers_state.svelte.d.ts.map +0 -1
@@ -15,14 +15,15 @@ import { z } from 'zod';
15
15
  import { DEV } from 'esm-env';
16
16
  import {} from '../http/route_spec.js';
17
17
  import { get_client_ip } from '../http/proxy.js';
18
- import { get_request_context, has_role } from '../auth/request_context.js';
19
- import { CREDENTIAL_TYPE_KEY } from '../hono_context.js';
20
- import { is_null_schema, is_void_schema } from '../http/schema_helpers.js';
18
+ import { get_request_context, } from '../auth/request_context.js';
19
+ import { ACCOUNT_ID_KEY, CREDENTIAL_TYPE_KEY, TEST_CONTEXT_PRESET_KEY } from '../hono_context.js';
20
+ import { compile_action_registry } from './compile_action_registry.js';
21
21
  import { JSONRPC_VERSION, JsonrpcRequest, } from '../http/jsonrpc.js';
22
22
  import { jsonrpc_error_messages, jsonrpc_error_code_to_http_status, JSONRPC_ERROR_CODES, } from '../http/jsonrpc_errors.js';
23
- import { ERROR_INSUFFICIENT_PERMISSIONS, ERROR_KEEPER_REQUIRES_DAEMON_TOKEN, } from '../http/error_schemas.js';
23
+ import { perform_action, perform_action_result_to_envelope } from './perform_action.js';
24
24
  /**
25
- * Pair a spec with a handler while preserving per-method input/output types.
25
+ * Pair a spec with a handler while preserving per-method input/output types
26
+ * and selecting the narrowest `ctx.auth` shape the spec literal admits.
26
27
  *
27
28
  * Constructing `{spec, handler}` literals widens `handler` to
28
29
  * `ActionHandler<any, any>`, so spec/handler drift (renamed Zod schema,
@@ -31,60 +32,57 @@ import { ERROR_INSUFFICIENT_PERMISSIONS, ERROR_KEEPER_REQUIRES_DAEMON_TOKEN, } f
31
32
  * `(input: z.infer<spec.input>, ctx) => z.infer<spec.output>` via the
32
33
  * generic spec parameter — drift surfaces at the call site.
33
34
  *
35
+ * The `ctx.auth` narrowing follows the spec's `auth.account` /
36
+ * `auth.actor` literals (see `HandlerForSpec`): an actor-implying spec
37
+ * gets `ctx.auth: RequestActorContext`; an account-grain spec gets
38
+ * `ctx.auth: RequestContext`; everything else stays `ctx.auth:
39
+ * RequestContext | null`. Handlers can rely on the dispatcher's
40
+ * runtime guarantee without a manual narrowing call.
41
+ *
34
42
  * Fits fuz_app's factory-closure pattern (handlers close over
35
43
  * `grantable_roles`, `app_settings` ref, `notification_sender`, etc.).
36
44
  * zzz uses a different shape — a codegen-keyed `Record<Method, Handler>`
37
45
  * map typed via generated `ActionInputs`/`ActionOutputs` — which works when
38
46
  * handlers are pure (no closure state) and specs are codegen-enumerated.
39
- * fuz_app's admin + permit-offer actions have neither, so per-pair typing
47
+ * fuz_app's admin + role-grant-offer actions have neither, so per-pair typing
40
48
  * at the registration site is the right fit.
49
+ *
50
+ * Spec-literal preservation is load-bearing: declare specs with
51
+ * `satisfies RequestResponseActionSpec` (canonical) so `auth.actor`
52
+ * keeps its `'required'` / `'none'` literal type. A spec typed
53
+ * directly as `RequestResponseActionSpec` widens the axes to
54
+ * `AuthAxisState` and the handler defaults to the loosest tier — sound,
55
+ * but loses the ergonomic narrowing.
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * // actor-implying spec → ctx.auth: RequestActorContext
60
+ * rpc_action(role_grant_revoke_action_spec, async (input, ctx) => {
61
+ * const revoker_id = ctx.auth.actor.id; // no narrowing needed
62
+ * });
63
+ *
64
+ * // account-grain spec → ctx.auth: RequestContext (actor: null)
65
+ * rpc_action(account_verify_action_spec, (_input, ctx) => {
66
+ * return to_session_account(ctx.auth.account); // no narrowing needed
67
+ * });
68
+ * ```
41
69
  */
42
70
  export const rpc_action = (spec, handler) => ({
43
71
  spec,
44
72
  handler: handler,
45
73
  });
46
- const jsonrpc_error_response = (id, error) => ({
74
+ /**
75
+ * Build a JSON-RPC error envelope for transport-shape errors (envelope
76
+ * parse failures, method-not-found, GET-on-mutation rejections). The
77
+ * dispatch core in `perform_action` returns a `PerformActionResult`
78
+ * directly; this helper covers only the wire-shape errors the HTTP shim
79
+ * emits before / after the core runs.
80
+ */
81
+ const jsonrpc_error_envelope = (id, error) => ({
47
82
  jsonrpc: JSONRPC_VERSION,
48
83
  id,
49
84
  error,
50
85
  });
51
- /**
52
- * Check auth for an action spec against the request context.
53
- *
54
- * @returns a JSON-RPC error object if auth fails, or `null` if authorized
55
- */
56
- const check_action_auth = (auth, request_context, credential_type) => {
57
- if (auth === 'public')
58
- return null;
59
- if (!request_context)
60
- return jsonrpc_error_messages.unauthenticated();
61
- if (auth === 'authenticated')
62
- return null;
63
- if (auth === 'keeper') {
64
- // keeper requires daemon_token credential type AND the keeper role.
65
- // API tokens and session cookies cannot access keeper actions even
66
- // if the account has the keeper permit. Attach the credential type
67
- // under `data` so clients can distinguish "wrong credential shape"
68
- // from "missing keeper role" — mirrors REST 403 semantics.
69
- if (credential_type !== 'daemon_token' || !has_role(request_context, 'keeper')) {
70
- return jsonrpc_error_messages.forbidden('forbidden', {
71
- reason: ERROR_KEEPER_REQUIRES_DAEMON_TOKEN,
72
- credential_type,
73
- });
74
- }
75
- return null;
76
- }
77
- // role check — attach `required_role` under `data.required_role` so
78
- // clients can render targeted copy (matches the former REST `PermissionError`
79
- // shape that exposed `required_role` as a top-level field).
80
- if (!has_role(request_context, auth.role)) {
81
- return jsonrpc_error_messages.forbidden(`requires role: ${auth.role}`, {
82
- reason: ERROR_INSUFFICIENT_PERMISSIONS,
83
- required_role: auth.role,
84
- });
85
- }
86
- return null;
87
- };
88
86
  /**
89
87
  * Single JSON-RPC 2.0 endpoint — the canonical RPC transport binding.
90
88
  *
@@ -94,9 +92,18 @@ const check_action_auth = (auth, request_context, credential_type) => {
94
92
  * 1. **Parse envelope** — POST: JSON body as `JsonrpcRequest`. GET: `method`
95
93
  * and `params` from query string.
96
94
  * 2. **Lookup method** — find the `RpcAction` by method name.
97
- * 3. **Auth check** — verify identity against the action's `auth` requirement.
98
- * 4. **Validate params** parse input against the action's `input` schema.
99
- * 5. **Dispatch** — acquire DB handle (transaction for mutations, pool for reads),
95
+ * 3. **Pre-validation auth** — short-circuit `unauthenticated` when no
96
+ * account is on the request, before input validation runs.
97
+ * 4. **Authorization phase** — resolve the acting actor (when the action's
98
+ * auth requires role_grants or its input declares `acting?: ActingActor`)
99
+ * and build the request context. Runs before input validation so
100
+ * role-grant-grain auth checks return 403 before 400 invalid_params;
101
+ * `acting` is read from raw params via a string typeguard.
102
+ * 5. **Post-authorization auth** — enforce role / keeper requirements
103
+ * against the request context.
104
+ * 6. **Validate params** — parse input against the action's `input` schema.
105
+ * 7. **Rate limit** — per-action IP / account throttling.
106
+ * 8. **Dispatch** — acquire DB handle (transaction for mutations, pool for reads),
100
107
  * construct `ActionContext`, call handler, return JSON-RPC response.
101
108
  *
102
109
  * GET is restricted to `side_effects: false` actions (cacheable reads).
@@ -115,156 +122,68 @@ const check_action_auth = (auth, request_context, credential_type) => {
115
122
  */
116
123
  export const create_rpc_endpoint = (options) => {
117
124
  const { path: endpoint_path, actions, log, action_ip_rate_limiter = null, action_account_rate_limiter = null, } = options;
118
- // build action lookup map
119
- const action_map = new Map();
120
- for (const action of actions) {
121
- if (action_map.has(action.spec.method)) {
122
- throw new Error(`Duplicate RPC action method: ${action.spec.method}`);
123
- }
124
- if (is_null_schema(action.spec.input)) {
125
- throw new Error(`RPC action "${action.spec.method}" uses z.null() for input — JSON-RPC 2.0 §4.2 forbids "params": null on the wire (must be omitted or be a Structured value). Use z.void() for parameterless methods.`);
126
- }
127
- // Reject account-keyed rate limiting on public actions — there's no
128
- // actor post-auth, so the account bucket has no key to consume.
129
- if ((action.spec.rate_limit === 'account' || action.spec.rate_limit === 'both') &&
130
- action.spec.auth === 'public') {
131
- throw new Error(`RPC action "${action.spec.method}" declares rate_limit: '${action.spec.rate_limit}' but auth: 'public' — no actor available for account-keyed limiting. Use 'ip' or change auth.`);
132
- }
133
- action_map.set(action.spec.method, action);
134
- }
125
+ const { action_map } = compile_action_registry(actions, 'RPC action');
135
126
  /**
136
- * Core dispatchershared by GET and POST handlers.
127
+ * HTTP-shape dispatch shim the GET/POST entry points share this:
128
+ *
129
+ * 1. Resolve the action by method name (HTTP-shape `method_not_found` envelope).
130
+ * 2. Reject GET requests for `side_effects: true` actions (HTTP-only constraint).
131
+ * 3. Hand off to `perform_action` for the post-parse pipeline.
132
+ * 4. Bind the result to `c.json` — `'ok'` returns the result envelope,
133
+ * `'error'` returns the error envelope at the `result.status` HTTP code.
137
134
  *
138
135
  * @param restrict_to_reads - `true` for GET (rejects `side_effects: true` actions)
139
136
  */
140
137
  const dispatch = async (c, route, method_name, raw_params, id, restrict_to_reads) => {
141
- // step 2: lookup method
142
138
  const action = action_map.get(method_name);
143
139
  if (!action) {
144
- const error = jsonrpc_error_response(id, jsonrpc_error_messages.method_not_found(method_name));
145
- return c.json(error, jsonrpc_error_code_to_http_status(JSONRPC_ERROR_CODES.method_not_found));
140
+ return c.json(jsonrpc_error_envelope(id, jsonrpc_error_messages.method_not_found(method_name)), jsonrpc_error_code_to_http_status(JSONRPC_ERROR_CODES.method_not_found));
146
141
  }
147
- // GET restriction: only side_effects:false actions
148
142
  if (restrict_to_reads && action.spec.side_effects) {
149
- const error = jsonrpc_error_response(id, jsonrpc_error_messages.invalid_request({
143
+ return c.json(jsonrpc_error_envelope(id, jsonrpc_error_messages.invalid_request({
150
144
  reason: `method '${method_name}' has side effects and must use POST`,
151
- }));
152
- return c.json(error, jsonrpc_error_code_to_http_status(JSONRPC_ERROR_CODES.invalid_request));
153
- }
154
- // step 3: auth check
155
- const request_context = get_request_context(c);
156
- const credential_type = c.get(CREDENTIAL_TYPE_KEY) ?? null;
157
- const auth_error = check_action_auth(action.spec.auth, request_context, credential_type);
158
- if (auth_error) {
159
- const error = jsonrpc_error_response(id, auth_error);
160
- return c.json(error, jsonrpc_error_code_to_http_status(auth_error.code));
145
+ })), jsonrpc_error_code_to_http_status(JSONRPC_ERROR_CODES.invalid_request));
161
146
  }
162
- // step 3.5: rate limit throttle-requests semantics (record on every
163
- // invocation, no success-reset). Suits admin mutation oracles where
164
- // the *successful* call is the threat. Different from REST login's
165
- // throttle-failures pattern that resets on success. Silent partial
166
- // enforcement: a key is checked iff its bucket's limiter is wired —
167
- // `rate_limit: 'both'` with only one limiter set runs only that side.
168
- const rate_limit = action.spec.rate_limit;
169
- const client_ip = get_client_ip(c);
170
- if (rate_limit) {
171
- const ip_check = action_ip_rate_limiter && (rate_limit === 'ip' || rate_limit === 'both');
172
- const account_check = action_account_rate_limiter &&
173
- request_context &&
174
- (rate_limit === 'account' || rate_limit === 'both');
175
- const reject = (retry_after) => {
176
- const error = jsonrpc_error_response(id, jsonrpc_error_messages.rate_limited('rate limited', { retry_after }));
177
- return c.json(error, jsonrpc_error_code_to_http_status(JSONRPC_ERROR_CODES.rate_limited));
178
- };
179
- if (ip_check) {
180
- const result = action_ip_rate_limiter.check(client_ip);
181
- if (!result.allowed)
182
- return reject(result.retry_after);
183
- }
184
- if (account_check) {
185
- const result = action_account_rate_limiter.check(request_context.actor.id);
186
- if (!result.allowed)
187
- return reject(result.retry_after);
188
- }
189
- if (ip_check)
190
- action_ip_rate_limiter.record(client_ip);
191
- if (account_check)
192
- action_account_rate_limiter.record(request_context.actor.id);
193
- }
194
- // step 4: validate params
195
- // Missing `params` on the envelope maps to `undefined` for `z.void()`
196
- // input schemas and `{}` for object inputs (matches HTTP's "empty
197
- // body = empty object" convention so callers of all-optional-object
198
- // RPC methods can omit `params` on the wire). JSON-RPC 2.0 §4.2
199
- // forbids `params: null`, so `z.void()` is the spec-correct schema
200
- // for parameterless methods — registration above rejects `z.null()`
201
- // inputs to keep this branch from having to consider that legacy
202
- // shape. When `raw_params` is present it flows through unchanged so
203
- // contract-violating shapes still fail validation.
204
- const params = is_void_schema(action.spec.input) ? raw_params : (raw_params ?? {});
205
- const parse_result = action.spec.input.safeParse(params);
206
- if (!parse_result.success) {
207
- const error = jsonrpc_error_response(id, jsonrpc_error_messages.invalid_params('invalid params', {
208
- issues: parse_result.error.issues,
209
- }));
210
- return c.json(error, jsonrpc_error_code_to_http_status(JSONRPC_ERROR_CODES.invalid_params));
211
- }
212
- // step 5: dispatch — transaction for mutations, pool for reads
213
- const use_transaction = action.spec.side_effects;
147
+ // HTTP RPC has no streaming channel; `ctx.notify` warn-and-drops in DEV.
214
148
  const notify = (notify_method, _notify_params) => {
215
149
  if (DEV) {
216
150
  log.warn(`ctx.notify('${notify_method}') called on non-streaming transport; notification dropped (method=${method_name})`);
217
151
  }
218
152
  };
219
- const signal = c.req.raw.signal;
220
- const execute = async (db) => {
221
- const action_context = {
222
- auth: request_context,
223
- request_id: id,
224
- db,
225
- background_db: route.background_db,
226
- pending_effects: route.pending_effects,
227
- client_ip,
228
- log,
229
- notify,
230
- signal,
231
- };
232
- const output = await action.handler(parse_result.data, action_context);
233
- // DEV-only output validation — logs an error on mismatch, does not throw.
234
- if (DEV) {
235
- const output_result = action.spec.output.safeParse(output);
236
- if (!output_result.success) {
237
- log.error(`RPC output schema mismatch: ${method_name}`, output_result.error.issues);
238
- }
239
- }
240
- return c.json({ jsonrpc: JSONRPC_VERSION, id, result: output });
241
- };
242
- // error handling wraps the transaction boundary so handler throws
243
- // cause rollback before the error is formatted as a JSON-RPC response
244
- try {
245
- if (use_transaction) {
246
- return await route.db.transaction((tx) => execute(tx));
247
- }
248
- return await execute(route.db);
249
- }
250
- catch (err) {
251
- // Duck-type check: Error with numeric `code` signals a JSON-RPC error.
252
- // Avoids instanceof which fails when consumers throw their own ThrownJsonrpcError
253
- // (structurally identical but different class identity, e.g. zzz's copy).
254
- if (err instanceof Error && typeof err.code === 'number') {
255
- const code = err.code;
256
- const data = err.data;
257
- const status = jsonrpc_error_code_to_http_status(code);
258
- const error_json = { code, message: err.message };
259
- if (data !== undefined)
260
- error_json.data = data;
261
- return c.json(jsonrpc_error_response(id, error_json), status);
262
- }
263
- // generic error
264
- log.error(`Unhandled RPC handler error: ${method_name}`, err);
265
- const message = DEV && err instanceof Error ? err.message : 'internal server error';
266
- return c.json(jsonrpc_error_response(id, jsonrpc_error_messages.internal_error(message)), 500);
153
+ // Test escape hatch: harnesses pre-populate `REQUEST_CONTEXT_KEY` and
154
+ // flag `TEST_CONTEXT_PRESET_KEY = true`. Production middleware never
155
+ // sets the flag; the shim honors it and `perform_action` trusts the
156
+ // pre-baked context instead of running the live authorization phase.
157
+ const preset = c.get(TEST_CONTEXT_PRESET_KEY)
158
+ ? { request_context: get_request_context(c) }
159
+ : undefined;
160
+ const result = await perform_action({
161
+ action,
162
+ raw_params,
163
+ request_id: id,
164
+ account_id: c.get(ACCOUNT_ID_KEY) ?? null,
165
+ credential_type: c.get(CREDENTIAL_TYPE_KEY) ?? null,
166
+ client_ip: get_client_ip(c),
167
+ signal: c.req.raw.signal,
168
+ notify,
169
+ preset,
170
+ }, {
171
+ db: route.db,
172
+ pending_effects: route.pending_effects,
173
+ post_commit_effects: route.post_commit_effects,
174
+ log,
175
+ action_ip_rate_limiter,
176
+ action_account_rate_limiter,
177
+ });
178
+ const envelope = perform_action_result_to_envelope(id, result);
179
+ if (result.kind === 'error') {
180
+ // `result.status` is one of the JSON-RPC → HTTP status codes the
181
+ // dispatcher emits; Hono types `c.json`'s second arg as
182
+ // `ContentfulStatusCode`, which the cast bridges (the value space
183
+ // is verified by `jsonrpc_error_code_to_http_status`).
184
+ return c.json(envelope, result.status);
267
185
  }
186
+ return c.json(envelope);
268
187
  };
269
188
  // POST handler — parse JSON-RPC envelope from body
270
189
  const post_handler = async (c, route) => {
@@ -274,7 +193,7 @@ export const create_rpc_endpoint = (options) => {
274
193
  body = await c.req.json();
275
194
  }
276
195
  catch {
277
- const error = jsonrpc_error_response(null, jsonrpc_error_messages.parse_error());
196
+ const error = jsonrpc_error_envelope(null, jsonrpc_error_messages.parse_error());
278
197
  return c.json(error, 400);
279
198
  }
280
199
  const envelope = JsonrpcRequest.safeParse(body);
@@ -284,7 +203,7 @@ export const create_rpc_endpoint = (options) => {
284
203
  ? body.id
285
204
  : null;
286
205
  const id = typeof raw_id === 'string' || typeof raw_id === 'number' ? raw_id : null;
287
- const error = jsonrpc_error_response(id, jsonrpc_error_messages.invalid_request({ issues: envelope.error.issues }));
206
+ const error = jsonrpc_error_envelope(id, jsonrpc_error_messages.invalid_request({ issues: envelope.error.issues }));
288
207
  return c.json(error, 400);
289
208
  }
290
209
  return dispatch(c, route, envelope.data.method, envelope.data.params, envelope.data.id, false);
@@ -294,12 +213,12 @@ export const create_rpc_endpoint = (options) => {
294
213
  // step 1: parse from query string
295
214
  const method_name = c.req.query('method');
296
215
  if (!method_name) {
297
- const error = jsonrpc_error_response(null, jsonrpc_error_messages.invalid_request({ reason: 'missing method query parameter' }));
216
+ const error = jsonrpc_error_envelope(null, jsonrpc_error_messages.invalid_request({ reason: 'missing method query parameter' }));
298
217
  return c.json(error, 400);
299
218
  }
300
219
  const id_raw = c.req.query('id');
301
220
  if (!id_raw) {
302
- const error = jsonrpc_error_response(null, jsonrpc_error_messages.invalid_request({ reason: 'missing id query parameter' }));
221
+ const error = jsonrpc_error_envelope(null, jsonrpc_error_messages.invalid_request({ reason: 'missing id query parameter' }));
303
222
  return c.json(error, 400);
304
223
  }
305
224
  // parse integer ids so GET ?id=42 matches POST {id: 42} behavior
@@ -314,7 +233,7 @@ export const create_rpc_endpoint = (options) => {
314
233
  params = JSON.parse(params_raw);
315
234
  }
316
235
  catch {
317
- const error = jsonrpc_error_response(id, jsonrpc_error_messages.invalid_params('params query parameter is not valid JSON'));
236
+ const error = jsonrpc_error_envelope(id, jsonrpc_error_messages.invalid_params('params query parameter is not valid JSON'));
318
237
  return c.json(error, 400);
319
238
  }
320
239
  }
@@ -324,7 +243,7 @@ export const create_rpc_endpoint = (options) => {
324
243
  {
325
244
  method: 'POST',
326
245
  path: endpoint_path,
327
- auth: { type: 'none' }, // per-action auth inside dispatcher
246
+ auth: { account: 'none', actor: 'none' }, // per-action auth inside dispatcher
328
247
  handler: post_handler,
329
248
  description: `JSON-RPC 2.0 endpoint — ${actions.length} method${actions.length === 1 ? '' : 's'}`,
330
249
  input: z.null(), // dispatcher owns body parsing; rpc_endpoints surface has the real schemas
@@ -334,7 +253,7 @@ export const create_rpc_endpoint = (options) => {
334
253
  {
335
254
  method: 'GET',
336
255
  path: endpoint_path,
337
- auth: { type: 'none' }, // per-action auth inside dispatcher
256
+ auth: { account: 'none', actor: 'none' }, // per-action auth inside dispatcher
338
257
  handler: get_handler,
339
258
  description: `JSON-RPC 2.0 endpoint (cacheable reads) — ${actions.length} method${actions.length === 1 ? '' : 's'}`,
340
259
  input: z.null(), // params from query string, validated by dispatcher
@@ -23,10 +23,6 @@ export declare const ActionInitiator: z.ZodEnum<{
23
23
  backend: "backend";
24
24
  }>;
25
25
  export type ActionInitiator = z.infer<typeof ActionInitiator>;
26
- export declare const ActionAuth: z.ZodUnion<readonly [z.ZodLiteral<"public">, z.ZodLiteral<"authenticated">, z.ZodLiteral<"keeper">, z.ZodObject<{
27
- role: z.ZodString;
28
- }, z.core.$strict>]>;
29
- export type ActionAuth = z.infer<typeof ActionAuth>;
30
26
  export declare const ActionSideEffects: z.ZodBoolean;
31
27
  export type ActionSideEffects = z.infer<typeof ActionSideEffects>;
32
28
  export declare const ActionSpec: z.ZodObject<{
@@ -41,9 +37,29 @@ export declare const ActionSpec: z.ZodObject<{
41
37
  frontend: "frontend";
42
38
  backend: "backend";
43
39
  }>;
44
- auth: z.ZodNullable<z.ZodUnion<readonly [z.ZodLiteral<"public">, z.ZodLiteral<"authenticated">, z.ZodLiteral<"keeper">, z.ZodObject<{
45
- role: z.ZodString;
46
- }, z.core.$strict>]>>;
40
+ /**
41
+ * The four-axis auth shape (canonical schema in `http/auth_shape.ts`).
42
+ * `null` for `remote_notification` and `local_call` — those don't
43
+ * dispatch through the request/response auth gate.
44
+ *
45
+ * See `../http/auth_shape.ts` for the design rationale (orthogonal
46
+ * authentication / account-resolution / actor-resolution / role-and-
47
+ * credential authorization axes).
48
+ */
49
+ auth: z.ZodNullable<z.ZodObject<{
50
+ account: z.ZodEnum<{
51
+ optional: "optional";
52
+ none: "none";
53
+ required: "required";
54
+ }>;
55
+ actor: z.ZodEnum<{
56
+ optional: "optional";
57
+ none: "none";
58
+ required: "required";
59
+ }>;
60
+ roles: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
61
+ credential_types: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
62
+ }, z.core.$strict>>;
47
63
  side_effects: z.ZodBoolean;
48
64
  input: z.ZodCustom<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
49
65
  output: z.ZodCustom<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
@@ -62,7 +78,7 @@ export declare const ActionSpec: z.ZodObject<{
62
78
  * failure. Declarative metadata mirroring the `streams` precedent —
63
79
  * codegen, UI form-state matching, and docs read it off the spec instead
64
80
  * of scanning handler implementations. Reuses the same `as const` string
65
- * constants the handler throws (e.g. `ERROR_OFFER_*`) so call sites can
81
+ * constants the handler throws (e.g. `ERROR_ROLE_GRANT_OFFER_*`) so call sites can
66
82
  * import either side. Optional — actions that surface only standard
67
83
  * transport errors leave it unset.
68
84
  */
@@ -72,8 +88,9 @@ export declare const ActionSpec: z.ZodObject<{
72
88
  * actions without it skip the rate-limit hook entirely.
73
89
  *
74
90
  * - `'ip'` — keyed on the resolved client IP (`get_client_ip(c)`).
75
- * - `'account'` — keyed on the post-auth actor id (`request_context.actor.id`).
76
- * Registration-time error if paired with `auth: 'public'` (no actor).
91
+ * - `'account'` — keyed on the post-auth account id (`request_context.account.id`).
92
+ * Registration-time error if paired with `auth.account !== 'required'`
93
+ * (no account to key on).
77
94
  * - `'both'` — both checks run; either can block.
78
95
  *
79
96
  * Throttle-requests semantics — every invocation records, regardless of
@@ -112,9 +129,20 @@ export declare const RequestResponseActionSpec: z.ZodObject<{
112
129
  both: "both";
113
130
  }>>;
114
131
  kind: z.ZodDefault<z.ZodLiteral<"request_response">>;
115
- auth: z.ZodUnion<readonly [z.ZodLiteral<"public">, z.ZodLiteral<"authenticated">, z.ZodLiteral<"keeper">, z.ZodObject<{
116
- role: z.ZodString;
117
- }, z.core.$strict>]>;
132
+ auth: z.ZodObject<{
133
+ account: z.ZodEnum<{
134
+ optional: "optional";
135
+ none: "none";
136
+ required: "required";
137
+ }>;
138
+ actor: z.ZodEnum<{
139
+ optional: "optional";
140
+ none: "none";
141
+ required: "required";
142
+ }>;
143
+ roles: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
144
+ credential_types: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
145
+ }, z.core.$strict>;
118
146
  async: z.ZodDefault<z.ZodLiteral<true>>;
119
147
  }, z.core.$strict>;
120
148
  export type RequestResponseActionSpec = z.infer<typeof RequestResponseActionSpec>;
@@ -187,9 +215,20 @@ export declare const ActionSpecUnion: z.ZodUnion<readonly [z.ZodObject<{
187
215
  both: "both";
188
216
  }>>;
189
217
  kind: z.ZodDefault<z.ZodLiteral<"request_response">>;
190
- auth: z.ZodUnion<readonly [z.ZodLiteral<"public">, z.ZodLiteral<"authenticated">, z.ZodLiteral<"keeper">, z.ZodObject<{
191
- role: z.ZodString;
192
- }, z.core.$strict>]>;
218
+ auth: z.ZodObject<{
219
+ account: z.ZodEnum<{
220
+ optional: "optional";
221
+ none: "none";
222
+ required: "required";
223
+ }>;
224
+ actor: z.ZodEnum<{
225
+ optional: "optional";
226
+ none: "none";
227
+ required: "required";
228
+ }>;
229
+ roles: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
230
+ credential_types: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
231
+ }, z.core.$strict>;
193
232
  async: z.ZodDefault<z.ZodLiteral<true>>;
194
233
  }, z.core.$strict>, z.ZodObject<{
195
234
  method: z.ZodString;
@@ -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,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAItB,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,UAAU;;oBAKrB,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAC7C,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAElE,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;IAUtB;;;;;;OAMG;;IAEH;;;;;;;;OAQG;;IAEH;;;;;;;;;;;;;;;;;;OAkBG;;;;;;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,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAKtB,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"}
@@ -12,20 +12,24 @@
12
12
  */
13
13
  import { z } from 'zod';
14
14
  import { RateLimitKey } from '../http/error_schemas.js';
15
+ import { RouteAuth } from '../http/auth_shape.js';
15
16
  export const ActionKind = z.enum(['request_response', 'remote_notification', 'local_call']);
16
17
  export const ActionInitiator = z.enum(['frontend', 'backend', 'both']);
17
- export const ActionAuth = z.union([
18
- z.literal('public'),
19
- z.literal('authenticated'),
20
- z.literal('keeper'),
21
- z.strictObject({ role: z.string() }),
22
- ]);
23
18
  export const ActionSideEffects = z.boolean();
24
19
  export const ActionSpec = z.strictObject({
25
20
  method: z.string(),
26
21
  kind: ActionKind,
27
22
  initiator: ActionInitiator,
28
- auth: ActionAuth.nullable(),
23
+ /**
24
+ * The four-axis auth shape (canonical schema in `http/auth_shape.ts`).
25
+ * `null` for `remote_notification` and `local_call` — those don't
26
+ * dispatch through the request/response auth gate.
27
+ *
28
+ * See `../http/auth_shape.ts` for the design rationale (orthogonal
29
+ * authentication / account-resolution / actor-resolution / role-and-
30
+ * credential authorization axes).
31
+ */
32
+ auth: RouteAuth.nullable(),
29
33
  side_effects: ActionSideEffects,
30
34
  input: z.custom((v) => v instanceof z.ZodType),
31
35
  output: z.custom((v) => v instanceof z.ZodType),
@@ -44,7 +48,7 @@ export const ActionSpec = z.strictObject({
44
48
  * failure. Declarative metadata mirroring the `streams` precedent —
45
49
  * codegen, UI form-state matching, and docs read it off the spec instead
46
50
  * of scanning handler implementations. Reuses the same `as const` string
47
- * constants the handler throws (e.g. `ERROR_OFFER_*`) so call sites can
51
+ * constants the handler throws (e.g. `ERROR_ROLE_GRANT_OFFER_*`) so call sites can
48
52
  * import either side. Optional — actions that surface only standard
49
53
  * transport errors leave it unset.
50
54
  */
@@ -54,8 +58,9 @@ export const ActionSpec = z.strictObject({
54
58
  * actions without it skip the rate-limit hook entirely.
55
59
  *
56
60
  * - `'ip'` — keyed on the resolved client IP (`get_client_ip(c)`).
57
- * - `'account'` — keyed on the post-auth actor id (`request_context.actor.id`).
58
- * Registration-time error if paired with `auth: 'public'` (no actor).
61
+ * - `'account'` — keyed on the post-auth account id (`request_context.account.id`).
62
+ * Registration-time error if paired with `auth.account !== 'required'`
63
+ * (no account to key on).
59
64
  * - `'both'` — both checks run; either can block.
60
65
  *
61
66
  * Throttle-requests semantics — every invocation records, regardless of
@@ -72,7 +77,7 @@ export const ActionSpec = z.strictObject({
72
77
  });
73
78
  export const RequestResponseActionSpec = ActionSpec.extend({
74
79
  kind: z.literal('request_response').default('request_response'),
75
- auth: ActionAuth,
80
+ auth: RouteAuth,
76
81
  async: z.literal(true).default(true),
77
82
  });
78
83
  export const RemoteNotificationActionSpec = ActionSpec.extend({