@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
@@ -25,8 +25,10 @@ import { create_app_surface_spec, } from '../http/surface.js';
25
25
  import { apply_middleware_specs, apply_route_specs, prefix_route_specs, } from '../http/route_spec.js';
26
26
  import { check_bootstrap_status, create_bootstrap_route_specs, } from '../auth/bootstrap_routes.js';
27
27
  import { create_surface_route_spec } from '../http/common_routes.js';
28
+ import { flush_pending_effects, flush_post_commit_effects } from '../http/pending_effects.js';
28
29
  import { create_auth_middleware_specs } from '../auth/middleware.js';
29
- import { fuz_auth_guard_resolver } from '../auth/route_guards.js';
30
+ import { fuz_auth_guard_resolver } from '../auth/auth_guard_resolver.js';
31
+ import { create_fuz_authorization_handler } from '../auth/request_context.js';
30
32
  import { ERROR_PAYLOAD_TOO_LARGE } from '../http/error_schemas.js';
31
33
  import { create_rpc_endpoint } from '../actions/action_rpc.js';
32
34
  /** Default maximum request body size: 1 MiB. */
@@ -39,15 +41,15 @@ export const DEFAULT_MAX_BODY_SIZE = 1024 * 1024;
39
41
  * static serving. Database migrations belong to the backend lifecycle —
40
42
  * pass `migration_namespaces` to `create_app_backend`.
41
43
  *
42
- * When `audit_log_sse` is set, shallow-copies `backend.deps` with a composed
43
- * `on_audit_event` that fans out to the SSE registry and the original
44
- * callback — `backend.deps` itself is not mutated.
44
+ * When `audit_log_sse` is set, the SSE registry's listener is appended to
45
+ * `backend.deps.audit.on_event_chain` no shallow-copy of `AppDeps`.
45
46
  *
46
47
  * @returns assembled Hono app, backend, surface build, and bootstrap status
47
48
  */
48
49
  export const create_app_server = async (options) => {
49
50
  const { backend } = options;
50
- const { log } = backend.deps;
51
+ const { deps } = backend;
52
+ const { log } = deps;
51
53
  // Rate limiter defaults (undefined = default, null = disable)
52
54
  const ip_rate_limiter = options.ip_rate_limiter === undefined ? create_rate_limiter() : options.ip_rate_limiter;
53
55
  const login_account_rate_limiter = options.login_account_rate_limiter === undefined
@@ -65,22 +67,18 @@ export const create_app_server = async (options) => {
65
67
  const action_account_rate_limiter = options.action_account_rate_limiter === undefined
66
68
  ? create_rate_limiter(DEFAULT_ACTION_ACCOUNT_RATE_LIMIT)
67
69
  : options.action_account_rate_limiter;
68
- // Factory-managed audit SSE (shallow copy deps, no mutation of backend.deps)
70
+ // Factory-managed audit SSE appends a listener to the bound emitter's
71
+ // chain so SSE fan-out runs alongside the consumer's `on_audit_event`
72
+ // without rebuilding `AppDeps`.
69
73
  const audit_sse = options.audit_log_sse
70
74
  ? create_audit_log_sse({
71
75
  log,
72
76
  role: typeof options.audit_log_sse === 'object' ? options.audit_log_sse.role : undefined,
73
77
  })
74
78
  : null;
75
- const deps = audit_sse
76
- ? {
77
- ...backend.deps,
78
- on_audit_event: (event) => {
79
- audit_sse.on_audit_event(event);
80
- backend.deps.on_audit_event(event);
81
- },
82
- }
83
- : backend.deps;
79
+ if (audit_sse) {
80
+ deps.audit.on_event_chain.push(audit_sse.on_audit_event);
81
+ }
84
82
  // Proxy middleware
85
83
  const proxy_spec = create_proxy_middleware_spec({ ...options.proxy, log });
86
84
  // Auth middleware
@@ -215,31 +213,37 @@ export const create_app_server = async (options) => {
215
213
  log_startup_summary(surface_spec.surface, log, options.env_values);
216
214
  // Hono app assembly
217
215
  const app = new Hono();
218
- // Pending effects — collects fire-and-forget promises (audit logs, usage tracking).
219
- // In test mode, effects are awaited before the response returns.
220
- // In production, rejected effects are reported via on_effect_error.
216
+ // Two-queue side-effect flush. `pending_effects` collects eager
217
+ // fire-and-forget promises (audit emits, session touch, api-token
218
+ // usage). `post_commit_effects` collects deferred thunks pushed via
219
+ // `emit_after_commit` (WS notifications, anything that must observe a
220
+ // committed transaction). Both queues drain here, after the handler
221
+ // (and any wrapping `db.transaction`) returns. In test mode both are
222
+ // awaited before the response returns; in production, eager-queue
223
+ // rejections are reported via `on_effect_error`.
221
224
  app.use('*', async (c, next) => {
222
225
  c.set('pending_effects', []);
226
+ c.set('post_commit_effects', []);
223
227
  try {
224
228
  await next();
225
229
  }
226
230
  finally {
227
- const effects = c.var.pending_effects;
228
- if (effects.length) {
231
+ const eager = c.var.pending_effects;
232
+ const deferred = c.var.post_commit_effects;
233
+ if (eager.length || deferred.length) {
229
234
  if (options.await_pending_effects) {
230
- await Promise.allSettled(effects);
235
+ await flush_pending_effects(eager, log);
236
+ await flush_post_commit_effects(deferred, log);
231
237
  }
232
238
  else {
233
- const ctx = { method: c.req.method, path: c.req.path };
239
+ const error_ctx = { method: c.req.method, path: c.req.path };
234
240
  const callback = options.on_effect_error;
235
- void Promise.allSettled(effects).then((results) => {
236
- for (const result of results) {
237
- if (result.status === 'rejected') {
238
- log.error('Pending effect rejected:', result.reason, ctx);
239
- callback?.(result.reason, ctx);
240
- }
241
- }
242
- });
241
+ void flush_pending_effects(eager, log, callback ? (reason) => callback(reason, error_ctx) : undefined);
242
+ // `flush_post_commit_effects` is non-throwing: per-thunk
243
+ // errors are routed through `log.error` inside the helper,
244
+ // so production fire-and-forget skips the `on_effect_error`
245
+ // fan-out (deferred thunks are wrapped end-to-end already).
246
+ void flush_post_commit_effects(deferred, log);
243
247
  }
244
248
  }
245
249
  }
@@ -257,7 +261,8 @@ export const create_app_server = async (options) => {
257
261
  }));
258
262
  }
259
263
  apply_middleware_specs(app, middleware_specs);
260
- apply_route_specs(app, route_specs, fuz_auth_guard_resolver, log, deps.db);
264
+ const authorize = create_fuz_authorization_handler({ db: deps.db });
265
+ apply_route_specs(app, route_specs, fuz_auth_guard_resolver, log, deps.db, authorize);
261
266
  // Post-route middleware (before static serving)
262
267
  if (options.post_route_middleware) {
263
268
  apply_middleware_specs(app, options.post_route_middleware);
@@ -24,7 +24,7 @@ export interface NginxValidationResult {
24
24
  *
25
25
  * Checks for required security headers, Authorization stripping in `/api`
26
26
  * blocks, and the nginx `add_header` inheritance gotcha. Designed for
27
- * fuz_app consumer deploy configs (tx.ts `NGINX_CONFIG` constants).
27
+ * fuz_app consumer deploy configs (zap.ts `NGINX_CONFIG` constants).
28
28
  *
29
29
  * Limitations: string pattern matching, not a real nginx parser. Catches
30
30
  * common omissions in fuz_app deploy configs but won't catch all possible
@@ -92,7 +92,7 @@ const location_matches_api = (block) => {
92
92
  *
93
93
  * Checks for required security headers, Authorization stripping in `/api`
94
94
  * blocks, and the nginx `add_header` inheritance gotcha. Designed for
95
- * fuz_app consumer deploy configs (tx.ts `NGINX_CONFIG` constants).
95
+ * fuz_app consumer deploy configs (zap.ts `NGINX_CONFIG` constants).
96
96
  *
97
97
  * Limitations: string pattern matching, not a real nginx parser. Catches
98
98
  * common omissions in fuz_app deploy configs but won't catch all possible
@@ -36,8 +36,10 @@ module load.
36
36
  | `create_stub_db()` | Returns a real `Db` whose `client.query` yields `{rows: []}` and whose `transaction(fn)` synchronously calls `fn(inner_stub_db)`. Safe for `apply_route_specs`'s declarative transaction wrapper. |
37
37
  | `stub_handler()` | Returns a fresh `Response('stub')`. |
38
38
  | `stub_mw` | Pass-through middleware handler (`async (_c, next) => next()`). |
39
- | `stub_app_deps` | Frozen `AppDeps` — every capability is a throwing stub, `on_audit_event` is a noop. |
40
- | `create_stub_app_deps()` | Factory returning fresh `AppDeps` with no-op FS/keyring/password, a `create_noop_stub` DB, silent `Logger`. |
39
+ | `stub_app_deps` | Frozen `AppDeps` — every capability is a throwing stub, `audit` is a no-op `AuditEmitter` from `create_test_audit_emitter`. |
40
+ | `create_stub_app_deps()` | Factory returning fresh `AppDeps` with no-op FS/keyring/password, a `create_noop_stub` DB, silent `Logger`, no-op `audit`. |
41
+ | `create_test_audit_emitter()` | No-op `AuditEmitter` for tests that don't assert on audit fan-out. `emit` / `emit_role_grant_target` are no-ops; `emit_pool` resolves immediately; `notify` is a no-op; `on_event_chain` is empty. |
42
+ | `create_stub_audit_sse()` | No-op `AuditLogSse` for surface-test wiring without booting real SSE. `subscribe` returns a no-op cleanup; `on_audit_event` is a no-op; the `registry` is a fresh `SubscriberRegistry` (live `.size` / `.close_*` for tests touching registry state, isolated per call). For real SSE plumbing, build via `create_audit_log_sse` against `create_test_app`. |
41
43
  | `create_stub_api_middleware({include_daemon_token?})` | Stub `MiddlewareSpec[]` matching `create_auth_middleware_specs`'s output (origin/session/request_context/bearer_auth, optional daemon_token) for surface generation without booting real auth. See `../auth/CLAUDE.md` §Middleware for the real stack. |
42
44
  | `create_stub_app_server_context(session_options)` | Stub `AppServerContext` — rate limiters null, `bootstrap_status.available: false`, `app_settings.open_signup: false`. |
43
45
  | `create_test_app_surface_spec(options)` | Builds an `AppSurfaceSpec` that mirrors `create_app_server`'s route assembly: consumer routes + factory-managed bootstrap routes (prefixed via `bootstrap_route_prefix`, default `'/api/account'`) + stub middleware + surface generation. `CreateTestAppSurfaceSpecOptions` accepts `session_options`, `create_route_specs`, `env_schema?`, `event_specs?`, `rpc_endpoints?`, `transform_middleware?`, `bootstrap_route_prefix?`. Single source of truth for attack-surface tests — track `create_app_server` wiring changes here. |
@@ -58,14 +60,14 @@ factories.
58
60
  Override types widen branded `Uuid` fields to `string` so tests pass
59
61
  literal ids without per-site casts — the factory brands internally.
60
62
  Exported as `TestAccountOverrides` / `TestActorOverrides` /
61
- `TestPermitOverrides` / `TestAuditEventOverrides`.
63
+ `TestRoleGrantOverrides` / `TestAuditEventOverrides`.
62
64
 
63
65
  | Factory | Default id / role |
64
66
  | ------------------------------------- | --------------------------------------------------------------------------------------------- |
65
67
  | `create_test_account(overrides?)` | `{id: 'acct-test', username: 'test_user', …}` |
66
68
  | `create_test_actor(overrides?)` | `{id: 'actor-test', account_id: 'acct-test', …}` |
67
- | `create_test_permit(overrides?)` | `{id: 'permit-test', actor_id: 'actor-test', role: 'admin', scope_id: null, …}` |
68
- | `create_test_context(permits?)` | `{account, actor, permits}` — pass `[{role: 'keeper'}, {role: 'admin'}]` for multi-role. |
69
+ | `create_test_role_grant(overrides?)` | `{id: 'role-grant-test', actor_id: 'actor-test', role: 'admin', scope_id: null, …}` |
70
+ | `create_test_context(role_grants?)` | `{account, actor, role_grants}` — pass `[{role: 'keeper'}, {role: 'admin'}]` for multi-role. |
69
71
  | `create_test_audit_event(overrides?)` | `{id: 'evt-test', event_type: 'login', outcome: 'success', …}` — for SSE guard / audit tests. |
70
72
 
71
73
  ### `mock_fs.ts` — in-memory filesystem
@@ -75,6 +77,17 @@ Missing-path reads throw an `Error` with `.code = 'ENOENT'` so callers
75
77
  exercise the same branches as `node:fs`. Use for DI-based filesystem
76
78
  tests; never replaces `node:fs` globally.
77
79
 
80
+ ### `db_entities.ts` — DB-backed entity factories
81
+
82
+ `create_test_account_with_actor(db, {username, password_hash?})` wraps
83
+ `query_create_account_with_actor` with a default `password_hash` (`'hash'`).
84
+ Returns `{account, actor}`. Replaces the per-file `create_user` /
85
+ `create_test_actor` / `create_test_account` helpers that had accumulated
86
+ across the auth test suite. Use for query-level tests that need real
87
+ DB rows but not a full session/token bundle. For tests that also need
88
+ an API token + session cookie + role_grants, use `bootstrap_test_account`
89
+ from `app_server.ts` instead.
90
+
78
91
  ## Database — `db.ts`
79
92
 
80
93
  Factory builders for parameterized DB tests. Consumer projects pass their
@@ -88,7 +101,7 @@ factories accept any migration namespace set.
88
101
  | `reset_pglite(db)` | `DROP SCHEMA public CASCADE` + recreate. Reuses a live PGlite instance. |
89
102
  | `create_pglite_factory(init_schema)` | In-memory; no external deps; `skip: false`. See WASM caching below. |
90
103
  | `create_pg_factory(init_schema, test_url?)` | PostgreSQL; `skip: true` when `test_url` is missing; drops `schema_version` before `init_schema` so migrations re-evaluate against actual tables (prevents stale tracker rows from skipping migrations when DDL changes between test sessions); pool is reused + cleaned up across `create()` calls. |
91
- | `AUTH_TRUNCATE_TABLES` | `['invite', 'api_token', 'auth_session', 'permit', 'permit_offer', 'actor', 'account']` in FK-safe order. Excludes `audit_log` — unit DB tests don't need to truncate it. |
104
+ | `AUTH_TRUNCATE_TABLES` | `['invite', 'api_token', 'auth_session', 'role_grant', 'role_grant_offer', 'actor', 'account']` in FK-safe order. Excludes `audit_log` — unit DB tests don't need to truncate it. |
92
105
  | `AUTH_INTEGRATION_TRUNCATE_TABLES` | `AUTH_TRUNCATE_TABLES + ['audit_log']` — for integration suites that exercise the audit path. |
93
106
  | `AUTH_DROP_TABLES` | Full set from `AUTH_MIGRATIONS` in drop order; call `drop_auth_schema(db)` at the top of `init_schema` on persistent pg databases that may hold stale DDL from previous fuz_app versions. |
94
107
  | `drop_auth_schema(db)` | `DROP TABLE IF EXISTS <table> CASCADE` for every entry in `AUTH_DROP_TABLES` plus `schema_version`. Safe on fresh DBs. |
@@ -157,16 +170,20 @@ bind to the server's deps (db, keyring). Hono assembly is cheap
157
170
 
158
171
  Pre-built Hono apps at each auth level (public / authed / keeper / per-role)
159
172
  for attack-surface testing. No middleware stack — a single `/*` middleware
160
- injects the `REQUEST_CONTEXT_KEY` + `CREDENTIAL_TYPE_KEY` (default
161
- `'session'`) and hands off to `apply_route_specs` with
162
- `fuz_auth_guard_resolver`.
173
+ injects `ACCOUNT_ID_KEY` + `REQUEST_CONTEXT_KEY` + `CREDENTIAL_TYPE_KEY`
174
+ (default `'session'`) plus the `TEST_CONTEXT_PRESET_KEY` flag (so the
175
+ dispatcher's authorization phase trusts the pre-baked context and skips
176
+ its DB-backed actor resolution), then hands off to `apply_route_specs`
177
+ with `fuz_auth_guard_resolver` + `create_fuz_authorization_handler`.
178
+ Production middleware never sets `TEST_CONTEXT_PRESET_KEY`, so the escape
179
+ hatch is test-only by construction.
163
180
 
164
181
  | Helper | Role |
165
182
  | ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
166
- | `create_test_request_context(role?)` | Minimal `RequestContext` — one account, one actor, one permit for `role` (or none). |
183
+ | `create_test_request_context(role?)` | Minimal `RequestContext` — one account, one actor, one role_grant for `role` (or none). |
167
184
  | `create_test_app_from_specs(specs, auth_ctx?, credential_type?)` | Hono app with pre-set context + `apply_route_specs`. `credential_type` defaults to `'session'` when an auth context is supplied — override for `'daemon_token'` / `'api_token'` tests. |
168
185
  | `AuthTestApps` | `{public, authed, keeper, by_role: Map<string, Hono>}`. |
169
- | `create_auth_test_apps(specs, roles)` | Builds one app per auth level. Keeper app uses `credential_type: 'daemon_token'` so `require_keeper` passes. |
186
+ | `create_auth_test_apps(specs, roles)` | Builds one app per auth level. Keeper app uses `credential_type: 'daemon_token'` so `require_credential_types(['daemon_token'])` passes. |
170
187
  | `select_auth_app(apps, auth)` | Map `RouteAuth` → matching Hono app. Throws for missing `role:*` entries. |
171
188
  | `resolve_test_path(path)` | `:foo` → `test_foo` — adequate for routes without format-constrained params. |
172
189
 
@@ -297,20 +314,20 @@ Walks Zod schemas to generate valid values for adversarial/round-trip tests.
297
314
 
298
315
  ### `integration_helpers.ts` — route lookup + body checks
299
316
 
300
- | Helper | Role |
301
- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
302
- | `find_route_spec(specs, method, path)` | Exact match then parameterized match (`:foo` matches any segment). |
303
- | `find_auth_route(specs, suffix, method)` | Suffix-ending match for REST auth routes — decouples tests from consumer prefix. `suffix` is typed as `RestAuthRouteSuffix` and throws at runtime on unknown values (post-RPC-migration, only login/logout/password/verify/signup/bootstrap remain). |
304
- | `assert_response_matches_spec(specs, method, path, response)` | 2xx → validates against `spec.output`; non-2xx → validates against merged error schemas for that status. Non-JSON responses allowed only when no schema applies. |
305
- | `create_expired_test_cookie(keyring, session_options)` | Validly signed cookie with `expires_at` in 1970. |
306
- | `check_error_response_fields(body)` | Returns the list of fields outside `KNOWN_SAFE_ERROR_FIELDS` (`error`, `issues`, `required_role`, `retry_after`, `credential_type`, `has_references`, `ok`). |
307
- | `assert_no_error_info_leakage(body, context)` | Rejects field-name patterns (`stack`, `trace`, `sql`, …) + value patterns (`node_modules`, stack-like `at …`, `.ts:NN`). |
308
- | `assert_rate_limit_retry_after_header(response, body)` | `Retry-After` numeric header equals `Math.ceil(body.retry_after)`. |
309
- | `SENSITIVE_FIELD_BLOCKLIST` | `['password_hash', 'token_hash']` — never in any response body. |
310
- | `ADMIN_ONLY_FIELD_BLOCKLIST` | `['updated_by', 'created_by']` — never in non-admin response bodies. |
311
- | `collect_json_keys_recursive(value)` | Deep walk; returns `Set<string>` of every key at every nesting depth. |
312
- | `assert_no_sensitive_fields_in_json(body, blocklist, context)` | Rejects any key in the blocklist at any depth. |
313
- | `pick_auth_headers(spec, test_app, authed_account, admin_account)` | `RouteAuth` → appropriate test credentials; role `admin` uses `admin_account`, other roles use bootstrapped keeper, `keeper` uses daemon token. |
317
+ | Helper | Role |
318
+ | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
319
+ | `find_route_spec(specs, method, path)` | Exact match then parameterized match (`:foo` matches any segment). |
320
+ | `find_auth_route(specs, suffix, method)` | Suffix-ending match for REST auth routes — decouples tests from consumer prefix. `suffix` is typed as `RestAuthRouteSuffix` and throws at runtime on unknown values (only login/logout/password/verify/signup/bootstrap remain on REST). |
321
+ | `assert_response_matches_spec(specs, method, path, response)` | 2xx → validates against `spec.output`; non-2xx → validates against merged error schemas for that status. Non-JSON responses allowed only when no schema applies. |
322
+ | `create_expired_test_cookie(keyring, session_options)` | Validly signed cookie with `expires_at` in 1970. |
323
+ | `check_error_response_fields(body)` | Returns the list of fields outside `KNOWN_SAFE_ERROR_FIELDS` (`error`, `issues`, `required_roles`, `required_credential_types`, `retry_after`, `has_references`, `ok`). |
324
+ | `assert_no_error_info_leakage(body, context)` | Rejects field-name patterns (`stack`, `trace`, `sql`, …) + value patterns (`node_modules`, stack-like `at …`, `.ts:NN`). |
325
+ | `assert_rate_limit_retry_after_header(response, body)` | `Retry-After` numeric header equals `Math.ceil(body.retry_after)`. |
326
+ | `SENSITIVE_FIELD_BLOCKLIST` | `['password_hash', 'token_hash']` — never in any response body. |
327
+ | `ADMIN_ONLY_FIELD_BLOCKLIST` | `['updated_by', 'created_by']` — never in non-admin response bodies. |
328
+ | `collect_json_keys_recursive(value)` | Deep walk; returns `Set<string>` of every key at every nesting depth. |
329
+ | `assert_no_sensitive_fields_in_json(body, blocklist, context)` | Rejects any key in the blocklist at any depth. |
330
+ | `pick_auth_headers(spec, test_app, authed_account, admin_account)` | `RouteAuth` → appropriate test credentials; role `admin` uses `admin_account`, other roles use bootstrapped keeper, `keeper` uses daemon token. |
314
331
 
315
332
  ## Attack surface suites
316
333
 
@@ -383,28 +400,30 @@ validation. Extra cases append to the standard list.
383
400
  ## Middleware stack — `middleware.ts`
384
401
 
385
402
  Module-level `vi.mock()` for the four query modules bearer auth touches:
386
- `api_token_queries`, `account_queries`, `permit_queries`. Because
403
+ `api_token_queries`, `account_queries`, `role_grant_queries`. Because
387
404
  `vi.mock()` is hoisted, these run before any imports resolve — so any
388
405
  test file that imports from `middleware.ts` gets these mocks globally.
389
406
  Pair with `vi.restoreAllMocks()` in `afterEach` when mixing into
390
407
  `.db.test.ts` files (see DB test caveat below).
391
408
 
392
- | Helper | Role |
393
- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
394
- | `BearerAuthTestOptions`, `BearerAuthTestCase` | Test-case table shape for the bearer auth runner. |
395
- | `create_bearer_auth_mocks(tc)` | Configures the module-level mocks per test case; returns spy references. |
396
- | `TEST_CLIENT_IP = '127.0.0.1'` | IP set by the proxy stub in `create_bearer_auth_test_app`. |
397
- | `create_bearer_auth_test_app(tc, ip_rate_limiter?)` | Hono app with bearer middleware + echo route at `/api/test` returning `{ok, has_context, credential_type, account_id, actor_id, permit_count, api_token_id}`. |
398
- | `describe_bearer_auth_cases(suite_name, cases, ip_rate_limiter?)` | Table-driven runner — one `test()` per case; asserts status, error, body fields, `api_token_id`, context preservation. |
399
- | `TEST_MIDDLEWARE_PATH = '/api/test'` | Path used by the echo route in the stack factory. |
400
- | `create_test_middleware_stack_app(options?)` | Real proxy + origin + bearer middleware for integration-shape testing. Echo route returns `{ok, client_ip, has_context}`. |
409
+ | Helper | Role |
410
+ | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
411
+ | `BearerAuthTestOptions`, `BearerAuthTestCase` | Test-case table shape for the bearer auth runner. |
412
+ | `create_bearer_auth_mocks(tc)` | Configures the module-level mocks per test case; returns spy references. |
413
+ | `TEST_CLIENT_IP = '127.0.0.1'` | IP set by the proxy stub in `create_bearer_auth_test_app`. |
414
+ | `create_bearer_auth_test_app(tc, ip_rate_limiter?)` | Hono app with bearer middleware + echo route at `/api/test` returning `{ok, account_id, credential_type, api_token_id, request_context_set}` — the account-grain identity bearer auth writes, plus a flag for tests that pre-populate `REQUEST_CONTEXT_KEY` via `pre_context`. |
415
+ | `describe_bearer_auth_cases(suite_name, cases, ip_rate_limiter?)` | Table-driven runner — one `test()` per case; asserts status, error, body fields, `api_token_id`, context preservation. |
416
+ | `TEST_MIDDLEWARE_PATH = '/api/test'` | Path used by the echo route in the stack factory. |
417
+ | `create_test_middleware_stack_app(options?)` | Real proxy + origin + bearer middleware for integration-shape testing. Echo route returns `{ok, client_ip, has_context}`. |
401
418
 
402
419
  The echo route under `create_bearer_auth_test_app` deliberately surfaces
403
- every middleware-written context variable (`REQUEST_CONTEXT_KEY`,
404
- `CREDENTIAL_TYPE_KEY`, `AUTH_API_TOKEN_ID_KEY`). When public auth surface
405
- gains a new context variable, header, or field, update this echo
406
- alongside the assertions in `src/test/auth/*.test.ts` the two move
407
- together.
420
+ every middleware-written context variable (`ACCOUNT_ID_KEY`,
421
+ `CREDENTIAL_TYPE_KEY`, `AUTH_API_TOKEN_ID_KEY`) bearer middleware
422
+ writes account-grain identity only; the dispatcher's authorization phase
423
+ owns `REQUEST_CONTEXT_KEY`. The `request_context_set` flag covers the
424
+ test-only `pre_context` injection path. When public auth surface gains a
425
+ new context variable, header, or field, update this echo alongside the
426
+ assertions in `src/test/auth/*.test.ts` — the two move together.
408
427
 
409
428
  ## Round-trip suites
410
429
 
@@ -464,7 +483,7 @@ Three layers:
464
483
  1. **Primitives** — `create_fake_ws()`, `create_fake_hono_context(opts)`,
465
484
  `create_stub_upgrade()`, `MinimalActionEnvironment`,
466
485
  `dispatch_ws_message(on_message, event, ws)`.
467
- 2. **Harness** — `create_ws_test_harness<TCtx>({actions, extend_context?, transport?, heartbeat?, log?, on_socket_open?, on_socket_close?})` → `WsTestHarness`. `connect(identity?)` is async and resolves after `on_socket_open` completes, so broadcasts sent immediately after `await harness.connect()` reach the client.
486
+ 2. **Harness** — `create_ws_test_harness({actions, transport?, heartbeat?, log?, on_socket_open?, on_socket_close?})` → `WsTestHarness`. `connect(identity?)` is async and resolves after `on_socket_open` completes, so broadcasts sent immediately after `await harness.connect()` reach the client. The harness threads its own `create_stub_db()` into the dispatcher's `db` slot so handlers declaring `side_effects: true` execute under the same transaction wrap they would in production (the stub's `transaction(fn)` synchronously calls `fn(stub_db)`); domain deps reach handlers via factory closures, the same way HTTP RPC factories already wire them. Audit fan-out runs through whatever `audit` emitter the consumer supplied to its action factory closure (typically `create_test_audit_emitter()` for unit harnesses).
468
487
  3. **Round-trip helpers** — `is_notification(method)`,
469
488
  `is_notification_with<P>(method, match)` (type-guard combinator —
470
489
  narrows `wait_for` return type), `is_response_for(id)`.
@@ -551,9 +570,9 @@ Options: `{session_options, create_route_specs, app_options?, db_factories?}`.
551
570
 
552
571
  ### `admin_integration.ts` — `describe_standard_admin_integration_tests`
553
572
 
554
- 7 test groups covering admin surface: account listing, permit grant
555
- lifecycle (via `permit_offer_create` + `permit_revoke` RPC flows —
556
- **not** REST; see `../auth/CLAUDE.md` for `permit_offer_action_specs.ts` + `permit_offer_actions.ts`), session / token management, audit log reads (RPC),
573
+ 7 test groups covering admin surface: account listing, role_grant grant
574
+ lifecycle (via `role_grant_offer_create` + `role_grant_revoke` RPC flows —
575
+ **not** REST; see `../auth/CLAUDE.md` for `role_grant_offer_action_specs.ts` + `role_grant_offer_actions.ts`), session / token management, audit log reads (RPC),
557
576
  admin-to-admin isolation, error coverage, response schema validation.
558
577
 
559
578
  Required options: `{session_options, create_route_specs, roles: RoleSchemaResult, rpc_endpoints: RpcEndpointsSuiteOption, admin_prefix?, app_options?, db_factories?}`.
@@ -571,22 +590,21 @@ once with a stub ctx for path lookup and `create_app_server` invokes it
571
590
  again per-test for live dispatch.
572
591
 
573
592
  **Hard-fails via `require_rpc_endpoint_path`** at setup time when
574
- `rpc_endpoints` is empty — admin permit grant/revoke plus session/token
575
- revoke-all plus audit-log list/history are all RPC-only since the
576
- 2026-04-22 migration. A confusing test failure mid-suite is worse than a
577
- clear setup error.
593
+ `rpc_endpoints` is empty — admin role_grant grant/revoke plus session/token
594
+ revoke-all plus audit-log list/history are RPC-only. A confusing test
595
+ failure mid-suite is worse than a clear setup error.
578
596
 
579
597
  The suite also exercises `account_token_create` (and
580
598
  `account_token_revoke`) for the cross-admin isolation + audit-trail
581
- scenarios. Wire the account actions alongside admin / permit-offer —
599
+ scenarios. Wire the account actions alongside admin / role-grant-offer —
582
600
  the easiest path is `create_standard_rpc_actions`, which bundles all
583
601
  three. Consumers that only wire admin will hit `method not found:
584
602
  account_token_create` on first run.
585
603
 
586
604
  Error-coverage scope is narrowed to the REST suffixes still on the
587
605
  admin surface (`/audit/stream`); the RPC surface is covered by
588
- `describe_rpc_round_trip_tests`. Post-RPC-migration that surface is
589
- 0–1 routes — when the scoped count is ≤1, the `afterAll` hook logs
606
+ `describe_rpc_round_trip_tests`. The scoped REST surface is 0–1
607
+ routes — when the scoped count is ≤1, the `afterAll` hook logs
590
608
  `[error coverage] skipped admin REST coverage assertion — …` and
591
609
  does not fail. The 20% `DEFAULT_INTEGRATION_ERROR_COVERAGE` baseline
592
610
  is a REST-era threshold; the RPC surface has its own coverage via
@@ -599,9 +617,9 @@ branch.
599
617
  Verifies every auth mutation produces the expected `audit_log` row by
600
618
  querying the table after each request. Uses the real middleware stack.
601
619
  Same `rpc_endpoints` hard-fail as the admin suite — the mutation-audit
602
- tests drive permit flow, session/token revoke-all, and invite
603
- create/delete through `permit_offer_create_action_spec` /
604
- `permit_revoke_action_spec` / `admin_session_revoke_all_action_spec` /
620
+ tests drive role_grant flow, session/token revoke-all, and invite
621
+ create/delete through `role_grant_offer_create_action_spec` /
622
+ `role_grant_revoke_action_spec` / `admin_session_revoke_all_action_spec` /
605
623
  `admin_token_revoke_all_action_spec` / `app_settings_update_action_spec` /
606
624
  `invite_create_action_spec` / `invite_delete_action_spec`.
607
625
 
@@ -670,7 +688,7 @@ Registry lookups:
670
688
  - unauthenticated → `unauthenticated` (code -32001)
671
689
  - wrong role → `forbidden` (-32002)
672
690
  - authenticated without role → `forbidden`
673
- - **keeper rejects non-daemon credentials** — session and api_token credentials are rejected even when the account has the keeper role (only `daemon_token` passes). Mirrors `require_keeper`'s two-part guard (see `../auth/CLAUDE.md` for `require_keeper.ts`).
691
+ - **keeper rejects non-daemon credentials** — session and api_token credentials are rejected even when the account has the keeper role (only `daemon_token` passes). The credential-type gate fires before the role gate (see `../auth/CLAUDE.md` §`request_context.ts` for `require_credential_types`).
674
692
  - correct auth passes (not 401/403)
675
693
  - GET unauthenticated for `side_effects: false` reads
676
694
  2. **RPC adversarial envelopes** — fixed set exercising dispatcher steps 1–2: non-JSON body, wrong `jsonrpc` version, missing `jsonrpc` / `method` / `id`, batch array, unknown method, GET missing `method`/`id`, GET invalid JSON params, GET non-object params, GET mutation method → `invalid_request`.
@@ -17,7 +17,7 @@ export interface StandardAdminIntegrationTestOptions {
17
17
  /** Role schema result from `create_role_schema()` — used to determine valid/invalid/web-grantable roles. */
18
18
  roles: RoleSchemaResult;
19
19
  /**
20
- * RPC endpoint specs — the source `RpcAction` arrays. Required; permit
20
+ * RPC endpoint specs — the source `RpcAction` arrays. Required; role_grant
21
21
  * grant/revoke are RPC-only and the suite hard-fails without them.
22
22
  *
23
23
  * Accepts either an array (eager) or a factory
@@ -48,17 +48,16 @@ export interface StandardAdminIntegrationTestOptions {
48
48
  /**
49
49
  * Standard admin integration test suite for fuz_app admin routes.
50
50
  *
51
- * Exercises account listing, permit grant/revoke (via RPC), session
51
+ * Exercises account listing, role_grant grant/revoke (via RPC), session
52
52
  * management, token management, audit log reads, admin-to-admin
53
53
  * isolation, and 401/403 error-coverage on the admin REST surface.
54
54
  * Output-schema conformance is not in scope — see the module docstring
55
55
  * for the suites that cover it.
56
56
  *
57
57
  * @throws Error at setup time when `options.rpc_endpoints` is empty — admin
58
- * permit grant/revoke, session/token revoke-all, and audit-log reads are
59
- * all RPC-only since the 2026-04-22 migration. Hard-fails via
60
- * `require_rpc_endpoint_path` so consumers see a clear setup error rather
61
- * than `method not found` mid-suite.
58
+ * role_grant grant/revoke, session/token revoke-all, and audit-log reads
59
+ * are RPC-only. Hard-fails via `require_rpc_endpoint_path` so consumers
60
+ * see a clear setup error rather than `method not found` mid-suite.
62
61
  */
63
62
  export declare const describe_standard_admin_integration_tests: (options: StandardAdminIntegrationTestOptions) => void;
64
63
  //# sourceMappingURL=admin_integration.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"admin_integration.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/admin_integration.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAgC7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAA0B,KAAK,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;AAEtF,OAAO,EAA6C,KAAK,eAAe,EAAC,MAAM,iBAAiB,CAAC;AACjG,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,SAAS,CAAC;AASjB,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAqB1B;;GAEG;AACH,MAAM,WAAW,mCAAmC;IACnD,4CAA4C;IAC5C,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,wDAAwD;IACxD,kBAAkB,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE,4GAA4G;IAC5G,KAAK,EAAE,gBAAgB,CAAC;IACxB;;;;;;;;;;;;OAYG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B;;;OAGG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;CAChC;AAgCD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,yCAAyC,GACrD,SAAS,mCAAmC,KAC1C,IAu1BF,CAAC"}
1
+ {"version":3,"file":"admin_integration.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/admin_integration.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAgC7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAA0B,KAAK,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;AAGtF,OAAO,EAA6C,KAAK,eAAe,EAAC,MAAM,iBAAiB,CAAC;AACjG,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,SAAS,CAAC;AASjB,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAoB1B;;GAEG;AACH,MAAM,WAAW,mCAAmC;IACnD,4CAA4C;IAC5C,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,wDAAwD;IACxD,kBAAkB,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE,4GAA4G;IAC5G,KAAK,EAAE,gBAAgB,CAAC;IACxB;;;;;;;;;;;;OAYG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B;;;OAGG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;CAChC;AAmCD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yCAAyC,GACrD,SAAS,mCAAmC,KAC1C,IA+1BF,CAAC"}