@fuzdev/fuz_app 0.55.0 → 0.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (331) hide show
  1. package/dist/actions/CLAUDE.md +211 -155
  2. package/dist/actions/action_bridge.d.ts +8 -5
  3. package/dist/actions/action_bridge.d.ts.map +1 -1
  4. package/dist/actions/action_bridge.js +1 -11
  5. package/dist/actions/action_codegen.d.ts +19 -0
  6. package/dist/actions/action_codegen.d.ts.map +1 -1
  7. package/dist/actions/action_codegen.js +20 -14
  8. package/dist/actions/action_registry.d.ts.map +1 -1
  9. package/dist/actions/action_registry.js +5 -2
  10. package/dist/actions/action_rpc.d.ts +110 -44
  11. package/dist/actions/action_rpc.d.ts.map +1 -1
  12. package/dist/actions/action_rpc.js +92 -287
  13. package/dist/actions/action_spec.d.ts +55 -16
  14. package/dist/actions/action_spec.d.ts.map +1 -1
  15. package/dist/actions/action_spec.js +16 -11
  16. package/dist/actions/action_types.d.ts +28 -60
  17. package/dist/actions/action_types.d.ts.map +1 -1
  18. package/dist/actions/action_types.js +13 -5
  19. package/dist/actions/broadcast_api.d.ts +2 -2
  20. package/dist/actions/broadcast_api.js +2 -2
  21. package/dist/actions/compile_action_registry.d.ts +50 -0
  22. package/dist/actions/compile_action_registry.d.ts.map +1 -0
  23. package/dist/actions/compile_action_registry.js +69 -0
  24. package/dist/actions/heartbeat.d.ts +8 -4
  25. package/dist/actions/heartbeat.d.ts.map +1 -1
  26. package/dist/actions/heartbeat.js +5 -4
  27. package/dist/actions/perform_action.d.ts +145 -0
  28. package/dist/actions/perform_action.d.ts.map +1 -0
  29. package/dist/actions/perform_action.js +258 -0
  30. package/dist/actions/register_action_ws.d.ts +44 -38
  31. package/dist/actions/register_action_ws.d.ts.map +1 -1
  32. package/dist/actions/register_action_ws.js +101 -159
  33. package/dist/actions/register_ws_endpoint.d.ts +2 -10
  34. package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
  35. package/dist/actions/register_ws_endpoint.js +32 -10
  36. package/dist/actions/transports_ws_auth_guard.d.ts +1 -1
  37. package/dist/actions/transports_ws_auth_guard.js +1 -1
  38. package/dist/actions/transports_ws_backend.d.ts +1 -1
  39. package/dist/actions/transports_ws_backend.js +1 -1
  40. package/dist/auth/CLAUDE.md +673 -442
  41. package/dist/auth/account_action_specs.d.ts +28 -7
  42. package/dist/auth/account_action_specs.d.ts.map +1 -1
  43. package/dist/auth/account_action_specs.js +7 -7
  44. package/dist/auth/account_actions.d.ts +8 -14
  45. package/dist/auth/account_actions.d.ts.map +1 -1
  46. package/dist/auth/account_actions.js +26 -32
  47. package/dist/auth/account_queries.d.ts +46 -13
  48. package/dist/auth/account_queries.d.ts.map +1 -1
  49. package/dist/auth/account_queries.js +73 -33
  50. package/dist/auth/account_routes.d.ts +4 -3
  51. package/dist/auth/account_routes.d.ts.map +1 -1
  52. package/dist/auth/account_routes.js +58 -33
  53. package/dist/auth/account_schema.d.ts +46 -54
  54. package/dist/auth/account_schema.d.ts.map +1 -1
  55. package/dist/auth/account_schema.js +21 -48
  56. package/dist/auth/admin_action_specs.d.ts +55 -21
  57. package/dist/auth/admin_action_specs.d.ts.map +1 -1
  58. package/dist/auth/admin_action_specs.js +42 -26
  59. package/dist/auth/admin_actions.d.ts +14 -21
  60. package/dist/auth/admin_actions.d.ts.map +1 -1
  61. package/dist/auth/admin_actions.js +47 -44
  62. package/dist/auth/audit_emitter.d.ts +160 -0
  63. package/dist/auth/audit_emitter.d.ts.map +1 -0
  64. package/dist/auth/audit_emitter.js +83 -0
  65. package/dist/auth/audit_log_queries.d.ts +17 -87
  66. package/dist/auth/audit_log_queries.d.ts.map +1 -1
  67. package/dist/auth/audit_log_queries.js +17 -96
  68. package/dist/auth/audit_log_routes.d.ts +1 -1
  69. package/dist/auth/audit_log_routes.d.ts.map +1 -1
  70. package/dist/auth/audit_log_routes.js +7 -3
  71. package/dist/auth/audit_log_schema.d.ts +48 -42
  72. package/dist/auth/audit_log_schema.d.ts.map +1 -1
  73. package/dist/auth/audit_log_schema.js +56 -43
  74. package/dist/auth/auth_guard_resolver.d.ts +44 -0
  75. package/dist/auth/auth_guard_resolver.d.ts.map +1 -0
  76. package/dist/auth/auth_guard_resolver.js +56 -0
  77. package/dist/auth/bootstrap_account.d.ts +7 -7
  78. package/dist/auth/bootstrap_account.d.ts.map +1 -1
  79. package/dist/auth/bootstrap_account.js +7 -7
  80. package/dist/auth/bootstrap_routes.d.ts.map +1 -1
  81. package/dist/auth/bootstrap_routes.js +11 -10
  82. package/dist/auth/cleanup.d.ts +20 -26
  83. package/dist/auth/cleanup.d.ts.map +1 -1
  84. package/dist/auth/cleanup.js +33 -47
  85. package/dist/auth/credential_type_schema.d.ts +115 -0
  86. package/dist/auth/credential_type_schema.d.ts.map +1 -0
  87. package/dist/auth/credential_type_schema.js +127 -0
  88. package/dist/auth/daemon_token_middleware.d.ts +1 -1
  89. package/dist/auth/daemon_token_middleware.js +3 -3
  90. package/dist/auth/ddl.d.ts +2 -2
  91. package/dist/auth/ddl.d.ts.map +1 -1
  92. package/dist/auth/ddl.js +6 -6
  93. package/dist/auth/deps.d.ts +7 -32
  94. package/dist/auth/deps.d.ts.map +1 -1
  95. package/dist/auth/grant_path_schema.d.ts +117 -0
  96. package/dist/auth/grant_path_schema.d.ts.map +1 -0
  97. package/dist/auth/grant_path_schema.js +137 -0
  98. package/dist/auth/invite_queries.d.ts +12 -1
  99. package/dist/auth/invite_queries.d.ts.map +1 -1
  100. package/dist/auth/invite_queries.js +12 -1
  101. package/dist/auth/invite_schema.d.ts +1 -1
  102. package/dist/auth/invite_schema.d.ts.map +1 -1
  103. package/dist/auth/invite_schema.js +1 -1
  104. package/dist/auth/middleware.d.ts.map +1 -1
  105. package/dist/auth/middleware.js +5 -2
  106. package/dist/auth/migrations.d.ts +22 -7
  107. package/dist/auth/migrations.d.ts.map +1 -1
  108. package/dist/auth/migrations.js +64 -25
  109. package/dist/auth/request_context.d.ts +157 -170
  110. package/dist/auth/request_context.d.ts.map +1 -1
  111. package/dist/auth/request_context.js +224 -268
  112. package/dist/auth/{permit_offer_action_specs.d.ts → role_grant_offer_action_specs.d.ts} +130 -100
  113. package/dist/auth/role_grant_offer_action_specs.d.ts.map +1 -0
  114. package/dist/auth/role_grant_offer_action_specs.js +262 -0
  115. package/dist/auth/role_grant_offer_actions.d.ts +104 -0
  116. package/dist/auth/role_grant_offer_actions.d.ts.map +1 -0
  117. package/dist/auth/{permit_offer_actions.js → role_grant_offer_actions.js} +153 -140
  118. package/dist/auth/{permit_offer_notifications.d.ts → role_grant_offer_notifications.d.ts} +80 -70
  119. package/dist/auth/role_grant_offer_notifications.d.ts.map +1 -0
  120. package/dist/auth/role_grant_offer_notifications.js +182 -0
  121. package/dist/auth/{permit_offer_queries.d.ts → role_grant_offer_queries.d.ts} +64 -64
  122. package/dist/auth/role_grant_offer_queries.d.ts.map +1 -0
  123. package/dist/auth/{permit_offer_queries.js → role_grant_offer_queries.js} +136 -123
  124. package/dist/auth/role_grant_offer_schema.d.ts +150 -0
  125. package/dist/auth/role_grant_offer_schema.d.ts.map +1 -0
  126. package/dist/auth/{permit_offer_schema.js → role_grant_offer_schema.js} +55 -36
  127. package/dist/auth/role_grant_queries.d.ts +231 -0
  128. package/dist/auth/role_grant_queries.d.ts.map +1 -0
  129. package/dist/auth/role_grant_queries.js +320 -0
  130. package/dist/auth/role_schema.d.ts +150 -40
  131. package/dist/auth/role_schema.d.ts.map +1 -1
  132. package/dist/auth/role_schema.js +144 -45
  133. package/dist/auth/scope_kind_schema.d.ts +96 -0
  134. package/dist/auth/scope_kind_schema.d.ts.map +1 -0
  135. package/dist/auth/scope_kind_schema.js +94 -0
  136. package/dist/auth/self_service_role_action_specs.d.ts +4 -1
  137. package/dist/auth/self_service_role_action_specs.d.ts.map +1 -1
  138. package/dist/auth/self_service_role_action_specs.js +2 -2
  139. package/dist/auth/self_service_role_actions.d.ts +35 -29
  140. package/dist/auth/self_service_role_actions.d.ts.map +1 -1
  141. package/dist/auth/self_service_role_actions.js +58 -48
  142. package/dist/auth/session_cookie.d.ts +43 -6
  143. package/dist/auth/session_cookie.d.ts.map +1 -1
  144. package/dist/auth/session_cookie.js +31 -5
  145. package/dist/auth/session_middleware.d.ts +37 -3
  146. package/dist/auth/session_middleware.d.ts.map +1 -1
  147. package/dist/auth/session_middleware.js +33 -7
  148. package/dist/auth/signup_routes.d.ts.map +1 -1
  149. package/dist/auth/signup_routes.js +48 -19
  150. package/dist/auth/standard_action_specs.d.ts +2 -2
  151. package/dist/auth/standard_action_specs.js +4 -4
  152. package/dist/auth/standard_rpc_actions.d.ts +23 -19
  153. package/dist/auth/standard_rpc_actions.d.ts.map +1 -1
  154. package/dist/auth/standard_rpc_actions.js +12 -12
  155. package/dist/db/migrate.d.ts +1 -1
  156. package/dist/db/migrate.js +1 -1
  157. package/dist/dev/setup.d.ts +2 -2
  158. package/dist/dev/setup.d.ts.map +1 -1
  159. package/dist/dev/setup.js +4 -4
  160. package/dist/env/load.d.ts +1 -1
  161. package/dist/env/load.js +1 -1
  162. package/dist/hono_context.d.ts +27 -45
  163. package/dist/hono_context.d.ts.map +1 -1
  164. package/dist/hono_context.js +14 -28
  165. package/dist/http/CLAUDE.md +235 -121
  166. package/dist/http/auth_shape.d.ts +191 -0
  167. package/dist/http/auth_shape.d.ts.map +1 -0
  168. package/dist/http/auth_shape.js +237 -0
  169. package/dist/http/common_routes.js +3 -3
  170. package/dist/http/db_routes.d.ts +4 -0
  171. package/dist/http/db_routes.d.ts.map +1 -1
  172. package/dist/http/db_routes.js +44 -7
  173. package/dist/http/error_schemas.d.ts +56 -34
  174. package/dist/http/error_schemas.d.ts.map +1 -1
  175. package/dist/http/error_schemas.js +63 -28
  176. package/dist/http/pending_effects.d.ts +71 -18
  177. package/dist/http/pending_effects.d.ts.map +1 -1
  178. package/dist/http/pending_effects.js +87 -18
  179. package/dist/http/proxy.d.ts +52 -5
  180. package/dist/http/proxy.d.ts.map +1 -1
  181. package/dist/http/proxy.js +92 -14
  182. package/dist/http/route_spec.d.ts +89 -75
  183. package/dist/http/route_spec.d.ts.map +1 -1
  184. package/dist/http/route_spec.js +54 -72
  185. package/dist/http/schema_helpers.d.ts +3 -14
  186. package/dist/http/schema_helpers.d.ts.map +1 -1
  187. package/dist/http/schema_helpers.js +2 -14
  188. package/dist/http/surface.d.ts +2 -10
  189. package/dist/http/surface.d.ts.map +1 -1
  190. package/dist/http/surface.js +3 -4
  191. package/dist/http/surface_query.d.ts +39 -35
  192. package/dist/http/surface_query.d.ts.map +1 -1
  193. package/dist/http/surface_query.js +79 -36
  194. package/dist/primitive_schemas.d.ts +39 -0
  195. package/dist/primitive_schemas.d.ts.map +1 -0
  196. package/dist/primitive_schemas.js +40 -0
  197. package/dist/realtime/sse_auth_guard.d.ts +5 -5
  198. package/dist/realtime/sse_auth_guard.js +9 -9
  199. package/dist/runtime/mock.d.ts +1 -1
  200. package/dist/runtime/mock.js +1 -1
  201. package/dist/server/app_backend.d.ts +14 -11
  202. package/dist/server/app_backend.d.ts.map +1 -1
  203. package/dist/server/app_backend.js +12 -8
  204. package/dist/server/app_server.d.ts +7 -7
  205. package/dist/server/app_server.d.ts.map +1 -1
  206. package/dist/server/app_server.js +35 -40
  207. package/dist/server/validate_nginx.d.ts +1 -1
  208. package/dist/server/validate_nginx.js +1 -1
  209. package/dist/testing/CLAUDE.md +50 -38
  210. package/dist/testing/admin_integration.d.ts +5 -6
  211. package/dist/testing/admin_integration.d.ts.map +1 -1
  212. package/dist/testing/admin_integration.js +87 -85
  213. package/dist/testing/app_server.d.ts +11 -14
  214. package/dist/testing/app_server.d.ts.map +1 -1
  215. package/dist/testing/app_server.js +16 -15
  216. package/dist/testing/assertions.d.ts.map +1 -1
  217. package/dist/testing/assertions.js +2 -1
  218. package/dist/testing/attack_surface.d.ts.map +1 -1
  219. package/dist/testing/attack_surface.js +15 -9
  220. package/dist/testing/audit_completeness.d.ts +2 -2
  221. package/dist/testing/audit_completeness.d.ts.map +1 -1
  222. package/dist/testing/audit_completeness.js +36 -36
  223. package/dist/testing/auth_apps.d.ts +5 -4
  224. package/dist/testing/auth_apps.d.ts.map +1 -1
  225. package/dist/testing/auth_apps.js +22 -19
  226. package/dist/testing/data_exposure.d.ts.map +1 -1
  227. package/dist/testing/data_exposure.js +5 -5
  228. package/dist/testing/db.d.ts +1 -1
  229. package/dist/testing/db.d.ts.map +1 -1
  230. package/dist/testing/db.js +4 -4
  231. package/dist/testing/db_entities.d.ts +22 -0
  232. package/dist/testing/db_entities.d.ts.map +1 -0
  233. package/dist/testing/db_entities.js +28 -0
  234. package/dist/testing/entities.d.ts +8 -7
  235. package/dist/testing/entities.d.ts.map +1 -1
  236. package/dist/testing/entities.js +21 -18
  237. package/dist/testing/integration.d.ts.map +1 -1
  238. package/dist/testing/integration.js +13 -14
  239. package/dist/testing/integration_helpers.d.ts +4 -4
  240. package/dist/testing/integration_helpers.d.ts.map +1 -1
  241. package/dist/testing/integration_helpers.js +20 -18
  242. package/dist/testing/middleware.d.ts +4 -4
  243. package/dist/testing/middleware.d.ts.map +1 -1
  244. package/dist/testing/middleware.js +12 -11
  245. package/dist/testing/rpc_attack_surface.d.ts.map +1 -1
  246. package/dist/testing/rpc_attack_surface.js +40 -24
  247. package/dist/testing/rpc_round_trip.d.ts +1 -1
  248. package/dist/testing/rpc_round_trip.d.ts.map +1 -1
  249. package/dist/testing/rpc_round_trip.js +14 -13
  250. package/dist/testing/sse_round_trip.d.ts +3 -4
  251. package/dist/testing/sse_round_trip.d.ts.map +1 -1
  252. package/dist/testing/sse_round_trip.js +7 -11
  253. package/dist/testing/standard.d.ts +1 -1
  254. package/dist/testing/stubs.d.ts +25 -0
  255. package/dist/testing/stubs.d.ts.map +1 -1
  256. package/dist/testing/stubs.js +43 -2
  257. package/dist/testing/surface_invariants.d.ts +2 -2
  258. package/dist/testing/ws_round_trip.d.ts +12 -13
  259. package/dist/testing/ws_round_trip.d.ts.map +1 -1
  260. package/dist/testing/ws_round_trip.js +19 -11
  261. package/dist/ui/AdminAccounts.svelte +23 -20
  262. package/dist/ui/AdminOverview.svelte +15 -13
  263. package/dist/ui/AdminOverview.svelte.d.ts.map +1 -1
  264. package/dist/ui/{AdminPermitHistory.svelte → AdminRoleGrantHistory.svelte} +12 -12
  265. package/dist/ui/AdminRoleGrantHistory.svelte.d.ts +4 -0
  266. package/dist/ui/AdminRoleGrantHistory.svelte.d.ts.map +1 -0
  267. package/dist/ui/BootstrapForm.svelte +1 -1
  268. package/dist/ui/CLAUDE.md +60 -60
  269. package/dist/ui/{PermitOfferForm.svelte → RoleGrantOfferForm.svelte} +27 -26
  270. package/dist/ui/{PermitOfferForm.svelte.d.ts → RoleGrantOfferForm.svelte.d.ts} +7 -7
  271. package/dist/ui/RoleGrantOfferForm.svelte.d.ts.map +1 -0
  272. package/dist/ui/{PermitOfferHistory.svelte → RoleGrantOfferHistory.svelte} +12 -12
  273. package/dist/ui/{PermitOfferHistory.svelte.d.ts → RoleGrantOfferHistory.svelte.d.ts} +4 -4
  274. package/dist/ui/RoleGrantOfferHistory.svelte.d.ts.map +1 -0
  275. package/dist/ui/{PermitOfferInbox.svelte → RoleGrantOfferInbox.svelte} +14 -14
  276. package/dist/ui/{PermitOfferInbox.svelte.d.ts → RoleGrantOfferInbox.svelte.d.ts} +4 -4
  277. package/dist/ui/RoleGrantOfferInbox.svelte.d.ts.map +1 -0
  278. package/dist/ui/SignupForm.svelte +1 -1
  279. package/dist/ui/SurfaceExplorer.svelte +35 -15
  280. package/dist/ui/SurfaceExplorer.svelte.d.ts.map +1 -1
  281. package/dist/ui/account_sessions_state.svelte.d.ts +2 -3
  282. package/dist/ui/account_sessions_state.svelte.d.ts.map +1 -1
  283. package/dist/ui/account_sessions_state.svelte.js +2 -3
  284. package/dist/ui/admin_accounts_state.svelte.d.ts +18 -18
  285. package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
  286. package/dist/ui/admin_accounts_state.svelte.js +16 -16
  287. package/dist/ui/admin_rpc_adapters.d.ts +20 -20
  288. package/dist/ui/admin_rpc_adapters.d.ts.map +1 -1
  289. package/dist/ui/admin_rpc_adapters.js +17 -17
  290. package/dist/ui/admin_sessions_state.svelte.d.ts +2 -2
  291. package/dist/ui/admin_sessions_state.svelte.js +2 -2
  292. package/dist/ui/audit_log_state.svelte.d.ts +7 -7
  293. package/dist/ui/audit_log_state.svelte.d.ts.map +1 -1
  294. package/dist/ui/audit_log_state.svelte.js +6 -6
  295. package/dist/ui/auth_state.svelte.d.ts +3 -3
  296. package/dist/ui/auth_state.svelte.d.ts.map +1 -1
  297. package/dist/ui/auth_state.svelte.js +6 -6
  298. package/dist/ui/format_scope.d.ts +2 -2
  299. package/dist/ui/format_scope.js +2 -2
  300. package/dist/ui/{permit_offers_state.svelte.d.ts → role_grant_offers_state.svelte.d.ts} +30 -30
  301. package/dist/ui/role_grant_offers_state.svelte.d.ts.map +1 -0
  302. package/dist/ui/{permit_offers_state.svelte.js → role_grant_offers_state.svelte.js} +18 -18
  303. package/dist/ui/ui_format.js +2 -2
  304. package/package.json +3 -3
  305. package/dist/auth/permit_offer_action_specs.d.ts.map +0 -1
  306. package/dist/auth/permit_offer_action_specs.js +0 -258
  307. package/dist/auth/permit_offer_actions.d.ts +0 -110
  308. package/dist/auth/permit_offer_actions.d.ts.map +0 -1
  309. package/dist/auth/permit_offer_notifications.d.ts.map +0 -1
  310. package/dist/auth/permit_offer_notifications.js +0 -182
  311. package/dist/auth/permit_offer_queries.d.ts.map +0 -1
  312. package/dist/auth/permit_offer_schema.d.ts +0 -125
  313. package/dist/auth/permit_offer_schema.d.ts.map +0 -1
  314. package/dist/auth/permit_queries.d.ts +0 -222
  315. package/dist/auth/permit_queries.d.ts.map +0 -1
  316. package/dist/auth/permit_queries.js +0 -305
  317. package/dist/auth/require_keeper.d.ts +0 -20
  318. package/dist/auth/require_keeper.d.ts.map +0 -1
  319. package/dist/auth/require_keeper.js +0 -35
  320. package/dist/auth/route_guards.d.ts +0 -27
  321. package/dist/auth/route_guards.d.ts.map +0 -1
  322. package/dist/auth/route_guards.js +0 -38
  323. package/dist/auth/session_lifecycle.d.ts +0 -37
  324. package/dist/auth/session_lifecycle.d.ts.map +0 -1
  325. package/dist/auth/session_lifecycle.js +0 -29
  326. package/dist/ui/AdminPermitHistory.svelte.d.ts +0 -4
  327. package/dist/ui/AdminPermitHistory.svelte.d.ts.map +0 -1
  328. package/dist/ui/PermitOfferForm.svelte.d.ts.map +0 -1
  329. package/dist/ui/PermitOfferHistory.svelte.d.ts.map +0 -1
  330. package/dist/ui/PermitOfferInbox.svelte.d.ts.map +0 -1
  331. package/dist/ui/permit_offers_state.svelte.d.ts.map +0 -1
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Reusable validator-schema primitives — `Username`, `UsernameProvided`,
3
+ * `Email`. Lives at the top level (not inside `auth/` or `http/`) because
4
+ * these shapes don't depend on or imply any domain — accounts hold a
5
+ * username and email, but invites, password resets, future cell-sharing,
6
+ * and other surfaces all reach for the same primitives without going
7
+ * through auth.
8
+ *
9
+ * Split out from `auth/account_schema.ts` so the auth module shrinks to
10
+ * entity types + client-safe JSON shapes (its real responsibility) and
11
+ * non-auth consumers can import these primitives without dragging the
12
+ * auth domain along. Future cross-domain primitives (phone, url, slug)
13
+ * land here too.
14
+ *
15
+ * @module
16
+ */
17
+ import { z } from 'zod';
18
+ /** Minimum username length (must have start + middle + end characters). */
19
+ export declare const USERNAME_LENGTH_MIN = 3;
20
+ /** Maximum username length (matches GitHub's limit). */
21
+ export declare const USERNAME_LENGTH_MAX = 39;
22
+ /** Maximum length for username input on login/lookup — more permissive than `USERNAME_LENGTH_MAX` for forward-compatibility if the creation limit is raised. */
23
+ export declare const USERNAME_PROVIDED_LENGTH_MAX = 255;
24
+ /** Username for account creation — starts with letter, alphanumeric/dash/underscore middle, ends with alphanumeric. No @ or . allowed. */
25
+ export declare const Username: z.ZodString;
26
+ export type Username = z.infer<typeof Username>;
27
+ /** Username submitted for login or lookup — minimal validation for forward-compatibility if format rules change. */
28
+ export declare const UsernameProvided: z.ZodString;
29
+ export type UsernameProvided = z.infer<typeof UsernameProvided>;
30
+ /**
31
+ * Email validation. Lives here rather than `@fuzdev/fuz_util` because every
32
+ * current consumer pairs it with `Username` (signup, invites, audit log) —
33
+ * keeping the two together avoids a cross-package import for the
34
+ * identity-primitive bundle. Promote to fuz_util if a non-identity consumer
35
+ * surfaces.
36
+ */
37
+ export declare const Email: z.ZodEmail;
38
+ export type Email = z.infer<typeof Email>;
39
+ //# sourceMappingURL=primitive_schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitive_schemas.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/primitive_schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAItB,2EAA2E;AAC3E,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,wDAAwD;AACxD,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,gKAAgK;AAChK,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAEhD,0IAA0I;AAC1I,eAAO,MAAM,QAAQ,aAIyB,CAAC;AAC/C,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAEhD,oHAAoH;AACpH,eAAO,MAAM,gBAAgB,aAAsD,CAAC;AACpF,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE;;;;;;GAMG;AACH,eAAO,MAAM,KAAK,YAAY,CAAC;AAC/B,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Reusable validator-schema primitives — `Username`, `UsernameProvided`,
3
+ * `Email`. Lives at the top level (not inside `auth/` or `http/`) because
4
+ * these shapes don't depend on or imply any domain — accounts hold a
5
+ * username and email, but invites, password resets, future cell-sharing,
6
+ * and other surfaces all reach for the same primitives without going
7
+ * through auth.
8
+ *
9
+ * Split out from `auth/account_schema.ts` so the auth module shrinks to
10
+ * entity types + client-safe JSON shapes (its real responsibility) and
11
+ * non-auth consumers can import these primitives without dragging the
12
+ * auth domain along. Future cross-domain primitives (phone, url, slug)
13
+ * land here too.
14
+ *
15
+ * @module
16
+ */
17
+ import { z } from 'zod';
18
+ // TODO consider `.brand()` on Username and Email for compile-time safety
19
+ /** Minimum username length (must have start + middle + end characters). */
20
+ export const USERNAME_LENGTH_MIN = 3;
21
+ /** Maximum username length (matches GitHub's limit). */
22
+ export const USERNAME_LENGTH_MAX = 39;
23
+ /** Maximum length for username input on login/lookup — more permissive than `USERNAME_LENGTH_MAX` for forward-compatibility if the creation limit is raised. */
24
+ export const USERNAME_PROVIDED_LENGTH_MAX = 255;
25
+ /** Username for account creation — starts with letter, alphanumeric/dash/underscore middle, ends with alphanumeric. No @ or . allowed. */
26
+ export const Username = z
27
+ .string()
28
+ .min(USERNAME_LENGTH_MIN)
29
+ .max(USERNAME_LENGTH_MAX)
30
+ .regex(/^[a-zA-Z][0-9a-zA-Z_-]*[0-9a-zA-Z]$/);
31
+ /** Username submitted for login or lookup — minimal validation for forward-compatibility if format rules change. */
32
+ export const UsernameProvided = z.string().min(1).max(USERNAME_PROVIDED_LENGTH_MAX);
33
+ /**
34
+ * Email validation. Lives here rather than `@fuzdev/fuz_util` because every
35
+ * current consumer pairs it with `Username` (signup, invites, audit log) —
36
+ * keeping the two together avoids a cross-package import for the
37
+ * identity-primitive bundle. Promote to fuz_util if a non-identity consumer
38
+ * surfaces.
39
+ */
40
+ export const Email = z.email();
@@ -19,9 +19,9 @@ export declare const AUDIT_LOG_CHANNEL = "audit_log";
19
19
  /**
20
20
  * Audit event types that trigger SSE stream disconnection.
21
21
  *
22
- * `permit_revoke` requires the revoked role to match the guard's `required_role`
22
+ * `role_grant_revoke` requires the revoked role to match the guard's `required_role`
23
23
  * (or is skipped entirely when `required_role` is `null` — useful for streams
24
- * not gated by any specific permit).
24
+ * not gated by any specific role_grant).
25
25
  * `session_revoke_all` and `password_change` close every stream for the target account.
26
26
  * `session_revoke` closes only the stream tied to the specific revoked session
27
27
  * (matched by the blake3 session hash in `event.metadata.session_id`) — closing
@@ -32,7 +32,7 @@ export declare const DISCONNECT_EVENT_TYPES: ReadonlySet<string>;
32
32
  * Create an audit event handler that closes SSE streams on auth changes.
33
33
  *
34
34
  * Closes streams when:
35
- * - `permit_revoke` fires for the `required_role` targeting a connected subscriber
35
+ * - `role_grant_revoke` fires for the `required_role` targeting a connected subscriber
36
36
  * - `session_revoke_all` targets a connected subscriber (consistent invalidation)
37
37
  * - `password_change` targets a connected subscriber (sessions revoked implicitly)
38
38
  *
@@ -41,8 +41,8 @@ export declare const DISCONNECT_EVENT_TYPES: ReadonlySet<string>;
41
41
  *
42
42
  * @param registry - the subscriber registry to guard
43
43
  * @param required_role - the role that grants access to the SSE endpoint,
44
- * or `null` to skip `permit_revoke` handling entirely (for streams not gated
45
- * by a specific permit)
44
+ * or `null` to skip `role_grant_revoke` handling entirely (for streams not gated
45
+ * by a specific role_grant)
46
46
  * @param log - logger for disconnect events
47
47
  * @returns an `on_audit_event` callback
48
48
  */
@@ -17,16 +17,16 @@ export const AUDIT_LOG_CHANNEL = 'audit_log';
17
17
  /**
18
18
  * Audit event types that trigger SSE stream disconnection.
19
19
  *
20
- * `permit_revoke` requires the revoked role to match the guard's `required_role`
20
+ * `role_grant_revoke` requires the revoked role to match the guard's `required_role`
21
21
  * (or is skipped entirely when `required_role` is `null` — useful for streams
22
- * not gated by any specific permit).
22
+ * not gated by any specific role_grant).
23
23
  * `session_revoke_all` and `password_change` close every stream for the target account.
24
24
  * `session_revoke` closes only the stream tied to the specific revoked session
25
25
  * (matched by the blake3 session hash in `event.metadata.session_id`) — closing
26
26
  * all of a user's streams for a single-session revoke would be over-aggressive.
27
27
  */
28
28
  export const DISCONNECT_EVENT_TYPES = new Set([
29
- 'permit_revoke', // role revoked — user lost access
29
+ 'role_grant_revoke', // role revoked — user lost access
30
30
  'session_revoke', // single session revoked — close only that stream
31
31
  'session_revoke_all', // all sessions invalidated — user should be kicked
32
32
  'password_change', // password changed — all sessions revoked implicitly
@@ -35,7 +35,7 @@ export const DISCONNECT_EVENT_TYPES = new Set([
35
35
  * Create an audit event handler that closes SSE streams on auth changes.
36
36
  *
37
37
  * Closes streams when:
38
- * - `permit_revoke` fires for the `required_role` targeting a connected subscriber
38
+ * - `role_grant_revoke` fires for the `required_role` targeting a connected subscriber
39
39
  * - `session_revoke_all` targets a connected subscriber (consistent invalidation)
40
40
  * - `password_change` targets a connected subscriber (sessions revoked implicitly)
41
41
  *
@@ -44,8 +44,8 @@ export const DISCONNECT_EVENT_TYPES = new Set([
44
44
  *
45
45
  * @param registry - the subscriber registry to guard
46
46
  * @param required_role - the role that grants access to the SSE endpoint,
47
- * or `null` to skip `permit_revoke` handling entirely (for streams not gated
48
- * by a specific permit)
47
+ * or `null` to skip `role_grant_revoke` handling entirely (for streams not gated
48
+ * by a specific role_grant)
49
49
  * @param log - logger for disconnect events
50
50
  * @returns an `on_audit_event` callback
51
51
  */
@@ -73,9 +73,9 @@ export const create_sse_auth_guard = (registry, required_role, log) => {
73
73
  }
74
74
  return;
75
75
  }
76
- // permit_revoke requires matching the specific role. `null` means the
77
- // stream isn't gated by a specific permit, so permit_revoke is a no-op.
78
- if (event.event_type === 'permit_revoke') {
76
+ // role_grant_revoke requires matching the specific role. `null` means the
77
+ // stream isn't gated by a specific role_grant, so role_grant_revoke is a no-op.
78
+ if (event.event_type === 'role_grant_revoke') {
79
79
  if (required_role === null)
80
80
  return;
81
81
  if (event.metadata?.role !== required_role)
@@ -58,7 +58,7 @@ export interface MockRuntime extends RuntimeDeps {
58
58
  *
59
59
  * @example
60
60
  * ```ts
61
- * const runtime = create_mock_runtime(['apply', 'tx.ts']);
61
+ * const runtime = create_mock_runtime(['apply', 'zap.ts']);
62
62
  * runtime.mock_env.set('HOME', '/home/test');
63
63
  * runtime.mock_fs.set('/home/test/.app/config.json', '{}');
64
64
  *
@@ -18,7 +18,7 @@
18
18
  *
19
19
  * @example
20
20
  * ```ts
21
- * const runtime = create_mock_runtime(['apply', 'tx.ts']);
21
+ * const runtime = create_mock_runtime(['apply', 'zap.ts']);
22
22
  * runtime.mock_env.set('HOME', '/home/test');
23
23
  * runtime.mock_fs.set('/home/test/.app/config.json', '{}');
24
24
  *
@@ -55,17 +55,19 @@ export interface CreateAppBackendOptions {
55
55
  /** Structured logger instance. Omit for default (`new Logger('server')`). */
56
56
  log?: Logger;
57
57
  /**
58
- * Called after each audit log INSERT succeeds.
59
- * Use to broadcast audit events via SSE. Flows through `AppDeps`
60
- * to all route factories automatically. Defaults to a noop.
58
+ * Initial subscriber appended to `AppDeps.audit.on_event_chain`.
59
+ * Use to broadcast audit events via SSE / WS. Additional subscribers
60
+ * (e.g. the factory-managed audit-log SSE) are appended at server
61
+ * assembly via `audit.on_event_chain.push(listener)` — no shallow-copy
62
+ * of `AppDeps` required.
61
63
  */
62
64
  on_audit_event?: (event: AuditLogEvent) => void;
63
65
  /**
64
66
  * Audit-log config for consumer event-type extensions. Built once at
65
- * startup via `create_audit_log_config({extra_events})` and threaded
66
- * through `AppDeps.audit_log_config` to every fuz_app emit site so
67
- * consumer handlers cannot silently fall back to the builtin config.
68
- * Omit to use `BUILTIN_AUDIT_LOG_CONFIG` (no extra events).
67
+ * startup via `create_audit_log_config({extra_events})` and captured
68
+ * inside `AppDeps.audit` so consumer handlers cannot silently fall
69
+ * back to the builtin config. Omit to use `BUILTIN_AUDIT_LOG_CONFIG`
70
+ * (no extra events).
69
71
  */
70
72
  audit_log_config?: AuditLogConfig;
71
73
  /**
@@ -74,9 +76,10 @@ export interface CreateAppBackendOptions {
74
76
  * (`namespace`, `name`, `sequence`); order is append-only so forward-only
75
77
  * guarantees hold per-namespace.
76
78
  *
77
- * The reserved `'fuz_auth'` namespace is rejected at startup. Omit for no
78
- * extra namespaces. This is the only place to splice consumer migrations
79
- * — DB init belongs to the backend lifecycle, not server assembly.
79
+ * Names in `RESERVED_MIGRATION_NAMESPACES` (currently `['fuz_auth']`) are
80
+ * rejected at startup. Omit for no extra namespaces. This is the only
81
+ * place to splice consumer migrations — DB init belongs to the backend
82
+ * lifecycle, not server assembly.
80
83
  */
81
84
  migration_namespaces?: ReadonlyArray<MigrationNamespace>;
82
85
  }
@@ -89,7 +92,7 @@ export interface CreateAppBackendOptions {
89
92
  *
90
93
  * @param options - keyring, password deps, optional database URL, and optional `migration_namespaces`
91
94
  * @returns app backend with deps, database metadata, and combined migration results
92
- * @throws Error if `migration_namespaces` contains the reserved `'fuz_auth'` namespace
95
+ * @throws Error if `migration_namespaces` contains a namespace in `RESERVED_MIGRATION_NAMESPACES`
93
96
  */
94
97
  export declare const create_app_backend: (options: CreateAppBackendOptions) => Promise<AppBackend>;
95
98
  //# sourceMappingURL=app_backend.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"app_backend.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/app_backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAE/C,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAC,cAAc,EAAE,aAAa,EAAC,MAAM,6BAA6B,CAAC;AAC/E,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAiB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAI/F;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,oIAAoI;IACpI,QAAQ,CAAC,iBAAiB,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAC3D,iEAAiE;IACjE,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACvC,+DAA+D;IAC/D,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACnD,2BAA2B;IAC3B,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,qBAAqB;IACrB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAC;IACrB,wCAAwC;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,iFAAiF;IACjF,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,6EAA6E;IAC7E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAChD;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,cAAc,CAAC;IAClC;;;;;;;;;OASG;IACH,oBAAoB,CAAC,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC;CACzD;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,GAAU,SAAS,uBAAuB,KAAG,OAAO,CAAC,UAAU,CAoC7F,CAAC"}
1
+ {"version":3,"file":"app_backend.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/app_backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAE/C,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAC,cAAc,EAAE,aAAa,EAAC,MAAM,6BAA6B,CAAC;AAE/E,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAiB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAI/F;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,oIAAoI;IACpI,QAAQ,CAAC,iBAAiB,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAC3D,iEAAiE;IACjE,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACvC,+DAA+D;IAC/D,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACnD,2BAA2B;IAC3B,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,qBAAqB;IACrB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAC;IACrB,wCAAwC;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,iFAAiF;IACjF,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,6EAA6E;IAC7E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAChD;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,cAAc,CAAC;IAClC;;;;;;;;;;OAUG;IACH,oBAAoB,CAAC,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC;CACzD;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,GAAU,SAAS,uBAAuB,KAAG,OAAO,CAAC,UAAU,CAuC7F,CAAC"}
@@ -11,8 +11,9 @@
11
11
  * @module
12
12
  */
13
13
  import { Logger } from '@fuzdev/fuz_util/log.js';
14
+ import { create_audit_emitter } from '../auth/audit_emitter.js';
14
15
  import { run_migrations } from '../db/migrate.js';
15
- import { AUTH_MIGRATION_NS, AUTH_MIGRATION_NAMESPACE } from '../auth/migrations.js';
16
+ import { AUTH_MIGRATION_NS, RESERVED_MIGRATION_NAMESPACES } from '../auth/migrations.js';
16
17
  import { create_db } from '../db/create_db.js';
17
18
  /**
18
19
  * Initialize the backend: database + auth migrations + deps.
@@ -23,18 +24,16 @@ import { create_db } from '../db/create_db.js';
23
24
  *
24
25
  * @param options - keyring, password deps, optional database URL, and optional `migration_namespaces`
25
26
  * @returns app backend with deps, database metadata, and combined migration results
26
- * @throws Error if `migration_namespaces` contains the reserved `'fuz_auth'` namespace
27
+ * @throws Error if `migration_namespaces` contains a namespace in `RESERVED_MIGRATION_NAMESPACES`
27
28
  */
28
29
  export const create_app_backend = async (options) => {
29
30
  const { database_url, keyring, password, stat, read_text_file, delete_file } = options;
30
31
  const log = options.log ?? new Logger('server');
31
- const on_audit_event = options.on_audit_event ?? (() => { }); // eslint-disable-line @typescript-eslint/no-empty-function
32
- const { audit_log_config } = options;
33
32
  const { db, close, db_type, db_name } = await create_db(database_url);
34
33
  if (options.migration_namespaces?.length) {
35
34
  for (const ns of options.migration_namespaces) {
36
- if (ns.namespace === AUTH_MIGRATION_NAMESPACE) {
37
- throw new Error(`Migration namespace "${AUTH_MIGRATION_NAMESPACE}" is reserved by fuz_app — choose a different namespace`);
35
+ if (RESERVED_MIGRATION_NAMESPACES.includes(ns.namespace)) {
36
+ throw new Error(`Migration namespace "${ns.namespace}" is reserved by fuz_app — choose a different namespace`);
38
37
  }
39
38
  }
40
39
  }
@@ -42,6 +41,12 @@ export const create_app_backend = async (options) => {
42
41
  AUTH_MIGRATION_NS,
43
42
  ...(options.migration_namespaces ?? []),
44
43
  ]);
44
+ const audit = create_audit_emitter({
45
+ db,
46
+ log,
47
+ on_audit_event: options.on_audit_event,
48
+ audit_log_config: options.audit_log_config,
49
+ });
45
50
  return {
46
51
  db_type,
47
52
  db_name,
@@ -55,8 +60,7 @@ export const create_app_backend = async (options) => {
55
60
  read_text_file,
56
61
  delete_file,
57
62
  log,
58
- on_audit_event,
59
- audit_log_config,
63
+ audit,
60
64
  },
61
65
  };
62
66
  };
@@ -133,10 +133,11 @@ export interface AppServerOptions {
133
133
  /**
134
134
  * Enable factory-managed audit log SSE.
135
135
  *
136
- * When truthy, creates an `AuditLogSse` instance internally, wires `on_audit_event`
137
- * on the backend deps (composing with any existing callback), and auto-includes
138
- * `AUDIT_LOG_EVENT_SPECS` in the surface. The result is exposed on `AppServerContext`
139
- * (for route factories) and `AppServer` (for the caller).
136
+ * When truthy, creates an `AuditLogSse` instance internally, appends the SSE
137
+ * listener to `backend.deps.audit.on_event_chain` (composing with the
138
+ * consumer's `on_audit_event` callback rather than rebuilding `AppDeps`), and
139
+ * auto-includes `AUDIT_LOG_EVENT_SPECS` in the surface. The result is exposed
140
+ * on `AppServerContext` (for route factories) and `AppServer` (for the caller).
140
141
  *
141
142
  * Pass `true` for defaults (admin role), or `{role: 'custom'}` for a custom role.
142
143
  * Omit to wire audit SSE manually.
@@ -229,9 +230,8 @@ export declare const DEFAULT_MAX_BODY_SIZE: number;
229
230
  * static serving. Database migrations belong to the backend lifecycle —
230
231
  * pass `migration_namespaces` to `create_app_backend`.
231
232
  *
232
- * When `audit_log_sse` is set, shallow-copies `backend.deps` with a composed
233
- * `on_audit_event` that fans out to the SSE registry and the original
234
- * callback — `backend.deps` itself is not mutated.
233
+ * When `audit_log_sse` is set, the SSE registry's listener is appended to
234
+ * `backend.deps.audit.on_event_chain` no shallow-copy of `AppDeps`.
235
235
  *
236
236
  * @returns assembled Hono app, backend, surface build, and bootstrap status
237
237
  */
@@ -1 +1 @@
1
- {"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/app_server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/app_server.ts"],"names":[],"mappings":"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"}
@@ -25,9 +25,10 @@ import { create_app_surface_spec, } from '../http/surface.js';
25
25
  import { apply_middleware_specs, apply_route_specs, prefix_route_specs, } from '../http/route_spec.js';
26
26
  import { check_bootstrap_status, create_bootstrap_route_specs, } from '../auth/bootstrap_routes.js';
27
27
  import { create_surface_route_spec } from '../http/common_routes.js';
28
+ import { flush_pending_effects, flush_post_commit_effects } from '../http/pending_effects.js';
28
29
  import { create_auth_middleware_specs } from '../auth/middleware.js';
29
- import { fuz_auth_guard_resolver } from '../auth/route_guards.js';
30
- import { create_fuz_authorization_handler, input_schema_declares_acting, is_actor_implying_auth, } from '../auth/request_context.js';
30
+ import { fuz_auth_guard_resolver } from '../auth/auth_guard_resolver.js';
31
+ import { create_fuz_authorization_handler } from '../auth/request_context.js';
31
32
  import { ERROR_PAYLOAD_TOO_LARGE } from '../http/error_schemas.js';
32
33
  import { create_rpc_endpoint } from '../actions/action_rpc.js';
33
34
  /** Default maximum request body size: 1 MiB. */
@@ -40,15 +41,15 @@ export const DEFAULT_MAX_BODY_SIZE = 1024 * 1024;
40
41
  * static serving. Database migrations belong to the backend lifecycle —
41
42
  * pass `migration_namespaces` to `create_app_backend`.
42
43
  *
43
- * When `audit_log_sse` is set, shallow-copies `backend.deps` with a composed
44
- * `on_audit_event` that fans out to the SSE registry and the original
45
- * callback — `backend.deps` itself is not mutated.
44
+ * When `audit_log_sse` is set, the SSE registry's listener is appended to
45
+ * `backend.deps.audit.on_event_chain` no shallow-copy of `AppDeps`.
46
46
  *
47
47
  * @returns assembled Hono app, backend, surface build, and bootstrap status
48
48
  */
49
49
  export const create_app_server = async (options) => {
50
50
  const { backend } = options;
51
- const { log } = backend.deps;
51
+ const { deps } = backend;
52
+ const { log } = deps;
52
53
  // Rate limiter defaults (undefined = default, null = disable)
53
54
  const ip_rate_limiter = options.ip_rate_limiter === undefined ? create_rate_limiter() : options.ip_rate_limiter;
54
55
  const login_account_rate_limiter = options.login_account_rate_limiter === undefined
@@ -66,22 +67,18 @@ export const create_app_server = async (options) => {
66
67
  const action_account_rate_limiter = options.action_account_rate_limiter === undefined
67
68
  ? create_rate_limiter(DEFAULT_ACTION_ACCOUNT_RATE_LIMIT)
68
69
  : options.action_account_rate_limiter;
69
- // Factory-managed audit SSE (shallow copy deps, no mutation of backend.deps)
70
+ // Factory-managed audit SSE appends a listener to the bound emitter's
71
+ // chain so SSE fan-out runs alongside the consumer's `on_audit_event`
72
+ // without rebuilding `AppDeps`.
70
73
  const audit_sse = options.audit_log_sse
71
74
  ? create_audit_log_sse({
72
75
  log,
73
76
  role: typeof options.audit_log_sse === 'object' ? options.audit_log_sse.role : undefined,
74
77
  })
75
78
  : null;
76
- const deps = audit_sse
77
- ? {
78
- ...backend.deps,
79
- on_audit_event: (event) => {
80
- audit_sse.on_audit_event(event);
81
- backend.deps.on_audit_event(event);
82
- },
83
- }
84
- : backend.deps;
79
+ if (audit_sse) {
80
+ deps.audit.on_event_chain.push(audit_sse.on_audit_event);
81
+ }
85
82
  // Proxy middleware
86
83
  const proxy_spec = create_proxy_middleware_spec({ ...options.proxy, log });
87
84
  // Auth middleware
@@ -161,20 +158,12 @@ export const create_app_server = async (options) => {
161
158
  ...(options.event_specs ?? []),
162
159
  ...(audit_sse ? AUDIT_LOG_EVENT_SPECS : []),
163
160
  ];
164
- // Per-route flag for the dispatcher's authorization-phase error shapes.
165
- // Mirrors the runtime check in `apply_authorization_phase`: a route emits
166
- // actor-failure errors when its input declares `acting?: ActingActor` or
167
- // its auth requires permits. Routes that fail this check stay on the
168
- // narrow derived schema (validation + auth shapes) so non-fuz_app HTTP
169
- // frameworks aren't forced to surface fuz_app-specific error codes.
170
- const fuz_is_acting_aware = (spec) => is_actor_implying_auth(spec.auth) || input_schema_declares_acting(spec.input);
171
161
  const surface_spec = create_app_surface_spec({
172
162
  middleware_specs: surface_middleware,
173
163
  route_specs,
174
164
  env_schema: options.env_schema,
175
165
  event_specs: all_event_specs,
176
166
  rpc_endpoints: resolved_rpc_endpoints,
177
- is_acting_aware: fuz_is_acting_aware,
178
167
  });
179
168
  // Config-level diagnostics (concatenated after spec-level from generate_app_surface)
180
169
  const config_diagnostics = [];
@@ -224,31 +213,37 @@ export const create_app_server = async (options) => {
224
213
  log_startup_summary(surface_spec.surface, log, options.env_values);
225
214
  // Hono app assembly
226
215
  const app = new Hono();
227
- // Pending effects — collects fire-and-forget promises (audit logs, usage tracking).
228
- // In test mode, effects are awaited before the response returns.
229
- // In production, rejected effects are reported via on_effect_error.
216
+ // Two-queue side-effect flush. `pending_effects` collects eager
217
+ // fire-and-forget promises (audit emits, session touch, api-token
218
+ // usage). `post_commit_effects` collects deferred thunks pushed via
219
+ // `emit_after_commit` (WS notifications, anything that must observe a
220
+ // committed transaction). Both queues drain here, after the handler
221
+ // (and any wrapping `db.transaction`) returns. In test mode both are
222
+ // awaited before the response returns; in production, eager-queue
223
+ // rejections are reported via `on_effect_error`.
230
224
  app.use('*', async (c, next) => {
231
225
  c.set('pending_effects', []);
226
+ c.set('post_commit_effects', []);
232
227
  try {
233
228
  await next();
234
229
  }
235
230
  finally {
236
- const effects = c.var.pending_effects;
237
- if (effects.length) {
231
+ const eager = c.var.pending_effects;
232
+ const deferred = c.var.post_commit_effects;
233
+ if (eager.length || deferred.length) {
238
234
  if (options.await_pending_effects) {
239
- await Promise.allSettled(effects);
235
+ await flush_pending_effects(eager, log);
236
+ await flush_post_commit_effects(deferred, log);
240
237
  }
241
238
  else {
242
- const ctx = { method: c.req.method, path: c.req.path };
239
+ const error_ctx = { method: c.req.method, path: c.req.path };
243
240
  const callback = options.on_effect_error;
244
- void Promise.allSettled(effects).then((results) => {
245
- for (const result of results) {
246
- if (result.status === 'rejected') {
247
- log.error('Pending effect rejected:', result.reason, ctx);
248
- callback?.(result.reason, ctx);
249
- }
250
- }
251
- });
241
+ void flush_pending_effects(eager, log, callback ? (reason) => callback(reason, error_ctx) : undefined);
242
+ // `flush_post_commit_effects` is non-throwing: per-thunk
243
+ // errors are routed through `log.error` inside the helper,
244
+ // so production fire-and-forget skips the `on_effect_error`
245
+ // fan-out (deferred thunks are wrapped end-to-end already).
246
+ void flush_post_commit_effects(deferred, log);
252
247
  }
253
248
  }
254
249
  }
@@ -267,7 +262,7 @@ export const create_app_server = async (options) => {
267
262
  }
268
263
  apply_middleware_specs(app, middleware_specs);
269
264
  const authorize = create_fuz_authorization_handler({ db: deps.db });
270
- apply_route_specs(app, route_specs, fuz_auth_guard_resolver, log, deps.db, authorize, fuz_is_acting_aware);
265
+ apply_route_specs(app, route_specs, fuz_auth_guard_resolver, log, deps.db, authorize);
271
266
  // Post-route middleware (before static serving)
272
267
  if (options.post_route_middleware) {
273
268
  apply_middleware_specs(app, options.post_route_middleware);
@@ -24,7 +24,7 @@ export interface NginxValidationResult {
24
24
  *
25
25
  * Checks for required security headers, Authorization stripping in `/api`
26
26
  * blocks, and the nginx `add_header` inheritance gotcha. Designed for
27
- * fuz_app consumer deploy configs (tx.ts `NGINX_CONFIG` constants).
27
+ * fuz_app consumer deploy configs (zap.ts `NGINX_CONFIG` constants).
28
28
  *
29
29
  * Limitations: string pattern matching, not a real nginx parser. Catches
30
30
  * common omissions in fuz_app deploy configs but won't catch all possible
@@ -92,7 +92,7 @@ const location_matches_api = (block) => {
92
92
  *
93
93
  * Checks for required security headers, Authorization stripping in `/api`
94
94
  * blocks, and the nginx `add_header` inheritance gotcha. Designed for
95
- * fuz_app consumer deploy configs (tx.ts `NGINX_CONFIG` constants).
95
+ * fuz_app consumer deploy configs (zap.ts `NGINX_CONFIG` constants).
96
96
  *
97
97
  * Limitations: string pattern matching, not a real nginx parser. Catches
98
98
  * common omissions in fuz_app deploy configs but won't catch all possible