@fuzdev/fuz_app 0.55.0 → 0.57.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 (333) 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 +72 -39
  174. package/dist/http/error_schemas.d.ts.map +1 -1
  175. package/dist/http/error_schemas.js +81 -33
  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 +14 -6
  258. package/dist/testing/surface_invariants.d.ts.map +1 -1
  259. package/dist/testing/surface_invariants.js +119 -43
  260. package/dist/testing/ws_round_trip.d.ts +12 -13
  261. package/dist/testing/ws_round_trip.d.ts.map +1 -1
  262. package/dist/testing/ws_round_trip.js +19 -11
  263. package/dist/ui/AdminAccounts.svelte +23 -20
  264. package/dist/ui/AdminOverview.svelte +15 -13
  265. package/dist/ui/AdminOverview.svelte.d.ts.map +1 -1
  266. package/dist/ui/{AdminPermitHistory.svelte → AdminRoleGrantHistory.svelte} +12 -12
  267. package/dist/ui/AdminRoleGrantHistory.svelte.d.ts +4 -0
  268. package/dist/ui/AdminRoleGrantHistory.svelte.d.ts.map +1 -0
  269. package/dist/ui/BootstrapForm.svelte +1 -1
  270. package/dist/ui/CLAUDE.md +60 -60
  271. package/dist/ui/{PermitOfferForm.svelte → RoleGrantOfferForm.svelte} +27 -26
  272. package/dist/ui/{PermitOfferForm.svelte.d.ts → RoleGrantOfferForm.svelte.d.ts} +7 -7
  273. package/dist/ui/RoleGrantOfferForm.svelte.d.ts.map +1 -0
  274. package/dist/ui/{PermitOfferHistory.svelte → RoleGrantOfferHistory.svelte} +12 -12
  275. package/dist/ui/{PermitOfferHistory.svelte.d.ts → RoleGrantOfferHistory.svelte.d.ts} +4 -4
  276. package/dist/ui/RoleGrantOfferHistory.svelte.d.ts.map +1 -0
  277. package/dist/ui/{PermitOfferInbox.svelte → RoleGrantOfferInbox.svelte} +14 -14
  278. package/dist/ui/{PermitOfferInbox.svelte.d.ts → RoleGrantOfferInbox.svelte.d.ts} +4 -4
  279. package/dist/ui/RoleGrantOfferInbox.svelte.d.ts.map +1 -0
  280. package/dist/ui/SignupForm.svelte +1 -1
  281. package/dist/ui/SurfaceExplorer.svelte +35 -15
  282. package/dist/ui/SurfaceExplorer.svelte.d.ts.map +1 -1
  283. package/dist/ui/account_sessions_state.svelte.d.ts +2 -3
  284. package/dist/ui/account_sessions_state.svelte.d.ts.map +1 -1
  285. package/dist/ui/account_sessions_state.svelte.js +2 -3
  286. package/dist/ui/admin_accounts_state.svelte.d.ts +18 -18
  287. package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
  288. package/dist/ui/admin_accounts_state.svelte.js +16 -16
  289. package/dist/ui/admin_rpc_adapters.d.ts +20 -20
  290. package/dist/ui/admin_rpc_adapters.d.ts.map +1 -1
  291. package/dist/ui/admin_rpc_adapters.js +17 -17
  292. package/dist/ui/admin_sessions_state.svelte.d.ts +2 -2
  293. package/dist/ui/admin_sessions_state.svelte.js +2 -2
  294. package/dist/ui/audit_log_state.svelte.d.ts +7 -7
  295. package/dist/ui/audit_log_state.svelte.d.ts.map +1 -1
  296. package/dist/ui/audit_log_state.svelte.js +6 -6
  297. package/dist/ui/auth_state.svelte.d.ts +3 -3
  298. package/dist/ui/auth_state.svelte.d.ts.map +1 -1
  299. package/dist/ui/auth_state.svelte.js +6 -6
  300. package/dist/ui/format_scope.d.ts +2 -2
  301. package/dist/ui/format_scope.js +2 -2
  302. package/dist/ui/{permit_offers_state.svelte.d.ts → role_grant_offers_state.svelte.d.ts} +30 -30
  303. package/dist/ui/role_grant_offers_state.svelte.d.ts.map +1 -0
  304. package/dist/ui/{permit_offers_state.svelte.js → role_grant_offers_state.svelte.js} +18 -18
  305. package/dist/ui/ui_format.js +2 -2
  306. package/package.json +3 -3
  307. package/dist/auth/permit_offer_action_specs.d.ts.map +0 -1
  308. package/dist/auth/permit_offer_action_specs.js +0 -258
  309. package/dist/auth/permit_offer_actions.d.ts +0 -110
  310. package/dist/auth/permit_offer_actions.d.ts.map +0 -1
  311. package/dist/auth/permit_offer_notifications.d.ts.map +0 -1
  312. package/dist/auth/permit_offer_notifications.js +0 -182
  313. package/dist/auth/permit_offer_queries.d.ts.map +0 -1
  314. package/dist/auth/permit_offer_schema.d.ts +0 -125
  315. package/dist/auth/permit_offer_schema.d.ts.map +0 -1
  316. package/dist/auth/permit_queries.d.ts +0 -222
  317. package/dist/auth/permit_queries.d.ts.map +0 -1
  318. package/dist/auth/permit_queries.js +0 -305
  319. package/dist/auth/require_keeper.d.ts +0 -20
  320. package/dist/auth/require_keeper.d.ts.map +0 -1
  321. package/dist/auth/require_keeper.js +0 -35
  322. package/dist/auth/route_guards.d.ts +0 -27
  323. package/dist/auth/route_guards.d.ts.map +0 -1
  324. package/dist/auth/route_guards.js +0 -38
  325. package/dist/auth/session_lifecycle.d.ts +0 -37
  326. package/dist/auth/session_lifecycle.d.ts.map +0 -1
  327. package/dist/auth/session_lifecycle.js +0 -29
  328. package/dist/ui/AdminPermitHistory.svelte.d.ts +0 -4
  329. package/dist/ui/AdminPermitHistory.svelte.d.ts.map +0 -1
  330. package/dist/ui/PermitOfferForm.svelte.d.ts.map +0 -1
  331. package/dist/ui/PermitOfferHistory.svelte.d.ts.map +0 -1
  332. package/dist/ui/PermitOfferInbox.svelte.d.ts.map +0 -1
  333. package/dist/ui/permit_offers_state.svelte.d.ts.map +0 -1
@@ -22,13 +22,12 @@
22
22
  * @module
23
23
  */
24
24
  import { z } from 'zod';
25
- import { clear_session_cookie } from './session_middleware.js';
26
- import { create_session_and_set_cookie } from './session_lifecycle.js';
27
- import { ActorSummaryJson, PermitSummaryJson, SessionAccountJson, to_session_account, UsernameProvided, } from './account_schema.js';
25
+ import { clear_session_cookie, create_session_and_set_cookie } from './session_middleware.js';
26
+ import { ActorSummaryJson, RoleGrantSummaryJson, SessionAccountJson, to_session_account, } from './account_schema.js';
27
+ import { UsernameProvided } from '../primitive_schemas.js';
28
28
  import { hash_session_token, query_session_revoke_all_for_account, query_session_revoke_by_hash_unscoped, } from './session_queries.js';
29
29
  import { query_account_by_username_or_email, query_update_account_password, } from './account_queries.js';
30
30
  import { query_revoke_all_api_tokens_for_account } from './api_token_queries.js';
31
- import { audit_log_fire_and_forget } from './audit_log_queries.js';
32
31
  import { build_account_context, build_request_context, get_request_context, require_request_context, resolve_acting_actor, } from './request_context.js';
33
32
  import { ACCOUNT_ID_KEY } from '../hono_context.js';
34
33
  import { get_route_input } from '../http/route_spec.js';
@@ -42,15 +41,15 @@ export const AccountStatusInput = z.null();
42
41
  * Output for `GET /api/account/status` on the authenticated path.
43
42
  *
44
43
  * `account` is always populated for authenticated callers. `actor` and
45
- * `permits` are populated when the caller's account has a unique actor or
44
+ * `role_grants` are populated when the caller's account has a unique actor or
46
45
  * the request supplies `?acting=<actor_id>`; on multi-actor accounts
47
- * without an `acting` query, `actor` is `null` and `permits` is empty so
46
+ * without an `acting` query, `actor` is `null` and `role_grants` is empty so
48
47
  * the frontend can show a persona picker without a separate roundtrip.
49
48
  */
50
49
  export const AccountStatusOutput = z.strictObject({
51
50
  account: SessionAccountJson,
52
51
  actor: ActorSummaryJson.nullable(),
53
- permits: z.array(PermitSummaryJson),
52
+ role_grants: z.array(RoleGrantSummaryJson),
54
53
  });
55
54
  /** Error body for `GET /api/account/status` on the unauthenticated path. */
56
55
  export const AccountStatusUnauthenticatedError = z.looseObject({
@@ -73,7 +72,7 @@ export const AccountStatusUnauthenticatedError = z.looseObject({
73
72
  export const create_account_status_route_spec = (options) => ({
74
73
  method: 'GET',
75
74
  path: options?.path ?? '/api/account/status',
76
- auth: { type: 'none' },
75
+ auth: { account: 'none', actor: 'none' },
77
76
  description: 'Current account info (unauthenticated: 401 with bootstrap status)',
78
77
  input: AccountStatusInput,
79
78
  output: AccountStatusOutput,
@@ -94,9 +93,10 @@ export const create_account_status_route_spec = (options) => ({
94
93
  // it directly to avoid redundant lookups.
95
94
  const existing = get_request_context(c);
96
95
  if (existing && existing.account.id === account_id) {
97
- const permits = existing.permits.map((p) => ({
96
+ const role_grants = existing.role_grants.map((p) => ({
98
97
  id: p.id,
99
98
  role: p.role,
99
+ scope_kind: p.scope_kind,
100
100
  scope_id: p.scope_id,
101
101
  created_at: p.created_at,
102
102
  expires_at: p.expires_at,
@@ -105,10 +105,10 @@ export const create_account_status_route_spec = (options) => ({
105
105
  return c.json({
106
106
  account: to_session_account(existing.account),
107
107
  actor: existing.actor ? { id: existing.actor.id, name: existing.actor.name } : null,
108
- permits,
108
+ role_grants,
109
109
  });
110
110
  }
111
- // Resolve actor + permits when the caller is unambiguous (single-actor
111
+ // Resolve actor + role_grants when the caller is unambiguous (single-actor
112
112
  // account, or supplied `?acting=<uuid>`). On multi-actor accounts
113
113
  // without `acting`, fall back to account-only so the frontend can
114
114
  // surface a persona picker.
@@ -117,9 +117,10 @@ export const create_account_status_route_spec = (options) => ({
117
117
  if (acting_result.ok) {
118
118
  const ctx = await build_request_context(route, account_id, acting_result.actor_id);
119
119
  if (ctx) {
120
- const permits = ctx.permits.map((p) => ({
120
+ const role_grants = ctx.role_grants.map((p) => ({
121
121
  id: p.id,
122
122
  role: p.role,
123
+ scope_kind: p.scope_kind,
123
124
  scope_id: p.scope_id,
124
125
  created_at: p.created_at,
125
126
  expires_at: p.expires_at,
@@ -128,7 +129,7 @@ export const create_account_status_route_spec = (options) => ({
128
129
  return c.json({
129
130
  account: to_session_account(ctx.account),
130
131
  actor: { id: ctx.actor.id, name: ctx.actor.name },
131
- permits,
132
+ role_grants,
132
133
  });
133
134
  }
134
135
  }
@@ -142,7 +143,7 @@ export const create_account_status_route_spec = (options) => ({
142
143
  return c.json({
143
144
  account: to_session_account(account_ctx.account),
144
145
  actor: null,
145
- permits: [],
146
+ role_grants: [],
146
147
  });
147
148
  },
148
149
  });
@@ -221,7 +222,7 @@ export const create_account_route_specs = (deps, options) => {
221
222
  {
222
223
  method: 'GET',
223
224
  path: '/verify',
224
- auth: { type: 'authenticated' },
225
+ auth: { account: 'required', actor: 'none' },
225
226
  description: 'Session-validity probe for nginx auth_request (empty body, 200 or 401)',
226
227
  input: z.null(),
227
228
  output: z.null(),
@@ -233,7 +234,7 @@ export const create_account_route_specs = (deps, options) => {
233
234
  {
234
235
  method: 'POST',
235
236
  path: '/login',
236
- auth: { type: 'none' },
237
+ auth: { account: 'none', actor: 'none' },
237
238
  description: 'Exchange credentials for session',
238
239
  input: LoginInput,
239
240
  output: LoginOutput,
@@ -279,12 +280,12 @@ export const create_account_route_specs = (deps, options) => {
279
280
  ip_rate_limiter.record(ip);
280
281
  if (login_account_rate_limiter)
281
282
  login_account_rate_limiter.record(account_rate_key);
282
- void audit_log_fire_and_forget(route, {
283
+ deps.audit.emit(route, {
283
284
  event_type: 'login',
284
285
  outcome: 'failure',
285
286
  ip: get_client_ip(c),
286
287
  metadata: { username },
287
- }, deps);
288
+ });
288
289
  await delay;
289
290
  return c.json({ error: ERROR_INVALID_CREDENTIALS }, 401);
290
291
  }
@@ -294,13 +295,13 @@ export const create_account_route_specs = (deps, options) => {
294
295
  ip_rate_limiter.record(ip);
295
296
  if (login_account_rate_limiter)
296
297
  login_account_rate_limiter.record(account_rate_key);
297
- void audit_log_fire_and_forget(route, {
298
+ deps.audit.emit(route, {
298
299
  event_type: 'login',
299
300
  outcome: 'failure',
300
301
  account_id: account.id,
301
302
  ip: get_client_ip(c),
302
303
  metadata: { username },
303
- }, deps);
304
+ });
304
305
  await delay;
305
306
  return c.json({ error: ERROR_INVALID_CREDENTIALS }, 401);
306
307
  }
@@ -317,18 +318,18 @@ export const create_account_route_specs = (deps, options) => {
317
318
  session_options,
318
319
  max_sessions,
319
320
  });
320
- void audit_log_fire_and_forget(route, {
321
+ deps.audit.emit(route, {
321
322
  event_type: 'login',
322
323
  account_id: account.id,
323
324
  ip: get_client_ip(c),
324
- }, deps);
325
+ });
325
326
  return c.json({ ok: true });
326
327
  },
327
328
  },
328
329
  {
329
330
  method: 'POST',
330
331
  path: '/logout',
331
- auth: { type: 'authenticated' },
332
+ auth: { account: 'required', actor: 'none' },
332
333
  description: 'Revoke current session and clear cookie',
333
334
  input: LogoutInput,
334
335
  output: LogoutOutput,
@@ -343,18 +344,18 @@ export const create_account_route_specs = (deps, options) => {
343
344
  // Account-grain operation — no `actor_id` (which actor was
344
345
  // resolved per-request is incidental to "this account ended
345
346
  // its session"). Mirrors `login`.
346
- void audit_log_fire_and_forget(route, {
347
+ deps.audit.emit(route, {
347
348
  event_type: 'logout',
348
349
  account_id: ctx.account.id,
349
350
  ip: get_client_ip(c),
350
- }, deps);
351
+ });
351
352
  return c.json({ ok: true, username: ctx.account.username });
352
353
  },
353
354
  },
354
355
  {
355
356
  method: 'POST',
356
357
  path: '/password',
357
- auth: { type: 'authenticated' },
358
+ auth: { account: 'required', actor: 'none' },
358
359
  description: 'Change password (revokes all sessions and API tokens)',
359
360
  input: PasswordChangeInput,
360
361
  output: PasswordChangeOutput,
@@ -388,12 +389,12 @@ export const create_account_route_specs = (deps, options) => {
388
389
  ip_rate_limiter.record(ip);
389
390
  if (login_account_rate_limiter)
390
391
  login_account_rate_limiter.record(ctx.account.id);
391
- void audit_log_fire_and_forget(route, {
392
+ deps.audit.emit(route, {
392
393
  event_type: 'password_change',
393
394
  outcome: 'failure',
394
395
  account_id: ctx.account.id,
395
396
  ip: get_client_ip(c),
396
- }, deps);
397
+ });
397
398
  return c.json({ error: ERROR_INVALID_CREDENTIALS }, 401);
398
399
  }
399
400
  // successful verification — reset rate limiters
@@ -402,9 +403,33 @@ export const create_account_route_specs = (deps, options) => {
402
403
  if (login_account_rate_limiter)
403
404
  login_account_rate_limiter.reset(ctx.account.id);
404
405
  const new_hash = await password.hash_password(new_password);
405
- // Account-grain operation `updated_by` stays null (the per-request
406
- // actor is incidental; password is account-level state).
407
- await query_update_account_password(route, ctx.account.id, new_hash, null);
406
+ // Conditional UPDATE keyed on the verified hash: closes the
407
+ // verify-write race with a concurrent password change that
408
+ // already committed against the same starting hash. Account-grain
409
+ // operation — `updated_by` stays null (the per-request actor is
410
+ // incidental; password is account-level state).
411
+ const updated = await query_update_account_password(route, ctx.account.id, new_hash, null, ctx.account.password_hash);
412
+ if (!updated) {
413
+ // A concurrent password change committed first — our
414
+ // `current_password` was correct at read-time but the row's
415
+ // `password_hash` no longer matches. Mirrors the wrong-password
416
+ // 401 shape; tag the failure metadata so admins reading the
417
+ // audit log can distinguish "user typoed" from "two clients
418
+ // raced." Sessions/tokens were already revoked by the winner;
419
+ // no cookie clear here either.
420
+ if (ip_rate_limiter && ip)
421
+ ip_rate_limiter.record(ip);
422
+ if (login_account_rate_limiter)
423
+ login_account_rate_limiter.record(ctx.account.id);
424
+ deps.audit.emit(route, {
425
+ event_type: 'password_change',
426
+ outcome: 'failure',
427
+ account_id: ctx.account.id,
428
+ ip: get_client_ip(c),
429
+ metadata: { reason: 'concurrent_change' },
430
+ });
431
+ return c.json({ error: ERROR_INVALID_CREDENTIALS }, 401);
432
+ }
408
433
  // revoke all sessions and API tokens (force re-auth everywhere)
409
434
  const sessions_revoked = await query_session_revoke_all_for_account(route, ctx.account.id);
410
435
  const tokens_revoked = await query_revoke_all_api_tokens_for_account(route, ctx.account.id);
@@ -413,12 +438,12 @@ export const create_account_route_specs = (deps, options) => {
413
438
  // account-level state; which per-request actor was resolved
414
439
  // has no semantic bearing on "this account changed its
415
440
  // password". Mirrors `login`/`logout`.
416
- void audit_log_fire_and_forget(route, {
441
+ deps.audit.emit(route, {
417
442
  event_type: 'password_change',
418
443
  account_id: ctx.account.id,
419
444
  ip: get_client_ip(c),
420
445
  metadata: { sessions_revoked, tokens_revoked },
421
- }, deps);
446
+ });
422
447
  return c.json({ ok: true, sessions_revoked, tokens_revoked });
423
448
  },
424
449
  },
@@ -2,7 +2,14 @@
2
2
  * Auth entity types and client-safe schemas.
3
3
  *
4
4
  * Defines the runtime types for the fuz identity system:
5
- * `Account`, `Actor`, `Permit`, `AuthSession`, and `ApiToken`.
5
+ * `Account`, `Actor`, `RoleGrant`, `AuthSession`, and `ApiToken`.
6
+ *
7
+ * Identifier primitives (`Username`, `UsernameProvided`, `Email`) live
8
+ * in `../primitive_schemas.ts` — they're general validator shapes that
9
+ * don't depend on the auth domain. The auth-shape request-contract
10
+ * primitive `ActingActor` lives in `../http/auth_shape.ts` next to
11
+ * `RouteAuth` (the two pair: `auth.actor !== 'none'` ⟺ input declares
12
+ * `acting?: ActingActor`).
6
13
  *
7
14
  * DDL lives in `auth/ddl.ts`; role system in `auth/role_schema.ts`.
8
15
  * See docs/identity.md for design rationale.
@@ -11,40 +18,7 @@
11
18
  */
12
19
  import { z } from 'zod';
13
20
  import { Uuid } from '@fuzdev/fuz_util/id.js';
14
- /** Minimum username length (must have start + middle + end characters). */
15
- export declare const USERNAME_LENGTH_MIN = 3;
16
- /** Maximum username length (matches GitHub's limit). */
17
- export declare const USERNAME_LENGTH_MAX = 39;
18
- /** Maximum length for username input on login/lookup — more permissive than `USERNAME_LENGTH_MAX` for forward-compatibility if the creation limit is raised. */
19
- export declare const USERNAME_PROVIDED_LENGTH_MAX = 255;
20
- /** Username for account creation — starts with letter, alphanumeric/dash/underscore middle, ends with alphanumeric. No @ or . allowed. */
21
- export declare const Username: z.ZodString;
22
- export type Username = z.infer<typeof Username>;
23
- /** Username submitted for login or lookup — minimal validation for forward-compatibility if format rules change. */
24
- export declare const UsernameProvided: z.ZodString;
25
- export type UsernameProvided = z.infer<typeof UsernameProvided>;
26
- /** Email validation. */
27
- export declare const Email: z.ZodEmail;
28
- export type Email = z.infer<typeof Email>;
29
- /**
30
- * `acting` field shared by every action input that needs the caller's
31
- * acting actor. Declaring `acting: ActingActor` on an action's input
32
- * is the signal to the RPC dispatcher / route-spec wrapper to resolve
33
- * an actor against the authenticated account: the authorization phase
34
- * runs `resolve_acting_actor`, builds the actor-bound `RequestContext`,
35
- * and loads permits before auth guards fire.
36
- *
37
- * Resolution rules: omitted + 1 actor → use it; omitted + multiple
38
- * actors → `actor_required` with the available list; supplied + on
39
- * the account → use it; supplied + foreign actor → `actor_not_on_account`.
40
- *
41
- * Account-grain routes — input doesn't declare `acting` and auth
42
- * doesn't require permits (`role` / `keeper`) — skip resolution
43
- * entirely; their `RequestContext.actor` is `null` and the audit
44
- * envelope's `actor_id` stays null.
45
- */
46
- export declare const ActingActor: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
47
- export type ActingActor = z.infer<typeof ActingActor>;
21
+ import { Username, Email } from '../primitive_schemas.js';
48
22
  /** Account — authentication identity. You log in as an account. */
49
23
  export interface Account {
50
24
  id: Uuid;
@@ -65,7 +39,7 @@ export interface SessionAccount {
65
39
  email_verified: boolean;
66
40
  created_at: string;
67
41
  }
68
- /** Actor — the entity that acts. Owns cells, holds permits, appears in audit trails. */
42
+ /** Actor — the entity that acts. Owns cells, holds role_grants, appears in audit trails. */
69
43
  export interface Actor {
70
44
  id: Uuid;
71
45
  account_id: Uuid;
@@ -76,17 +50,25 @@ export interface Actor {
76
50
  }
77
51
  /**
78
52
  * Maximum length of the optional free-form `revoked_reason` attached to a
79
- * revoked permit. Bounds the value at the schema layer so both the admin
53
+ * revoked role_grant. Bounds the value at the schema layer so both the admin
80
54
  * input (when the route surfaces a reason field) and the revokee-facing
81
- * `permit_revoke` WS notification validate against the same ceiling.
55
+ * `role_grant_revoke` WS notification validate against the same ceiling.
82
56
  */
83
- export declare const PERMIT_REVOKED_REASON_LENGTH_MAX = 500;
84
- /** Permit — time-bounded, revocable grant of a role to an actor. */
85
- export interface Permit {
57
+ export declare const ROLE_GRANT_REVOKED_REASON_LENGTH_MAX = 500;
58
+ /** Role grant — time-bounded, revocable grant of a role to an actor. */
59
+ export interface RoleGrant {
86
60
  id: Uuid;
87
61
  actor_id: Uuid;
88
62
  role: string;
89
- /** Resource scope this grant applies to (e.g. a classroom id). `null` for global permits. */
63
+ /**
64
+ * Machine-readable kind tag for the polymorphic `scope_id`. Paired-null
65
+ * with `scope_id` per the `role_grant_scope_kind_paired` CHECK: both null
66
+ * (global) or both non-null (scoped). Consumer-declared via
67
+ * `create_scope_kind_schema(...)`; v1 keeps validation registry-membership
68
+ * only, with no INSERT-time `(role, scope_kind)` enforcement.
69
+ */
70
+ scope_kind: string | null;
71
+ /** Resource scope this grant applies to (e.g. a classroom id). `null` for global role_grants. */
90
72
  scope_id: Uuid | null;
91
73
  created_at: string;
92
74
  expires_at: string | null;
@@ -95,10 +77,10 @@ export interface Permit {
95
77
  /** Optional free-form reason attached on revoke (surfaced in the revokee WS notification once it lands). */
96
78
  revoked_reason: string | null;
97
79
  granted_by: Uuid | null;
98
- /** Offer that produced this permit (set by `query_accept_offer`). `null` for direct grants. */
80
+ /** Offer that produced this role_grant (set by `query_accept_offer`). `null` for direct grants. */
99
81
  source_offer_id: Uuid | null;
100
82
  }
101
- export declare const is_permit_active: (p: {
83
+ export declare const is_role_grant_active: (p: {
102
84
  revoked_at?: string | null;
103
85
  expires_at: string | null;
104
86
  }, now?: Date) => boolean;
@@ -150,16 +132,17 @@ export declare const ClientApiTokenJson: z.ZodObject<{
150
132
  created_at: z.ZodString;
151
133
  }, z.core.$strict>;
152
134
  export type ClientApiTokenJson = z.infer<typeof ClientApiTokenJson>;
153
- /** Zod schema for the permit summary returned in admin account listings. */
154
- export declare const PermitSummaryJson: z.ZodObject<{
135
+ /** Zod schema for the role_grant summary returned in admin account listings. */
136
+ export declare const RoleGrantSummaryJson: z.ZodObject<{
155
137
  id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
156
138
  role: z.ZodString;
139
+ scope_kind: z.ZodNullable<z.ZodString>;
157
140
  scope_id: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
158
141
  created_at: z.ZodString;
159
142
  expires_at: z.ZodNullable<z.ZodString>;
160
143
  granted_by: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
161
144
  }, z.core.$strict>;
162
- export type PermitSummaryJson = z.infer<typeof PermitSummaryJson>;
145
+ export type RoleGrantSummaryJson = z.infer<typeof RoleGrantSummaryJson>;
163
146
  /** Zod schema for the actor summary returned in admin account listings. */
164
147
  export declare const ActorSummaryJson: z.ZodObject<{
165
148
  id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
@@ -178,9 +161,9 @@ export declare const AdminAccountJson: z.ZodObject<{
178
161
  }, z.core.$strict>;
179
162
  export type AdminAccountJson = z.infer<typeof AdminAccountJson>;
180
163
  /**
181
- * Zod schema for a pending permit offer surfaced in admin account listings.
164
+ * Zod schema for a pending role_grant offer surfaced in admin account listings.
182
165
  *
183
- * Deliberately narrower than `PermitOfferJson`: omits `message` and
166
+ * Deliberately narrower than `RoleGrantOfferJson`: omits `message` and
184
167
  * `decline_reason` so cross-admin visibility of the listing does not expose
185
168
  * grantor-authored text that the audit log also withholds. Full offer
186
169
  * payloads remain available through the offer-specific RPC surface and the
@@ -193,6 +176,7 @@ export type AdminAccountJson = z.infer<typeof AdminAccountJson>;
193
176
  export declare const PendingOfferSummaryJson: z.ZodObject<{
194
177
  id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
195
178
  role: z.ZodString;
179
+ scope_kind: z.ZodNullable<z.ZodString>;
196
180
  scope_id: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
197
181
  from_actor_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
198
182
  from_username: z.ZodString;
@@ -200,7 +184,7 @@ export declare const PendingOfferSummaryJson: z.ZodObject<{
200
184
  expires_at: z.ZodString;
201
185
  }, z.core.$strict>;
202
186
  export type PendingOfferSummaryJson = z.infer<typeof PendingOfferSummaryJson>;
203
- /** Zod schema for an admin account listing entry (account + actor + permits + pending offers). */
187
+ /** Zod schema for an admin account listing entry (account + actor + role_grants + pending offers). */
204
188
  export declare const AdminAccountEntryJson: z.ZodObject<{
205
189
  account: z.ZodObject<{
206
190
  id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
@@ -215,9 +199,10 @@ export declare const AdminAccountEntryJson: z.ZodObject<{
215
199
  id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
216
200
  name: z.ZodString;
217
201
  }, z.core.$strict>>;
218
- permits: z.ZodArray<z.ZodObject<{
202
+ role_grants: z.ZodArray<z.ZodObject<{
219
203
  id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
220
204
  role: z.ZodString;
205
+ scope_kind: z.ZodNullable<z.ZodString>;
221
206
  scope_id: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
222
207
  created_at: z.ZodString;
223
208
  expires_at: z.ZodNullable<z.ZodString>;
@@ -226,6 +211,7 @@ export declare const AdminAccountEntryJson: z.ZodObject<{
226
211
  pending_offers: z.ZodArray<z.ZodObject<{
227
212
  id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
228
213
  role: z.ZodString;
214
+ scope_kind: z.ZodNullable<z.ZodString>;
229
215
  scope_id: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
230
216
  from_actor_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
231
217
  from_username: z.ZodString;
@@ -239,14 +225,20 @@ export interface CreateAccountInput {
239
225
  password_hash: string;
240
226
  email?: Email | null;
241
227
  }
242
- export interface GrantPermitInput {
228
+ export interface CreateRoleGrantInput {
243
229
  actor_id: Uuid;
244
230
  role: string;
245
- /** Scope the grant applies to. `null` / omitted grants a global permit. */
231
+ /**
232
+ * Machine-readable kind for the `scope_id`. Required iff `scope_id` is
233
+ * set; must be null/omitted when `scope_id` is null. The DB-level
234
+ * `role_grant_scope_kind_paired` CHECK rejects mismatched pairs.
235
+ */
236
+ scope_kind?: string | null;
237
+ /** Scope the grant applies to. `null` / omitted grants a global role_grant. */
246
238
  scope_id?: Uuid | null;
247
239
  expires_at?: Date | null;
248
240
  granted_by: Uuid | null;
249
- /** Offer id that produced this permit. Set by `query_accept_offer`; leave unset for direct grants. */
241
+ /** Offer id that produced this role_grant. Set by `query_accept_offer`; leave unset for direct grants. */
250
242
  source_offer_id?: Uuid | null;
251
243
  }
252
244
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"account_schema.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/account_schema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"account_schema.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/account_schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,EAAC,IAAI,EAAC,MAAM,wBAAwB,CAAC;AAE5C,OAAO,EAAC,QAAQ,EAAE,KAAK,EAAC,MAAM,yBAAyB,CAAC;AAIxD,mEAAmE;AACnE,MAAM,WAAW,OAAO;IACvB,EAAE,EAAE,IAAI,CAAC;IACT,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;CACxB;AAED,wFAAwF;AACxF,MAAM,WAAW,cAAc;IAC9B,EAAE,EAAE,IAAI,CAAC;IACT,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,4FAA4F;AAC5F,MAAM,WAAW,KAAK;IACrB,EAAE,EAAE,IAAI,CAAC;IACT,UAAU,EAAE,IAAI,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;CACxB;AAED;;;;;GAKG;AACH,eAAO,MAAM,oCAAoC,MAAM,CAAC;AAExD,wEAAwE;AACxE,MAAM,WAAW,SAAS;IACzB,EAAE,EAAE,IAAI,CAAC;IACT,QAAQ,EAAE,IAAI,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;OAMG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,iGAAiG;IACjG,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,4GAA4G;IAC5G,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,mGAAmG;IACnG,eAAe,EAAE,IAAI,GAAG,IAAI,CAAC;CAC7B;AAED,eAAO,MAAM,oBAAoB,GAChC,GAAG;IAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAAC,EAC1D,MAAK,IAAiB,KACpB,OAA2E,CAAC;AAE/E,uEAAuE;AACvE,MAAM,WAAW,WAAW;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,IAAI,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,6CAA6C;AAC7C,MAAM,WAAW,QAAQ;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,IAAI,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;CACnB;AAID,0EAA0E;AAC1E,eAAO,MAAM,kBAAkB;;;;;;kBAM7B,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEpE,6EAA6E;AAC7E,eAAO,MAAM,eAAe;;;;;;kBAM1B,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB;;;;;;;;kBAQ7B,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEpE,gFAAgF;AAChF,eAAO,MAAM,oBAAoB;;;;;;;;kBAQ/B,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE,2EAA2E;AAC3E,eAAO,MAAM,gBAAgB;;;kBAG3B,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE,iGAAiG;AACjG,eAAO,MAAM,gBAAgB;;;;;;;;kBAG3B,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;kBASlC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAE9E,sGAAsG;AACtG,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAKhC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAI1E,MAAM,WAAW,kBAAkB;IAClC,QAAQ,EAAE,QAAQ,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACpC,QAAQ,EAAE,IAAI,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,UAAU,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,0GAA0G;IAC1G,eAAe,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,OAAO,KAAG,cAMpD,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,SAAS,OAAO,KAAG,gBAIlD,CAAC"}
@@ -2,7 +2,14 @@
2
2
  * Auth entity types and client-safe schemas.
3
3
  *
4
4
  * Defines the runtime types for the fuz identity system:
5
- * `Account`, `Actor`, `Permit`, `AuthSession`, and `ApiToken`.
5
+ * `Account`, `Actor`, `RoleGrant`, `AuthSession`, and `ApiToken`.
6
+ *
7
+ * Identifier primitives (`Username`, `UsernameProvided`, `Email`) live
8
+ * in `../primitive_schemas.ts` — they're general validator shapes that
9
+ * don't depend on the auth domain. The auth-shape request-contract
10
+ * primitive `ActingActor` lives in `../http/auth_shape.ts` next to
11
+ * `RouteAuth` (the two pair: `auth.actor !== 'none'` ⟺ input declares
12
+ * `acting?: ActingActor`).
6
13
  *
7
14
  * DDL lives in `auth/ddl.ts`; role system in `auth/role_schema.ts`.
8
15
  * See docs/identity.md for design rationale.
@@ -11,51 +18,15 @@
11
18
  */
12
19
  import { z } from 'zod';
13
20
  import { Uuid } from '@fuzdev/fuz_util/id.js';
14
- // TODO consider `.brand()` on Username and Email for compile-time safety
15
- /** Minimum username length (must have start + middle + end characters). */
16
- export const USERNAME_LENGTH_MIN = 3;
17
- /** Maximum username length (matches GitHub's limit). */
18
- export const USERNAME_LENGTH_MAX = 39;
19
- /** Maximum length for username input on login/lookup — more permissive than `USERNAME_LENGTH_MAX` for forward-compatibility if the creation limit is raised. */
20
- export const USERNAME_PROVIDED_LENGTH_MAX = 255;
21
- /** Username for account creation — starts with letter, alphanumeric/dash/underscore middle, ends with alphanumeric. No @ or . allowed. */
22
- export const Username = z
23
- .string()
24
- .min(USERNAME_LENGTH_MIN)
25
- .max(USERNAME_LENGTH_MAX)
26
- .regex(/^[a-zA-Z][0-9a-zA-Z_-]*[0-9a-zA-Z]$/);
27
- /** Username submitted for login or lookup — minimal validation for forward-compatibility if format rules change. */
28
- export const UsernameProvided = z.string().min(1).max(USERNAME_PROVIDED_LENGTH_MAX);
29
- /** Email validation. */
30
- export const Email = z.email();
31
- /**
32
- * `acting` field shared by every action input that needs the caller's
33
- * acting actor. Declaring `acting: ActingActor` on an action's input
34
- * is the signal to the RPC dispatcher / route-spec wrapper to resolve
35
- * an actor against the authenticated account: the authorization phase
36
- * runs `resolve_acting_actor`, builds the actor-bound `RequestContext`,
37
- * and loads permits before auth guards fire.
38
- *
39
- * Resolution rules: omitted + 1 actor → use it; omitted + multiple
40
- * actors → `actor_required` with the available list; supplied + on
41
- * the account → use it; supplied + foreign actor → `actor_not_on_account`.
42
- *
43
- * Account-grain routes — input doesn't declare `acting` and auth
44
- * doesn't require permits (`role` / `keeper`) — skip resolution
45
- * entirely; their `RequestContext.actor` is `null` and the audit
46
- * envelope's `actor_id` stays null.
47
- */
48
- export const ActingActor = Uuid.optional().meta({
49
- description: 'Actor on the authenticated account that this request acts as. Omit on single-actor accounts; required on multi-actor.',
50
- });
21
+ import { Username, Email } from '../primitive_schemas.js';
51
22
  /**
52
23
  * Maximum length of the optional free-form `revoked_reason` attached to a
53
- * revoked permit. Bounds the value at the schema layer so both the admin
24
+ * revoked role_grant. Bounds the value at the schema layer so both the admin
54
25
  * input (when the route surfaces a reason field) and the revokee-facing
55
- * `permit_revoke` WS notification validate against the same ceiling.
26
+ * `role_grant_revoke` WS notification validate against the same ceiling.
56
27
  */
57
- export const PERMIT_REVOKED_REASON_LENGTH_MAX = 500;
58
- export const is_permit_active = (p, now = new Date()) => !p.revoked_at && (!p.expires_at || new Date(p.expires_at) > now);
28
+ export const ROLE_GRANT_REVOKED_REASON_LENGTH_MAX = 500;
29
+ export const is_role_grant_active = (p, now = new Date()) => !p.revoked_at && (!p.expires_at || new Date(p.expires_at) > now);
59
30
  // Client-safe Zod schemas — for route output validation and ActionSpec outputs.
60
31
  /** Zod schema for `SessionAccount` — account without sensitive fields. */
61
32
  export const SessionAccountJson = z.strictObject({
@@ -83,10 +54,11 @@ export const ClientApiTokenJson = z.strictObject({
83
54
  last_used_ip: z.string().nullable(),
84
55
  created_at: z.string(),
85
56
  });
86
- /** Zod schema for the permit summary returned in admin account listings. */
87
- export const PermitSummaryJson = z.strictObject({
57
+ /** Zod schema for the role_grant summary returned in admin account listings. */
58
+ export const RoleGrantSummaryJson = z.strictObject({
88
59
  id: Uuid,
89
60
  role: z.string(),
61
+ scope_kind: z.string().nullable(),
90
62
  scope_id: Uuid.nullable(),
91
63
  created_at: z.string(),
92
64
  expires_at: z.string().nullable(),
@@ -103,9 +75,9 @@ export const AdminAccountJson = SessionAccountJson.extend({
103
75
  updated_by: Uuid.nullable(),
104
76
  });
105
77
  /**
106
- * Zod schema for a pending permit offer surfaced in admin account listings.
78
+ * Zod schema for a pending role_grant offer surfaced in admin account listings.
107
79
  *
108
- * Deliberately narrower than `PermitOfferJson`: omits `message` and
80
+ * Deliberately narrower than `RoleGrantOfferJson`: omits `message` and
109
81
  * `decline_reason` so cross-admin visibility of the listing does not expose
110
82
  * grantor-authored text that the audit log also withholds. Full offer
111
83
  * payloads remain available through the offer-specific RPC surface and the
@@ -118,17 +90,18 @@ export const AdminAccountJson = SessionAccountJson.extend({
118
90
  export const PendingOfferSummaryJson = z.strictObject({
119
91
  id: Uuid,
120
92
  role: z.string(),
93
+ scope_kind: z.string().nullable(),
121
94
  scope_id: Uuid.nullable(),
122
95
  from_actor_id: Uuid,
123
96
  from_username: z.string(),
124
97
  created_at: z.string(),
125
98
  expires_at: z.string(),
126
99
  });
127
- /** Zod schema for an admin account listing entry (account + actor + permits + pending offers). */
100
+ /** Zod schema for an admin account listing entry (account + actor + role_grants + pending offers). */
128
101
  export const AdminAccountEntryJson = z.strictObject({
129
102
  account: AdminAccountJson,
130
103
  actor: ActorSummaryJson.nullable(),
131
- permits: z.array(PermitSummaryJson),
104
+ role_grants: z.array(RoleGrantSummaryJson),
132
105
  pending_offers: z.array(PendingOfferSummaryJson),
133
106
  });
134
107
  /**