@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
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Auth guard resolver for the route spec system.
3
+ *
4
+ * Maps the four-axis `RouteAuth` (`account` / `actor` / `roles` /
5
+ * `credential_types`) to two-phase middleware sets that
6
+ * `apply_route_specs` weaves into the per-route pipeline:
7
+ *
8
+ * - `pre_validation` runs before input validation. `require_auth` lands
9
+ * here whenever `auth.account === 'required'` or `auth.actor ===
10
+ * 'required'` (per registry-time invariant 3, `actor: 'required'`
11
+ * today implies a credential — accountless actors are out of scope
12
+ * for v1). Pre-validation 401 fires before any body parsing so
13
+ * unauthenticated callers never see route-shape information from
14
+ * parse failures.
15
+ * - `post_authorization` runs after the dispatcher's authorization
16
+ * phase has populated `RequestContext`. `require_role(roles)` fires
17
+ * whenever `auth.roles?.length`. `require_credential_types(types)`
18
+ * fires whenever `auth.credential_types?.length`.
19
+ *
20
+ * Public routes (`auth.account === 'none' && auth.actor === 'none'`)
21
+ * yield empty guard arrays. `'optional'` axes contribute no
22
+ * pre-validation 401; the authorization phase sets `RequestContext`
23
+ * to whatever the credential supports and the post-authorization
24
+ * gates decide whether the actor's role_grants / credential type match.
25
+ *
26
+ * @module
27
+ */
28
+ import { require_auth, require_credential_types, require_role } from './request_context.js';
29
+ /**
30
+ * Standard auth guard resolver for fuz_app.
31
+ *
32
+ * Reads each axis of the four-axis `RouteAuth` shape and emits the
33
+ * corresponding middleware:
34
+ *
35
+ * - `account === 'required'` or `actor === 'required'` → pre-validation `require_auth`
36
+ * - `roles?.length` → post-authorization `require_role(roles)` (multi-role any-of)
37
+ * - `credential_types?.length` → post-authorization `require_credential_types(types)`
38
+ *
39
+ * Multiple post-authorization guards run in declaration order: credential
40
+ * type check first (since failing it implies the request can never
41
+ * resolve a usable identity), role check second.
42
+ */
43
+ export const fuz_auth_guard_resolver = (auth) => {
44
+ const pre_validation = [];
45
+ const post_authorization = [];
46
+ if (auth.account === 'required' || auth.actor === 'required') {
47
+ pre_validation.push(require_auth);
48
+ }
49
+ if (auth.credential_types?.length) {
50
+ post_authorization.push(require_credential_types(auth.credential_types));
51
+ }
52
+ if (auth.roles?.length) {
53
+ post_authorization.push(require_role(auth.roles));
54
+ }
55
+ return { pre_validation, post_authorization };
56
+ };
@@ -18,18 +18,20 @@ import { type RateLimiter } from '../rate_limiter.js';
18
18
  * Create middleware that authenticates via bearer token.
19
19
  *
20
20
  * Soft-fails for invalid, expired, or empty tokens — calls `next()` without
21
- * setting a request context, letting downstream auth enforcement (per-action
22
- * `check_action_auth` or `require_auth`) return a consistent JSON-RPC or
23
- * route-level error. This avoids leaking token-specific diagnostics
21
+ * setting account identity, letting downstream auth enforcement (the RPC
22
+ * dispatcher's pre-validation / post-authorization auth gates or
23
+ * `require_auth`) return a consistent JSON-RPC or route-level error. This
24
+ * avoids leaking token-specific diagnostics
24
25
  * (`invalid_token`, `account_not_found`) that could aid enumeration attacks,
25
26
  * and ensures public actions are not blocked by bad credentials.
26
27
  *
27
28
  * Rejects bearer tokens when an `Origin` or `Referer` header is present —
28
29
  * browsers must use cookie auth to reduce attack surface.
29
30
  * Auth scheme matching is case-insensitive per RFC 7235.
30
- * On success, builds the request context (`{ account, actor, permits }`)
31
- * and sets it on the Hono context. Skips if a request context is already set
32
- * (e.g. by session middleware).
31
+ * On success, sets `c.var.auth_account_id`, `CREDENTIAL_TYPE_KEY = 'api_token'`,
32
+ * and `AUTH_API_TOKEN_ID_KEY`. Skips when an account is already authenticated
33
+ * (e.g. by session middleware). Acting-actor resolution + `RequestContext`
34
+ * construction are deferred to the dispatcher's authorization phase.
33
35
  *
34
36
  * Rate limiting (429) is the only hard-fail — it's a throttling concern
35
37
  * independent of auth identity.
@@ -37,7 +39,7 @@ import { type RateLimiter } from '../rate_limiter.js';
37
39
  * @param deps - query dependencies (pool-level db for middleware)
38
40
  * @param ip_rate_limiter - per-IP rate limiter for bearer token attempts (null to disable)
39
41
  * @param log - the logger instance
40
- * @mutates Hono context - sets `REQUEST_CONTEXT_KEY`, `CREDENTIAL_TYPE_KEY`, and `AUTH_API_TOKEN_ID_KEY` on success
42
+ * @mutates Hono context - sets `ACCOUNT_ID_KEY`, `CREDENTIAL_TYPE_KEY`, and `AUTH_API_TOKEN_ID_KEY` on success
41
43
  * @mutates `ip_rate_limiter` - records on attempt; resets on a valid token
42
44
  */
43
45
  export declare const create_bearer_auth_middleware: (deps: QueryDeps, ip_rate_limiter: RateLimiter | null, log: Logger) => MiddlewareHandler;
@@ -1 +1 @@
1
- {"version":3,"file":"bearer_auth.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/bearer_auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,MAAM,CAAC;AAC5C,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAKpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAA+B,KAAK,WAAW,EAAC,MAAM,oBAAoB,CAAC;AAElF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,6BAA6B,GACzC,MAAM,SAAS,EACf,iBAAiB,WAAW,GAAG,IAAI,EACnC,KAAK,MAAM,KACT,iBAsFF,CAAC"}
1
+ {"version":3,"file":"bearer_auth.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/bearer_auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,MAAM,CAAC;AAC5C,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAIpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAA+B,KAAK,WAAW,EAAC,MAAM,oBAAoB,CAAC;AAElF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,6BAA6B,GACzC,MAAM,SAAS,EACf,iBAAiB,WAAW,GAAG,IAAI,EACnC,KAAK,MAAM,KACT,iBA4EF,CAAC"}
@@ -10,8 +10,7 @@
10
10
  *
11
11
  * @module
12
12
  */
13
- import { REQUEST_CONTEXT_KEY, build_request_context } from './request_context.js';
14
- import { AUTH_API_TOKEN_ID_KEY, CREDENTIAL_TYPE_KEY } from '../hono_context.js';
13
+ import { AUTH_API_TOKEN_ID_KEY, ACCOUNT_ID_KEY, CREDENTIAL_TYPE_KEY } from '../hono_context.js';
15
14
  import { query_validate_api_token } from './api_token_queries.js';
16
15
  import { get_client_ip } from '../http/proxy.js';
17
16
  import { rate_limit_exceeded_response } from '../rate_limiter.js';
@@ -19,18 +18,20 @@ import { rate_limit_exceeded_response } from '../rate_limiter.js';
19
18
  * Create middleware that authenticates via bearer token.
20
19
  *
21
20
  * Soft-fails for invalid, expired, or empty tokens — calls `next()` without
22
- * setting a request context, letting downstream auth enforcement (per-action
23
- * `check_action_auth` or `require_auth`) return a consistent JSON-RPC or
24
- * route-level error. This avoids leaking token-specific diagnostics
21
+ * setting account identity, letting downstream auth enforcement (the RPC
22
+ * dispatcher's pre-validation / post-authorization auth gates or
23
+ * `require_auth`) return a consistent JSON-RPC or route-level error. This
24
+ * avoids leaking token-specific diagnostics
25
25
  * (`invalid_token`, `account_not_found`) that could aid enumeration attacks,
26
26
  * and ensures public actions are not blocked by bad credentials.
27
27
  *
28
28
  * Rejects bearer tokens when an `Origin` or `Referer` header is present —
29
29
  * browsers must use cookie auth to reduce attack surface.
30
30
  * Auth scheme matching is case-insensitive per RFC 7235.
31
- * On success, builds the request context (`{ account, actor, permits }`)
32
- * and sets it on the Hono context. Skips if a request context is already set
33
- * (e.g. by session middleware).
31
+ * On success, sets `c.var.auth_account_id`, `CREDENTIAL_TYPE_KEY = 'api_token'`,
32
+ * and `AUTH_API_TOKEN_ID_KEY`. Skips when an account is already authenticated
33
+ * (e.g. by session middleware). Acting-actor resolution + `RequestContext`
34
+ * construction are deferred to the dispatcher's authorization phase.
34
35
  *
35
36
  * Rate limiting (429) is the only hard-fail — it's a throttling concern
36
37
  * independent of auth identity.
@@ -38,13 +39,13 @@ import { rate_limit_exceeded_response } from '../rate_limiter.js';
38
39
  * @param deps - query dependencies (pool-level db for middleware)
39
40
  * @param ip_rate_limiter - per-IP rate limiter for bearer token attempts (null to disable)
40
41
  * @param log - the logger instance
41
- * @mutates Hono context - sets `REQUEST_CONTEXT_KEY`, `CREDENTIAL_TYPE_KEY`, and `AUTH_API_TOKEN_ID_KEY` on success
42
+ * @mutates Hono context - sets `ACCOUNT_ID_KEY`, `CREDENTIAL_TYPE_KEY`, and `AUTH_API_TOKEN_ID_KEY` on success
42
43
  * @mutates `ip_rate_limiter` - records on attempt; resets on a valid token
43
44
  */
44
45
  export const create_bearer_auth_middleware = (deps, ip_rate_limiter, log) => {
45
46
  return async (c, next) => {
46
- // Skip if already authenticated via session
47
- if (c.get(REQUEST_CONTEXT_KEY)) {
47
+ // Skip if an account is already authenticated (e.g. by session middleware)
48
+ if (c.get(ACCOUNT_ID_KEY) != null) {
48
49
  await next();
49
50
  return;
50
51
  }
@@ -97,16 +98,7 @@ export const create_bearer_auth_middleware = (deps, ip_rate_limiter, log) => {
97
98
  // Valid token — reset rate limit counter
98
99
  if (ip_rate_limiter)
99
100
  ip_rate_limiter.reset(ip);
100
- // Build request context from the token's account
101
- const ctx = await build_request_context(deps, api_token.account_id);
102
- if (!ctx) {
103
- // Token exists but account/actor missing — soft-fail to avoid
104
- // leaking account lifecycle information.
105
- log.debug('bearer auth soft-fail: account or actor not found for token');
106
- await next();
107
- return;
108
- }
109
- c.set(REQUEST_CONTEXT_KEY, ctx);
101
+ c.set(ACCOUNT_ID_KEY, api_token.account_id);
110
102
  c.set(CREDENTIAL_TYPE_KEY, 'api_token');
111
103
  c.set(AUTH_API_TOKEN_ID_KEY, api_token.id);
112
104
  await next();
@@ -9,7 +9,7 @@
9
9
  import type { Logger } from '@fuzdev/fuz_util/log.js';
10
10
  import type { PasswordHashDeps } from './password.js';
11
11
  import { ERROR_INVALID_TOKEN, ERROR_ALREADY_BOOTSTRAPPED, ERROR_TOKEN_FILE_MISSING } from '../http/error_schemas.js';
12
- import type { Account, Actor, Permit } from './account_schema.js';
12
+ import type { Account, Actor, RoleGrant } from './account_schema.js';
13
13
  import type { Db } from '../db/db.js';
14
14
  /** Input for the bootstrap account creation. */
15
15
  export interface BootstrapAccountInput {
@@ -21,9 +21,9 @@ export interface BootstrapAccountSuccess {
21
21
  ok: true;
22
22
  account: Account;
23
23
  actor: Actor;
24
- permits: {
25
- keeper: Permit;
26
- admin: Permit;
24
+ role_grants: {
25
+ keeper: RoleGrant;
26
+ admin: RoleGrant;
27
27
  };
28
28
  /** Whether the bootstrap token file was successfully deleted after account creation. */
29
29
  token_file_deleted: boolean;
@@ -70,15 +70,15 @@ export interface BootstrapAccountDeps {
70
70
  * 2. Hash the password (CPU-intensive, before transaction)
71
71
  * 3. Acquire the bootstrap lock atomically (inside transaction)
72
72
  * 4. Create account + actor
73
- * 5. Grant keeper and admin permits (no expiry, `granted_by = null`)
73
+ * 5. Grant keeper and admin role_grants (no expiry, `granted_by = null`)
74
74
  * 6. Delete the token file (after commit, reported via `token_file_deleted`)
75
75
  *
76
76
  * @param deps - database, token path, filesystem callbacks, and password hashing
77
77
  * @param provided_token - the bootstrap token from the user
78
78
  * @param input - username and password
79
- * @returns the created account, actor, and permits — or a bootstrap failure
79
+ * @returns the created account, actor, and role_grants — or a bootstrap failure
80
80
  * @mutates `bootstrap_lock` row - flips `bootstrapped` to `true` atomically
81
- * @mutates `account` / `actor` / `permit` tables - inserts the bootstrap account, actor, and the keeper + admin permits
81
+ * @mutates `account` / `actor` / `role_grant` tables - inserts the bootstrap account, actor, and the keeper + admin role_grants
82
82
  * @mutates filesystem - deletes the bootstrap token file after commit (reported via `token_file_deleted`)
83
83
  */
84
84
  export declare const bootstrap_account: (deps: BootstrapAccountDeps, provided_token: string, input: BootstrapAccountInput) => Promise<BootstrapAccountResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"bootstrap_account.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/bootstrap_account.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,eAAe,CAAC;AACpD,OAAO,EACN,mBAAmB,EACnB,0BAA0B,EAC1B,wBAAwB,EACxB,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAC,MAAM,qBAAqB,CAAC;AAGhE,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,aAAa,CAAC;AAEpC,gDAAgD;AAChD,MAAM,WAAW,qBAAqB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,6DAA6D;AAC7D,MAAM,WAAW,uBAAuB;IACvC,EAAE,EAAE,IAAI,CAAC;IACT,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,EAAE;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CAAC;IACzC,wFAAwF;IACxF,kBAAkB,EAAE,OAAO,CAAC;CAC5B;AAED,gCAAgC;AAChC,MAAM,MAAM,uBAAuB,GAChC;IAAC,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,0BAA0B,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAC,GAClE;IAAC,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,wBAAwB,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAC,GAChE;IAAC,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,mBAAmB,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAC,CAAC;AAE/D,qFAAqF;AACrF,MAAM,MAAM,sBAAsB,GAAG,uBAAuB,GAAG,uBAAuB,CAAC;AAEvF;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC,EAAE,EAAE,EAAE,CAAC;IACP,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,qBAAqB;IACrB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,6EAA6E;IAC7E,QAAQ,EAAE,IAAI,CAAC,gBAAgB,EAAE,eAAe,CAAC,CAAC;IAClD,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAC;CACZ;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,iBAAiB,GAC7B,MAAM,oBAAoB,EAC1B,gBAAgB,MAAM,EACtB,OAAO,qBAAqB,KAC1B,OAAO,CAAC,sBAAsB,CA4EhC,CAAC"}
1
+ {"version":3,"file":"bootstrap_account.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/bootstrap_account.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,eAAe,CAAC;AACpD,OAAO,EACN,mBAAmB,EACnB,0BAA0B,EAC1B,wBAAwB,EACxB,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAGnE,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,aAAa,CAAC;AAEpC,gDAAgD;AAChD,MAAM,WAAW,qBAAqB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,6DAA6D;AAC7D,MAAM,WAAW,uBAAuB;IACvC,EAAE,EAAE,IAAI,CAAC;IACT,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;IACb,WAAW,EAAE;QAAC,MAAM,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAC,CAAC;IACnD,wFAAwF;IACxF,kBAAkB,EAAE,OAAO,CAAC;CAC5B;AAED,gCAAgC;AAChC,MAAM,MAAM,uBAAuB,GAChC;IAAC,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,0BAA0B,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAC,GAClE;IAAC,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,wBAAwB,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAC,GAChE;IAAC,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,mBAAmB,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAC,CAAC;AAE/D,qFAAqF;AACrF,MAAM,MAAM,sBAAsB,GAAG,uBAAuB,GAAG,uBAAuB,CAAC;AAEvF;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC,EAAE,EAAE,EAAE,CAAC;IACP,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,qBAAqB;IACrB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,6EAA6E;IAC7E,QAAQ,EAAE,IAAI,CAAC,gBAAgB,EAAE,eAAe,CAAC,CAAC;IAClD,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAC;CACZ;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,iBAAiB,GAC7B,MAAM,oBAAoB,EAC1B,gBAAgB,MAAM,EACtB,OAAO,qBAAqB,KAC1B,OAAO,CAAC,sBAAsB,CA4EhC,CAAC"}
@@ -10,7 +10,7 @@ import { timingSafeEqual } from 'node:crypto';
10
10
  import { ERROR_INVALID_TOKEN, ERROR_ALREADY_BOOTSTRAPPED, ERROR_TOKEN_FILE_MISSING, } from '../http/error_schemas.js';
11
11
  import { ROLE_ADMIN, ROLE_KEEPER } from './role_schema.js';
12
12
  import { query_create_account_with_actor, query_account_has_any } from './account_queries.js';
13
- import { query_grant_permit } from './permit_queries.js';
13
+ import { query_create_role_grant } from './role_grant_queries.js';
14
14
  /**
15
15
  * Bootstrap the first account with keeper and admin privileges.
16
16
  *
@@ -21,15 +21,15 @@ import { query_grant_permit } from './permit_queries.js';
21
21
  * 2. Hash the password (CPU-intensive, before transaction)
22
22
  * 3. Acquire the bootstrap lock atomically (inside transaction)
23
23
  * 4. Create account + actor
24
- * 5. Grant keeper and admin permits (no expiry, `granted_by = null`)
24
+ * 5. Grant keeper and admin role_grants (no expiry, `granted_by = null`)
25
25
  * 6. Delete the token file (after commit, reported via `token_file_deleted`)
26
26
  *
27
27
  * @param deps - database, token path, filesystem callbacks, and password hashing
28
28
  * @param provided_token - the bootstrap token from the user
29
29
  * @param input - username and password
30
- * @returns the created account, actor, and permits — or a bootstrap failure
30
+ * @returns the created account, actor, and role_grants — or a bootstrap failure
31
31
  * @mutates `bootstrap_lock` row - flips `bootstrapped` to `true` atomically
32
- * @mutates `account` / `actor` / `permit` tables - inserts the bootstrap account, actor, and the keeper + admin permits
32
+ * @mutates `account` / `actor` / `role_grant` tables - inserts the bootstrap account, actor, and the keeper + admin role_grants
33
33
  * @mutates filesystem - deletes the bootstrap token file after commit (reported via `token_file_deleted`)
34
34
  */
35
35
  export const bootstrap_account = async (deps, provided_token, input) => {
@@ -66,13 +66,13 @@ export const bootstrap_account = async (deps, provided_token, input) => {
66
66
  username: input.username,
67
67
  password_hash,
68
68
  });
69
- const keeper_permit = await query_grant_permit(tx_deps, {
69
+ const keeper_role_grant = await query_create_role_grant(tx_deps, {
70
70
  actor_id: actor.id,
71
71
  role: ROLE_KEEPER,
72
72
  granted_by: null,
73
73
  expires_at: null,
74
74
  });
75
- const admin_permit = await query_grant_permit(tx_deps, {
75
+ const admin_role_grant = await query_create_role_grant(tx_deps, {
76
76
  actor_id: actor.id,
77
77
  role: ROLE_ADMIN,
78
78
  granted_by: null,
@@ -82,7 +82,7 @@ export const bootstrap_account = async (deps, provided_token, input) => {
82
82
  ok: true,
83
83
  account,
84
84
  actor,
85
- permits: { keeper: keeper_permit, admin: admin_permit },
85
+ role_grants: { keeper: keeper_role_grant, admin: admin_role_grant },
86
86
  };
87
87
  });
88
88
  if (!tx_result.ok)
@@ -1 +1 @@
1
- {"version":3,"file":"bootstrap_routes.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/bootstrap_routes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,MAAM,CAAC;AAClC,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,qBAAqB,CAAC;AAExD,OAAO,EAAoB,KAAK,uBAAuB,EAAC,MAAM,wBAAwB,CAAC;AAGvF,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,aAAa,CAAC;AACpC,OAAO,EAAkB,KAAK,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAEtE,OAAO,EAA+B,KAAK,WAAW,EAAC,MAAM,oBAAoB,CAAC;AAClF,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAC;AAanD,gFAAgF;AAChF,eAAO,MAAM,cAAc;;;;kBAIzB,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D,iFAAiF;AACjF,eAAO,MAAM,eAAe;;;kBAG1B,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACrC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,8EAA8E;IAC9E,gBAAgB,EAAE,eAAe,CAAC;IAClC;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,uBAAuB,EAAE,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E,4EAA4E;IAC5E,eAAe,EAAE,WAAW,GAAG,IAAI,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACxC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACnD,EAAE,EAAE,EAAE,CAAC;IACP,GAAG,EAAE,MAAM,CAAC;CACZ;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,wBAAwB,EAC9B,SAAS;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAAC,KAClC,OAAO,CAAC,eAAe,CAwBzB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,GACxC,MAAM,gBAAgB,EACtB,SAAS,qBAAqB,KAC5B,KAAK,CAAC,SAAS,CAuHjB,CAAC"}
1
+ {"version":3,"file":"bootstrap_routes.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/bootstrap_routes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,MAAM,CAAC;AAClC,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,qBAAqB,CAAC;AAExD,OAAO,EAAoB,KAAK,uBAAuB,EAAC,MAAM,wBAAwB,CAAC;AAGvF,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,aAAa,CAAC;AACpC,OAAO,EAAkB,KAAK,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAEtE,OAAO,EAA+B,KAAK,WAAW,EAAC,MAAM,oBAAoB,CAAC;AAClF,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAC;AAYnD,gFAAgF;AAChF,eAAO,MAAM,cAAc;;;;kBAIzB,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D,iFAAiF;AACjF,eAAO,MAAM,eAAe;;;kBAG1B,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACrC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,8EAA8E;IAC9E,gBAAgB,EAAE,eAAe,CAAC;IAClC;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,uBAAuB,EAAE,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E,4EAA4E;IAC5E,eAAe,EAAE,WAAW,GAAG,IAAI,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACxC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACnD,EAAE,EAAE,EAAE,CAAC;IACP,GAAG,EAAE,MAAM,CAAC;CACZ;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,wBAAwB,EAC9B,SAAS;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAAC,KAClC,OAAO,CAAC,eAAe,CAwBzB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,GACxC,MAAM,gBAAgB,EACtB,SAAS,qBAAqB,KAC5B,KAAK,CAAC,SAAS,CAiHjB,CAAC"}
@@ -7,15 +7,14 @@
7
7
  * @module
8
8
  */
9
9
  import { z } from 'zod';
10
- import { create_session_and_set_cookie } from './session_lifecycle.js';
10
+ import { create_session_and_set_cookie } from './session_middleware.js';
11
11
  import { bootstrap_account } from './bootstrap_account.js';
12
- import { Username } from './account_schema.js';
12
+ import { Username } from '../primitive_schemas.js';
13
13
  import { Password } from './password.js';
14
14
  import { get_route_input } from '../http/route_spec.js';
15
15
  import { get_client_ip } from '../http/proxy.js';
16
16
  import { rate_limit_exceeded_response } from '../rate_limiter.js';
17
17
  import { ERROR_BOOTSTRAP_NOT_CONFIGURED, ERROR_INVALID_TOKEN, ERROR_ALREADY_BOOTSTRAPPED, ERROR_TOKEN_FILE_MISSING, ERROR_INVALID_JSON_BODY, ERROR_INVALID_REQUEST_BODY, } from '../http/error_schemas.js';
18
- import { audit_log_fire_and_forget } from './audit_log_queries.js';
19
18
  // -- Input/output schemas ---------------------------------------------------
20
19
  /** Input for `POST /bootstrap`. `token` is the one-shot token file contents. */
21
20
  export const BootstrapInput = z.strictObject({
@@ -74,7 +73,7 @@ export const create_bootstrap_route_specs = (deps, options) => {
74
73
  {
75
74
  method: 'POST',
76
75
  path: '/bootstrap',
77
- auth: { type: 'none' },
76
+ auth: { account: 'none', actor: 'none' },
78
77
  description: 'Create initial keeper account (one-shot)',
79
78
  transaction: false, // bootstrap_account manages its own transaction
80
79
  input: BootstrapInput,
@@ -107,8 +106,10 @@ export const create_bootstrap_route_specs = (deps, options) => {
107
106
  if (token_path === null) {
108
107
  return c.json({ error: ERROR_BOOTSTRAP_NOT_CONFIGURED }, 404);
109
108
  }
109
+ // `transaction: false` makes `route.db` the pool. `bootstrap_account`
110
+ // manages its own transaction internally.
110
111
  const result = await bootstrap_account({
111
- db: route.background_db,
112
+ db: route.db,
112
113
  token_path,
113
114
  read_text_file: deps.read_text_file,
114
115
  delete_file: deps.delete_file,
@@ -118,12 +119,12 @@ export const create_bootstrap_route_specs = (deps, options) => {
118
119
  if (!result.ok) {
119
120
  if (ip_rate_limiter && ip)
120
121
  ip_rate_limiter.record(ip);
121
- void audit_log_fire_and_forget(route, {
122
+ deps.audit.emit(route, {
122
123
  event_type: 'bootstrap',
123
124
  outcome: 'failure',
124
125
  ip: get_client_ip(c),
125
126
  metadata: { error: result.error },
126
- }, deps);
127
+ });
127
128
  return c.json({ error: result.error }, result.status);
128
129
  }
129
130
  // Successful bootstrap — update state immediately
@@ -132,7 +133,7 @@ export const create_bootstrap_route_specs = (deps, options) => {
132
133
  bootstrap_status.available = false;
133
134
  await create_session_and_set_cookie({
134
135
  keyring,
135
- deps: { db: route.background_db },
136
+ deps: { db: route.db },
136
137
  c,
137
138
  account_id: result.account.id,
138
139
  session_options,
@@ -145,12 +146,12 @@ export const create_bootstrap_route_specs = (deps, options) => {
145
146
  deps.log.error(`on_bootstrap callback failed: ${err instanceof Error ? err.message : String(err)}`);
146
147
  }
147
148
  }
148
- void audit_log_fire_and_forget(route, {
149
+ deps.audit.emit(route, {
149
150
  event_type: 'bootstrap',
150
151
  actor_id: result.actor.id,
151
152
  account_id: result.account.id,
152
153
  ip: get_client_ip(c),
153
- }, deps);
154
+ });
154
155
  // CRITICAL: If token file deletion failed, throw to force operator attention.
155
156
  // All success work (session, on_bootstrap, audit) has completed above.
156
157
  // The error response alerts the operator to delete the token file manually.
@@ -1,17 +1,17 @@
1
1
  /**
2
- * Periodic auth cleanup — sweeps expired sessions and permit offers.
2
+ * Periodic auth cleanup — sweeps expired sessions and role_grant offers.
3
3
  *
4
4
  * Single entry point for consumers scheduling auth maintenance. Internally
5
5
  * runs every known sweep and emits the corresponding audit events so
6
6
  * consumer code only manages cadence, not per-task wiring.
7
7
  *
8
8
  * The per-task primitives remain exported from their home modules
9
- * (`query_session_cleanup_expired`, `query_permit_offer_sweep_expired`);
10
- * `cleanup_expired_permit_offers` here wraps the latter with the required
11
- * `permit_offer_expire` audit emission and is the piece most likely to be
9
+ * (`query_session_cleanup_expired`, `query_role_grant_offer_sweep_expired`);
10
+ * `cleanup_expired_role_grant_offers` here wraps the latter with the required
11
+ * `role_grant_offer_expire` audit emission and is the piece most likely to be
12
12
  * reused in a consumer's bespoke scheduler.
13
13
  *
14
- * Idempotency: the audit log has no tombstone on `permit_offer_expire`, so
14
+ * Idempotency: the audit log has no tombstone on `role_grant_offer_expire`, so
15
15
  * concurrent sweep runs double-audit. The expected deployment pattern is a
16
16
  * single scheduled invocation per instance — matching
17
17
  * `query_session_cleanup_expired`.
@@ -20,57 +20,51 @@
20
20
  */
21
21
  import type { Logger } from '@fuzdev/fuz_util/log.js';
22
22
  import type { QueryDeps } from '../db/query_deps.js';
23
- import type { AuditLogConfig, AuditLogEvent } from './audit_log_schema.js';
23
+ import type { AuditEmitter } from './audit_emitter.js';
24
24
  /** Dependencies for the cleanup helpers. */
25
25
  export interface AuthCleanupDeps extends QueryDeps {
26
26
  log: Logger;
27
27
  /**
28
- * Called after each audit event INSERT succeeds. Typically the same
29
- * callback wired into `AppDeps.on_audit_event` (SSE broadcast). Omit
30
- * to skip broadcast the audit rows still land in the DB.
28
+ * Bound audit emitter. `cleanup_expired_role_grant_offers` writes via
29
+ * `audit.emit_pool` (the captured pool + config + listener chain), so
30
+ * one slot covers both row persistence and SSE/WS fan-out. Required
31
+ * production wiring always has a bound emitter on `AppDeps.audit`, and
32
+ * tests that need a no-op pass `create_test_audit_emitter()`.
31
33
  */
32
- on_audit_event?: ((event: AuditLogEvent) => void) | null;
33
- /**
34
- * Audit-log config. Only the builtin `permit_offer_expire` event type is
35
- * emitted here, so omitting this is safe — the field exists so consumers
36
- * threading the same `AppDeps` bundle to scheduled cleanup keep using
37
- * their registered config (and consumer extensions to the
38
- * `permit_offer_expire` metadata schema get validated).
39
- */
40
- audit_log_config?: AuditLogConfig;
34
+ audit: AuditEmitter;
41
35
  }
42
36
  /** Result of `run_auth_cleanup`. */
43
37
  export interface AuthCleanupResult {
44
38
  /** Number of expired session rows deleted. */
45
39
  expired_sessions: number;
46
- /** Number of expired permit offer rows audit-stamped. */
40
+ /** Number of expired role_grant offer rows audit-stamped. */
47
41
  expired_offers: number;
48
42
  }
49
43
  /**
50
- * Sweep expired permit offers and emit one `permit_offer_expire` audit
44
+ * Sweep expired role_grant offers and emit one `role_grant_offer_expire` audit
51
45
  * event per row.
52
46
  *
53
47
  * Returns the count of offers audit-stamped. The offer rows themselves are
54
48
  * preserved — offers carry audit value for the history view even after
55
- * expiry, and accepted rows are the provenance for the resulting permit
49
+ * expiry, and accepted rows are the provenance for the resulting role_grant
56
50
  * (deleting expired rows would not threaten that, but keeping them uniform
57
51
  * with the retention policy for terminal rows is simpler).
58
52
  *
59
- * @mutates `audit_log` table - inserts one `permit_offer_expire` row per swept offer
53
+ * @mutates `audit_log` table - inserts one `role_grant_offer_expire` row per swept offer
60
54
  */
61
- export declare const cleanup_expired_permit_offers: (deps: AuthCleanupDeps) => Promise<number>;
55
+ export declare const cleanup_expired_role_grant_offers: (deps: AuthCleanupDeps) => Promise<number>;
62
56
  /**
63
- * Run every auth cleanup sweep — expired sessions and expired permit
57
+ * Run every auth cleanup sweep — expired sessions and expired role_grant
64
58
  * offers — and return the counts.
65
59
  *
66
60
  * Consumers call this from a scheduled task (setInterval, cron, etc.)
67
61
  * alongside their own domain cleanup. Errors from individual sweeps are
68
62
  * re-thrown so the caller's scheduler can log/alert; use the per-task
69
- * helpers (`query_session_cleanup_expired`, `cleanup_expired_permit_offers`)
63
+ * helpers (`query_session_cleanup_expired`, `cleanup_expired_role_grant_offers`)
70
64
  * directly if you need finer error isolation.
71
65
  *
72
66
  * @mutates `auth_session` table - deletes expired sessions
73
- * @mutates `audit_log` table - emits `permit_offer_expire` rows for expired offers
67
+ * @mutates `audit_log` table - emits `role_grant_offer_expire` rows for expired offers
74
68
  * @throws Error re-thrown from any sweep that fails (no per-sweep isolation here)
75
69
  */
76
70
  export declare const run_auth_cleanup: (deps: AuthCleanupDeps) => Promise<AuthCleanupResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"cleanup.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/cleanup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAInD,OAAO,KAAK,EAAC,cAAc,EAAE,aAAa,EAAC,MAAM,uBAAuB,CAAC;AAEzE,4CAA4C;AAC5C,MAAM,WAAW,eAAgB,SAAQ,SAAS;IACjD,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC;IACzD;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,cAAc,CAAC;CAClC;AAED,oCAAoC;AACpC,MAAM,WAAW,iBAAiB;IACjC,8CAA8C;IAC9C,gBAAgB,EAAE,MAAM,CAAC;IACzB,yDAAyD;IACzD,cAAc,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,6BAA6B,GAAU,MAAM,eAAe,KAAG,OAAO,CAAC,MAAM,CAiCzF,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gBAAgB,GAAU,MAAM,eAAe,KAAG,OAAO,CAAC,iBAAiB,CAIvF,CAAC"}
1
+ {"version":3,"file":"cleanup.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/cleanup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAGnD,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAC;AAErD,4CAA4C;AAC5C,MAAM,WAAW,eAAgB,SAAQ,SAAS;IACjD,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;OAMG;IACH,KAAK,EAAE,YAAY,CAAC;CACpB;AAED,oCAAoC;AACpC,MAAM,WAAW,iBAAiB;IACjC,8CAA8C;IAC9C,gBAAgB,EAAE,MAAM,CAAC;IACzB,6DAA6D;IAC7D,cAAc,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iCAAiC,GAAU,MAAM,eAAe,KAAG,OAAO,CAAC,MAAM,CAuB7F,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gBAAgB,GAAU,MAAM,eAAe,KAAG,OAAO,CAAC,iBAAiB,CAIvF,CAAC"}
@@ -1,17 +1,17 @@
1
1
  /**
2
- * Periodic auth cleanup — sweeps expired sessions and permit offers.
2
+ * Periodic auth cleanup — sweeps expired sessions and role_grant offers.
3
3
  *
4
4
  * Single entry point for consumers scheduling auth maintenance. Internally
5
5
  * runs every known sweep and emits the corresponding audit events so
6
6
  * consumer code only manages cadence, not per-task wiring.
7
7
  *
8
8
  * The per-task primitives remain exported from their home modules
9
- * (`query_session_cleanup_expired`, `query_permit_offer_sweep_expired`);
10
- * `cleanup_expired_permit_offers` here wraps the latter with the required
11
- * `permit_offer_expire` audit emission and is the piece most likely to be
9
+ * (`query_session_cleanup_expired`, `query_role_grant_offer_sweep_expired`);
10
+ * `cleanup_expired_role_grant_offers` here wraps the latter with the required
11
+ * `role_grant_offer_expire` audit emission and is the piece most likely to be
12
12
  * reused in a consumer's bespoke scheduler.
13
13
  *
14
- * Idempotency: the audit log has no tombstone on `permit_offer_expire`, so
14
+ * Idempotency: the audit log has no tombstone on `role_grant_offer_expire`, so
15
15
  * concurrent sweep runs double-audit. The expected deployment pattern is a
16
16
  * single scheduled invocation per instance — matching
17
17
  * `query_session_cleanup_expired`.
@@ -19,68 +19,59 @@
19
19
  * @module
20
20
  */
21
21
  import { query_session_cleanup_expired } from './session_queries.js';
22
- import { query_permit_offer_sweep_expired } from './permit_offer_queries.js';
23
- import { query_audit_log } from './audit_log_queries.js';
22
+ import { query_role_grant_offer_sweep_expired } from './role_grant_offer_queries.js';
24
23
  /**
25
- * Sweep expired permit offers and emit one `permit_offer_expire` audit
24
+ * Sweep expired role_grant offers and emit one `role_grant_offer_expire` audit
26
25
  * event per row.
27
26
  *
28
27
  * Returns the count of offers audit-stamped. The offer rows themselves are
29
28
  * preserved — offers carry audit value for the history view even after
30
- * expiry, and accepted rows are the provenance for the resulting permit
29
+ * expiry, and accepted rows are the provenance for the resulting role_grant
31
30
  * (deleting expired rows would not threaten that, but keeping them uniform
32
31
  * with the retention policy for terminal rows is simpler).
33
32
  *
34
- * @mutates `audit_log` table - inserts one `permit_offer_expire` row per swept offer
33
+ * @mutates `audit_log` table - inserts one `role_grant_offer_expire` row per swept offer
35
34
  */
36
- export const cleanup_expired_permit_offers = async (deps) => {
37
- const expired = await query_permit_offer_sweep_expired(deps);
38
- const { on_audit_event, audit_log_config } = deps;
35
+ export const cleanup_expired_role_grant_offers = async (deps) => {
36
+ const expired = await query_role_grant_offer_sweep_expired(deps);
39
37
  for (const offer of expired) {
40
- try {
41
- const event = await query_audit_log(deps, {
42
- event_type: 'permit_offer_expire',
43
- actor_id: offer.from_actor_id,
44
- target_account_id: offer.to_account_id,
45
- ip: null,
46
- metadata: {
47
- offer_id: offer.id,
48
- role: offer.role,
49
- scope_id: offer.scope_id,
50
- },
51
- }, audit_log_config);
52
- if (on_audit_event) {
53
- try {
54
- on_audit_event(event);
55
- }
56
- catch (callback_err) {
57
- deps.log.error('on_audit_event callback failed:', callback_err);
58
- }
59
- }
60
- }
61
- catch (err) {
62
- // One failed audit write must not starve siblings — log and continue.
63
- deps.log.error('permit_offer_expire audit write failed:', err);
64
- }
38
+ // `role_grant_offer_expire` populates `target_actor_id` only when the
39
+ // offer was actor-targeted (`to_actor_id` set at create time).
40
+ // Account-grain offers (no `to_actor_id`) never bound to a
41
+ // specific actor and leave the field null.
42
+ // `emit_pool` swallows + logs both write errors and per-listener
43
+ // throws, so a single bad row never starves the rest of the sweep.
44
+ await deps.audit.emit_pool({
45
+ event_type: 'role_grant_offer_expire',
46
+ actor_id: offer.from_actor_id,
47
+ target_account_id: offer.to_account_id,
48
+ target_actor_id: offer.to_actor_id,
49
+ ip: null,
50
+ metadata: {
51
+ offer_id: offer.id,
52
+ role: offer.role,
53
+ scope_id: offer.scope_id,
54
+ },
55
+ });
65
56
  }
66
57
  return expired.length;
67
58
  };
68
59
  /**
69
- * Run every auth cleanup sweep — expired sessions and expired permit
60
+ * Run every auth cleanup sweep — expired sessions and expired role_grant
70
61
  * offers — and return the counts.
71
62
  *
72
63
  * Consumers call this from a scheduled task (setInterval, cron, etc.)
73
64
  * alongside their own domain cleanup. Errors from individual sweeps are
74
65
  * re-thrown so the caller's scheduler can log/alert; use the per-task
75
- * helpers (`query_session_cleanup_expired`, `cleanup_expired_permit_offers`)
66
+ * helpers (`query_session_cleanup_expired`, `cleanup_expired_role_grant_offers`)
76
67
  * directly if you need finer error isolation.
77
68
  *
78
69
  * @mutates `auth_session` table - deletes expired sessions
79
- * @mutates `audit_log` table - emits `permit_offer_expire` rows for expired offers
70
+ * @mutates `audit_log` table - emits `role_grant_offer_expire` rows for expired offers
80
71
  * @throws Error re-thrown from any sweep that fails (no per-sweep isolation here)
81
72
  */
82
73
  export const run_auth_cleanup = async (deps) => {
83
74
  const expired_sessions = await query_session_cleanup_expired(deps);
84
- const expired_offers = await cleanup_expired_permit_offers(deps);
75
+ const expired_offers = await cleanup_expired_role_grant_offers(deps);
85
76
  return { expired_sessions, expired_offers };
86
77
  };