ts-procedures 7.3.0 → 8.1.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 (332) 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 +418 -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 +351 -55
  39. package/build/codegen/emit-scope.js.map +1 -1
  40. package/build/codegen/emit-scope.test.js +540 -110
  41. package/build/codegen/emit-scope.test.js.map +1 -1
  42. package/build/codegen/emit-types.d.ts +6 -2
  43. package/build/codegen/emit-types.js +81 -20
  44. package/build/codegen/emit-types.js.map +1 -1
  45. package/build/codegen/emit-types.test.js +70 -1
  46. package/build/codegen/emit-types.test.js.map +1 -1
  47. package/build/codegen/pipeline.test.js +7 -7
  48. package/build/codegen/pipeline.test.js.map +1 -1
  49. package/build/codegen/resolve-envelope.js +1 -1
  50. package/build/codegen/resolve-envelope.js.map +1 -1
  51. package/build/codegen/resolve-envelope.test.js +5 -5
  52. package/build/codegen/resolve-envelope.test.js.map +1 -1
  53. package/build/codegen/targets/_shared/route-slots.d.ts +8 -3
  54. package/build/codegen/targets/_shared/route-slots.js +49 -8
  55. package/build/codegen/targets/_shared/route-slots.js.map +1 -1
  56. package/build/codegen/targets/_shared/route-slots.test.js +99 -26
  57. package/build/codegen/targets/_shared/route-slots.test.js.map +1 -1
  58. package/build/codegen/targets/kotlin/emit-route-kotlin.test.js +88 -17
  59. package/build/codegen/targets/kotlin/emit-route-kotlin.test.js.map +1 -1
  60. package/build/codegen/targets/kotlin/emit-scope-kotlin.test.js +9 -6
  61. package/build/codegen/targets/kotlin/emit-scope-kotlin.test.js.map +1 -1
  62. package/build/codegen/targets/kotlin/integration.test.js +6 -0
  63. package/build/codegen/targets/kotlin/integration.test.js.map +1 -1
  64. package/build/codegen/targets/swift/access-level.test.js +8 -11
  65. package/build/codegen/targets/swift/access-level.test.js.map +1 -1
  66. package/build/codegen/targets/swift/emit-route-swift.test.js +91 -20
  67. package/build/codegen/targets/swift/emit-route-swift.test.js.map +1 -1
  68. package/build/codegen/targets/swift/emit-scope-swift.test.js +12 -9
  69. package/build/codegen/targets/swift/emit-scope-swift.test.js.map +1 -1
  70. package/build/codegen/targets/swift/integration.test.js +6 -0
  71. package/build/codegen/targets/swift/integration.test.js.map +1 -1
  72. package/build/create-http-stream.d.ts +58 -0
  73. package/build/create-http-stream.js +122 -0
  74. package/build/create-http-stream.js.map +1 -0
  75. package/build/create-http-stream.test.js +88 -0
  76. package/build/create-http-stream.test.js.map +1 -0
  77. package/build/create-http.d.ts +49 -0
  78. package/build/create-http.js +108 -0
  79. package/build/create-http.js.map +1 -0
  80. package/build/create-http.test.js +137 -0
  81. package/build/create-http.test.js.map +1 -0
  82. package/build/create-stream.d.ts +35 -0
  83. package/build/create-stream.js +123 -0
  84. package/build/create-stream.js.map +1 -0
  85. package/build/create-stream.test.js +428 -0
  86. package/build/create-stream.test.js.map +1 -0
  87. package/build/create.d.ts +28 -0
  88. package/build/create.js +82 -0
  89. package/build/create.js.map +1 -0
  90. package/build/create.test.js +483 -0
  91. package/build/create.test.js.map +1 -0
  92. package/build/exports.d.ts +2 -0
  93. package/build/implementations/http/astro/index.test.js +20 -12
  94. package/build/implementations/http/astro/index.test.js.map +1 -1
  95. package/build/implementations/http/doc-registry.js +1 -1
  96. package/build/implementations/http/doc-registry.js.map +1 -1
  97. package/build/implementations/http/doc-registry.test.js +36 -5
  98. package/build/implementations/http/doc-registry.test.js.map +1 -1
  99. package/build/implementations/http/error-dispatch.d.ts +76 -0
  100. package/build/implementations/http/error-dispatch.js +77 -0
  101. package/build/implementations/http/error-dispatch.js.map +1 -0
  102. package/build/implementations/http/error-dispatch.test.js +254 -0
  103. package/build/implementations/http/error-dispatch.test.js.map +1 -0
  104. package/build/implementations/http/error-taxonomy.d.ts +5 -5
  105. package/build/implementations/http/hono/docs/http-doc.d.ts +6 -0
  106. package/build/implementations/http/hono/docs/http-doc.js +42 -0
  107. package/build/implementations/http/hono/docs/http-doc.js.map +1 -0
  108. package/build/implementations/http/hono/docs/http-stream-doc.d.ts +6 -0
  109. package/build/implementations/http/hono/docs/http-stream-doc.js +40 -0
  110. package/build/implementations/http/hono/docs/http-stream-doc.js.map +1 -0
  111. package/build/implementations/http/hono/docs/rpc-doc.d.ts +6 -0
  112. package/build/implementations/http/hono/docs/rpc-doc.js +24 -0
  113. package/build/implementations/http/hono/docs/rpc-doc.js.map +1 -0
  114. package/build/implementations/http/hono/docs/stream-doc.d.ts +6 -0
  115. package/build/implementations/http/hono/docs/stream-doc.js +42 -0
  116. package/build/implementations/http/hono/docs/stream-doc.js.map +1 -0
  117. package/build/implementations/http/hono/handlers/http-stream.d.ts +10 -0
  118. package/build/implementations/http/hono/handlers/http-stream.js +123 -0
  119. package/build/implementations/http/hono/handlers/http-stream.js.map +1 -0
  120. package/build/implementations/http/hono/handlers/http-stream.test.js +128 -0
  121. package/build/implementations/http/hono/handlers/http-stream.test.js.map +1 -0
  122. package/build/implementations/http/hono/handlers/http.d.ts +10 -0
  123. package/build/implementations/http/hono/handlers/http.js +115 -0
  124. package/build/implementations/http/hono/handlers/http.js.map +1 -0
  125. package/build/implementations/http/hono/handlers/http.test.js +118 -0
  126. package/build/implementations/http/hono/handlers/http.test.js.map +1 -0
  127. package/build/implementations/http/hono/handlers/rpc.d.ts +11 -0
  128. package/build/implementations/http/hono/handlers/rpc.js +32 -0
  129. package/build/implementations/http/hono/handlers/rpc.js.map +1 -0
  130. package/build/implementations/http/hono/handlers/rpc.test.js +73 -0
  131. package/build/implementations/http/hono/handlers/rpc.test.js.map +1 -0
  132. package/build/implementations/http/hono/handlers/stream.d.ts +23 -0
  133. package/build/implementations/http/hono/handlers/stream.js +147 -0
  134. package/build/implementations/http/hono/handlers/stream.js.map +1 -0
  135. package/build/implementations/http/hono/handlers/stream.test.d.ts +1 -0
  136. package/build/implementations/http/hono/handlers/stream.test.js +177 -0
  137. package/build/implementations/http/hono/handlers/stream.test.js.map +1 -0
  138. package/build/implementations/http/hono/index.d.ts +57 -0
  139. package/build/implementations/http/hono/index.js +149 -0
  140. package/build/implementations/http/hono/index.js.map +1 -0
  141. package/build/implementations/http/hono/index.test.d.ts +1 -0
  142. package/build/implementations/http/hono/index.test.js +274 -0
  143. package/build/implementations/http/hono/index.test.js.map +1 -0
  144. package/build/implementations/http/hono/path.d.ts +17 -0
  145. package/build/implementations/http/hono/path.js +39 -0
  146. package/build/implementations/http/hono/path.js.map +1 -0
  147. package/build/implementations/http/hono/path.test.d.ts +1 -0
  148. package/build/implementations/http/hono/path.test.js +83 -0
  149. package/build/implementations/http/hono/path.test.js.map +1 -0
  150. package/build/implementations/http/hono/types.d.ts +51 -0
  151. package/build/implementations/http/hono/types.js.map +1 -0
  152. package/build/implementations/http/on-request-error.test.js +6 -96
  153. package/build/implementations/http/on-request-error.test.js.map +1 -1
  154. package/build/implementations/http/route-errors.test.js +11 -59
  155. package/build/implementations/http/route-errors.test.js.map +1 -1
  156. package/build/implementations/types.d.ts +43 -9
  157. package/build/index.d.ts +124 -124
  158. package/build/index.js +10 -221
  159. package/build/index.js.map +1 -1
  160. package/build/index.test.js +20 -919
  161. package/build/index.test.js.map +1 -1
  162. package/build/migration.test.d.ts +1 -0
  163. package/build/migration.test.js +34 -0
  164. package/build/migration.test.js.map +1 -0
  165. package/build/schema/compute-schema.d.ts +11 -3
  166. package/build/schema/compute-schema.js +13 -7
  167. package/build/schema/compute-schema.js.map +1 -1
  168. package/build/schema/parser.d.ts +11 -3
  169. package/build/schema/parser.js +49 -9
  170. package/build/schema/parser.js.map +1 -1
  171. package/build/stack-utils.js +8 -0
  172. package/build/stack-utils.js.map +1 -1
  173. package/build/types.d.ts +142 -0
  174. package/build/types.js.map +1 -0
  175. package/docs/astro-adapter.md +5 -5
  176. package/docs/core.md +15 -17
  177. package/docs/http-integrations.md +83 -170
  178. package/docs/streaming.md +3 -60
  179. package/docs/superpowers/plans/2026-05-07-astro-adapter.md +2 -7
  180. package/docs/superpowers/plans/2026-05-08-create-http.md +3355 -0
  181. package/docs/superpowers/plans/2026-05-08-hono-app-builder-convergence.md +3365 -0
  182. package/docs/superpowers/specs/2026-05-07-astro-adapter-design.md +1 -3
  183. package/docs/superpowers/specs/2026-05-08-create-http-design.md +409 -0
  184. package/docs/superpowers/specs/2026-05-08-hono-app-builder-convergence-design.md +411 -0
  185. package/package.json +4 -22
  186. package/src/client/call.test.ts +26 -0
  187. package/src/client/call.ts +4 -1
  188. package/src/client/fetch-adapter.test.ts +14 -1
  189. package/src/client/fetch-adapter.ts +3 -1
  190. package/src/client/index.test.ts +7 -7
  191. package/src/client/request-builder.ts +2 -2
  192. package/src/client/stream.test.ts +39 -7
  193. package/src/client/stream.ts +16 -2
  194. package/src/client/typed-error-dispatch.test.ts +7 -97
  195. package/src/client/types.ts +21 -3
  196. package/src/codegen/__fixtures__/users-envelope.json +119 -38
  197. package/src/codegen/e2e.test.ts +452 -24
  198. package/src/codegen/emit-errors.integration.test.ts +1 -1
  199. package/src/codegen/emit-scope.test.ts +581 -110
  200. package/src/codegen/emit-scope.ts +390 -61
  201. package/src/codegen/emit-types.test.ts +73 -1
  202. package/src/codegen/emit-types.ts +82 -21
  203. package/src/codegen/pipeline.test.ts +7 -7
  204. package/src/codegen/resolve-envelope.test.ts +5 -5
  205. package/src/codegen/resolve-envelope.ts +1 -1
  206. package/src/codegen/targets/_shared/route-slots.test.ts +109 -26
  207. package/src/codegen/targets/_shared/route-slots.ts +48 -11
  208. package/src/codegen/targets/kotlin/__fixtures__/users-golden.kt +73 -0
  209. package/src/codegen/targets/kotlin/emit-route-kotlin.test.ts +100 -17
  210. package/src/codegen/targets/kotlin/emit-scope-kotlin.test.ts +9 -6
  211. package/src/codegen/targets/kotlin/integration.test.ts +19 -0
  212. package/src/codegen/targets/swift/__fixtures__/users-golden.swift +79 -0
  213. package/src/codegen/targets/swift/access-level.test.ts +8 -11
  214. package/src/codegen/targets/swift/emit-route-swift.test.ts +103 -20
  215. package/src/codegen/targets/swift/emit-scope-swift.test.ts +12 -9
  216. package/src/codegen/targets/swift/integration.test.ts +17 -0
  217. package/src/create-http-stream.test.ts +97 -0
  218. package/src/create-http-stream.ts +191 -0
  219. package/src/create-http.test.ts +163 -0
  220. package/src/create-http.ts +211 -0
  221. package/src/create-stream.test.ts +565 -0
  222. package/src/create-stream.ts +228 -0
  223. package/src/create.test.ts +658 -0
  224. package/src/create.ts +172 -0
  225. package/src/exports.ts +2 -0
  226. package/src/implementations/http/README.md +135 -95
  227. package/src/implementations/http/astro/README.md +4 -5
  228. package/src/implementations/http/astro/index.test.ts +25 -18
  229. package/src/implementations/http/doc-registry.test.ts +42 -5
  230. package/src/implementations/http/doc-registry.ts +1 -1
  231. package/src/implementations/http/error-dispatch.test.ts +283 -0
  232. package/src/implementations/http/error-dispatch.ts +176 -0
  233. package/src/implementations/http/error-taxonomy.ts +5 -5
  234. package/src/implementations/http/hono/docs/http-doc.ts +43 -0
  235. package/src/implementations/http/hono/docs/http-stream-doc.ts +44 -0
  236. package/src/implementations/http/hono/docs/rpc-doc.ts +34 -0
  237. package/src/implementations/http/hono/docs/stream-doc.ts +53 -0
  238. package/src/implementations/http/hono/handlers/http-stream.test.ts +150 -0
  239. package/src/implementations/http/hono/handlers/http-stream.ts +152 -0
  240. package/src/implementations/http/hono/handlers/http.test.ts +130 -0
  241. package/src/implementations/http/hono/handlers/http.ts +147 -0
  242. package/src/implementations/http/hono/handlers/rpc.test.ts +81 -0
  243. package/src/implementations/http/hono/handlers/rpc.ts +54 -0
  244. package/src/implementations/http/hono/handlers/stream.test.ts +198 -0
  245. package/src/implementations/http/hono/handlers/stream.ts +208 -0
  246. package/src/implementations/http/hono/index.test.ts +329 -0
  247. package/src/implementations/http/hono/index.ts +204 -0
  248. package/src/implementations/http/hono/path.test.ts +96 -0
  249. package/src/implementations/http/hono/path.ts +59 -0
  250. package/src/implementations/http/hono/types.ts +93 -0
  251. package/src/implementations/http/on-request-error.test.ts +10 -116
  252. package/src/implementations/http/route-errors.test.ts +11 -77
  253. package/src/implementations/types.ts +44 -9
  254. package/src/index.test.ts +22 -1249
  255. package/src/index.ts +49 -485
  256. package/src/migration.test.ts +48 -0
  257. package/src/schema/compute-schema.ts +26 -12
  258. package/src/schema/parser.ts +62 -12
  259. package/src/stack-utils.ts +8 -0
  260. package/src/types.ts +133 -0
  261. package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/express-rpc.md +0 -137
  262. package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/hono-api.md +0 -173
  263. package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/hono-rpc.md +0 -142
  264. package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/hono-stream.md +0 -147
  265. package/build/implementations/http/express-rpc/error-taxonomy.test.js +0 -83
  266. package/build/implementations/http/express-rpc/error-taxonomy.test.js.map +0 -1
  267. package/build/implementations/http/express-rpc/index.d.ts +0 -125
  268. package/build/implementations/http/express-rpc/index.js +0 -216
  269. package/build/implementations/http/express-rpc/index.js.map +0 -1
  270. package/build/implementations/http/express-rpc/index.test.js +0 -684
  271. package/build/implementations/http/express-rpc/index.test.js.map +0 -1
  272. package/build/implementations/http/express-rpc/types.d.ts +0 -11
  273. package/build/implementations/http/express-rpc/types.js.map +0 -1
  274. package/build/implementations/http/hono-api/error-taxonomy.test.js +0 -137
  275. package/build/implementations/http/hono-api/error-taxonomy.test.js.map +0 -1
  276. package/build/implementations/http/hono-api/index.d.ts +0 -151
  277. package/build/implementations/http/hono-api/index.js +0 -344
  278. package/build/implementations/http/hono-api/index.js.map +0 -1
  279. package/build/implementations/http/hono-api/index.test.js +0 -992
  280. package/build/implementations/http/hono-api/index.test.js.map +0 -1
  281. package/build/implementations/http/hono-api/types.d.ts +0 -13
  282. package/build/implementations/http/hono-api/types.js.map +0 -1
  283. package/build/implementations/http/hono-rpc/error-taxonomy.test.js +0 -64
  284. package/build/implementations/http/hono-rpc/error-taxonomy.test.js.map +0 -1
  285. package/build/implementations/http/hono-rpc/index.d.ts +0 -130
  286. package/build/implementations/http/hono-rpc/index.js +0 -209
  287. package/build/implementations/http/hono-rpc/index.js.map +0 -1
  288. package/build/implementations/http/hono-rpc/index.test.js +0 -828
  289. package/build/implementations/http/hono-rpc/index.test.js.map +0 -1
  290. package/build/implementations/http/hono-rpc/types.d.ts +0 -11
  291. package/build/implementations/http/hono-rpc/types.js +0 -2
  292. package/build/implementations/http/hono-rpc/types.js.map +0 -1
  293. package/build/implementations/http/hono-stream/error-taxonomy.test.js +0 -159
  294. package/build/implementations/http/hono-stream/error-taxonomy.test.js.map +0 -1
  295. package/build/implementations/http/hono-stream/index.d.ts +0 -171
  296. package/build/implementations/http/hono-stream/index.js +0 -415
  297. package/build/implementations/http/hono-stream/index.js.map +0 -1
  298. package/build/implementations/http/hono-stream/index.test.js +0 -1383
  299. package/build/implementations/http/hono-stream/index.test.js.map +0 -1
  300. package/build/implementations/http/hono-stream/types.d.ts +0 -15
  301. package/build/implementations/http/hono-stream/types.js +0 -2
  302. package/build/implementations/http/hono-stream/types.js.map +0 -1
  303. package/src/implementations/http/express-rpc/README.md +0 -280
  304. package/src/implementations/http/express-rpc/error-taxonomy.test.ts +0 -103
  305. package/src/implementations/http/express-rpc/index.test.ts +0 -957
  306. package/src/implementations/http/express-rpc/index.ts +0 -327
  307. package/src/implementations/http/express-rpc/types.ts +0 -16
  308. package/src/implementations/http/hono-api/README.md +0 -284
  309. package/src/implementations/http/hono-api/error-taxonomy.test.ts +0 -179
  310. package/src/implementations/http/hono-api/index.test.ts +0 -1341
  311. package/src/implementations/http/hono-api/index.ts +0 -519
  312. package/src/implementations/http/hono-api/types.ts +0 -16
  313. package/src/implementations/http/hono-rpc/README.md +0 -357
  314. package/src/implementations/http/hono-rpc/error-taxonomy.test.ts +0 -82
  315. package/src/implementations/http/hono-rpc/index.test.ts +0 -1107
  316. package/src/implementations/http/hono-rpc/index.ts +0 -320
  317. package/src/implementations/http/hono-rpc/types.ts +0 -16
  318. package/src/implementations/http/hono-stream/README.md +0 -559
  319. package/src/implementations/http/hono-stream/error-taxonomy.test.ts +0 -178
  320. package/src/implementations/http/hono-stream/index.test.ts +0 -1804
  321. package/src/implementations/http/hono-stream/index.ts +0 -622
  322. package/src/implementations/http/hono-stream/types.ts +0 -20
  323. /package/build/{implementations/http/express-rpc/error-taxonomy.test.d.ts → create-http-stream.test.d.ts} +0 -0
  324. /package/build/{implementations/http/express-rpc/index.test.d.ts → create-http.test.d.ts} +0 -0
  325. /package/build/{implementations/http/hono-api/error-taxonomy.test.d.ts → create-stream.test.d.ts} +0 -0
  326. /package/build/{implementations/http/hono-api/index.test.d.ts → create.test.d.ts} +0 -0
  327. /package/build/implementations/http/{hono-rpc/error-taxonomy.test.d.ts → error-dispatch.test.d.ts} +0 -0
  328. /package/build/implementations/http/{hono-rpc/index.test.d.ts → hono/handlers/http-stream.test.d.ts} +0 -0
  329. /package/build/implementations/http/{hono-stream/error-taxonomy.test.d.ts → hono/handlers/http.test.d.ts} +0 -0
  330. /package/build/implementations/http/{hono-stream/index.test.d.ts → hono/handlers/rpc.test.d.ts} +0 -0
  331. /package/build/implementations/http/{express-rpc → hono}/types.js +0 -0
  332. /package/build/{implementations/http/hono-api/types.js → types.js} +0 -0
@@ -34,11 +34,9 @@ describe('emitKotlinRoute', () => {
34
34
  name: 'GetUser',
35
35
  method: 'GET',
36
36
  fullPath: '/users/:id',
37
- schema: {
38
- input: {
39
- pathParams: { type: 'object' },
40
- },
41
- returnType: { type: 'object' },
37
+ jsonSchema: {
38
+ req: { pathParams: { type: 'object' } },
39
+ res: { body: { type: 'object' } },
42
40
  },
43
41
  errors: [],
44
42
  } as unknown as AnyHttpRouteDoc
@@ -64,7 +62,10 @@ describe('emitKotlinRoute', () => {
64
62
  name: 'CreateUser',
65
63
  method: 'POST',
66
64
  fullPath: '/users',
67
- schema: { input: { body: { type: 'object' } }, returnType: { type: 'object' } },
65
+ jsonSchema: {
66
+ req: { body: { type: 'object' } },
67
+ res: { body: { type: 'object' } },
68
+ },
68
69
  errors: [],
69
70
  } as unknown as AnyHttpRouteDoc
70
71
 
@@ -84,7 +85,10 @@ describe('emitKotlinRoute', () => {
84
85
  name: 'GetUser',
85
86
  method: 'GET',
86
87
  fullPath: '/users/:id',
87
- schema: { input: { pathParams: { type: 'object' } }, returnType: { type: 'object' } },
88
+ jsonSchema: {
89
+ req: { pathParams: { type: 'object' } },
90
+ res: { body: { type: 'object' } },
91
+ },
88
92
  errors: ['NotFound'],
89
93
  } as unknown as AnyHttpRouteDoc
90
94
 
@@ -103,14 +107,14 @@ describe('emitKotlinRoute', () => {
103
107
  it('silently skips error keys with no schema in the envelope map', () => {
104
108
  const route = {
105
109
  kind: 'api', name: 'GetUser', method: 'GET', fullPath: '/users',
106
- schema: {}, errors: ['UnknownTaxonomyKey'],
110
+ jsonSchema: {}, errors: ['UnknownTaxonomyKey'],
107
111
  } as unknown as AnyHttpRouteDoc
108
112
  const result = emitKotlinRoute(route, createStubKotlinEmitter({}), new Map())
109
113
  expect(result.code).not.toContain('object Errors {')
110
114
  })
111
115
 
112
116
  it('returns skipped:true for stream routes', () => {
113
- const route = { kind: 'stream', name: 'WatchUsers', method: 'GET', path: '/users/stream', schema: {}, errors: [] } as unknown as AnyHttpRouteDoc
117
+ const route = { kind: 'stream', name: 'WatchUsers', method: 'GET', path: '/users/stream', jsonSchema: {}, errors: [] } as unknown as AnyHttpRouteDoc
114
118
  const result = emitKotlinRoute(route, createStubKotlinEmitter({}), noErrors)
115
119
  expect(result.code).toBe('')
116
120
  expect(result.skipped).toBe(true)
@@ -122,9 +126,9 @@ describe('emitKotlinRoute', () => {
122
126
  name: 'GetUser',
123
127
  method: 'GET',
124
128
  fullPath: '/users/:id',
125
- schema: {
126
- input: { pathParams: { type: 'object' } },
127
- returnType: { type: 'object' },
129
+ jsonSchema: {
130
+ req: { pathParams: { type: 'object' } },
131
+ res: { body: { type: 'object' } },
128
132
  },
129
133
  errors: ['NotFound'],
130
134
  } as unknown as AnyHttpRouteDoc
@@ -155,13 +159,13 @@ describe('emitKotlinRoute', () => {
155
159
  name: 'X',
156
160
  method: 'POST',
157
161
  fullPath: '/x/:id',
158
- schema: {
159
- input: {
162
+ jsonSchema: {
163
+ req: {
160
164
  pathParams: { type: 'object' },
161
165
  query: { type: 'object' },
162
166
  body: { type: 'object' },
163
167
  },
164
- returnType: { type: 'object' },
168
+ res: { body: { type: 'object' } },
165
169
  },
166
170
  errors: ['Z'],
167
171
  } as unknown as AnyHttpRouteDoc
@@ -187,7 +191,7 @@ describe('emitKotlinRoute', () => {
187
191
  name: 'X',
188
192
  method: 'GET',
189
193
  fullPath: '/x',
190
- schema: { returnType: { type: 'object' } },
194
+ jsonSchema: { res: { body: { type: 'object' } } },
191
195
  errors: [],
192
196
  } as unknown as AnyHttpRouteDoc
193
197
 
@@ -207,13 +211,92 @@ describe('emitKotlinRoute', () => {
207
211
  expect(calls[0]!.opts.uncountableWords).toEqual(['data', 'metadata'])
208
212
  })
209
213
 
214
+ it('emits ResponseHeaders slot when res.headers is declared on an api route', () => {
215
+ const route = {
216
+ kind: 'api',
217
+ name: 'DownloadUser',
218
+ method: 'GET',
219
+ fullPath: '/users/:id/download',
220
+ jsonSchema: {
221
+ req: { pathParams: { type: 'object' } },
222
+ res: {
223
+ body: { type: 'object' },
224
+ headers: { type: 'object' },
225
+ },
226
+ },
227
+ errors: [],
228
+ } as unknown as AnyHttpRouteDoc
229
+
230
+ const { emitter, calls } = makeSpyEmitter({
231
+ PathParams: ok('@Serializable data class PathParams(val id: String)', 'PathParams'),
232
+ Response: ok('@Serializable data class Response(val url: String)', 'Response'),
233
+ ResponseHeaders: ok(
234
+ '@Serializable\ndata class ResponseHeaders(\n @SerialName("x-download-token") val xDownloadToken: String,\n)',
235
+ 'ResponseHeaders',
236
+ ),
237
+ })
238
+
239
+ const result = emitKotlinRoute(route, emitter, noErrors)
240
+ expect(calls.map((c) => c.opts.rootTypeName)).toEqual(['PathParams', 'Response', 'ResponseHeaders'])
241
+ expect(result.code).toContain('@SerialName("x-download-token") val xDownloadToken: String')
242
+ })
243
+
244
+ it('does not emit ResponseHeaders when res.headers is absent', () => {
245
+ const route = {
246
+ kind: 'api',
247
+ name: 'GetUser',
248
+ method: 'GET',
249
+ fullPath: '/users/:id',
250
+ jsonSchema: {
251
+ req: { pathParams: { type: 'object' } },
252
+ res: { body: { type: 'object' } },
253
+ },
254
+ errors: [],
255
+ } as unknown as AnyHttpRouteDoc
256
+
257
+ const { emitter, calls } = makeSpyEmitter({
258
+ PathParams: ok('@Serializable data class PathParams(val id: String)', 'PathParams'),
259
+ Response: ok('@Serializable data class Response(val id: String)', 'Response'),
260
+ })
261
+
262
+ emitKotlinRoute(route, emitter, noErrors)
263
+ expect(calls.map((c) => c.opts.rootTypeName)).not.toContain('ResponseHeaders')
264
+ })
265
+
266
+ it('processes http-stream routes (not skipped) and emits Yield/ReturnType slots', () => {
267
+ const route = {
268
+ kind: 'http-stream',
269
+ name: 'TailLogs',
270
+ method: 'GET',
271
+ fullPath: '/logs/tail',
272
+ jsonSchema: {
273
+ req: { query: { type: 'object' } },
274
+ yield: { type: 'object' },
275
+ returnType: { type: 'object' },
276
+ },
277
+ errors: [],
278
+ } as unknown as AnyHttpRouteDoc
279
+
280
+ const { emitter, calls } = makeSpyEmitter({
281
+ Query: ok('@Serializable data class Query(val filter: String? = null)', 'Query'),
282
+ Yield: ok('@Serializable data class Yield(val line: String)', 'Yield'),
283
+ ReturnType: ok('@Serializable data class ReturnType(val count: Long)', 'ReturnType'),
284
+ })
285
+
286
+ const result = emitKotlinRoute(route, emitter, noErrors)
287
+ expect(result.skipped).toBeFalsy()
288
+ expect(calls.map((c) => c.opts.rootTypeName)).toEqual(['Query', 'Yield', 'ReturnType'])
289
+ expect(result.code).toContain('const val method = "GET"')
290
+ expect(result.code).toContain('const val path = "/logs/tail"')
291
+ })
292
+
210
293
  it('does not include passthrough keys when caller omits them', () => {
211
294
  const route = {
212
295
  kind: 'api',
213
296
  name: 'X',
214
297
  method: 'GET',
215
298
  fullPath: '/x',
216
- schema: { returnType: { type: 'object' } },
299
+ jsonSchema: { res: { body: { type: 'object' } } },
217
300
  errors: [],
218
301
  } as unknown as AnyHttpRouteDoc
219
302
 
@@ -18,7 +18,10 @@ describe('emitKotlinScope', () => {
18
18
  name: 'GetUser',
19
19
  method: 'GET',
20
20
  fullPath: '/users/:id',
21
- schema: { input: { pathParams: { type: 'object' } }, returnType: { type: 'object' } },
21
+ jsonSchema: {
22
+ req: { pathParams: { type: 'object' } },
23
+ res: { body: { type: 'object' } },
24
+ },
22
25
  errors: [],
23
26
  } as unknown as AnyHttpRouteDoc
24
27
 
@@ -40,8 +43,8 @@ describe('emitKotlinScope', () => {
40
43
  })
41
44
 
42
45
  it('joins multiple routes inside one scope object', () => {
43
- const route1 = { kind: 'api', name: 'GetUser', method: 'GET', fullPath: '/users/:id', schema: {}, errors: [] } as unknown as AnyHttpRouteDoc
44
- const route2 = { kind: 'api', name: 'CreateUser', method: 'POST', fullPath: '/users', schema: {}, errors: [] } as unknown as AnyHttpRouteDoc
46
+ const route1 = { kind: 'api', name: 'GetUser', method: 'GET', fullPath: '/users/:id', jsonSchema: {}, errors: [] } as unknown as AnyHttpRouteDoc
47
+ const route2 = { kind: 'api', name: 'CreateUser', method: 'POST', fullPath: '/users', jsonSchema: {}, errors: [] } as unknown as AnyHttpRouteDoc
45
48
  const group: ScopeGroup = { scopeKey: 'users', camelCase: 'users', routes: [route1, route2] }
46
49
  const emitter = createStubKotlinEmitter({})
47
50
 
@@ -60,7 +63,7 @@ describe('emitKotlinScope', () => {
60
63
  })
61
64
 
62
65
  it('threads all 5 passthrough opts to every emitter call', () => {
63
- const route = { kind: 'api', name: 'X', method: 'GET', fullPath: '/x', schema: { returnType: { type: 'object' } }, errors: [] } as unknown as AnyHttpRouteDoc
66
+ const route = { kind: 'api', name: 'X', method: 'GET', fullPath: '/x', jsonSchema: { res: { body: { type: 'object' } } }, errors: [] } as unknown as AnyHttpRouteDoc
64
67
  const group: ScopeGroup = { scopeKey: 'x', camelCase: 'x', routes: [route] }
65
68
 
66
69
  const calls: KotlinEmitOptions[] = []
@@ -96,8 +99,8 @@ describe('emitKotlinScope', () => {
96
99
  })
97
100
 
98
101
  it('collects skipped stream-route names', () => {
99
- const stream = { kind: 'stream', name: 'WatchUsers', method: 'GET', path: '/u/stream', schema: {}, errors: [] } as unknown as AnyHttpRouteDoc
100
- const api = { kind: 'api', name: 'GetUser', method: 'GET', fullPath: '/u', schema: { returnType: { type: 'object' } }, errors: [] } as unknown as AnyHttpRouteDoc
102
+ const stream = { kind: 'stream', name: 'WatchUsers', method: 'GET', path: '/u/stream', jsonSchema: {}, errors: [] } as unknown as AnyHttpRouteDoc
103
+ const api = { kind: 'api', name: 'GetUser', method: 'GET', fullPath: '/u', jsonSchema: { res: { body: { type: 'object' } } }, errors: [] } as unknown as AnyHttpRouteDoc
101
104
  const group: ScopeGroup = { scopeKey: 'u', camelCase: 'u', routes: [stream, api] }
102
105
 
103
106
  const emitter = createStubKotlinEmitter({
@@ -61,6 +61,25 @@ describe('kotlin codegen — integration', () => {
61
61
  'Query',
62
62
  ['kotlinx.serialization.Serializable', 'kotlinx.serialization.SerialName'],
63
63
  ),
64
+
65
+ // DownloadUser
66
+ ResponseHeaders: ok(
67
+ '@Serializable\ndata class ResponseHeaders(\n @SerialName("x-download-token") val xDownloadToken: String,\n @SerialName("content-disposition") val contentDisposition: String? = null,\n)',
68
+ 'ResponseHeaders',
69
+ ['kotlinx.serialization.Serializable', 'kotlinx.serialization.SerialName'],
70
+ ),
71
+
72
+ // WatchUsers (http-stream) — reuses Query and ResponseHeaders stubs from above;
73
+ // adds Yield and ReturnType which are unique to the stream route.
74
+ Yield: ok(
75
+ '@Serializable\ndata class Yield(\n val id: String,\n val event: Event,\n) {\n @Serializable\n enum class Event {\n @SerialName("created") CREATED,\n @SerialName("updated") UPDATED,\n @SerialName("deleted") DELETED,\n }\n}',
76
+ 'Yield',
77
+ ['kotlinx.serialization.Serializable', 'kotlinx.serialization.SerialName'],
78
+ ),
79
+ ReturnType: ok(
80
+ '@Serializable\ndata class ReturnType(\n val count: Long,\n)',
81
+ 'ReturnType',
82
+ ),
64
83
  })
65
84
 
66
85
  const files = await runPipeline({
@@ -120,4 +120,83 @@ public enum Users {
120
120
  }
121
121
  }
122
122
  }
123
+
124
+ public enum DownloadUser {
125
+ public static let method = "GET"
126
+ public static let pathTemplate = "/users/{id}/download"
127
+ public static func path(_ p: PathParams) -> String { return "/users/\(p.id)/download" }
128
+
129
+ public struct PathParams: Codable {
130
+ public let id: String
131
+ }
132
+
133
+ public struct Response: Codable {
134
+ public let id: String
135
+ public let name: String
136
+ public let createdAt: Date
137
+ public let address: Address
138
+
139
+ enum CodingKeys: String, CodingKey {
140
+ case id, name
141
+ case createdAt = "created-at"
142
+ case address
143
+ }
144
+
145
+ public struct Address: Codable {
146
+ public let street: String
147
+ public let city: String
148
+ }
149
+ }
150
+
151
+ public struct ResponseHeaders: Codable {
152
+ public let xDownloadToken: String
153
+ public let contentDisposition: String?
154
+
155
+ enum CodingKeys: String, CodingKey {
156
+ case xDownloadToken = "x-download-token"
157
+ case contentDisposition = "content-disposition"
158
+ }
159
+ }
160
+ }
161
+
162
+ public enum WatchUsers {
163
+ public static let method = "GET"
164
+ public static let pathTemplate = "/users/watch"
165
+ public static let path = "/users/watch"
166
+
167
+ public struct Query: Codable {
168
+ public let status: Status?
169
+ public let limit: Int64?
170
+
171
+ public enum Status: String, Codable {
172
+ case active
173
+ case inactive
174
+ }
175
+ }
176
+
177
+ public struct ResponseHeaders: Codable {
178
+ public let xDownloadToken: String
179
+ public let contentDisposition: String?
180
+
181
+ enum CodingKeys: String, CodingKey {
182
+ case xDownloadToken = "x-download-token"
183
+ case contentDisposition = "content-disposition"
184
+ }
185
+ }
186
+
187
+ public struct Yield: Codable {
188
+ public let id: String
189
+ public let event: Event
190
+
191
+ public enum Event: String, Codable {
192
+ case created
193
+ case updated
194
+ case deleted
195
+ }
196
+ }
197
+
198
+ public struct ReturnType: Codable {
199
+ public let count: Int64
200
+ }
201
+ }
123
202
  }
@@ -28,23 +28,20 @@ const envelope: DocEnvelope = {
28
28
  method: 'get',
29
29
  path: '/things/:id',
30
30
  fullPath: '/things/:id',
31
- jsonSchema: {},
32
- // The swift route emitter reads `route.schema.input.*` and
33
- // `route.schema.returnType` directly; mirror what the codegen
34
- // pipeline downstream expects rather than the doc-builder
35
- // `jsonSchema` shape.
36
- schema: {
37
- input: {
31
+ jsonSchema: {
32
+ req: {
38
33
  pathParams: {
39
34
  type: 'object',
40
35
  properties: { id: { type: 'string' } },
41
36
  required: ['id'],
42
37
  },
43
38
  },
44
- returnType: {
45
- type: 'object',
46
- properties: { id: { type: 'string' } },
47
- required: ['id'],
39
+ res: {
40
+ body: {
41
+ type: 'object',
42
+ properties: { id: { type: 'string' } },
43
+ required: ['id'],
44
+ },
48
45
  },
49
46
  },
50
47
  errors: [],
@@ -34,11 +34,9 @@ describe('emitSwiftRoute', () => {
34
34
  name: 'GetUser',
35
35
  method: 'GET',
36
36
  fullPath: '/users/:id',
37
- schema: {
38
- input: {
39
- pathParams: { type: 'object' },
40
- },
41
- returnType: { type: 'object' },
37
+ jsonSchema: {
38
+ req: { pathParams: { type: 'object' } },
39
+ res: { body: { type: 'object' } },
42
40
  },
43
41
  errors: [],
44
42
  } as unknown as AnyHttpRouteDoc
@@ -64,7 +62,10 @@ describe('emitSwiftRoute', () => {
64
62
  name: 'CreateUser',
65
63
  method: 'POST',
66
64
  fullPath: '/users',
67
- schema: { input: { body: { type: 'object' } }, returnType: { type: 'object' } },
65
+ jsonSchema: {
66
+ req: { body: { type: 'object' } },
67
+ res: { body: { type: 'object' } },
68
+ },
68
69
  errors: [],
69
70
  } as unknown as AnyHttpRouteDoc
70
71
 
@@ -84,7 +85,10 @@ describe('emitSwiftRoute', () => {
84
85
  name: 'GetUser',
85
86
  method: 'GET',
86
87
  fullPath: '/users/:id',
87
- schema: { input: { pathParams: { type: 'object' } }, returnType: { type: 'object' } },
88
+ jsonSchema: {
89
+ req: { pathParams: { type: 'object' } },
90
+ res: { body: { type: 'object' } },
91
+ },
88
92
  errors: ['NotFound'],
89
93
  } as unknown as AnyHttpRouteDoc
90
94
 
@@ -103,14 +107,14 @@ describe('emitSwiftRoute', () => {
103
107
  it('silently skips error keys with no schema in the envelope map', () => {
104
108
  const route = {
105
109
  kind: 'api', name: 'GetUser', method: 'GET', fullPath: '/users',
106
- schema: {}, errors: ['UnknownTaxonomyKey'],
110
+ jsonSchema: {}, errors: ['UnknownTaxonomyKey'],
107
111
  } as unknown as AnyHttpRouteDoc
108
112
  const result = emitSwiftRoute(route, createStubSwiftEmitter({}), new Map())
109
113
  expect(result.code).not.toContain('enum Errors {')
110
114
  })
111
115
 
112
116
  it('returns skipped:true for stream routes', () => {
113
- const route = { kind: 'stream', name: 'WatchUsers', method: 'GET', path: '/users/stream', schema: {}, errors: [] } as unknown as AnyHttpRouteDoc
117
+ const route = { kind: 'stream', name: 'WatchUsers', method: 'GET', path: '/users/stream', jsonSchema: {}, errors: [] } as unknown as AnyHttpRouteDoc
114
118
  const result = emitSwiftRoute(route, createStubSwiftEmitter({}), noErrors)
115
119
  expect(result.code).toBe('')
116
120
  expect(result.skipped).toBe(true)
@@ -122,9 +126,9 @@ describe('emitSwiftRoute', () => {
122
126
  name: 'GetUser',
123
127
  method: 'GET',
124
128
  fullPath: '/users/:id',
125
- schema: {
126
- input: { pathParams: { type: 'object' } },
127
- returnType: { type: 'object' },
129
+ jsonSchema: {
130
+ req: { pathParams: { type: 'object' } },
131
+ res: { body: { type: 'object' } },
128
132
  },
129
133
  errors: ['NotFound'],
130
134
  } as unknown as AnyHttpRouteDoc
@@ -157,13 +161,13 @@ describe('emitSwiftRoute', () => {
157
161
  name: 'X',
158
162
  method: 'POST',
159
163
  fullPath: '/x/:id',
160
- schema: {
161
- input: {
164
+ jsonSchema: {
165
+ req: {
162
166
  pathParams: { type: 'object' },
163
167
  query: { type: 'object' },
164
168
  body: { type: 'object' },
165
169
  },
166
- returnType: { type: 'object' },
170
+ res: { body: { type: 'object' } },
167
171
  },
168
172
  errors: ['Z'],
169
173
  } as unknown as AnyHttpRouteDoc
@@ -189,7 +193,7 @@ describe('emitSwiftRoute', () => {
189
193
  name: 'X',
190
194
  method: 'GET',
191
195
  fullPath: '/x',
192
- schema: { returnType: { type: 'object' } },
196
+ jsonSchema: { res: { body: { type: 'object' } } },
193
197
  errors: [],
194
198
  } as unknown as AnyHttpRouteDoc
195
199
 
@@ -209,13 +213,92 @@ describe('emitSwiftRoute', () => {
209
213
  expect(calls[0]!.opts.uncountableWords).toEqual(['data', 'metadata'])
210
214
  })
211
215
 
216
+ it('emits ResponseHeaders slot when res.headers is declared on an api route', () => {
217
+ const route = {
218
+ kind: 'api',
219
+ name: 'DownloadUser',
220
+ method: 'GET',
221
+ fullPath: '/users/:id/download',
222
+ jsonSchema: {
223
+ req: { pathParams: { type: 'object' } },
224
+ res: {
225
+ body: { type: 'object' },
226
+ headers: { type: 'object' },
227
+ },
228
+ },
229
+ errors: [],
230
+ } as unknown as AnyHttpRouteDoc
231
+
232
+ const { emitter, calls } = makeSpyEmitter({
233
+ PathParams: ok('public struct PathParams: Codable { public let id: String }', 'PathParams'),
234
+ Response: ok('public struct Response: Codable { public let url: String }', 'Response'),
235
+ ResponseHeaders: ok(
236
+ 'public struct ResponseHeaders: Codable { public let xDownloadToken: String }',
237
+ 'ResponseHeaders',
238
+ ),
239
+ })
240
+
241
+ const result = emitSwiftRoute(route, emitter, noErrors)
242
+ expect(calls.map((c) => c.opts.rootTypeName)).toEqual(['PathParams', 'Response', 'ResponseHeaders'])
243
+ expect(result.code).toContain('public struct ResponseHeaders: Codable { public let xDownloadToken: String }')
244
+ })
245
+
246
+ it('does not emit ResponseHeaders when res.headers is absent', () => {
247
+ const route = {
248
+ kind: 'api',
249
+ name: 'GetUser',
250
+ method: 'GET',
251
+ fullPath: '/users/:id',
252
+ jsonSchema: {
253
+ req: { pathParams: { type: 'object' } },
254
+ res: { body: { type: 'object' } },
255
+ },
256
+ errors: [],
257
+ } as unknown as AnyHttpRouteDoc
258
+
259
+ const { emitter, calls } = makeSpyEmitter({
260
+ PathParams: ok('public struct PathParams: Codable { public let id: String }', 'PathParams'),
261
+ Response: ok('public struct Response: Codable { public let id: String }', 'Response'),
262
+ })
263
+
264
+ emitSwiftRoute(route, emitter, noErrors)
265
+ expect(calls.map((c) => c.opts.rootTypeName)).not.toContain('ResponseHeaders')
266
+ })
267
+
268
+ it('processes http-stream routes (not skipped) and emits Yield/ReturnType slots', () => {
269
+ const route = {
270
+ kind: 'http-stream',
271
+ name: 'TailLogs',
272
+ method: 'GET',
273
+ fullPath: '/logs/tail',
274
+ jsonSchema: {
275
+ req: { query: { type: 'object' } },
276
+ yield: { type: 'object' },
277
+ returnType: { type: 'object' },
278
+ },
279
+ errors: [],
280
+ } as unknown as AnyHttpRouteDoc
281
+
282
+ const { emitter, calls } = makeSpyEmitter({
283
+ Query: ok('public struct Query: Codable { public let filter: String? }', 'Query'),
284
+ Yield: ok('public struct Yield: Codable { public let line: String }', 'Yield'),
285
+ ReturnType: ok('public struct ReturnType: Codable { public let count: Int }', 'ReturnType'),
286
+ })
287
+
288
+ const result = emitSwiftRoute(route, emitter, noErrors)
289
+ expect(result.skipped).toBeFalsy()
290
+ expect(calls.map((c) => c.opts.rootTypeName)).toEqual(['Query', 'Yield', 'ReturnType'])
291
+ expect(result.code).toContain('public static let method = "GET"')
292
+ expect(result.code).toContain('public static let path = "/logs/tail"')
293
+ })
294
+
212
295
  it('does not include passthrough keys when caller omits them', () => {
213
296
  const route = {
214
297
  kind: 'api',
215
298
  name: 'X',
216
299
  method: 'GET',
217
300
  fullPath: '/x',
218
- schema: { returnType: { type: 'object' } },
301
+ jsonSchema: { res: { body: { type: 'object' } } },
219
302
  errors: [],
220
303
  } as unknown as AnyHttpRouteDoc
221
304
 
@@ -246,7 +329,7 @@ describe('emitSwiftRoute', () => {
246
329
  name: 'GetUser',
247
330
  method: 'GET',
248
331
  fullPath: '/users/:id',
249
- schema: { input: { pathParams: { type: 'object' } } },
332
+ jsonSchema: { req: { pathParams: { type: 'object' } } },
250
333
  errors: [],
251
334
  } as unknown as AnyHttpRouteDoc
252
335
 
@@ -265,7 +348,7 @@ describe('emitSwiftRoute', () => {
265
348
  name: 'GetUser',
266
349
  method: 'GET',
267
350
  fullPath: '/users/:id',
268
- schema: { input: { pathParams: { type: 'object' } } },
351
+ jsonSchema: { req: { pathParams: { type: 'object' } } },
269
352
  errors: ['NotFound'],
270
353
  } as unknown as AnyHttpRouteDoc
271
354
 
@@ -291,7 +374,7 @@ describe('emitSwiftRoute', () => {
291
374
  name: 'CreateUser',
292
375
  method: 'POST',
293
376
  fullPath: '/users',
294
- schema: {},
377
+ jsonSchema: {},
295
378
  errors: [],
296
379
  } as unknown as AnyHttpRouteDoc
297
380
  const result = emitSwiftRoute(route, createStubSwiftEmitter({}), noErrors, { accessLevel: 'internal' })
@@ -18,7 +18,10 @@ describe('emitSwiftScope', () => {
18
18
  name: 'GetUser',
19
19
  method: 'GET',
20
20
  fullPath: '/users/:id',
21
- schema: { input: { pathParams: { type: 'object' } }, returnType: { type: 'object' } },
21
+ jsonSchema: {
22
+ req: { pathParams: { type: 'object' } },
23
+ res: { body: { type: 'object' } },
24
+ },
22
25
  errors: [],
23
26
  } as unknown as AnyHttpRouteDoc
24
27
 
@@ -41,8 +44,8 @@ describe('emitSwiftScope', () => {
41
44
  })
42
45
 
43
46
  it('joins multiple routes inside one scope enum, separated by a blank line', () => {
44
- const route1 = { kind: 'api', name: 'GetUser', method: 'GET', fullPath: '/users/:id', schema: {}, errors: [] } as unknown as AnyHttpRouteDoc
45
- const route2 = { kind: 'api', name: 'CreateUser', method: 'POST', fullPath: '/users', schema: {}, errors: [] } as unknown as AnyHttpRouteDoc
47
+ const route1 = { kind: 'api', name: 'GetUser', method: 'GET', fullPath: '/users/:id', jsonSchema: {}, errors: [] } as unknown as AnyHttpRouteDoc
48
+ const route2 = { kind: 'api', name: 'CreateUser', method: 'POST', fullPath: '/users', jsonSchema: {}, errors: [] } as unknown as AnyHttpRouteDoc
46
49
  const group: ScopeGroup = { scopeKey: 'users', camelCase: 'users', routes: [route1, route2] }
47
50
  const emitter = createStubSwiftEmitter({})
48
51
 
@@ -74,8 +77,8 @@ describe('emitSwiftScope', () => {
74
77
  })
75
78
 
76
79
  it('dedupes and sorts imports across all routes in the scope', () => {
77
- const route1 = { kind: 'api', name: 'A', method: 'GET', fullPath: '/a', schema: { returnType: { type: 'object' } }, errors: [] } as unknown as AnyHttpRouteDoc
78
- const route2 = { kind: 'api', name: 'B', method: 'GET', fullPath: '/b', schema: { returnType: { type: 'object' } }, errors: [] } as unknown as AnyHttpRouteDoc
80
+ const route1 = { kind: 'api', name: 'A', method: 'GET', fullPath: '/a', jsonSchema: { res: { body: { type: 'object' } } }, errors: [] } as unknown as AnyHttpRouteDoc
81
+ const route2 = { kind: 'api', name: 'B', method: 'GET', fullPath: '/b', jsonSchema: { res: { body: { type: 'object' } } }, errors: [] } as unknown as AnyHttpRouteDoc
79
82
  const group: ScopeGroup = { scopeKey: 'multi', camelCase: 'multi', routes: [route1, route2] }
80
83
  const emitter = {
81
84
  emit(_s: unknown, opts: SwiftEmitOptions): SwiftEmitResult {
@@ -93,7 +96,7 @@ describe('emitSwiftScope', () => {
93
96
  })
94
97
 
95
98
  it('threads all 6 passthrough opts to every emitter call', () => {
96
- const route = { kind: 'api', name: 'X', method: 'GET', fullPath: '/x', schema: { returnType: { type: 'object' } }, errors: [] } as unknown as AnyHttpRouteDoc
99
+ const route = { kind: 'api', name: 'X', method: 'GET', fullPath: '/x', jsonSchema: { res: { body: { type: 'object' } } }, errors: [] } as unknown as AnyHttpRouteDoc
97
100
  const group: ScopeGroup = { scopeKey: 'x', camelCase: 'x', routes: [route] }
98
101
 
99
102
  const calls: SwiftEmitOptions[] = []
@@ -130,7 +133,7 @@ describe('emitSwiftScope', () => {
130
133
  })
131
134
 
132
135
  it('applies accessLevel to the outer scope enum and the route enum wrappers', () => {
133
- const route = { kind: 'api', name: 'GetUser', method: 'GET', fullPath: '/users', schema: {}, errors: [] } as unknown as AnyHttpRouteDoc
136
+ const route = { kind: 'api', name: 'GetUser', method: 'GET', fullPath: '/users', jsonSchema: {}, errors: [] } as unknown as AnyHttpRouteDoc
134
137
  const group: ScopeGroup = { scopeKey: 'users', camelCase: 'users', routes: [route] }
135
138
  const emitter = createStubSwiftEmitter({})
136
139
 
@@ -142,8 +145,8 @@ describe('emitSwiftScope', () => {
142
145
  })
143
146
 
144
147
  it('collects skipped stream-route names', () => {
145
- const stream = { kind: 'stream', name: 'WatchUsers', method: 'GET', path: '/u/stream', schema: {}, errors: [] } as unknown as AnyHttpRouteDoc
146
- const api = { kind: 'api', name: 'GetUser', method: 'GET', fullPath: '/u', schema: { returnType: { type: 'object' } }, errors: [] } as unknown as AnyHttpRouteDoc
148
+ const stream = { kind: 'stream', name: 'WatchUsers', method: 'GET', path: '/u/stream', jsonSchema: {}, errors: [] } as unknown as AnyHttpRouteDoc
149
+ const api = { kind: 'api', name: 'GetUser', method: 'GET', fullPath: '/u', jsonSchema: { res: { body: { type: 'object' } } }, errors: [] } as unknown as AnyHttpRouteDoc
147
150
  const group: ScopeGroup = { scopeKey: 'u', camelCase: 'u', routes: [stream, api] }
148
151
 
149
152
  const emitter = createStubSwiftEmitter({