ts-procedures 7.3.0 → 8.0.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 (325) hide show
  1. package/README.md +65 -3
  2. package/agent_config/claude-code/agents/ts-procedures-architect.md +6 -8
  3. package/agent_config/claude-code/skills/ts-procedures/SKILL.md +30 -33
  4. package/agent_config/claude-code/skills/ts-procedures/anti-patterns.md +104 -53
  5. package/agent_config/claude-code/skills/ts-procedures/api-reference.md +205 -232
  6. package/agent_config/claude-code/skills/ts-procedures/patterns.md +80 -153
  7. package/agent_config/claude-code/skills/ts-procedures-review/SKILL.md +1 -1
  8. package/agent_config/claude-code/skills/ts-procedures-review/checklist.md +4 -5
  9. package/agent_config/claude-code/skills/ts-procedures-scaffold/SKILL.md +4 -7
  10. package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/hono.md +223 -0
  11. package/agent_config/copilot/copilot-instructions.md +34 -48
  12. package/agent_config/cursor/cursorrules +34 -48
  13. package/build/client/call.js +4 -1
  14. package/build/client/call.js.map +1 -1
  15. package/build/client/call.test.js +23 -0
  16. package/build/client/call.test.js.map +1 -1
  17. package/build/client/fetch-adapter.js +3 -1
  18. package/build/client/fetch-adapter.js.map +1 -1
  19. package/build/client/fetch-adapter.test.js +11 -1
  20. package/build/client/fetch-adapter.test.js.map +1 -1
  21. package/build/client/index.test.js +7 -7
  22. package/build/client/index.test.js.map +1 -1
  23. package/build/client/request-builder.d.ts +1 -1
  24. package/build/client/request-builder.js +2 -2
  25. package/build/client/request-builder.js.map +1 -1
  26. package/build/client/stream.js +13 -2
  27. package/build/client/stream.js.map +1 -1
  28. package/build/client/stream.test.js +32 -7
  29. package/build/client/stream.test.js.map +1 -1
  30. package/build/client/typed-error-dispatch.test.js +8 -92
  31. package/build/client/typed-error-dispatch.test.js.map +1 -1
  32. package/build/client/types.d.ts +21 -3
  33. package/build/codegen/bin/cli.js +0 -0
  34. package/build/codegen/e2e.test.js +87 -23
  35. package/build/codegen/e2e.test.js.map +1 -1
  36. package/build/codegen/emit-errors.integration.test.js +1 -1
  37. package/build/codegen/emit-errors.integration.test.js.map +1 -1
  38. package/build/codegen/emit-scope.js +308 -47
  39. package/build/codegen/emit-scope.js.map +1 -1
  40. package/build/codegen/emit-scope.test.js +363 -110
  41. package/build/codegen/emit-scope.test.js.map +1 -1
  42. package/build/codegen/pipeline.test.js +7 -7
  43. package/build/codegen/pipeline.test.js.map +1 -1
  44. package/build/codegen/resolve-envelope.js +1 -1
  45. package/build/codegen/resolve-envelope.js.map +1 -1
  46. package/build/codegen/resolve-envelope.test.js +5 -5
  47. package/build/codegen/resolve-envelope.test.js.map +1 -1
  48. package/build/codegen/targets/_shared/route-slots.d.ts +8 -3
  49. package/build/codegen/targets/_shared/route-slots.js +49 -8
  50. package/build/codegen/targets/_shared/route-slots.js.map +1 -1
  51. package/build/codegen/targets/_shared/route-slots.test.js +99 -26
  52. package/build/codegen/targets/_shared/route-slots.test.js.map +1 -1
  53. package/build/codegen/targets/kotlin/emit-route-kotlin.test.js +88 -17
  54. package/build/codegen/targets/kotlin/emit-route-kotlin.test.js.map +1 -1
  55. package/build/codegen/targets/kotlin/emit-scope-kotlin.test.js +9 -6
  56. package/build/codegen/targets/kotlin/emit-scope-kotlin.test.js.map +1 -1
  57. package/build/codegen/targets/kotlin/integration.test.js +6 -0
  58. package/build/codegen/targets/kotlin/integration.test.js.map +1 -1
  59. package/build/codegen/targets/swift/access-level.test.js +8 -11
  60. package/build/codegen/targets/swift/access-level.test.js.map +1 -1
  61. package/build/codegen/targets/swift/emit-route-swift.test.js +91 -20
  62. package/build/codegen/targets/swift/emit-route-swift.test.js.map +1 -1
  63. package/build/codegen/targets/swift/emit-scope-swift.test.js +12 -9
  64. package/build/codegen/targets/swift/emit-scope-swift.test.js.map +1 -1
  65. package/build/codegen/targets/swift/integration.test.js +6 -0
  66. package/build/codegen/targets/swift/integration.test.js.map +1 -1
  67. package/build/create-http-stream.d.ts +58 -0
  68. package/build/create-http-stream.js +122 -0
  69. package/build/create-http-stream.js.map +1 -0
  70. package/build/create-http-stream.test.js +88 -0
  71. package/build/create-http-stream.test.js.map +1 -0
  72. package/build/create-http.d.ts +49 -0
  73. package/build/create-http.js +108 -0
  74. package/build/create-http.js.map +1 -0
  75. package/build/create-http.test.js +137 -0
  76. package/build/create-http.test.js.map +1 -0
  77. package/build/create-stream.d.ts +35 -0
  78. package/build/create-stream.js +123 -0
  79. package/build/create-stream.js.map +1 -0
  80. package/build/create-stream.test.js +428 -0
  81. package/build/create-stream.test.js.map +1 -0
  82. package/build/create.d.ts +28 -0
  83. package/build/create.js +82 -0
  84. package/build/create.js.map +1 -0
  85. package/build/create.test.js +483 -0
  86. package/build/create.test.js.map +1 -0
  87. package/build/exports.d.ts +2 -0
  88. package/build/implementations/http/astro/index.test.js +20 -12
  89. package/build/implementations/http/astro/index.test.js.map +1 -1
  90. package/build/implementations/http/doc-registry.js +1 -1
  91. package/build/implementations/http/doc-registry.js.map +1 -1
  92. package/build/implementations/http/doc-registry.test.js +36 -5
  93. package/build/implementations/http/doc-registry.test.js.map +1 -1
  94. package/build/implementations/http/error-dispatch.d.ts +76 -0
  95. package/build/implementations/http/error-dispatch.js +77 -0
  96. package/build/implementations/http/error-dispatch.js.map +1 -0
  97. package/build/implementations/http/error-dispatch.test.js +254 -0
  98. package/build/implementations/http/error-dispatch.test.js.map +1 -0
  99. package/build/implementations/http/error-taxonomy.d.ts +5 -5
  100. package/build/implementations/http/hono/docs/http-doc.d.ts +6 -0
  101. package/build/implementations/http/hono/docs/http-doc.js +42 -0
  102. package/build/implementations/http/hono/docs/http-doc.js.map +1 -0
  103. package/build/implementations/http/hono/docs/http-stream-doc.d.ts +6 -0
  104. package/build/implementations/http/hono/docs/http-stream-doc.js +40 -0
  105. package/build/implementations/http/hono/docs/http-stream-doc.js.map +1 -0
  106. package/build/implementations/http/hono/docs/rpc-doc.d.ts +6 -0
  107. package/build/implementations/http/hono/docs/rpc-doc.js +24 -0
  108. package/build/implementations/http/hono/docs/rpc-doc.js.map +1 -0
  109. package/build/implementations/http/hono/docs/stream-doc.d.ts +6 -0
  110. package/build/implementations/http/hono/docs/stream-doc.js +42 -0
  111. package/build/implementations/http/hono/docs/stream-doc.js.map +1 -0
  112. package/build/implementations/http/hono/handlers/http-stream.d.ts +10 -0
  113. package/build/implementations/http/hono/handlers/http-stream.js +123 -0
  114. package/build/implementations/http/hono/handlers/http-stream.js.map +1 -0
  115. package/build/implementations/http/hono/handlers/http-stream.test.js +128 -0
  116. package/build/implementations/http/hono/handlers/http-stream.test.js.map +1 -0
  117. package/build/implementations/http/hono/handlers/http.d.ts +10 -0
  118. package/build/implementations/http/hono/handlers/http.js +115 -0
  119. package/build/implementations/http/hono/handlers/http.js.map +1 -0
  120. package/build/implementations/http/hono/handlers/http.test.js +118 -0
  121. package/build/implementations/http/hono/handlers/http.test.js.map +1 -0
  122. package/build/implementations/http/hono/handlers/rpc.d.ts +11 -0
  123. package/build/implementations/http/hono/handlers/rpc.js +32 -0
  124. package/build/implementations/http/hono/handlers/rpc.js.map +1 -0
  125. package/build/implementations/http/hono/handlers/rpc.test.js +73 -0
  126. package/build/implementations/http/hono/handlers/rpc.test.js.map +1 -0
  127. package/build/implementations/http/hono/handlers/stream.d.ts +23 -0
  128. package/build/implementations/http/hono/handlers/stream.js +147 -0
  129. package/build/implementations/http/hono/handlers/stream.js.map +1 -0
  130. package/build/implementations/http/hono/handlers/stream.test.d.ts +1 -0
  131. package/build/implementations/http/hono/handlers/stream.test.js +177 -0
  132. package/build/implementations/http/hono/handlers/stream.test.js.map +1 -0
  133. package/build/implementations/http/hono/index.d.ts +57 -0
  134. package/build/implementations/http/hono/index.js +149 -0
  135. package/build/implementations/http/hono/index.js.map +1 -0
  136. package/build/implementations/http/hono/index.test.d.ts +1 -0
  137. package/build/implementations/http/hono/index.test.js +274 -0
  138. package/build/implementations/http/hono/index.test.js.map +1 -0
  139. package/build/implementations/http/hono/path.d.ts +17 -0
  140. package/build/implementations/http/hono/path.js +39 -0
  141. package/build/implementations/http/hono/path.js.map +1 -0
  142. package/build/implementations/http/hono/path.test.d.ts +1 -0
  143. package/build/implementations/http/hono/path.test.js +83 -0
  144. package/build/implementations/http/hono/path.test.js.map +1 -0
  145. package/build/implementations/http/hono/types.d.ts +51 -0
  146. package/build/implementations/http/hono/types.js.map +1 -0
  147. package/build/implementations/http/on-request-error.test.js +6 -96
  148. package/build/implementations/http/on-request-error.test.js.map +1 -1
  149. package/build/implementations/http/route-errors.test.js +11 -59
  150. package/build/implementations/http/route-errors.test.js.map +1 -1
  151. package/build/implementations/types.d.ts +43 -9
  152. package/build/index.d.ts +124 -124
  153. package/build/index.js +10 -221
  154. package/build/index.js.map +1 -1
  155. package/build/index.test.js +20 -919
  156. package/build/index.test.js.map +1 -1
  157. package/build/migration.test.d.ts +1 -0
  158. package/build/migration.test.js +34 -0
  159. package/build/migration.test.js.map +1 -0
  160. package/build/schema/compute-schema.d.ts +11 -3
  161. package/build/schema/compute-schema.js +13 -7
  162. package/build/schema/compute-schema.js.map +1 -1
  163. package/build/schema/parser.d.ts +11 -3
  164. package/build/schema/parser.js +49 -9
  165. package/build/schema/parser.js.map +1 -1
  166. package/build/stack-utils.js +8 -0
  167. package/build/stack-utils.js.map +1 -1
  168. package/build/types.d.ts +142 -0
  169. package/build/types.js.map +1 -0
  170. package/docs/astro-adapter.md +5 -5
  171. package/docs/core.md +15 -17
  172. package/docs/http-integrations.md +83 -170
  173. package/docs/streaming.md +3 -60
  174. package/docs/superpowers/plans/2026-05-07-astro-adapter.md +2 -7
  175. package/docs/superpowers/plans/2026-05-08-create-http.md +3355 -0
  176. package/docs/superpowers/plans/2026-05-08-hono-app-builder-convergence.md +3365 -0
  177. package/docs/superpowers/specs/2026-05-07-astro-adapter-design.md +1 -3
  178. package/docs/superpowers/specs/2026-05-08-create-http-design.md +409 -0
  179. package/docs/superpowers/specs/2026-05-08-hono-app-builder-convergence-design.md +411 -0
  180. package/package.json +4 -22
  181. package/src/client/call.test.ts +26 -0
  182. package/src/client/call.ts +4 -1
  183. package/src/client/fetch-adapter.test.ts +14 -1
  184. package/src/client/fetch-adapter.ts +3 -1
  185. package/src/client/index.test.ts +7 -7
  186. package/src/client/request-builder.ts +2 -2
  187. package/src/client/stream.test.ts +39 -7
  188. package/src/client/stream.ts +16 -2
  189. package/src/client/typed-error-dispatch.test.ts +7 -97
  190. package/src/client/types.ts +21 -3
  191. package/src/codegen/__fixtures__/users-envelope.json +119 -38
  192. package/src/codegen/e2e.test.ts +98 -24
  193. package/src/codegen/emit-errors.integration.test.ts +1 -1
  194. package/src/codegen/emit-scope.test.ts +395 -110
  195. package/src/codegen/emit-scope.ts +350 -55
  196. package/src/codegen/pipeline.test.ts +7 -7
  197. package/src/codegen/resolve-envelope.test.ts +5 -5
  198. package/src/codegen/resolve-envelope.ts +1 -1
  199. package/src/codegen/targets/_shared/route-slots.test.ts +109 -26
  200. package/src/codegen/targets/_shared/route-slots.ts +48 -11
  201. package/src/codegen/targets/kotlin/__fixtures__/users-golden.kt +73 -0
  202. package/src/codegen/targets/kotlin/emit-route-kotlin.test.ts +100 -17
  203. package/src/codegen/targets/kotlin/emit-scope-kotlin.test.ts +9 -6
  204. package/src/codegen/targets/kotlin/integration.test.ts +19 -0
  205. package/src/codegen/targets/swift/__fixtures__/users-golden.swift +79 -0
  206. package/src/codegen/targets/swift/access-level.test.ts +8 -11
  207. package/src/codegen/targets/swift/emit-route-swift.test.ts +103 -20
  208. package/src/codegen/targets/swift/emit-scope-swift.test.ts +12 -9
  209. package/src/codegen/targets/swift/integration.test.ts +17 -0
  210. package/src/create-http-stream.test.ts +97 -0
  211. package/src/create-http-stream.ts +191 -0
  212. package/src/create-http.test.ts +163 -0
  213. package/src/create-http.ts +211 -0
  214. package/src/create-stream.test.ts +565 -0
  215. package/src/create-stream.ts +228 -0
  216. package/src/create.test.ts +658 -0
  217. package/src/create.ts +172 -0
  218. package/src/exports.ts +2 -0
  219. package/src/implementations/http/README.md +135 -95
  220. package/src/implementations/http/astro/README.md +4 -5
  221. package/src/implementations/http/astro/index.test.ts +25 -18
  222. package/src/implementations/http/doc-registry.test.ts +42 -5
  223. package/src/implementations/http/doc-registry.ts +1 -1
  224. package/src/implementations/http/error-dispatch.test.ts +283 -0
  225. package/src/implementations/http/error-dispatch.ts +176 -0
  226. package/src/implementations/http/error-taxonomy.ts +5 -5
  227. package/src/implementations/http/hono/docs/http-doc.ts +43 -0
  228. package/src/implementations/http/hono/docs/http-stream-doc.ts +44 -0
  229. package/src/implementations/http/hono/docs/rpc-doc.ts +34 -0
  230. package/src/implementations/http/hono/docs/stream-doc.ts +53 -0
  231. package/src/implementations/http/hono/handlers/http-stream.test.ts +150 -0
  232. package/src/implementations/http/hono/handlers/http-stream.ts +152 -0
  233. package/src/implementations/http/hono/handlers/http.test.ts +130 -0
  234. package/src/implementations/http/hono/handlers/http.ts +147 -0
  235. package/src/implementations/http/hono/handlers/rpc.test.ts +81 -0
  236. package/src/implementations/http/hono/handlers/rpc.ts +54 -0
  237. package/src/implementations/http/hono/handlers/stream.test.ts +198 -0
  238. package/src/implementations/http/hono/handlers/stream.ts +208 -0
  239. package/src/implementations/http/hono/index.test.ts +329 -0
  240. package/src/implementations/http/hono/index.ts +204 -0
  241. package/src/implementations/http/hono/path.test.ts +96 -0
  242. package/src/implementations/http/hono/path.ts +59 -0
  243. package/src/implementations/http/hono/types.ts +93 -0
  244. package/src/implementations/http/on-request-error.test.ts +10 -116
  245. package/src/implementations/http/route-errors.test.ts +11 -77
  246. package/src/implementations/types.ts +44 -9
  247. package/src/index.test.ts +22 -1249
  248. package/src/index.ts +49 -485
  249. package/src/migration.test.ts +48 -0
  250. package/src/schema/compute-schema.ts +26 -12
  251. package/src/schema/parser.ts +62 -12
  252. package/src/stack-utils.ts +8 -0
  253. package/src/types.ts +133 -0
  254. package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/express-rpc.md +0 -137
  255. package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/hono-api.md +0 -173
  256. package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/hono-rpc.md +0 -142
  257. package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/hono-stream.md +0 -147
  258. package/build/implementations/http/express-rpc/error-taxonomy.test.js +0 -83
  259. package/build/implementations/http/express-rpc/error-taxonomy.test.js.map +0 -1
  260. package/build/implementations/http/express-rpc/index.d.ts +0 -125
  261. package/build/implementations/http/express-rpc/index.js +0 -216
  262. package/build/implementations/http/express-rpc/index.js.map +0 -1
  263. package/build/implementations/http/express-rpc/index.test.js +0 -684
  264. package/build/implementations/http/express-rpc/index.test.js.map +0 -1
  265. package/build/implementations/http/express-rpc/types.d.ts +0 -11
  266. package/build/implementations/http/express-rpc/types.js.map +0 -1
  267. package/build/implementations/http/hono-api/error-taxonomy.test.js +0 -137
  268. package/build/implementations/http/hono-api/error-taxonomy.test.js.map +0 -1
  269. package/build/implementations/http/hono-api/index.d.ts +0 -151
  270. package/build/implementations/http/hono-api/index.js +0 -344
  271. package/build/implementations/http/hono-api/index.js.map +0 -1
  272. package/build/implementations/http/hono-api/index.test.js +0 -992
  273. package/build/implementations/http/hono-api/index.test.js.map +0 -1
  274. package/build/implementations/http/hono-api/types.d.ts +0 -13
  275. package/build/implementations/http/hono-api/types.js.map +0 -1
  276. package/build/implementations/http/hono-rpc/error-taxonomy.test.js +0 -64
  277. package/build/implementations/http/hono-rpc/error-taxonomy.test.js.map +0 -1
  278. package/build/implementations/http/hono-rpc/index.d.ts +0 -130
  279. package/build/implementations/http/hono-rpc/index.js +0 -209
  280. package/build/implementations/http/hono-rpc/index.js.map +0 -1
  281. package/build/implementations/http/hono-rpc/index.test.js +0 -828
  282. package/build/implementations/http/hono-rpc/index.test.js.map +0 -1
  283. package/build/implementations/http/hono-rpc/types.d.ts +0 -11
  284. package/build/implementations/http/hono-rpc/types.js +0 -2
  285. package/build/implementations/http/hono-rpc/types.js.map +0 -1
  286. package/build/implementations/http/hono-stream/error-taxonomy.test.js +0 -159
  287. package/build/implementations/http/hono-stream/error-taxonomy.test.js.map +0 -1
  288. package/build/implementations/http/hono-stream/index.d.ts +0 -171
  289. package/build/implementations/http/hono-stream/index.js +0 -415
  290. package/build/implementations/http/hono-stream/index.js.map +0 -1
  291. package/build/implementations/http/hono-stream/index.test.js +0 -1383
  292. package/build/implementations/http/hono-stream/index.test.js.map +0 -1
  293. package/build/implementations/http/hono-stream/types.d.ts +0 -15
  294. package/build/implementations/http/hono-stream/types.js +0 -2
  295. package/build/implementations/http/hono-stream/types.js.map +0 -1
  296. package/src/implementations/http/express-rpc/README.md +0 -280
  297. package/src/implementations/http/express-rpc/error-taxonomy.test.ts +0 -103
  298. package/src/implementations/http/express-rpc/index.test.ts +0 -957
  299. package/src/implementations/http/express-rpc/index.ts +0 -327
  300. package/src/implementations/http/express-rpc/types.ts +0 -16
  301. package/src/implementations/http/hono-api/README.md +0 -284
  302. package/src/implementations/http/hono-api/error-taxonomy.test.ts +0 -179
  303. package/src/implementations/http/hono-api/index.test.ts +0 -1341
  304. package/src/implementations/http/hono-api/index.ts +0 -519
  305. package/src/implementations/http/hono-api/types.ts +0 -16
  306. package/src/implementations/http/hono-rpc/README.md +0 -357
  307. package/src/implementations/http/hono-rpc/error-taxonomy.test.ts +0 -82
  308. package/src/implementations/http/hono-rpc/index.test.ts +0 -1107
  309. package/src/implementations/http/hono-rpc/index.ts +0 -320
  310. package/src/implementations/http/hono-rpc/types.ts +0 -16
  311. package/src/implementations/http/hono-stream/README.md +0 -559
  312. package/src/implementations/http/hono-stream/error-taxonomy.test.ts +0 -178
  313. package/src/implementations/http/hono-stream/index.test.ts +0 -1804
  314. package/src/implementations/http/hono-stream/index.ts +0 -622
  315. package/src/implementations/http/hono-stream/types.ts +0 -20
  316. /package/build/{implementations/http/express-rpc/error-taxonomy.test.d.ts → create-http-stream.test.d.ts} +0 -0
  317. /package/build/{implementations/http/express-rpc/index.test.d.ts → create-http.test.d.ts} +0 -0
  318. /package/build/{implementations/http/hono-api/error-taxonomy.test.d.ts → create-stream.test.d.ts} +0 -0
  319. /package/build/{implementations/http/hono-api/index.test.d.ts → create.test.d.ts} +0 -0
  320. /package/build/implementations/http/{hono-rpc/error-taxonomy.test.d.ts → error-dispatch.test.d.ts} +0 -0
  321. /package/build/implementations/http/{hono-rpc/index.test.d.ts → hono/handlers/http-stream.test.d.ts} +0 -0
  322. /package/build/implementations/http/{hono-stream/error-taxonomy.test.d.ts → hono/handlers/http.test.d.ts} +0 -0
  323. /package/build/implementations/http/{hono-stream/index.test.d.ts → hono/handlers/rpc.test.d.ts} +0 -0
  324. /package/build/implementations/http/{express-rpc → hono}/types.js +0 -0
  325. /package/build/{implementations/http/hono-api/types.js → types.js} +0 -0
@@ -0,0 +1,223 @@
1
+ # Hono Template: {{Name}}
2
+
3
+ A single `HonoAppBuilder` can host all four procedure kinds — RPC (`Create`), RPC stream (`CreateStream`), HTTP REST (`CreateHttp`), and HTTP stream (`CreateHttpStream`) — registered against one `Procedures` factory and mounted with one `register(...)` call. This template demonstrates that.
4
+
5
+ ## Implementation — `{{Name}}.hono.ts`
6
+
7
+ ```typescript
8
+ import { Procedures } from 'ts-procedures'
9
+ import type { RPCConfig } from 'ts-procedures/http'
10
+ import { defineErrorTaxonomy, HonoAppBuilder } from 'ts-procedures/hono'
11
+ import { Type } from 'typebox'
12
+
13
+ // ─── Context ──────────────────────────────────────────────
14
+
15
+ type {{Name}}Context = {
16
+ userId: string
17
+ requestId: string
18
+ }
19
+
20
+ // ─── Procedures ───────────────────────────────────────────
21
+ // Capture the factory in a single `procs` variable so every kind shares
22
+ // the same context type and the same final register() call.
23
+
24
+ const procs = Procedures<{{Name}}Context, RPCConfig>()
25
+
26
+ // RPC — `Create`. Mounted at POST /api/{{kebab}}/get-item/1
27
+ export const { GetItem } = procs.Create(
28
+ 'GetItem',
29
+ {
30
+ scope: '{{kebab}}',
31
+ version: 1,
32
+ description: 'Fetch an item by id (RPC).',
33
+ schema: {
34
+ params: Type.Object({
35
+ id: Type.String(),
36
+ }),
37
+ returnType: Type.Object({
38
+ id: Type.String(),
39
+ name: Type.String(),
40
+ }),
41
+ },
42
+ },
43
+ async (ctx, params) => {
44
+ // TODO: implement
45
+ return { id: params.id, name: 'Example' }
46
+ }
47
+ )
48
+
49
+ // RPC stream — `CreateStream`. Mounted at POST /api/{{kebab}}/stream-events/1 (SSE)
50
+ export const { StreamEvents } = procs.CreateStream(
51
+ 'StreamEvents',
52
+ {
53
+ scope: '{{kebab}}',
54
+ version: 1,
55
+ description: 'Stream events for the given subject (rpc-stream / SSE).',
56
+ schema: {
57
+ params: Type.Object({
58
+ subject: Type.String(),
59
+ }),
60
+ yieldType: Type.Object({
61
+ seq: Type.Number(),
62
+ message: Type.String(),
63
+ }),
64
+ },
65
+ },
66
+ async function* (ctx, params) {
67
+ // ctx.signal is guaranteed for streams. Pass it to all downstream async work.
68
+ for (let seq = 0; seq < 3; seq++) {
69
+ if (ctx.signal.aborted) return
70
+ yield { seq, message: `event-${params.subject}-${seq}` }
71
+ }
72
+ }
73
+ )
74
+
75
+ // HTTP REST — `CreateHttp`. Mounted at GET /api/{{kebab}}/:id
76
+ export const { GetUser } = procs.CreateHttp(
77
+ 'GetUser',
78
+ {
79
+ path: '/{{kebab}}/:id',
80
+ method: 'get',
81
+ description: 'Fetch a user (REST).',
82
+ schema: {
83
+ req: {
84
+ pathParams: Type.Object({ id: Type.String() }),
85
+ },
86
+ res: {
87
+ body: Type.Object({
88
+ id: Type.String(),
89
+ name: Type.String(),
90
+ }),
91
+ },
92
+ },
93
+ },
94
+ async (ctx, { pathParams }) => {
95
+ // TODO: implement
96
+ return { id: pathParams.id, name: 'Example' }
97
+ }
98
+ )
99
+
100
+ // HTTP stream — `CreateHttpStream`. Mounted at GET /api/{{kebab}}/:id/watch (text/event-stream)
101
+ export const { WatchUser } = procs.CreateHttpStream(
102
+ 'WatchUser',
103
+ {
104
+ path: '/{{kebab}}/:id/watch',
105
+ method: 'get',
106
+ description: 'Server-sent stream of user updates (http-stream).',
107
+ schema: {
108
+ req: {
109
+ pathParams: Type.Object({ id: Type.String() }),
110
+ },
111
+ yield: Type.Object({
112
+ id: Type.String(),
113
+ revision: Type.Number(),
114
+ }),
115
+ },
116
+ },
117
+ async function* (ctx, { pathParams }) {
118
+ for (let revision = 1; revision <= 3; revision++) {
119
+ if (ctx.signal.aborted) return
120
+ yield { id: pathParams.id, revision }
121
+ }
122
+ }
123
+ )
124
+
125
+ // ─── Error Taxonomy ───────────────────────────────────────
126
+ // Declare the error classes this service throws. Framework errors
127
+ // (ProcedureValidationError → 400, ctx.error() → 500) are caught by the
128
+ // default taxonomy automatically. Add your own classes here — handlers just
129
+ // `throw` them and the builder serializes via this map. See
130
+ // docs/http-integrations.md#error-handling for the full contract.
131
+
132
+ const {{name}}Errors = defineErrorTaxonomy({
133
+ // Example — replace with your app's error classes:
134
+ // NotFoundError: { class: NotFoundError, statusCode: 404 },
135
+ // AuthError: { class: AuthError, statusCode: 401 },
136
+ })
137
+
138
+ // ─── Hono App Builder ─────────────────────────────────────
139
+ // One builder, one register() call, all four kinds. Config is stratified by
140
+ // kind: rpc.{onSuccess}, api.{queryParser, onSuccess}, stream.{...}. Cross-cutting
141
+ // concerns (errors, unknownError, onError, onRequestError, onRequestStart/End,
142
+ // pathPrefix) live at the top level. See src/implementations/http/hono/types.ts.
143
+
144
+ // Optional observers (uncomment as needed):
145
+ // onRequestStart: (c) => {...} // every inbound request (all kinds)
146
+ // rpc: { onSuccess: (procedure, c) => {...} } // successful RPC (Create) responses
147
+ // api: { onSuccess: (procedure, c) => {...} } // successful REST (CreateHttp) responses
148
+ // stream: { onStreamStart: (procedure, c, mode) => {...}, onStreamEnd: (procedure, c, mode) => {...} }
149
+
150
+ const {{name}}Builder = new HonoAppBuilder({
151
+ pathPrefix: '/api',
152
+ errors: {{name}}Errors,
153
+ unknownError: {
154
+ statusCode: 500,
155
+ toResponse: () => ({ name: 'InternalServerError', message: 'Unexpected error' }),
156
+ onCatch: (err, { procedure }) => console.error(`[${procedure.name}]`, err),
157
+ },
158
+ })
159
+ .register(procs, (c) => ({
160
+ userId: c.req.header('x-user-id') || 'anonymous',
161
+ requestId: c.req.header('x-request-id') || crypto.randomUUID(),
162
+ }))
163
+
164
+ export const {{name}}App = {{name}}Builder.build()
165
+
166
+ // Route map:
167
+ // POST /api/{{kebab}}/get-item/1 → RPC (Create)
168
+ // POST /api/{{kebab}}/stream-events/1 → RPC stream (CreateStream, SSE)
169
+ // GET /api/{{kebab}}/:id → REST (CreateHttp)
170
+ // GET /api/{{kebab}}/:id/watch → HTTP stream (CreateHttpStream, SSE)
171
+
172
+ // Documentation: {{name}}Builder.docs or {{name}}Builder.toDocEnvelope()
173
+ ```
174
+
175
+ ## Test — `{{Name}}.hono.test.ts`
176
+
177
+ ```typescript
178
+ import { describe, test, expect } from 'vitest'
179
+ import { {{name}}App } from './{{Name}}.hono'
180
+
181
+ describe('{{Name}} Hono — all four kinds', () => {
182
+ test('Create (RPC) — POST /api/{{kebab}}/get-item/1', async () => {
183
+ const res = await {{name}}App.request('/api/{{kebab}}/get-item/1', {
184
+ method: 'POST',
185
+ headers: { 'Content-Type': 'application/json' },
186
+ body: JSON.stringify({ id: 'item-1' }),
187
+ })
188
+ expect(res.status).toBe(200)
189
+ expect(await res.json()).toEqual({ id: 'item-1', name: 'Example' })
190
+ })
191
+
192
+ test('CreateStream (rpc-stream) — POST /api/{{kebab}}/stream-events/1 yields SSE', async () => {
193
+ const res = await {{name}}App.request('/api/{{kebab}}/stream-events/1', {
194
+ method: 'POST',
195
+ headers: { 'Content-Type': 'application/json' },
196
+ body: JSON.stringify({ subject: 'orders' }),
197
+ })
198
+ expect(res.status).toBe(200)
199
+ expect(res.headers.get('content-type') ?? '').toContain('text/event-stream')
200
+
201
+ const text = await res.text()
202
+ // Yielded events are emitted as SSE `data:` frames.
203
+ expect(text).toContain('event-orders-0')
204
+ expect(text).toContain('event-orders-2')
205
+ })
206
+
207
+ test('CreateHttp (REST) — GET /api/{{kebab}}/:id', async () => {
208
+ const res = await {{name}}App.request('/api/{{kebab}}/u-1')
209
+ expect(res.status).toBe(200)
210
+ expect(await res.json()).toEqual({ id: 'u-1', name: 'Example' })
211
+ })
212
+
213
+ test('CreateHttpStream (http-stream) — GET /api/{{kebab}}/:id/watch yields SSE', async () => {
214
+ const res = await {{name}}App.request('/api/{{kebab}}/u-1/watch')
215
+ expect(res.status).toBe(200)
216
+ expect(res.headers.get('content-type') ?? '').toContain('text/event-stream')
217
+
218
+ const text = await res.text()
219
+ expect(text).toContain('"revision":1')
220
+ expect(text).toContain('"revision":3')
221
+ })
222
+ })
223
+ ```
@@ -26,18 +26,15 @@ import { ProcedureError, ProcedureValidationError, ProcedureYieldValidationError
26
26
  // HTTP types
27
27
  import type { RPCConfig, RPCHttpRouteDoc, StreamHttpRouteDoc, StreamMode } from 'ts-procedures/http'
28
28
 
29
- // Express RPC
30
- import { ExpressRPCAppBuilder } from 'ts-procedures/express-rpc'
31
-
32
29
  // Hono RPC
33
- import { HonoRPCAppBuilder } from 'ts-procedures/hono-rpc'
30
+ import { HonoAppBuilder } from 'ts-procedures/hono'
34
31
 
35
32
  // Hono Streaming
36
- import { HonoStreamAppBuilder, sse } from 'ts-procedures/hono-stream'
33
+ import { HonoAppBuilder, sse } from 'ts-procedures/hono'
37
34
 
38
35
  // Hono API (REST-style)
39
- import { HonoAPIAppBuilder } from 'ts-procedures/hono-api'
40
- import type { APIConfig, APIInput } from 'ts-procedures/hono-api'
36
+ import { HonoAppBuilder } from 'ts-procedures/hono'
37
+ import type { APIConfig, APIInput } from 'ts-procedures/hono'
41
38
 
42
39
  // Doc Registry — compose route docs from multiple builders
43
40
  import { DocRegistry } from 'ts-procedures/http-docs'
@@ -114,31 +111,12 @@ const { StreamEvents } = CreateStream(
114
111
  )
115
112
  ```
116
113
 
117
- ## Express RPC Pattern
118
-
119
- ```typescript
120
- import { ExpressRPCAppBuilder } from 'ts-procedures/express-rpc'
121
- import type { RPCConfig } from 'ts-procedures/http'
122
-
123
- const RPC = Procedures<AppContext, RPCConfig>()
124
-
125
- RPC.Create('GetUser', {
126
- scope: 'users', version: 1,
127
- schema: { params: Type.Object({ id: Type.String() }) },
128
- }, async (ctx, params) => fetchUser(params.id))
129
-
130
- const app = new ExpressRPCAppBuilder({ pathPrefix: '/api' })
131
- .register(RPC, async (req) => ({ userId: await authenticate(req) }))
132
- .build()
133
- // POST /api/users/get-user/1
134
- ```
135
-
136
114
  ## Hono RPC Pattern
137
115
 
138
116
  ```typescript
139
- import { HonoRPCAppBuilder } from 'ts-procedures/hono-rpc'
117
+ import { HonoAppBuilder } from 'ts-procedures/hono'
140
118
 
141
- const app = new HonoRPCAppBuilder({ pathPrefix: '/api' })
119
+ const app = new HonoAppBuilder({ pathPrefix: '/api' })
142
120
  .register(RPC, (c) => ({ userId: c.req.header('x-user-id') }))
143
121
  .build()
144
122
  ```
@@ -146,7 +124,7 @@ const app = new HonoRPCAppBuilder({ pathPrefix: '/api' })
146
124
  ## Hono Streaming Pattern
147
125
 
148
126
  ```typescript
149
- import { HonoStreamAppBuilder, sse } from 'ts-procedures/hono-stream'
127
+ import { HonoAppBuilder, sse } from 'ts-procedures/hono'
150
128
 
151
129
  const StreamRPC = Procedures<AppContext, RPCConfig>()
152
130
 
@@ -160,43 +138,53 @@ StreamRPC.CreateStream('Feed', {
160
138
  }
161
139
  })
162
140
 
163
- const app = new HonoStreamAppBuilder({ defaultStreamMode: 'sse' })
141
+ const app = new HonoAppBuilder({ defaultStreamMode: 'sse' })
164
142
  .register(StreamRPC, (c) => ({ userId: c.req.header('x-user-id') }))
165
143
  .build()
166
144
  // GET|POST /events/feed/1
167
145
  ```
168
146
 
169
- ## Hono API Pattern (REST-style)
147
+ ## Hono API Pattern (REST-style) — v8 `CreateHttp`
148
+
149
+ In v8, HTTP routes use `CreateHttp` (not `Create + APIConfig`). `schema.input` is renamed `schema.req`. The factory needs no `APIConfig` type parameter.
170
150
 
171
151
  ```typescript
172
- import { HonoAPIAppBuilder } from 'ts-procedures/hono-api'
173
- import type { APIConfig } from 'ts-procedures/http'
152
+ import { HonoAppBuilder } from 'ts-procedures/hono'
174
153
 
175
- const API = Procedures<AppContext, APIConfig>()
154
+ const API = Procedures<AppContext>()
176
155
 
177
- API.Create('GetUser', {
156
+ API.CreateHttp('GetUser', {
178
157
  path: '/users/:id', method: 'get',
179
158
  schema: {
180
- input: { pathParams: Type.Object({ id: Type.String() }) },
159
+ req: { pathParams: Type.Object({ id: Type.String() }) },
160
+ res: { body: Type.Object({ id: Type.String(), name: Type.String() }) },
181
161
  },
182
162
  }, async (ctx, { pathParams }) => fetchUser(pathParams.id))
183
163
 
184
- API.Create('CreateUser', {
164
+ API.CreateHttp('CreateUser', {
185
165
  path: '/users', method: 'post',
186
166
  schema: {
187
- input: { body: Type.Object({ name: Type.String() }) },
167
+ req: { body: Type.Object({ name: Type.String() }) },
188
168
  },
189
169
  }, async (ctx, { body }) => createUser(body))
190
170
 
191
- const app = new HonoAPIAppBuilder({ pathPrefix: '/api' })
171
+ const app = new HonoAppBuilder({ pathPrefix: '/api' })
192
172
  .register(API, (c) => ({ userId: c.req.header('x-user-id') }))
193
173
  .build()
194
174
  // GET /api/users/:id → 200, POST /api/users → 201
195
175
  ```
196
176
 
177
+ **v7 → v8 migration:**
178
+
179
+ 1. `Procedures<Ctx, APIConfig>()` → `Procedures<Ctx>()`
180
+ 2. `.Create(` → `.CreateHttp(` for HTTP routes
181
+ 3. `schema.input` → `schema.req` (same channels: `pathParams`, `query`, `body`, `headers`)
182
+ 4. Move response type to `schema.res.body` (optional)
183
+ 5. Re-run `npx ts-procedures-codegen`
184
+
197
185
  ## Astro adapter
198
186
 
199
- Catch-all endpoint pattern. Build Hono apps once with HonoAPI/RPC/Stream builders, mount via `createAstroHandler` in `src/pages/api/[...rest].ts` with `pathPrefix: '/api'`. Read Astro context inside factory closures with `getAstroContext(c)`. Multi-app dispatch is first-non-404-wins. Express builders are not supported.
187
+ Catch-all endpoint pattern. Build Hono apps once with `HonoAppBuilder`, mount via `createAstroHandler` in `src/pages/api/[...rest].ts` with `pathPrefix: '/api'`. Read Astro context inside factory closures with `getAstroContext(c)`. Multi-app dispatch is first-non-404-wins.
200
188
 
201
189
  ## Error Handling
202
190
 
@@ -209,7 +197,7 @@ Catch-all endpoint pattern. Build Hono apps once with HonoAPI/RPC/Stream builder
209
197
 
210
198
  ### Error Taxonomy (required for custom errors)
211
199
 
212
- `defineErrorTaxonomy` maps error classes to HTTP responses declaratively. Works with every HTTP builder (`hono-api`, `hono-rpc`, `express-rpc`, `hono-stream` pre-stream).
200
+ `defineErrorTaxonomy` maps error classes to HTTP responses declaratively. Works with `HonoAppBuilder` for `rpc`, `http`, and pre-stream paths (`rpc-stream` / `http-stream`).
213
201
 
214
202
  Do NOT write `onError` `instanceof` ladders — that's anti-pattern #20. Use the taxonomy instead:
215
203
 
@@ -239,13 +227,13 @@ const appErrors = defineErrorTaxonomy({
239
227
  },
240
228
  })
241
229
 
242
- new HonoAPIAppBuilder({
230
+ new HonoAppBuilder({
243
231
  errors: appErrors,
244
232
  unknownError: { statusCode: 500, toResponse: () => ({ name: 'InternalServerError' }) },
245
233
  })
246
234
  ```
247
235
 
248
- Handlers throw the error classes directly — the builder auto-serializes. `onError` is the first-class imperative peer when you want to handle errors in one callback instead (both modes coexist). In v6 `HonoStreamAppBuilder.onPreStreamError` was renamed to `onError`. Cross-cutting `onRequestError` observer fires for every caught error.
236
+ Handlers throw the error classes directly — the builder auto-serializes. `onError` is the first-class imperative peer when you want to handle errors in one callback instead (both modes coexist). In v6 `HonoAppBuilder.onPreStreamError` was renamed to `onError`. Cross-cutting `onRequestError` observer fires for every caught error.
249
237
 
250
238
  ### Per-route errors (typed)
251
239
 
@@ -313,10 +301,7 @@ onRequestStart → factoryContext() → validation → onStreamStart → handler
313
301
  - **TypeBox** (`import { Type } from 'typebox'`)
314
302
 
315
303
  **Which HTTP implementation?**
316
- - Express → `ExpressRPCAppBuilder`
317
- - Hono (standard) → `HonoRPCAppBuilder`
318
- - Hono (streaming) → `HonoStreamAppBuilder`
319
- - Hono (REST-style, per-channel input) → `HonoAPIAppBuilder`
304
+ - Hono (RPC, streams, REST, REST streams) → `HonoAppBuilder`
320
305
 
321
306
  **Stream mode?**
322
307
  - Browser EventSource → `'sse'` (default)
@@ -329,13 +314,14 @@ onRequestStart → factoryContext() → validation → onStreamStart → handler
329
314
  3. **Never put validation logic in handler** — use `schema.params`
330
315
  4. **Never ignore ctx.signal** — pass to all async calls
331
316
  5. **Never skip signal.aborted check in stream loops** — causes resource leaks
332
- 6. **Never register Create procedures with HonoStreamAppBuilder** — they're silently ignored
317
+ 6. **Never register Create procedures with HonoAppBuilder** — they're silently ignored
333
318
  7. **Never use plain JSON Schema objects** — use TypeBox builders
334
319
  8. **Never swallow errors without re-throwing** — hides failures
335
320
  9. **Never assume extra params fields survive** — `removeAdditional: true` strips them
336
321
  10. **Never manually parse types AJV coerces** — `coerceTypes: true` handles it
337
322
  11. **Never define both schema.params and schema.input** — mutually exclusive, throws ProcedureRegistrationError
338
323
  12. **Never catch raw DOMException/TypeError from generated callables** — catch `ClientTimeoutError`, `ClientAbortError`, `ClientNetworkError` instead; or use `.safe()` for Result-based narrowing
324
+ 13. **Never use `Create` for HTTP routes (v8+)** — use `CreateHttp` (unary) or `CreateHttpStream` (streaming); `schema.input` → `schema.req`; `Procedures<Ctx, APIConfig>()` → `Procedures<Ctx>()`
339
325
 
340
326
  ## Testing
341
327
 
@@ -26,18 +26,15 @@ import { ProcedureError, ProcedureValidationError, ProcedureYieldValidationError
26
26
  // HTTP types
27
27
  import type { RPCConfig, RPCHttpRouteDoc, StreamHttpRouteDoc, StreamMode } from 'ts-procedures/http'
28
28
 
29
- // Express RPC
30
- import { ExpressRPCAppBuilder } from 'ts-procedures/express-rpc'
31
-
32
29
  // Hono RPC
33
- import { HonoRPCAppBuilder } from 'ts-procedures/hono-rpc'
30
+ import { HonoAppBuilder } from 'ts-procedures/hono'
34
31
 
35
32
  // Hono Streaming
36
- import { HonoStreamAppBuilder, sse } from 'ts-procedures/hono-stream'
33
+ import { HonoAppBuilder, sse } from 'ts-procedures/hono'
37
34
 
38
35
  // Hono API (REST-style)
39
- import { HonoAPIAppBuilder } from 'ts-procedures/hono-api'
40
- import type { APIConfig, APIInput } from 'ts-procedures/hono-api'
36
+ import { HonoAppBuilder } from 'ts-procedures/hono'
37
+ import type { APIConfig, APIInput } from 'ts-procedures/hono'
41
38
 
42
39
  // Doc Registry — compose route docs from multiple builders
43
40
  import { DocRegistry } from 'ts-procedures/http-docs'
@@ -114,31 +111,12 @@ const { StreamEvents } = CreateStream(
114
111
  )
115
112
  ```
116
113
 
117
- ## Express RPC Pattern
118
-
119
- ```typescript
120
- import { ExpressRPCAppBuilder } from 'ts-procedures/express-rpc'
121
- import type { RPCConfig } from 'ts-procedures/http'
122
-
123
- const RPC = Procedures<AppContext, RPCConfig>()
124
-
125
- RPC.Create('GetUser', {
126
- scope: 'users', version: 1,
127
- schema: { params: Type.Object({ id: Type.String() }) },
128
- }, async (ctx, params) => fetchUser(params.id))
129
-
130
- const app = new ExpressRPCAppBuilder({ pathPrefix: '/api' })
131
- .register(RPC, async (req) => ({ userId: await authenticate(req) }))
132
- .build()
133
- // POST /api/users/get-user/1
134
- ```
135
-
136
114
  ## Hono RPC Pattern
137
115
 
138
116
  ```typescript
139
- import { HonoRPCAppBuilder } from 'ts-procedures/hono-rpc'
117
+ import { HonoAppBuilder } from 'ts-procedures/hono'
140
118
 
141
- const app = new HonoRPCAppBuilder({ pathPrefix: '/api' })
119
+ const app = new HonoAppBuilder({ pathPrefix: '/api' })
142
120
  .register(RPC, (c) => ({ userId: c.req.header('x-user-id') }))
143
121
  .build()
144
122
  ```
@@ -146,7 +124,7 @@ const app = new HonoRPCAppBuilder({ pathPrefix: '/api' })
146
124
  ## Hono Streaming Pattern
147
125
 
148
126
  ```typescript
149
- import { HonoStreamAppBuilder, sse } from 'ts-procedures/hono-stream'
127
+ import { HonoAppBuilder, sse } from 'ts-procedures/hono'
150
128
 
151
129
  const StreamRPC = Procedures<AppContext, RPCConfig>()
152
130
 
@@ -160,43 +138,53 @@ StreamRPC.CreateStream('Feed', {
160
138
  }
161
139
  })
162
140
 
163
- const app = new HonoStreamAppBuilder({ defaultStreamMode: 'sse' })
141
+ const app = new HonoAppBuilder({ defaultStreamMode: 'sse' })
164
142
  .register(StreamRPC, (c) => ({ userId: c.req.header('x-user-id') }))
165
143
  .build()
166
144
  // GET|POST /events/feed/1
167
145
  ```
168
146
 
169
- ## Hono API Pattern (REST-style)
147
+ ## Hono API Pattern (REST-style) — v8 `CreateHttp`
148
+
149
+ In v8, HTTP routes use `CreateHttp` (not `Create + APIConfig`). `schema.input` is renamed `schema.req`. The factory needs no `APIConfig` type parameter.
170
150
 
171
151
  ```typescript
172
- import { HonoAPIAppBuilder } from 'ts-procedures/hono-api'
173
- import type { APIConfig } from 'ts-procedures/http'
152
+ import { HonoAppBuilder } from 'ts-procedures/hono'
174
153
 
175
- const API = Procedures<AppContext, APIConfig>()
154
+ const API = Procedures<AppContext>()
176
155
 
177
- API.Create('GetUser', {
156
+ API.CreateHttp('GetUser', {
178
157
  path: '/users/:id', method: 'get',
179
158
  schema: {
180
- input: { pathParams: Type.Object({ id: Type.String() }) },
159
+ req: { pathParams: Type.Object({ id: Type.String() }) },
160
+ res: { body: Type.Object({ id: Type.String(), name: Type.String() }) },
181
161
  },
182
162
  }, async (ctx, { pathParams }) => fetchUser(pathParams.id))
183
163
 
184
- API.Create('CreateUser', {
164
+ API.CreateHttp('CreateUser', {
185
165
  path: '/users', method: 'post',
186
166
  schema: {
187
- input: { body: Type.Object({ name: Type.String() }) },
167
+ req: { body: Type.Object({ name: Type.String() }) },
188
168
  },
189
169
  }, async (ctx, { body }) => createUser(body))
190
170
 
191
- const app = new HonoAPIAppBuilder({ pathPrefix: '/api' })
171
+ const app = new HonoAppBuilder({ pathPrefix: '/api' })
192
172
  .register(API, (c) => ({ userId: c.req.header('x-user-id') }))
193
173
  .build()
194
174
  // GET /api/users/:id → 200, POST /api/users → 201
195
175
  ```
196
176
 
177
+ **v7 → v8 migration:**
178
+
179
+ 1. `Procedures<Ctx, APIConfig>()` → `Procedures<Ctx>()`
180
+ 2. `.Create(` → `.CreateHttp(` for HTTP routes
181
+ 3. `schema.input` → `schema.req` (same channels: `pathParams`, `query`, `body`, `headers`)
182
+ 4. Move response type to `schema.res.body` (optional)
183
+ 5. Re-run `npx ts-procedures-codegen`
184
+
197
185
  ## Astro adapter
198
186
 
199
- Catch-all endpoint pattern. Build Hono apps once with HonoAPI/RPC/Stream builders, mount via `createAstroHandler` in `src/pages/api/[...rest].ts` with `pathPrefix: '/api'`. Read Astro context inside factory closures with `getAstroContext(c)`. Multi-app dispatch is first-non-404-wins. Express builders are not supported.
187
+ Catch-all endpoint pattern. Build Hono apps once with `HonoAppBuilder`, mount via `createAstroHandler` in `src/pages/api/[...rest].ts` with `pathPrefix: '/api'`. Read Astro context inside factory closures with `getAstroContext(c)`. Multi-app dispatch is first-non-404-wins.
200
188
 
201
189
  ## Error Handling
202
190
 
@@ -209,7 +197,7 @@ Catch-all endpoint pattern. Build Hono apps once with HonoAPI/RPC/Stream builder
209
197
 
210
198
  ### Error Taxonomy (required for custom errors)
211
199
 
212
- `defineErrorTaxonomy` maps error classes to HTTP responses declaratively. Works with every HTTP builder (`hono-api`, `hono-rpc`, `express-rpc`, `hono-stream` pre-stream).
200
+ `defineErrorTaxonomy` maps error classes to HTTP responses declaratively. Works with `HonoAppBuilder` for `rpc`, `http`, and pre-stream paths (`rpc-stream` / `http-stream`).
213
201
 
214
202
  Do NOT write `onError` `instanceof` ladders — that's anti-pattern #20. Use the taxonomy instead:
215
203
 
@@ -239,13 +227,13 @@ const appErrors = defineErrorTaxonomy({
239
227
  },
240
228
  })
241
229
 
242
- new HonoAPIAppBuilder({
230
+ new HonoAppBuilder({
243
231
  errors: appErrors,
244
232
  unknownError: { statusCode: 500, toResponse: () => ({ name: 'InternalServerError' }) },
245
233
  })
246
234
  ```
247
235
 
248
- Handlers throw the error classes directly — the builder auto-serializes. `onError` is the first-class imperative peer when you want to handle errors in one callback instead (both modes coexist). In v6 `HonoStreamAppBuilder.onPreStreamError` was renamed to `onError`. Cross-cutting `onRequestError` observer fires for every caught error.
236
+ Handlers throw the error classes directly — the builder auto-serializes. `onError` is the first-class imperative peer when you want to handle errors in one callback instead (both modes coexist). In v6 `HonoAppBuilder.onPreStreamError` was renamed to `onError`. Cross-cutting `onRequestError` observer fires for every caught error.
249
237
 
250
238
  ### Per-route errors (typed)
251
239
 
@@ -313,10 +301,7 @@ onRequestStart → factoryContext() → validation → onStreamStart → handler
313
301
  - **TypeBox** (`import { Type } from 'typebox'`)
314
302
 
315
303
  **Which HTTP implementation?**
316
- - Express → `ExpressRPCAppBuilder`
317
- - Hono (standard) → `HonoRPCAppBuilder`
318
- - Hono (streaming) → `HonoStreamAppBuilder`
319
- - Hono (REST-style, per-channel input) → `HonoAPIAppBuilder`
304
+ - Hono (RPC, streams, REST, REST streams) → `HonoAppBuilder`
320
305
 
321
306
  **Stream mode?**
322
307
  - Browser EventSource → `'sse'` (default)
@@ -329,13 +314,14 @@ onRequestStart → factoryContext() → validation → onStreamStart → handler
329
314
  3. **Never put validation logic in handler** — use `schema.params`
330
315
  4. **Never ignore ctx.signal** — pass to all async calls
331
316
  5. **Never skip signal.aborted check in stream loops** — causes resource leaks
332
- 6. **Never register Create procedures with HonoStreamAppBuilder** — they're silently ignored
317
+ 6. **Never register Create procedures with HonoAppBuilder** — they're silently ignored
333
318
  7. **Never use plain JSON Schema objects** — use TypeBox builders
334
319
  8. **Never swallow errors without re-throwing** — hides failures
335
320
  9. **Never assume extra params fields survive** — `removeAdditional: true` strips them
336
321
  10. **Never manually parse types AJV coerces** — `coerceTypes: true` handles it
337
322
  11. **Never define both schema.params and schema.input** — mutually exclusive, throws ProcedureRegistrationError
338
323
  12. **Never catch raw DOMException/TypeError from generated callables** — catch `ClientTimeoutError`, `ClientAbortError`, `ClientNetworkError` instead; or use `.safe()` for Result-based narrowing
324
+ 13. **Never use `Create` for HTTP routes (v8+)** — use `CreateHttp` (unary) or `CreateHttpStream` (streaming); `schema.input` → `schema.req`; `Procedures<Ctx, APIConfig>()` → `Procedures<Ctx>()`
339
325
 
340
326
  ## Testing
341
327
 
@@ -84,7 +84,10 @@ export async function executeCall(config) {
84
84
  scope: descriptor.scope,
85
85
  });
86
86
  }
87
- // 8. Return the body
87
+ // 8. Return the body (or { body, headers } when the route declares res.headers)
88
+ if (descriptor.responseHeadersDeclared) {
89
+ return { body: response.body, headers: response.headers };
90
+ }
88
91
  return response.body;
89
92
  }
90
93
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"call.js","sourceRoot":"","sources":["../../src/client/call.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"call.js","sourceRoot":"","sources":["../../src/client/call.ts"],"names":[],"mappings":"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"}
@@ -270,6 +270,29 @@ describe('executeCall', () => {
270
270
  });
271
271
  expect(observedMeta).toEqual({ traceId: 'override', attempt: 1 });
272
272
  });
273
+ // ── responseHeadersDeclared ──
274
+ it('returns bare body when responseHeadersDeclared is not set', async () => {
275
+ const adapter = makeAdapter({ body: { id: 'abc' } });
276
+ const result = await run({ adapter, descriptor: makeDescriptor() });
277
+ expect(result).toEqual({ id: 'abc' });
278
+ });
279
+ it('returns { body, headers } when responseHeadersDeclared is true', async () => {
280
+ const adapter = {
281
+ request: vi.fn(async () => ({
282
+ status: 200,
283
+ headers: { 'x-rate-limit': '99' },
284
+ body: { id: 'abc' },
285
+ })),
286
+ stream: vi.fn(async () => { throw new Error('not expected'); }),
287
+ };
288
+ const descriptor = makeDescriptor({ responseHeadersDeclared: true });
289
+ const result = await run({
290
+ adapter,
291
+ descriptor,
292
+ });
293
+ expect(result).toEqual({ body: { id: 'abc' }, headers: { 'x-rate-limit': '99' } });
294
+ expect(result.headers['x-rate-limit']).toBe('99');
295
+ });
273
296
  });
274
297
  describe('executeCall classifier integration', () => {
275
298
  it('throws ClientNetworkError when adapter throws TypeError', async () => {