@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
@@ -1,182 +0,0 @@
1
- /**
2
- * Permit offer WebSocket notification specs, builders, and the narrow
3
- * `NotificationSender` interface that decouples offer/revoke send sites
4
- * from `BackendWebsocketTransport`.
5
- *
6
- * Six `RemoteNotificationActionSpec`s cover the consentful-permits
7
- * lifecycle events the server pushes to affected accounts:
8
- *
9
- * - `permit_offer_received` → recipient's sockets when an offer is created
10
- * - `permit_offer_retracted` → recipient's sockets when a grantor retracts
11
- * - `permit_offer_accepted` → grantor's sockets when the recipient accepts
12
- * - `permit_offer_declined` → grantor's sockets when the recipient declines
13
- * - `permit_offer_supersede` → grantor's sockets when a sibling accept,
14
- * a revoke of the resulting permit, or destruction of the parent scope
15
- * row obsoletes their pending offer
16
- * - `permit_revoke` → revokee's sockets when one of their active permits
17
- * is revoked (companion to the `permit_revoke` audit event)
18
- *
19
- * Payloads are flat and normalized — `PermitOfferJson` for the offer-lifecycle
20
- * notifications (decline reason rides on `offer.decline_reason`, not a
21
- * sibling field), and `{permit_id, role, scope_id, reason?}` for `permit_revoke`. The
22
- * revokee/grantor/recipient account id travels via the send target (the
23
- * `NotificationSender.send_to_account` argument), not in the payload.
24
- *
25
- * The specs surface as `EventSpec`s via `create_action_event_spec` — callers
26
- * append `PERMIT_OFFER_NOTIFICATION_SPECS` to their `event_specs` on
27
- * `create_app_server` so the surface reflects them and DEV-mode broadcast
28
- * validation catches payload drift.
29
- *
30
- * @module
31
- */
32
- import { z } from 'zod';
33
- import { Uuid as UuidSchema } from '@fuzdev/fuz_util/id.js';
34
- import { create_action_event_spec } from '../actions/action_bridge.js';
35
- import { create_jsonrpc_notification } from '../http/jsonrpc_helpers.js';
36
- import { RoleName } from './role_schema.js';
37
- import { PermitOfferJson } from './permit_offer_schema.js';
38
- import { PERMIT_REVOKED_REASON_LENGTH_MAX } from './account_schema.js';
39
- // -- Method constants -------------------------------------------------------
40
- export const PERMIT_OFFER_RECEIVED_NOTIFICATION_METHOD = 'permit_offer_received';
41
- export const PERMIT_OFFER_RETRACTED_NOTIFICATION_METHOD = 'permit_offer_retracted';
42
- export const PERMIT_OFFER_ACCEPTED_NOTIFICATION_METHOD = 'permit_offer_accepted';
43
- export const PERMIT_OFFER_DECLINED_NOTIFICATION_METHOD = 'permit_offer_declined';
44
- export const PERMIT_OFFER_SUPERSEDE_NOTIFICATION_METHOD = 'permit_offer_supersede';
45
- export const PERMIT_REVOKE_NOTIFICATION_METHOD = 'permit_revoke';
46
- // -- Params schemas ---------------------------------------------------------
47
- /** Params for `permit_offer_received` — offer delivered to its recipient. */
48
- export const PermitOfferReceivedParams = z.strictObject({
49
- offer: PermitOfferJson,
50
- });
51
- /** Params for `permit_offer_retracted` — grantor-side retraction. */
52
- export const PermitOfferRetractedParams = z.strictObject({
53
- offer: PermitOfferJson,
54
- });
55
- /** Params for `permit_offer_accepted` — recipient accepted the offer. */
56
- export const PermitOfferAcceptedParams = z.strictObject({
57
- offer: PermitOfferJson,
58
- });
59
- /**
60
- * Params for `permit_offer_declined`. The decline reason (if any) rides along
61
- * inside `offer.decline_reason` — the DB stamps it on the offer row during
62
- * decline, so a sibling `reason` field would just duplicate it.
63
- */
64
- export const PermitOfferDeclinedParams = z.strictObject({
65
- offer: PermitOfferJson,
66
- });
67
- /**
68
- * Params for `permit_offer_supersede`. Fires to the grantor's sockets when
69
- * their pending offer is obsoleted — either by a sibling accept
70
- * (`reason: 'sibling_accepted'`), by revoke of the resulting permit
71
- * (`reason: 'permit_revoked'`), or by deletion of the parent scope row
72
- * the offer was bound to (`reason: 'scope_destroyed'`). `cause_id` points
73
- * at the accepted offer id, the revoked permit id, or the destroyed scope
74
- * row id respectively.
75
- */
76
- export const PermitOfferSupersedeParams = z.strictObject({
77
- offer: PermitOfferJson,
78
- reason: z.enum(['sibling_accepted', 'permit_revoked', 'scope_destroyed']),
79
- cause_id: UuidSchema,
80
- });
81
- /**
82
- * Params for `permit_revoke`. Delivered to the revokee's sockets when one
83
- * of their active permits is revoked. Flat wire shape — `revoked_by` is
84
- * admin-UI-visible but deliberately omitted here (the revokee doesn't need
85
- * to learn the admin's identity). Target account is implicit in the send
86
- * target.
87
- */
88
- export const PermitRevokeParams = z.strictObject({
89
- permit_id: UuidSchema,
90
- role: RoleName,
91
- scope_id: UuidSchema.nullable(),
92
- reason: z.string().max(PERMIT_REVOKED_REASON_LENGTH_MAX).nullable(),
93
- });
94
- // -- Action specs -----------------------------------------------------------
95
- export const permit_offer_received_notification_spec = {
96
- method: PERMIT_OFFER_RECEIVED_NOTIFICATION_METHOD,
97
- kind: 'remote_notification',
98
- initiator: 'backend',
99
- auth: null,
100
- side_effects: true,
101
- input: PermitOfferReceivedParams,
102
- output: z.void(),
103
- async: true,
104
- description: 'A new permit offer arrived in the recipient’s inbox.',
105
- };
106
- export const permit_offer_retracted_notification_spec = {
107
- method: PERMIT_OFFER_RETRACTED_NOTIFICATION_METHOD,
108
- kind: 'remote_notification',
109
- initiator: 'backend',
110
- auth: null,
111
- side_effects: true,
112
- input: PermitOfferRetractedParams,
113
- output: z.void(),
114
- async: true,
115
- description: 'A pending permit offer was retracted by its grantor.',
116
- };
117
- export const permit_offer_accepted_notification_spec = {
118
- method: PERMIT_OFFER_ACCEPTED_NOTIFICATION_METHOD,
119
- kind: 'remote_notification',
120
- initiator: 'backend',
121
- auth: null,
122
- side_effects: true,
123
- input: PermitOfferAcceptedParams,
124
- output: z.void(),
125
- async: true,
126
- description: 'A pending permit offer was accepted by its recipient.',
127
- };
128
- export const permit_offer_declined_notification_spec = {
129
- method: PERMIT_OFFER_DECLINED_NOTIFICATION_METHOD,
130
- kind: 'remote_notification',
131
- initiator: 'backend',
132
- auth: null,
133
- side_effects: true,
134
- input: PermitOfferDeclinedParams,
135
- output: z.void(),
136
- async: true,
137
- description: 'A pending permit offer was declined by its recipient.',
138
- };
139
- export const permit_offer_supersede_notification_spec = {
140
- method: PERMIT_OFFER_SUPERSEDE_NOTIFICATION_METHOD,
141
- kind: 'remote_notification',
142
- initiator: 'backend',
143
- auth: null,
144
- side_effects: true,
145
- input: PermitOfferSupersedeParams,
146
- output: z.void(),
147
- async: true,
148
- description: 'A grantor’s pending permit offer was obsoleted by a sibling accept, by revoke of the resulting permit, or by destruction of the parent scope row.',
149
- };
150
- export const permit_revoke_notification_spec = {
151
- method: PERMIT_REVOKE_NOTIFICATION_METHOD,
152
- kind: 'remote_notification',
153
- initiator: 'backend',
154
- auth: null,
155
- side_effects: true,
156
- input: PermitRevokeParams,
157
- output: z.void(),
158
- async: true,
159
- description: 'An active permit on the revokee’s account was revoked.',
160
- };
161
- // -- EventSpec surface ------------------------------------------------------
162
- /**
163
- * SSE/WS event specs for the consentful-permits notification surface.
164
- *
165
- * Pass to `create_app_server`'s `event_specs` so the attack surface reflects
166
- * them and DEV-mode `create_validated_broadcaster` catches payload drift.
167
- */
168
- export const PERMIT_OFFER_NOTIFICATION_SPECS = [
169
- create_action_event_spec(permit_offer_received_notification_spec),
170
- create_action_event_spec(permit_offer_retracted_notification_spec),
171
- create_action_event_spec(permit_offer_accepted_notification_spec),
172
- create_action_event_spec(permit_offer_declined_notification_spec),
173
- create_action_event_spec(permit_offer_supersede_notification_spec),
174
- create_action_event_spec(permit_revoke_notification_spec),
175
- ];
176
- // -- Notification builders --------------------------------------------------
177
- export const build_permit_offer_received_notification = (params) => create_jsonrpc_notification(PERMIT_OFFER_RECEIVED_NOTIFICATION_METHOD, params);
178
- export const build_permit_offer_retracted_notification = (params) => create_jsonrpc_notification(PERMIT_OFFER_RETRACTED_NOTIFICATION_METHOD, params);
179
- export const build_permit_offer_accepted_notification = (params) => create_jsonrpc_notification(PERMIT_OFFER_ACCEPTED_NOTIFICATION_METHOD, params);
180
- export const build_permit_offer_declined_notification = (params) => create_jsonrpc_notification(PERMIT_OFFER_DECLINED_NOTIFICATION_METHOD, params);
181
- export const build_permit_offer_supersede_notification = (params) => create_jsonrpc_notification(PERMIT_OFFER_SUPERSEDE_NOTIFICATION_METHOD, params);
182
- export const build_permit_revoke_notification = (params) => create_jsonrpc_notification(PERMIT_REVOKE_NOTIFICATION_METHOD, params);
@@ -1 +0,0 @@
1
- {"version":3,"file":"permit_offer_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/permit_offer_queries.ts"],"names":[],"mappings":"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"}
@@ -1,125 +0,0 @@
1
- /**
2
- * Permit offer DDL, types, and client-safe schemas.
3
- *
4
- * An offer is a pending grant awaiting recipient consent. Lifecycle states
5
- * are mutually exclusive via a CHECK constraint (`permit_offer_single_terminal`):
6
- * at most one of `accepted_at` / `declined_at` / `retracted_at` may be set.
7
- * On accept, the offer's `resulting_permit_id` links to the permit row
8
- * produced by `query_accept_offer`.
9
- *
10
- * @module
11
- */
12
- import { z } from 'zod';
13
- import { Uuid } from '@fuzdev/fuz_util/id.js';
14
- /** Sentinel UUID used inside the partial unique indexes to collapse `scope_id IS NULL` into a comparable value. */
15
- export declare const PERMIT_OFFER_SCOPE_SENTINEL_UUID = "00000000-0000-0000-0000-000000000000";
16
- /** Maximum length of the optional message attached to an offer. */
17
- export declare const PERMIT_OFFER_MESSAGE_LENGTH_MAX = 500;
18
- /** Default TTL for a newly created offer — 30 days. Matches GitHub org-invite expiry. */
19
- export declare const PERMIT_OFFER_DEFAULT_TTL_MS: number;
20
- export declare const PERMIT_OFFER_SCHEMA = "\nCREATE TABLE IF NOT EXISTS permit_offer (\n id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n from_actor_id UUID NOT NULL REFERENCES actor(id) ON DELETE CASCADE,\n to_account_id UUID NOT NULL REFERENCES account(id) ON DELETE CASCADE,\n to_actor_id UUID NULL REFERENCES actor(id) ON DELETE CASCADE,\n role TEXT NOT NULL,\n scope_id UUID NULL,\n message TEXT NULL,\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n expires_at TIMESTAMPTZ NOT NULL,\n accepted_at TIMESTAMPTZ NULL,\n declined_at TIMESTAMPTZ NULL,\n decline_reason TEXT NULL,\n retracted_at TIMESTAMPTZ NULL,\n superseded_at TIMESTAMPTZ NULL,\n resulting_permit_id UUID NULL REFERENCES permit(id) ON DELETE SET NULL,\n CONSTRAINT permit_offer_single_terminal CHECK (\n (accepted_at IS NOT NULL)::int\n + (declined_at IS NOT NULL)::int\n + (retracted_at IS NOT NULL)::int\n + (superseded_at IS NOT NULL)::int\n <= 1\n ),\n CONSTRAINT permit_offer_permit_iff_accepted CHECK (\n (accepted_at IS NOT NULL) = (resulting_permit_id IS NOT NULL)\n ),\n CONSTRAINT permit_offer_reason_iff_declined CHECK (\n decline_reason IS NULL OR declined_at IS NOT NULL\n )\n)";
21
- /**
22
- * At most one pending offer per (to_account, role, scope, from_actor).
23
- *
24
- * Including `from_actor_id` in the tuple lets multiple grantors coexist —
25
- * teacher A and teacher B can each have a pending `classroom_student` offer
26
- * for the same student and scope. A same-grantor re-offer upserts the
27
- * existing pending row. `COALESCE` collapses `NULL` scopes into the
28
- * sentinel UUID so Postgres's NULL-in-unique-index quirk does not allow
29
- * duplicate global pending offers. The ON CONFLICT target in
30
- * `query_permit_offer_create` must match this expression literally.
31
- */
32
- export declare const PERMIT_OFFER_PENDING_UNIQUE_INDEX = "\nCREATE UNIQUE INDEX IF NOT EXISTS permit_offer_pending_unique\n ON permit_offer (\n to_account_id,\n role,\n COALESCE(scope_id, '00000000-0000-0000-0000-000000000000'::uuid),\n from_actor_id\n )\n WHERE accepted_at IS NULL\n AND declined_at IS NULL\n AND retracted_at IS NULL\n AND superseded_at IS NULL";
33
- /** Inbox lookup — pending offers for an account, ordered by soonest expiry. */
34
- export declare const PERMIT_OFFER_INBOX_INDEX = "\nCREATE INDEX IF NOT EXISTS permit_offer_inbox\n ON permit_offer (to_account_id, expires_at)\n WHERE accepted_at IS NULL\n AND declined_at IS NULL\n AND retracted_at IS NULL\n AND superseded_at IS NULL";
35
- /** Permit offer row as returned by the database. */
36
- export interface PermitOffer {
37
- id: Uuid;
38
- from_actor_id: Uuid;
39
- to_account_id: Uuid;
40
- /**
41
- * Optional actor-grain target on the recipient account. When set, accept
42
- * is gated to this specific actor — `query_accept_offer` rejects any
43
- * other actor with `permit_offer_actor_mismatch` even when they belong
44
- * to `to_account_id`. When null the offer is account-grain and any
45
- * actor on `to_account_id` may accept (the v1 default).
46
- *
47
- * Drives the audit envelope's `target_actor_id` on offer-shape events
48
- * (`permit_offer_create` / `_expire` / `_retract` / `_supersede`) — when
49
- * set, the actor-grain forensic field carries the named actor; when
50
- * null the offer-shape events leave it null by design.
51
- */
52
- to_actor_id: Uuid | null;
53
- role: string;
54
- scope_id: Uuid | null;
55
- message: string | null;
56
- created_at: string;
57
- expires_at: string;
58
- accepted_at: string | null;
59
- declined_at: string | null;
60
- decline_reason: string | null;
61
- retracted_at: string | null;
62
- /**
63
- * Set when the offer was obsoleted by an external event — a sibling
64
- * offer was accepted (yielding the permit this offer's role+scope maps to)
65
- * or the resulting permit for this (to_account, role, scope) was revoked.
66
- * Closes the "accept a pre-revoke offer to bypass the revoke" path.
67
- */
68
- superseded_at: string | null;
69
- resulting_permit_id: Uuid | null;
70
- }
71
- /**
72
- * A superseded offer row annotated with the grantor's `account_id`.
73
- *
74
- * Carried by `superseded_offers` in accept/revoke query results so callers
75
- * can fan out `permit_offer_supersede` notifications to the grantor's
76
- * sockets without a second round-trip. Populated via a CTE join on `actor`
77
- * in the supersede UPDATE.
78
- */
79
- export interface SupersededOffer extends PermitOffer {
80
- from_account_id: Uuid;
81
- }
82
- /**
83
- * Input for `query_permit_offer_create`.
84
- *
85
- * `expires_at` must be supplied — the query layer does not apply a default,
86
- * so callers can thread their own TTL (typically `PERMIT_OFFER_DEFAULT_TTL_MS`).
87
- */
88
- export interface CreatePermitOfferInput {
89
- from_actor_id: Uuid;
90
- to_account_id: Uuid;
91
- /**
92
- * Optional actor-grain target on the recipient account. When set,
93
- * `query_permit_offer_create` validates that the actor belongs to
94
- * `to_account_id` and stamps the column; accept then matches against
95
- * this specific actor. Omit (or pass null) for the account-grain
96
- * default — any actor on `to_account_id` may accept.
97
- */
98
- to_actor_id?: Uuid | null;
99
- role: string;
100
- scope_id?: Uuid | null;
101
- message?: string | null;
102
- expires_at: Date;
103
- }
104
- /** Zod schema for client-safe permit offer data. */
105
- export declare const PermitOfferJson: z.ZodObject<{
106
- id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
107
- from_actor_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
108
- to_account_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
109
- to_actor_id: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
110
- role: z.ZodString;
111
- scope_id: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
112
- message: z.ZodNullable<z.ZodString>;
113
- created_at: z.ZodString;
114
- expires_at: z.ZodString;
115
- accepted_at: z.ZodNullable<z.ZodString>;
116
- declined_at: z.ZodNullable<z.ZodString>;
117
- decline_reason: z.ZodNullable<z.ZodString>;
118
- retracted_at: z.ZodNullable<z.ZodString>;
119
- superseded_at: z.ZodNullable<z.ZodString>;
120
- resulting_permit_id: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
121
- }, z.core.$strict>;
122
- export type PermitOfferJson = z.infer<typeof PermitOfferJson>;
123
- /** Convert a `PermitOffer` row to its JSON payload shape. */
124
- export declare const to_permit_offer_json: (offer: PermitOffer) => PermitOfferJson;
125
- //# sourceMappingURL=permit_offer_schema.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"permit_offer_schema.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/permit_offer_schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,EAAC,IAAI,EAAC,MAAM,wBAAwB,CAAC;AAI5C,mHAAmH;AACnH,eAAO,MAAM,gCAAgC,yCAAyC,CAAC;AAEvF,mEAAmE;AACnE,eAAO,MAAM,+BAA+B,MAAM,CAAC;AAEnD,yFAAyF;AACzF,eAAO,MAAM,2BAA2B,QAA2B,CAAC;AAEpE,eAAO,MAAM,mBAAmB,8oCA8B9B,CAAC;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iCAAiC,8UAWhB,CAAC;AAE/B,+EAA+E;AAC/E,eAAO,MAAM,wBAAwB,0NAMP,CAAC;AAQ/B,oDAAoD;AACpD,MAAM,WAAW,WAAW;IAC3B,EAAE,EAAE,IAAI,CAAC;IACT,aAAa,EAAE,IAAI,CAAC;IACpB,aAAa,EAAE,IAAI,CAAC;IACpB;;;;;;;;;;;OAWG;IACH,WAAW,EAAE,IAAI,GAAG,IAAI,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B;;;;;OAKG;IACH,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,mBAAmB,EAAE,IAAI,GAAG,IAAI,CAAC;CACjC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,eAAgB,SAAQ,WAAW;IACnD,eAAe,EAAE,IAAI,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,WAAW,sBAAsB;IACtC,aAAa,EAAE,IAAI,CAAC;IACpB,aAAa,EAAE,IAAI,CAAC;IACpB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,IAAI,CAAC;CACjB;AAED,oDAAoD;AACpD,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;kBAgDyD,CAAC;AACtF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,6DAA6D;AAC7D,eAAO,MAAM,oBAAoB,GAAI,OAAO,WAAW,KAAG,eAgBxD,CAAC"}
@@ -1,222 +0,0 @@
1
- /**
2
- * Permit database queries.
3
- *
4
- * Permits are time-bounded, revocable grants of a role to an actor.
5
- * The system is safe by default — no permit, no capability.
6
- *
7
- * @module
8
- */
9
- import type { Uuid } from '@fuzdev/fuz_util/id.js';
10
- import type { QueryDeps } from '../db/query_deps.js';
11
- import type { Permit, GrantPermitInput } from './account_schema.js';
12
- import { type SupersededOffer } from './permit_offer_schema.js';
13
- /**
14
- * Grant a permit to an actor.
15
- * Idempotent — if an active permit already exists for this actor, role, and
16
- * scope, returns the existing permit instead of creating a duplicate.
17
- *
18
- * The `ON CONFLICT` target and the fallback `SELECT` both collapse `NULL`
19
- * scopes via the same sentinel used by the partial unique index
20
- * (`permit_actor_role_scope_active_unique`). The `IS NOT DISTINCT FROM`
21
- * form on the fallback is deliberate — plain `=` would miss the
22
- * NULL-scope case where the conflict fired.
23
- *
24
- * @param deps - query dependencies
25
- * @param input - the permit fields
26
- * @returns the created or existing active permit
27
- * @mutates `permit` table - inserts a row when no active permit matches `(actor_id, role, scope_id)`
28
- */
29
- export declare const query_grant_permit: (deps: QueryDeps, input: GrantPermitInput) => Promise<Permit>;
30
- /**
31
- * Look up the role of an active permit (constrained to a specific
32
- * actor) plus the actor's `account_id`.
33
- *
34
- * Used by admin routes to inspect the permit's role before acting
35
- * (e.g., enforcing `web_grantable` on revoke). The actor constraint
36
- * mirrors `query_revoke_permit` so IDOR protection is consistent:
37
- * a caller can only see permits belonging to the target actor.
38
- *
39
- * The JOIN to `actor` collapses what used to be a second
40
- * `query_actor_by_id` round-trip in the revoke handler into one read,
41
- * which closes the small TOCTOU window where the actor row could be
42
- * deleted between the IDOR check and the actor lookup. The `account_id`
43
- * is needed by the audit envelope's `target_account_id` field and the
44
- * SSE/WS socket-close fan-out targeting.
45
- *
46
- * Returns `null` if the permit is not found, already revoked, or
47
- * belongs to a different actor.
48
- *
49
- * @param deps - query dependencies
50
- * @param permit_id - the permit id to look up
51
- * @param actor_id - the actor that must own the permit
52
- * @returns `{role, account_id}` on a match, or `null`
53
- */
54
- export declare const query_permit_find_active_role_for_actor: (deps: QueryDeps, permit_id: string, actor_id: string) => Promise<{
55
- role: string;
56
- account_id: Uuid;
57
- } | null>;
58
- /** Result of `query_revoke_permit` — the revoked permit plus any pending offers superseded by the revoke. */
59
- export interface RevokePermitResult {
60
- id: Uuid;
61
- role: string;
62
- scope_id: Uuid | null;
63
- /**
64
- * Pending offers for the revoked permit's `(account, role, scope)` that
65
- * were marked superseded as a side effect. Each entry carries its
66
- * grantor's `from_account_id` so callers can fan out
67
- * `permit_offer_supersede` notifications without a second round-trip.
68
- * The caller is responsible for emitting a `permit_offer_supersede`
69
- * audit event per entry (with `reason: 'permit_revoked'` and
70
- * `cause_id: <revoked permit id>`).
71
- */
72
- superseded_offers: Array<SupersededOffer>;
73
- }
74
- /**
75
- * Revoke a permit by id, constrained to a specific actor.
76
- *
77
- * Requires `actor_id` to prevent cross-account revocation (IDOR guard).
78
- * Returns `null` if the permit is not found, already revoked, or belongs
79
- * to a different actor.
80
- *
81
- * Supersedes any pending offers for the revoked permit's
82
- * `(to_account, role, scope)` in the same transaction. Prevents the
83
- * "accept a pre-revoke offer to bypass the revoke" path — any stale
84
- * offer becomes terminal at revoke time. A fresh post-revoke grant
85
- * requires the grantor to call `query_permit_offer_create` again.
86
- *
87
- * @param deps - query dependencies
88
- * @param permit_id - the permit to revoke
89
- * @param actor_id - the actor that must own the permit
90
- * @param revoked_by - the actor who revoked it (for audit trail)
91
- * @param reason - optional free-form reason, stamped on `permit.revoked_reason` and surfaced to the revokee notification.
92
- * @mutates `permit` row - sets `revoked_at`, `revoked_by`, and `revoked_reason`
93
- * @mutates `permit_offer` rows - stamps `superseded_at` on every pending sibling for the same `(account, role, scope)`
94
- */
95
- export declare const query_revoke_permit: (deps: QueryDeps, permit_id: Uuid, actor_id: Uuid, revoked_by: Uuid | null, reason?: string | null) => Promise<RevokePermitResult | null>;
96
- /**
97
- * Find all active (non-revoked, non-expired) permits for an actor.
98
- */
99
- export declare const query_permit_find_active_for_actor: (deps: QueryDeps, actor_id: string) => Promise<Array<Permit>>;
100
- /**
101
- * Check if an actor has an active permit for a given role.
102
- *
103
- * The `scope_id` parameter selects between global and scoped checks:
104
- * - Omitted or `null` — matches a global permit (`scope_id IS NULL`).
105
- * Pre-scope callers keep their existing semantics.
106
- * - A scope uuid — matches a permit bound to that exact scope.
107
- *
108
- * The `IS NOT DISTINCT FROM` comparison handles the NULL case uniformly.
109
- */
110
- export declare const query_permit_has_role: (deps: QueryDeps, actor_id: string, role: string, scope_id?: string | null) => Promise<boolean>;
111
- /**
112
- * List all permits for an actor (including revoked/expired).
113
- */
114
- export declare const query_permit_list_for_actor: (deps: QueryDeps, actor_id: string) => Promise<Array<Permit>>;
115
- /**
116
- * Find the account ID of an account that holds an active permit for a given role.
117
- *
118
- * Joins permit → actor → account. Returns the first match, or `null` if none.
119
- *
120
- * @param deps - query dependencies
121
- * @param role - the role to search for
122
- * @returns the account ID, or `null`
123
- */
124
- export declare const query_permit_find_account_id_for_role: (deps: QueryDeps, role: string) => Promise<string | null>;
125
- /** Result of `query_permit_revoke_for_scope` — every permit revoked plus every pending offer superseded by the scope-wide cascade. */
126
- export interface RevokeForScopeResult {
127
- /**
128
- * One entry per permit revoked by this call. Carries both the revokee's
129
- * `actor_id` (the permit's grantee — drives `target_actor_id` audit
130
- * envelopes) and `account_id` (the actor's account — drives
131
- * `target_account_id` for SSE/WS socket-close fan-out). Empty array
132
- * means no active permit was bound to the scope.
133
- */
134
- revoked: Array<{
135
- permit_id: Uuid;
136
- role: string;
137
- scope_id: Uuid;
138
- actor_id: Uuid;
139
- account_id: Uuid;
140
- }>;
141
- /**
142
- * Every pending offer at the scope — tuple-matched and orphan, undifferentiated
143
- * — superseded in the same cascade. Each entry carries its grantor's
144
- * `from_account_id` for `permit_offer_supersede` notification fan-out.
145
- *
146
- * The caller is responsible for emitting `permit_offer_supersede` audit
147
- * events with `reason: 'scope_destroyed'` and `cause_id: <destroyed scope row id>`
148
- * per entry — the cause of every supersede here is the scope deletion,
149
- * not any individual permit revoke (the revokes are themselves
150
- * consequences of the scope going away).
151
- */
152
- superseded_offers: Array<SupersededOffer>;
153
- }
154
- /**
155
- * Revoke every active permit bound to a scope and supersede every pending
156
- * offer at the scope, in one cascade.
157
- *
158
- * Use this from a consumer's parent-scope delete handler (e.g., classroom
159
- * deletion) — `permit.scope_id` and `permit_offer.scope_id` are polymorphic
160
- * with no FK constraint by design, so a parent row deletion would otherwise
161
- * orphan permits and offers. The cascade is **role-agnostic**: anything
162
- * attached to the destroyed scope is cleaned up.
163
- *
164
- * Both updates run as separate statements inside the caller's transaction
165
- * (mirrors `query_permit_revoke_role`'s shape). The two halves are
166
- * independent — orphan pending offers can exist at a scope with no active
167
- * permits, so the supersede half always runs even when no permit was
168
- * revoked.
169
- *
170
- * @param deps - query dependencies
171
- * @param scope_id - the scope whose permits and offers to terminate
172
- * @param revoked_by - the actor performing the cascade (audit trail)
173
- * @param reason - optional free-form reason, stamped on `permit.revoked_reason`.
174
- * @returns the revoked permits (with `account_id` for fan-out) and superseded offers (with `from_account_id` for fan-out)
175
- * @mutates `permit` table - sets `revoked_at`/`revoked_by`/`revoked_reason` on every active row at `scope_id`
176
- * @mutates `permit_offer` table - stamps `superseded_at` on every pending row at `scope_id`
177
- */
178
- export declare const query_permit_revoke_for_scope: (deps: QueryDeps, scope_id: Uuid, revoked_by: Uuid | null, reason?: string | null) => Promise<RevokeForScopeResult>;
179
- /** Result of `query_permit_revoke_role` — every permit revoked plus the pending offers superseded by the bulk revoke. */
180
- export interface RevokeRoleResult {
181
- /**
182
- * One entry per permit revoked by this call. Carries the revokee's
183
- * `account_id` so callers can fan out a `permit_revoke` notification per
184
- * scope-instance. Empty array means nothing was active for `(actor, role)`.
185
- */
186
- revoked: Array<{
187
- permit_id: string;
188
- role: string;
189
- scope_id: string | null;
190
- account_id: string;
191
- }>;
192
- /**
193
- * Pending offers for the actor's account+role (all scopes) superseded by
194
- * the bulk revoke. Each entry carries its grantor's `from_account_id` so
195
- * callers can fan out `permit_offer_supersede` notifications without a
196
- * second round-trip.
197
- */
198
- superseded_offers: Array<SupersededOffer>;
199
- }
200
- /**
201
- * Revoke every active permit an actor holds for a given role.
202
- *
203
- * With scoped permits a single actor+role tuple can hold several active
204
- * permits (one per scope), so this revokes all of them. Pass
205
- * `query_revoke_permit(permit_id, ...)` when a single scoped permit
206
- * is the target.
207
- *
208
- * Also supersedes pending offers for the actor's account across every
209
- * scope of this role (the actor can no longer hold the role, so any
210
- * pending offer of the same role is a bypass vector).
211
- *
212
- * @param deps - query dependencies
213
- * @param actor_id - the actor whose permits to revoke
214
- * @param role - the role to revoke
215
- * @param revoked_by - the actor who revoked it (for audit trail)
216
- * @param reason - optional free-form reason, stamped on `permit.revoked_reason`.
217
- * @returns the list of revoked permits (empty if none were active) and superseded pending offers
218
- * @mutates `permit` table - sets `revoked_at`/`revoked_by`/`revoked_reason` on every active row for `(actor, role)`
219
- * @mutates `permit_offer` table - stamps `superseded_at` on every matching pending offer
220
- */
221
- export declare const query_permit_revoke_role: (deps: QueryDeps, actor_id: string, role: string, revoked_by: string | null, reason?: string | null) => Promise<RevokeRoleResult>;
222
- //# sourceMappingURL=permit_queries.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"permit_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/permit_queries.ts"],"names":[],"mappings":"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"}