@fuzdev/fuz_app 0.147.0 → 0.149.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 (303) hide show
  1. package/dist/actions/CLAUDE.md +8 -6
  2. package/dist/actions/action_codegen.d.ts +15 -1
  3. package/dist/actions/action_codegen.d.ts.map +1 -1
  4. package/dist/actions/action_codegen.js +23 -2
  5. package/dist/actions/action_event.d.ts.map +1 -1
  6. package/dist/actions/action_event.js +14 -1
  7. package/dist/actions/perform_action.d.ts +17 -1
  8. package/dist/actions/perform_action.d.ts.map +1 -1
  9. package/dist/actions/perform_action.js +23 -3
  10. package/dist/auth/CLAUDE.md +3 -2
  11. package/dist/auth/account_action_specs.d.ts +12 -0
  12. package/dist/auth/account_action_specs.d.ts.map +1 -1
  13. package/dist/auth/account_action_specs.js +16 -2
  14. package/dist/auth/account_actions.d.ts.map +1 -1
  15. package/dist/auth/account_actions.js +7 -4
  16. package/dist/auth/admin_action_specs.d.ts.map +1 -1
  17. package/dist/auth/admin_action_specs.js +29 -8
  18. package/dist/auth/audit_emitter.d.ts +14 -0
  19. package/dist/auth/audit_emitter.d.ts.map +1 -1
  20. package/dist/auth/audit_emitter.js +5 -1
  21. package/dist/auth/cell_action_specs.d.ts +3 -1
  22. package/dist/auth/cell_action_specs.d.ts.map +1 -1
  23. package/dist/auth/cell_action_specs.js +5 -5
  24. package/dist/auth/cell_actions.d.ts.map +1 -1
  25. package/dist/auth/cell_actions.js +2 -3
  26. package/dist/auth/cell_data_schema.d.ts +1 -1
  27. package/dist/auth/cell_data_schema.js +1 -1
  28. package/dist/auth/cell_field_action_specs.d.ts +4 -3
  29. package/dist/auth/cell_field_action_specs.d.ts.map +1 -1
  30. package/dist/auth/cell_field_action_specs.js +5 -6
  31. package/dist/auth/cell_field_actions.d.ts.map +1 -1
  32. package/dist/auth/cell_field_actions.js +8 -1
  33. package/dist/auth/cell_item_action_specs.d.ts +4 -2
  34. package/dist/auth/cell_item_action_specs.d.ts.map +1 -1
  35. package/dist/auth/cell_item_action_specs.js +5 -5
  36. package/dist/auth/cell_item_actions.d.ts.map +1 -1
  37. package/dist/auth/cell_item_actions.js +8 -1
  38. package/dist/auth/role_grant_offer_action_specs.d.ts +2 -0
  39. package/dist/auth/role_grant_offer_action_specs.d.ts.map +1 -1
  40. package/dist/auth/role_grant_offer_action_specs.js +8 -4
  41. package/dist/http/CLAUDE.md +14 -2
  42. package/dist/http/error_schemas.d.ts +8 -0
  43. package/dist/http/error_schemas.d.ts.map +1 -1
  44. package/dist/http/error_schemas.js +12 -0
  45. package/dist/http/jsonrpc_errors.d.ts +40 -15
  46. package/dist/http/jsonrpc_errors.d.ts.map +1 -1
  47. package/dist/http/jsonrpc_errors.js +90 -35
  48. package/dist/primitive_schemas.d.ts +1 -1
  49. package/dist/primitive_schemas.d.ts.map +1 -1
  50. package/dist/primitive_schemas.js +2 -1
  51. package/dist/schema_meta.d.ts +80 -0
  52. package/dist/schema_meta.d.ts.map +1 -1
  53. package/dist/schema_meta.js +71 -1
  54. package/dist/testing/CLAUDE.md +853 -146
  55. package/dist/testing/admin_integration.d.ts.map +1 -1
  56. package/dist/testing/admin_integration.js +73 -5
  57. package/dist/testing/adversarial_input.d.ts +0 -47
  58. package/dist/testing/adversarial_input.d.ts.map +1 -1
  59. package/dist/testing/adversarial_input.js +4 -340
  60. package/dist/testing/adversarial_input_cases.d.ts +124 -0
  61. package/dist/testing/adversarial_input_cases.d.ts.map +1 -0
  62. package/dist/testing/adversarial_input_cases.js +393 -0
  63. package/dist/testing/audit_completeness.d.ts.map +1 -1
  64. package/dist/testing/audit_completeness.js +24 -20
  65. package/dist/testing/audit_drift_guard.d.ts +30 -3
  66. package/dist/testing/audit_drift_guard.d.ts.map +1 -1
  67. package/dist/testing/audit_drift_guard.js +55 -3
  68. package/dist/testing/cross_backend/account_lifecycle.d.ts.map +1 -1
  69. package/dist/testing/cross_backend/account_lifecycle.js +29 -12
  70. package/dist/testing/cross_backend/actor_lookup.d.ts.map +1 -1
  71. package/dist/testing/cross_backend/actor_lookup.js +7 -25
  72. package/dist/testing/cross_backend/app_settings.d.ts.map +1 -1
  73. package/dist/testing/cross_backend/app_settings.js +4 -6
  74. package/dist/testing/cross_backend/audit_cross_helpers.d.ts +57 -0
  75. package/dist/testing/cross_backend/audit_cross_helpers.d.ts.map +1 -0
  76. package/dist/testing/cross_backend/audit_cross_helpers.js +89 -0
  77. package/dist/testing/cross_backend/backend_config.d.ts +2 -1
  78. package/dist/testing/cross_backend/backend_config.d.ts.map +1 -1
  79. package/dist/testing/cross_backend/body_size.d.ts +6 -0
  80. package/dist/testing/cross_backend/body_size.d.ts.map +1 -1
  81. package/dist/testing/cross_backend/body_size.js +26 -44
  82. package/dist/testing/cross_backend/body_size_smuggling.d.ts +5 -0
  83. package/dist/testing/cross_backend/body_size_smuggling.d.ts.map +1 -1
  84. package/dist/testing/cross_backend/body_size_smuggling.js +7 -14
  85. package/dist/testing/cross_backend/build_test_backend_paths.d.ts +3 -1
  86. package/dist/testing/cross_backend/build_test_backend_paths.d.ts.map +1 -1
  87. package/dist/testing/cross_backend/capabilities.d.ts +78 -59
  88. package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
  89. package/dist/testing/cross_backend/capabilities.js +25 -24
  90. package/dist/testing/cross_backend/cargo_binary.d.ts +70 -0
  91. package/dist/testing/cross_backend/cargo_binary.d.ts.map +1 -0
  92. package/dist/testing/cross_backend/cargo_binary.js +148 -0
  93. package/dist/testing/cross_backend/cell_crud.d.ts.map +1 -1
  94. package/dist/testing/cross_backend/cell_crud.js +174 -3
  95. package/dist/testing/cross_backend/cell_gated_create.d.ts +0 -60
  96. package/dist/testing/cross_backend/cell_gated_create.d.ts.map +1 -1
  97. package/dist/testing/cross_backend/cell_gated_create.js +9 -487
  98. package/dist/testing/cross_backend/cell_grant_role.d.ts +14 -2
  99. package/dist/testing/cross_backend/cell_grant_role.d.ts.map +1 -1
  100. package/dist/testing/cross_backend/cell_grant_role.js +22 -12
  101. package/dist/testing/cross_backend/cell_moderate.d.ts +66 -0
  102. package/dist/testing/cross_backend/cell_moderate.d.ts.map +1 -0
  103. package/dist/testing/cross_backend/cell_moderate.js +511 -0
  104. package/dist/testing/cross_backend/cell_ref_admission.d.ts.map +1 -1
  105. package/dist/testing/cross_backend/cell_ref_admission.js +1 -1
  106. package/dist/testing/cross_backend/cell_relations.d.ts.map +1 -1
  107. package/dist/testing/cross_backend/cell_relations.js +40 -19
  108. package/dist/testing/cross_backend/conformance_case.d.ts +43 -4
  109. package/dist/testing/cross_backend/conformance_case.d.ts.map +1 -1
  110. package/dist/testing/cross_backend/conformance_case.js +29 -1
  111. package/dist/testing/cross_backend/conformance_rpc_auth.d.ts +93 -0
  112. package/dist/testing/cross_backend/conformance_rpc_auth.d.ts.map +1 -0
  113. package/dist/testing/cross_backend/conformance_rpc_auth.js +125 -0
  114. package/dist/testing/cross_backend/conformance_table.d.ts +144 -4
  115. package/dist/testing/cross_backend/conformance_table.d.ts.map +1 -1
  116. package/dist/testing/cross_backend/conformance_table.js +297 -65
  117. package/dist/testing/cross_backend/cookie_attributes.d.ts.map +1 -1
  118. package/dist/testing/cross_backend/cookie_attributes.js +3 -2
  119. package/dist/testing/cross_backend/create_cross_backend_global_setup.d.ts +38 -5
  120. package/dist/testing/cross_backend/create_cross_backend_global_setup.d.ts.map +1 -1
  121. package/dist/testing/cross_backend/create_cross_backend_global_setup.js +24 -3
  122. package/dist/testing/cross_backend/create_dual_spawn_global_setup.d.ts +5 -5
  123. package/dist/testing/cross_backend/create_dual_spawn_global_setup.d.ts.map +1 -1
  124. package/dist/testing/cross_backend/credential_deadline.d.ts +10 -6
  125. package/dist/testing/cross_backend/credential_deadline.d.ts.map +1 -1
  126. package/dist/testing/cross_backend/credential_deadline.js +32 -31
  127. package/dist/testing/cross_backend/credential_header_robustness.d.ts.map +1 -1
  128. package/dist/testing/cross_backend/credential_header_robustness.js +4 -6
  129. package/dist/testing/cross_backend/{cell_cross_helpers.d.ts → cross_rpc.d.ts} +14 -2
  130. package/dist/testing/cross_backend/cross_rpc.d.ts.map +1 -0
  131. package/dist/testing/cross_backend/{cell_cross_helpers.js → cross_rpc.js} +31 -7
  132. package/dist/testing/cross_backend/default_backend_configs.d.ts +58 -61
  133. package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
  134. package/dist/testing/cross_backend/default_backend_configs.js +97 -91
  135. package/dist/testing/cross_backend/default_spine_surface.d.ts.map +1 -1
  136. package/dist/testing/cross_backend/default_spine_surface.js +2 -2
  137. package/dist/testing/cross_backend/differential.d.ts +126 -0
  138. package/dist/testing/cross_backend/differential.d.ts.map +1 -0
  139. package/dist/testing/cross_backend/differential.js +201 -0
  140. package/dist/testing/cross_backend/differential_normalize.d.ts +150 -0
  141. package/dist/testing/cross_backend/differential_normalize.d.ts.map +1 -0
  142. package/dist/testing/cross_backend/differential_normalize.js +153 -0
  143. package/dist/testing/cross_backend/fact_serving.d.ts.map +1 -1
  144. package/dist/testing/cross_backend/fact_serving.js +27 -17
  145. package/dist/testing/cross_backend/full_spine_mount.d.ts +15 -0
  146. package/dist/testing/cross_backend/full_spine_mount.d.ts.map +1 -1
  147. package/dist/testing/cross_backend/full_spine_mount.js +55 -1
  148. package/dist/testing/cross_backend/identity_parity.d.ts.map +1 -1
  149. package/dist/testing/cross_backend/identity_parity.js +6 -5
  150. package/dist/testing/cross_backend/in_process_setup.d.ts +12 -2
  151. package/dist/testing/cross_backend/in_process_setup.d.ts.map +1 -1
  152. package/dist/testing/cross_backend/in_process_setup.js +10 -7
  153. package/dist/testing/cross_backend/login_security.d.ts.map +1 -1
  154. package/dist/testing/cross_backend/login_security.js +13 -18
  155. package/dist/testing/cross_backend/origin.js +1 -1
  156. package/dist/testing/cross_backend/origin_conformance.js +1 -1
  157. package/dist/testing/cross_backend/origin_scope.d.ts +6 -0
  158. package/dist/testing/cross_backend/origin_scope.d.ts.map +1 -1
  159. package/dist/testing/cross_backend/origin_scope.js +13 -12
  160. package/dist/testing/cross_backend/peer_ping_ws.d.ts +2 -5
  161. package/dist/testing/cross_backend/peer_ping_ws.d.ts.map +1 -1
  162. package/dist/testing/cross_backend/peer_ping_ws.js +14 -24
  163. package/dist/testing/cross_backend/postgres_database.d.ts +85 -0
  164. package/dist/testing/cross_backend/postgres_database.d.ts.map +1 -0
  165. package/dist/testing/cross_backend/postgres_database.js +140 -0
  166. package/dist/testing/cross_backend/provided_context.d.ts +28 -0
  167. package/dist/testing/cross_backend/provided_context.d.ts.map +1 -0
  168. package/dist/testing/cross_backend/provided_context.js +35 -0
  169. package/dist/testing/cross_backend/query_shape.d.ts.map +1 -1
  170. package/dist/testing/cross_backend/query_shape.js +10 -12
  171. package/dist/testing/cross_backend/ready.js +2 -2
  172. package/dist/testing/cross_backend/revocation_drivers.d.ts +4 -3
  173. package/dist/testing/cross_backend/revocation_drivers.d.ts.map +1 -1
  174. package/dist/testing/cross_backend/revocation_drivers.js +1 -1
  175. package/dist/testing/cross_backend/role_grant_cross_helpers.d.ts +3 -2
  176. package/dist/testing/cross_backend/role_grant_cross_helpers.d.ts.map +1 -1
  177. package/dist/testing/cross_backend/role_grant_offer_lifecycle.d.ts +13 -0
  178. package/dist/testing/cross_backend/role_grant_offer_lifecycle.d.ts.map +1 -0
  179. package/dist/testing/cross_backend/role_grant_offer_lifecycle.js +203 -0
  180. package/dist/testing/cross_backend/role_grant_offer_notification_ws.d.ts +2 -5
  181. package/dist/testing/cross_backend/role_grant_offer_notification_ws.d.ts.map +1 -1
  182. package/dist/testing/cross_backend/role_grant_offer_notification_ws.js +203 -111
  183. package/dist/testing/cross_backend/role_grant_participation.d.ts +13 -0
  184. package/dist/testing/cross_backend/role_grant_participation.d.ts.map +1 -1
  185. package/dist/testing/cross_backend/role_grant_participation.js +32 -21
  186. package/dist/testing/cross_backend/role_grant_role_grammar.d.ts.map +1 -1
  187. package/dist/testing/cross_backend/role_grant_role_grammar.js +6 -9
  188. package/dist/testing/cross_backend/rpc_adversarial.d.ts +47 -0
  189. package/dist/testing/cross_backend/rpc_adversarial.d.ts.map +1 -0
  190. package/dist/testing/cross_backend/rpc_adversarial.js +302 -0
  191. package/dist/testing/cross_backend/rpc_success_fixtures.d.ts +24 -0
  192. package/dist/testing/cross_backend/rpc_success_fixtures.d.ts.map +1 -0
  193. package/dist/testing/cross_backend/rpc_success_fixtures.js +124 -0
  194. package/dist/testing/cross_backend/rust_spine_consumer_surface.d.ts +101 -0
  195. package/dist/testing/cross_backend/rust_spine_consumer_surface.d.ts.map +1 -0
  196. package/dist/testing/cross_backend/rust_spine_consumer_surface.js +113 -0
  197. package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts +10 -0
  198. package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts.map +1 -1
  199. package/dist/testing/cross_backend/rust_spine_stub_backend_config.js +33 -21
  200. package/dist/testing/cross_backend/session_cap.d.ts +9 -8
  201. package/dist/testing/cross_backend/session_cap.d.ts.map +1 -1
  202. package/dist/testing/cross_backend/session_cap.js +9 -4
  203. package/dist/testing/cross_backend/session_cookie_codec.js +1 -1
  204. package/dist/testing/cross_backend/setup.d.ts +58 -56
  205. package/dist/testing/cross_backend/setup.d.ts.map +1 -1
  206. package/dist/testing/cross_backend/setup.js +29 -29
  207. package/dist/testing/cross_backend/simple_request.d.ts.map +1 -1
  208. package/dist/testing/cross_backend/simple_request.js +4 -4
  209. package/dist/testing/cross_backend/spawn_backend.d.ts +59 -10
  210. package/dist/testing/cross_backend/spawn_backend.d.ts.map +1 -1
  211. package/dist/testing/cross_backend/spawn_backend.js +219 -60
  212. package/dist/testing/cross_backend/spine_suites.d.ts +311 -0
  213. package/dist/testing/cross_backend/spine_suites.d.ts.map +1 -0
  214. package/dist/testing/cross_backend/spine_suites.js +897 -0
  215. package/dist/testing/cross_backend/spine_surface_constants.d.ts +44 -0
  216. package/dist/testing/cross_backend/spine_surface_constants.d.ts.map +1 -1
  217. package/dist/testing/cross_backend/spine_surface_constants.js +53 -0
  218. package/dist/testing/cross_backend/sse_round_trip.d.ts.map +1 -1
  219. package/dist/testing/cross_backend/sse_round_trip.js +3 -4
  220. package/dist/testing/cross_backend/standard.d.ts +18 -1
  221. package/dist/testing/cross_backend/standard.d.ts.map +1 -1
  222. package/dist/testing/cross_backend/standard.js +2 -0
  223. package/dist/testing/cross_backend/test_cell_gated_create_authorize.d.ts +24 -0
  224. package/dist/testing/cross_backend/test_cell_gated_create_authorize.d.ts.map +1 -1
  225. package/dist/testing/cross_backend/test_cell_gated_create_authorize.js +15 -0
  226. package/dist/testing/cross_backend/testing_backdoor.d.ts +29 -12
  227. package/dist/testing/cross_backend/testing_backdoor.d.ts.map +1 -1
  228. package/dist/testing/cross_backend/testing_backdoor.js +143 -51
  229. package/dist/testing/cross_backend/testing_reset_actions.d.ts +30 -14
  230. package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
  231. package/dist/testing/cross_backend/testing_reset_actions.js +58 -37
  232. package/dist/testing/cross_backend/testing_server_bun.js +1 -1
  233. package/dist/testing/cross_backend/token_lifetime.js +1 -1
  234. package/dist/testing/cross_backend/token_scope_surface.d.ts.map +1 -1
  235. package/dist/testing/cross_backend/token_scope_surface.js +9 -13
  236. package/dist/testing/cross_backend/transport_composition.d.ts +26 -2
  237. package/dist/testing/cross_backend/transport_composition.d.ts.map +1 -1
  238. package/dist/testing/cross_backend/transport_composition.js +81 -51
  239. package/dist/testing/cross_backend/ts_spine_backend_config.d.ts +8 -0
  240. package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -1
  241. package/dist/testing/cross_backend/ts_spine_backend_config.js +23 -13
  242. package/dist/testing/cross_backend/ws_action_rate_limit.d.ts +2 -5
  243. package/dist/testing/cross_backend/ws_action_rate_limit.d.ts.map +1 -1
  244. package/dist/testing/cross_backend/ws_action_rate_limit.js +8 -14
  245. package/dist/testing/cross_backend/ws_connection_cap.d.ts +4 -9
  246. package/dist/testing/cross_backend/ws_connection_cap.d.ts.map +1 -1
  247. package/dist/testing/cross_backend/ws_connection_cap.js +11 -12
  248. package/dist/testing/cross_backend/ws_endpoint.d.ts +52 -0
  249. package/dist/testing/cross_backend/ws_endpoint.d.ts.map +1 -0
  250. package/dist/testing/cross_backend/ws_endpoint.js +54 -0
  251. package/dist/testing/cross_backend/ws_inbound_dispatch.d.ts +2 -5
  252. package/dist/testing/cross_backend/ws_inbound_dispatch.d.ts.map +1 -1
  253. package/dist/testing/cross_backend/ws_inbound_dispatch.js +9 -15
  254. package/dist/testing/cross_backend/ws_outbound_overflow.d.ts +2 -7
  255. package/dist/testing/cross_backend/ws_outbound_overflow.d.ts.map +1 -1
  256. package/dist/testing/cross_backend/ws_outbound_overflow.js +5 -9
  257. package/dist/testing/cross_backend/ws_role_gated.d.ts +4 -5
  258. package/dist/testing/cross_backend/ws_role_gated.d.ts.map +1 -1
  259. package/dist/testing/cross_backend/ws_role_gated.js +12 -21
  260. package/dist/testing/cross_backend/ws_round_trip.d.ts +12 -9
  261. package/dist/testing/cross_backend/ws_round_trip.d.ts.map +1 -1
  262. package/dist/testing/cross_backend/ws_round_trip.js +29 -34
  263. package/dist/testing/db_entities.d.ts +16 -3
  264. package/dist/testing/db_entities.d.ts.map +1 -1
  265. package/dist/testing/db_entities.js +28 -5
  266. package/dist/testing/integration_helpers.d.ts +61 -2
  267. package/dist/testing/integration_helpers.d.ts.map +1 -1
  268. package/dist/testing/integration_helpers.js +75 -18
  269. package/dist/testing/round_trip.d.ts +17 -0
  270. package/dist/testing/round_trip.d.ts.map +1 -1
  271. package/dist/testing/round_trip.js +67 -24
  272. package/dist/testing/rpc_attack_surface.d.ts +10 -0
  273. package/dist/testing/rpc_attack_surface.d.ts.map +1 -1
  274. package/dist/testing/rpc_attack_surface.js +27 -140
  275. package/dist/testing/rpc_envelope_cases.d.ts +114 -0
  276. package/dist/testing/rpc_envelope_cases.d.ts.map +1 -0
  277. package/dist/testing/rpc_envelope_cases.js +243 -0
  278. package/dist/testing/rpc_helpers.d.ts +31 -0
  279. package/dist/testing/rpc_helpers.d.ts.map +1 -1
  280. package/dist/testing/rpc_helpers.js +35 -14
  281. package/dist/testing/rpc_round_trip.d.ts +62 -6
  282. package/dist/testing/rpc_round_trip.d.ts.map +1 -1
  283. package/dist/testing/rpc_round_trip.js +151 -39
  284. package/dist/testing/schema_generators.d.ts +99 -2
  285. package/dist/testing/schema_generators.d.ts.map +1 -1
  286. package/dist/testing/schema_generators.js +261 -73
  287. package/dist/testing/standard.d.ts +26 -0
  288. package/dist/testing/standard.d.ts.map +1 -1
  289. package/dist/testing/standard.js +4 -1
  290. package/dist/testing/stubs.d.ts +4 -3
  291. package/dist/testing/stubs.d.ts.map +1 -1
  292. package/dist/testing/stubs.js +6 -4
  293. package/dist/testing/transports/raw_http.d.ts +21 -0
  294. package/dist/testing/transports/raw_http.d.ts.map +1 -1
  295. package/dist/testing/transports/raw_http.js +30 -0
  296. package/dist/zod.d.ts +9 -0
  297. package/dist/zod.d.ts.map +1 -1
  298. package/dist/zod.js +20 -0
  299. package/package.json +6 -4
  300. package/dist/testing/cross_backend/actor_search.d.ts +0 -6
  301. package/dist/testing/cross_backend/actor_search.d.ts.map +0 -1
  302. package/dist/testing/cross_backend/actor_search.js +0 -90
  303. package/dist/testing/cross_backend/cell_cross_helpers.d.ts.map +0 -1
@@ -4,7 +4,8 @@
4
4
  * Provides error types, named constructors, and HTTP status mapping
5
5
  * for the throw/catch error pattern used by `apply_route_specs`.
6
6
  * Core error codes (5 standard + 10 general application). Domain-specific
7
- * codes stay in consumers — add by casting `as JsonrpcErrorCode`.
7
+ * codes stay in consumers — add by casting `as JsonrpcErrorCode`, and
8
+ * declare each one's HTTP status with `register_jsonrpc_error_code`.
8
9
  *
9
10
  * `JsonrpcErrorCode` and `JsonrpcErrorObject` types are Zod-inferred
10
11
  * from `http/jsonrpc.ts` — this module re-uses those as the single source
@@ -17,14 +18,15 @@
17
18
  * @module
18
19
  */
19
20
  import { DEV } from 'esm-env';
20
- import { JSONRPC_PARSE_ERROR, JSONRPC_INVALID_REQUEST, JSONRPC_METHOD_NOT_FOUND, JSONRPC_INVALID_PARAMS, JSONRPC_INTERNAL_ERROR } from './jsonrpc.js';
21
+ import { JSONRPC_PARSE_ERROR, JSONRPC_INVALID_REQUEST, JSONRPC_METHOD_NOT_FOUND, JSONRPC_INVALID_PARAMS, JSONRPC_INTERNAL_ERROR, JSONRPC_SERVER_ERROR_START, JSONRPC_SERVER_ERROR_END } from './jsonrpc.js';
21
22
  /** Default message for unknown errors. */
22
23
  export const UNKNOWN_ERROR_MESSAGE = 'unknown error';
23
24
  /**
24
25
  * Standard JSON-RPC error codes (5) plus general application codes (10).
25
26
  *
26
27
  * Extensible — consumers add domain-specific codes to their own objects
27
- * by casting `as JsonrpcErrorCode`. Application codes use the -32000 to
28
+ * by casting `as JsonrpcErrorCode`, and declare each one's HTTP status with
29
+ * `register_jsonrpc_error_code`. Application codes use the -32000 to
28
30
  * -32099 range reserved by the JSON-RPC spec.
29
31
  *
30
32
  * Frozen with `Object.freeze` to convert accidental mutation (test
@@ -225,54 +227,106 @@ export const jsonrpc_errors = {
225
227
  };
226
228
  // --- HTTP status mapping ---
227
229
  /**
228
- * Maps JSON-RPC error codes to HTTP status codes.
230
+ * The HTTP status each JSON-RPC error code answers — the base set, plus each
231
+ * consumer code `register_jsonrpc_error_code` adds.
229
232
  *
230
- * Extensible — consumers with domain-specific error codes assign directly
231
- * (`JSONRPC_ERROR_CODE_TO_HTTP_STATUS[-32020] = 502`) at module load. The
232
- * lookup function reads at call time, so mutation is the supported
233
- * extension mechanism.
233
+ * Module-private so a consumer can't remap a base code or skip the checks
234
+ * registration makes; read it through `jsonrpc_error_code_to_http_status`.
234
235
  */
235
- export const JSONRPC_ERROR_CODE_TO_HTTP_STATUS = {
236
- [-32700]: 400, // parse_error
237
- [-32600]: 400, // invalid_request
238
- [-32601]: 404, // method_not_found
239
- [-32602]: 400, // invalid_params
240
- [-32603]: 500, // internal_error
241
- [-32001]: 401, // unauthenticated
242
- [-32002]: 403, // forbidden
243
- [-32003]: 404, // not_found
244
- [-32004]: 409, // conflict
245
- [-32005]: 422, // validation_error
246
- // queue_overflow shares 429 with rate_limited — listed first so reverse
247
- // map wins with rate_limited (a policy) rather than a full buffer.
248
- [-32009]: 429, // queue_overflow (backpressure)
249
- [-32006]: 429, // rate_limited
250
- [-32007]: 503, // service_unavailable
251
- [-32008]: 504, // timeout
252
- [-32010]: 499 // request_cancelled (nginx "client closed request")
236
+ const jsonrpc_error_code_http_statuses = new Map([
237
+ [JSONRPC_PARSE_ERROR, 400],
238
+ [JSONRPC_INVALID_REQUEST, 400],
239
+ [JSONRPC_METHOD_NOT_FOUND, 404],
240
+ [JSONRPC_INVALID_PARAMS, 400],
241
+ [JSONRPC_INTERNAL_ERROR, 500],
242
+ [JSONRPC_ERROR_CODES.unauthenticated, 401],
243
+ [JSONRPC_ERROR_CODES.forbidden, 403],
244
+ [JSONRPC_ERROR_CODES.not_found, 404],
245
+ [JSONRPC_ERROR_CODES.conflict, 409],
246
+ [JSONRPC_ERROR_CODES.validation_error, 422],
247
+ // queue_overflow shares 429 with rate_limited — listed first so the
248
+ // last-wins reverse map resolves 429 to rate_limited (a policy) rather
249
+ // than a full buffer
250
+ [JSONRPC_ERROR_CODES.queue_overflow, 429],
251
+ [JSONRPC_ERROR_CODES.rate_limited, 429],
252
+ [JSONRPC_ERROR_CODES.service_unavailable, 503],
253
+ [JSONRPC_ERROR_CODES.timeout, 504],
254
+ [JSONRPC_ERROR_CODES.request_cancelled, 499] // nginx "client closed request"
255
+ ]);
256
+ /** Every code `JSONRPC_ERROR_CODES` defines — the numbers a consumer code may not reuse. */
257
+ const BASE_JSONRPC_ERROR_CODE_SET = new Set(Object.values(JSONRPC_ERROR_CODES));
258
+ /**
259
+ * Declare a consumer JSON-RPC error code and the HTTP status it answers, so
260
+ * `jsonrpc_error_code_to_http_status` maps it instead of falling back to 500.
261
+ *
262
+ * Call once at module load, beside the code's declaration — the module's
263
+ * import is then a side effect, so list it in the package's `sideEffects`.
264
+ * Registering the same code again with the same status is a no-op, so a
265
+ * module evaluated twice (a duplicated dependency, a test reload) is fine.
266
+ * A registered code joins neither `HTTP_STATUS_TO_JSONRPC_ERROR_CODE` (a bare
267
+ * status carries no consumer meaning, e.g. a proxy's envelope-less 502) nor
268
+ * `JSONRPC_ERROR_CODE_TO_NAME` (its name lives in the consumer's own
269
+ * taxonomy), matching the Rust spine's `ConsumerErrorCode`, which carries a
270
+ * code and a status only.
271
+ *
272
+ * @param code - a new code in the -32099 to -32000 server-error range
273
+ * @param http_status - the 4xx or 5xx status the code answers
274
+ * @throws Error when `code` is not an integer in -32099 to -32000, is a code
275
+ * `JSONRPC_ERROR_CODES` defines, or is already registered with another
276
+ * status, or when `http_status` is not an integer in 400 to 599
277
+ * @example
278
+ * ```ts
279
+ * export const JSONRPC_ERROR_CODES = {
280
+ * ...BASE_JSONRPC_ERROR_CODES,
281
+ * ai_provider_error: -32020 as JsonrpcErrorCode
282
+ * } as const;
283
+ * register_jsonrpc_error_code(JSONRPC_ERROR_CODES.ai_provider_error, 502);
284
+ * ```
285
+ */
286
+ export const register_jsonrpc_error_code = (code, http_status) => {
287
+ if (!Number.isInteger(code) ||
288
+ code < JSONRPC_SERVER_ERROR_END ||
289
+ code > JSONRPC_SERVER_ERROR_START) {
290
+ throw new Error(`a consumer JSON-RPC error code must be an integer in ${JSONRPC_SERVER_ERROR_END} to ${JSONRPC_SERVER_ERROR_START}, got ${code}`);
291
+ }
292
+ if (BASE_JSONRPC_ERROR_CODE_SET.has(code)) {
293
+ throw new Error(`a consumer JSON-RPC error code may not reuse a base-set code, got ${code}`);
294
+ }
295
+ if (!Number.isInteger(http_status) || http_status < 400 || http_status > 599) {
296
+ throw new Error(`a consumer JSON-RPC error code must answer a 4xx or 5xx status, got ${http_status} for ${code}`);
297
+ }
298
+ const registered = jsonrpc_error_code_http_statuses.get(code);
299
+ if (registered === undefined) {
300
+ jsonrpc_error_code_http_statuses.set(code, http_status);
301
+ }
302
+ else if (registered !== http_status) {
303
+ throw new Error(`JSON-RPC error code ${code} is already registered with status ${registered}, not ${http_status}`);
304
+ }
253
305
  };
254
306
  /**
255
- * Maps HTTP status codes to JSON-RPC error codes (reverse mapping).
307
+ * Maps HTTP status codes to JSON-RPC error codes (reverse mapping), over the
308
+ * base set only — built once at module load, before any consumer code is
309
+ * registered, and frozen.
256
310
  *
257
311
  * When multiple error codes map to the same HTTP status (e.g. parse_error
258
312
  * and invalid_request both map to 400), the last one wins. Use for
259
313
  * best-effort HTTP → JSON-RPC translation.
260
314
  */
261
- export const HTTP_STATUS_TO_JSONRPC_ERROR_CODE = Object.fromEntries(Object.entries(JSONRPC_ERROR_CODE_TO_HTTP_STATUS).map(([code, status]) => [
315
+ export const HTTP_STATUS_TO_JSONRPC_ERROR_CODE = Object.freeze(Object.fromEntries(Array.from(jsonrpc_error_code_http_statuses, ([code, status]) => [
262
316
  status,
263
- Number(code)
264
- ]));
317
+ code
318
+ ])));
265
319
  /**
266
320
  * Map a JSON-RPC error code to an HTTP status code.
267
321
  *
268
- * Returns 500 for unrecognized codes (consumer-defined codes
269
- * without a mapping default to internal server error). The return
322
+ * Returns 500 for unrecognized codes (a consumer code never passed to
323
+ * `register_jsonrpc_error_code` answers internal server error). The return
270
324
  * is narrowed to Hono's `ContentfulStatusCode` so call sites can
271
325
  * pass the result to `c.json(body, status)` without `as any` —
272
326
  * 499 (nginx "client closed request") is non-standard and gets
273
327
  * absorbed by the cast here rather than at every dispatcher branch.
274
328
  */
275
- export const jsonrpc_error_code_to_http_status = (code) => (JSONRPC_ERROR_CODE_TO_HTTP_STATUS[code] ?? 500);
329
+ export const jsonrpc_error_code_to_http_status = (code) => (jsonrpc_error_code_http_statuses.get(code) ?? 500);
276
330
  /**
277
331
  * Map an HTTP status code to a JSON-RPC error code.
278
332
  *
@@ -287,8 +341,9 @@ export const http_status_to_jsonrpc_error_code = (status) => HTTP_STATUS_TO_JSON
287
341
  * without inventing a separate vocabulary. Built once at module load
288
342
  * from the canonical `JSONRPC_ERROR_CODES` map so the two cannot drift.
289
343
  *
290
- * Consumer-defined codes outside the standard taxonomy are not present;
291
- * `jsonrpc_error_code_to_name` falls back to `'internal_error'` so the
344
+ * Consumer-defined codes outside the standard taxonomy are not present —
345
+ * registering one with `register_jsonrpc_error_code` gives it a status, not
346
+ * a name; `jsonrpc_error_code_to_name` falls back to `'internal_error'` so the
292
347
  * REST shape always carries some reason rather than `undefined`.
293
348
  */
294
349
  export const JSONRPC_ERROR_CODE_TO_NAME = Object.freeze(Object.fromEntries(Object.entries(JSONRPC_ERROR_CODES).map(([name, code]) => [code, name])));
@@ -53,7 +53,7 @@ export interface BoundedStringOptions {
53
53
  * @param options - the bounds, in UTF-16 code units
54
54
  * @returns the bounded string schema
55
55
  */
56
- export declare const bounded_string: ({ min, max, max_message }: BoundedStringOptions) => z.ZodString;
56
+ export declare const bounded_string: (options: BoundedStringOptions) => z.ZodString;
57
57
  /** Minimum username length (must have start + middle + end characters). */
58
58
  export declare const USERNAME_LENGTH_MIN = 3;
59
59
  /** Maximum username length (matches GitHub's limit). The grammar is ASCII, so units and characters agree. */
@@ -1 +1 @@
1
- {"version":3,"file":"primitive_schemas.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/primitive_schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAIlF,gEAAgE;AAChE,MAAM,WAAW,oBAAoB;IACpC,yDAAyD;IACzD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,cAAc,GAAI,2BAA2B,oBAAoB,KAAG,CAAC,CAAC,SA8ClF,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,6GAA6G;AAC7G,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,gNAAgN;AAChN,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAEhD;;;;;;;;;GASG;AACH,eAAO,MAAM,QAAQ,wDAEc,CAAC;AACpC,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAEhD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,gBAAgB,wDAEqE,CAAC;AACnG,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,MAAM,CAAC;AAqBpC;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,KAAK,aAYhB,CAAC;AACH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,CAAC;AAE1C,wCAAwC;AACxC,eAAO,MAAM,WAAW,QAAO,IAAmC,CAAC;AAEnE;;;;;;;;;GASG;AACH,eAAO,MAAM,IAAI,8CAAuC,CAAC;AACzD,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AAExC,qFAAqF;AACrF,eAAO,MAAM,eAAe,4DAA4B,CAAC;AACzD,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,wCAAwC;AACxC,eAAO,MAAM,QAAQ,yDAAqC,CAAC;AAC3D,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAEhD,gEAAgE;AAChE,eAAO,MAAM,gBAAgB,QAAO,QAAgD,CAAC;AAErF,sFAAsF;AACtF,eAAO,MAAM,WAAW,uEAAqC,CAAC;AAC9D,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEtD,uFAAuF;AACvF,eAAO,MAAM,UAAU,aAEuD,CAAC;AAC/E,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,cAAc,EAAE,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAEA,CAAC"}
1
+ {"version":3,"file":"primitive_schemas.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/primitive_schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAIlF,gEAAgE;AAChE,MAAM,WAAW,oBAAoB;IACpC,yDAAyD;IACzD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,cAAc,GAAI,SAAS,oBAAoB,KAAG,CAAC,CAAC,SA+ChE,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,6GAA6G;AAC7G,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,gNAAgN;AAChN,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAEhD;;;;;;;;;GASG;AACH,eAAO,MAAM,QAAQ,wDAEc,CAAC;AACpC,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAEhD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,gBAAgB,wDAEqE,CAAC;AACnG,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,MAAM,CAAC;AAqBpC;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,KAAK,aAYhB,CAAC;AACH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,CAAC;AAE1C,wCAAwC;AACxC,eAAO,MAAM,WAAW,QAAO,IAAmC,CAAC;AAEnE;;;;;;;;;GASG;AACH,eAAO,MAAM,IAAI,8CAAuC,CAAC;AACzD,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AAExC,qFAAqF;AACrF,eAAO,MAAM,eAAe,4DAA4B,CAAC;AACzD,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,wCAAwC;AACxC,eAAO,MAAM,QAAQ,yDAAqC,CAAC;AAC3D,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAEhD,gEAAgE;AAChE,eAAO,MAAM,gBAAgB,QAAO,QAAgD,CAAC;AAErF,sFAAsF;AACtF,eAAO,MAAM,WAAW,uEAAqC,CAAC;AAC9D,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEtD,uFAAuF;AACvF,eAAO,MAAM,UAAU,aAEuD,CAAC;AAC/E,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,cAAc,EAAE,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAEA,CAAC"}
@@ -44,7 +44,8 @@ import { FACT_HASH_EXACT } from '@fuzdev/fuz_util/hash_schemas.ts';
44
44
  * @param options - the bounds, in UTF-16 code units
45
45
  * @returns the bounded string schema
46
46
  */
47
- export const bounded_string = ({ min, max, max_message }) => {
47
+ export const bounded_string = (options) => {
48
+ const { min, max, max_message } = options;
48
49
  let schema = z.string();
49
50
  if (min !== undefined)
50
51
  schema = schema.min(min);
@@ -6,11 +6,91 @@
6
6
  *
7
7
  * @module
8
8
  */
9
+ import type { z } from 'zod';
9
10
  import type { Sensitivity } from './sensitivity.js';
10
11
  /** Zod `.meta()` shape for fuz_app schema metadata conventions. */
11
12
  export interface SchemaFieldMeta {
12
13
  description?: string;
13
14
  /** Sensitivity level for masking/redaction. `'secret'` masks the value. */
14
15
  sensitivity?: Sensitivity;
16
+ /**
17
+ * Set on an action's **input** schema that accepts `{}` by design while
18
+ * its handler refuses `{}` with a declared reason — an input taking one of
19
+ * several optional selectors, where the handler names the missing or
20
+ * conflicting one (a schema-level refine would answer a reason-less
21
+ * `invalid_params` first). A call with no input is never valid for such an
22
+ * action, so the typed surface keeps its input required
23
+ * (`action_input_is_optional`), and the input-shape invariant ("an input
24
+ * accepting `{}` accepts `undefined` too") exempts it. Read from the input
25
+ * schema itself, so a wrapper (`.optional()`, `.extend()`) drops it.
26
+ */
27
+ empty_input_handler_guarded?: boolean;
28
+ /**
29
+ * The `error.data.reason` an action input refuses this field with. On a
30
+ * field of an action's **input** schema, every `invalid_params` whose first
31
+ * Zod issue lands on the field — missing, wrong type, `null`, out of range,
32
+ * malformed, or a fault anywhere inside it — carries this reason, where an
33
+ * undeclared field's refusal carries none. The message stays the generic
34
+ * `invalid params`. A body with faults on several fields answers the first
35
+ * issue's reason in Zod's order, which a twin checking in another order
36
+ * need not match, so the reason is defined for a single-fault body only —
37
+ * except that an issue on the input itself (an unknown key) anywhere among
38
+ * the issues means no reason, as the Rust twin refuses unknown keys first.
39
+ * Declared reasons are named `<field>_invalid`.
40
+ *
41
+ * The declaration is the one source of the reason: the dispatcher reads it
42
+ * (`perform_action`), the adversarial suites expect it, and the Rust twin
43
+ * owes the same reason on every refusal of the field. Read through the
44
+ * field's optional, nullable, default, prefault, transform and pipe layers
45
+ * (not `.readonly()`, `.catch()` or `z.lazy()`), so it may sit on any of
46
+ * them; a declaration on a nested field overrides its parent's for a fault
47
+ * inside it, and an object-level refine whose issue names the field takes
48
+ * its reason too. See `resolve_issues_invalid_reason`.
49
+ */
50
+ invalid_reason?: string;
15
51
  }
52
+ /**
53
+ * Whether `schema` carries `empty_input_handler_guarded: true` in its `.meta()`.
54
+ *
55
+ * @param schema - an action's input schema
56
+ * @returns whether its handler refuses the `{}` the schema admits
57
+ */
58
+ export declare const is_empty_input_handler_guarded: (schema: z.ZodType) => boolean;
59
+ /**
60
+ * The `invalid_reason` a schema declares, read through its wrappers, the
61
+ * outermost declaration winning.
62
+ *
63
+ * @param schema - a field schema, possibly wrapped
64
+ * @returns the declared reason, or `undefined` when no layer declares one
65
+ */
66
+ export declare const schema_invalid_reason: (schema: z.ZodType) => string | undefined;
67
+ /**
68
+ * The `error.data.reason` an input validation failure at `path` carries: the
69
+ * `invalid_reason` of the deepest field along `path` that declares one.
70
+ *
71
+ * Walks object fields only, each through its wrappers: a segment that is not
72
+ * a key of an object schema (an array index, a union member's key, an unknown
73
+ * key) ends the walk, so a fault inside a declared field still resolves to
74
+ * that field's reason. An empty path — a whole-input fault such as an
75
+ * unrecognized key on the input object — resolves to none, as does a schema
76
+ * that is not an object.
77
+ *
78
+ * @param input_schema - an action's input schema
79
+ * @param path - the failing issue's path (`ZodError.issues[0].path`)
80
+ * @returns the declared reason, or `undefined`
81
+ */
82
+ export declare const resolve_invalid_reason: (input_schema: z.ZodType, path: ReadonlyArray<PropertyKey>) => string | undefined;
83
+ /**
84
+ * The `error.data.reason` a failed input parse answers: the declared reason
85
+ * of the first issue's field (`resolve_invalid_reason`), or none when any
86
+ * issue sits on the input itself. Such an issue is an unknown key on the
87
+ * input object (or a non-object input), which the Rust twin refuses before
88
+ * reading any field, so a stale client sending an extra key gets the same
89
+ * answer from both spines whatever else its body gets wrong.
90
+ *
91
+ * @param input_schema - an action's input schema
92
+ * @param issues - the failed parse's issues, in Zod's order
93
+ * @returns the declared reason, or `undefined`
94
+ */
95
+ export declare const resolve_issues_invalid_reason: (input_schema: z.ZodType, issues: ReadonlyArray<z.core.$ZodIssue>) => string | undefined;
16
96
  //# sourceMappingURL=schema_meta.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema_meta.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/schema_meta.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,mEAAmE;AACnE,MAAM,WAAW,eAAe;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,WAAW,CAAC,EAAE,WAAW,CAAC;CAC1B"}
1
+ {"version":3,"file":"schema_meta.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/schema_meta.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpD,mEAAmE;AACnE,MAAM,WAAW,eAAe;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;;;;;;;;OAUG;IACH,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OACkB,CAAC;AAEtF;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,MAAM,GAAG,SAMlE,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,sBAAsB,GAClC,cAAc,CAAC,CAAC,OAAO,EACvB,MAAM,aAAa,CAAC,WAAW,CAAC,KAC9B,MAAM,GAAG,SAYX,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,6BAA6B,GACzC,cAAc,CAAC,CAAC,OAAO,EACvB,QAAQ,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KACrC,MAAM,GAAG,SAIX,CAAC"}
@@ -6,4 +6,74 @@
6
6
  *
7
7
  * @module
8
8
  */
9
- export {};
9
+ import { zod_get_schema_layers, zod_unwrap_to_object } from './zod.js';
10
+ /**
11
+ * Whether `schema` carries `empty_input_handler_guarded: true` in its `.meta()`.
12
+ *
13
+ * @param schema - an action's input schema
14
+ * @returns whether its handler refuses the `{}` the schema admits
15
+ */
16
+ export const is_empty_input_handler_guarded = (schema) => schema.meta()?.empty_input_handler_guarded === true;
17
+ /**
18
+ * The `invalid_reason` a schema declares, read through its wrappers, the
19
+ * outermost declaration winning.
20
+ *
21
+ * @param schema - a field schema, possibly wrapped
22
+ * @returns the declared reason, or `undefined` when no layer declares one
23
+ */
24
+ export const schema_invalid_reason = (schema) => {
25
+ for (const layer of zod_get_schema_layers(schema)) {
26
+ const reason = layer.meta()?.invalid_reason;
27
+ if (reason !== undefined)
28
+ return reason;
29
+ }
30
+ return undefined;
31
+ };
32
+ /**
33
+ * The `error.data.reason` an input validation failure at `path` carries: the
34
+ * `invalid_reason` of the deepest field along `path` that declares one.
35
+ *
36
+ * Walks object fields only, each through its wrappers: a segment that is not
37
+ * a key of an object schema (an array index, a union member's key, an unknown
38
+ * key) ends the walk, so a fault inside a declared field still resolves to
39
+ * that field's reason. An empty path — a whole-input fault such as an
40
+ * unrecognized key on the input object — resolves to none, as does a schema
41
+ * that is not an object.
42
+ *
43
+ * @param input_schema - an action's input schema
44
+ * @param path - the failing issue's path (`ZodError.issues[0].path`)
45
+ * @returns the declared reason, or `undefined`
46
+ */
47
+ export const resolve_invalid_reason = (input_schema, path) => {
48
+ let reason;
49
+ let schema = input_schema;
50
+ for (const segment of path) {
51
+ if (typeof segment !== 'string')
52
+ break;
53
+ const shape = zod_unwrap_to_object(schema)?.shape;
54
+ if (!shape || !Object.hasOwn(shape, segment))
55
+ break;
56
+ const field = shape[segment];
57
+ reason = schema_invalid_reason(field) ?? reason;
58
+ schema = field;
59
+ }
60
+ return reason;
61
+ };
62
+ /**
63
+ * The `error.data.reason` a failed input parse answers: the declared reason
64
+ * of the first issue's field (`resolve_invalid_reason`), or none when any
65
+ * issue sits on the input itself. Such an issue is an unknown key on the
66
+ * input object (or a non-object input), which the Rust twin refuses before
67
+ * reading any field, so a stale client sending an extra key gets the same
68
+ * answer from both spines whatever else its body gets wrong.
69
+ *
70
+ * @param input_schema - an action's input schema
71
+ * @param issues - the failed parse's issues, in Zod's order
72
+ * @returns the declared reason, or `undefined`
73
+ */
74
+ export const resolve_issues_invalid_reason = (input_schema, issues) => {
75
+ const first = issues[0];
76
+ if (!first || issues.some((issue) => issue.path.length === 0))
77
+ return undefined;
78
+ return resolve_invalid_reason(input_schema, first.path);
79
+ };