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
package/src/create.ts ADDED
@@ -0,0 +1,172 @@
1
+ import { ProcedureError, ProcedureRegistrationError, ProcedureValidationError } from './errors.js'
2
+ import { computeSchema } from './schema/compute-schema.js'
3
+ import { Prettify, TSchemaLib } from './schema/types.js'
4
+ import { captureDefinitionInfo } from './stack-utils.js'
5
+ import {
6
+ TBuilderConfig,
7
+ THttpProcedureRegistration,
8
+ THttpStreamProcedureRegistration,
9
+ TLocalContext,
10
+ TProcedureRegistration,
11
+ TStreamProcedureRegistration,
12
+ } from './types.js'
13
+
14
+ export type CreateBuilderArg<TContext, TExtendedConfig> = {
15
+ config?: TBuilderConfig
16
+ onCreate?: (
17
+ procedure:
18
+ | TProcedureRegistration<TContext, TExtendedConfig>
19
+ | TStreamProcedureRegistration<TContext, TExtendedConfig>
20
+ ) => void
21
+ }
22
+
23
+ export function makeCreate<TContext, TExtendedConfig>(
24
+ procedures: Map<
25
+ string,
26
+ | TProcedureRegistration<TContext, TExtendedConfig>
27
+ | TStreamProcedureRegistration<TContext, TExtendedConfig>
28
+ | THttpProcedureRegistration<TContext>
29
+ | THttpStreamProcedureRegistration<TContext>
30
+ >,
31
+ builder?: CreateBuilderArg<TContext, TExtendedConfig>
32
+ ) {
33
+ return function Create<TName extends string, TParams, TReturnType>(
34
+ name: TName,
35
+ config: {
36
+ description?: string
37
+ schema?: {
38
+ params?: TParams
39
+ returnType?: TReturnType
40
+ }
41
+ } & TExtendedConfig,
42
+ handler: (
43
+ ctx: Prettify<TContext & TLocalContext>,
44
+ params: TSchemaLib<TParams>
45
+ ) => Promise<TSchemaLib<TReturnType>>
46
+ ) {
47
+ // Capture definition location as first action
48
+ const definitionInfo = captureDefinitionInfo()
49
+
50
+ const HTTP_FIELDS = ['path', 'method', 'req', 'res', 'successStatus'] as const
51
+ const presentHttpFields = HTTP_FIELDS.filter((f) => (config as any)[f] !== undefined)
52
+ if (presentHttpFields.length > 0) {
53
+ throw new ProcedureRegistrationError(
54
+ name,
55
+ `HTTP fields require CreateHttp / CreateHttpStream. Procedure "${name}" has [${presentHttpFields.join(', ')}] which are not valid on Create.`,
56
+ definitionInfo,
57
+ )
58
+ }
59
+
60
+ // BEFORE computeSchema - fail fast on duplicate
61
+ if (procedures.has(name)) {
62
+ throw new Error(`Procedure with name ${name} is already registered`)
63
+ }
64
+
65
+ const { jsonSchema, validations } = computeSchema(name, config.schema, definitionInfo)
66
+
67
+ // Create error factory once at registration time (outside handler)
68
+ const errorFactory = (message: string, meta?: object) =>
69
+ new ProcedureError(name, message, meta, definitionInfo)
70
+
71
+ const registeredProcedure: TProcedureRegistration<TContext, TExtendedConfig> = {
72
+ name,
73
+ kind: 'rpc',
74
+ config: {
75
+ ...config,
76
+ description: config.description,
77
+ schema: jsonSchema,
78
+ validation: {
79
+ params: validations.params,
80
+ },
81
+ },
82
+
83
+ handler: async (ctx: Prettify<TContext>, params: TSchemaLib<TParams>) => {
84
+ try {
85
+ // Skip validation if caller has already validated or if builder config dictates noRuntimeValidation
86
+ const skipValidation =
87
+ (ctx as { isPrevalidated?: boolean }).isPrevalidated ||
88
+ builder?.config?.noRuntimeValidation
89
+
90
+ if (validations?.params && !skipValidation) {
91
+ const { errors } = validations.params(params)
92
+
93
+ if (errors) {
94
+ throw new ProcedureValidationError(
95
+ name,
96
+ `Validation error for ${name}`,
97
+ errors,
98
+ definitionInfo
99
+ )
100
+ }
101
+ }
102
+
103
+ const localCtx: TLocalContext = {
104
+ error: errorFactory,
105
+ }
106
+
107
+ // params is correctly typed at the public API boundary;
108
+ // cast here because TS cannot narrow generics inside implementations
109
+ return await handler(
110
+ { ...ctx, ...localCtx } as Prettify<TContext & TLocalContext>,
111
+ params as any
112
+ )
113
+ } catch (error: any) {
114
+ if (error instanceof ProcedureError) throw error
115
+ const err = new ProcedureError(
116
+ name,
117
+ `Error in handler for ${name} - ${error?.message}`,
118
+ undefined,
119
+ definitionInfo
120
+ )
121
+ err.cause = error
122
+ // Preserve original stack but append definition info
123
+ if (error.stack && definitionInfo.definedAt) {
124
+ const { file, line, column } = definitionInfo.definedAt
125
+ err.stack =
126
+ error.stack +
127
+ `\n--- Procedure "${name}" defined at ---\n at ${file}:${line}:${column}`
128
+ } else if (error.stack) {
129
+ err.stack = error.stack
130
+ }
131
+ throw err
132
+ }
133
+ },
134
+ }
135
+
136
+ procedures.set(name, registeredProcedure)
137
+ builder?.onCreate?.(registeredProcedure)
138
+
139
+ const info = {
140
+ name,
141
+ ...registeredProcedure.config,
142
+ }
143
+
144
+ // return so can be called directly (ie: int/unit tests)
145
+ return {
146
+ [name]: registeredProcedure.handler,
147
+ procedure: registeredProcedure.handler,
148
+ info,
149
+ } as {
150
+ [K in TName]: (
151
+ ctx: Prettify<TContext>,
152
+ params: TSchemaLib<TParams>
153
+ ) => Promise<TSchemaLib<TReturnType>>
154
+ } & {
155
+ procedure: (
156
+ ctx: Prettify<TContext>,
157
+ params: TSchemaLib<TParams>
158
+ ) => Promise<TSchemaLib<TReturnType>>
159
+ info: {
160
+ name: TName
161
+ description?: string
162
+ schema: {
163
+ params?: TParams
164
+ returnType?: TReturnType
165
+ }
166
+ validation?: {
167
+ params?: (params: any) => { errors?: any[] }
168
+ }
169
+ } & TExtendedConfig
170
+ }
171
+ }
172
+ }
package/src/exports.ts CHANGED
@@ -5,3 +5,5 @@ export * from './schema/extract-json-schema.js'
5
5
  export * from './schema/parser.js'
6
6
  export * from './schema/resolve-schema-lib.js'
7
7
  export * from './schema/types.js'
8
+ export type { HttpReturn } from './create-http.js'
9
+ export type { TCreateHttpConfig } from './types.js'
@@ -4,59 +4,46 @@ HTTP implementation builders for `ts-procedures` that create type-safe, versione
4
4
 
5
5
  ## Available Implementations
6
6
 
7
- ### RPC (Request/Response)
8
-
9
- For procedures created with `Create()` - standard request/response pattern using POST.
10
-
11
- | Framework | Package | Description |
12
- |-----------|---------|-------------|
13
- | [Express RPC](./express-rpc/README.md) | `express-rpc` | Express.js integration |
14
- | [Hono RPC](./hono-rpc/README.md) | `hono-rpc` | Hono integration (Bun, Deno, Cloudflare Workers, Node.js) |
15
-
16
- ### Streaming
17
-
18
- For procedures created with `CreateStream()` - server-sent events and streaming responses.
19
-
20
- | Framework | Package | Description |
7
+ | Framework | Subpath | Description |
21
8
  |-----------|---------|-------------|
22
- | [Hono Stream](./hono-stream/README.md) | `hono-stream` | SSE and text streaming for async generators |
9
+ | HonoAppBuilder | `ts-procedures/hono` | Unified Hono builder — dispatches RPC, RPC streams, REST, and REST streams from one `register()` call. Works on Bun, Deno, Cloudflare Workers, and Node.js. |
23
10
 
24
- ### API (REST-style)
11
+ `HonoAppBuilder` is a unified builder: one builder, one `app`, one set of cross-cutting hooks. The procedure kind drives behavior — pick the creator that matches the shape you need.
25
12
 
26
- For procedures using `schema.input` per-channel input validation with standard HTTP methods.
27
-
28
- | Framework | Package | Description |
29
- |-----------|---------|-------------|
30
- | [Hono API](./hono-api/) | `hono-api` | REST-style routing by HTTP method (GET, POST, PUT, DELETE, PATCH, HEAD) |
13
+ ### Procedure kinds and which creator to use
31
14
 
32
- ## Procedure Types
15
+ | Procedure kind | Created with | Config shape | Handler return | HTTP methods | Use case |
16
+ |----------------|--------------|--------------|----------------|--------------|----------|
17
+ | `rpc` | `Create()` | `RPCConfig` (`scope`, `version`) | `Promise<T>` | POST | Standard request/response |
18
+ | `rpc-stream` | `CreateStream()` | `RPCConfig` | `AsyncGenerator<T>` | GET, POST | RPC-style streaming (SSE / text) |
19
+ | `http` | `CreateHttp()` | `APIConfig` (`path`, `method`) | `Promise<T>` | GET, POST, PUT, DELETE, PATCH, HEAD | REST-style endpoint with `schema.req` channels |
20
+ | `http-stream` | `CreateHttpStream()` | `APIConfig` | `AsyncGenerator<T>` | GET, POST | REST-style streaming endpoint |
33
21
 
34
- | Type | Created With | Handler Return | HTTP Methods | Use Case |
35
- |------|--------------|----------------|--------------|----------|
36
- | RPC | `Create()` | `Promise<T>` | POST | Standard request/response |
37
- | Stream | `CreateStream()` | `AsyncGenerator<T>` | GET, POST | Real-time updates, SSE |
38
- | API | `Create()` | `Promise<T>` | GET, POST, PUT, DELETE, PATCH, HEAD | REST-style endpoints with per-channel input |
22
+ `HonoAppBuilder` accepts all four kinds from the same factory.
39
23
 
40
24
  ## Core Concepts
41
25
 
42
- ### Config Interface
26
+ ### Config Interfaces
43
27
 
44
- All HTTP implementations use a shared configuration interface:
28
+ RPC and RPC-stream procedures share `RPCConfig`:
45
29
 
46
30
  ```typescript
47
31
  interface RPCConfig {
48
32
  scope: string | string[] // Route path segment(s)
49
33
  version: number // API version number
34
+ errors?: string[] // Optional taxonomy keys for typed-client narrowing
50
35
  }
51
36
  ```
52
37
 
53
- #### APIConfig (REST-style)
38
+ REST-style procedures (`CreateHttp` / `CreateHttpStream`) use `APIConfig`:
54
39
 
55
40
  ```typescript
56
41
  interface APIConfig {
57
42
  path: string // Route path with Hono params (e.g., '/users/:id')
58
43
  method: HttpMethod // 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head'
59
44
  successStatus?: number // Default: POST→201, DELETE→204, others→200
45
+ scope?: string // Optional grouping for codegen file emission
46
+ errors?: string[]
60
47
  }
61
48
  ```
62
49
 
@@ -110,71 +97,94 @@ builder.register(Factory, async (c) => {
110
97
 
111
98
  All HTTP implementations automatically inject an `AbortSignal` into the handler context as `ctx.signal`. This signal aborts when the client disconnects, enabling handlers to cancel in-flight work (fetch calls, database queries, etc.).
112
99
 
113
- | Framework | Signal Source | Behavior |
114
- |-----------|-------------|----------|
115
- | Hono RPC | `c.req.raw.signal` | Web standard Request signal |
116
- | Hono Stream | `c.req.raw.signal` | Combined with internal stream AbortController via `AbortSignal.any()` |
117
- | Express RPC | Lazy `AbortController` | Created on first `ctx.signal` access, wired to `req.on('close')` |
100
+ | Framework | Procedure kind | Signal source | Behavior |
101
+ |-----------|---------------|---------------|----------|
102
+ | HonoAppBuilder | `rpc`, `http` | `c.req.raw.signal` | Web standard Request signal |
103
+ | HonoAppBuilder | `rpc-stream`, `http-stream` | `c.req.raw.signal` | Combined with internal stream AbortController via `AbortSignal.any()` |
118
104
 
119
105
  For streaming procedures, `signal.reason` is `'stream-completed'` on normal completion, allowing handlers to distinguish from client disconnection.
120
106
 
121
107
  ### Error Handling
122
108
 
123
- All four builders support two peer error-handling modes — **declarative** (`errors` taxonomy + `unknownError`) and **imperative** (`onError` callback) — plus a cross-cutting `onRequestError` observer for logging, tracing, and metrics.
109
+ Both builders support two peer error-handling modes — **declarative** (`errors` taxonomy + `unknownError`) and **imperative** (`onError` callback) — plus a cross-cutting `onRequestError` observer for logging, tracing, and metrics.
124
110
 
125
111
  Full spec (taxonomy shape, `toResponse`/`onCatch`/`match`, per-route narrowing, mid-stream caveats): **[docs/http-integrations.md § Error Handling](../../../docs/http-integrations.md#error-handling)**.
126
112
 
127
113
  ### Lifecycle Hooks
128
114
 
129
- **RPC Implementations:**
115
+ `HonoAppBuilder`'s config is **stratified**: cross-cutting hooks live at the top level, kind-specific hooks live inside `rpc:`, `api:`, and `stream:` blocks.
116
+
117
+ ```typescript
118
+ new HonoAppBuilder({
119
+ // Cross-cutting (every kind)
120
+ onRequestStart, onRequestEnd, onRequestError,
121
+ errors, unknownError, onError,
122
+
123
+ // Kind-specific blocks
124
+ rpc: { onSuccess },
125
+ api: { queryParser, onSuccess },
126
+ stream: { defaultStreamMode, onStreamStart, onStreamEnd, onMidStreamError },
127
+ })
128
+ ```
129
+
130
+ **Non-streaming flow (`rpc`, `http`):**
130
131
 
131
132
  ```
132
133
  onRequestStart → handler → onSuccess → onRequestEnd
133
134
 
134
135
  (on error)
135
136
 
136
- onError handler
137
+ onRequestError (observer)
138
+
139
+ errors taxonomy / onError fallback
137
140
 
138
141
  onRequestEnd
139
142
  ```
140
143
 
141
- **Stream Implementations:**
144
+ **Streaming flow (`rpc-stream`, `http-stream`):**
142
145
 
143
146
  ```
144
147
  onRequestStart → onStreamStart → [yields...] → onStreamEnd → onRequestEnd
145
148
 
146
149
  (on error)
147
150
 
148
- error in stream
149
-
150
- onStreamEnd
151
+ ┌──────────────────┴──────────────────┐
152
+ (pre-stream — before onStreamStart) ↓ (mid-stream — after first yield)
153
+ errors taxonomy / onError → onRequestEnd onMidStreamError → onStreamEnd → onRequestEnd
151
154
  ```
152
155
 
153
- | Hook | Available In | Trigger |
154
- |------|--------------|---------|
155
- | `onRequestStart` | Both | Before route handler |
156
- | `onRequestEnd` | Both | After response sent |
157
- | `onSuccess` | RPC, API | After successful handler |
158
- | `onError` | RPC, API | On handler error |
159
- | `onStreamStart` | Stream | Before first yield |
160
- | `onStreamEnd` | Stream | After stream completes |
161
- | `onError` (HonoStream) | Stream | Imperative pre-stream error callback peer of `errors` taxonomy |
162
- | `onRequestError` | All | Cross-cutting observer fires for every caught error before dispatch |
163
- | `onMidStreamError` | Stream | On mid-stream error (generator throws) |
156
+ Pre-stream errors short-circuit before `onStreamStart` fires, so `onStreamEnd` does **not** run on that path. Mid-stream errors run `onMidStreamError` and then still fire `onStreamEnd` because the stream had already started.
157
+
158
+ | Hook | Config block | Triggers on |
159
+ |------|--------------|-------------|
160
+ | `onRequestStart` | top-level | Before route handler (every kind) |
161
+ | `onRequestEnd` | top-level | After response sent (every kind) |
162
+ | `onRequestError` | top-level | Cross-cutting observer fires for every caught error before dispatch |
163
+ | `onError` | top-level | Imperative pre-stream error callback — peer of `errors` taxonomy |
164
+ | `errors` / `unknownError` | top-level | Declarative taxonomy dispatch |
165
+ | `rpc.onSuccess` | `rpc:` | After successful RPC handler |
166
+ | `api.onSuccess` | `api:` | After successful HTTP handler |
167
+ | `api.queryParser` | `api:` | Custom query-string parser for HTTP routes |
168
+ | `stream.defaultStreamMode` | `stream:` | Default mode (`'sse'` \| `'text'`) for both stream kinds |
169
+ | `stream.onStreamStart` | `stream:` | Before first yield |
170
+ | `stream.onStreamEnd` | `stream:` | After stream completes |
171
+ | `stream.onMidStreamError` | `stream:` | On mid-stream error (generator throws after first yield) |
164
172
 
165
173
  ### Route Documentation
166
174
 
167
- Each registered procedure generates documentation accessible via `builder.docs`.
175
+ Each registered procedure generates documentation accessible via `builder.docs`. Every doc carries a `kind` discriminant for reliable narrowing.
168
176
 
169
- **RPC Documentation (`RPCHttpRouteDoc`):**
177
+ **RPC (`RPCHttpRouteDoc`, `kind: 'rpc'`):**
170
178
 
171
179
  ```typescript
172
180
  interface RPCHttpRouteDoc {
181
+ kind: 'rpc'
173
182
  name: string
174
183
  path: string
175
184
  method: 'post'
176
185
  scope: string | string[]
177
186
  version: number
187
+ errors?: string[]
178
188
  jsonSchema: {
179
189
  body?: object // From schema.params
180
190
  response?: object // From schema.returnType
@@ -182,16 +192,18 @@ interface RPCHttpRouteDoc {
182
192
  }
183
193
  ```
184
194
 
185
- **Stream Documentation (`StreamHttpRouteDoc`):**
195
+ **RPC stream (`StreamHttpRouteDoc`, `kind: 'stream'`):**
186
196
 
187
197
  ```typescript
188
198
  interface StreamHttpRouteDoc {
199
+ kind: 'stream'
189
200
  name: string
190
201
  path: string
191
202
  methods: ('get' | 'post')[]
192
203
  streamMode: 'sse' | 'text'
193
204
  scope: string | string[]
194
205
  version: number
206
+ errors?: string[]
195
207
  jsonSchema: {
196
208
  params?: object // From schema.params
197
209
  yieldType?: object // From schema.yieldType
@@ -200,31 +212,65 @@ interface StreamHttpRouteDoc {
200
212
  }
201
213
  ```
202
214
 
203
- **API Documentation (`APIHttpRouteDoc`):**
215
+ **REST (`APIHttpRouteDoc`, `kind: 'api'`):**
204
216
 
205
217
  ```typescript
206
218
  interface APIHttpRouteDoc {
219
+ kind: 'api'
207
220
  name: string
221
+ scope?: string
208
222
  path: string
209
223
  method: HttpMethod
210
- fullPath: string
224
+ fullPath: string // Includes pathPrefix
211
225
  successStatus?: number
226
+ errors?: string[]
212
227
  jsonSchema: {
213
- pathParams?: object // From schema.input.pathParams
214
- query?: object // From schema.input.query
215
- body?: object // From schema.input.body
216
- headers?: object // From schema.input.headers
217
- response?: object // From schema.returnType
228
+ req?: {
229
+ pathParams?: object // From schema.req.pathParams
230
+ query?: object // From schema.req.query
231
+ body?: object // From schema.req.body
232
+ headers?: object // From schema.req.headers
233
+ }
234
+ res?: {
235
+ body?: object // From schema.res.body
236
+ headers?: object // From schema.res.headers
237
+ }
238
+ }
239
+ }
240
+ ```
241
+
242
+ **REST stream (`HttpStreamRouteDoc`, `kind: 'http-stream'`):**
243
+
244
+ ```typescript
245
+ interface HttpStreamRouteDoc {
246
+ kind: 'http-stream'
247
+ name: string
248
+ scope?: string
249
+ path: string
250
+ method: HttpMethod
251
+ fullPath: string
252
+ streamMode: 'sse' | 'text'
253
+ errors?: string[]
254
+ jsonSchema: {
255
+ req?: {
256
+ pathParams?: object
257
+ query?: object
258
+ body?: object
259
+ headers?: object
260
+ }
261
+ res?: { headers?: object }
262
+ yield?: object
263
+ returnType?: object
218
264
  }
219
265
  }
220
266
  ```
221
267
 
222
268
  ### Builder Pattern
223
269
 
224
- All implementations follow the same builder pattern:
270
+ Both builders follow the same pattern:
225
271
 
226
272
  ```typescript
227
- const builder = new AppBuilder(config)
273
+ const builder = new HonoAppBuilder(config)
228
274
  .register(PublicFactory, publicContextResolver)
229
275
  .register(ProtectedFactory, protectedContextResolver)
230
276
 
@@ -232,9 +278,9 @@ const app = builder.build()
232
278
  const docs = builder.docs
233
279
  ```
234
280
 
235
- All four builders' `build()` methods are synchronous — they return the framework app instance directly. Don't `await` the call.
281
+ `build()` is synchronous — it returns the framework app instance directly. Don't `await` the call.
236
282
 
237
- **Single Hono server across builders:** all three Hono builders (`HonoRPCAppBuilder`, `HonoAPIAppBuilder`, `HonoStreamAppBuilder`) accept an optional `app?: Hono` in their config. Pass the same `new Hono()` instance to mount RPC, API, and Stream routes onto one server the builders are registration scopes, not separate servers. See **[docs/http-integrations.md § One Hono Server, Multiple Builders](../../../docs/http-integrations.md#one-hono-server-multiple-builders)**.
283
+ A single `HonoAppBuilder` registers procedures of every kind from the same factory and mounts them on one Hono `app`. The optional `app?: Hono` config lets you mount onto an existing Hono instance that already has custom middleware, health checks, or static routes; if omitted, the builder constructs its own.
238
284
 
239
285
  **Key methods:**
240
286
 
@@ -248,11 +294,13 @@ All four builders' `build()` methods are synchronous — they return the framewo
248
294
  | Property | Type | Description |
249
295
  |----------|------|-------------|
250
296
  | `app` | Framework app | The underlying framework application |
251
- | `docs` | Route doc array | Route documentation (populated after `build()`) |
297
+ | `docs` | Route doc array | Route documentation, lazily computed on first read; `build()` also populates it. |
252
298
 
253
299
  ### DocRegistry
254
300
 
255
- Composes route documentation from multiple builders into a typed envelope, replacing manual `/docs` endpoint assembly.
301
+ For single-builder apps, prefer `builder.toDocEnvelope({ basePath, errors })` it wraps `DocRegistry` for the common case and produces an envelope identical to the multi-app aggregator.
302
+
303
+ For multi-app aggregation (e.g., two `HonoAppBuilder` instances mounted on different prefixes), `DocRegistry` composes route documentation from every source into one typed envelope:
256
304
 
257
305
  ```typescript
258
306
  import { DocRegistry } from 'ts-procedures/http-docs'
@@ -261,9 +309,8 @@ const docs = new DocRegistry({
261
309
  basePath: '/api',
262
310
  errors: appErrors, // your ErrorTaxonomy — framework defaults auto-merged and deduped
263
311
  })
264
- .from(rpcBuilder)
265
- .from(apiBuilder)
266
- .from(streamBuilder)
312
+ .from(builderA)
313
+ .from(builderB)
267
314
 
268
315
  app.get('/docs', (c) => c.json(docs.toJSON()))
269
316
  ```
@@ -271,34 +318,37 @@ app.get('/docs', (c) => c.json(docs.toJSON()))
271
318
  - `from()` stores a reference — routes are read lazily at `toJSON()` time
272
319
  - `toJSON()` supports optional `filter` and `transform` options
273
320
  - `errors` accepts an `ErrorTaxonomy` or raw `ErrorDoc[]`; framework defaults are auto-merged (opt out via `includeDefaults: false`)
274
- - All builders satisfy the `DocSource` interface (`{ readonly docs: AnyHttpRouteDoc[] }`)
321
+ - Every builder satisfies the `DocSource` interface (`{ readonly docs: AnyHttpRouteDoc[] }`)
275
322
 
276
323
  ### Client Code Generation
277
324
 
278
325
  Generate type-safe client SDKs from your DocRegistry output. The codegen reads the `DocEnvelope` JSON and produces per-scope TypeScript files with typed params, response types, and callable functions.
279
326
 
280
- **Requirements:** All routes need a `scope` field for file grouping. RPC and Stream routes already have `scope` via `RPCConfig`. API routes support optional `scope` on `APIConfig`:
327
+ **Requirements:** every route needs a `scope` field for file grouping. RPC and stream routes carry `scope` via `RPCConfig`. REST routes (`CreateHttp` / `CreateHttpStream`) carry an optional `scope` directly on the procedure config:
281
328
 
282
329
  ```typescript
283
- const apiBuilder = new HonoAPIAppBuilder()
284
- apiBuilder.register(factory, (c) => ctx, {
330
+ procs.CreateHttp('GetUser', {
331
+ path: '/users/:id',
332
+ method: 'get',
285
333
  scope: 'users', // Used for codegen file grouping
286
- })
334
+ schema: { req: { pathParams: Type.Object({ id: Type.String() }) } },
335
+ }, async (_, { pathParams }) => /* ... */)
287
336
  ```
288
337
 
289
- **Route type handling in generated code:**
338
+ **Route-doc kinds and how the codegen consumes them:**
290
339
 
291
- | Builder | Route Kind | Params Source | Generated Callable |
292
- |---------|-----------|---------------|-------------------|
293
- | HonoRPCAppBuilder | `rpc` | `jsonSchema.body` → flat params | `client.call()` |
294
- | HonoAPIAppBuilder | `api` | `jsonSchema.pathParams/query/body/headers` → structured params | `client.call()` |
295
- | HonoStreamAppBuilder | `stream` | `jsonSchema.params` → flat params | `client.stream()` |
340
+ | Doc kind | Source procedure | Params shape in generated callable | Generated callable |
341
+ |----------|------------------|------------------------------------|--------------------|
342
+ | `rpc` | `Create()` | `jsonSchema.body` → flat params | `client.call()` |
343
+ | `api` | `CreateHttp()` | `jsonSchema.req.{pathParams,query,body,headers}` → structured params | `client.call()` |
344
+ | `stream` | `CreateStream()` | `jsonSchema.params` → flat params | `client.stream()` |
345
+ | `http-stream` | `CreateHttpStream()` | `jsonSchema.req.{pathParams,query,body,headers}` → structured params | `client.stream()` |
296
346
 
297
347
  **SSE return values:** Stream procedures that return a value have it sent as `event: 'return'` SSE message. The client's `TypedStream.result` promise resolves with this value.
298
348
 
299
349
  **SSE yieldType unwrapping:** Codegen detects the SSE envelope in `yieldType` and uses the inner `data` schema for the generated `Yield` type.
300
350
 
301
- **Kind discriminant:** All route docs include a `kind` field (`'rpc' | 'api' | 'stream'`) for reliable type narrowing in the codegen pipeline and consumer code.
351
+ **Kind discriminant:** All route docs include a `kind` field (`'rpc' | 'api' | 'stream' | 'http-stream'`) for reliable type narrowing in the codegen pipeline and consumer code.
302
352
 
303
353
  **Namespace types:** Use `--namespace-types` to wrap generated types in nested TS namespaces (`Scope.Route.Params`) instead of flat prefixed exports (`RouteParams`).
304
354
 
@@ -308,17 +358,6 @@ apiBuilder.register(factory, (c) => ctx, {
308
358
 
309
359
  **Clean output directory:** Use `--clean-out-dir` (or `cleanOutDir: true` in the programmatic API) to recursively remove the output directory before writing, so scope files left over from deleted or renamed scopes are pruned. Skipped under `--dry-run`.
310
360
 
311
- ## Framework Comparison
312
-
313
- | Aspect | Express | Hono |
314
- |--------|---------|------|
315
- | Context param | `req: express.Request` | `c: Context` |
316
- | Error handler return | `void` (mutates res) | `Response` |
317
- | Body access | `req.body` | `await c.req.json()` |
318
- | Header access | `req.headers['x-id']` | `c.req.header('x-id')` |
319
- | JSON middleware | Auto-added (or manual) | Built-in |
320
- | Streaming support | Not yet | `hono-stream` |
321
-
322
361
  ## TypeScript Types
323
362
 
324
363
  ```typescript
@@ -326,6 +365,7 @@ import type {
326
365
  RPCConfig,
327
366
  RPCHttpRouteDoc,
328
367
  StreamHttpRouteDoc,
368
+ HttpStreamRouteDoc,
329
369
  StreamMode,
330
370
  APIConfig,
331
371
  APIHttpRouteDoc,
@@ -1,6 +1,6 @@
1
1
  # `ts-procedures/astro`
2
2
 
3
- Drop one or more pre-built Hono apps (from `HonoAPIAppBuilder`, `HonoRPCAppBuilder`, or `HonoStreamAppBuilder`) into a single Astro catch-all endpoint. Procedure handlers can read Astro's per-request data (`locals`, `cookies`, `redirect`, `params`) inside their factory-context closures.
3
+ Drop one or more pre-built Hono apps (from `HonoAppBuilder`, `HonoAppBuilder`, or `HonoAppBuilder`) into a single Astro catch-all endpoint. Procedure handlers can read Astro's per-request data (`locals`, `cookies`, `redirect`, `params`) inside their factory-context closures.
4
4
 
5
5
  > **Requires SSR.** Your Astro project must use `output: 'server'` or `output: 'hybrid'` with `export const prerender = false` in the catch-all file. Static-prerender mode bypasses live endpoints.
6
6
 
@@ -16,12 +16,12 @@ npm install ts-procedures hono astro
16
16
 
17
17
  ```ts
18
18
  // src/server/api.ts
19
- import { HonoAPIAppBuilder } from 'ts-procedures/hono-api'
19
+ import { HonoAppBuilder } from 'ts-procedures/hono'
20
20
  import { getAstroContext } from 'ts-procedures/astro'
21
21
  import { usersAPI } from './procedures/users'
22
22
  import { db } from './db'
23
23
 
24
- export const apiApp = new HonoAPIAppBuilder()
24
+ export const apiApp = new HonoAppBuilder()
25
25
  .register(usersAPI, (c) => {
26
26
  const astro = getAstroContext(c)
27
27
  return { db, user: astro.locals.user ?? null }
@@ -81,9 +81,8 @@ Dispatch rules:
81
81
 
82
82
  ## Streams
83
83
 
84
- `HonoStreamAppBuilder` returns a `Response` with a `ReadableStream` body. Astro SSR forwards that body verbatim — no additional configuration. Client disconnects abort `ctx.signal` inside the stream handler.
84
+ `HonoAppBuilder` returns a `Response` with a `ReadableStream` body. Astro SSR forwards that body verbatim — no additional configuration. Client disconnects abort `ctx.signal` inside the stream handler.
85
85
 
86
86
  ## What's NOT included
87
87
 
88
- - Express RPC support (Express uses Node `req`/`res`, not Web Fetch).
89
88
  - DocRegistry coupling — wire `DocRegistry` against the same builders separately for client codegen.