@lovrozagar/honey 0.6.5 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +410 -149
  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 +776 -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 +1893 -1761
  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 +271 -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 +562 -424
  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
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
- import re
4
- from typing import AsyncIterator, TypedDict
3
+ import codecs
4
+ from typing import AsyncIterator, Iterable, Iterator, TypedDict
5
5
 
6
6
  import httpx
7
7
 
@@ -13,87 +13,143 @@ class SSEEvent(TypedDict, total=False):
13
13
  retry: int
14
14
 
15
15
 
16
- def _parse_sse_block(block: str) -> SSEEvent | None:
17
- lines = block.splitlines()
18
- is_comment = True
19
- data: str | None = None
20
- event: str | None = None
21
- id_val: str | None = None
22
- retry: int | None = None
23
-
24
- for line in lines:
16
+ DEFAULT_MAX_BUFFER = 1024 * 1024
17
+ MAX_EVENT_DATA = 8 * 1024 * 1024
18
+
19
+
20
+ class SSEParser:
21
+ """WHATWG event-stream parser.
22
+
23
+ Lines end in CRLF, LF or CR only (never U+2028 and friends, which
24
+ ``str.splitlines`` would also split on). A blank line dispatches the event;
25
+ a final event without its blank line is discarded; the id is sticky across
26
+ events; ``retry`` needs ASCII digits. Each chunk is scanned once.
27
+ """
28
+
29
+ def __init__(self, max_line: int = DEFAULT_MAX_BUFFER) -> None:
30
+ self._max_line = max_line
31
+ self._decoder = codecs.getincrementaldecoder("utf-8")("replace")
32
+ self._line: list[str] = []
33
+ self._line_len = 0
34
+ self._pending_cr = False
35
+ self._first = True
36
+ self._data: list[str] = []
37
+ self._data_len = 0
38
+ self._has_data = False
39
+ self._event: str | None = None
40
+ self._last_id: str | None = None
41
+ self._retry: int | None = None
42
+
43
+ def feed(self, chunk: bytes) -> Iterator[SSEEvent]:
44
+ yield from self._feed_text(self._decoder.decode(chunk))
45
+
46
+ def feed_text(self, text: str) -> Iterator[SSEEvent]:
47
+ yield from self._feed_text(text)
48
+
49
+ def _feed_text(self, text: str) -> Iterator[SSEEvent]:
50
+ start = 0
51
+ for i, ch in enumerate(text):
52
+ if i < start or (ch != "\r" and ch != "\n"):
53
+ continue
54
+ if ch == "\n" and self._pending_cr and i == start:
55
+ # LF completing a CRLF split across chunks
56
+ self._pending_cr = False
57
+ start = i + 1
58
+ continue
59
+ self._pending_cr = False
60
+ self._append(text[start:i])
61
+ line = "".join(self._line)
62
+ self._line = []
63
+ self._line_len = 0
64
+ if ch == "\r":
65
+ if i + 1 < len(text):
66
+ if text[i + 1] == "\n":
67
+ start = i + 2
68
+ event = self._process(line)
69
+ if event is not None:
70
+ yield event
71
+ continue
72
+ else:
73
+ self._pending_cr = True
74
+ start = i + 1
75
+ event = self._process(line)
76
+ if event is not None:
77
+ yield event
78
+ if start < len(text):
79
+ self._pending_cr = False
80
+ self._append(text[start:])
81
+
82
+ def _append(self, part: str) -> None:
83
+ if not part:
84
+ return
85
+ self._line_len += len(part)
86
+ if self._line_len > self._max_line:
87
+ raise RuntimeError(f"SSE line exceeded {self._max_line} characters")
88
+ self._line.append(part)
89
+
90
+ def _process(self, line: str) -> SSEEvent | None:
91
+ if self._first:
92
+ self._first = False
93
+ if line.startswith("\ufeff"):
94
+ line = line[1:]
95
+ if line == "":
96
+ return self._dispatch()
25
97
  if line.startswith(":"):
26
- continue
27
- is_comment = False
28
- colon_idx = line.find(":")
29
- if colon_idx == -1:
30
- field_name = line
31
- val = ""
32
- else:
33
- field_name = line[:colon_idx]
34
- val = line[colon_idx + 1:]
35
- if val.startswith(" "):
36
- val = val[1:]
37
-
38
- if field_name == "data":
39
- data = val if data is None else f"{data}\n{val}"
40
- elif field_name == "event":
41
- event = val
42
- elif field_name == "id":
43
- # per SSE spec: id containing null byte must be ignored
44
- if "\0" not in val:
45
- id_val = val
46
- elif field_name == "retry":
47
- try:
48
- n = int(val)
49
- if n >= 0:
50
- retry = n
51
- except ValueError:
52
- pass
53
-
54
- if is_comment or data is None:
98
+ return None
99
+ name, sep, value = line.partition(":")
100
+ if sep and value.startswith(" "):
101
+ value = value[1:]
102
+ if name == "data":
103
+ self._data_len += len(value) + 1
104
+ if self._data_len > MAX_EVENT_DATA:
105
+ raise RuntimeError(f"SSE event exceeded {MAX_EVENT_DATA} characters")
106
+ self._data.append(value)
107
+ self._has_data = True
108
+ elif name == "event":
109
+ self._event = value
110
+ elif name == "id":
111
+ if "\0" not in value:
112
+ self._last_id = value
113
+ elif name == "retry":
114
+ if value and value.isascii() and value.isdigit():
115
+ self._retry = int(value)
55
116
  return None
56
117
 
57
- result: SSEEvent = {"data": data}
58
- if event is not None:
59
- result["event"] = event
60
- if id_val is not None:
61
- result["id"] = id_val
62
- if retry is not None:
63
- result["retry"] = retry
64
- return result
65
-
66
-
67
- DEFAULT_MAX_BUFFER = 1024 * 1024
68
-
69
- _SSE_BLOCK_RE = re.compile(r"\r\n\r\n|\r\n\r|\r\n\n|\r\r\n|\n\r\n|\n\r|\r\r|\n\n")
118
+ def _dispatch(self) -> SSEEvent | None:
119
+ event: SSEEvent | None = None
120
+ if self._has_data:
121
+ event = {"data": "\n".join(self._data)}
122
+ if self._event is not None:
123
+ event["event"] = self._event
124
+ if self._last_id is not None:
125
+ event["id"] = self._last_id
126
+ if self._retry is not None:
127
+ event["retry"] = self._retry
128
+ self._data = []
129
+ self._data_len = 0
130
+ self._has_data = False
131
+ self._event = None
132
+ self._retry = None
133
+ return event
134
+
135
+
136
+ def parse_sse_text(chunks: Iterable[str]) -> list[SSEEvent]:
137
+ """Parse already-decoded text chunks; used by the conformance vectors."""
138
+ parser = SSEParser()
139
+ out: list[SSEEvent] = []
140
+ for chunk in chunks:
141
+ out.extend(parser.feed_text(chunk))
142
+ return out
70
143
 
71
144
 
72
145
  async def parse_sse_stream(
73
146
  response: httpx.Response,
74
147
  max_buffer_size: int = DEFAULT_MAX_BUFFER,
75
148
  ) -> AsyncIterator[SSEEvent]:
76
- buffer = ""
77
- async for chunk in response.aiter_text():
78
- buffer += chunk
79
- if len(buffer) > max_buffer_size:
80
- raise RuntimeError(f"SSE buffer exceeded {max_buffer_size} characters")
81
-
82
- # split on double-newline (any combo of \r\n, \r, \n)
83
- blocks = _SSE_BLOCK_RE.split(buffer)
84
- buffer = blocks.pop()
85
-
86
- for block in blocks:
87
- if not block.strip():
88
- continue
89
- event = _parse_sse_block(block)
90
- if event is not None:
91
- yield event
92
-
93
- if buffer.strip():
94
- event = _parse_sse_block(buffer)
95
- if event is not None:
149
+ parser = SSEParser(max_buffer_size)
150
+ async for chunk in response.aiter_bytes():
151
+ for event in parser.feed(chunk):
96
152
  yield event
97
153
 
98
154
 
99
- __all__ = ["SSEEvent", "parse_sse_stream"]
155
+ __all__ = ["SSEEvent", "SSEParser", "parse_sse_stream", "parse_sse_text"]
@@ -4,7 +4,7 @@ import json
4
4
  import uuid
5
5
  from dataclasses import dataclass, field
6
6
  from enum import Enum
7
- from typing import Any, Protocol, runtime_checkable
7
+ from typing import Any, Protocol, cast, runtime_checkable
8
8
  from urllib.parse import urlencode
9
9
 
10
10
  try:
@@ -28,12 +28,21 @@ class TransportKind(str, Enum):
28
28
 
29
29
  @dataclass
30
30
  class TransportOpts:
31
+ """Options for each transport connect.
32
+
33
+ ``max_reconnect_attempts`` caps consecutive failed reconnects (0 or less:
34
+ unlimited); ``reconnect_delay_ms`` is the first backoff delay. ``headers``
35
+ are sent on every transport (the generated SDK fills in config headers and
36
+ auth). ``max_message_bytes`` caps one WebSocket message.
37
+ """
38
+
31
39
  reconnect_token: str | None = None
32
40
  last_event_id: str | None = None
33
41
  headers: dict[str, str] | None = None
34
42
  max_reconnect_attempts: int = 5
35
43
  reconnect_delay_ms: int = 1000
36
44
  protocols: list[str] | None = None
45
+ max_message_bytes: int = 16 * 1024 * 1024
37
46
 
38
47
 
39
48
  @runtime_checkable
@@ -81,9 +90,9 @@ class _StubConn:
81
90
 
82
91
  def _to_ws_url(url: str) -> str:
83
92
  if url.startswith("https://"):
84
- return "wss://" + url[len("https://"):]
93
+ return "wss://" + url[len("https://") :]
85
94
  if url.startswith("http://"):
86
- return "ws://" + url[len("http://"):]
95
+ return "ws://" + url[len("http://") :]
87
96
  return url
88
97
 
89
98
 
@@ -148,8 +157,9 @@ class WsAdapter:
148
157
  headers = opts.headers or None
149
158
  conn = await websockets.connect(
150
159
  ws_url,
151
- subprotocols=subprotocols,
160
+ subprotocols=cast(Any, subprotocols),
152
161
  additional_headers=headers,
162
+ max_size=opts.max_message_bytes,
153
163
  )
154
164
  return _WsConn(conn)
155
165
 
@@ -224,14 +234,32 @@ class SseAdapter:
224
234
  headers["x-request-id"] = str(uuid.uuid4())
225
235
  client = self.http_client or httpx.AsyncClient()
226
236
  owns_client = self.http_client is None
237
+ # a stream may idle between events: no read timeout
227
238
  ctx = client.stream(
228
- "GET", url, params=params or None, headers=headers,
239
+ "GET",
240
+ url,
241
+ params=params or None,
242
+ headers=headers,
243
+ timeout=httpx.Timeout(30.0, read=None),
229
244
  )
230
- response = await ctx.__aenter__()
231
- response.raise_for_status()
245
+ try:
246
+ response = await ctx.__aenter__()
247
+ except BaseException:
248
+ if owns_client:
249
+ await client.aclose()
250
+ raise
251
+ try:
252
+ response.raise_for_status()
253
+ except BaseException:
254
+ await ctx.__aexit__(None, None, None)
255
+ if owns_client:
256
+ await client.aclose()
257
+ raise
232
258
  return _SseConn(
233
- client=client, owns_client=owns_client,
234
- ctx=ctx, response=response,
259
+ client=client,
260
+ owns_client=owns_client,
261
+ ctx=ctx,
262
+ response=response,
235
263
  )
236
264
 
237
265
 
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import json
4
- from typing import Any, AsyncIterator, Callable
4
+ from typing import Any, AsyncIterator, Callable, cast
5
5
 
6
6
  try:
7
7
  import websockets
@@ -43,15 +43,12 @@ class _TypedWebSocket:
43
43
  }
44
44
  self.close_code: int | None = None
45
45
  self.close_reason: str | None = None
46
+ self._close_fired = False
46
47
 
47
48
  async def __aenter__(self) -> _TypedWebSocket:
48
49
  if websockets is None:
49
50
  raise ImportError("pip install honey-sdk[ws] to use WebSocket methods")
50
- self._conn = await websockets.connect(
51
- self._url,
52
- subprotocols=self._protocols or None,
53
- additional_headers=self._extra_headers or None,
54
- )
51
+ self._conn = await _connect(self._url, self._protocols, self._extra_headers)
55
52
  for handler in self._handlers["open"]:
56
53
  try:
57
54
  handler()
@@ -66,13 +63,10 @@ class _TypedWebSocket:
66
63
  except Exception:
67
64
  pass
68
65
  self._capture_close()
69
- code = self.close_code if self.close_code is not None else 1000
70
- reason = self.close_reason if self.close_reason is not None else ""
71
- for handler in self._handlers["close"]:
72
- try:
73
- handler(code, reason)
74
- except Exception:
75
- pass
66
+ self._fire_close(
67
+ self.close_code if self.close_code is not None else 1000,
68
+ self.close_reason if self.close_reason is not None else "",
69
+ )
76
70
 
77
71
  def __aiter__(self) -> AsyncIterator[str | bytes]:
78
72
  return self._iter_messages()
@@ -86,16 +80,31 @@ class _TypedWebSocket:
86
80
  except Exception:
87
81
  pass
88
82
  yield msg
89
- finally:
90
- self._capture_close()
91
- code = self.close_code
92
- reason = self.close_reason
93
- if code is not None:
94
- for handler in self._handlers["close"]:
83
+ except Exception as exc:
84
+ closed_ok = websockets is not None and isinstance(
85
+ exc, getattr(websockets.exceptions, "ConnectionClosedOK", ())
86
+ )
87
+ if not closed_ok:
88
+ for handler in self._handlers["error"]:
95
89
  try:
96
- handler(code, reason or "")
90
+ handler(exc)
97
91
  except Exception:
98
92
  pass
93
+ raise
94
+ finally:
95
+ self._capture_close()
96
+ if self.close_code is not None:
97
+ self._fire_close(self.close_code, self.close_reason or "")
98
+
99
+ def _fire_close(self, code: int, reason: str) -> None:
100
+ if self._close_fired:
101
+ return
102
+ self._close_fired = True
103
+ for handler in self._handlers["close"]:
104
+ try:
105
+ handler(code, reason)
106
+ except Exception:
107
+ pass
99
108
 
100
109
  def _capture_close(self) -> None:
101
110
  """Read close code/reason from the underlying websockets.Connection once
@@ -118,8 +127,9 @@ class _TypedWebSocket:
118
127
  )
119
128
  self._handlers[event].append(callback)
120
129
 
121
- async def send(self, data: str | bytes | dict[str, Any]) -> None:
122
- if isinstance(data, dict):
130
+ async def send(self, data: Any) -> None:
131
+ """Send str/bytes as-is; anything else (dict, list, numbers) as JSON text."""
132
+ if not isinstance(data, (str, bytes, bytearray)):
123
133
  data = json.dumps(data)
124
134
  await self._conn.send(data)
125
135
 
@@ -128,4 +138,22 @@ class _TypedWebSocket:
128
138
  await self._conn.close(code, reason)
129
139
 
130
140
 
141
+ async def _connect(url: str, protocols: list[str], headers: dict[str, str]) -> Any:
142
+ """websockets >= 14 takes ``additional_headers``; older releases take
143
+ ``extra_headers``."""
144
+ assert websockets is not None
145
+ try:
146
+ return await websockets.connect(
147
+ url,
148
+ subprotocols=cast(Any, protocols or None),
149
+ additional_headers=headers or None,
150
+ )
151
+ except TypeError:
152
+ return await websockets.connect(
153
+ url,
154
+ subprotocols=cast(Any, protocols or None),
155
+ extra_headers=headers or None,
156
+ )
157
+
158
+
131
159
  __all__ = ["_TypedWebSocket"]
@@ -181,7 +181,7 @@ pub(crate) fn raise_for_status(status: u16, body: Vec<u8>) -> Option<Error> {
181
181
  } else {
182
182
  serde_json::from_slice(&body).ok()
183
183
  };
184
- let message = String::from_utf8_lossy(&body).to_string();
184
+ let message = error_message(&body, data.as_ref());
185
185
  let api_err: Box<dyn ApiError + Send + Sync> = match status {
186
186
  400 => Box::new(BadRequestError { message, body, status_code: 400, data }),
187
187
  401 => Box::new(UnauthorizedError { message, body, status_code: 401, data }),
@@ -198,3 +198,23 @@ pub(crate) fn raise_for_status(status: u16, body: Vec<u8>) -> Option<Error> {
198
198
  };
199
199
  Some(Error::Api(api_err))
200
200
  }
201
+
202
+ /// error_message is the server's `message` field when the body is a JSON object
203
+ /// carrying one, else the body text, with control characters dropped and capped
204
+ /// at 512 characters.
205
+ pub(crate) fn error_message(body: &[u8], data: Option<&serde_json::Value>) -> String {
206
+ let text = data
207
+ .and_then(|d| d.get("message"))
208
+ .and_then(|m| m.as_str())
209
+ .map(|s| s.to_string())
210
+ .unwrap_or_else(|| String::from_utf8_lossy(body).into_owned());
211
+ let mut out = String::new();
212
+ for (n, ch) in text.chars().filter(|c| !c.is_control()).enumerate() {
213
+ if n >= 512 {
214
+ out.push('…');
215
+ break;
216
+ }
217
+ out.push(ch);
218
+ }
219
+ out
220
+ }