@lovrozagar/honey 0.6.8 → 0.7.1

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 (674) hide show
  1. package/README.md +514 -192
  2. package/bin/honey.js +25 -0
  3. package/dist/accepts.d.ts +7 -1
  4. package/dist/accepts.d.ts.map +1 -1
  5. package/dist/accepts.js +126 -0
  6. package/dist/accepts.js.map +1 -0
  7. package/dist/body-kind.d.ts +26 -0
  8. package/dist/body-kind.d.ts.map +1 -0
  9. package/dist/body-kind.js +70 -0
  10. package/dist/body-kind.js.map +1 -0
  11. package/dist/body-limit.d.ts +5 -1
  12. package/dist/body-limit.d.ts.map +1 -1
  13. package/dist/body-limit.js +126 -0
  14. package/dist/body-limit.js.map +1 -0
  15. package/dist/build/index.d.ts +19 -3
  16. package/dist/build/index.d.ts.map +1 -1
  17. package/dist/build/index.js +173 -0
  18. package/dist/build/index.js.map +1 -0
  19. package/dist/cli-args.d.ts +33 -0
  20. package/dist/cli-args.d.ts.map +1 -0
  21. package/dist/cli-args.js +102 -0
  22. package/dist/cli-args.js.map +1 -0
  23. package/dist/cli-go/auth.go +26 -0
  24. package/dist/cli-go/config.go +192 -0
  25. package/dist/cli-go/errors.go +75 -0
  26. package/dist/cli-go/multipart.go +79 -0
  27. package/dist/cli-go/output.go +163 -0
  28. package/dist/cli-go/root.go +30 -0
  29. package/dist/cli-go/stream.go +88 -0
  30. package/dist/cli-go/version.go +5 -0
  31. package/dist/cli.d.ts +1 -1
  32. package/dist/cli.js +209 -0
  33. package/dist/cli.js.map +1 -0
  34. package/dist/client/defaults.js +48 -0
  35. package/dist/client/defaults.js.map +1 -0
  36. package/dist/client/error.d.ts +35 -0
  37. package/dist/client/error.d.ts.map +1 -1
  38. package/dist/client/error.js +71 -0
  39. package/dist/client/error.js.map +1 -0
  40. package/dist/client/http.d.ts +67 -8
  41. package/dist/client/http.d.ts.map +1 -1
  42. package/dist/client/http.js +571 -0
  43. package/dist/client/http.js.map +1 -0
  44. package/dist/client/index.d.ts +3 -2
  45. package/dist/client/index.d.ts.map +1 -1
  46. package/dist/client/index.js +95 -0
  47. package/dist/client/index.js.map +1 -0
  48. package/dist/client/path.d.ts +26 -0
  49. package/dist/client/path.d.ts.map +1 -0
  50. package/dist/client/path.js +163 -0
  51. package/dist/client/path.js.map +1 -0
  52. package/dist/client/redirect-policy.d.ts +12 -0
  53. package/dist/client/redirect-policy.d.ts.map +1 -0
  54. package/dist/client/redirect-policy.js +20 -0
  55. package/dist/client/redirect-policy.js.map +1 -0
  56. package/dist/client/sdk.d.ts +36 -0
  57. package/dist/client/sdk.d.ts.map +1 -1
  58. package/dist/client/sdk.js +292 -0
  59. package/dist/client/sdk.js.map +1 -0
  60. package/dist/client/sse.d.ts +13 -0
  61. package/dist/client/sse.d.ts.map +1 -1
  62. package/dist/client/sse.js +129 -0
  63. package/dist/client/sse.js.map +1 -0
  64. package/dist/client/types.js +2 -0
  65. package/dist/client/types.js.map +1 -0
  66. package/dist/client/ws.d.ts +9 -2
  67. package/dist/client/ws.d.ts.map +1 -1
  68. package/dist/client/ws.js +112 -0
  69. package/dist/client/ws.js.map +1 -0
  70. package/dist/client-go/errors.go +236 -0
  71. package/dist/client-go/export.go +44 -0
  72. package/dist/client-go/invalidation.go +371 -0
  73. package/dist/client-go/nullable.go +62 -0
  74. package/dist/client-go/realtime.go +354 -0
  75. package/dist/client-go/result.go +20 -0
  76. package/dist/client-go/runtime.go +975 -0
  77. package/dist/client-go/sse.go +159 -0
  78. package/dist/client-go/transport.go +495 -0
  79. package/dist/client-go/ws.go +128 -0
  80. package/dist/client-info.d.ts +36 -0
  81. package/dist/client-info.d.ts.map +1 -0
  82. package/dist/client-info.js +53 -0
  83. package/dist/client-info.js.map +1 -0
  84. package/dist/client-mcp/README.md +10 -0
  85. package/dist/client-mcp/server.ts +221 -0
  86. package/dist/client-mcp/types.ts +19 -0
  87. package/dist/client-python/_errors.py +115 -0
  88. package/dist/client-python/_invalidation.py +494 -0
  89. package/dist/client-python/_realtime.py +179 -0
  90. package/dist/client-python/_runtime.py +860 -0
  91. package/dist/client-python/_sse.py +155 -0
  92. package/dist/client-python/_transport.py +366 -0
  93. package/dist/client-python/_ws.py +159 -0
  94. package/dist/client-python/py.typed +0 -0
  95. package/dist/client-rust/errors.rs +220 -0
  96. package/dist/client-rust/invalidation.rs +412 -0
  97. package/dist/client-rust/invalidation_sync.rs +93 -0
  98. package/dist/client-rust/nullable.rs +17 -0
  99. package/dist/client-rust/realtime.rs +702 -0
  100. package/dist/client-rust/result.rs +22 -0
  101. package/dist/client-rust/runtime.rs +980 -0
  102. package/dist/client-rust/runtime_sync.rs +484 -0
  103. package/dist/client-rust/sse.rs +188 -0
  104. package/dist/client-rust/ws.rs +167 -0
  105. package/dist/codegen-go-cli.d.ts.map +1 -1
  106. package/dist/codegen-go-cli.js +964 -0
  107. package/dist/codegen-go-cli.js.map +1 -0
  108. package/dist/codegen-go.d.ts +15 -3
  109. package/dist/codegen-go.d.ts.map +1 -1
  110. package/dist/codegen-go.js +872 -0
  111. package/dist/codegen-go.js.map +1 -0
  112. package/dist/codegen-hash.js +9 -0
  113. package/dist/codegen-hash.js.map +1 -0
  114. package/dist/codegen-ir.d.ts +69 -2
  115. package/dist/codegen-ir.d.ts.map +1 -1
  116. package/dist/codegen-ir.js +661 -0
  117. package/dist/codegen-ir.js.map +1 -0
  118. package/dist/codegen-lang.d.ts +65 -0
  119. package/dist/codegen-lang.d.ts.map +1 -0
  120. package/dist/codegen-lang.js +526 -0
  121. package/dist/codegen-lang.js.map +1 -0
  122. package/dist/codegen-load.d.ts +31 -0
  123. package/dist/codegen-load.d.ts.map +1 -0
  124. package/dist/codegen-load.js +138 -0
  125. package/dist/codegen-load.js.map +1 -0
  126. package/dist/codegen-loaders.js +55 -0
  127. package/dist/codegen-loaders.js.map +1 -0
  128. package/dist/codegen-mcp.d.ts.map +1 -1
  129. package/dist/codegen-mcp.js +368 -0
  130. package/dist/codegen-mcp.js.map +1 -0
  131. package/dist/codegen-python.d.ts +13 -1
  132. package/dist/codegen-python.d.ts.map +1 -1
  133. package/dist/codegen-python.js +828 -0
  134. package/dist/codegen-python.js.map +1 -0
  135. package/dist/codegen-route-tree-intern.d.ts +15 -5
  136. package/dist/codegen-route-tree-intern.d.ts.map +1 -1
  137. package/dist/codegen-route-tree-intern.js +221 -0
  138. package/dist/codegen-route-tree-intern.js.map +1 -0
  139. package/dist/codegen-rust.d.ts.map +1 -1
  140. package/dist/codegen-rust.js +1293 -0
  141. package/dist/codegen-rust.js.map +1 -0
  142. package/dist/codegen-sanitize.d.ts.map +1 -1
  143. package/dist/codegen-sanitize.js +56 -0
  144. package/dist/codegen-sanitize.js.map +1 -0
  145. package/dist/codegen-schema-naming.d.ts +5 -0
  146. package/dist/codegen-schema-naming.d.ts.map +1 -1
  147. package/dist/codegen-schema-naming.js +150 -0
  148. package/dist/codegen-schema-naming.js.map +1 -0
  149. package/dist/codegen-sdk-model.d.ts +71 -0
  150. package/dist/codegen-sdk-model.d.ts.map +1 -0
  151. package/dist/codegen-sdk-model.js +179 -0
  152. package/dist/codegen-sdk-model.js.map +1 -0
  153. package/dist/codegen.d.ts +41 -23
  154. package/dist/codegen.d.ts.map +1 -1
  155. package/dist/codegen.js +4610 -0
  156. package/dist/codegen.js.map +1 -0
  157. package/dist/context.d.ts +36 -6
  158. package/dist/context.d.ts.map +1 -1
  159. package/dist/context.js +242 -0
  160. package/dist/context.js.map +1 -0
  161. package/dist/cookie-sign.d.ts +16 -2
  162. package/dist/cookie-sign.d.ts.map +1 -1
  163. package/dist/cookie-sign.js +104 -0
  164. package/dist/cookie-sign.js.map +1 -0
  165. package/dist/cookie.d.ts +12 -0
  166. package/dist/cookie.d.ts.map +1 -1
  167. package/dist/cookie.js +138 -0
  168. package/dist/cookie.js.map +1 -0
  169. package/dist/cors.d.ts +1 -0
  170. package/dist/cors.d.ts.map +1 -1
  171. package/dist/cors.js +87 -0
  172. package/dist/cors.js.map +1 -0
  173. package/dist/crypto.d.ts +6 -1
  174. package/dist/crypto.d.ts.map +1 -1
  175. package/dist/crypto.js +38 -0
  176. package/dist/crypto.js.map +1 -0
  177. package/dist/csrf.d.ts +19 -0
  178. package/dist/csrf.d.ts.map +1 -1
  179. package/dist/csrf.js +79 -0
  180. package/dist/csrf.js.map +1 -0
  181. package/dist/curl-logger.d.ts +14 -3
  182. package/dist/curl-logger.d.ts.map +1 -1
  183. package/dist/curl-logger.js +199 -0
  184. package/dist/curl-logger.js.map +1 -0
  185. package/dist/detect-runtime.js +13 -0
  186. package/dist/detect-runtime.js.map +1 -0
  187. package/dist/dict.d.ts +11 -0
  188. package/dist/dict.d.ts.map +1 -0
  189. package/dist/dict.js +13 -0
  190. package/dist/dict.js.map +1 -0
  191. package/dist/error.d.ts.map +1 -1
  192. package/dist/error.js +44 -0
  193. package/dist/error.js.map +1 -0
  194. package/dist/errors.js +39 -0
  195. package/dist/errors.js.map +1 -0
  196. package/dist/etag.d.ts +2 -0
  197. package/dist/etag.d.ts.map +1 -1
  198. package/dist/etag.js +82 -0
  199. package/dist/etag.js.map +1 -0
  200. package/dist/feature-detect.d.ts +25 -0
  201. package/dist/feature-detect.d.ts.map +1 -0
  202. package/dist/feature-detect.js +144 -0
  203. package/dist/feature-detect.js.map +1 -0
  204. package/dist/feature-load.js +36 -0
  205. package/dist/feature-load.js.map +1 -0
  206. package/dist/feature-slots.d.ts +44 -0
  207. package/dist/feature-slots.d.ts.map +1 -0
  208. package/dist/feature-slots.js +48 -0
  209. package/dist/feature-slots.js.map +1 -0
  210. package/dist/fetch-request.d.ts +10 -0
  211. package/dist/fetch-request.d.ts.map +1 -0
  212. package/dist/fetch-request.js +13 -0
  213. package/dist/fetch-request.js.map +1 -0
  214. package/dist/gen-process.d.ts +15 -0
  215. package/dist/gen-process.d.ts.map +1 -0
  216. package/dist/gen-process.js +43 -0
  217. package/dist/gen-process.js.map +1 -0
  218. package/dist/gen-write.d.ts +19 -0
  219. package/dist/gen-write.d.ts.map +1 -0
  220. package/dist/gen-write.js +120 -0
  221. package/dist/gen-write.js.map +1 -0
  222. package/dist/glob.d.ts +21 -0
  223. package/dist/glob.d.ts.map +1 -0
  224. package/dist/glob.js +115 -0
  225. package/dist/glob.js.map +1 -0
  226. package/dist/go-type-emitter.d.ts +18 -4
  227. package/dist/go-type-emitter.d.ts.map +1 -1
  228. package/dist/go-type-emitter.js +594 -0
  229. package/dist/go-type-emitter.js.map +1 -0
  230. package/dist/honey-response.d.ts.map +1 -1
  231. package/dist/honey-response.js +338 -0
  232. package/dist/honey-response.js.map +1 -0
  233. package/dist/i18n-slot.d.ts +8 -0
  234. package/dist/i18n-slot.d.ts.map +1 -1
  235. package/dist/i18n-slot.js +14 -0
  236. package/dist/i18n-slot.js.map +1 -0
  237. package/dist/i18n.d.ts +3 -0
  238. package/dist/i18n.d.ts.map +1 -1
  239. package/dist/i18n.js +250 -0
  240. package/dist/i18n.js.map +1 -0
  241. package/dist/index.d.ts +408 -148
  242. package/dist/index.d.ts.map +1 -1
  243. package/dist/index.js +2324 -0
  244. package/dist/index.js.map +1 -0
  245. package/dist/init.d.ts +3 -5
  246. package/dist/init.d.ts.map +1 -1
  247. package/dist/init.js +140 -0
  248. package/dist/init.js.map +1 -0
  249. package/dist/input.js +4 -0
  250. package/dist/input.js.map +1 -0
  251. package/dist/invalidate-check.d.ts +11 -0
  252. package/dist/invalidate-check.d.ts.map +1 -1
  253. package/dist/invalidate-check.js +163 -0
  254. package/dist/invalidate-check.js.map +1 -0
  255. package/dist/invoke-user.d.ts +35 -0
  256. package/dist/invoke-user.d.ts.map +1 -0
  257. package/dist/invoke-user.js +73 -0
  258. package/dist/invoke-user.js.map +1 -0
  259. package/dist/ip-restrict.d.ts +13 -1
  260. package/dist/ip-restrict.d.ts.map +1 -1
  261. package/dist/ip-restrict.js +60 -0
  262. package/dist/ip-restrict.js.map +1 -0
  263. package/dist/ip.d.ts +39 -0
  264. package/dist/ip.d.ts.map +1 -0
  265. package/dist/ip.js +209 -0
  266. package/dist/ip.js.map +1 -0
  267. package/dist/logger.d.ts.map +1 -1
  268. package/dist/logger.js +113 -0
  269. package/dist/logger.js.map +1 -0
  270. package/dist/media-type.d.ts +30 -0
  271. package/dist/media-type.d.ts.map +1 -0
  272. package/dist/media-type.js +97 -0
  273. package/dist/media-type.js.map +1 -0
  274. package/dist/meta-spec-merge.d.ts +32 -0
  275. package/dist/meta-spec-merge.d.ts.map +1 -0
  276. package/dist/meta-spec-merge.js +68 -0
  277. package/dist/meta-spec-merge.js.map +1 -0
  278. package/dist/meta-spec.d.ts +16 -3
  279. package/dist/meta-spec.d.ts.map +1 -1
  280. package/dist/meta-spec.js +535 -0
  281. package/dist/meta-spec.js.map +1 -0
  282. package/dist/middleware.d.ts +23 -6
  283. package/dist/middleware.d.ts.map +1 -1
  284. package/dist/middleware.js +253 -0
  285. package/dist/middleware.js.map +1 -0
  286. package/dist/node-request.d.ts +57 -12
  287. package/dist/node-request.d.ts.map +1 -1
  288. package/dist/node-request.js +407 -0
  289. package/dist/node-request.js.map +1 -0
  290. package/dist/node.d.ts +20 -3
  291. package/dist/node.d.ts.map +1 -1
  292. package/dist/node.js +396 -0
  293. package/dist/node.js.map +1 -0
  294. package/dist/openapi/collect.d.ts +6 -3
  295. package/dist/openapi/collect.d.ts.map +1 -1
  296. package/dist/openapi/collect.js +30 -0
  297. package/dist/openapi/collect.js.map +1 -0
  298. package/dist/openapi/docs-page.d.ts +42 -0
  299. package/dist/openapi/docs-page.d.ts.map +1 -0
  300. package/dist/openapi/docs-page.js +80 -0
  301. package/dist/openapi/docs-page.js.map +1 -0
  302. package/dist/openapi/document.d.ts +4 -0
  303. package/dist/openapi/document.d.ts.map +1 -1
  304. package/dist/openapi/document.js +785 -0
  305. package/dist/openapi/document.js.map +1 -0
  306. package/dist/openapi/json-schema-slot.d.ts +7 -0
  307. package/dist/openapi/json-schema-slot.d.ts.map +1 -1
  308. package/dist/openapi/json-schema-slot.js +38 -0
  309. package/dist/openapi/json-schema-slot.js.map +1 -0
  310. package/dist/openapi/register.d.ts.map +1 -1
  311. package/dist/openapi/register.js +20 -0
  312. package/dist/openapi/register.js.map +1 -0
  313. package/dist/openapi/scalar.d.ts +3 -1
  314. package/dist/openapi/scalar.d.ts.map +1 -1
  315. package/dist/openapi/scalar.js +21 -0
  316. package/dist/openapi/scalar.js.map +1 -0
  317. package/dist/openapi/serve.d.ts +9 -0
  318. package/dist/openapi/serve.d.ts.map +1 -0
  319. package/dist/openapi/serve.js +36 -0
  320. package/dist/openapi/serve.js.map +1 -0
  321. package/dist/openapi/spec-factory.d.ts +30 -1
  322. package/dist/openapi/spec-factory.d.ts.map +1 -1
  323. package/dist/openapi/spec-factory.js +52 -0
  324. package/dist/openapi/spec-factory.js.map +1 -0
  325. package/dist/openapi/spec.d.ts +14 -5
  326. package/dist/openapi/spec.d.ts.map +1 -1
  327. package/dist/openapi/spec.js +50 -0
  328. package/dist/openapi/spec.js.map +1 -0
  329. package/dist/openapi/swagger.d.ts +3 -1
  330. package/dist/openapi/swagger.d.ts.map +1 -1
  331. package/dist/openapi/swagger.js +22 -0
  332. package/dist/openapi/swagger.js.map +1 -0
  333. package/dist/pattern.d.ts +71 -0
  334. package/dist/pattern.d.ts.map +1 -0
  335. package/dist/pattern.js +239 -0
  336. package/dist/pattern.js.map +1 -0
  337. package/dist/peer.d.ts +17 -0
  338. package/dist/peer.d.ts.map +1 -0
  339. package/dist/peer.js +50 -0
  340. package/dist/peer.js.map +1 -0
  341. package/dist/plugin.d.ts +67 -16
  342. package/dist/plugin.d.ts.map +1 -1
  343. package/dist/plugin.js +649 -0
  344. package/dist/plugin.js.map +1 -0
  345. package/dist/powered-by.d.ts.map +1 -1
  346. package/dist/powered-by.js +11 -0
  347. package/dist/powered-by.js.map +1 -0
  348. package/dist/pretty-json.d.ts.map +1 -1
  349. package/dist/pretty-json.js +47 -0
  350. package/dist/pretty-json.js.map +1 -0
  351. package/dist/producer-stream.d.ts +47 -0
  352. package/dist/producer-stream.d.ts.map +1 -0
  353. package/dist/producer-stream.js +267 -0
  354. package/dist/producer-stream.js.map +1 -0
  355. package/dist/proxy.d.ts +47 -8
  356. package/dist/proxy.d.ts.map +1 -1
  357. package/dist/proxy.js +274 -0
  358. package/dist/proxy.js.map +1 -0
  359. package/dist/python-type-emitter.d.ts +14 -1
  360. package/dist/python-type-emitter.d.ts.map +1 -1
  361. package/dist/python-type-emitter.js +157 -0
  362. package/dist/python-type-emitter.js.map +1 -0
  363. package/dist/realtime/bus.d.ts +17 -1
  364. package/dist/realtime/bus.d.ts.map +1 -1
  365. package/dist/realtime/bus.js +112 -0
  366. package/dist/realtime/bus.js.map +1 -0
  367. package/dist/realtime/register.d.ts +3 -0
  368. package/dist/realtime/register.d.ts.map +1 -0
  369. package/dist/realtime/register.js +10 -0
  370. package/dist/realtime/register.js.map +1 -0
  371. package/dist/realtime/route.d.ts +65 -26
  372. package/dist/realtime/route.d.ts.map +1 -1
  373. package/dist/realtime/route.js +72 -0
  374. package/dist/realtime/route.js.map +1 -0
  375. package/dist/realtime/server.d.ts +43 -0
  376. package/dist/realtime/server.d.ts.map +1 -0
  377. package/dist/realtime/server.js +255 -0
  378. package/dist/realtime/server.js.map +1 -0
  379. package/dist/request-id.d.ts +7 -0
  380. package/dist/request-id.d.ts.map +1 -1
  381. package/dist/request-id.js +16 -0
  382. package/dist/request-id.js.map +1 -0
  383. package/dist/request-limits.d.ts +3 -0
  384. package/dist/request-limits.d.ts.map +1 -0
  385. package/dist/request-limits.js +3 -0
  386. package/dist/request-limits.js.map +1 -0
  387. package/dist/request-path.d.ts +33 -0
  388. package/dist/request-path.d.ts.map +1 -0
  389. package/dist/request-path.js +178 -0
  390. package/dist/request-path.js.map +1 -0
  391. package/dist/request-to-curl.d.ts +7 -1
  392. package/dist/request-to-curl.d.ts.map +1 -1
  393. package/dist/request-to-curl.js +48 -0
  394. package/dist/request-to-curl.js.map +1 -0
  395. package/dist/response.d.ts +25 -2
  396. package/dist/response.d.ts.map +1 -1
  397. package/dist/response.js +313 -0
  398. package/dist/response.js.map +1 -0
  399. package/dist/rust-type-emitter.d.ts +14 -2
  400. package/dist/rust-type-emitter.d.ts.map +1 -1
  401. package/dist/rust-type-emitter.js +463 -0
  402. package/dist/rust-type-emitter.js.map +1 -0
  403. package/dist/secure-headers.d.ts.map +1 -1
  404. package/dist/secure-headers.js +53 -0
  405. package/dist/secure-headers.js.map +1 -0
  406. package/dist/serve-register.d.ts +4 -0
  407. package/dist/serve-register.d.ts.map +1 -1
  408. package/dist/serve-register.js +9 -0
  409. package/dist/serve-register.js.map +1 -0
  410. package/dist/serve-slot.d.ts +3 -0
  411. package/dist/serve-slot.d.ts.map +1 -1
  412. package/dist/serve-slot.js +52 -0
  413. package/dist/serve-slot.js.map +1 -0
  414. package/dist/serve.d.ts +18 -1
  415. package/dist/serve.d.ts.map +1 -1
  416. package/dist/serve.js +157 -0
  417. package/dist/serve.js.map +1 -0
  418. package/dist/server-timing.d.ts.map +1 -1
  419. package/dist/server-timing.js +51 -0
  420. package/dist/server-timing.js.map +1 -0
  421. package/dist/static.d.ts +9 -0
  422. package/dist/static.d.ts.map +1 -1
  423. package/dist/static.js +102 -0
  424. package/dist/static.js.map +1 -0
  425. package/dist/telemetry/otel.d.ts +2 -0
  426. package/dist/telemetry/otel.d.ts.map +1 -1
  427. package/dist/telemetry/otel.js +135 -0
  428. package/dist/telemetry/otel.js.map +1 -0
  429. package/dist/testing.d.ts +12 -0
  430. package/dist/testing.d.ts.map +1 -1
  431. package/dist/testing.js +124 -0
  432. package/dist/testing.js.map +1 -0
  433. package/dist/timeout.d.ts +6 -0
  434. package/dist/timeout.d.ts.map +1 -1
  435. package/dist/timeout.js +36 -0
  436. package/dist/timeout.js.map +1 -0
  437. package/dist/tree.d.ts +133 -36
  438. package/dist/tree.d.ts.map +1 -1
  439. package/dist/tree.js +437 -0
  440. package/dist/tree.js.map +1 -0
  441. package/dist/trust.d.ts +21 -0
  442. package/dist/trust.d.ts.map +1 -0
  443. package/dist/trust.js +100 -0
  444. package/dist/trust.js.map +1 -0
  445. package/dist/ts-type-emitter.d.ts.map +1 -1
  446. package/dist/ts-type-emitter.js +150 -0
  447. package/dist/ts-type-emitter.js.map +1 -0
  448. package/dist/type-emitter.d.ts +16 -2
  449. package/dist/type-emitter.d.ts.map +1 -1
  450. package/dist/type-emitter.js +729 -0
  451. package/dist/type-emitter.js.map +1 -0
  452. package/dist/type-extractor.d.ts +8 -4
  453. package/dist/type-extractor.d.ts.map +1 -1
  454. package/dist/type-extractor.js +819 -0
  455. package/dist/type-extractor.js.map +1 -0
  456. package/dist/types.d.ts +7 -0
  457. package/dist/types.d.ts.map +1 -1
  458. package/dist/types.js +96 -0
  459. package/dist/types.js.map +1 -0
  460. package/dist/validation.d.ts +14 -2
  461. package/dist/validation.d.ts.map +1 -1
  462. package/dist/validation.js +335 -0
  463. package/dist/validation.js.map +1 -0
  464. package/dist/with-headers.d.ts +15 -0
  465. package/dist/with-headers.d.ts.map +1 -0
  466. package/dist/with-headers.js +45 -0
  467. package/dist/with-headers.js.map +1 -0
  468. package/dist/ws/bun.d.ts +11 -5
  469. package/dist/ws/bun.d.ts.map +1 -1
  470. package/dist/ws/bun.js +82 -0
  471. package/dist/ws/bun.js.map +1 -0
  472. package/dist/ws/cloudflare.d.ts +25 -3
  473. package/dist/ws/cloudflare.d.ts.map +1 -1
  474. package/dist/ws/cloudflare.js +117 -0
  475. package/dist/ws/cloudflare.js.map +1 -0
  476. package/dist/ws/deno.d.ts +4 -4
  477. package/dist/ws/deno.d.ts.map +1 -1
  478. package/dist/ws/deno.js +133 -0
  479. package/dist/ws/deno.js.map +1 -0
  480. package/dist/ws/node.d.ts +20 -3
  481. package/dist/ws/node.d.ts.map +1 -1
  482. package/dist/ws/node.js +173 -0
  483. package/dist/ws/node.js.map +1 -0
  484. package/dist/ws/session.d.ts +11 -0
  485. package/dist/ws/session.d.ts.map +1 -0
  486. package/dist/ws/session.js +60 -0
  487. package/dist/ws/session.js.map +1 -0
  488. package/dist/ws/shared.d.ts +65 -0
  489. package/dist/ws/shared.d.ts.map +1 -0
  490. package/dist/ws/shared.js +103 -0
  491. package/dist/ws/shared.js.map +1 -0
  492. package/dist/ws-origin.d.ts +20 -0
  493. package/dist/ws-origin.d.ts.map +1 -0
  494. package/dist/ws-origin.js +41 -0
  495. package/dist/ws-origin.js.map +1 -0
  496. package/dist/yaml.d.ts +15 -1
  497. package/dist/yaml.d.ts.map +1 -1
  498. package/dist/yaml.js +101 -0
  499. package/dist/yaml.js.map +1 -0
  500. package/docs/invalidate-spec.md +13 -1
  501. package/docs/meta-spec.md +36 -12
  502. package/docs/packaging.md +43 -24
  503. package/docs/regression-matrix/README.md +32 -0
  504. package/docs/regression-matrix/review.md +44 -0
  505. package/docs/regression-matrix/ws1-3.md +97 -0
  506. package/docs/regression-matrix/ws4-8.md +107 -0
  507. package/docs/regression-matrix/ws9-12.md +266 -0
  508. package/docs/sdk.md +102 -52
  509. package/package.json +183 -52
  510. package/src/accepts.ts +91 -33
  511. package/src/body-kind.ts +67 -0
  512. package/src/body-limit.ts +102 -87
  513. package/src/build/index.ts +104 -54
  514. package/src/cli-args.ts +123 -0
  515. package/src/cli-go/auth.go +12 -1
  516. package/src/cli-go/config.go +29 -2
  517. package/src/cli-go/errors.go +28 -10
  518. package/src/cli-go/multipart.go +51 -27
  519. package/src/cli-go/output.go +58 -4
  520. package/src/cli-go/root.go +1 -1
  521. package/src/cli-go/version.go +2 -2
  522. package/src/cli.ts +154 -148
  523. package/src/client/error.ts +56 -1
  524. package/src/client/http.ts +479 -256
  525. package/src/client/index.ts +55 -17
  526. package/src/client/path.ts +169 -0
  527. package/src/client/redirect-policy.ts +19 -0
  528. package/src/client/sdk.ts +180 -101
  529. package/src/client/sse.ts +92 -66
  530. package/src/client/ws.ts +67 -31
  531. package/src/client-go/errors.go +41 -12
  532. package/src/client-go/export.go +44 -0
  533. package/src/client-go/invalidation.go +52 -54
  534. package/src/client-go/nullable.go +62 -0
  535. package/src/client-go/realtime.go +147 -110
  536. package/src/client-go/runtime.go +646 -88
  537. package/src/client-go/sse.go +104 -94
  538. package/src/client-go/transport.go +67 -27
  539. package/src/client-go/ws.go +49 -25
  540. package/src/client-info.ts +79 -0
  541. package/src/client-mcp/server.ts +133 -3
  542. package/src/client-python/_invalidation.py +207 -291
  543. package/src/client-python/_realtime.py +63 -40
  544. package/src/client-python/_runtime.py +501 -119
  545. package/src/client-python/_sse.py +130 -74
  546. package/src/client-python/_transport.py +37 -9
  547. package/src/client-python/_ws.py +50 -22
  548. package/src/client-rust/errors.rs +21 -1
  549. package/src/client-rust/invalidation.rs +202 -231
  550. package/src/client-rust/invalidation_sync.rs +16 -229
  551. package/src/client-rust/nullable.rs +17 -0
  552. package/src/client-rust/realtime.rs +217 -217
  553. package/src/client-rust/runtime.rs +602 -177
  554. package/src/client-rust/runtime_sync.rs +169 -145
  555. package/src/client-rust/sse.rs +142 -121
  556. package/src/client-rust/ws.rs +61 -37
  557. package/src/codegen-go-cli.ts +607 -728
  558. package/src/codegen-go.ts +710 -770
  559. package/src/codegen-ir.ts +381 -75
  560. package/src/codegen-lang.ts +517 -0
  561. package/src/codegen-load.ts +150 -0
  562. package/src/codegen-mcp.ts +207 -108
  563. package/src/codegen-python.ts +684 -816
  564. package/src/codegen-route-tree-intern.ts +51 -25
  565. package/src/codegen-rust.ts +946 -1240
  566. package/src/codegen-sanitize.ts +0 -4
  567. package/src/codegen-schema-naming.ts +19 -6
  568. package/src/codegen-sdk-model.ts +228 -0
  569. package/src/codegen.ts +1488 -1140
  570. package/src/context.ts +130 -11
  571. package/src/cookie-sign.ts +85 -16
  572. package/src/cookie.ts +66 -11
  573. package/src/cors.ts +55 -54
  574. package/src/crypto.ts +27 -5
  575. package/src/csrf.ts +57 -25
  576. package/src/curl-logger.ts +155 -114
  577. package/src/dict.ts +12 -0
  578. package/src/error.ts +4 -2
  579. package/src/etag.ts +58 -34
  580. package/src/feature-detect.ts +147 -0
  581. package/src/feature-slots.ts +70 -0
  582. package/src/fetch-request.ts +13 -0
  583. package/src/gen-process.ts +42 -0
  584. package/src/gen-write.ts +127 -0
  585. package/src/glob.ts +109 -0
  586. package/src/go-type-emitter.ts +406 -155
  587. package/src/honey-response.ts +36 -9
  588. package/src/i18n-slot.ts +10 -0
  589. package/src/i18n.ts +98 -23
  590. package/src/index.ts +1887 -1756
  591. package/src/init.ts +40 -28
  592. package/src/invalidate-check.ts +42 -4
  593. package/src/invoke-user.ts +95 -0
  594. package/src/ip-restrict.ts +47 -161
  595. package/src/ip.ts +194 -0
  596. package/src/logger.ts +65 -36
  597. package/src/media-type.ts +104 -0
  598. package/src/meta-spec-merge.ts +80 -0
  599. package/src/meta-spec.ts +0 -0
  600. package/src/middleware.ts +112 -12
  601. package/src/node-request.ts +242 -52
  602. package/src/node.ts +318 -75
  603. package/src/openapi/collect.ts +19 -44
  604. package/src/openapi/docs-page.ts +89 -0
  605. package/src/openapi/document.ts +503 -224
  606. package/src/openapi/json-schema-slot.ts +40 -0
  607. package/src/openapi/register.ts +7 -2
  608. package/src/openapi/scalar.ts +11 -10
  609. package/src/openapi/serve.ts +39 -0
  610. package/src/openapi/spec-factory.ts +50 -1
  611. package/src/openapi/spec.ts +53 -30
  612. package/src/openapi/swagger.ts +12 -11
  613. package/src/pattern.ts +245 -0
  614. package/src/peer.ts +53 -0
  615. package/src/plugin.ts +270 -185
  616. package/src/powered-by.ts +2 -2
  617. package/src/pretty-json.ts +25 -9
  618. package/src/producer-stream.ts +296 -0
  619. package/src/proxy.ts +253 -55
  620. package/src/python-type-emitter.ts +68 -56
  621. package/src/realtime/bus.ts +56 -9
  622. package/src/realtime/register.ts +13 -0
  623. package/src/realtime/route.ts +129 -80
  624. package/src/realtime/server.ts +298 -0
  625. package/src/request-id.ts +13 -3
  626. package/src/request-limits.ts +2 -0
  627. package/src/request-path.ts +165 -0
  628. package/src/request-to-curl.ts +28 -7
  629. package/src/response.ts +143 -103
  630. package/src/rust-type-emitter.ts +265 -170
  631. package/src/secure-headers.ts +8 -4
  632. package/src/serve-register.ts +4 -0
  633. package/src/serve-slot.ts +38 -0
  634. package/src/serve.ts +113 -25
  635. package/src/server-timing.ts +11 -7
  636. package/src/static.ts +85 -32
  637. package/src/telemetry/otel.ts +29 -7
  638. package/src/testing.ts +76 -14
  639. package/src/timeout.ts +15 -7
  640. package/src/tree.ts +405 -333
  641. package/src/trust.ts +117 -0
  642. package/src/ts-type-emitter.ts +18 -12
  643. package/src/type-emitter.ts +227 -89
  644. package/src/type-extractor.ts +603 -423
  645. package/src/types.ts +8 -0
  646. package/src/validation.ts +221 -96
  647. package/src/with-headers.ts +45 -0
  648. package/src/ws/bun.ts +53 -15
  649. package/src/ws/cloudflare.ts +81 -19
  650. package/src/ws/deno.ts +124 -36
  651. package/src/ws/node.ts +173 -79
  652. package/src/ws/session.ts +73 -0
  653. package/src/ws/shared.ts +140 -0
  654. package/src/ws-origin.ts +53 -0
  655. package/src/yaml.ts +45 -22
  656. package/dist/client-mcp/server.d.ts +0 -10
  657. package/dist/client-mcp/server.d.ts.map +0 -1
  658. package/dist/client-mcp/types.d.ts +0 -16
  659. package/dist/client-mcp/types.d.ts.map +0 -1
  660. package/dist/cloudflare/realtime.d.ts +0 -30
  661. package/dist/cloudflare/realtime.d.ts.map +0 -1
  662. package/dist/realtime/buffer.d.ts +0 -18
  663. package/dist/realtime/buffer.d.ts.map +0 -1
  664. package/dist/realtime/longpoll.d.ts +0 -23
  665. package/dist/realtime/longpoll.d.ts.map +0 -1
  666. package/dist/realtime/protocol.d.ts +0 -50
  667. package/dist/realtime/protocol.d.ts.map +0 -1
  668. package/dist/realtime/runtime.d.ts +0 -74
  669. package/dist/realtime/runtime.d.ts.map +0 -1
  670. package/src/cloudflare/realtime.ts +0 -234
  671. package/src/realtime/buffer.ts +0 -101
  672. package/src/realtime/longpoll.ts +0 -148
  673. package/src/realtime/protocol.ts +0 -128
  674. package/src/realtime/runtime.ts +0 -427
package/src/codegen-ir.ts CHANGED
@@ -1,10 +1,15 @@
1
- import { type OpenApiSpecInput, extractOpenApiPathParams, resolveRefs } from "./codegen.ts"
1
+ import type { OpenApiSpecInput } from "./codegen.ts"
2
+ import { cmpCodeUnit, pascalWords } from "./codegen-lang.ts"
2
3
 
3
4
  export type IRScalarType = "string" | "number" | "integer" | "boolean" | "null"
4
5
 
5
6
  export type IRSchema =
6
7
  | { kind: "scalar"; type: IRScalarType; format?: string; enum?: (string | number | boolean)[] }
7
- | { kind: "const"; value: string | number | boolean }
8
+ | {
9
+ kind: "const"
10
+ value: string | number | boolean
11
+ /** the declared `type`, when the schema has one */ type?: IRScalarType
12
+ }
8
13
  | { kind: "object"; fields: IRField[]; additional?: IRSchema | false }
9
14
  | { kind: "array"; items: IRSchema }
10
15
  | { kind: "tuple"; items: IRSchema[] }
@@ -31,6 +36,12 @@ export type IRParam = {
31
36
  name: string
32
37
  schema: IRSchema
33
38
  description?: string
39
+ /** Path params are always required. */
40
+ required?: boolean
41
+ /** A path param that may span segments (`x-honey-wildcard`). */
42
+ wildcard?: true
43
+ /** `schema.default` as declared. */
44
+ default?: unknown
34
45
  }
35
46
 
36
47
  export type IRMultipartPart = {
@@ -48,6 +59,8 @@ export type IRBody =
48
59
  contentType: "multipart/form-data"
49
60
  parts: IRMultipartPart[]
50
61
  required: boolean
62
+ /** The whole form object, for emitters that type the form as one value. */
63
+ schema?: IRSchema
51
64
  }
52
65
 
53
66
  export type IRResponse = {
@@ -71,12 +84,18 @@ export type IROperation = {
71
84
  method: string /* upper-cased HTTP method */
72
85
  path: string /* OpenAPI path template, {param} preserved */
73
86
  description?: string
87
+ summary?: string
74
88
  params: {
75
89
  path: IRParam[]
76
90
  query: IRParam[]
77
91
  header: IRParam[]
92
+ /** Cookie params. Most SDKs leave them to per-call options; the TypeScript SDK types them. */
93
+ cookie?: IRParam[]
78
94
  }
95
+ /** The preferred request body: JSON first, then form, multipart, raw bytes. */
79
96
  body?: IRBody
97
+ /** Every declared request body, one per content type, in the same preference order. */
98
+ bodies?: IRBody[]
80
99
  responses: Record<string, IRResponse>
81
100
  extensions: IROperationExtensions
82
101
  }
@@ -87,24 +106,33 @@ export type IRNamespace = {
87
106
  entries: Map<string, IRTreeEntry>
88
107
  }
89
108
 
109
+ /** How a client authenticates: the header it sends and the prefix before the token. */
110
+ export type IRAuth = { headerName: string; prefix: string }
111
+
112
+ export type IRInfo = { title?: string; description?: string; version?: string }
113
+
90
114
  export type IR = {
91
115
  operations: IROperation[]
92
116
  schemas: Record<string, IRSchema>
117
+ /** `description` of each component schema that has one. */
118
+ schemaDescriptions: Record<string, string>
93
119
  tree: IRNamespace
120
+ auth: IRAuth
121
+ info: IRInfo
94
122
  }
95
123
 
96
124
  export function methodsOf(ns: IRNamespace): Array<[string, IROperation]> {
97
125
  return [...ns.entries.entries()]
98
126
  .filter((e): e is [string, Extract<IRTreeEntry, { kind: "method" }>] => e[1].kind === "method")
99
127
  .map(([k, v]): [string, IROperation] => [k, v.op])
100
- .sort(([a], [b]) => a.localeCompare(b))
128
+ .sort(([a], [b]) => cmpCodeUnit(a, b))
101
129
  }
102
130
 
103
131
  export function namespacesOf(ns: IRNamespace): Array<[string, IRNamespace]> {
104
132
  return [...ns.entries.entries()]
105
133
  .filter((e): e is [string, Extract<IRTreeEntry, { kind: "namespace" }>] => e[1].kind === "namespace")
106
134
  .map(([k, v]): [string, IRNamespace] => [k, v.ns])
107
- .sort(([a], [b]) => a.localeCompare(b))
135
+ .sort(([a], [b]) => cmpCodeUnit(a, b))
108
136
  }
109
137
 
110
138
  function firstDescendantId(ns: IRNamespace): string {
@@ -215,7 +243,10 @@ export function schemaToIR(schema: Record<string, unknown> | undefined): IRSchem
215
243
  if (schema.const !== undefined) {
216
244
  const v = schema.const
217
245
  if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
218
- return { kind: "const", value: v }
246
+ const out: Extract<IRSchema, { kind: "const" }> = { kind: "const", value: v }
247
+ const t = schema.type
248
+ if (t === "string" || t === "integer" || t === "number" || t === "boolean") out.type = t
249
+ return out
219
250
  }
220
251
  }
221
252
 
@@ -344,15 +375,68 @@ export function schemaToIR(schema: Record<string, unknown> | undefined): IRSchem
344
375
 
345
376
  const HTTP_METHODS = ["get", "post", "put", "patch", "delete", "head", "options"] as const
346
377
 
378
+ export type IRPathSegment = { kind: "literal"; text: string } | { kind: "param"; name: string }
379
+
380
+ /** Splits an OpenAPI path template into literal and `{param}` pieces. Any text between braces is a name. */
381
+ export function parseOpenApiPath(path: string): IRPathSegment[] {
382
+ const out: IRPathSegment[] = []
383
+ const re = /\{([^{}]+)\}/g
384
+ let last = 0
385
+ let match: RegExpExecArray | null = re.exec(path)
386
+ while (match !== null) {
387
+ if (match.index > last) out.push({ kind: "literal", text: path.slice(last, match.index) })
388
+ out.push({ kind: "param", name: match[1] })
389
+ last = match.index + match[0].length
390
+ match = re.exec(path)
391
+ }
392
+ if (last < path.length) out.push({ kind: "literal", text: path.slice(last) })
393
+ return out
394
+ }
395
+
396
+ export function openApiPathParams(path: string): string[] {
397
+ const names: string[] = []
398
+ for (const seg of parseOpenApiPath(path)) {
399
+ if (seg.kind === "param" && !names.includes(seg.name)) names.push(seg.name)
400
+ }
401
+ return names
402
+ }
403
+
404
+ type Components = Record<string, Record<string, unknown>>
405
+
406
+ /** Follows a component `$ref` on a parameter, request body or response object (not on schemas). */
407
+ function deref(value: unknown, components: Components, depth = 0): Record<string, unknown> | undefined {
408
+ if (!value || typeof value !== "object") return undefined
409
+ const obj = value as Record<string, unknown>
410
+ if (typeof obj.$ref !== "string" || depth > 16) return obj
411
+ const parts = obj.$ref.replace(/^#\//, "").split("/")
412
+ if (parts[0] !== "components" || parts.length !== 3) return undefined
413
+ const target = Object.hasOwn(components, parts[1]) ? components[parts[1]] : undefined
414
+ const next = target && Object.hasOwn(target, parts[2]) ? target[parts[2]] : undefined
415
+ return deref(next, components, depth + 1)
416
+ }
417
+
418
+ /** Resolves a top-level schema `$ref` against `components.schemas`, for shape checks only. */
419
+ function resolveSchemaShallow(
420
+ schema: Record<string, unknown> | undefined,
421
+ components: Components,
422
+ depth = 0,
423
+ ): Record<string, unknown> | undefined {
424
+ if (!schema || typeof schema.$ref !== "string" || depth > 16) return schema
425
+ const name = schema.$ref.split("/").pop() ?? ""
426
+ const schemas = components.schemas ?? {}
427
+ const next = Object.hasOwn(schemas, name) ? (schemas[name] as Record<string, unknown>) : undefined
428
+ return resolveSchemaShallow(next, components, depth + 1)
429
+ }
430
+
347
431
  /** Detect whether a multipart/form-data schema has at least one binary (file) property. */
348
- function hasBinaryMultipartPart(mediaType: Record<string, unknown> | undefined): boolean {
349
- const schema = mediaType?.schema as Record<string, unknown> | undefined
432
+ function hasBinaryMultipartPart(schema: Record<string, unknown> | undefined, components: Components): boolean {
350
433
  const props = schema?.properties as Record<string, Record<string, unknown>> | undefined
351
434
  if (!props) return false
352
- for (const prop of Object.values(props)) {
353
- if (prop.format === "binary") return true
354
- if (prop.type === "array") {
355
- const items = prop.items as Record<string, unknown> | undefined
435
+ for (const raw of Object.values(props)) {
436
+ const prop = resolveSchemaShallow(raw, components)
437
+ if (prop?.format === "binary") return true
438
+ if (prop?.type === "array") {
439
+ const items = resolveSchemaShallow(prop.items as Record<string, unknown> | undefined, components)
356
440
  if (items?.format === "binary") return true
357
441
  }
358
442
  }
@@ -360,147 +444,369 @@ function hasBinaryMultipartPart(mediaType: Record<string, unknown> | undefined):
360
444
  }
361
445
 
362
446
  /** Normalise a multipart/form-data object schema into typed parts. */
363
- function extractMultipartParts(mediaType: Record<string, unknown> | undefined): IRMultipartPart[] {
364
- const schema = mediaType?.schema as Record<string, unknown> | undefined
447
+ function extractMultipartParts(schema: Record<string, unknown> | undefined, components: Components): IRMultipartPart[] {
365
448
  const props = schema?.properties as Record<string, Record<string, unknown>> | undefined
366
449
  if (!props) return []
367
450
  const parts: IRMultipartPart[] = []
368
451
  for (const [name, propSchema] of Object.entries(props)) {
369
- const ir = schemaToIR(propSchema)
370
- const isBinary = ir.kind === "binary" || (ir.kind === "array" && ir.items.kind === "binary")
371
- parts.push({ name, schema: ir, type: isBinary ? "file" : "text" })
452
+ const resolved = resolveSchemaShallow(propSchema, components)
453
+ const resolvedItems =
454
+ resolved?.type === "array"
455
+ ? resolveSchemaShallow(resolved.items as Record<string, unknown> | undefined, components)
456
+ : undefined
457
+ const isBinary = resolved?.format === "binary" || resolvedItems?.format === "binary"
458
+ parts.push({ name, schema: schemaToIR(propSchema), type: isBinary ? "file" : "text" })
372
459
  }
373
460
  return parts
374
461
  }
375
462
 
376
- function buildOperation(id: string, method: string, path: string, op: Record<string, unknown>): IROperation {
463
+ /* JSON first, then the structured kinds, then whatever the spec lists first. */
464
+ const BODY_PREFERENCE = [
465
+ "application/json",
466
+ "application/x-www-form-urlencoded",
467
+ "multipart/form-data",
468
+ "application/octet-stream",
469
+ ]
470
+
471
+ function isJsonMediaType(ct: string): boolean {
472
+ const essence = ct.split(";")[0]?.trim().toLowerCase() ?? ""
473
+ return essence === "application/json" || essence.endsWith("+json")
474
+ }
475
+
476
+ function contentTypeRank(ct: string): number {
477
+ const essence = ct.split(";")[0]?.trim().toLowerCase() ?? ""
478
+ const i = BODY_PREFERENCE.indexOf(essence)
479
+ if (i >= 0) return i
480
+ return isJsonMediaType(ct) ? BODY_PREFERENCE.length : BODY_PREFERENCE.length + 1
481
+ }
482
+
483
+ /** Content types in preference order; ties keep the order the spec lists them in. */
484
+ function orderedContentTypes(content: Record<string, unknown>): string[] {
485
+ return Object.keys(content)
486
+ .map((ct, i) => ({ ct, i, rank: contentTypeRank(ct) }))
487
+ .sort((a, b) => a.rank - b.rank || a.i - b.i)
488
+ .map((x) => x.ct)
489
+ }
490
+
491
+ function preferredContentType(content: Record<string, unknown>): string | undefined {
492
+ return orderedContentTypes(content)[0]
493
+ }
494
+
495
+ function bodyFor(
496
+ ct: string,
497
+ mediaType: Record<string, unknown> | undefined,
498
+ required: boolean,
499
+ components: Components,
500
+ ): IRBody {
501
+ const rawSchema = mediaType?.schema as Record<string, unknown> | undefined
502
+ const essence = ct.split(";")[0]?.trim().toLowerCase()
503
+ if (essence === "application/octet-stream") {
504
+ return { contentType: "application/octet-stream", kind: "stream", required }
505
+ }
506
+ if (
507
+ essence === "multipart/form-data" &&
508
+ hasBinaryMultipartPart(resolveSchemaShallow(rawSchema, components), components)
509
+ ) {
510
+ const body: IRBody = {
511
+ contentType: "multipart/form-data",
512
+ kind: "multipart",
513
+ parts: extractMultipartParts(resolveSchemaShallow(rawSchema, components), components),
514
+ required,
515
+ }
516
+ if (rawSchema) body.schema = schemaToIR(rawSchema)
517
+ return body
518
+ }
519
+ const bodySchema = rawSchema ? schemaToIR(rawSchema) : { kind: "unknown" as const }
520
+ return { contentType: ct, kind: "raw", required, schema: bodySchema }
521
+ }
522
+
523
+ function buildOperation(
524
+ id: string,
525
+ method: string,
526
+ path: string,
527
+ op: Record<string, unknown>,
528
+ pathItem: Record<string, unknown>,
529
+ components: Components,
530
+ ): IROperation {
377
531
  const upperMethod = method.toUpperCase()
378
532
 
379
- const declaredParams = (op.parameters as Record<string, unknown>[] | undefined) ?? []
533
+ /* path-item parameters apply to every operation unless the operation overrides (same name + in) */
534
+ const opParams = ((op.parameters as unknown[] | undefined) ?? []).map((p) => deref(p, components))
535
+ const itemParams = ((pathItem.parameters as unknown[] | undefined) ?? []).map((p) => deref(p, components))
536
+ const declaredParams: Record<string, unknown>[] = []
537
+ for (const p of opParams) if (p) declaredParams.push(p)
538
+ for (const p of itemParams) {
539
+ if (!p) continue
540
+ if (!declaredParams.some((d) => d.name === p.name && d.in === p.in)) declaredParams.push(p)
541
+ }
542
+
380
543
  const pathParams: IRParam[] = []
381
544
  const queryParams: IRParam[] = []
382
545
  const headerParams: IRParam[] = []
383
- const declaredPathNames = new Set<string>()
546
+ const cookieParams: IRParam[] = []
547
+ const templateNames = openApiPathParams(path)
384
548
 
385
549
  for (const p of declaredParams) {
386
550
  const pIn = p.in as string
387
- const pName = p.name as string
551
+ const pName = String(p.name)
388
552
  const pSchema = p.schema
389
553
  ? schemaToIR(p.schema as Record<string, unknown>)
390
554
  : { kind: "scalar" as const, type: "string" as const }
391
- const param: IRParam = { name: pName, schema: pSchema }
555
+ const param: IRParam = { name: pName, required: pIn === "path" || p.required === true, schema: pSchema }
392
556
  if (typeof p.description === "string") param.description = p.description
557
+ if (p["x-honey-wildcard"] === true) param.wildcard = true
558
+ const pDefault = (p.schema as Record<string, unknown> | undefined)?.default
559
+ if (pDefault !== undefined) param.default = pDefault
393
560
  if (pIn === "path") {
394
- pathParams.push(param)
395
- declaredPathNames.add(pName)
561
+ /* a declared path param missing from the template cannot be sent */
562
+ if (templateNames.includes(pName)) pathParams.push(param)
396
563
  } else if (pIn === "query") {
397
564
  queryParams.push(param)
398
565
  } else if (pIn === "header") {
399
566
  headerParams.push(param)
567
+ } else if (pIn === "cookie") {
568
+ cookieParams.push(param)
400
569
  }
401
- /* cookie params discarded per OpenAPI client convention */
402
570
  }
403
571
 
404
- /* back-fill path params absent from parameters[] but present in the URL template */
405
- for (const name of extractOpenApiPathParams(path)) {
406
- if (!declaredPathNames.has(name)) {
407
- pathParams.push({ name, schema: { kind: "scalar", type: "string" } })
408
- }
572
+ /* path params in template order; back-fill the ones absent from parameters[] */
573
+ const orderedPath: IRParam[] = []
574
+ for (const name of templateNames) {
575
+ orderedPath.push(
576
+ pathParams.find((p) => p.name === name) ?? { name, required: true, schema: { kind: "scalar", type: "string" } },
577
+ )
409
578
  }
410
579
 
411
580
  let body: IRBody | undefined
412
- const requestBody = op.requestBody as Record<string, unknown> | undefined
581
+ const bodies: IRBody[] = []
582
+ const requestBody = deref(op.requestBody, components)
413
583
  if (requestBody) {
414
584
  const content = requestBody.content as Record<string, Record<string, unknown>> | undefined
415
- const firstCt = content ? Object.keys(content)[0] : undefined
416
- if (firstCt && content) {
417
- const mediaType = content[firstCt]
418
- const required = requestBody.required === true
419
-
420
- if (firstCt === "application/octet-stream") {
421
- body = { contentType: "application/octet-stream", kind: "stream", required }
422
- } else if (firstCt === "multipart/form-data" && hasBinaryMultipartPart(mediaType)) {
423
- body = {
424
- contentType: "multipart/form-data",
425
- kind: "multipart",
426
- parts: extractMultipartParts(mediaType),
427
- required,
428
- }
429
- } else {
430
- const bodySchema = mediaType?.schema
431
- ? schemaToIR(mediaType.schema as Record<string, unknown>)
432
- : { kind: "unknown" as const }
433
- body = { contentType: firstCt, kind: "raw", required, schema: bodySchema }
434
- }
585
+ const required = requestBody.required === true
586
+ for (const ct of content ? orderedContentTypes(content) : []) {
587
+ bodies.push(bodyFor(ct, content?.[ct], required, components))
435
588
  }
589
+ body = bodies[0]
436
590
  }
437
591
 
438
592
  const responses: Record<string, IRResponse> = {}
439
593
  const extensions: IROperationExtensions = {}
440
594
 
441
- const rawResponses = op.responses as Record<string, Record<string, unknown>> | undefined
595
+ const rawResponses = op.responses as Record<string, unknown> | undefined
442
596
  if (rawResponses) {
443
- for (const [status, response] of Object.entries(rawResponses)) {
597
+ for (const [status, rawResponse] of Object.entries(rawResponses)) {
598
+ const response = deref(rawResponse, components) ?? {}
444
599
  const content = response.content as Record<string, Record<string, unknown>> | undefined
445
600
  if (!content || Object.keys(content).length === 0) {
446
601
  responses[status] = { status }
447
- } else {
448
- const firstCt = Object.keys(content)[0]
449
- /* SSE detected by response content-type, not a request extension */
450
- if (firstCt === "text/event-stream") extensions.sse = true
451
- const mediaType = content[firstCt]
452
- const respSchema = mediaType?.schema ? schemaToIR(mediaType.schema as Record<string, unknown>) : undefined
453
- const resp: IRResponse = { contentType: firstCt, status }
454
- if (respSchema !== undefined) resp.schema = respSchema
455
- responses[status] = resp
602
+ continue
456
603
  }
604
+ /* SSE detected by response content-type, not a request extension */
605
+ if (Object.keys(content).some((k) => k.split(";")[0]?.trim().toLowerCase() === "text/event-stream")) {
606
+ extensions.sse = true
607
+ }
608
+ const ct = preferredContentType(content) ?? Object.keys(content)[0]
609
+ const mediaType = content[ct]
610
+ const respSchema = mediaType?.schema ? schemaToIR(mediaType.schema as Record<string, unknown>) : undefined
611
+ const resp: IRResponse = { contentType: ct, status }
612
+ if (respSchema !== undefined) resp.schema = respSchema
613
+ responses[status] = resp
457
614
  }
458
615
  }
459
616
 
460
617
  if (op["x-websocket"] === true) extensions.websocket = true
461
618
  if (op["x-realtime"] === true) extensions.realtime = true
462
- if (op["x-deprecated"] === true) extensions.deprecated = true
619
+ if (op["x-deprecated"] === true || op.deprecated === true) extensions.deprecated = true
463
620
  if (op["x-idempotency-key"] === true) extensions.idempotencyKey = true
464
621
  if (op["x-mcp"] === true) extensions.mcp = true
465
- if (Array.isArray(op["x-invalidate"])) extensions.invalidates = op["x-invalidate"] as string[]
622
+ if (Array.isArray(op["x-invalidate"])) {
623
+ extensions.invalidates = (op["x-invalidate"] as unknown[]).filter((x): x is string => typeof x === "string")
624
+ }
466
625
 
467
626
  const operation: IROperation = {
468
627
  extensions,
469
628
  id,
470
629
  method: upperMethod,
471
- params: { header: headerParams, path: pathParams, query: queryParams },
630
+ params: { header: headerParams, path: orderedPath, query: queryParams },
472
631
  path,
473
632
  responses,
474
633
  }
634
+ if (cookieParams.length > 0) operation.params.cookie = cookieParams
475
635
  if (body) operation.body = body
636
+ if (bodies.length > 1) operation.bodies = bodies
476
637
  if (typeof op.description === "string") operation.description = op.description
638
+ if (typeof op.summary === "string") operation.summary = op.summary
477
639
 
478
640
  return operation
479
641
  }
480
642
 
481
- export function toIR(spec: OpenApiSpecInput): IR {
482
- /* schemas built from raw components BEFORE resolveRefs, which strips them */
643
+ /** Deterministic id for an operation without an `operationId`: `GET /users/{id}` → `getUsersById`. */
644
+ export function deriveOperationId(method: string, path: string): string {
645
+ const literal: string[] = []
646
+ const params: string[] = []
647
+ for (const seg of parseOpenApiPath(path)) {
648
+ if (seg.kind === "param") params.push(pascalWords(seg.name))
649
+ else literal.push(pascalWords(seg.text))
650
+ }
651
+ const base = `${method.toLowerCase()}${literal.join("")}${params.length > 0 ? `By${params.join("And")}` : ""}`
652
+ return base === method.toLowerCase() ? `${base}Root` : base
653
+ }
654
+
655
+ export type ToIROptions = {
656
+ /** Give operations without an `operationId` a derived one instead of dropping them, and disambiguate
657
+ * a shared `operationId` by method. The non-TypeScript SDK emitters use this. */
658
+ deriveOperationIds?: boolean
659
+ /** A shared `operationId`: `"suffix"` disambiguates by method (default with `deriveOperationIds`),
660
+ * `"throw"` refuses the document (default otherwise; the TypeScript SDK always refuses). */
661
+ duplicateOperationIds?: "suffix" | "throw"
662
+ }
663
+
664
+ export function toIR(spec: OpenApiSpecInput, options: ToIROptions = {}): IR {
483
665
  const schemas: Record<string, IRSchema> = {}
484
666
  for (const [name, schema] of Object.entries(spec.components?.schemas ?? {})) {
485
667
  schemas[name] = schemaToIR(schema)
486
668
  }
487
669
 
488
- const resolved = resolveRefs(spec)
670
+ const components = (spec.components ?? {}) as Components
489
671
  const operations: IROperation[] = []
490
672
  const seen = new Set<string>()
491
-
492
- for (const [path, pathItem] of Object.entries(resolved.paths)) {
673
+ const pending: Array<{
674
+ method: string
675
+ op: Record<string, unknown>
676
+ path: string
677
+ pathItem: Record<string, unknown>
678
+ }> = []
679
+
680
+ for (const [path, pathItem] of Object.entries(spec.paths ?? {})) {
493
681
  for (const method of HTTP_METHODS) {
494
- const op = pathItem[method] as Record<string, unknown> | undefined
682
+ const op = (pathItem as Record<string, unknown>)[method] as Record<string, unknown> | undefined
495
683
  if (!op) continue
496
684
  const id = op.operationId as string | undefined
497
- if (!id) continue
498
- if (seen.has(id)) throw new Error(`Duplicate operationId: "${id}"`)
499
- seen.add(id)
500
- operations.push(buildOperation(id, method, path, op))
685
+ if (!id) {
686
+ if (options.deriveOperationIds)
687
+ pending.push({ method, op, path, pathItem: pathItem as Record<string, unknown> })
688
+ continue
689
+ }
690
+ let finalId = id
691
+ if (seen.has(id)) {
692
+ const onDuplicate = options.duplicateOperationIds ?? (options.deriveOperationIds ? "suffix" : "throw")
693
+ if (onDuplicate === "throw") throw new Error(`Duplicate operationId: "${id}"`)
694
+ finalId = `${id}${pascalWords(method)}`
695
+ for (let i = 2; seen.has(finalId); i++) finalId = `${id}${pascalWords(method)}${i}`
696
+ }
697
+ seen.add(finalId)
698
+ operations.push(buildOperation(finalId, method, path, op, pathItem as Record<string, unknown>, components))
501
699
  }
502
700
  }
503
701
 
702
+ /* derived ids after explicit ones, so an explicit id always keeps its name */
703
+ const namespaceRoots = new Set(operations.map((o) => o.id.split(".")[0] ?? o.id))
704
+ for (const { method, op, path, pathItem } of pending) {
705
+ const base = deriveOperationId(method, path)
706
+ let id = base
707
+ for (let i = 2; seen.has(id) || namespaceRoots.has(id); i++) id = `${base}${i}`
708
+ seen.add(id)
709
+ operations.push(buildOperation(id, method, path, op, pathItem, components))
710
+ }
711
+
504
712
  const tree = buildResourceTree(operations)
505
- return { operations, schemas, tree }
713
+ const schemaDescriptions: Record<string, string> = {}
714
+ for (const [name, schema] of Object.entries(spec.components?.schemas ?? {})) {
715
+ if (typeof schema.description === "string") schemaDescriptions[name] = schema.description
716
+ }
717
+ return { auth: specAuth(spec), info: infoOf(spec), operations, schemaDescriptions, schemas, tree }
718
+ }
719
+
720
+ /**
721
+ * The first security scheme (code-unit order) decides the header: http basic → `Basic `, other
722
+ * http → `Bearer `, a header apiKey → its name, with a prefix when its description says
723
+ * `Format: <prefix> {token}`. Anything else, or no scheme, is `Authorization: Bearer`.
724
+ */
725
+ export function specAuth(spec: OpenApiSpecInput): IRAuth {
726
+ const components = (spec.components ?? {}) as Record<string, unknown>
727
+ const schemes = (components.securitySchemes ?? {}) as Record<string, Record<string, unknown>>
728
+ const keys = Object.keys(schemes).sort(cmpCodeUnit)
729
+ const fallback = { headerName: "Authorization", prefix: "Bearer " }
730
+ const scheme = keys.length > 0 ? schemes[keys[0]] : undefined
731
+ if (!scheme) return fallback
732
+ const type = String(scheme.type ?? "")
733
+ if (type === "http") {
734
+ const httpScheme = String(scheme.scheme ?? "").toLowerCase()
735
+ return { headerName: "Authorization", prefix: httpScheme === "basic" ? "Basic " : "Bearer " }
736
+ }
737
+ if (type === "apiKey" && scheme.in === "header") {
738
+ const headerName = String(scheme.name ?? "Authorization")
739
+ const match = /Format:\s*(\S+)\s+\{/i.exec(String(scheme.description ?? ""))
740
+ return { headerName, prefix: match ? `${match[1]} ` : "" }
741
+ }
742
+ return fallback
743
+ }
744
+
745
+ function infoOf(spec: OpenApiSpecInput): IRInfo {
746
+ const info = ((spec as { info?: unknown }).info ?? {}) as Record<string, unknown>
747
+ const out: IRInfo = {}
748
+ for (const key of ["title", "description", "version"] as const) {
749
+ if (typeof info[key] === "string") out[key] = info[key] as string
750
+ }
751
+ return out
752
+ }
753
+
754
+ /** Every request body an operation declares, preferred first. */
755
+ export function bodiesOf(op: IROperation): IRBody[] {
756
+ return op.bodies ?? (op.body ? [op.body] : [])
757
+ }
758
+
759
+ /** Follows `ref` nodes to their component schema; an unknown ref resolves to `unknown`. */
760
+ export function irResolver(schemas: Record<string, IRSchema>): (schema: IRSchema) => IRSchema {
761
+ return (schema) => {
762
+ let cur = schema
763
+ for (let i = 0; i < 32 && cur.kind === "ref"; i++) {
764
+ const next = Object.hasOwn(schemas, cur.name) ? schemas[cur.name] : undefined
765
+ if (!next) return { kind: "unknown" }
766
+ cur = next
767
+ }
768
+ return cur
769
+ }
770
+ }
771
+
772
+ function isStringSchema(s: IRSchema | undefined): boolean {
773
+ return s?.kind === "scalar" && s.type === "string"
774
+ }
775
+
776
+ /**
777
+ * Honey's standard error envelope (`success: false`, `error_key` enum, one `status`), read from the IR.
778
+ * Returns its error keys and status, or null for any other shape.
779
+ */
780
+ export function irErrorEnvelope(
781
+ schema: IRSchema,
782
+ resolve: (schema: IRSchema) => IRSchema,
783
+ ): { keys: string[]; status: number } | null {
784
+ const obj = resolve(schema)
785
+ if (obj.kind !== "object") return null
786
+ const field = (o: Extract<IRSchema, { kind: "object" }>, name: string): IRSchema | undefined => {
787
+ const f = o.fields.find((x) => x.name === name)
788
+ return f ? resolve(f.schema) : undefined
789
+ }
790
+
791
+ const success = field(obj, "success")
792
+ if (success?.kind !== "const" || success.value !== false) return null
793
+ if (!isStringSchema(field(obj, "message")) || !isStringSchema(field(obj, "status_key"))) return null
794
+
795
+ const fields = field(obj, "fields")
796
+ if (fields?.kind !== "object" || !fields.additional) return null
797
+ const list = resolve(fields.additional)
798
+ if (list.kind !== "array") return null
799
+ const item = resolve(list.items)
800
+ if (item.kind !== "object") return null
801
+ for (const k of ["error_key", "message", "path"]) if (!isStringSchema(field(item, k))) return null
802
+
803
+ const status = field(obj, "status")
804
+ if (status?.kind !== "scalar" || !status.enum || status.enum.length !== 1) return null
805
+ const statusVal = status.enum[0]
806
+ if (typeof statusVal !== "number") return null
807
+
808
+ const key = field(obj, "error_key")
809
+ if (key?.kind !== "scalar" || !key.enum || key.enum.length === 0) return null
810
+ if (!key.enum.every((k) => typeof k === "string")) return null
811
+ return { keys: key.enum as string[], status: statusVal }
506
812
  }