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
@@ -91,6 +91,45 @@ export interface ExtractedTypeOutput {
91
91
  body: string
92
92
  }
93
93
 
94
+ /**
95
+ * Splits a block of ajsc output into individual top-level declarations.
96
+ *
97
+ * ajsc glues sibling extracted declarations with a single `\n`, but each
98
+ * declaration may itself span multiple lines (multi-line enums, object bodies
99
+ * with per-property JSDoc). A simple line/`export`-prefix split would therefore
100
+ * break multi-line declarations apart. Instead we walk lines tracking brace
101
+ * depth and close a declaration when depth returns to 0 on a line that ends in
102
+ * a statement terminator (`;` or `}`). Any leading comment lines (JSDoc) stay
103
+ * attached to the declaration that follows them.
104
+ */
105
+ function splitTopLevelDeclarations(block: string): string[] {
106
+ const decls: string[] = []
107
+ let current: string[] = []
108
+ let depth = 0
109
+
110
+ const flush = () => {
111
+ const joined = current.join('\n').trim()
112
+ if (joined) decls.push(joined)
113
+ current = []
114
+ }
115
+
116
+ for (const line of block.split('\n')) {
117
+ current.push(line)
118
+ for (const ch of line) {
119
+ if (ch === '{') depth += 1
120
+ else if (ch === '}') depth -= 1
121
+ }
122
+ const trimmed = line.trimEnd()
123
+ if (depth <= 0 && (trimmed.endsWith(';') || trimmed.endsWith('}'))) {
124
+ flush()
125
+ depth = 0
126
+ }
127
+ }
128
+ flush()
129
+
130
+ return decls
131
+ }
132
+
94
133
  /**
95
134
  * Converts a JSON Schema to extracted TypeScript types using ajsc with
96
135
  * `inlineTypes: false`. This produces named sub-types (objects, enums) that
@@ -122,13 +161,23 @@ export async function jsonSchemaToExtractedTypes(
122
161
  )
123
162
  }
124
163
 
125
- // ajsc with inlineTypes: false produces blocks separated by blank lines:
164
+ // ajsc with inlineTypes: false produces output like:
126
165
  // export enum Status { Active = "active" }
127
166
  // export type Contact = { name: string; };
167
+ //
128
168
  // export type Root = { status: Status; contacts: Array<Contact>; };
129
169
  //
130
- // The Root type is always the last declaration.
170
+ // Crucially, *sibling* extracted declarations are joined by a SINGLE "\n"
171
+ // (one block) while the Root is separated by a blank line ("\n\n"). Splitting
172
+ // only on blank lines would therefore fuse two or more sibling declarations
173
+ // into one array element — and every downstream consumer (extractedDeclName,
174
+ // renameExtractedTypes, the namespace dedup) assumes one declaration per
175
+ // element, so the non-first siblings would be mis-parsed and emitted twice
176
+ // (`error TS2300: Duplicate identifier`). We split on blank lines first, then
177
+ // split each block into individual statements so each element holds exactly
178
+ // one declaration. The Root type is always the last declaration.
131
179
  const blocks = code.split(/\n\n+/).map((b) => b.trim()).filter(Boolean)
180
+ const rawDecls = blocks.flatMap(splitTopLevelDeclarations)
132
181
 
133
182
  const declarations: string[] = []
134
183
  let body = ''
@@ -139,13 +188,13 @@ export async function jsonSchemaToExtractedTypes(
139
188
  // declarations branch instead of being eaten as the body.
140
189
  const rootDeclPattern = /^export\s+type\s+Root\s*=\s*/
141
190
 
142
- for (const block of blocks) {
143
- if (rootDeclPattern.test(block)) {
191
+ for (const decl of rawDecls) {
192
+ if (rootDeclPattern.test(decl)) {
144
193
  // Strip "export type Root = " prefix and trailing ";"
145
- body = block.replace(rootDeclPattern, '').replace(/;\s*$/, '').trim()
194
+ body = decl.replace(rootDeclPattern, '').replace(/;\s*$/, '').trim()
146
195
  } else {
147
196
  // Sub-type or enum declaration — remove trailing ";" for consistency
148
- declarations.push(block.replace(/;\s*$/, ''))
197
+ declarations.push(decl.replace(/;\s*$/, ''))
149
198
  }
150
199
  }
151
200
 
@@ -188,25 +237,28 @@ export function extractedDeclName(decl: string): string | undefined {
188
237
  * alias is generated (`Params` → `ParamsInner`, then `ParamsInner2`, …) so
189
238
  * the renamed type reads like a real, intentional name (not a placeholder).
190
239
  * The declaration is rewritten with the new name and every word-boundary
191
- * occurrence in `result.body` is substituted so the body keeps referencing
192
- * the renamed type.
240
+ * occurrence of the old name is substituted in `result.body` AND in every
241
+ * sibling declaration. The sibling patch matters because extracted sub-types
242
+ * reference each other (e.g. `Contact = { address: Address }`): renaming
243
+ * `Address` → `AddressInner` must update that reference too, otherwise the
244
+ * renamed type silently resolves to a different schema's sub-type of the same
245
+ * name (a latent wrong-type bug that only hides when the shapes happen to match).
193
246
  */
194
247
  export function renameExtractedTypes(
195
248
  result: ExtractedTypeOutput,
196
249
  taken: Set<string>,
197
250
  ): ExtractedTypeOutput {
198
- let body = result.body
199
- const declarations: string[] = []
251
+ // Work on a mutable copy so we can patch cross-references after renaming.
252
+ const declarations = [...result.declarations]
253
+ const renames = new Map<string, string>()
200
254
 
201
- for (const decl of result.declarations) {
255
+ // Pass 1: decide renames and rewrite each declaration's leading identifier.
256
+ for (let i = 0; i < declarations.length; i += 1) {
257
+ const decl = declarations[i]!
202
258
  const name = extractedDeclName(decl)
203
- if (name == null) {
204
- declarations.push(decl)
205
- continue
206
- }
259
+ if (name == null) continue
207
260
  if (!taken.has(name)) {
208
261
  taken.add(name)
209
- declarations.push(decl)
210
262
  continue
211
263
  }
212
264
 
@@ -220,16 +272,25 @@ export function renameExtractedTypes(
220
272
  suffix += 1
221
273
  }
222
274
  taken.add(alias)
275
+ renames.set(name, alias)
223
276
 
224
- // Rewrite the declaration's leading identifier.
225
- const renamedDecl = decl.replace(
277
+ declarations[i] = decl.replace(
226
278
  new RegExp(`^(export\\s+(?:type|enum|interface)\\s+)${name}\\b`),
227
279
  `$1${alias}`,
228
280
  )
229
- declarations.push(renamedDecl)
281
+ }
230
282
 
231
- // Patch every word-boundary occurrence of the old name in the body.
232
- body = body.replace(new RegExp(`\\b${name}\\b`, 'g'), alias)
283
+ // Pass 2: patch every reference to a renamed name in the body and in every
284
+ // declaration body so cross-references between sibling sub-types follow the
285
+ // rename. `\bAddress\b` does not match inside `AddressInner` (no word
286
+ // boundary between `s` and `I`), so already-renamed identifiers are untouched.
287
+ let body = result.body
288
+ for (const [name, alias] of renames) {
289
+ const re = new RegExp(`\\b${name}\\b`, 'g')
290
+ body = body.replace(re, alias)
291
+ for (let i = 0; i < declarations.length; i += 1) {
292
+ declarations[i] = declarations[i]!.replace(re, alias)
293
+ }
233
294
  }
234
295
 
235
296
  return { declarations, body }
@@ -375,7 +375,7 @@ describe('runPipeline (kotlin target)', () => {
375
375
  scope: 'users',
376
376
  method: 'GET',
377
377
  fullPath: '/users/:id',
378
- schema: { input: { pathParams: { type: 'object' } }, returnType: { type: 'object' } },
378
+ jsonSchema: { req: { pathParams: { type: 'object' } }, res: { body: { type: 'object' } } },
379
379
  errors: [],
380
380
  },
381
381
  ],
@@ -438,7 +438,7 @@ describe('runPipeline (kotlin target)', () => {
438
438
  routes: [
439
439
  {
440
440
  kind: 'api', name: 'GetUser', scope: 'users', method: 'GET', fullPath: '/users/:id',
441
- schema: { input: { pathParams: { type: 'object' } }, returnType: { type: 'object' } },
441
+ jsonSchema: { req: { pathParams: { type: 'object' } }, res: { body: { type: 'object' } } },
442
442
  errors: [],
443
443
  },
444
444
  ],
@@ -466,9 +466,9 @@ describe('runPipeline (kotlin target)', () => {
466
466
  const envelope = {
467
467
  basePath: '/api', headers: [], version: '1' as const, errors: [],
468
468
  routes: [
469
- { kind: 'stream', name: 'WatchA', scope: 's', method: 'GET', path: '/a', schema: {}, errors: [] },
470
- { kind: 'stream', name: 'WatchB', scope: 's', method: 'GET', path: '/b', schema: {}, errors: [] },
471
- { kind: 'api', name: 'GetThing', scope: 's', method: 'GET', fullPath: '/c', schema: { returnType: { type: 'object' } }, errors: [] },
469
+ { kind: 'stream', name: 'WatchA', scope: 's', method: 'GET', path: '/a', jsonSchema: {}, errors: [] },
470
+ { kind: 'stream', name: 'WatchB', scope: 's', method: 'GET', path: '/b', jsonSchema: {}, errors: [] },
471
+ { kind: 'api', name: 'GetThing', scope: 's', method: 'GET', fullPath: '/c', jsonSchema: { res: { body: { type: 'object' } } }, errors: [] },
472
472
  ],
473
473
  } as any
474
474
  await runPipeline({
@@ -493,7 +493,7 @@ describe('runPipeline (kotlin target)', () => {
493
493
  try {
494
494
  const envelope = {
495
495
  basePath: '/api', headers: [], version: '1' as const, errors: [],
496
- routes: [{ kind: 'api', name: 'X', scope: 's', method: 'GET', fullPath: '/x', schema: { returnType: { type: 'object' } }, errors: [] }],
496
+ routes: [{ kind: 'api', name: 'X', scope: 's', method: 'GET', fullPath: '/x', jsonSchema: { res: { body: { type: 'object' } } }, errors: [] }],
497
497
  } as any
498
498
  await runPipeline({
499
499
  envelope, outDir: 'out', dryRun: true,
@@ -518,7 +518,7 @@ describe('runPipeline (kotlin target)', () => {
518
518
 
519
519
  const envelope = {
520
520
  basePath: '/api', headers: [], version: '1' as const, errors: [],
521
- routes: [{ kind: 'api', name: 'GetUser', scope: 'users', method: 'GET', fullPath: '/u', schema: { returnType: { type: 'object' } }, errors: [] }],
521
+ routes: [{ kind: 'api', name: 'GetUser', scope: 'users', method: 'GET', fullPath: '/u', jsonSchema: { res: { body: { type: 'object' } } }, errors: [] }],
522
522
  } as any
523
523
 
524
524
  await runPipeline({
@@ -54,11 +54,11 @@ describe('resolveEnvelope', () => {
54
54
  })
55
55
 
56
56
  // Defensive (downstream bug repro): forgetting `builder.build()` is a common
57
- // cause of an empty routes array because hono-rpc/hono-api/hono-stream/express-rpc
58
- // builders only populate their `_docs` array inside `build()`. The current
59
- // error message says "Register at least one procedure", which led the
60
- // downstream dev to look in the wrong place. The message should mention
61
- // `.build()` as a likely cause so the next person hits the right fix faster.
57
+ // cause of an empty routes array because the hono builder only populates
58
+ // its `_docs` array inside `build()`. The current error message says
59
+ // "Register at least one procedure", which led the downstream dev to look
60
+ // in the wrong place. The message should mention `.build()` as a likely
61
+ // cause so the next person hits the right fix faster.
62
62
  it('empty-routes error message mentions builder.build() as a likely cause', async () => {
63
63
  const empty: DocEnvelope = { basePath: '', headers: [], errors: [], routes: [] }
64
64
  await expect(resolveEnvelope({ envelope: empty })).rejects.toThrow(/\.build\(\)/)
@@ -55,7 +55,7 @@ export async function resolveEnvelope(input: ResolveInput): Promise<DocEnvelope>
55
55
  throw new Error(
56
56
  '[ts-procedures-codegen] DocEnvelope has an empty "routes" array. ' +
57
57
  'Common causes: (1) you forgot to call `builder.build()` before passing ' +
58
- 'the builder to `DocRegistry.from(...)` — hono/express builders only populate ' +
58
+ 'the builder to `DocRegistry.from(...)` — hono builders only populate ' +
59
59
  '`docs` inside `build()`; (2) no procedures registered with the builder.'
60
60
  )
61
61
  }
@@ -2,54 +2,137 @@ import { describe, expect, it } from 'vitest'
2
2
  import { extractRouteSlots } from './route-slots.js'
3
3
  import type { AnyHttpRouteDoc } from '../../../implementations/types.js'
4
4
 
5
- const r = (schema: Record<string, unknown> | undefined): AnyHttpRouteDoc =>
6
- ({ name: 'X', kind: 'api', method: 'GET', fullPath: '/x', schema } as unknown as AnyHttpRouteDoc)
5
+ // Helpers for constructing minimal route docs per kind
6
+ function apiRoute(jsonSchema: Record<string, unknown>): AnyHttpRouteDoc {
7
+ return { name: 'X', kind: 'api', method: 'get', path: '/x', fullPath: '/x', jsonSchema } as unknown as AnyHttpRouteDoc
8
+ }
7
9
 
8
- describe('extractRouteSlots', () => {
9
- it('returns no slots when schema is undefined', () => {
10
- expect(extractRouteSlots(r(undefined))).toEqual([])
11
- })
10
+ function httpStreamRoute(jsonSchema: Record<string, unknown>): AnyHttpRouteDoc {
11
+ return { name: 'X', kind: 'http-stream', method: 'get', path: '/x', fullPath: '/x', streamMode: 'sse', jsonSchema } as unknown as AnyHttpRouteDoc
12
+ }
13
+
14
+ function rpcRoute(jsonSchema: Record<string, unknown>): AnyHttpRouteDoc {
15
+ return { name: 'X', kind: 'rpc', method: 'post', path: '/x', scope: 'x', version: 1, jsonSchema } as unknown as AnyHttpRouteDoc
16
+ }
12
17
 
13
- it('returns no slots when schema is empty', () => {
14
- expect(extractRouteSlots(r({}))).toEqual([])
18
+ function streamRoute(jsonSchema: Record<string, unknown>): AnyHttpRouteDoc {
19
+ return { name: 'X', kind: 'stream', path: '/x', scope: 'x', version: 1, methods: ['get'], streamMode: 'sse', jsonSchema } as unknown as AnyHttpRouteDoc
20
+ }
21
+
22
+ describe('extractRouteSlots — api kind', () => {
23
+ it('returns no slots when jsonSchema is empty', () => {
24
+ expect(extractRouteSlots(apiRoute({}))).toEqual([])
15
25
  })
16
26
 
17
- it('returns the deterministic slot order: PathParams, Query, Body, Response', () => {
27
+ it('returns the deterministic slot order: PathParams, Query, Body, Headers, Response, ResponseHeaders', () => {
18
28
  const slots = extractRouteSlots(
19
- r({
20
- input: {
21
- body: { type: 'object', x: 'body' },
22
- query: { type: 'object', x: 'query' },
23
- pathParams: { type: 'object', x: 'path' },
29
+ apiRoute({
30
+ req: {
31
+ body: { type: 'object', tag: 'body' },
32
+ query: { type: 'object', tag: 'query' },
33
+ pathParams: { type: 'object', tag: 'path' },
34
+ headers: { type: 'object', tag: 'headers' },
35
+ },
36
+ res: {
37
+ body: { type: 'object', tag: 'response' },
38
+ headers: { type: 'object', tag: 'resHeaders' },
24
39
  },
25
- returnType: { type: 'object', x: 'response' },
26
40
  }),
27
41
  )
28
- expect(slots.map((s) => s.rootName)).toEqual(['PathParams', 'Query', 'Body', 'Response'])
42
+ expect(slots.map((s) => s.rootName)).toEqual(['PathParams', 'Query', 'Body', 'Headers', 'Response', 'ResponseHeaders'])
29
43
  })
30
44
 
31
45
  it('omits slots whose source is null or undefined', () => {
32
46
  const slots = extractRouteSlots(
33
- r({
34
- input: { pathParams: { type: 'object' }, query: null, body: undefined },
35
- // returnType missing
47
+ apiRoute({
48
+ req: { pathParams: { type: 'object' }, query: null, body: undefined },
36
49
  }),
37
50
  )
38
51
  expect(slots.map((s) => s.rootName)).toEqual(['PathParams'])
39
52
  })
40
53
 
41
- it('attaches the source schema verbatim to each slot', () => {
54
+ it('attaches source schemas verbatim', () => {
42
55
  const path = { type: 'object', tag: 'p' }
43
- const ret = { type: 'object', tag: 'r' }
44
- const slots = extractRouteSlots(r({ input: { pathParams: path }, returnType: ret }))
56
+ const body = { type: 'object', tag: 'b' }
57
+ const slots = extractRouteSlots(apiRoute({ req: { pathParams: path, body }, res: {} }))
45
58
  expect(slots).toEqual([
46
59
  { rootName: 'PathParams', source: path },
47
- { rootName: 'Response', source: ret },
60
+ { rootName: 'Body', source: body },
61
+ ])
62
+ })
63
+
64
+ it('reads responseHeaders from res.headers', () => {
65
+ const resHeaders = { type: 'object', tag: 'rh' }
66
+ const slots = extractRouteSlots(apiRoute({ res: { headers: resHeaders } }))
67
+ expect(slots).toEqual([{ rootName: 'ResponseHeaders', source: resHeaders }])
68
+ })
69
+ })
70
+
71
+ describe('extractRouteSlots — http-stream kind', () => {
72
+ it('returns no slots when jsonSchema is empty', () => {
73
+ expect(extractRouteSlots(httpStreamRoute({}))).toEqual([])
74
+ })
75
+
76
+ it('returns the deterministic slot order: PathParams, Query, Body, Headers, ResponseHeaders, Yield, ReturnType', () => {
77
+ const slots = extractRouteSlots(
78
+ httpStreamRoute({
79
+ req: {
80
+ pathParams: { type: 'object', tag: 'path' },
81
+ query: { type: 'object', tag: 'query' },
82
+ body: { type: 'object', tag: 'body' },
83
+ headers: { type: 'object', tag: 'headers' },
84
+ },
85
+ res: { headers: { type: 'object', tag: 'resHeaders' } },
86
+ yield: { type: 'object', tag: 'yield' },
87
+ returnType: { type: 'object', tag: 'return' },
88
+ }),
89
+ )
90
+ expect(slots.map((s) => s.rootName)).toEqual([
91
+ 'PathParams', 'Query', 'Body', 'Headers', 'ResponseHeaders', 'Yield', 'ReturnType',
48
92
  ])
49
93
  })
50
94
 
51
- it('returns no slots for stream/no-schema routes', () => {
52
- const stream = { name: 'S', kind: 'stream', method: 'GET', path: '/s' } as unknown as AnyHttpRouteDoc
53
- expect(extractRouteSlots(stream)).toEqual([])
95
+ it('attaches yield and returnType sources correctly', () => {
96
+ const yieldSchema = { type: 'object', tag: 'y' }
97
+ const returnSchema = { type: 'object', tag: 'r' }
98
+ const slots = extractRouteSlots(httpStreamRoute({ yield: yieldSchema, returnType: returnSchema }))
99
+ expect(slots).toEqual([
100
+ { rootName: 'Yield', source: yieldSchema },
101
+ { rootName: 'ReturnType', source: returnSchema },
102
+ ])
103
+ })
104
+ })
105
+
106
+ describe('extractRouteSlots — rpc kind', () => {
107
+ it('returns no slots when jsonSchema is empty', () => {
108
+ expect(extractRouteSlots(rpcRoute({}))).toEqual([])
109
+ })
110
+
111
+ it('maps body and response slots', () => {
112
+ const body = { type: 'object', tag: 'b' }
113
+ const response = { type: 'object', tag: 'r' }
114
+ const slots = extractRouteSlots(rpcRoute({ body, response }))
115
+ expect(slots).toEqual([
116
+ { rootName: 'Body', source: body },
117
+ { rootName: 'Response', source: response },
118
+ ])
119
+ })
120
+ })
121
+
122
+ describe('extractRouteSlots — stream kind', () => {
123
+ it('returns no slots when jsonSchema is empty', () => {
124
+ expect(extractRouteSlots(streamRoute({}))).toEqual([])
125
+ })
126
+
127
+ it('maps params→Body, yieldType→Yield, returnType→ReturnType', () => {
128
+ const params = { type: 'object', tag: 'p' }
129
+ const yieldType = { type: 'object', tag: 'y' }
130
+ const returnType = { type: 'object', tag: 'r' }
131
+ const slots = extractRouteSlots(streamRoute({ params, yieldType, returnType }))
132
+ expect(slots).toEqual([
133
+ { rootName: 'Body', source: params },
134
+ { rootName: 'Yield', source: yieldType },
135
+ { rootName: 'ReturnType', source: returnType },
136
+ ])
54
137
  })
55
138
  })
@@ -1,9 +1,8 @@
1
1
  import type { AnyHttpRouteDoc } from '../../../implementations/types.js'
2
2
 
3
3
  /**
4
- * A "slot" is one of the deterministic schema sources a route exposes:
5
- * `pathParams`, `query`, `body` (under `schema.input`) and the response
6
- * (`schema.returnType`). Targets emit one type per non-null slot.
4
+ * A "slot" is one of the deterministic schema sources a route exposes.
5
+ * Targets emit one type per non-null slot.
7
6
  */
8
7
  export interface RouteSlot {
9
8
  /** Stable identifier used as the emitted type's `rootTypeName`. */
@@ -15,18 +14,56 @@ export interface RouteSlot {
15
14
  /**
16
15
  * Returns the deterministic ordered slot list for a route, filtered to slots
17
16
  * with non-null sources. Order is fixed at the module level for stable output.
17
+ *
18
+ * Kind dispatch:
19
+ * - `'api'` — reads from `jsonSchema.req` / `jsonSchema.res` (new envelope shape)
20
+ * - `'http-stream'` — reads from `jsonSchema.req` / `jsonSchema.res` / `jsonSchema.yield` / `jsonSchema.returnType`
21
+ * - `'rpc'` — reads from `jsonSchema.body` / `jsonSchema.response`
22
+ * - `'stream'` — reads from `jsonSchema.params` / `jsonSchema.yieldType` / `jsonSchema.returnType`
18
23
  */
19
24
  export function extractRouteSlots(route: AnyHttpRouteDoc): RouteSlot[] {
20
- const schema = (route as { schema?: Record<string, unknown> }).schema ?? {}
21
- const input = (schema.input ?? {}) as Record<string, unknown>
25
+ const kind = route.kind
22
26
 
23
27
  // Order is load-bearing: targets emit slots in this sequence.
24
- const slots: RouteSlot[] = [
25
- { rootName: 'PathParams', source: input.pathParams },
26
- { rootName: 'Query', source: input.query },
27
- { rootName: 'Body', source: input.body },
28
- { rootName: 'Response', source: schema.returnType },
29
- ]
28
+ let slots: RouteSlot[]
29
+
30
+ if (kind === 'api') {
31
+ const req = route.jsonSchema.req ?? {}
32
+ const res = route.jsonSchema.res ?? {}
33
+ slots = [
34
+ { rootName: 'PathParams', source: req.pathParams },
35
+ { rootName: 'Query', source: req.query },
36
+ { rootName: 'Body', source: req.body },
37
+ { rootName: 'Headers', source: req.headers },
38
+ { rootName: 'Response', source: res.body },
39
+ { rootName: 'ResponseHeaders', source: res.headers },
40
+ ]
41
+ } else if (kind === 'http-stream') {
42
+ const req = route.jsonSchema.req ?? {}
43
+ const res = route.jsonSchema.res ?? {}
44
+ slots = [
45
+ { rootName: 'PathParams', source: req.pathParams },
46
+ { rootName: 'Query', source: req.query },
47
+ { rootName: 'Body', source: req.body },
48
+ { rootName: 'Headers', source: req.headers },
49
+ { rootName: 'ResponseHeaders', source: res.headers },
50
+ { rootName: 'Yield', source: route.jsonSchema.yield },
51
+ { rootName: 'ReturnType', source: route.jsonSchema.returnType },
52
+ ]
53
+ } else if (kind === 'rpc') {
54
+ slots = [
55
+ { rootName: 'Body', source: route.jsonSchema.body },
56
+ { rootName: 'Response', source: route.jsonSchema.response },
57
+ ]
58
+ } else if (kind === 'stream') {
59
+ slots = [
60
+ { rootName: 'Body', source: route.jsonSchema.params },
61
+ { rootName: 'Yield', source: route.jsonSchema.yieldType },
62
+ { rootName: 'ReturnType', source: route.jsonSchema.returnType },
63
+ ]
64
+ } else {
65
+ slots = []
66
+ }
30
67
 
31
68
  return slots.filter((s) => s.source != null)
32
69
  }
@@ -118,4 +118,77 @@ object Users {
118
118
  )
119
119
  }
120
120
  }
121
+
122
+ object DownloadUser {
123
+ const val method = "GET"
124
+ const val pathTemplate = "/users/{id}/download"
125
+ fun path(p: PathParams): String = "/users/${p.id}/download"
126
+
127
+ @Serializable
128
+ data class PathParams(
129
+ val id: String,
130
+ )
131
+
132
+ @Serializable
133
+ data class Response(
134
+ val id: String,
135
+ val name: String,
136
+ @SerialName("created-at") @Contextual val createdAt: java.time.Instant,
137
+ val address: Address,
138
+ ) {
139
+ @Serializable
140
+ data class Address(
141
+ val street: String,
142
+ val city: String,
143
+ )
144
+ }
145
+
146
+ @Serializable
147
+ data class ResponseHeaders(
148
+ @SerialName("x-download-token") val xDownloadToken: String,
149
+ @SerialName("content-disposition") val contentDisposition: String? = null,
150
+ )
151
+ }
152
+
153
+ object WatchUsers {
154
+ const val method = "GET"
155
+ const val pathTemplate = "/users/watch"
156
+ const val path = "/users/watch"
157
+
158
+ @Serializable
159
+ data class Query(
160
+ val status: Status? = null,
161
+ val limit: Long? = null,
162
+ ) {
163
+ @Serializable
164
+ enum class Status {
165
+ @SerialName("active") ACTIVE,
166
+ @SerialName("inactive") INACTIVE,
167
+ }
168
+ }
169
+
170
+ @Serializable
171
+ data class ResponseHeaders(
172
+ @SerialName("x-download-token") val xDownloadToken: String,
173
+ @SerialName("content-disposition") val contentDisposition: String? = null,
174
+ )
175
+
176
+ @Serializable
177
+ data class Yield(
178
+ val id: String,
179
+ val event: Event,
180
+ ) {
181
+ @Serializable
182
+ enum class Event {
183
+ @SerialName("created") CREATED,
184
+ @SerialName("updated") UPDATED,
185
+ @SerialName("deleted") DELETED,
186
+ }
187
+ }
188
+
189
+ @Serializable
190
+ data class ReturnType(
191
+ val count: Long,
192
+ )
193
+ }
121
194
  }