@fuzdev/fuz_app 0.55.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 (331) hide show
  1. package/dist/actions/CLAUDE.md +211 -155
  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 +19 -0
  6. package/dist/actions/action_codegen.d.ts.map +1 -1
  7. package/dist/actions/action_codegen.js +20 -14
  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 +110 -44
  11. package/dist/actions/action_rpc.d.ts.map +1 -1
  12. package/dist/actions/action_rpc.js +92 -287
  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 +44 -38
  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 +2 -10
  34. package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
  35. package/dist/actions/register_ws_endpoint.js +32 -10
  36. package/dist/actions/transports_ws_auth_guard.d.ts +1 -1
  37. package/dist/actions/transports_ws_auth_guard.js +1 -1
  38. package/dist/actions/transports_ws_backend.d.ts +1 -1
  39. package/dist/actions/transports_ws_backend.js +1 -1
  40. package/dist/auth/CLAUDE.md +673 -442
  41. package/dist/auth/account_action_specs.d.ts +28 -7
  42. package/dist/auth/account_action_specs.d.ts.map +1 -1
  43. package/dist/auth/account_action_specs.js +7 -7
  44. package/dist/auth/account_actions.d.ts +8 -14
  45. package/dist/auth/account_actions.d.ts.map +1 -1
  46. package/dist/auth/account_actions.js +26 -32
  47. package/dist/auth/account_queries.d.ts +46 -13
  48. package/dist/auth/account_queries.d.ts.map +1 -1
  49. package/dist/auth/account_queries.js +73 -33
  50. package/dist/auth/account_routes.d.ts +4 -3
  51. package/dist/auth/account_routes.d.ts.map +1 -1
  52. package/dist/auth/account_routes.js +58 -33
  53. package/dist/auth/account_schema.d.ts +46 -54
  54. package/dist/auth/account_schema.d.ts.map +1 -1
  55. package/dist/auth/account_schema.js +21 -48
  56. package/dist/auth/admin_action_specs.d.ts +55 -21
  57. package/dist/auth/admin_action_specs.d.ts.map +1 -1
  58. package/dist/auth/admin_action_specs.js +42 -26
  59. package/dist/auth/admin_actions.d.ts +14 -21
  60. package/dist/auth/admin_actions.d.ts.map +1 -1
  61. package/dist/auth/admin_actions.js +47 -44
  62. package/dist/auth/audit_emitter.d.ts +160 -0
  63. package/dist/auth/audit_emitter.d.ts.map +1 -0
  64. package/dist/auth/audit_emitter.js +83 -0
  65. package/dist/auth/audit_log_queries.d.ts +17 -87
  66. package/dist/auth/audit_log_queries.d.ts.map +1 -1
  67. package/dist/auth/audit_log_queries.js +17 -96
  68. package/dist/auth/audit_log_routes.d.ts +1 -1
  69. package/dist/auth/audit_log_routes.d.ts.map +1 -1
  70. package/dist/auth/audit_log_routes.js +7 -3
  71. package/dist/auth/audit_log_schema.d.ts +48 -42
  72. package/dist/auth/audit_log_schema.d.ts.map +1 -1
  73. package/dist/auth/audit_log_schema.js +56 -43
  74. package/dist/auth/auth_guard_resolver.d.ts +44 -0
  75. package/dist/auth/auth_guard_resolver.d.ts.map +1 -0
  76. package/dist/auth/auth_guard_resolver.js +56 -0
  77. package/dist/auth/bootstrap_account.d.ts +7 -7
  78. package/dist/auth/bootstrap_account.d.ts.map +1 -1
  79. package/dist/auth/bootstrap_account.js +7 -7
  80. package/dist/auth/bootstrap_routes.d.ts.map +1 -1
  81. package/dist/auth/bootstrap_routes.js +11 -10
  82. package/dist/auth/cleanup.d.ts +20 -26
  83. package/dist/auth/cleanup.d.ts.map +1 -1
  84. package/dist/auth/cleanup.js +33 -47
  85. package/dist/auth/credential_type_schema.d.ts +115 -0
  86. package/dist/auth/credential_type_schema.d.ts.map +1 -0
  87. package/dist/auth/credential_type_schema.js +127 -0
  88. package/dist/auth/daemon_token_middleware.d.ts +1 -1
  89. package/dist/auth/daemon_token_middleware.js +3 -3
  90. package/dist/auth/ddl.d.ts +2 -2
  91. package/dist/auth/ddl.d.ts.map +1 -1
  92. package/dist/auth/ddl.js +6 -6
  93. package/dist/auth/deps.d.ts +7 -32
  94. package/dist/auth/deps.d.ts.map +1 -1
  95. package/dist/auth/grant_path_schema.d.ts +117 -0
  96. package/dist/auth/grant_path_schema.d.ts.map +1 -0
  97. package/dist/auth/grant_path_schema.js +137 -0
  98. package/dist/auth/invite_queries.d.ts +12 -1
  99. package/dist/auth/invite_queries.d.ts.map +1 -1
  100. package/dist/auth/invite_queries.js +12 -1
  101. package/dist/auth/invite_schema.d.ts +1 -1
  102. package/dist/auth/invite_schema.d.ts.map +1 -1
  103. package/dist/auth/invite_schema.js +1 -1
  104. package/dist/auth/middleware.d.ts.map +1 -1
  105. package/dist/auth/middleware.js +5 -2
  106. package/dist/auth/migrations.d.ts +22 -7
  107. package/dist/auth/migrations.d.ts.map +1 -1
  108. package/dist/auth/migrations.js +64 -25
  109. package/dist/auth/request_context.d.ts +157 -170
  110. package/dist/auth/request_context.d.ts.map +1 -1
  111. package/dist/auth/request_context.js +224 -268
  112. package/dist/auth/{permit_offer_action_specs.d.ts → role_grant_offer_action_specs.d.ts} +130 -100
  113. package/dist/auth/role_grant_offer_action_specs.d.ts.map +1 -0
  114. package/dist/auth/role_grant_offer_action_specs.js +262 -0
  115. package/dist/auth/role_grant_offer_actions.d.ts +104 -0
  116. package/dist/auth/role_grant_offer_actions.d.ts.map +1 -0
  117. package/dist/auth/{permit_offer_actions.js → role_grant_offer_actions.js} +153 -140
  118. package/dist/auth/{permit_offer_notifications.d.ts → role_grant_offer_notifications.d.ts} +80 -70
  119. package/dist/auth/role_grant_offer_notifications.d.ts.map +1 -0
  120. package/dist/auth/role_grant_offer_notifications.js +182 -0
  121. package/dist/auth/{permit_offer_queries.d.ts → role_grant_offer_queries.d.ts} +64 -64
  122. package/dist/auth/role_grant_offer_queries.d.ts.map +1 -0
  123. package/dist/auth/{permit_offer_queries.js → role_grant_offer_queries.js} +136 -123
  124. package/dist/auth/role_grant_offer_schema.d.ts +150 -0
  125. package/dist/auth/role_grant_offer_schema.d.ts.map +1 -0
  126. package/dist/auth/{permit_offer_schema.js → role_grant_offer_schema.js} +55 -36
  127. package/dist/auth/role_grant_queries.d.ts +231 -0
  128. package/dist/auth/role_grant_queries.d.ts.map +1 -0
  129. package/dist/auth/role_grant_queries.js +320 -0
  130. package/dist/auth/role_schema.d.ts +150 -40
  131. package/dist/auth/role_schema.d.ts.map +1 -1
  132. package/dist/auth/role_schema.js +144 -45
  133. package/dist/auth/scope_kind_schema.d.ts +96 -0
  134. package/dist/auth/scope_kind_schema.d.ts.map +1 -0
  135. package/dist/auth/scope_kind_schema.js +94 -0
  136. package/dist/auth/self_service_role_action_specs.d.ts +4 -1
  137. package/dist/auth/self_service_role_action_specs.d.ts.map +1 -1
  138. package/dist/auth/self_service_role_action_specs.js +2 -2
  139. package/dist/auth/self_service_role_actions.d.ts +35 -29
  140. package/dist/auth/self_service_role_actions.d.ts.map +1 -1
  141. package/dist/auth/self_service_role_actions.js +58 -48
  142. package/dist/auth/session_cookie.d.ts +43 -6
  143. package/dist/auth/session_cookie.d.ts.map +1 -1
  144. package/dist/auth/session_cookie.js +31 -5
  145. package/dist/auth/session_middleware.d.ts +37 -3
  146. package/dist/auth/session_middleware.d.ts.map +1 -1
  147. package/dist/auth/session_middleware.js +33 -7
  148. package/dist/auth/signup_routes.d.ts.map +1 -1
  149. package/dist/auth/signup_routes.js +48 -19
  150. package/dist/auth/standard_action_specs.d.ts +2 -2
  151. package/dist/auth/standard_action_specs.js +4 -4
  152. package/dist/auth/standard_rpc_actions.d.ts +23 -19
  153. package/dist/auth/standard_rpc_actions.d.ts.map +1 -1
  154. package/dist/auth/standard_rpc_actions.js +12 -12
  155. package/dist/db/migrate.d.ts +1 -1
  156. package/dist/db/migrate.js +1 -1
  157. package/dist/dev/setup.d.ts +2 -2
  158. package/dist/dev/setup.d.ts.map +1 -1
  159. package/dist/dev/setup.js +4 -4
  160. package/dist/env/load.d.ts +1 -1
  161. package/dist/env/load.js +1 -1
  162. package/dist/hono_context.d.ts +27 -45
  163. package/dist/hono_context.d.ts.map +1 -1
  164. package/dist/hono_context.js +14 -28
  165. package/dist/http/CLAUDE.md +235 -121
  166. package/dist/http/auth_shape.d.ts +191 -0
  167. package/dist/http/auth_shape.d.ts.map +1 -0
  168. package/dist/http/auth_shape.js +237 -0
  169. package/dist/http/common_routes.js +3 -3
  170. package/dist/http/db_routes.d.ts +4 -0
  171. package/dist/http/db_routes.d.ts.map +1 -1
  172. package/dist/http/db_routes.js +44 -7
  173. package/dist/http/error_schemas.d.ts +56 -34
  174. package/dist/http/error_schemas.d.ts.map +1 -1
  175. package/dist/http/error_schemas.js +63 -28
  176. package/dist/http/pending_effects.d.ts +71 -18
  177. package/dist/http/pending_effects.d.ts.map +1 -1
  178. package/dist/http/pending_effects.js +87 -18
  179. package/dist/http/proxy.d.ts +52 -5
  180. package/dist/http/proxy.d.ts.map +1 -1
  181. package/dist/http/proxy.js +92 -14
  182. package/dist/http/route_spec.d.ts +89 -75
  183. package/dist/http/route_spec.d.ts.map +1 -1
  184. package/dist/http/route_spec.js +54 -72
  185. package/dist/http/schema_helpers.d.ts +3 -14
  186. package/dist/http/schema_helpers.d.ts.map +1 -1
  187. package/dist/http/schema_helpers.js +2 -14
  188. package/dist/http/surface.d.ts +2 -10
  189. package/dist/http/surface.d.ts.map +1 -1
  190. package/dist/http/surface.js +3 -4
  191. package/dist/http/surface_query.d.ts +39 -35
  192. package/dist/http/surface_query.d.ts.map +1 -1
  193. package/dist/http/surface_query.js +79 -36
  194. package/dist/primitive_schemas.d.ts +39 -0
  195. package/dist/primitive_schemas.d.ts.map +1 -0
  196. package/dist/primitive_schemas.js +40 -0
  197. package/dist/realtime/sse_auth_guard.d.ts +5 -5
  198. package/dist/realtime/sse_auth_guard.js +9 -9
  199. package/dist/runtime/mock.d.ts +1 -1
  200. package/dist/runtime/mock.js +1 -1
  201. package/dist/server/app_backend.d.ts +14 -11
  202. package/dist/server/app_backend.d.ts.map +1 -1
  203. package/dist/server/app_backend.js +12 -8
  204. package/dist/server/app_server.d.ts +7 -7
  205. package/dist/server/app_server.d.ts.map +1 -1
  206. package/dist/server/app_server.js +35 -40
  207. package/dist/server/validate_nginx.d.ts +1 -1
  208. package/dist/server/validate_nginx.js +1 -1
  209. package/dist/testing/CLAUDE.md +50 -38
  210. package/dist/testing/admin_integration.d.ts +5 -6
  211. package/dist/testing/admin_integration.d.ts.map +1 -1
  212. package/dist/testing/admin_integration.js +87 -85
  213. package/dist/testing/app_server.d.ts +11 -14
  214. package/dist/testing/app_server.d.ts.map +1 -1
  215. package/dist/testing/app_server.js +16 -15
  216. package/dist/testing/assertions.d.ts.map +1 -1
  217. package/dist/testing/assertions.js +2 -1
  218. package/dist/testing/attack_surface.d.ts.map +1 -1
  219. package/dist/testing/attack_surface.js +15 -9
  220. package/dist/testing/audit_completeness.d.ts +2 -2
  221. package/dist/testing/audit_completeness.d.ts.map +1 -1
  222. package/dist/testing/audit_completeness.js +36 -36
  223. package/dist/testing/auth_apps.d.ts +5 -4
  224. package/dist/testing/auth_apps.d.ts.map +1 -1
  225. package/dist/testing/auth_apps.js +22 -19
  226. package/dist/testing/data_exposure.d.ts.map +1 -1
  227. package/dist/testing/data_exposure.js +5 -5
  228. package/dist/testing/db.d.ts +1 -1
  229. package/dist/testing/db.d.ts.map +1 -1
  230. package/dist/testing/db.js +4 -4
  231. package/dist/testing/db_entities.d.ts +22 -0
  232. package/dist/testing/db_entities.d.ts.map +1 -0
  233. package/dist/testing/db_entities.js +28 -0
  234. package/dist/testing/entities.d.ts +8 -7
  235. package/dist/testing/entities.d.ts.map +1 -1
  236. package/dist/testing/entities.js +21 -18
  237. package/dist/testing/integration.d.ts.map +1 -1
  238. package/dist/testing/integration.js +13 -14
  239. package/dist/testing/integration_helpers.d.ts +4 -4
  240. package/dist/testing/integration_helpers.d.ts.map +1 -1
  241. package/dist/testing/integration_helpers.js +20 -18
  242. package/dist/testing/middleware.d.ts +4 -4
  243. package/dist/testing/middleware.d.ts.map +1 -1
  244. package/dist/testing/middleware.js +12 -11
  245. package/dist/testing/rpc_attack_surface.d.ts.map +1 -1
  246. package/dist/testing/rpc_attack_surface.js +40 -24
  247. package/dist/testing/rpc_round_trip.d.ts +1 -1
  248. package/dist/testing/rpc_round_trip.d.ts.map +1 -1
  249. package/dist/testing/rpc_round_trip.js +14 -13
  250. package/dist/testing/sse_round_trip.d.ts +3 -4
  251. package/dist/testing/sse_round_trip.d.ts.map +1 -1
  252. package/dist/testing/sse_round_trip.js +7 -11
  253. package/dist/testing/standard.d.ts +1 -1
  254. package/dist/testing/stubs.d.ts +25 -0
  255. package/dist/testing/stubs.d.ts.map +1 -1
  256. package/dist/testing/stubs.js +43 -2
  257. package/dist/testing/surface_invariants.d.ts +2 -2
  258. package/dist/testing/ws_round_trip.d.ts +12 -13
  259. package/dist/testing/ws_round_trip.d.ts.map +1 -1
  260. package/dist/testing/ws_round_trip.js +19 -11
  261. package/dist/ui/AdminAccounts.svelte +23 -20
  262. package/dist/ui/AdminOverview.svelte +15 -13
  263. package/dist/ui/AdminOverview.svelte.d.ts.map +1 -1
  264. package/dist/ui/{AdminPermitHistory.svelte → AdminRoleGrantHistory.svelte} +12 -12
  265. package/dist/ui/AdminRoleGrantHistory.svelte.d.ts +4 -0
  266. package/dist/ui/AdminRoleGrantHistory.svelte.d.ts.map +1 -0
  267. package/dist/ui/BootstrapForm.svelte +1 -1
  268. package/dist/ui/CLAUDE.md +60 -60
  269. package/dist/ui/{PermitOfferForm.svelte → RoleGrantOfferForm.svelte} +27 -26
  270. package/dist/ui/{PermitOfferForm.svelte.d.ts → RoleGrantOfferForm.svelte.d.ts} +7 -7
  271. package/dist/ui/RoleGrantOfferForm.svelte.d.ts.map +1 -0
  272. package/dist/ui/{PermitOfferHistory.svelte → RoleGrantOfferHistory.svelte} +12 -12
  273. package/dist/ui/{PermitOfferHistory.svelte.d.ts → RoleGrantOfferHistory.svelte.d.ts} +4 -4
  274. package/dist/ui/RoleGrantOfferHistory.svelte.d.ts.map +1 -0
  275. package/dist/ui/{PermitOfferInbox.svelte → RoleGrantOfferInbox.svelte} +14 -14
  276. package/dist/ui/{PermitOfferInbox.svelte.d.ts → RoleGrantOfferInbox.svelte.d.ts} +4 -4
  277. package/dist/ui/RoleGrantOfferInbox.svelte.d.ts.map +1 -0
  278. package/dist/ui/SignupForm.svelte +1 -1
  279. package/dist/ui/SurfaceExplorer.svelte +35 -15
  280. package/dist/ui/SurfaceExplorer.svelte.d.ts.map +1 -1
  281. package/dist/ui/account_sessions_state.svelte.d.ts +2 -3
  282. package/dist/ui/account_sessions_state.svelte.d.ts.map +1 -1
  283. package/dist/ui/account_sessions_state.svelte.js +2 -3
  284. package/dist/ui/admin_accounts_state.svelte.d.ts +18 -18
  285. package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
  286. package/dist/ui/admin_accounts_state.svelte.js +16 -16
  287. package/dist/ui/admin_rpc_adapters.d.ts +20 -20
  288. package/dist/ui/admin_rpc_adapters.d.ts.map +1 -1
  289. package/dist/ui/admin_rpc_adapters.js +17 -17
  290. package/dist/ui/admin_sessions_state.svelte.d.ts +2 -2
  291. package/dist/ui/admin_sessions_state.svelte.js +2 -2
  292. package/dist/ui/audit_log_state.svelte.d.ts +7 -7
  293. package/dist/ui/audit_log_state.svelte.d.ts.map +1 -1
  294. package/dist/ui/audit_log_state.svelte.js +6 -6
  295. package/dist/ui/auth_state.svelte.d.ts +3 -3
  296. package/dist/ui/auth_state.svelte.d.ts.map +1 -1
  297. package/dist/ui/auth_state.svelte.js +6 -6
  298. package/dist/ui/format_scope.d.ts +2 -2
  299. package/dist/ui/format_scope.js +2 -2
  300. package/dist/ui/{permit_offers_state.svelte.d.ts → role_grant_offers_state.svelte.d.ts} +30 -30
  301. package/dist/ui/role_grant_offers_state.svelte.d.ts.map +1 -0
  302. package/dist/ui/{permit_offers_state.svelte.js → role_grant_offers_state.svelte.js} +18 -18
  303. package/dist/ui/ui_format.js +2 -2
  304. package/package.json +3 -3
  305. package/dist/auth/permit_offer_action_specs.d.ts.map +0 -1
  306. package/dist/auth/permit_offer_action_specs.js +0 -258
  307. package/dist/auth/permit_offer_actions.d.ts +0 -110
  308. package/dist/auth/permit_offer_actions.d.ts.map +0 -1
  309. package/dist/auth/permit_offer_notifications.d.ts.map +0 -1
  310. package/dist/auth/permit_offer_notifications.js +0 -182
  311. package/dist/auth/permit_offer_queries.d.ts.map +0 -1
  312. package/dist/auth/permit_offer_schema.d.ts +0 -125
  313. package/dist/auth/permit_offer_schema.d.ts.map +0 -1
  314. package/dist/auth/permit_queries.d.ts +0 -222
  315. package/dist/auth/permit_queries.d.ts.map +0 -1
  316. package/dist/auth/permit_queries.js +0 -305
  317. package/dist/auth/require_keeper.d.ts +0 -20
  318. package/dist/auth/require_keeper.d.ts.map +0 -1
  319. package/dist/auth/require_keeper.js +0 -35
  320. package/dist/auth/route_guards.d.ts +0 -27
  321. package/dist/auth/route_guards.d.ts.map +0 -1
  322. package/dist/auth/route_guards.js +0 -38
  323. package/dist/auth/session_lifecycle.d.ts +0 -37
  324. package/dist/auth/session_lifecycle.d.ts.map +0 -1
  325. package/dist/auth/session_lifecycle.js +0 -29
  326. package/dist/ui/AdminPermitHistory.svelte.d.ts +0 -4
  327. package/dist/ui/AdminPermitHistory.svelte.d.ts.map +0 -1
  328. package/dist/ui/PermitOfferForm.svelte.d.ts.map +0 -1
  329. package/dist/ui/PermitOfferHistory.svelte.d.ts.map +0 -1
  330. package/dist/ui/PermitOfferInbox.svelte.d.ts.map +0 -1
  331. package/dist/ui/permit_offers_state.svelte.d.ts.map +0 -1
@@ -26,6 +26,7 @@ import { RateLimiter } from '../rate_limiter.js';
26
26
  import { run_migrations } from '../db/migrate.js';
27
27
  import { ErrorCoverageCollector, assert_error_coverage, DEFAULT_INTEGRATION_ERROR_COVERAGE, } from './error_coverage.js';
28
28
  import { ApiError, ERROR_FORBIDDEN_ORIGIN } from '../http/error_schemas.js';
29
+ import { is_public_auth } from '../http/auth_shape.js';
29
30
  import { account_verify_action_spec, account_session_list_action_spec, account_session_revoke_action_spec, account_session_revoke_all_action_spec, account_token_create_action_spec, account_token_list_action_spec, account_token_revoke_action_spec, } from '../auth/account_action_specs.js';
30
31
  import { invite_create_action_spec } from '../auth/admin_action_specs.js';
31
32
  /**
@@ -93,7 +94,7 @@ export const describe_standard_integration_tests = (options) => {
93
94
  // dilute the coverage percentage; admin-role routes are scoped
94
95
  // to the admin suite instead.
95
96
  const auth_routes = captured_route_specs.filter((s) => {
96
- if (s.auth.type === 'role' && s.auth.role === 'admin')
97
+ if (s.auth.roles?.includes('admin') ?? false)
97
98
  return false;
98
99
  const rest_suffixes = ['/login', '/logout', '/password', '/signup', '/bootstrap'];
99
100
  if (rest_suffixes.some((suffix) => s.path.endsWith(suffix)))
@@ -645,7 +646,7 @@ export const describe_standard_integration_tests = (options) => {
645
646
  const test_app = await create_test_app(build_test_app_options(options, get_db()));
646
647
  // admin routes are optional in the base suite — admin-specific coverage
647
648
  // lives in describe_standard_admin_integration_tests
648
- const admin_route = test_app.route_specs.find((s) => s.auth.type === 'role' && s.auth.role === 'admin');
649
+ const admin_route = test_app.route_specs.find((s) => s.auth.roles?.includes('admin') ?? false);
649
650
  if (!admin_route)
650
651
  return;
651
652
  const res = await test_app.app.request(admin_route.path, {
@@ -788,11 +789,9 @@ export const describe_standard_integration_tests = (options) => {
788
789
  // --- 9. Response body validation ---
789
790
  describe('response body validation', () => {
790
791
  // `assert_response_matches_spec` validates REST `RouteSpec` outputs.
791
- // The account REST routes that used to cover this (/verify, /sessions,
792
- // /tokens, /tokens/create) moved to RPC in the 2026-04-23 migration,
793
- // so we exercise the remaining REST endpoints (/login, /logout,
794
- // /password) against their declared schemas. RPC output validation is
795
- // covered by `describe_rpc_round_trip_tests`.
792
+ // Session/token CRUD lives on the RPC surface; only /login, /logout,
793
+ // /password remain as REST routes whose responses we exercise here.
794
+ // RPC output validation is covered by `describe_rpc_round_trip_tests`.
796
795
  test('POST /login 401 response matches declared error schema', async () => {
797
796
  const test_app = await create_test_app(build_test_app_options(options, get_db()));
798
797
  const login_route = find_auth_route(test_app.route_specs, '/login', 'POST');
@@ -1091,12 +1090,12 @@ export const describe_standard_integration_tests = (options) => {
1091
1090
  describe('signup invite edge cases', () => {
1092
1091
  test('signup with non-matching email cannot claim another email invite', async () => {
1093
1092
  const test_app = await create_test_app(build_test_app_options(options, get_db()));
1094
- const signup_route = test_app.route_specs.find((s) => s.method === 'POST' && s.path.endsWith('/signup') && s.auth.type === 'none');
1093
+ const signup_route = test_app.route_specs.find((s) => s.method === 'POST' && s.path.endsWith('/signup') && is_public_auth(s.auth));
1095
1094
  if (!signup_route)
1096
1095
  return; // signup is optional
1097
- // `invite_create` became RPC-only in the 2026-04-23 migration.
1098
- // Consumers that don't wire admin RPC actions can't exercise invites;
1099
- // skip the test rather than fail.
1096
+ // `invite_create` lives on the RPC surface; consumers that don't
1097
+ // wire admin RPC actions can't exercise invites — skip the test
1098
+ // rather than fail.
1100
1099
  if (!find_rpc_action(rpc_endpoints_for_setup, invite_create_action_spec.method))
1101
1100
  return;
1102
1101
  // Create an admin to manage invites
@@ -1137,11 +1136,11 @@ export const describe_standard_integration_tests = (options) => {
1137
1136
  test('no-invite and conflict failure responses are structurally identical', async () => {
1138
1137
  const test_app = await create_test_app(build_test_app_options(options, get_db()));
1139
1138
  // Find signup route (POST ending in /signup, public)
1140
- const signup_route = test_app.route_specs.find((s) => s.method === 'POST' && s.path.endsWith('/signup') && s.auth.type === 'none');
1139
+ const signup_route = test_app.route_specs.find((s) => s.method === 'POST' && s.path.endsWith('/signup') && is_public_auth(s.auth));
1141
1140
  if (!signup_route)
1142
1141
  return; // signup is optional
1143
- // `invite_create` became RPC-only in the 2026-04-23 migration.
1144
- // Consumers that don't wire admin RPC actions can't exercise invites.
1142
+ // `invite_create` lives on the RPC surface; consumers that don't
1143
+ // wire admin RPC actions can't exercise invites.
1145
1144
  if (!find_rpc_action(rpc_endpoints_for_setup, invite_create_action_spec.method))
1146
1145
  return;
1147
1146
  // We need admin access — create an admin account
@@ -12,10 +12,10 @@ import type { TestApp, TestAccount } from './app_server.js';
12
12
  */
13
13
  export declare const find_route_spec: (specs: Array<RouteSpec>, method: string, path: string) => RouteSpec | undefined;
14
14
  /**
15
- * REST auth route suffixes still on the account/bootstrap surface after the
16
- * 2026-04-22 RPC migration. `find_auth_route` rejects any other suffix at
17
- * runtime — session/token CRUD, admin operations, and permit flows live on
18
- * the RPC surface and should be reached via `rpc_call`.
15
+ * REST auth route suffixes on the account/bootstrap surface the only
16
+ * routes still REST. `find_auth_route` rejects any other suffix at runtime;
17
+ * session/token CRUD, admin operations, and role_grant flows live on the RPC
18
+ * surface and should be reached via `rpc_call`.
19
19
  */
20
20
  export declare const REST_AUTH_ROUTE_SUFFIXES: readonly ["/login", "/logout", "/password", "/verify", "/signup", "/bootstrap"];
21
21
  export type RestAuthRouteSuffix = (typeof REST_AUTH_ROUTE_SUFFIXES)[number];
@@ -1 +1 @@
1
- {"version":3,"file":"integration_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/integration_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAU7B,OAAO,KAAK,EAAC,SAAS,EAAE,WAAW,EAAC,MAAM,uBAAuB,CAAC;AAElE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAA8B,KAAK,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAE3F,OAAO,KAAK,EAAC,OAAO,EAAE,WAAW,EAAC,MAAM,iBAAiB,CAAC;AAE1D;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAC3B,OAAO,KAAK,CAAC,SAAS,CAAC,EACvB,QAAQ,MAAM,EACd,MAAM,MAAM,KACV,SAAS,GAAG,SAad,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,iFAO3B,CAAC;AACX,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,GAC3B,OAAO,KAAK,CAAC,SAAS,CAAC,EACvB,QAAQ,mBAAmB,EAC3B,QAAQ,WAAW,KACjB,SAAS,GAAG,SAOd,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,GACxC,aAAa,KAAK,CAAC,SAAS,CAAC,EAC7B,QAAQ,MAAM,EACd,MAAM,MAAM,EACZ,UAAU,QAAQ,KAChB,OAAO,CAAC,IAAI,CAmDd,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,GACtC,SAAS,OAAO,EAChB,iBAAiB,cAAc,CAAC,MAAM,CAAC,KACrC,OAAO,CAAC,MAAM,CAGhB,CAAC;AAgCF;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,GAAI,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,KAAK,CAAC,MAAM,CAQvF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,GAAI,MAAM,OAAO,EAAE,SAAS,MAAM,KAAG,IAoB7E,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,oCAAoC,GAChD,UAAU,QAAQ,EAClB,MAAM;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC,KACzB,IAUF,CAAC;AAIF,oEAAoE;AACpE,eAAO,MAAM,yBAAyB,EAAE,aAAa,CAAC,MAAM,CAAmC,CAAC;AAEhG,0EAA0E;AAC1E,eAAO,MAAM,0BAA0B,EAAE,aAAa,CAAC,MAAM,CAAgC,CAAC;AAE9F;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,GAAI,OAAO,OAAO,KAAG,GAAG,CAAC,MAAM,CAetE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,GAC9C,MAAM,OAAO,EACb,WAAW,aAAa,CAAC,MAAM,CAAC,EAChC,SAAS,MAAM,KACb,IAKF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,GAC7B,MAAM,SAAS,EACf,UAAU,OAAO,EACjB,gBAAgB,WAAW,EAC3B,eAAe,WAAW,KACxB,MAAM,CAAC,MAAM,EAAE,MAAM,CAcvB,CAAC"}
1
+ {"version":3,"file":"integration_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/integration_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAU7B,OAAO,KAAK,EAAC,SAAS,EAAE,WAAW,EAAC,MAAM,uBAAuB,CAAC;AAGlE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAA8B,KAAK,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAE3F,OAAO,KAAK,EAAC,OAAO,EAAE,WAAW,EAAC,MAAM,iBAAiB,CAAC;AAE1D;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAC3B,OAAO,KAAK,CAAC,SAAS,CAAC,EACvB,QAAQ,MAAM,EACd,MAAM,MAAM,KACV,SAAS,GAAG,SAad,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,iFAO3B,CAAC;AACX,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,GAC3B,OAAO,KAAK,CAAC,SAAS,CAAC,EACvB,QAAQ,mBAAmB,EAC3B,QAAQ,WAAW,KACjB,SAAS,GAAG,SAOd,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,GACxC,aAAa,KAAK,CAAC,SAAS,CAAC,EAC7B,QAAQ,MAAM,EACd,MAAM,MAAM,EACZ,UAAU,QAAQ,KAChB,OAAO,CAAC,IAAI,CAmDd,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,GACtC,SAAS,OAAO,EAChB,iBAAiB,cAAc,CAAC,MAAM,CAAC,KACrC,OAAO,CAAC,MAAM,CAGhB,CAAC;AAgCF;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,GAAI,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,KAAK,CAAC,MAAM,CAQvF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,GAAI,MAAM,OAAO,EAAE,SAAS,MAAM,KAAG,IAoB7E,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,oCAAoC,GAChD,UAAU,QAAQ,EAClB,MAAM;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC,KACzB,IAUF,CAAC;AAIF,oEAAoE;AACpE,eAAO,MAAM,yBAAyB,EAAE,aAAa,CAAC,MAAM,CAAmC,CAAC;AAEhG,0EAA0E;AAC1E,eAAO,MAAM,0BAA0B,EAAE,aAAa,CAAC,MAAM,CAAgC,CAAC;AAE9F;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,GAAI,OAAO,OAAO,KAAG,GAAG,CAAC,MAAM,CAetE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,GAC9C,MAAM,OAAO,EACb,WAAW,aAAa,CAAC,MAAM,CAAC,EAChC,SAAS,MAAM,KACb,IAKF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,GAC7B,MAAM,SAAS,EACf,UAAU,OAAO,EACjB,gBAAgB,WAAW,EAC3B,eAAe,WAAW,KACxB,MAAM,CAAC,MAAM,EAAE,MAAM,CAevB,CAAC"}
@@ -6,6 +6,7 @@ import './assert_dev_env.js';
6
6
  */
7
7
  import { assert } from 'vitest';
8
8
  import { is_null_schema, merge_error_schemas } from '../http/schema_helpers.js';
9
+ import { is_public_auth } from '../http/auth_shape.js';
9
10
  import { create_session_cookie_value } from '../auth/session_cookie.js';
10
11
  import { ROLE_ADMIN } from '../auth/role_schema.js';
11
12
  /**
@@ -32,10 +33,10 @@ export const find_route_spec = (specs, method, path) => {
32
33
  });
33
34
  };
34
35
  /**
35
- * REST auth route suffixes still on the account/bootstrap surface after the
36
- * 2026-04-22 RPC migration. `find_auth_route` rejects any other suffix at
37
- * runtime — session/token CRUD, admin operations, and permit flows live on
38
- * the RPC surface and should be reached via `rpc_call`.
36
+ * REST auth route suffixes on the account/bootstrap surface the only
37
+ * routes still REST. `find_auth_route` rejects any other suffix at runtime;
38
+ * session/token CRUD, admin operations, and role_grant flows live on the RPC
39
+ * surface and should be reached via `rpc_call`.
39
40
  */
40
41
  export const REST_AUTH_ROUTE_SUFFIXES = [
41
42
  '/login',
@@ -133,9 +134,9 @@ export const create_expired_test_cookie = async (keyring, session_options) => {
133
134
  const KNOWN_SAFE_ERROR_FIELDS = new Set([
134
135
  'error',
135
136
  'issues',
136
- 'required_role',
137
+ 'required_roles',
138
+ 'required_credential_types',
137
139
  'retry_after',
138
- 'credential_type',
139
140
  'has_references',
140
141
  'ok',
141
142
  ]);
@@ -254,17 +255,18 @@ export const assert_no_sensitive_fields_in_json = (body, blocklist, context) =>
254
255
  * - `keeper` — the test app's daemon token
255
256
  */
256
257
  export const pick_auth_headers = (spec, test_app, authed_account, admin_account) => {
257
- switch (spec.auth.type) {
258
- case 'none':
259
- return { host: 'localhost', origin: 'http://localhost:5173' };
260
- case 'authenticated':
261
- return authed_account.create_session_headers();
262
- case 'role':
263
- if (spec.auth.role === ROLE_ADMIN) {
264
- return admin_account.create_session_headers();
265
- }
266
- return test_app.create_session_headers();
267
- case 'keeper':
268
- return test_app.create_daemon_token_headers();
258
+ const { auth } = spec;
259
+ if (is_public_auth(auth)) {
260
+ return { host: 'localhost', origin: 'http://localhost:5173' };
261
+ }
262
+ if (auth.credential_types?.includes('daemon_token')) {
263
+ return test_app.create_daemon_token_headers();
264
+ }
265
+ if (auth.roles?.length) {
266
+ if (auth.roles.includes(ROLE_ADMIN)) {
267
+ return admin_account.create_session_headers();
268
+ }
269
+ return test_app.create_session_headers();
269
270
  }
271
+ return authed_account.create_session_headers();
270
272
  };
@@ -27,8 +27,8 @@ export interface BearerAuthTestOptions {
27
27
  mock_find_by_id_result?: unknown;
28
28
  /** What `query_actor_by_id()` returns. */
29
29
  mock_find_actor_by_id_result?: unknown;
30
- /** What `query_permit_find_active_for_actor()` returns. */
31
- mock_permits_result?: unknown;
30
+ /** What `query_role_grant_find_active_for_actor()` returns. */
31
+ mock_role_grants_result?: unknown;
32
32
  /** Expected HTTP status, or `'next'` if the middleware should call `next()`. */
33
33
  expected_status: number | 'next';
34
34
  /** Expected `error` field in JSON response body. */
@@ -63,12 +63,12 @@ export interface BearerAuthMocks {
63
63
  * Create mock dependencies for `create_bearer_auth_middleware`, configured per test case.
64
64
  *
65
65
  * Configures the module-level mocks for `query_validate_api_token`,
66
- * `query_account_by_id`, `query_actor_by_id`, and `query_permit_find_active_for_actor`
66
+ * `query_account_by_id`, `query_actor_by_id`, and `query_role_grant_find_active_for_actor`
67
67
  * so each test case controls return values independently.
68
68
  *
69
69
  * @returns mocks bundle with spy references
70
70
  * @mutates module-level `vi.mock` registrations for `api_token_queries`,
71
- * `account_queries`, and `permit_queries` — each call resets and re-binds
71
+ * `account_queries`, and `role_grant_queries` — each call resets and re-binds
72
72
  * the four spies, so cases run in sequence without bleeding state.
73
73
  */
74
74
  export declare const create_bearer_auth_mocks: (tc: BearerAuthTestOptions) => BearerAuthMocks;
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/middleware.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B;;;;;;;;GAQG;AAEH,OAAO,EAAC,EAAE,EAAyB,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAC,IAAI,EAAC,MAAM,MAAM,CAAC;AAC1B,OAAO,KAAK,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAc3B,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAsB,KAAK,cAAc,EAAC,MAAM,4BAA4B,CAAC;AA2BpF,gEAAgE;AAChE,MAAM,WAAW,qBAAqB;IACrC,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,uBAAuB;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,oEAAoE;IACpE,WAAW,CAAC,EAAE,cAAc,CAAC;IAC7B,iDAAiD;IACjD,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,4CAA4C;IAC5C,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,0CAA0C;IAC1C,4BAA4B,CAAC,EAAE,OAAO,CAAC;IACvC,+DAA+D;IAC/D,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,gFAAgF;IAChF,eAAe,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,oDAAoD;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+GAA+G;IAC/G,qBAAqB,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;CAClC;AAED,gEAAgE;AAChE,MAAM,WAAW,kBAAmB,SAAQ,qBAAqB;IAChE,+EAA+E;IAC/E,oBAAoB,EAAE,QAAQ,GAAG,YAAY,CAAC;IAC9C,2FAA2F;IAC3F,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,yEAAyE;IACzE,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mGAAmG;IACnG,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,mGAAmG;IACnG,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,uEAAuE;IACvE,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;CAChD;AAID,2DAA2D;AAC3D,MAAM,WAAW,eAAe;IAC/B,aAAa,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IACxC,eAAe,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC1C,qBAAqB,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAChD,2BAA2B,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IACtD,0BAA0B,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;CACrD;AAKD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,wBAAwB,GAAI,IAAI,qBAAqB,KAAG,eAoCpE,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,cAAc,cAAc,CAAC;AAE1C;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,GACvC,IAAI,qBAAqB,EACzB,kBAAiB,WAAW,GAAG,IAAW,KACxC;IAAC,GAAG,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,eAAe,CAAA;CAyDpC,CAAC;AAIF;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,GACtC,YAAY,MAAM,EAClB,OAAO,KAAK,CAAC,kBAAkB,CAAC,EAChC,kBAAiB,WAAW,GAAG,IAAW,KACxC,IAyEF,CAAC;AAIF,yEAAyE;AACzE,eAAO,MAAM,oBAAoB,cAAc,CAAC;AAEhD,sDAAsD;AACtD,MAAM,WAAW,0BAA0B;IAC1C,iDAAiD;IACjD,eAAe,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAChC,oFAAoF;IACpF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6DAA6D;IAC7D,aAAa,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC;IACpD,oDAAoD;IACpD,eAAe,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CACrC;AAED,yDAAyD;AACzD,MAAM,WAAW,sBAAsB;IACtC,GAAG,EAAE,IAAI,CAAC;IACV,aAAa,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IACxC,eAAe,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC1C,qBAAqB,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAChD,2BAA2B,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IACtD,0BAA0B,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;CACrD;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,gCAAgC,GAC5C,UAAU,0BAA0B,KAClC,sBA4DF,CAAC"}
@@ -14,7 +14,7 @@ import { Logger } from '@fuzdev/fuz_util/log.js';
14
14
  import { create_bearer_auth_middleware } from '../auth/bearer_auth.js';
15
15
  import { query_validate_api_token } from '../auth/api_token_queries.js';
16
16
  import { query_account_by_id, query_actor_by_id, query_actors_by_account, } from '../auth/account_queries.js';
17
- import { query_permit_find_active_for_actor } from '../auth/permit_queries.js';
17
+ import { query_role_grant_find_active_for_actor } from '../auth/role_grant_queries.js';
18
18
  import { create_proxy_middleware, get_client_ip } from '../http/proxy.js';
19
19
  import { verify_request_source, parse_allowed_origins } from '../http/origin.js';
20
20
  import { REQUEST_CONTEXT_KEY } from '../auth/request_context.js';
@@ -30,8 +30,8 @@ vi.mock('../auth/account_queries.js', () => ({
30
30
  query_actor_by_id: vi.fn(),
31
31
  query_actors_by_account: vi.fn(),
32
32
  }));
33
- vi.mock('../auth/permit_queries.js', () => ({
34
- query_permit_find_active_for_actor: vi.fn(),
33
+ vi.mock('../auth/role_grant_queries.js', () => ({
34
+ query_role_grant_find_active_for_actor: vi.fn(),
35
35
  }));
36
36
  /** Stub `QueryDeps` for bearer auth tests (no real DB needed). */
37
37
  const STUB_DEPS = { db: {} };
@@ -39,12 +39,12 @@ const STUB_DEPS = { db: {} };
39
39
  * Create mock dependencies for `create_bearer_auth_middleware`, configured per test case.
40
40
  *
41
41
  * Configures the module-level mocks for `query_validate_api_token`,
42
- * `query_account_by_id`, `query_actor_by_id`, and `query_permit_find_active_for_actor`
42
+ * `query_account_by_id`, `query_actor_by_id`, and `query_role_grant_find_active_for_actor`
43
43
  * so each test case controls return values independently.
44
44
  *
45
45
  * @returns mocks bundle with spy references
46
46
  * @mutates module-level `vi.mock` registrations for `api_token_queries`,
47
- * `account_queries`, and `permit_queries` — each call resets and re-binds
47
+ * `account_queries`, and `role_grant_queries` — each call resets and re-binds
48
48
  * the four spies, so cases run in sequence without bleeding state.
49
49
  */
50
50
  export const create_bearer_auth_mocks = (tc) => {
@@ -52,7 +52,7 @@ export const create_bearer_auth_mocks = (tc) => {
52
52
  const mock_find_by_id = vi.mocked(query_account_by_id);
53
53
  const mock_find_actor_by_id = vi.mocked(query_actor_by_id);
54
54
  const mock_find_actors_by_account = vi.mocked(query_actors_by_account);
55
- const mock_find_active_for_actor = vi.mocked(query_permit_find_active_for_actor);
55
+ const mock_find_active_for_actor = vi.mocked(query_role_grant_find_active_for_actor);
56
56
  mock_validate
57
57
  .mockReset()
58
58
  .mockImplementation(() => Promise.resolve(tc.mock_validate_result));
@@ -73,7 +73,7 @@ export const create_bearer_auth_mocks = (tc) => {
73
73
  });
74
74
  mock_find_active_for_actor
75
75
  .mockReset()
76
- .mockImplementation(() => Promise.resolve(tc.mock_permits_result ?? []));
76
+ .mockImplementation(() => Promise.resolve(tc.mock_role_grants_result ?? []));
77
77
  return {
78
78
  mock_validate,
79
79
  mock_find_by_id,
@@ -97,9 +97,10 @@ export const create_bearer_auth_test_app = (tc, ip_rate_limiter = null) => {
97
97
  // inject pre-existing session identity if the test case specifies one.
98
98
  // `pre_context` simulates the session middleware having authenticated
99
99
  // the caller — sets `ACCOUNT_ID_KEY` (the account-grain identity bearer
100
- // auth checks) and the legacy `REQUEST_CONTEXT_KEY` (preserved through
101
- // the bearer middleware unchanged so consumer expectations on the full
102
- // context shape stay testable).
100
+ // auth checks) and pre-populates `REQUEST_CONTEXT_KEY` as a test
101
+ // escape-hatch (production bearer middleware is account-only and never
102
+ // sets this key — see `auth/CLAUDE.md` Production-middleware invariant)
103
+ // so consumer expectations on the full context shape stay testable.
103
104
  if (tc.pre_context) {
104
105
  const pre_context = tc.pre_context;
105
106
  app.use('*', async (c, next) => {
@@ -210,7 +211,7 @@ export const create_test_middleware_stack_app = (options) => {
210
211
  const mock_find_by_id = vi.mocked(query_account_by_id);
211
212
  const mock_find_actor_by_id = vi.mocked(query_actor_by_id);
212
213
  const mock_find_actors_by_account = vi.mocked(query_actors_by_account);
213
- const mock_find_active_for_actor = vi.mocked(query_permit_find_active_for_actor);
214
+ const mock_find_active_for_actor = vi.mocked(query_role_grant_find_active_for_actor);
214
215
  mock_validate.mockReset().mockImplementation(() => Promise.resolve(undefined));
215
216
  mock_find_by_id.mockReset().mockImplementation(() => Promise.resolve(undefined));
216
217
  mock_find_actor_by_id.mockReset().mockImplementation(() => Promise.resolve(undefined));
@@ -1 +1 @@
1
- {"version":3,"file":"rpc_attack_surface.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_attack_surface.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAkB7B,OAAO,KAAK,EAA6C,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAoBnG,uDAAuD;AACvD,MAAM,WAAW,uBAAuB;IACvC,+FAA+F;IAC/F,KAAK,EAAE,MAAM,cAAc,CAAC;IAC5B,yDAAyD;IACzD,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACrB;AAodD;;;;;;;;;GASG;AACH,eAAO,MAAM,iCAAiC,GAAI,SAAS,uBAAuB,KAAG,IAOpF,CAAC"}
1
+ {"version":3,"file":"rpc_attack_surface.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_attack_surface.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAkB7B,OAAO,KAAK,EAA6C,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAqBnG,uDAAuD;AACvD,MAAM,WAAW,uBAAuB;IACvC,+FAA+F;IAC/F,KAAK,EAAE,MAAM,cAAc,CAAC;IAC5B,yDAAyD;IACzD,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACrB;AA0dD;;;;;;;;;GASG;AACH,eAAO,MAAM,iCAAiC,GAAI,SAAS,uBAAuB,KAAG,IAOpF,CAAC"}
@@ -13,18 +13,23 @@ import './assert_dev_env.js';
13
13
  * @module
14
14
  */
15
15
  import { test, assert, describe } from 'vitest';
16
+ import { is_keeper_auth, is_public_auth, is_role_auth } from '../http/auth_shape.js';
16
17
  import { JSONRPC_ERROR_CODES } from '../http/jsonrpc_errors.js';
17
18
  import { create_auth_test_apps, create_test_app_from_specs, create_test_request_context, select_auth_app, } from './auth_apps.js';
18
19
  import { generate_input_test_cases } from './adversarial_input.js';
20
+ import { generate_valid_body } from './schema_generators.js';
19
21
  import { ERROR_INVALID_JSON_BODY } from '../http/error_schemas.js';
20
22
  import { create_rpc_post_init, create_rpc_get_url, assert_jsonrpc_error_response, } from './rpc_helpers.js';
21
23
  // --- Helpers ---
22
24
  /** Filter RPC methods that require any form of authentication. */
23
- const filter_protected_rpc_methods = (endpoint) => endpoint.methods.filter((m) => m.auth.type !== 'none');
24
- /** Filter RPC methods that require a specific role. */
25
- const filter_role_rpc_methods = (endpoint) => endpoint.methods.filter((m) => m.auth.type === 'role');
26
- /** Filter RPC methods that require keeper auth (daemon_token + keeper role). */
27
- const filter_keeper_rpc_methods = (endpoint) => endpoint.methods.filter((m) => m.auth.type === 'keeper');
25
+ const filter_protected_rpc_methods = (endpoint) => endpoint.methods.filter((m) => !is_public_auth(m.auth));
26
+ /** Filter RPC methods that declare a role gate (`auth.roles?.length`). */
27
+ const filter_role_rpc_methods = (endpoint) => endpoint.methods.filter((m) => is_role_auth(m.auth));
28
+ /**
29
+ * Filter RPC methods that require daemon-token credentials. Today this
30
+ * is the keeper bucket; future credential gates will widen the filter.
31
+ */
32
+ const filter_keeper_rpc_methods = (endpoint) => endpoint.methods.filter((m) => is_keeper_auth(m.auth));
28
33
  /** Find the `RpcAction` source spec for a surface method. */
29
34
  const find_rpc_action = (rpc_endpoint_specs, endpoint_path, method_name) => {
30
35
  const ep = rpc_endpoint_specs.find((e) => e.path === endpoint_path);
@@ -47,7 +52,7 @@ const find_rpc_action = (rpc_endpoint_specs, endpoint_path, method_name) => {
47
52
  */
48
53
  const describe_rpc_auth = (options) => {
49
54
  const { build, roles } = options;
50
- const { surface, route_specs } = build();
55
+ const { surface, route_specs, rpc_endpoints: rpc_endpoint_specs } = build();
51
56
  if (surface.rpc_endpoints.length === 0)
52
57
  return;
53
58
  const apps = create_auth_test_apps(route_specs, roles);
@@ -71,13 +76,18 @@ const describe_rpc_auth = (options) => {
71
76
  if (role_methods.length > 0) {
72
77
  describe('wrong role → forbidden', () => {
73
78
  for (const method of role_methods) {
74
- const wrong_roles = roles.filter((r) => r !== method.auth.role);
79
+ const required_roles = method.auth.roles ?? [];
80
+ const wrong_roles = roles.filter((r) => !required_roles.includes(r));
75
81
  for (const wrong_role of wrong_roles) {
76
- test(`${method.name} (${wrong_role} instead of ${method.auth.role})`, async () => {
82
+ test(`${method.name} (${wrong_role} instead of ${required_roles.join('|')})`, async () => {
77
83
  const app = apps.by_role.get(wrong_role);
78
84
  if (!app)
79
85
  throw new Error(`No test app for role '${wrong_role}'`);
80
- const res = await app.request(endpoint.path, create_rpc_post_init(method.name));
86
+ // Send valid params so we trip the role gate (403), not input
87
+ // validation (400). Dispatcher ordering: 401 → 400 → 403.
88
+ const action = find_rpc_action(rpc_endpoint_specs, endpoint.path, method.name);
89
+ const params = action ? generate_valid_body(action.spec.input) : undefined;
90
+ const res = await app.request(endpoint.path, create_rpc_post_init(method.name, params));
81
91
  assert.strictEqual(res.status, 403, `${method.name} should return 403`);
82
92
  const body = await res.json();
83
93
  assert_jsonrpc_error_response(body, JSONRPC_ERROR_CODES.forbidden);
@@ -87,8 +97,12 @@ const describe_rpc_auth = (options) => {
87
97
  });
88
98
  describe('authenticated without role → forbidden', () => {
89
99
  for (const method of role_methods) {
90
- test(`${method.name} (${method.auth.role})`, async () => {
91
- const res = await apps.authed.request(endpoint.path, create_rpc_post_init(method.name));
100
+ test(`${method.name} (${(method.auth.roles ?? []).join('|')})`, async () => {
101
+ // Send valid params so we trip the role gate (403), not input
102
+ // validation (400).
103
+ const action = find_rpc_action(rpc_endpoint_specs, endpoint.path, method.name);
104
+ const params = action ? generate_valid_body(action.spec.input) : undefined;
105
+ const res = await apps.authed.request(endpoint.path, create_rpc_post_init(method.name, params));
92
106
  assert.strictEqual(res.status, 403, `${method.name} should return 403`);
93
107
  const body = await res.json();
94
108
  assert_jsonrpc_error_response(body, JSONRPC_ERROR_CODES.forbidden);
@@ -102,14 +116,16 @@ const describe_rpc_auth = (options) => {
102
116
  const session_app = create_test_app_from_specs(route_specs, create_test_request_context('keeper'), 'session');
103
117
  const api_token_app = create_test_app_from_specs(route_specs, create_test_request_context('keeper'), 'api_token');
104
118
  for (const method of keeper_methods) {
119
+ const action = find_rpc_action(rpc_endpoint_specs, endpoint.path, method.name);
120
+ const valid_params = action ? generate_valid_body(action.spec.input) : undefined;
105
121
  test(`${method.name} rejects session credential`, async () => {
106
- const res = await session_app.request(endpoint.path, create_rpc_post_init(method.name));
122
+ const res = await session_app.request(endpoint.path, create_rpc_post_init(method.name, valid_params));
107
123
  assert.strictEqual(res.status, 403, `${method.name} should reject session credential`);
108
124
  const body = await res.json();
109
125
  assert_jsonrpc_error_response(body, JSONRPC_ERROR_CODES.forbidden);
110
126
  });
111
127
  test(`${method.name} rejects api_token credential`, async () => {
112
- const res = await api_token_app.request(endpoint.path, create_rpc_post_init(method.name));
128
+ const res = await api_token_app.request(endpoint.path, create_rpc_post_init(method.name, valid_params));
113
129
  assert.strictEqual(res.status, 403, `${method.name} should reject api_token credential`);
114
130
  const body = await res.json();
115
131
  assert_jsonrpc_error_response(body, JSONRPC_ERROR_CODES.forbidden);
@@ -279,7 +295,7 @@ const describe_rpc_adversarial_envelopes = (options) => {
279
295
  return;
280
296
  // valid JSON but not an object — hits dispatcher's params validation
281
297
  const res = await apps.public.request(`${endpoint.path}?method=${read_method.name}&id=test&params=42`);
282
- // should reject: either invalid_params (step 4) or auth error (step 3)
298
+ // should reject: either invalid_params (validation) or auth error
283
299
  assert.ok(res.status >= 400, `expected error status for non-object params, got ${res.status}`);
284
300
  const body = await res.json();
285
301
  assert_jsonrpc_error_response(body);
@@ -362,16 +378,16 @@ const describe_rpc_adversarial_params = (options) => {
362
378
  // --- Helpers (formatting) ---
363
379
  /** Format a `RouteAuth` as a human-readable label. */
364
380
  const format_auth = (auth) => {
365
- switch (auth.type) {
366
- case 'none':
367
- return 'public';
368
- case 'authenticated':
369
- return 'authenticated';
370
- case 'role':
371
- return `role: ${auth.role}`;
372
- case 'keeper':
373
- return 'keeper';
374
- }
381
+ if (is_public_auth(auth))
382
+ return 'public';
383
+ const parts = [];
384
+ parts.push(`account:${auth.account}`);
385
+ parts.push(`actor:${auth.actor}`);
386
+ if (auth.roles?.length)
387
+ parts.push(`roles:${auth.roles.join('|')}`);
388
+ if (auth.credential_types?.length)
389
+ parts.push(`creds:${auth.credential_types.join('|')}`);
390
+ return parts.join(' ');
375
391
  };
376
392
  // --- Public API ---
377
393
  /**
@@ -27,7 +27,7 @@ export interface RpcRoundTripTestOptions {
27
27
  app_options?: SuiteAppOptions;
28
28
  /** Database factories to run tests against. Default: pglite only. */
29
29
  db_factories?: Array<DbFactory>;
30
- /** Methods to skip, by name (e.g., `'tx_plan'`). */
30
+ /** Methods to skip, by name (e.g., `'zap_plan'`). */
31
31
  skip_methods?: Array<string>;
32
32
  /** Override generated params for specific methods (method name → params). */
33
33
  input_overrides?: Map<string, Record<string, unknown>>;
@@ -1 +1 @@
1
- {"version":3,"file":"rpc_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAe7B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAE9D,OAAO,EAEN,KAAK,eAAe,EAGpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAwB,KAAK,SAAS,EAAC,MAAM,SAAS,CAAC;AAM9D,OAAO,EAMN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAE1B,mDAAmD;AACnD,MAAM,WAAW,uBAAuB;IACvC,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;;;;;;;;;;OAUG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC,iDAAiD;IACjD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,qEAAqE;IACrE,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAChC,oDAAoD;IACpD,YAAY,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7B,6EAA6E;IAC7E,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACvD;AA2BD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,6BAA6B,GAAI,SAAS,uBAAuB,KAAG,IA8IhF,CAAC"}
1
+ {"version":3,"file":"rpc_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAe7B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAE9D,OAAO,EAEN,KAAK,eAAe,EAGpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAwB,KAAK,SAAS,EAAC,MAAM,SAAS,CAAC;AAO9D,OAAO,EAMN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAE1B,mDAAmD;AACnD,MAAM,WAAW,uBAAuB;IACvC,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;;;;;;;;;;OAUG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC,iDAAiD;IACjD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,qEAAqE;IACrE,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAChC,qDAAqD;IACrD,YAAY,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7B,6EAA6E;IAC7E,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACvD;AA2BD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,6BAA6B,GAAI,SAAS,uBAAuB,KAAG,IA8IhF,CAAC"}
@@ -16,25 +16,26 @@ import { create_pglite_factory } from './db.js';
16
16
  import { generate_valid_body } from './schema_generators.js';
17
17
  import { run_migrations } from '../db/migrate.js';
18
18
  import { AUTH_MIGRATION_NS } from '../auth/migrations.js';
19
+ import { is_public_auth } from '../http/auth_shape.js';
19
20
  import { create_rpc_post_init, create_rpc_get_url, assert_jsonrpc_error_response, assert_jsonrpc_success_response, resolve_rpc_endpoints_for_setup, } from './rpc_helpers.js';
20
21
  /**
21
22
  * Pick auth headers matching an RPC method's auth requirement.
22
23
  */
23
24
  const pick_rpc_auth_headers = (method, test_app, authed_account, admin_account) => {
24
- switch (method.auth.type) {
25
- case 'none':
26
- return { host: 'localhost', origin: 'http://localhost:5173' };
27
- case 'authenticated':
28
- return authed_account.create_session_headers();
29
- case 'role':
30
- if (method.auth.role === ROLE_ADMIN) {
31
- return admin_account.create_session_headers();
32
- }
33
- // keeper role uses the bootstrapped account
34
- return test_app.create_session_headers();
35
- case 'keeper':
36
- return test_app.create_daemon_token_headers();
25
+ const { auth } = method;
26
+ if (is_public_auth(auth)) {
27
+ return { host: 'localhost', origin: 'http://localhost:5173' };
37
28
  }
29
+ if (auth.credential_types?.includes('daemon_token')) {
30
+ return test_app.create_daemon_token_headers();
31
+ }
32
+ if (auth.roles?.length) {
33
+ if (auth.roles.includes(ROLE_ADMIN)) {
34
+ return admin_account.create_session_headers();
35
+ }
36
+ return test_app.create_session_headers();
37
+ }
38
+ return authed_account.create_session_headers();
38
39
  };
39
40
  /**
40
41
  * Run schema-driven round-trip validation for RPC endpoints.
@@ -9,7 +9,7 @@ import { type DbFactory } from './db.js';
9
9
  import { type RpcEndpointsSuiteOption } from './rpc_helpers.js';
10
10
  /** Config for a single SSE route under test. */
11
11
  export interface SseRouteTestSpec {
12
- /** Full HTTP path of the SSE endpoint (e.g., `'/api/tx/subscribe'`). */
12
+ /** Full HTTP path of the SSE endpoint (e.g., `'/api/zap/subscribe'`). */
13
13
  path: string;
14
14
  /**
15
15
  * Fire an event matching one of the declared `event_specs` that should
@@ -51,9 +51,8 @@ export interface SseRouteTestOptions {
51
51
  on_audit_event?: (event: AuditLogEvent) => void;
52
52
  /**
53
53
  * RPC endpoint specs — required so the close-on-revoke assertion can
54
- * dispatch `account_session_revoke_all` via RPC (the former REST route
55
- * `POST /api/account/sessions/revoke-all` was removed in the 2026-04-23
56
- * migration). Hard-fails via `require_rpc_endpoint_path` on setup.
54
+ * dispatch `account_session_revoke_all` via RPC (there is no REST
55
+ * equivalent). Hard-fails via `require_rpc_endpoint_path` on setup.
57
56
  *
58
57
  * Accepts either an array (eager) or a factory
59
58
  * `(ctx: AppServerContext) => Array<RpcEndpointSpec>` — the factory form
@@ -1 +1 @@
1
- {"version":3,"file":"sse_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/sse_round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAmB7B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAwB,KAAK,SAAS,EAAuB,MAAM,oBAAoB,CAAC;AAE/F,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAEN,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAwB,KAAK,SAAS,EAAC,MAAM,SAAS,CAAC;AAE9D,OAAO,EAIN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAM1B,gDAAgD;AAChD,MAAM,WAAW,gBAAgB;IAChC,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,OAAO,EAAE,CAAC,GAAG,EAAE;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,WAAW,CAAA;KAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E;;;OAGG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC/B;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,8CAA8C;AAC9C,MAAM,WAAW,mBAAmB;IACnC,4CAA4C;IAC5C,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,qDAAqD;IACrD,kBAAkB,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE,iDAAiD;IACjD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,qEAAqE;IACrE,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAChC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAChD;;;;;;;;;;;;;OAaG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC,8BAA8B;IAC9B,MAAM,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;CAChC;AAyHD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,GAAI,SAAS,mBAAmB,KAAG,IA2HvE,CAAC"}
1
+ {"version":3,"file":"sse_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/sse_round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAmB7B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAwB,KAAK,SAAS,EAAuB,MAAM,oBAAoB,CAAC;AAE/F,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAEN,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAwB,KAAK,SAAS,EAAC,MAAM,SAAS,CAAC;AAE9D,OAAO,EAIN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAM1B,gDAAgD;AAChD,MAAM,WAAW,gBAAgB;IAChC,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,OAAO,EAAE,CAAC,GAAG,EAAE;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,WAAW,CAAA;KAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E;;;OAGG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC/B;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,8CAA8C;AAC9C,MAAM,WAAW,mBAAmB;IACnC,4CAA4C;IAC5C,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,qDAAqD;IACrD,kBAAkB,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE,iDAAiD;IACjD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,qEAAqE;IACrE,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAChC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAChD;;;;;;;;;;;;OAYG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC,8BAA8B;IAC9B,MAAM,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;CAChC;AAyHD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,GAAI,SAAS,mBAAmB,KAAG,IA2HvE,CAAC"}
@@ -229,18 +229,14 @@ export const describe_sse_route_tests = (options) => {
229
229
  * (keeper, other roles) uses the bootstrapped keeper account.
230
230
  */
231
231
  const pick_account_for_auth = (spec, test_app, authed_account, admin_account) => {
232
- switch (spec.auth.type) {
233
- case 'authenticated':
234
- return authed_account;
235
- case 'role':
236
- if (spec.auth.role === ROLE_ADMIN)
237
- return admin_account;
238
- // keeper role — bootstrapped account is the keeper; model it as a TestAccount
239
- return bootstrap_as_account(test_app);
240
- case 'keeper':
241
- case 'none':
242
- return bootstrap_as_account(test_app);
232
+ const { auth } = spec;
233
+ if (auth.roles?.includes(ROLE_ADMIN))
234
+ return admin_account;
235
+ if (auth.account === 'required' && !auth.roles?.length && !auth.credential_types?.length) {
236
+ return authed_account;
243
237
  }
238
+ // keeper / other-role / public — bootstrapped account
239
+ return bootstrap_as_account(test_app);
244
240
  };
245
241
  /**
246
242
  * Treat the bootstrapped `TestApp` account as a `TestAccount` for revocation.
@@ -36,7 +36,7 @@ export interface StandardTestOptions {
36
36
  /**
37
37
  * RPC endpoint specs — required. The standard integration tests drive
38
38
  * `account_verify`, `account_session_*`, `account_token_*` through the
39
- * RPC surface (and admin tests, when wired, drive permit grant/revoke
39
+ * RPC surface (and admin tests, when wired, drive role_grant grant/revoke
40
40
  * through it too).
41
41
  *
42
42
  * Accepts either an array (eager) or a factory
@@ -3,11 +3,13 @@ import type { z } from 'zod';
3
3
  import type { SessionOptions } from '../auth/session_cookie.js';
4
4
  import type { MiddlewareSpec } from '../http/middleware_spec.js';
5
5
  import type { AppDeps } from '../auth/deps.js';
6
+ import type { AuditEmitter } from '../auth/audit_emitter.js';
6
7
  import type { AppServerContext } from '../server/app_server.js';
7
8
  import { Db } from '../db/db.js';
8
9
  import { type RouteSpec } from '../http/route_spec.js';
9
10
  import { type AppSurfaceSpec, type RpcEndpointSpec } from '../http/surface.js';
10
11
  import type { EventSpec } from '../realtime/sse.js';
12
+ import { type AuditLogSse } from '../realtime/sse_auth_guard.js';
11
13
  /**
12
14
  * Create a Proxy that throws descriptive errors on any property access or method call.
13
15
  *
@@ -51,6 +53,29 @@ export declare const create_stub_db: () => Db;
51
53
  export declare const stub_handler: () => Response;
52
54
  /** Stub middleware that passes through. */
53
55
  export declare const stub_mw: (_c: any, next: any) => Promise<void>;
56
+ /**
57
+ * Build a no-op `AuditEmitter` for tests that don't assert on audit fan-out.
58
+ *
59
+ * `emit` / `emit_role_grant_target` are no-ops; `emit_pool` resolves
60
+ * immediately; `notify` is a no-op; `on_event_chain` is a frozen empty
61
+ * array — pushing onto it throws at runtime, so a test that wires a
62
+ * listener fails loudly instead of silently never firing. Tests asserting
63
+ * on real audit-row persistence (or on listener fan-out) build a real
64
+ * emitter via `create_audit_emitter` against a stub or real DB —
65
+ * `create_test_app` already does this on the test backend.
66
+ */
67
+ export declare const create_test_audit_emitter: () => AuditEmitter;
68
+ /**
69
+ * Build a no-op `AuditLogSse` for tests that wire `audit_sse` into the
70
+ * surface helper but don't assert on SSE fan-out or subscriber state.
71
+ *
72
+ * `subscribe` returns a no-op cleanup; `on_audit_event` is a no-op; the
73
+ * `registry` is a fresh `SubscriberRegistry` instance (call sites that
74
+ * inspect `.size` or call `.close_*` see a real registry, so writes are
75
+ * isolated per test). Tests that need real SSE plumbing build it via
76
+ * `create_audit_log_sse` against `create_test_app`.
77
+ */
78
+ export declare const create_stub_audit_sse: () => AuditLogSse;
54
79
  /** Stub `AppDeps` for auth surface tests — throws on any method access. */
55
80
  export declare const stub_app_deps: AppDeps;
56
81
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"stubs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/stubs.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAa7B,OAAO,KAAK,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAE3B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,4BAA4B,CAAC;AAE/D,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAC,EAAE,EAAC,MAAM,aAAa,CAAC;AAC/B,OAAO,EAAqB,KAAK,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAGzE,OAAO,EAEN,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAKlD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,oBAAoB,GAAI,CAAC,GAAG,GAAG,EAAE,OAAO,MAAM,KAAG,CAqBtD,CAAC;AAET;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,GAAI,CAAC,GAAG,GAAG,EAAE,QAAQ,MAAM,EAAE,YAAY,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,CAOxF,CAAC;AAET,iEAAiE;AACjE,eAAO,MAAM,IAAI,EAAE,GAAkC,CAAC;AAEtD;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,QAAO,EAI/B,CAAC;AAEJ,gDAAgD;AAChD,eAAO,MAAM,YAAY,QAAO,QAAgC,CAAC;AAEjE,2CAA2C;AAC3C,eAAO,MAAM,OAAO,GAAU,IAAI,GAAG,EAAE,MAAM,GAAG,KAAG,OAAO,CAAC,IAAI,CAAW,CAAC;AAI3E,2EAA2E;AAC3E,eAAO,MAAM,aAAa,EAAE,OAS3B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,QAAO,OAStC,CAAC;AAEH,2FAA2F;AAC3F,eAAO,MAAM,0BAA0B,GAAI,UAAU;IACpD,iDAAiD;IACjD,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAC/B,KAAG,KAAK,CAAC,cAAc,CAqBvB,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,8BAA8B,GAC1C,iBAAiB,cAAc,CAAC,MAAM,CAAC,KACrC,gBAqBF,CAAC;AAEF,kDAAkD;AAClD,MAAM,WAAW,+BAA+B;IAC/C,6DAA6D;IAC7D,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,qFAAqF;IACrF,kBAAkB,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE,oEAAoE;IACpE,UAAU,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACzB,8CAA8C;IAC9C,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC/B;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;IAC7F,iFAAiF;IACjF,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,KAAK,CAAC,cAAc,CAAC,CAAC;IAC/E,0DAA0D;IAC1D,sBAAsB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,GACxC,SAAS,+BAA+B,KACtC,cA2CF,CAAC"}
1
+ {"version":3,"file":"stubs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/stubs.ts"],"names":[],"mappings":"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"}