@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
@@ -1,13 +1,28 @@
1
1
  /**
2
- * Role system — builtin roles, role options, and extensible role schema factory.
2
+ * Role system — builtin roles, role specs, and extensible role schema factory.
3
3
  *
4
- * Defines the authorization policy vocabulary: which roles exist, what
5
- * capabilities they require (daemon token, web grantability), and a factory
6
- * for extending with app-defined roles.
4
+ * Defines the authorization policy vocabulary: which roles exist, their
5
+ * required credential types, the scope kinds each role applies to, and
6
+ * the grant paths through which each role can be granted. Each role
7
+ * gets a structured `RoleSpec`; the factory `create_role_schema` merges
8
+ * builtins with consumer-declared specs and validates every cross-axis
9
+ * field against the corresponding open registries
10
+ * (`create_credential_type_schema`, `create_scope_kind_schema`,
11
+ * `create_grant_path_schema`) at construction time so misconfigurations
12
+ * fire at server startup, not at first call.
13
+ *
14
+ * `RoleSpec` carries the four cross-axis fields that the dispatcher
15
+ * branches on: credential type, scope kind, grant path, and the
16
+ * role-name itself. v1 keeps the cross-axis fields informative-only
17
+ * (registry-membership validation, no INSERT-time enforcement); v2 may
18
+ * add `(role, scope_kind)` enforcement once the shape is clear from
19
+ * real consumer usage.
7
20
  *
8
21
  * @module
9
22
  */
10
23
  import { z } from 'zod';
24
+ import { CREDENTIAL_TYPE_DAEMON_TOKEN, } from './credential_type_schema.js';
25
+ import { GRANT_PATH_ADMIN, GRANT_PATH_BOOTSTRAP, } from './grant_path_schema.js';
11
26
  /** Valid role name: lowercase letters and underscores, no leading/trailing underscore. */
12
27
  export const RoleName = z
13
28
  .string()
@@ -15,67 +30,151 @@ export const RoleName = z
15
30
  // Builtin roles — provided by fuz_app, always available.
16
31
  /** System-level role. Requires daemon token (filesystem proof). Controls the keep. */
17
32
  export const ROLE_KEEPER = 'keeper';
18
- /** App-level administrative role. Web-grantable, manages users and content. */
33
+ /** App-level administrative role. Granted via the admin path. */
19
34
  export const ROLE_ADMIN = 'admin';
20
35
  /** The builtin role names as a const tuple. */
21
36
  export const BUILTIN_ROLES = [ROLE_KEEPER, ROLE_ADMIN];
22
37
  /** Zod schema for builtin roles only. */
23
38
  export const BuiltinRole = z.enum(BUILTIN_ROLES);
24
39
  /**
25
- * Builtin role configs. Not overridable by consumers.
26
- *
27
- * Typed `ReadonlyMap` for the contract but JS Maps don't honor
28
- * `Object.freeze` for `.set` / `.delete` / `.clear` (they mutate internal
29
- * slots, not own properties), so freeze adds no runtime guard here. Read
30
- * once at startup by `create_role_schema` and the admin / permit-offer
31
- * action factories; runtime mutation has no effect on already-built role
32
- * schemas.
40
+ * Builtin role specs, keyed by role name. Not overridable by consumers
41
+ * — read once at startup by `create_role_schema` and the action
42
+ * factories that fall back to builtins when no consumer `roles` is
43
+ * supplied. `ReadonlyMap` encodes the contract; runtime mutation has
44
+ * no effect on already-built role schemas (the factory copies entries
45
+ * into a fresh `Map`).
33
46
  */
34
- export const BUILTIN_ROLE_OPTIONS = new Map([
35
- [ROLE_KEEPER, { requires_daemon_token: true, web_grantable: false }],
36
- [ROLE_ADMIN, { requires_daemon_token: false, web_grantable: true }],
47
+ export const BUILTIN_ROLE_SPECS_BY_NAME = new Map([
48
+ [
49
+ ROLE_KEEPER,
50
+ {
51
+ name: ROLE_KEEPER,
52
+ description: 'System-level role; controls the keep. Requires the daemon-token credential and lands via the bootstrap grant path.',
53
+ required_credential_types: [CREDENTIAL_TYPE_DAEMON_TOKEN],
54
+ applicable_scope_kinds: [],
55
+ grant_paths: [GRANT_PATH_BOOTSTRAP],
56
+ },
57
+ ],
58
+ [
59
+ ROLE_ADMIN,
60
+ {
61
+ name: ROLE_ADMIN,
62
+ description: 'App-level administrative role. Web-grantable through the admin path; manages users and content.',
63
+ required_credential_types: [],
64
+ applicable_scope_kinds: [],
65
+ grant_paths: [GRANT_PATH_ADMIN],
66
+ },
67
+ ],
37
68
  ]);
69
+ const validate_registry_membership = (role_name, field, values, registry) => {
70
+ if (!registry || !values)
71
+ return;
72
+ for (const value of values) {
73
+ if (!registry.has(value)) {
74
+ throw new Error(`Role "${role_name}" declares ${field}="${value}" which is not a registered ${field.replace(/s$/, '')}`);
75
+ }
76
+ }
77
+ };
38
78
  /**
39
- * Create a role schema and config map that extends the builtins with app-defined roles.
79
+ * Create a role schema and spec map that extends the builtins with
80
+ * app-defined roles.
81
+ *
82
+ * Call once at server init. The returned `Role` schema validates role
83
+ * strings at I/O boundaries (grant endpoint, role_grant queries). The
84
+ * `role_specs` map is read by middleware for `required_credential_types`
85
+ * checks and by admin / self-service factories to derive their default
86
+ * eligibility filters from `RoleSpec.grant_paths`.
40
87
  *
41
- * Call once at server init. The returned `Role` schema validates role strings
42
- * at I/O boundaries (grant endpoint, permit queries). The `role_options` map
43
- * is used by middleware to check `requires_daemon_token` and by admin UI to
44
- * filter `web_grantable` roles.
88
+ * Construction-time guards (all fire on misconfiguration):
45
89
  *
46
- * @param app_roles - app-defined roles with optional config overrides
47
- * @returns `{Role, role_options}` Zod schema and full config map
90
+ * 1. Every `consumer_roles[i].name` matches `RoleName` regex.
91
+ * 2. No two consumer roles share a name.
92
+ * 3. No consumer role collides with a builtin (`keeper` / `admin`).
93
+ * 4. When `options.credential_types` is supplied, every entry in
94
+ * `required_credential_types` is registered in that map.
95
+ * 5. When `options.scope_kinds` is supplied, every entry in
96
+ * `applicable_scope_kinds` is registered in that map. (Builtins
97
+ * declare empty `applicable_scope_kinds`, so they pass any registry.)
98
+ * 6. When `options.grant_paths` is supplied, every entry in
99
+ * `grant_paths` is registered in that map. (Builtins use only
100
+ * `'admin'` and `'bootstrap'`, both of which are builtin grant
101
+ * paths, so they pass the default registry from
102
+ * `create_grant_path_schema()`.)
48
103
  *
49
- * @throws Error if any `app_roles` key fails the `RoleName` regex or collides with a builtin role
104
+ * @param consumer_roles - app-defined role specs
105
+ * @param options - optional registries for cross-axis validation
106
+ * @returns `{Role, role_specs}` — Zod schema and full spec map
107
+ *
108
+ * @throws Error if any `consumer_roles` entry fails any of the construction-time guards above
50
109
  *
51
110
  * @example
52
111
  * ```ts
53
- * // visiones
54
- * const {Role, role_options} = create_role_schema({
55
- * teacher: {},
112
+ * // visiones — opt into all four registries for full construction-time validation
113
+ * const credential_types = create_credential_type_schema();
114
+ * const scope_kinds = create_scope_kind_schema({
115
+ * classroom: {description: 'A classroom — teacher and student role_grants scope here.'},
56
116
  * });
57
- * // Role validates 'keeper' | 'admin' | 'teacher'
58
- * // role_options has all 3 entries with defaults applied
117
+ * const grant_paths = create_grant_path_schema();
118
+ *
119
+ * const {Role, role_specs} = create_role_schema(
120
+ * [
121
+ * {
122
+ * name: 'teacher',
123
+ * description: 'Educator role. Web-grantable; applies at classroom scope.',
124
+ * grant_paths: ['admin'],
125
+ * applicable_scope_kinds: ['classroom'],
126
+ * },
127
+ * ],
128
+ * {credential_types, scope_kinds, grant_paths},
129
+ * );
59
130
  * ```
60
131
  */
61
- export const create_role_schema = (app_roles) => {
62
- const app_role_names = Object.keys(app_roles);
63
- // Validate role names and no collisions with builtins
64
- for (const name of app_role_names) {
65
- RoleName.parse(name);
66
- if (BUILTIN_ROLE_OPTIONS.has(name)) {
67
- throw new Error(`App role "${name}" collides with builtin role`);
132
+ export const create_role_schema = (consumer_roles, options = {}) => {
133
+ const credential_types_registry = options.credential_types?.credential_types ?? null;
134
+ const scope_kinds_registry = options.scope_kinds?.scope_kinds ?? null;
135
+ const grant_paths_registry = options.grant_paths?.grant_paths ?? null;
136
+ const seen = new Set();
137
+ for (const spec of consumer_roles) {
138
+ const parsed = RoleName.safeParse(spec.name);
139
+ if (!parsed.success) {
140
+ throw new Error(`Invalid role name "${spec.name}": ${parsed.error.issues[0].message}`);
68
141
  }
142
+ if (BUILTIN_ROLE_SPECS_BY_NAME.has(spec.name)) {
143
+ throw new Error(`App role "${spec.name}" collides with builtin role`);
144
+ }
145
+ if (seen.has(spec.name)) {
146
+ throw new Error(`Duplicate role name "${spec.name}"`);
147
+ }
148
+ seen.add(spec.name);
149
+ validate_registry_membership(spec.name, 'required_credential_types', spec.required_credential_types, credential_types_registry);
150
+ validate_registry_membership(spec.name, 'applicable_scope_kinds', spec.applicable_scope_kinds, scope_kinds_registry);
151
+ validate_registry_membership(spec.name, 'grant_paths', spec.grant_paths, grant_paths_registry);
69
152
  }
70
- const all_names = [...BUILTIN_ROLES, ...app_role_names];
153
+ const role_specs = new Map(BUILTIN_ROLE_SPECS_BY_NAME);
154
+ for (const spec of consumer_roles) {
155
+ role_specs.set(spec.name, spec);
156
+ }
157
+ const all_names = [...role_specs.keys()];
71
158
  const Role = z.enum(all_names);
72
- const role_options = new Map(BUILTIN_ROLE_OPTIONS);
73
- for (const name of app_role_names) {
74
- const config = app_roles[name];
75
- role_options.set(name, {
76
- requires_daemon_token: config.requires_daemon_token ?? false,
77
- web_grantable: config.web_grantable ?? true,
78
- });
159
+ return { Role, role_specs };
160
+ };
161
+ /**
162
+ * Predicate over a `RoleSpec` map: does the named role include the given
163
+ * grant path? Returns `false` for unknown roles. Used by
164
+ * `admin_actions.create_admin_actions` (path = `'admin'`) and
165
+ * `self_service_role_actions.create_self_service_role_actions` (path =
166
+ * `'self_service'`) to derive their default eligibility filters.
167
+ */
168
+ export const role_has_grant_path = (role_specs, role, grant_path) => {
169
+ const spec = role_specs.get(role);
170
+ return !!spec?.grant_paths?.includes(grant_path);
171
+ };
172
+ /** Filter helper: list every role whose `grant_paths` includes the given path. */
173
+ export const list_roles_with_grant_path = (role_specs, grant_path) => {
174
+ const out = [];
175
+ for (const [name, spec] of role_specs) {
176
+ if (spec.grant_paths?.includes(grant_path))
177
+ out.push(name);
79
178
  }
80
- return { Role, role_options };
179
+ return out;
81
180
  };
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Scope-kind registry for role_grants and role_grant offers.
3
+ *
4
+ * Role grants have a polymorphic `scope_id` that references whatever entity
5
+ * the consumer chooses (a classroom, a tenant, a workspace, etc.); the
6
+ * `scope_kind` column tags each row with a machine-readable kind so
7
+ * admin UIs, codegen, and (in v2) registry-time `(role, scope_kind)`
8
+ * compatibility checks can read it without re-deriving from `scope_id`.
9
+ *
10
+ * `scope_kind` is encoded as nullable paired with the existing nullable
11
+ * `scope_id` — both null for global, both non-null for scoped, mismatch
12
+ * rejected at the DB layer by the `role_grant_scope_kind_paired` /
13
+ * `role_grant_offer_scope_kind_paired` CHECK constraints. There is no
14
+ * `'global'` magic-string value; the global case is unambiguously
15
+ * `(scope_kind=NULL, scope_id=NULL)`.
16
+ *
17
+ * Open registry, no builtins. Consumers declare their kinds via
18
+ * `create_scope_kind_schema(consumer_kinds)` and pass the result to
19
+ * `create_role_schema` so `RoleSpec.applicable_scope_kinds` can be
20
+ * validated at construction time. Mirrors the open-string registry
21
+ * pattern used for `RoleName`, `AuditEventTypeName`, and `CredentialType`.
22
+ *
23
+ * The literal `'GLOBAL'` (uppercase) appears as an index expression
24
+ * inside the partial unique indexes on `role_grant` and `role_grant_offer`
25
+ * (`COALESCE(scope_kind, 'GLOBAL')`) — never as a column value, never
26
+ * as a registry entry. The uppercase form is structurally distinct
27
+ * from any consumer-declared kind (which match the lowercase
28
+ * `ScopeKindName` regex), so it cannot collide.
29
+ *
30
+ * @module
31
+ */
32
+ import { z } from 'zod';
33
+ /**
34
+ * Letter (lowercase a-z) start and end (or single letter), with letters
35
+ * and underscores in between. Mirrors `RoleName`. Rejects empty strings,
36
+ * leading or trailing underscores, uppercase, digits, and the index-side
37
+ * `'GLOBAL'` token.
38
+ */
39
+ export declare const SCOPE_KIND_NAME_REGEX: RegExp;
40
+ /** Zod schema for valid scope-kind name strings. */
41
+ export declare const ScopeKindName: z.ZodString;
42
+ export type ScopeKindName = z.infer<typeof ScopeKindName>;
43
+ /**
44
+ * Per-scope-kind metadata. `description` is admin-UI-facing copy
45
+ * (mirrors `RoleSpec.description`). Open shape so v2 can extend without
46
+ * a breaking change.
47
+ */
48
+ export interface ScopeKindMeta {
49
+ description?: string;
50
+ }
51
+ /** The result of `create_scope_kind_schema` — a Zod schema and metadata map. */
52
+ export interface ScopeKindSchemaResult {
53
+ /**
54
+ * Zod schema that validates scope-kind name strings against the
55
+ * registered set. Use at I/O boundaries (admin UIs, codegen) and as
56
+ * the construction-time check inside `create_role_schema` for every
57
+ * `RoleSpec.applicable_scope_kinds` entry.
58
+ */
59
+ ScopeKind: z.ZodType<string>;
60
+ /**
61
+ * Map of every registered scope-kind to its metadata. Keyed by name.
62
+ * Read at startup by admin / codegen surfaces.
63
+ */
64
+ scope_kinds: ReadonlyMap<string, ScopeKindMeta>;
65
+ }
66
+ /**
67
+ * Create a scope-kind schema from a consumer-declared registry.
68
+ *
69
+ * Open registry — no builtins. The `'GLOBAL'` token used inside the
70
+ * partial unique indexes on `role_grant` and `role_grant_offer` is not a
71
+ * registry entry (it's an index expression only) and cannot collide
72
+ * with consumer-declared kinds because the regex rejects uppercase.
73
+ *
74
+ * Call once at server init. Pass the result into `create_role_schema`'s
75
+ * optional `scope_kinds` parameter so each role's
76
+ * `applicable_scope_kinds` entries are validated against this set at
77
+ * construction time. v1 keeps `applicable_scope_kinds` informative-only
78
+ * (registry-membership validation only); v2 may add INSERT-time
79
+ * `(role, scope_kind)` enforcement once the shape is clear from real
80
+ * consumer usage.
81
+ *
82
+ * @param consumer_kinds - the consumer-declared scope-kind set with optional metadata
83
+ * @returns `{ScopeKind, scope_kinds}` — Zod schema and metadata map
84
+ *
85
+ * @throws Error if any `consumer_kinds` key fails the `ScopeKindName` regex or appears more than once
86
+ *
87
+ * @example
88
+ * ```ts
89
+ * // visiones
90
+ * const {ScopeKind, scope_kinds} = create_scope_kind_schema({
91
+ * classroom: {description: 'A classroom — teacher and student role_grants scope here.'},
92
+ * });
93
+ * ```
94
+ */
95
+ export declare const create_scope_kind_schema: (consumer_kinds: Record<string, ScopeKindMeta>) => ScopeKindSchemaResult;
96
+ //# sourceMappingURL=scope_kind_schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope_kind_schema.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/scope_kind_schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,QAAgC,CAAC;AAEnE,oDAAoD;AACpD,eAAO,MAAM,aAAa,aAKxB,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,gFAAgF;AAChF,MAAM,WAAW,qBAAqB;IACrC;;;;;OAKG;IACH,SAAS,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7B;;;OAGG;IACH,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CAChD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,wBAAwB,GACpC,gBAAgB,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,KAC3C,qBA0BF,CAAC"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Scope-kind registry for role_grants and role_grant offers.
3
+ *
4
+ * Role grants have a polymorphic `scope_id` that references whatever entity
5
+ * the consumer chooses (a classroom, a tenant, a workspace, etc.); the
6
+ * `scope_kind` column tags each row with a machine-readable kind so
7
+ * admin UIs, codegen, and (in v2) registry-time `(role, scope_kind)`
8
+ * compatibility checks can read it without re-deriving from `scope_id`.
9
+ *
10
+ * `scope_kind` is encoded as nullable paired with the existing nullable
11
+ * `scope_id` — both null for global, both non-null for scoped, mismatch
12
+ * rejected at the DB layer by the `role_grant_scope_kind_paired` /
13
+ * `role_grant_offer_scope_kind_paired` CHECK constraints. There is no
14
+ * `'global'` magic-string value; the global case is unambiguously
15
+ * `(scope_kind=NULL, scope_id=NULL)`.
16
+ *
17
+ * Open registry, no builtins. Consumers declare their kinds via
18
+ * `create_scope_kind_schema(consumer_kinds)` and pass the result to
19
+ * `create_role_schema` so `RoleSpec.applicable_scope_kinds` can be
20
+ * validated at construction time. Mirrors the open-string registry
21
+ * pattern used for `RoleName`, `AuditEventTypeName`, and `CredentialType`.
22
+ *
23
+ * The literal `'GLOBAL'` (uppercase) appears as an index expression
24
+ * inside the partial unique indexes on `role_grant` and `role_grant_offer`
25
+ * (`COALESCE(scope_kind, 'GLOBAL')`) — never as a column value, never
26
+ * as a registry entry. The uppercase form is structurally distinct
27
+ * from any consumer-declared kind (which match the lowercase
28
+ * `ScopeKindName` regex), so it cannot collide.
29
+ *
30
+ * @module
31
+ */
32
+ import { z } from 'zod';
33
+ /**
34
+ * Letter (lowercase a-z) start and end (or single letter), with letters
35
+ * and underscores in between. Mirrors `RoleName`. Rejects empty strings,
36
+ * leading or trailing underscores, uppercase, digits, and the index-side
37
+ * `'GLOBAL'` token.
38
+ */
39
+ export const SCOPE_KIND_NAME_REGEX = /^[a-z][a-z_]*[a-z]$|^[a-z]$/;
40
+ /** Zod schema for valid scope-kind name strings. */
41
+ export const ScopeKindName = z
42
+ .string()
43
+ .regex(SCOPE_KIND_NAME_REGEX, 'Scope-kind names must be lowercase letters and underscores (a-z_), no leading/trailing underscore');
44
+ /**
45
+ * Create a scope-kind schema from a consumer-declared registry.
46
+ *
47
+ * Open registry — no builtins. The `'GLOBAL'` token used inside the
48
+ * partial unique indexes on `role_grant` and `role_grant_offer` is not a
49
+ * registry entry (it's an index expression only) and cannot collide
50
+ * with consumer-declared kinds because the regex rejects uppercase.
51
+ *
52
+ * Call once at server init. Pass the result into `create_role_schema`'s
53
+ * optional `scope_kinds` parameter so each role's
54
+ * `applicable_scope_kinds` entries are validated against this set at
55
+ * construction time. v1 keeps `applicable_scope_kinds` informative-only
56
+ * (registry-membership validation only); v2 may add INSERT-time
57
+ * `(role, scope_kind)` enforcement once the shape is clear from real
58
+ * consumer usage.
59
+ *
60
+ * @param consumer_kinds - the consumer-declared scope-kind set with optional metadata
61
+ * @returns `{ScopeKind, scope_kinds}` — Zod schema and metadata map
62
+ *
63
+ * @throws Error if any `consumer_kinds` key fails the `ScopeKindName` regex or appears more than once
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * // visiones
68
+ * const {ScopeKind, scope_kinds} = create_scope_kind_schema({
69
+ * classroom: {description: 'A classroom — teacher and student role_grants scope here.'},
70
+ * });
71
+ * ```
72
+ */
73
+ export const create_scope_kind_schema = (consumer_kinds) => {
74
+ const names = Object.keys(consumer_kinds);
75
+ const seen = new Set();
76
+ for (const name of names) {
77
+ const parsed = ScopeKindName.safeParse(name);
78
+ if (!parsed.success) {
79
+ throw new Error(`Invalid scope-kind name "${name}": ${parsed.error.issues[0].message}`);
80
+ }
81
+ if (seen.has(name)) {
82
+ throw new Error(`Duplicate scope-kind name "${name}"`);
83
+ }
84
+ seen.add(name);
85
+ }
86
+ const ScopeKind = names.length === 0
87
+ ? z.never()
88
+ : z.enum(names);
89
+ const scope_kinds = new Map();
90
+ for (const name of names) {
91
+ scope_kinds.set(name, consumer_kinds[name]);
92
+ }
93
+ return { ScopeKind, scope_kinds };
94
+ };
@@ -15,6 +15,7 @@ export declare const ERROR_ROLE_NOT_SELF_SERVICE_ELIGIBLE: "role_not_self_servic
15
15
  export declare const SelfServiceRoleSetInput: z.ZodObject<{
16
16
  role: z.ZodString;
17
17
  enabled: z.ZodBoolean;
18
+ acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
18
19
  }, z.core.$strict>;
19
20
  export type SelfServiceRoleSetInput = z.infer<typeof SelfServiceRoleSetInput>;
20
21
  /**
@@ -32,11 +33,15 @@ export declare const self_service_role_set_action_spec: {
32
33
  method: string;
33
34
  kind: "request_response";
34
35
  initiator: "frontend";
35
- auth: "authenticated";
36
+ auth: {
37
+ account: "required";
38
+ actor: "required";
39
+ };
36
40
  side_effects: true;
37
41
  input: z.ZodObject<{
38
42
  role: z.ZodString;
39
43
  enabled: z.ZodBoolean;
44
+ acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
40
45
  }, z.core.$strict>;
41
46
  output: z.ZodObject<{
42
47
  ok: z.ZodLiteral<true>;
@@ -1 +1 @@
1
- {"version":3,"file":"self_service_role_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/self_service_role_action_specs.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,2BAA2B,CAAC;AAGzE,0FAA0F;AAC1F,eAAO,MAAM,oCAAoC,EAAG,gCAAyC,CAAC;AAE9F,yCAAyC;AACzC,eAAO,MAAM,uBAAuB;;;kBAMlC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAE9E;;;;GAIG;AACH,eAAO,MAAM,wBAAwB;;;;kBAInC,CAAC;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAEhF,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;;CAWT,CAAC;AAEtC;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,EAAE,aAAa,CAAC,yBAAyB,CAEvF,CAAC"}
1
+ {"version":3,"file":"self_service_role_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/self_service_role_action_specs.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,2BAA2B,CAAC;AAIzE,0FAA0F;AAC1F,eAAO,MAAM,oCAAoC,EAAG,gCAAyC,CAAC;AAE9F,yCAAyC;AACzC,eAAO,MAAM,uBAAuB;;;;kBAOlC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAE9E;;;;GAIG;AACH,eAAO,MAAM,wBAAwB;;;;kBAInC,CAAC;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAEhF,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;;;;;;CAWT,CAAC;AAEtC;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,EAAE,aAAa,CAAC,yBAAyB,CAEvF,CAAC"}
@@ -9,6 +9,7 @@
9
9
  */
10
10
  import { z } from 'zod';
11
11
  import { RoleName } from './role_schema.js';
12
+ import { ActingActor } from '../http/auth_shape.js';
12
13
  /** Error reason — caller asked to self-toggle a role outside the configured allowlist. */
13
14
  export const ERROR_ROLE_NOT_SELF_SERVICE_ELIGIBLE = 'role_not_self_service_eligible';
14
15
  /** Input for `self_service_role_set`. */
@@ -17,6 +18,7 @@ export const SelfServiceRoleSetInput = z.strictObject({
17
18
  enabled: z.boolean().meta({
18
19
  description: 'Desired post-call state. `true` grants if not held; `false` revokes if held. Idempotent in both directions.',
19
20
  }),
21
+ acting: ActingActor,
20
22
  });
21
23
  /**
22
24
  * Output for `self_service_role_set`. `enabled` echoes the post-call state
@@ -32,7 +34,7 @@ export const self_service_role_set_action_spec = {
32
34
  method: 'self_service_role_set',
33
35
  kind: 'request_response',
34
36
  initiator: 'frontend',
35
- auth: 'authenticated',
37
+ auth: { account: 'required', actor: 'required' },
36
38
  side_effects: true,
37
39
  input: SelfServiceRoleSetInput,
38
40
  output: SelfServiceRoleSetOutput,
@@ -2,19 +2,24 @@
2
2
  * Unified self-service role toggle RPC action.
3
3
  *
4
4
  * One static `request_response` action — `self_service_role_set` — that
5
- * takes `{role, enabled}` and toggles a global permit on the caller for an
5
+ * takes `{role, enabled}` and toggles a global role_grant on the caller for an
6
6
  * allowlisted role. Idempotent in both directions: re-enabling an
7
7
  * already-held role returns `changed: false`; disabling a role the caller
8
8
  * doesn't hold returns `changed: false`.
9
9
  *
10
- * The factory takes an `eligible_roles` allowlist (validated against the
11
- * supplied `roles.role_options` at factory time so typos surface at startup
12
- * instead of at first call). Roles outside the allowlist are rejected
13
- * with `forbidden` + reason `role_not_self_service_eligible`.
10
+ * Eligibility is derived by default from `RoleSpec.grant_paths`
11
+ * every role whose `grant_paths` includes `'self_service'`
12
+ * (`GRANT_PATH_SELF_SERVICE`) is eligible. The factory accepts an
13
+ * optional `eligible_roles` override (validated against the supplied
14
+ * `roles.role_specs` at factory time so typos surface at startup
15
+ * instead of at first call) for deployments that want to lock the
16
+ * surface down further than the role spec declares. Roles outside
17
+ * the eligible set are rejected with `forbidden` + reason
18
+ * `role_not_self_service_eligible`.
14
19
  *
15
20
  * Audit metadata carries `self_service: true` so admin reviewers can
16
- * distinguish self-toggled permits from admin grants/offers. The
17
- * `permit_grant` / `permit_revoke` metadata schemas declare
21
+ * distinguish self-toggled role_grants from admin grants/offers. The
22
+ * `role_grant_create` / `role_grant_revoke` metadata schemas declare
18
23
  * `self_service: z.boolean().optional()` explicitly, so the field is
19
24
  * part of the documented schema surface and is round-trip-validated by
20
25
  * `query_audit_log`.
@@ -22,7 +27,7 @@
22
27
  * Static method name — `role` lives in the input, not the method name —
23
28
  * so the spec is codegen-compatible (`satisfies RequestResponseActionSpec`)
24
29
  * and the surface stays constant as consumers add eligible roles. Mirrors
25
- * the existing `permit_offer_create({role})` precedent rather than
30
+ * the existing `role_grant_offer_create({role})` precedent rather than
26
31
  * generating per-role methods.
27
32
  *
28
33
  * Specs and schemas live in `auth/self_service_role_action_specs.ts` so
@@ -32,37 +37,39 @@
32
37
  * @module
33
38
  */
34
39
  import { type RpcAction } from '../actions/action_rpc.js';
35
- import type { RoleSchemaResult } from './role_schema.js';
40
+ import { type RoleSchemaResult } from './role_schema.js';
36
41
  import type { RouteFactoryDeps } from './deps.js';
37
42
  /** Options for `create_self_service_role_actions`. */
38
43
  export interface SelfServiceRoleActionsOptions {
39
44
  /**
40
- * Allowlist of role strings eligible for self-service. Empty array
41
- * effectively disables the surface every call comes back as
42
- * `forbidden` with reason `role_not_self_service_eligible`.
45
+ * Optional override allowlist of role strings eligible for
46
+ * self-service. When omitted, eligibility is derived from
47
+ * `roles.role_specs` (or `BUILTIN_ROLE_SPECS_BY_NAME` when `roles`
48
+ * is also omitted) by selecting every role whose
49
+ * `RoleSpec.grant_paths` includes `'self_service'`. Pass an empty
50
+ * array to lock the surface down (every call comes back as
51
+ * `forbidden` with reason `role_not_self_service_eligible`).
52
+ *
53
+ * When supplied alongside `roles`, every entry is checked against
54
+ * `roles.role_specs` at factory time so typos throw at startup.
43
55
  */
44
- eligible_roles: ReadonlyArray<string>;
56
+ eligible_roles?: ReadonlyArray<string>;
45
57
  /**
46
- * Optional role schema. When supplied, `eligible_roles` entries are
47
- * checked against `roles.role_options` at factory time so typos throw
48
- * at startup instead of at first call.
58
+ * Optional role schema. Drives default eligibility derivation from
59
+ * `RoleSpec.grant_paths` and validates the `eligible_roles` override
60
+ * (when supplied) against the registered role set.
49
61
  */
50
62
  roles?: RoleSchemaResult;
51
63
  }
52
- /**
53
- * Dependencies for `create_self_service_role_actions`. Same shape as the
54
- * peer factories so consumers thread one deps object through all three.
55
- * `audit_log_config` flows from `AppDeps` and is consumed by
56
- * `audit_log_fire_and_forget`.
57
- */
58
- export type SelfServiceRoleActionDeps = Pick<RouteFactoryDeps, 'log' | 'on_audit_event' | 'audit_log_config'>;
59
64
  /**
60
65
  * Build the unified self-service role toggle RPC action.
61
66
  *
62
- * @param deps - `SelfServiceRoleActionDeps` slice of `AppDeps` (`log`, `on_audit_event`, optional `audit_log_config`)
63
- * @param options - eligible-role allowlist plus optional role schema for typo-checking
67
+ * @param deps - `RouteFactoryDeps` (`log`, `audit`, …); `audit.emit` writes
68
+ * audit rows via the captured pool. The bound emitter encapsulates
69
+ * `on_audit_event` fan-out and the optional `AuditLogConfig`.
70
+ * @param options - optional eligible-role override plus optional role schema for default-eligibility derivation
64
71
  * @returns the `RpcAction` array to spread into a `create_rpc_endpoint` call
65
- * @throws Error at factory time if any `eligible_roles` entry is missing from `options.roles.role_options`
72
+ * @throws Error at factory time if any `eligible_roles` entry is missing from `options.roles.role_specs`
66
73
  */
67
- export declare const create_self_service_role_actions: (deps: SelfServiceRoleActionDeps, options: SelfServiceRoleActionsOptions) => Array<RpcAction>;
74
+ export declare const create_self_service_role_actions: (deps: Pick<RouteFactoryDeps, "log" | "audit">, options?: SelfServiceRoleActionsOptions) => Array<RpcAction>;
68
75
  //# sourceMappingURL=self_service_role_actions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"self_service_role_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/self_service_role_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EAAiC,KAAK,SAAS,EAAC,MAAM,0BAA0B,CAAC;AAExF,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,WAAW,CAAC;AAYhD,sDAAsD;AACtD,MAAM,WAAW,6BAA6B;IAC7C;;;;OAIG;IACH,cAAc,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACtC;;;;OAIG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;CACzB;AAED;;;;;GAKG;AACH,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAC3C,gBAAgB,EAChB,KAAK,GAAG,gBAAgB,GAAG,kBAAkB,CAC7C,CAAC;AAOF;;;;;;;GAOG;AACH,eAAO,MAAM,gCAAgC,GAC5C,MAAM,yBAAyB,EAC/B,SAAS,6BAA6B,KACpC,KAAK,CAAC,SAAS,CA+GjB,CAAC"}
1
+ {"version":3,"file":"self_service_role_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/self_service_role_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,EAAsC,KAAK,SAAS,EAAC,MAAM,0BAA0B,CAAC;AAE7F,OAAO,EAGN,KAAK,gBAAgB,EACrB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,WAAW,CAAC;AAWhD,sDAAsD;AACtD,MAAM,WAAW,6BAA6B;IAC7C;;;;;;;;;;;OAWG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC;;;;OAIG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;CACzB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,gCAAgC,GAC5C,MAAM,IAAI,CAAC,gBAAgB,EAAE,KAAK,GAAG,OAAO,CAAC,EAC7C,UAAS,6BAAkC,KACzC,KAAK,CAAC,SAAS,CAyHjB,CAAC"}