ts-procedures 5.9.1 → 5.10.2

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 (305) hide show
  1. package/README.md +1 -1
  2. package/agent_config/bin/postinstall.mjs +3 -3
  3. package/agent_config/bin/setup.mjs +22 -11
  4. package/agent_config/claude-code/agents/ts-procedures-architect.md +46 -101
  5. package/agent_config/claude-code/skills/{guide → ts-procedures}/SKILL.md +50 -35
  6. package/agent_config/claude-code/skills/{guide → ts-procedures}/anti-patterns.md +6 -5
  7. package/agent_config/claude-code/skills/{guide → ts-procedures}/api-reference.md +60 -49
  8. package/agent_config/claude-code/skills/ts-procedures-review/SKILL.md +48 -0
  9. package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/SKILL.md +19 -24
  10. package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/client.md +115 -0
  11. package/agent_config/lib/install-claude.mjs +35 -87
  12. package/build/src/client/call.d.ts +14 -0
  13. package/build/src/client/call.js +47 -0
  14. package/build/src/client/call.js.map +1 -0
  15. package/build/src/client/call.test.d.ts +1 -0
  16. package/build/src/client/call.test.js +124 -0
  17. package/build/src/client/call.test.js.map +1 -0
  18. package/build/src/client/errors.d.ts +25 -0
  19. package/build/src/client/errors.js +33 -0
  20. package/build/src/client/errors.js.map +1 -0
  21. package/build/src/client/errors.test.d.ts +1 -0
  22. package/build/src/client/errors.test.js +41 -0
  23. package/build/src/client/errors.test.js.map +1 -0
  24. package/build/src/client/fetch-adapter.d.ts +12 -0
  25. package/build/src/client/fetch-adapter.js +156 -0
  26. package/build/src/client/fetch-adapter.js.map +1 -0
  27. package/build/src/client/fetch-adapter.test.d.ts +1 -0
  28. package/build/src/client/fetch-adapter.test.js +271 -0
  29. package/build/src/client/fetch-adapter.test.js.map +1 -0
  30. package/build/src/client/hooks.d.ts +17 -0
  31. package/build/src/client/hooks.js +40 -0
  32. package/build/src/client/hooks.js.map +1 -0
  33. package/build/src/client/hooks.test.d.ts +1 -0
  34. package/build/src/client/hooks.test.js +163 -0
  35. package/build/src/client/hooks.test.js.map +1 -0
  36. package/build/src/client/index.d.ts +22 -0
  37. package/build/src/client/index.js +67 -0
  38. package/build/src/client/index.js.map +1 -0
  39. package/build/src/client/index.test.d.ts +1 -0
  40. package/build/src/client/index.test.js +231 -0
  41. package/build/src/client/index.test.js.map +1 -0
  42. package/build/src/client/request-builder.d.ts +13 -0
  43. package/build/src/client/request-builder.js +53 -0
  44. package/build/src/client/request-builder.js.map +1 -0
  45. package/build/src/client/request-builder.test.d.ts +1 -0
  46. package/build/src/client/request-builder.test.js +160 -0
  47. package/build/src/client/request-builder.test.js.map +1 -0
  48. package/build/src/client/stream.d.ts +27 -0
  49. package/build/src/client/stream.js +118 -0
  50. package/build/src/client/stream.js.map +1 -0
  51. package/build/src/client/stream.test.d.ts +1 -0
  52. package/build/src/client/stream.test.js +228 -0
  53. package/build/src/client/stream.test.js.map +1 -0
  54. package/build/src/client/types.d.ts +78 -0
  55. package/build/src/client/types.js +3 -0
  56. package/build/src/client/types.js.map +1 -0
  57. package/build/src/codegen/bin/cli.d.ts +45 -0
  58. package/build/src/codegen/bin/cli.js +246 -0
  59. package/build/src/codegen/bin/cli.js.map +1 -0
  60. package/build/src/codegen/bin/cli.test.d.ts +1 -0
  61. package/build/src/codegen/bin/cli.test.js +220 -0
  62. package/build/src/codegen/bin/cli.test.js.map +1 -0
  63. package/build/src/codegen/constants.d.ts +1 -0
  64. package/build/src/codegen/constants.js +2 -0
  65. package/build/src/codegen/constants.js.map +1 -0
  66. package/build/src/codegen/e2e.test.d.ts +1 -0
  67. package/build/src/codegen/e2e.test.js +464 -0
  68. package/build/src/codegen/e2e.test.js.map +1 -0
  69. package/build/src/codegen/emit-client-runtime.d.ts +9 -0
  70. package/build/src/codegen/emit-client-runtime.js +99 -0
  71. package/build/src/codegen/emit-client-runtime.js.map +1 -0
  72. package/build/src/codegen/emit-client-runtime.test.d.ts +1 -0
  73. package/build/src/codegen/emit-client-runtime.test.js +78 -0
  74. package/build/src/codegen/emit-client-runtime.test.js.map +1 -0
  75. package/build/src/codegen/emit-client-types.d.ts +8 -0
  76. package/build/src/codegen/emit-client-types.js +25 -0
  77. package/build/src/codegen/emit-client-types.js.map +1 -0
  78. package/build/src/codegen/emit-client-types.test.d.ts +1 -0
  79. package/build/src/codegen/emit-client-types.test.js +33 -0
  80. package/build/src/codegen/emit-client-types.test.js.map +1 -0
  81. package/build/src/codegen/emit-errors.d.ts +19 -0
  82. package/build/src/codegen/emit-errors.js +59 -0
  83. package/build/src/codegen/emit-errors.js.map +1 -0
  84. package/build/src/codegen/emit-errors.test.d.ts +1 -0
  85. package/build/src/codegen/emit-errors.test.js +175 -0
  86. package/build/src/codegen/emit-errors.test.js.map +1 -0
  87. package/build/src/codegen/emit-index.d.ts +12 -0
  88. package/build/src/codegen/emit-index.js +41 -0
  89. package/build/src/codegen/emit-index.js.map +1 -0
  90. package/build/src/codegen/emit-index.test.d.ts +1 -0
  91. package/build/src/codegen/emit-index.test.js +106 -0
  92. package/build/src/codegen/emit-index.test.js.map +1 -0
  93. package/build/src/codegen/emit-scope.d.ts +15 -0
  94. package/build/src/codegen/emit-scope.js +299 -0
  95. package/build/src/codegen/emit-scope.js.map +1 -0
  96. package/build/src/codegen/emit-scope.test.d.ts +1 -0
  97. package/build/src/codegen/emit-scope.test.js +559 -0
  98. package/build/src/codegen/emit-scope.test.js.map +1 -0
  99. package/build/src/codegen/emit-types.d.ts +43 -0
  100. package/build/src/codegen/emit-types.js +111 -0
  101. package/build/src/codegen/emit-types.js.map +1 -0
  102. package/build/src/codegen/emit-types.test.d.ts +1 -0
  103. package/build/src/codegen/emit-types.test.js +184 -0
  104. package/build/src/codegen/emit-types.test.js.map +1 -0
  105. package/build/src/codegen/group-routes.d.ts +23 -0
  106. package/build/src/codegen/group-routes.js +46 -0
  107. package/build/src/codegen/group-routes.js.map +1 -0
  108. package/build/src/codegen/group-routes.test.d.ts +1 -0
  109. package/build/src/codegen/group-routes.test.js +131 -0
  110. package/build/src/codegen/group-routes.test.js.map +1 -0
  111. package/build/src/codegen/index.d.ts +15 -0
  112. package/build/src/codegen/index.js +16 -0
  113. package/build/src/codegen/index.js.map +1 -0
  114. package/build/src/codegen/naming.d.ts +7 -0
  115. package/build/src/codegen/naming.js +21 -0
  116. package/build/src/codegen/naming.js.map +1 -0
  117. package/build/src/codegen/naming.test.d.ts +1 -0
  118. package/build/src/codegen/naming.test.js +40 -0
  119. package/build/src/codegen/naming.test.js.map +1 -0
  120. package/build/src/codegen/pipeline.d.ts +17 -0
  121. package/build/src/codegen/pipeline.js +78 -0
  122. package/build/src/codegen/pipeline.js.map +1 -0
  123. package/build/src/codegen/pipeline.test.d.ts +1 -0
  124. package/build/src/codegen/pipeline.test.js +269 -0
  125. package/build/src/codegen/pipeline.test.js.map +1 -0
  126. package/build/src/codegen/resolve-envelope.d.ts +7 -0
  127. package/build/src/codegen/resolve-envelope.js +46 -0
  128. package/build/src/codegen/resolve-envelope.js.map +1 -0
  129. package/build/src/codegen/resolve-envelope.test.d.ts +1 -0
  130. package/build/src/codegen/resolve-envelope.test.js +69 -0
  131. package/build/src/codegen/resolve-envelope.test.js.map +1 -0
  132. package/build/src/errors.d.ts +33 -0
  133. package/build/src/errors.js +91 -0
  134. package/build/src/errors.js.map +1 -0
  135. package/build/src/errors.test.d.ts +1 -0
  136. package/build/src/errors.test.js +122 -0
  137. package/build/src/errors.test.js.map +1 -0
  138. package/build/src/exports.d.ts +7 -0
  139. package/build/src/exports.js +8 -0
  140. package/build/src/exports.js.map +1 -0
  141. package/build/src/implementations/http/doc-registry.d.ts +12 -0
  142. package/build/src/implementations/http/doc-registry.js +114 -0
  143. package/build/src/implementations/http/doc-registry.js.map +1 -0
  144. package/build/src/implementations/http/doc-registry.test.d.ts +1 -0
  145. package/build/src/implementations/http/doc-registry.test.js +347 -0
  146. package/build/src/implementations/http/doc-registry.test.js.map +1 -0
  147. package/build/src/implementations/http/express-rpc/index.d.ts +94 -0
  148. package/build/src/implementations/http/express-rpc/index.js +185 -0
  149. package/build/src/implementations/http/express-rpc/index.js.map +1 -0
  150. package/build/src/implementations/http/express-rpc/index.test.d.ts +1 -0
  151. package/build/src/implementations/http/express-rpc/index.test.js +684 -0
  152. package/build/src/implementations/http/express-rpc/index.test.js.map +1 -0
  153. package/build/src/implementations/http/express-rpc/types.d.ts +11 -0
  154. package/build/src/implementations/http/express-rpc/types.js +2 -0
  155. package/build/src/implementations/http/express-rpc/types.js.map +1 -0
  156. package/build/src/implementations/http/hono-api/index.d.ts +102 -0
  157. package/build/src/implementations/http/hono-api/index.js +341 -0
  158. package/build/src/implementations/http/hono-api/index.js.map +1 -0
  159. package/build/src/implementations/http/hono-api/index.test.d.ts +1 -0
  160. package/build/src/implementations/http/hono-api/index.test.js +992 -0
  161. package/build/src/implementations/http/hono-api/index.test.js.map +1 -0
  162. package/build/src/implementations/http/hono-api/types.d.ts +13 -0
  163. package/build/src/implementations/http/hono-api/types.js +2 -0
  164. package/build/src/implementations/http/hono-api/types.js.map +1 -0
  165. package/build/src/implementations/http/hono-rpc/index.d.ts +92 -0
  166. package/build/src/implementations/http/hono-rpc/index.js +161 -0
  167. package/build/src/implementations/http/hono-rpc/index.js.map +1 -0
  168. package/build/src/implementations/http/hono-rpc/index.test.d.ts +1 -0
  169. package/build/src/implementations/http/hono-rpc/index.test.js +803 -0
  170. package/build/src/implementations/http/hono-rpc/index.test.js.map +1 -0
  171. package/build/src/implementations/http/hono-rpc/types.d.ts +11 -0
  172. package/build/src/implementations/http/hono-rpc/types.js +2 -0
  173. package/build/src/implementations/http/hono-rpc/types.js.map +1 -0
  174. package/build/src/implementations/http/hono-stream/index.d.ts +120 -0
  175. package/build/src/implementations/http/hono-stream/index.js +309 -0
  176. package/build/src/implementations/http/hono-stream/index.js.map +1 -0
  177. package/build/src/implementations/http/hono-stream/index.test.d.ts +1 -0
  178. package/build/src/implementations/http/hono-stream/index.test.js +1356 -0
  179. package/build/src/implementations/http/hono-stream/index.test.js.map +1 -0
  180. package/build/src/implementations/http/hono-stream/types.d.ts +15 -0
  181. package/build/src/implementations/http/hono-stream/types.js +2 -0
  182. package/build/src/implementations/http/hono-stream/types.js.map +1 -0
  183. package/build/src/implementations/types.d.ts +142 -0
  184. package/build/src/implementations/types.js +2 -0
  185. package/build/src/implementations/types.js.map +1 -0
  186. package/build/src/index.d.ts +165 -0
  187. package/build/src/index.js +253 -0
  188. package/build/src/index.js.map +1 -0
  189. package/build/src/index.test.d.ts +1 -0
  190. package/build/src/index.test.js +890 -0
  191. package/build/src/index.test.js.map +1 -0
  192. package/build/src/schema/compute-schema.d.ts +35 -0
  193. package/build/src/schema/compute-schema.js +41 -0
  194. package/build/src/schema/compute-schema.js.map +1 -0
  195. package/build/src/schema/compute-schema.test.d.ts +1 -0
  196. package/build/src/schema/compute-schema.test.js +107 -0
  197. package/build/src/schema/compute-schema.test.js.map +1 -0
  198. package/build/src/schema/extract-json-schema.d.ts +2 -0
  199. package/build/src/schema/extract-json-schema.js +12 -0
  200. package/build/src/schema/extract-json-schema.js.map +1 -0
  201. package/build/src/schema/extract-json-schema.test.d.ts +1 -0
  202. package/build/src/schema/extract-json-schema.test.js +23 -0
  203. package/build/src/schema/extract-json-schema.test.js.map +1 -0
  204. package/build/src/schema/parser.d.ts +28 -0
  205. package/build/src/schema/parser.js +170 -0
  206. package/build/src/schema/parser.js.map +1 -0
  207. package/build/src/schema/parser.test.d.ts +1 -0
  208. package/build/src/schema/parser.test.js +120 -0
  209. package/build/src/schema/parser.test.js.map +1 -0
  210. package/build/src/schema/resolve-schema-lib.d.ts +12 -0
  211. package/build/src/schema/resolve-schema-lib.js +11 -0
  212. package/build/src/schema/resolve-schema-lib.js.map +1 -0
  213. package/build/src/schema/resolve-schema-lib.test.d.ts +1 -0
  214. package/build/src/schema/resolve-schema-lib.test.js +17 -0
  215. package/build/src/schema/resolve-schema-lib.test.js.map +1 -0
  216. package/build/src/schema/types.d.ts +8 -0
  217. package/build/src/schema/types.js +2 -0
  218. package/build/src/schema/types.js.map +1 -0
  219. package/build/src/stack-utils.d.ts +25 -0
  220. package/build/src/stack-utils.js +95 -0
  221. package/build/src/stack-utils.js.map +1 -0
  222. package/build/src/stack-utils.test.d.ts +1 -0
  223. package/build/src/stack-utils.test.js +80 -0
  224. package/build/src/stack-utils.test.js.map +1 -0
  225. package/docs/ai-agent-setup.md +7 -6
  226. package/docs/core.md +5 -9
  227. package/docs/streaming.md +9 -9
  228. package/package.json +2 -13
  229. package/src/client/call.test.ts +162 -0
  230. package/src/client/errors.test.ts +43 -0
  231. package/src/client/fetch-adapter.test.ts +340 -0
  232. package/src/client/hooks.test.ts +191 -0
  233. package/src/client/index.test.ts +290 -0
  234. package/src/client/request-builder.test.ts +184 -0
  235. package/src/client/stream.test.ts +331 -0
  236. package/src/codegen/bin/cli.test.ts +260 -0
  237. package/src/codegen/bin/cli.ts +282 -0
  238. package/src/codegen/constants.ts +1 -0
  239. package/src/codegen/e2e.test.ts +565 -0
  240. package/src/codegen/emit-client-runtime.test.ts +93 -0
  241. package/src/codegen/emit-client-runtime.ts +114 -0
  242. package/src/codegen/emit-client-types.test.ts +39 -0
  243. package/src/codegen/emit-client-types.ts +27 -0
  244. package/src/codegen/emit-errors.test.ts +202 -0
  245. package/src/codegen/emit-errors.ts +80 -0
  246. package/src/codegen/emit-index.test.ts +127 -0
  247. package/src/codegen/emit-index.ts +58 -0
  248. package/src/codegen/emit-scope.test.ts +624 -0
  249. package/src/codegen/emit-scope.ts +389 -0
  250. package/src/codegen/emit-types.test.ts +205 -0
  251. package/src/codegen/emit-types.ts +158 -0
  252. package/src/codegen/group-routes.test.ts +159 -0
  253. package/src/codegen/group-routes.ts +61 -0
  254. package/src/codegen/index.ts +30 -0
  255. package/src/codegen/naming.test.ts +50 -0
  256. package/src/codegen/naming.ts +25 -0
  257. package/src/codegen/pipeline.test.ts +316 -0
  258. package/src/codegen/pipeline.ts +108 -0
  259. package/src/codegen/resolve-envelope.test.ts +76 -0
  260. package/src/codegen/resolve-envelope.ts +61 -0
  261. package/src/errors.test.ts +163 -0
  262. package/src/errors.ts +107 -0
  263. package/src/exports.ts +7 -0
  264. package/src/implementations/http/doc-registry.test.ts +415 -0
  265. package/src/implementations/http/doc-registry.ts +143 -0
  266. package/src/implementations/http/express-rpc/README.md +6 -6
  267. package/src/implementations/http/express-rpc/index.test.ts +957 -0
  268. package/src/implementations/http/express-rpc/index.ts +266 -0
  269. package/src/implementations/http/express-rpc/types.ts +16 -0
  270. package/src/implementations/http/hono-api/index.test.ts +1341 -0
  271. package/src/implementations/http/hono-api/index.ts +463 -0
  272. package/src/implementations/http/hono-api/types.ts +16 -0
  273. package/src/implementations/http/hono-rpc/README.md +6 -6
  274. package/src/implementations/http/hono-rpc/index.test.ts +1075 -0
  275. package/src/implementations/http/hono-rpc/index.ts +238 -0
  276. package/src/implementations/http/hono-rpc/types.ts +16 -0
  277. package/src/implementations/http/hono-stream/README.md +12 -12
  278. package/src/implementations/http/hono-stream/index.test.ts +1768 -0
  279. package/src/implementations/http/hono-stream/index.ts +456 -0
  280. package/src/implementations/http/hono-stream/types.ts +20 -0
  281. package/src/implementations/types.ts +174 -0
  282. package/src/index.test.ts +1185 -0
  283. package/src/index.ts +522 -0
  284. package/src/schema/compute-schema.test.ts +128 -0
  285. package/src/schema/compute-schema.ts +88 -0
  286. package/src/schema/extract-json-schema.test.ts +25 -0
  287. package/src/schema/extract-json-schema.ts +15 -0
  288. package/src/schema/parser.test.ts +182 -0
  289. package/src/schema/parser.ts +215 -0
  290. package/src/schema/resolve-schema-lib.test.ts +19 -0
  291. package/src/schema/resolve-schema-lib.ts +29 -0
  292. package/src/schema/types.ts +20 -0
  293. package/src/stack-utils.test.ts +94 -0
  294. package/src/stack-utils.ts +129 -0
  295. package/agent_config/claude-code/skills/review/SKILL.md +0 -53
  296. package/docs/superpowers/plans/2026-03-30-client-codegen.md +0 -2833
  297. package/docs/superpowers/specs/2026-03-30-client-codegen-design.md +0 -632
  298. /package/agent_config/claude-code/skills/{guide → ts-procedures}/patterns.md +0 -0
  299. /package/agent_config/claude-code/skills/{review → ts-procedures-review}/checklist.md +0 -0
  300. /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/express-rpc.md +0 -0
  301. /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/hono-api.md +0 -0
  302. /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/hono-rpc.md +0 -0
  303. /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/hono-stream.md +0 -0
  304. /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/procedure.md +0 -0
  305. /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/stream-procedure.md +0 -0
@@ -1,38 +1,28 @@
1
1
  ---
2
- name: scaffold
3
- description: "Scaffold ts-procedures code with correct patterns. Usage: /ts-procedures:scaffold <type> <Name>"
4
- invocable_by:
5
- - user
6
- - model
7
- user_instructions: |
8
- Usage: /ts-procedures:scaffold <type> <Name>
9
-
10
- Types: procedure, stream-procedure, express-rpc, hono-rpc, hono-stream, hono-api
11
-
12
- Examples:
13
- /ts-procedures:scaffold procedure GetUser
14
- /ts-procedures:scaffold stream-procedure StreamActivity
15
- /ts-procedures:scaffold express-rpc UserApi
16
- /ts-procedures:scaffold hono-rpc OrderApi
17
- /ts-procedures:scaffold hono-stream LiveFeed
18
- /ts-procedures:scaffold hono-api ProductApi
2
+ name: ts-procedures-scaffold
3
+ description: "Generate ts-procedures implementations with correct patterns procedures, streams, Express RPC, Hono RPC, Hono streaming, REST APIs, and client setup."
4
+ argument-hint: "<type> <Name>"
5
+ allowed-tools: Read Write
19
6
  ---
20
7
 
21
8
  # Scaffold ts-procedures Code
22
9
 
23
- Parse `$ARGUMENTS` as `<type> <Name>` (case-insensitive type, PascalCase Name).
10
+ Scaffold a `$0` ts-procedures implementation named `$1`.
11
+
12
+ If either argument is missing, ask the user for `<type>` and `<Name>`.
24
13
 
25
14
  ## Instructions
26
15
 
27
- 1. Parse the arguments. If missing, ask the user for `<type>` and `<Name>`.
28
- 2. Derive placeholder variants from the provided PascalCase Name:
16
+ 1. Validate `$0` is a recognized type (see table below). Case-insensitive.
17
+ 2. Validate `$1` is PascalCase (e.g., `UserProfile`).
18
+ 3. Derive placeholder variants from the provided PascalCase Name:
29
19
  - `{{Name}}` — PascalCase as given (e.g., `UserProfile`)
30
20
  - `{{name}}` — camelCase (e.g., `userProfile`)
31
21
  - For URL scopes and file paths, use kebab-case (e.g., `user-profile`)
32
- 3. Read the template file from `templates/<type>.md` in this skill directory.
33
- 4. Replace all `{{Name}}` and `{{name}}` placeholders with the appropriate variants.
34
- 5. Generate the implementation file(s) following the template exactly.
35
- 6. Also generate a colocated test file following ts-procedures test conventions.
22
+ 4. Read the template file from `templates/$0.md` (relative to this skill directory).
23
+ 5. Replace all `{{Name}}` and `{{name}}` placeholders with the appropriate variants.
24
+ 6. Generate the implementation file(s) following the template exactly.
25
+ 7. Also generate a colocated test file following ts-procedures test conventions.
36
26
 
37
27
  ## Valid Types
38
28
 
@@ -44,6 +34,7 @@ Parse `$ARGUMENTS` as `<type> <Name>` (case-insensitive type, PascalCase Name).
44
34
  | `hono-rpc` | `templates/hono-rpc.md` | `{{Name}}.rpc.ts`, `{{Name}}.rpc.test.ts` |
45
35
  | `hono-stream` | `templates/hono-stream.md` | `{{Name}}.stream-rpc.ts`, `{{Name}}.stream-rpc.test.ts` |
46
36
  | `hono-api` | `templates/hono-api.md` | `{{Name}}.api.ts`, `{{Name}}.api.test.ts` |
37
+ | `client` | `templates/client.md` | `{{Name}}.client.ts`, `{{Name}}.client.test.ts` |
47
38
 
48
39
  ## Rules
49
40
 
@@ -54,3 +45,7 @@ Parse `$ARGUMENTS` as `<type> <Name>` (case-insensitive type, PascalCase Name).
54
45
  - Use TypeBox for schema definitions (`import { Type } from 'typebox'`).
55
46
  - AJV config: `allErrors: true`, `coerceTypes: true`, `removeAdditional: true`.
56
47
  - Test files use `describe`/`test` from vitest.
48
+
49
+ ## Workflow
50
+
51
+ Use the **ts-procedures-architect** agent to plan your API structure first, then scaffold each procedure. After scaffolding, use `/ts-procedures:review <path>` to validate the implementation.
@@ -0,0 +1,115 @@
1
+ # Client Template: {{Name}}
2
+
3
+ ## Implementation — `{{Name}}.client.ts`
4
+
5
+ ```typescript
6
+ import { createClient, createFetchAdapter } from 'ts-procedures/client'
7
+ import { createScopeBindings } from './generated/api'
8
+ // With --service-name: import { create{{Name}}Bindings } from './generated/api'
9
+
10
+ // Create the typed client
11
+ export const {{name}}Client = createClient({
12
+ adapter: createFetchAdapter(),
13
+ basePath: 'http://localhost:3000', // TODO: configure base URL
14
+ scopes: createScopeBindings,
15
+ // With --service-name: scopes: create{{Name}}Bindings,
16
+ hooks: {
17
+ onBeforeRequest(ctx) {
18
+ // TODO: add auth headers, request IDs, etc.
19
+ ctx.request.headers = {
20
+ ...ctx.request.headers,
21
+ // Authorization: `Bearer ${getToken()}`,
22
+ }
23
+ return ctx
24
+ },
25
+ onAfterResponse(ctx) {
26
+ // TODO: handle global response concerns (401 redirect, rate limiting, etc.)
27
+ // if (ctx.response.status === 401) { redirect('/login') }
28
+ },
29
+ },
30
+ })
31
+
32
+ // --- RPC call example ---
33
+ // const user = await {{name}}Client.users.GetUser({ userId: '123' })
34
+
35
+ // --- API call example (with schema.input channels) ---
36
+ // const user = await {{name}}Client.users.GetUser({ pathParams: { id: '123' } })
37
+
38
+ // --- Streaming call example ---
39
+ // const stream = {{name}}Client.events.WatchNotifications({ filter: 'all' })
40
+ // for await (const event of stream) {
41
+ // console.log(event) // Typed from server yieldType schema
42
+ // }
43
+ // const result = await stream.result // Typed from server returnType schema
44
+
45
+ // --- Per-procedure hook override ---
46
+ // const user = await {{name}}Client.users.GetUser({ id: '123' }, {
47
+ // onAfterResponse(ctx) {
48
+ // console.log('Rate limit:', ctx.response.headers['x-rate-limit-remaining'])
49
+ // },
50
+ // })
51
+ ```
52
+
53
+ ## Test — `{{Name}}.client.test.ts`
54
+
55
+ ```typescript
56
+ import { describe, test, expect, beforeAll, afterAll } from 'vitest'
57
+ import { {{name}}Client } from './{{Name}}.client'
58
+
59
+ // TODO: start your server before tests, or mock the adapter
60
+ // import { createServer } from './server'
61
+ // let server: ReturnType<typeof createServer>
62
+
63
+ describe('{{Name}} Client', () => {
64
+ // beforeAll(async () => {
65
+ // server = createServer()
66
+ // await server.listen(3000)
67
+ // })
68
+ //
69
+ // afterAll(async () => {
70
+ // await server.close()
71
+ // })
72
+
73
+ test('makes RPC calls with typed params and response', async () => {
74
+ // TODO: replace with an actual procedure call
75
+ // const result = await {{name}}Client.users.GetUser({ userId: 'test-id' })
76
+ // expect(result).toBeDefined()
77
+ // expect(result.id).toBe('test-id')
78
+ })
79
+
80
+ test('handles validation errors from the server', async () => {
81
+ // TODO: call with invalid params and verify error handling
82
+ // await expect(
83
+ // {{name}}Client.users.GetUser({} as any)
84
+ // ).rejects.toThrow()
85
+ })
86
+
87
+ test('streams data with typed yields', async () => {
88
+ // TODO: replace with an actual stream procedure call
89
+ // const stream = {{name}}Client.events.WatchNotifications({ filter: 'all' })
90
+ // const values = []
91
+ // for await (const event of stream) {
92
+ // values.push(event)
93
+ // if (values.length >= 3) break
94
+ // }
95
+ // expect(values).toHaveLength(3)
96
+ // const result = await stream.result
97
+ // expect(result).toBeDefined()
98
+ })
99
+ })
100
+ ```
101
+
102
+ ## Code Generation Setup
103
+
104
+ Generate the typed client bindings from your running server:
105
+
106
+ ```bash
107
+ # Default (self-contained, namespaced types, JSDoc)
108
+ npx ts-procedures-codegen --url http://localhost:3000/docs --out ./src/generated/api
109
+
110
+ # With service name for multi-service apps
111
+ npx ts-procedures-codegen --url http://localhost:3000/docs --out ./src/generated/api --service-name {{Name}}
112
+
113
+ # Watch mode for development
114
+ npx ts-procedures-codegen --url http://localhost:3000/docs --out ./src/generated/api --watch
115
+ ```
@@ -1,109 +1,57 @@
1
- import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
1
+ import { cpSync, mkdirSync, readdirSync, statSync } from 'node:fs';
2
2
  import { join, dirname } from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
4
 
5
5
  const __filename = fileURLToPath(import.meta.url);
6
6
  const __dirname = dirname(__filename);
7
- const SKILLS_DIR = join(__dirname, '..', 'claude-code', 'skills');
8
- const AGENTS_DIR = join(__dirname, '..', 'claude-code', 'agents');
9
-
10
- function getPackageVersion() {
11
- try {
12
- const pkg = JSON.parse(readFileSync(join(__dirname, '..', '..', 'package.json'), 'utf-8'));
13
- return pkg.version || 'unknown';
14
- } catch {
15
- return 'unknown';
16
- }
17
- }
18
-
19
- function makeAutoHeader() {
20
- const version = getPackageVersion();
21
- return `<!-- Auto-generated by ts-procedures@${version}. Updated on npm install/update. Do not edit. -->\n\n`;
22
- }
23
-
24
- function stripFrontmatter(content) {
25
- const match = content.match(/^---\n[\s\S]*?\n---\n([\s\S]*)$/);
26
- return match ? match[1].trim() : content.trim();
27
- }
28
-
29
- function ensureDir(dir) {
30
- if (!existsSync(dir)) {
31
- mkdirSync(dir, { recursive: true });
7
+ const SOURCE_DIR = join(__dirname, '..', 'claude-code');
8
+
9
+ const SKILL_NAMES = ['ts-procedures', 'ts-procedures-review', 'ts-procedures-scaffold'];
10
+ const AGENT_FILES = ['ts-procedures-architect.md'];
11
+
12
+ function listFilesRecursive(dir) {
13
+ const out = [];
14
+ for (const entry of readdirSync(dir)) {
15
+ const full = join(dir, entry);
16
+ if (statSync(full).isDirectory()) {
17
+ for (const nested of listFilesRecursive(full)) out.push(join(entry, nested));
18
+ } else {
19
+ out.push(entry);
20
+ }
32
21
  }
22
+ return out;
33
23
  }
34
24
 
35
25
  /**
36
26
  * Install Claude Code integration files into a project's .claude/ directory.
37
27
  *
38
28
  * Creates:
39
- * .claude/rules/ts-procedures.md — Framework reference (always loaded in context)
40
- * .claude/commands/ts-procedures-scaffold.md — Scaffold command (/project:ts-procedures-scaffold)
41
- * .claude/commands/ts-procedures-review.md — Review command (/project:ts-procedures-review)
42
- * .claude/agents/ts-procedures-architect.md — Architecture planning agent
29
+ * .claude/skills/ts-procedures/ — Framework reference skill
30
+ * .claude/skills/ts-procedures-scaffold/ — Scaffold skill (templates included)
31
+ * .claude/skills/ts-procedures-review/ — Review skill
32
+ * .claude/agents/ts-procedures-architect.md — Architecture planning agent
43
33
  *
44
34
  * @param {string} projectRoot — Absolute path to the consuming project's root
45
35
  * @returns {{ files: string[] }} — List of created/updated file paths (relative to projectRoot)
46
36
  */
47
37
  export function installClaude(projectRoot) {
48
38
  const claudeDir = join(projectRoot, '.claude');
49
- const rulesDir = join(claudeDir, 'rules');
50
- const commandsDir = join(claudeDir, 'commands');
51
- const agentsDir = join(claudeDir, 'agents');
52
-
53
- ensureDir(rulesDir);
54
- ensureDir(commandsDir);
55
- ensureDir(agentsDir);
39
+ const skillsDest = join(claudeDir, 'skills');
40
+ const agentsDest = join(claudeDir, 'agents');
41
+ mkdirSync(skillsDest, { recursive: true });
42
+ mkdirSync(agentsDest, { recursive: true });
56
43
 
57
- const autoHeader = makeAutoHeader();
58
44
  const files = [];
59
-
60
- // 1. Rules file — framework reference (always loaded in context)
61
- const guideSkill = readFileSync(join(SKILLS_DIR, 'guide', 'SKILL.md'), 'utf-8');
62
- const guideBody = stripFrontmatter(guideSkill)
63
- // Remove the "Supporting Files" section — replaced by "Detailed Reference" below
64
- .replace(/\n## Supporting Files[\s\S]*$/, '');
65
-
66
- const rulesContent = autoHeader + guideBody + `
67
-
68
- ## Detailed Reference
69
-
70
- For complete API details, patterns, and anti-patterns, read the files in:
71
- \`node_modules/ts-procedures/agent_config/claude-code/skills/guide/\`
72
-
73
- - \`api-reference.md\` — Full API reference for Procedures, Create, CreateStream, errors, schema, HTTP implementations
74
- - \`patterns.md\` — Prescribed patterns with code examples
75
- - \`anti-patterns.md\` — Common mistakes to avoid with fixes
76
- `;
77
-
78
- writeFileSync(join(rulesDir, 'ts-procedures.md'), rulesContent, 'utf-8');
79
- files.push('.claude/rules/ts-procedures.md');
80
-
81
- // 2. Scaffold command
82
- const scaffoldSkill = readFileSync(join(SKILLS_DIR, 'scaffold', 'SKILL.md'), 'utf-8');
83
- const scaffoldBody = stripFrontmatter(scaffoldSkill)
84
- .replace(
85
- 'Read the template file from `templates/<type>.md` in this skill directory.',
86
- 'Read the template file from `node_modules/ts-procedures/agent_config/claude-code/skills/scaffold/templates/<type>.md`.'
87
- );
88
-
89
- writeFileSync(join(commandsDir, 'ts-procedures-scaffold.md'), autoHeader + scaffoldBody, 'utf-8');
90
- files.push('.claude/commands/ts-procedures-scaffold.md');
91
-
92
- // 3. Review command
93
- const reviewSkill = readFileSync(join(SKILLS_DIR, 'review', 'SKILL.md'), 'utf-8');
94
- const reviewBody = stripFrontmatter(reviewSkill)
95
- .replaceAll(
96
- '`checklist.md`',
97
- '`node_modules/ts-procedures/agent_config/claude-code/skills/review/checklist.md`'
98
- );
99
-
100
- writeFileSync(join(commandsDir, 'ts-procedures-review.md'), autoHeader + reviewBody, 'utf-8');
101
- files.push('.claude/commands/ts-procedures-review.md');
102
-
103
- // 4. Architect agent
104
- const architectAgent = readFileSync(join(AGENTS_DIR, 'ts-procedures-architect.md'), 'utf-8');
105
- writeFileSync(join(agentsDir, 'ts-procedures-architect.md'), autoHeader + architectAgent, 'utf-8');
106
- files.push('.claude/agents/ts-procedures-architect.md');
107
-
45
+ for (const skill of SKILL_NAMES) {
46
+ const src = join(SOURCE_DIR, 'skills', skill);
47
+ cpSync(src, join(skillsDest, skill), { recursive: true, force: true });
48
+ for (const rel of listFilesRecursive(src)) {
49
+ files.push(`.claude/skills/${skill}/${rel}`);
50
+ }
51
+ }
52
+ for (const agent of AGENT_FILES) {
53
+ cpSync(join(SOURCE_DIR, 'agents', agent), join(agentsDest, agent), { force: true });
54
+ files.push(`.claude/agents/${agent}`);
55
+ }
108
56
  return { files };
109
57
  }
@@ -0,0 +1,14 @@
1
+ import type { ClientAdapter, ClientHooks, CallDescriptor } from './types.js';
2
+ /**
3
+ * Executes a single procedure call through the adapter.
4
+ *
5
+ * Flow:
6
+ * 1. Build AdapterRequest from descriptor
7
+ * 2. Run onBeforeRequest hooks (global then local)
8
+ * 3. Call adapter.request()
9
+ * 4. On adapter error: run onError hooks, re-throw
10
+ * 5. Run onAfterResponse hooks (hooks may mutate response.status)
11
+ * 6. If response status is non-2xx: throw ClientRequestError
12
+ * 7. Return response.body as TResponse
13
+ */
14
+ export declare function executeCall<TResponse>(descriptor: CallDescriptor, basePath: string, adapter: ClientAdapter, globalHooks: ClientHooks, localHooks: ClientHooks | undefined): Promise<TResponse>;
@@ -0,0 +1,47 @@
1
+ import { buildAdapterRequest } from './request-builder.js';
2
+ import { runBeforeRequest, runAfterResponse, runOnError } from './hooks.js';
3
+ import { ClientRequestError } from './errors.js';
4
+ /**
5
+ * Executes a single procedure call through the adapter.
6
+ *
7
+ * Flow:
8
+ * 1. Build AdapterRequest from descriptor
9
+ * 2. Run onBeforeRequest hooks (global then local)
10
+ * 3. Call adapter.request()
11
+ * 4. On adapter error: run onError hooks, re-throw
12
+ * 5. Run onAfterResponse hooks (hooks may mutate response.status)
13
+ * 6. If response status is non-2xx: throw ClientRequestError
14
+ * 7. Return response.body as TResponse
15
+ */
16
+ export async function executeCall(descriptor, basePath, adapter, globalHooks, localHooks) {
17
+ // 1. Build the initial request
18
+ let request = buildAdapterRequest(descriptor, basePath);
19
+ // 2. Run before-request hooks — they may mutate the request
20
+ const beforeCtx = await runBeforeRequest({ procedureName: descriptor.name, scope: descriptor.scope, request }, globalHooks, localHooks);
21
+ request = beforeCtx.request;
22
+ // 3. Call the adapter
23
+ let response;
24
+ try {
25
+ response = await adapter.request(request);
26
+ }
27
+ catch (err) {
28
+ // 4. On adapter error: run error hooks, re-throw
29
+ await runOnError({ procedureName: descriptor.name, scope: descriptor.scope, request, error: err }, globalHooks, localHooks);
30
+ throw err;
31
+ }
32
+ // 5. Run after-response hooks — they may mutate response.status to swallow errors
33
+ await runAfterResponse({ procedureName: descriptor.name, scope: descriptor.scope, request, response }, globalHooks, localHooks);
34
+ // 6. Check status AFTER hooks (hooks may have swallowed the error by mutating status)
35
+ if (response.status < 200 || response.status >= 300) {
36
+ throw new ClientRequestError({
37
+ status: response.status,
38
+ headers: response.headers,
39
+ body: response.body,
40
+ procedureName: descriptor.name,
41
+ scope: descriptor.scope,
42
+ });
43
+ }
44
+ // 7. Return the body
45
+ return response.body;
46
+ }
47
+ //# sourceMappingURL=call.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"call.js","sourceRoot":"","sources":["../../../src/client/call.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAOhD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,UAA0B,EAC1B,QAAgB,EAChB,OAAsB,EACtB,WAAwB,EACxB,UAAmC;IAEnC,+BAA+B;IAC/B,IAAI,OAAO,GAAG,mBAAmB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;IAEvD,4DAA4D;IAC5D,MAAM,SAAS,GAAG,MAAM,gBAAgB,CACtC,EAAE,aAAa,EAAE,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,EACpE,WAAW,EACX,UAAU,CACX,CAAA;IACD,OAAO,GAAG,SAAS,CAAC,OAAO,CAAA;IAE3B,sBAAsB;IACtB,IAAI,QAAQ,CAAA;IACZ,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAC3C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,iDAAiD;QACjD,MAAM,UAAU,CACd,EAAE,aAAa,EAAE,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAChF,WAAW,EACX,UAAU,CACX,CAAA;QACD,MAAM,GAAG,CAAA;IACX,CAAC;IAED,kFAAkF;IAClF,MAAM,gBAAgB,CACpB,EAAE,aAAa,EAAE,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,EAC9E,WAAW,EACX,UAAU,CACX,CAAA;IAED,sFAAsF;IACtF,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,IAAI,QAAQ,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;QACpD,MAAM,IAAI,kBAAkB,CAAC;YAC3B,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,OAAO,EAAE,QAAQ,CAAC,OAAO;YACzB,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,aAAa,EAAE,UAAU,CAAC,IAAI;YAC9B,KAAK,EAAE,UAAU,CAAC,KAAK;SACxB,CAAC,CAAA;IACJ,CAAC;IAED,qBAAqB;IACrB,OAAO,QAAQ,CAAC,IAAiB,CAAA;AACnC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,124 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { executeCall } from './call.js';
3
+ import { ClientRequestError } from './errors.js';
4
+ // ── helpers ───────────────────────────────────────────────
5
+ function makeDescriptor(overrides) {
6
+ return {
7
+ name: 'GetUser',
8
+ scope: 'users',
9
+ path: '/users',
10
+ method: 'GET',
11
+ kind: 'rpc',
12
+ params: { id: '42' },
13
+ ...overrides,
14
+ };
15
+ }
16
+ function makeAdapter(response) {
17
+ return {
18
+ request: vi.fn(async (_req) => ({
19
+ status: 200,
20
+ headers: {},
21
+ body: { id: '42', name: 'Alice' },
22
+ ...response,
23
+ })),
24
+ stream: vi.fn(async () => {
25
+ throw new Error('stream not expected in call tests');
26
+ }),
27
+ };
28
+ }
29
+ // ── executeCall ───────────────────────────────────────────
30
+ describe('executeCall', () => {
31
+ it('calls adapter.request and returns body', async () => {
32
+ const adapter = makeAdapter({ body: { id: '1', name: 'Bob' } });
33
+ const result = await executeCall(makeDescriptor(), 'https://api.example.com', adapter, {}, undefined);
34
+ expect(adapter.request).toHaveBeenCalledOnce();
35
+ expect(result).toEqual({ id: '1', name: 'Bob' });
36
+ });
37
+ it('throws ClientRequestError on 4xx response', async () => {
38
+ const adapter = makeAdapter({ status: 404, body: { message: 'Not Found' } });
39
+ await expect(executeCall(makeDescriptor(), 'https://api.example.com', adapter, {}, undefined)).rejects.toThrow(ClientRequestError);
40
+ });
41
+ it('throws ClientRequestError on 5xx response', async () => {
42
+ const adapter = makeAdapter({ status: 500, body: { message: 'Server Error' } });
43
+ await expect(executeCall(makeDescriptor(), 'https://api.example.com', adapter, {}, undefined)).rejects.toThrow(ClientRequestError);
44
+ });
45
+ it('throws ClientRequestError on 199 response (below 200)', async () => {
46
+ const adapter = makeAdapter({ status: 199, body: null });
47
+ await expect(executeCall(makeDescriptor(), 'https://api.example.com', adapter, {}, undefined)).rejects.toThrow(ClientRequestError);
48
+ });
49
+ it('does not throw on 2xx boundary responses (200, 201, 299)', async () => {
50
+ for (const status of [200, 201, 204, 299]) {
51
+ const adapter = makeAdapter({ status, body: null });
52
+ await expect(executeCall(makeDescriptor(), 'https://api.example.com', adapter, {}, undefined)).resolves.not.toThrow();
53
+ }
54
+ });
55
+ it('runs onBeforeRequest before calling adapter (headers are modified)', async () => {
56
+ const capturedHeaders = [];
57
+ const adapter = {
58
+ request: vi.fn(async (req) => {
59
+ capturedHeaders.push(req.headers ?? {});
60
+ return { status: 200, headers: {}, body: {} };
61
+ }),
62
+ stream: vi.fn(async () => { throw new Error('not expected'); }),
63
+ };
64
+ const globalHooks = {
65
+ onBeforeRequest: (ctx) => ({
66
+ ...ctx,
67
+ request: {
68
+ ...ctx.request,
69
+ headers: { ...ctx.request.headers, 'x-auth': 'token-123' },
70
+ },
71
+ }),
72
+ };
73
+ await executeCall(makeDescriptor(), 'https://api.example.com', adapter, globalHooks, undefined);
74
+ expect(capturedHeaders[0]?.['x-auth']).toBe('token-123');
75
+ });
76
+ it('runs onAfterResponse after adapter returns', async () => {
77
+ const order = [];
78
+ const adapter = {
79
+ request: vi.fn(async () => {
80
+ order.push('adapter');
81
+ return { status: 200, headers: {}, body: {} };
82
+ }),
83
+ stream: vi.fn(async () => { throw new Error('not expected'); }),
84
+ };
85
+ const globalHooks = {
86
+ onAfterResponse: () => { order.push('afterResponse'); },
87
+ };
88
+ await executeCall(makeDescriptor(), 'https://api.example.com', adapter, globalHooks, undefined);
89
+ expect(order).toEqual(['adapter', 'afterResponse']);
90
+ });
91
+ it('does not throw when onAfterResponse swallows non-2xx by mutating status', async () => {
92
+ const adapter = makeAdapter({ status: 401, body: { message: 'Unauthorized' } });
93
+ const globalHooks = {
94
+ onAfterResponse: (ctx) => {
95
+ // Swallow the error by setting status to 200
96
+ ctx.response.status = 200;
97
+ },
98
+ };
99
+ await expect(executeCall(makeDescriptor(), 'https://api.example.com', adapter, globalHooks, undefined)).resolves.not.toThrow();
100
+ });
101
+ it('runs onError on adapter failure and re-throws', async () => {
102
+ const adapterError = new Error('Network failure');
103
+ const adapter = {
104
+ request: vi.fn(async () => { throw adapterError; }),
105
+ stream: vi.fn(async () => { throw new Error('not expected'); }),
106
+ };
107
+ const receivedErrors = [];
108
+ const globalHooks = {
109
+ onError: (ctx) => { receivedErrors.push(ctx.error); },
110
+ };
111
+ await expect(executeCall(makeDescriptor(), 'https://api.example.com', adapter, globalHooks, undefined)).rejects.toThrow('Network failure');
112
+ expect(receivedErrors[0]).toBe(adapterError);
113
+ });
114
+ it('passes per-procedure hooks as local hooks', async () => {
115
+ const adapter = makeAdapter();
116
+ const localOrder = [];
117
+ const localHooks = {
118
+ onBeforeRequest: (ctx) => { localOrder.push('local-before'); return ctx; },
119
+ };
120
+ await executeCall(makeDescriptor(), 'https://api.example.com', adapter, {}, localHooks);
121
+ expect(localOrder).toContain('local-before');
122
+ });
123
+ });
124
+ //# sourceMappingURL=call.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"call.test.js","sourceRoot":"","sources":["../../../src/client/call.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ export declare class ClientRequestError extends Error {
2
+ readonly name = "ClientRequestError";
3
+ readonly status: number;
4
+ readonly headers: Record<string, string>;
5
+ readonly body: unknown;
6
+ readonly procedureName: string;
7
+ readonly scope: string;
8
+ constructor(opts: {
9
+ status: number;
10
+ headers: Record<string, string>;
11
+ body: unknown;
12
+ procedureName: string;
13
+ scope: string;
14
+ });
15
+ }
16
+ export declare class ClientPathParamError extends Error {
17
+ readonly name = "ClientPathParamError";
18
+ constructor(param: string, path: string, procedureName: string);
19
+ }
20
+ export declare class ClientStreamError extends Error {
21
+ readonly name = "ClientStreamError";
22
+ readonly procedureName: string;
23
+ readonly scope: string;
24
+ constructor(message: string, procedureName: string, scope: string);
25
+ }
@@ -0,0 +1,33 @@
1
+ export class ClientRequestError extends Error {
2
+ name = 'ClientRequestError';
3
+ status;
4
+ headers;
5
+ body;
6
+ procedureName;
7
+ scope;
8
+ constructor(opts) {
9
+ super(`${opts.procedureName} (${opts.scope}) failed with status ${opts.status}`);
10
+ this.status = opts.status;
11
+ this.headers = opts.headers;
12
+ this.body = opts.body;
13
+ this.procedureName = opts.procedureName;
14
+ this.scope = opts.scope;
15
+ }
16
+ }
17
+ export class ClientPathParamError extends Error {
18
+ name = 'ClientPathParamError';
19
+ constructor(param, path, procedureName) {
20
+ super(`Missing path parameter "${param}" in "${path}" for procedure ${procedureName}`);
21
+ }
22
+ }
23
+ export class ClientStreamError extends Error {
24
+ name = 'ClientStreamError';
25
+ procedureName;
26
+ scope;
27
+ constructor(message, procedureName, scope) {
28
+ super(message);
29
+ this.procedureName = procedureName;
30
+ this.scope = scope;
31
+ }
32
+ }
33
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/client/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAClC,IAAI,GAAG,oBAAoB,CAAA;IAC3B,MAAM,CAAQ;IACd,OAAO,CAAwB;IAC/B,IAAI,CAAS;IACb,aAAa,CAAQ;IACrB,KAAK,CAAQ;IAEtB,YAAY,IAMX;QACC,KAAK,CAAC,GAAG,IAAI,CAAC,aAAa,KAAK,IAAI,CAAC,KAAK,wBAAwB,IAAI,CAAC,MAAM,EAAE,CAAC,CAAA;QAChF,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;QACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAA;QAC3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;QACrB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAA;QACvC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;IACzB,CAAC;CACF;AAED,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IACpC,IAAI,GAAG,sBAAsB,CAAA;IAEtC,YAAY,KAAa,EAAE,IAAY,EAAE,aAAqB;QAC5D,KAAK,CAAC,2BAA2B,KAAK,SAAS,IAAI,mBAAmB,aAAa,EAAE,CAAC,CAAA;IACxF,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACjC,IAAI,GAAG,mBAAmB,CAAA;IAC1B,aAAa,CAAQ;IACrB,KAAK,CAAQ;IAEtB,YAAY,OAAe,EAAE,aAAqB,EAAE,KAAa;QAC/D,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,aAAa,GAAG,aAAa,CAAA;QAClC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;IACpB,CAAC;CACF"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,41 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { ClientRequestError, ClientPathParamError, ClientStreamError } from './errors.js';
3
+ describe('ClientRequestError', () => {
4
+ it('includes status, headers, and body', () => {
5
+ const err = new ClientRequestError({
6
+ status: 401,
7
+ headers: { 'x-request-id': 'abc' },
8
+ body: { message: 'Unauthorized' },
9
+ procedureName: 'GetUser',
10
+ scope: 'users',
11
+ });
12
+ expect(err).toBeInstanceOf(Error);
13
+ expect(err.name).toBe('ClientRequestError');
14
+ expect(err.status).toBe(401);
15
+ expect(err.headers['x-request-id']).toBe('abc');
16
+ expect(err.body).toEqual({ message: 'Unauthorized' });
17
+ expect(err.procedureName).toBe('GetUser');
18
+ expect(err.scope).toBe('users');
19
+ expect(err.message).toBe('GetUser (users) failed with status 401');
20
+ });
21
+ });
22
+ describe('ClientPathParamError', () => {
23
+ it('reports missing param', () => {
24
+ const err = new ClientPathParamError('id', '/users/:id', 'GetUser');
25
+ expect(err).toBeInstanceOf(Error);
26
+ expect(err.name).toBe('ClientPathParamError');
27
+ expect(err.message).toContain('id');
28
+ expect(err.message).toContain('/users/:id');
29
+ });
30
+ });
31
+ describe('ClientStreamError', () => {
32
+ it('includes procedure context', () => {
33
+ const err = new ClientStreamError('stream interrupted', 'Watch', 'events');
34
+ expect(err).toBeInstanceOf(Error);
35
+ expect(err.name).toBe('ClientStreamError');
36
+ expect(err.procedureName).toBe('Watch');
37
+ expect(err.scope).toBe('events');
38
+ expect(err.message).toBe('stream interrupted');
39
+ });
40
+ });
41
+ //# sourceMappingURL=errors.test.js.map