@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
@@ -1,10 +1,11 @@
1
1
  /* Code generated by honey. DO NOT EDIT. */
2
2
 
3
3
  use crate::errors::{raise_for_status, Error};
4
- use bytes::Bytes;
5
4
  use futures_util::StreamExt;
6
5
 
7
- /// SseEvent represents a single server-sent event.
6
+ /// SseEvent represents a single server-sent event. `id` is the last event id
7
+ /// seen on the stream so far (the spec's sticky "last event ID buffer").
8
+ #[derive(Debug, Clone, Default, PartialEq)]
8
9
  pub struct SseEvent {
9
10
  pub data: String,
10
11
  pub event: String,
@@ -12,156 +13,176 @@ pub struct SseEvent {
12
13
  pub retry: i32,
13
14
  }
14
15
 
15
- /// parse_sse_stream returns a Stream of SseEvent values read from a reqwest Response.
16
- /// On non-2xx response it yields a typed error immediately then terminates.
17
- /// Hand-parsed over reqwest bytes_stream; mirrors Go parseSSEStream line-for-line.
18
- pub fn parse_sse_stream(
19
- resp: reqwest::Response,
20
- ) -> impl futures_util::Stream<Item = Result<SseEvent, Error>> {
21
- async_stream::stream! {
22
- let status = resp.status().as_u16();
23
- if !(200..300).contains(&status) {
24
- let body = resp.bytes().await.unwrap_or_default().to_vec();
25
- if let Some(err) = raise_for_status(status, body) {
26
- yield Err(err);
27
- }
28
- return;
29
- }
16
+ /// Largest single line, and largest data of one event.
17
+ pub const SSE_MAX_LINE: usize = 1024 * 1024;
18
+ pub const SSE_MAX_EVENT: usize = 8 * 1024 * 1024;
30
19
 
31
- let mut byte_stream = resp.bytes_stream();
32
- let mut buf = Vec::<u8>::new();
20
+ /// SseParser is an incremental WHATWG event-stream parser. Lines end in CRLF,
21
+ /// LF or CR; a blank line dispatches; a final event without its blank line is
22
+ /// never dispatched; `id` is sticky; `retry` needs ASCII digits; field values
23
+ /// are not trimmed. Each input byte is scanned once.
24
+ #[derive(Debug, Default)]
25
+ pub struct SseParser {
26
+ line: Vec<u8>,
27
+ pending_cr: bool,
28
+ started: bool,
29
+ data: String,
30
+ has_data: bool,
31
+ event: String,
32
+ last_id: String,
33
+ retry: i32,
34
+ }
33
35
 
34
- while let Some(chunk) = byte_stream.next().await {
35
- match chunk {
36
- Err(e) => {
37
- yield Err(Error::Transport(e));
38
- return;
36
+ impl SseParser {
37
+ pub fn new() -> Self {
38
+ Self::default()
39
+ }
40
+
41
+ /// feed consumes a chunk and returns every event it completes.
42
+ pub fn feed(&mut self, chunk: &[u8]) -> Result<Vec<SseEvent>, Error> {
43
+ let mut out = Vec::new();
44
+ for &b in chunk {
45
+ if self.pending_cr {
46
+ self.pending_cr = false;
47
+ if b == b'\n' {
48
+ continue;
39
49
  }
40
- Ok(bytes) => {
41
- buf.extend_from_slice(&bytes);
42
- loop {
43
- /* find next double-newline delimiter: \r\n\r\n, \n\n, \r\r */
44
- let delim_pos = find_double_newline(&buf);
45
- match delim_pos {
46
- None => break,
47
- Some((start, end)) => {
48
- let block = buf[..start].to_vec();
49
- buf.drain(..end);
50
- let block_str = String::from_utf8_lossy(&block);
51
- let trimmed = block_str.trim();
52
- if !trimmed.is_empty() {
53
- if let Some(ev) = parse_sse_block(trimmed) {
54
- yield Ok(ev);
55
- }
56
- }
57
- }
58
- }
50
+ }
51
+ match b {
52
+ b'\n' | b'\r' => {
53
+ if b == b'\r' {
54
+ self.pending_cr = true;
55
+ }
56
+ let line = std::mem::take(&mut self.line);
57
+ if let Some(ev) = self.process(&line)? {
58
+ out.push(ev);
59
59
  }
60
60
  }
61
- }
62
- }
63
-
64
- /* flush any remaining data */
65
- if !buf.is_empty() {
66
- let block_str = String::from_utf8_lossy(&buf);
67
- let trimmed = block_str.trim();
68
- if !trimmed.is_empty() {
69
- if let Some(ev) = parse_sse_block(trimmed) {
70
- yield Ok(ev);
61
+ _ => {
62
+ if self.line.len() >= SSE_MAX_LINE {
63
+ return Err(Error::Other("sse line exceeds 1 MiB".into()));
64
+ }
65
+ self.line.push(b);
71
66
  }
72
67
  }
73
68
  }
69
+ Ok(out)
74
70
  }
75
- }
76
71
 
77
- /// find_double_newline returns (content_end, advance) positions for the first
78
- /// occurrence of \r\n\r\n, \n\n, or \r\r in buf.
79
- pub(crate) fn find_double_newline(buf: &[u8]) -> Option<(usize, usize)> {
80
- let delimiters: &[&[u8]] = &[b"\r\n\r\n", b"\n\n", b"\r\r"];
81
- for delim in delimiters {
82
- let dlen = delim.len();
83
- if buf.len() < dlen {
84
- continue;
85
- }
86
- for i in 0..=(buf.len() - dlen) {
87
- if &buf[i..i + dlen] == *delim {
88
- return Some((i, i + dlen));
72
+ fn process(&mut self, raw: &[u8]) -> Result<Option<SseEvent>, Error> {
73
+ let mut line = String::from_utf8_lossy(raw).into_owned();
74
+ if !self.started {
75
+ self.started = true;
76
+ if let Some(rest) = line.strip_prefix('\u{feff}') {
77
+ line = rest.to_string();
89
78
  }
90
79
  }
91
- }
92
- None
93
- }
94
-
95
- /// parse_sse_block parses a single SSE message block into an SseEvent.
96
- /// Mirrors Go parseSSEBlock line-for-line:
97
- /// - colon-prefix lines are comments and skipped
98
- /// - field/val split on first colon; leading space stripped from val
99
- /// - data lines joined with \n
100
- /// - id containing null byte (\0) is ignored per spec
101
- /// - retry parsed as non-negative i32
102
- pub(crate) fn parse_sse_block(block: &str) -> Option<SseEvent> {
103
- let mut data = String::new();
104
- let mut has_data = false;
105
- let mut event = String::new();
106
- let mut id = String::new();
107
- let mut retry: i32 = 0;
108
- let mut is_comment = true;
109
-
110
- for raw_line in block.split('\n') {
111
- let line = raw_line.trim_end_matches('\r');
80
+ if line.is_empty() {
81
+ return Ok(self.dispatch());
82
+ }
112
83
  if line.starts_with(':') {
113
- continue;
84
+ return Ok(None);
114
85
  }
115
- is_comment = false;
116
-
117
- let (field, val) = if let Some(colon_idx) = line.find(':') {
118
- let f = &line[..colon_idx];
119
- let v = &line[colon_idx + 1..];
120
- let v = v.strip_prefix(' ').unwrap_or(v);
121
- (f, v)
122
- } else {
123
- (line, "")
86
+ let (field, value) = match line.find(':') {
87
+ Some(i) => {
88
+ let v = &line[i + 1..];
89
+ (&line[..i], v.strip_prefix(' ').unwrap_or(v))
90
+ }
91
+ None => (line.as_str(), ""),
124
92
  };
125
-
126
93
  match field {
127
94
  "data" => {
128
- if has_data {
129
- data.push('\n');
130
- data.push_str(val);
131
- } else {
132
- data = val.to_string();
133
- has_data = true;
95
+ if self.has_data {
96
+ self.data.push('\n');
134
97
  }
98
+ if self.data.len() + value.len() > SSE_MAX_EVENT {
99
+ return Err(Error::Other("sse event exceeds 8 MiB".into()));
100
+ }
101
+ self.data.push_str(value);
102
+ self.has_data = true;
135
103
  }
136
- "event" => {
137
- event = val.to_string();
138
- }
104
+ "event" => self.event = value.to_string(),
139
105
  "id" => {
140
- /* per spec: id containing null byte must be ignored */
141
- if !val.contains('\0') {
142
- id = val.to_string();
106
+ if !value.contains('\0') {
107
+ self.last_id = value.to_string();
143
108
  }
144
109
  }
145
110
  "retry" => {
146
- use std::str::FromStr;
147
- if let Ok(n) = i32::from_str(val) {
148
- if n >= 0 {
149
- retry = n;
111
+ if !value.is_empty() && value.bytes().all(|c| c.is_ascii_digit()) {
112
+ if let Ok(n) = value.parse::<i32>() {
113
+ self.retry = n;
150
114
  }
151
115
  }
152
116
  }
153
117
  _ => {}
154
118
  }
119
+ Ok(None)
155
120
  }
156
121
 
157
- if is_comment || !has_data {
158
- return None;
122
+ fn dispatch(&mut self) -> Option<SseEvent> {
123
+ let ev = if self.has_data {
124
+ Some(SseEvent {
125
+ data: std::mem::take(&mut self.data),
126
+ event: std::mem::take(&mut self.event),
127
+ id: self.last_id.clone(),
128
+ retry: self.retry,
129
+ })
130
+ } else {
131
+ None
132
+ };
133
+ self.data.clear();
134
+ self.has_data = false;
135
+ self.event.clear();
136
+ self.retry = 0;
137
+ ev
159
138
  }
139
+ }
160
140
 
161
- Some(SseEvent { data, event, id, retry })
141
+ /// parse_sse_text parses complete text; used by the conformance vectors.
142
+ pub fn parse_sse_text(chunks: &[&str]) -> Result<Vec<SseEvent>, Error> {
143
+ let mut p = SseParser::new();
144
+ let mut out = Vec::new();
145
+ for c in chunks {
146
+ out.extend(p.feed(c.as_bytes())?);
147
+ }
148
+ Ok(out)
162
149
  }
163
150
 
164
- /* suppress unused import warning — Bytes is part of the public API contract */
165
- const _: fn() = || {
166
- let _: Bytes = Bytes::new();
167
- };
151
+ /// parse_sse_stream returns a Stream of SseEvent values read from a reqwest Response.
152
+ /// On non-2xx response it yields a typed error immediately then terminates.
153
+ pub fn parse_sse_stream(
154
+ resp: reqwest::Response,
155
+ ) -> impl futures_util::Stream<Item = Result<SseEvent, Error>> {
156
+ async_stream::stream! {
157
+ let status = resp.status().as_u16();
158
+ if !(200..300).contains(&status) {
159
+ let body = resp.bytes().await.unwrap_or_default().to_vec();
160
+ if let Some(err) = raise_for_status(status, body) {
161
+ yield Err(err);
162
+ }
163
+ return;
164
+ }
165
+
166
+ let mut byte_stream = resp.bytes_stream();
167
+ let mut parser = SseParser::new();
168
+ while let Some(chunk) = byte_stream.next().await {
169
+ match chunk {
170
+ Err(e) => {
171
+ yield Err(Error::Transport(e));
172
+ return;
173
+ }
174
+ Ok(bytes) => match parser.feed(&bytes) {
175
+ Ok(events) => {
176
+ for ev in events {
177
+ yield Ok(ev);
178
+ }
179
+ }
180
+ Err(e) => {
181
+ yield Err(e);
182
+ return;
183
+ }
184
+ },
185
+ }
186
+ }
187
+ }
188
+ }
@@ -20,16 +20,17 @@ pub const WS_STATUS_PROTOCOL_ERROR: u16 = 1002;
20
20
  type WsStream = WebSocketStream<tokio_tungstenite::MaybeTlsStream<tokio::net::TcpStream>>;
21
21
 
22
22
  type WsHandler = Box<dyn Fn(&[u8]) + Send + Sync>;
23
- type HandlerMap = Mutex<HashMap<String, Vec<WsHandler>>>;
23
+ type SharedHandler = std::sync::Arc<dyn Fn(&[u8]) + Send + Sync>;
24
+ type HandlerMap = Mutex<HashMap<String, Vec<SharedHandler>>>;
24
25
 
25
- /// TypedWebSocket wraps a tokio-tungstenite connection with a buffered pre-OPEN
26
- /// send queue (flushed once on first read via AtomicBool) and an event fanout
27
- /// system that mirrors the TS client's .on() escape hatch.
26
+ /// TypedWebSocket wraps a tokio-tungstenite connection with an event fanout
27
+ /// system that mirrors the TS client's .on() escape hatch: "message" handlers
28
+ /// get each payload, "close" handlers the close reason, "error" handlers the
29
+ /// error text.
28
30
  pub struct TypedWebSocket {
29
31
  conn: WsStream,
30
- send_buffer: Option<Vec<u8>>,
31
- once: AtomicBool,
32
32
  handlers: HandlerMap,
33
+ closed: AtomicBool,
33
34
  }
34
35
 
35
36
  impl TypedWebSocket {
@@ -37,12 +38,29 @@ impl TypedWebSocket {
37
38
  pub fn new(conn: WsStream) -> Self {
38
39
  TypedWebSocket {
39
40
  conn,
40
- send_buffer: None,
41
- once: AtomicBool::new(false),
42
41
  handlers: Mutex::new(HashMap::new()),
42
+ closed: AtomicBool::new(false),
43
43
  }
44
44
  }
45
45
 
46
+ /// send_text writes a text frame as-is.
47
+ pub async fn send_text(&mut self, text: &str) -> Result<(), Error> {
48
+ use futures_util::SinkExt;
49
+ self.conn
50
+ .send(Message::Text(text.to_string()))
51
+ .await
52
+ .map_err(|e| Error::Other(e.to_string()))
53
+ }
54
+
55
+ /// send_binary writes a binary frame as-is.
56
+ pub async fn send_binary(&mut self, data: &[u8]) -> Result<(), Error> {
57
+ use futures_util::SinkExt;
58
+ self.conn
59
+ .send(Message::Binary(data.to_vec()))
60
+ .await
61
+ .map_err(|e| Error::Other(e.to_string()))
62
+ }
63
+
46
64
  /// send serialises data to JSON and writes it to the WebSocket connection.
47
65
  /// Accepts any serde_json::Value or JSON-serializable payload pre-encoded as Value.
48
66
  pub async fn send(&mut self, data: &serde_json::Value) -> Result<(), Error> {
@@ -64,15 +82,21 @@ impl TypedWebSocket {
64
82
  .map_err(|e| Error::Other(e.to_string()))
65
83
  }
66
84
 
67
- /// close sends a WebSocket close frame with the given status code and reason.
85
+ /// close sends a WebSocket close frame with the given status code and reason
86
+ /// (truncated to the 123 bytes a close frame can carry).
68
87
  pub async fn close(&mut self, code: u16, reason: &str) -> Result<(), Error> {
69
88
  use futures_util::SinkExt;
70
89
  use tokio_tungstenite::tungstenite::protocol::frame::coding::CloseCode;
71
90
  use tokio_tungstenite::tungstenite::protocol::CloseFrame;
91
+ let mut end = reason.len().min(123);
92
+ while !reason.is_char_boundary(end) {
93
+ end -= 1;
94
+ }
72
95
  let frame = CloseFrame {
73
96
  code: CloseCode::from(code),
74
- reason: reason.to_string().into(),
97
+ reason: reason[..end].to_string().into(),
75
98
  };
99
+ self.fire_close(&reason[..end]);
76
100
  self.conn
77
101
  .send(Message::Close(Some(frame)))
78
102
  .await
@@ -80,28 +104,19 @@ impl TypedWebSocket {
80
104
  }
81
105
 
82
106
  /// read reads the next message from the connection.
83
- /// On the first call, any pre-OPEN buffered send is flushed via AtomicBool compare_exchange.
84
107
  pub async fn read(&mut self) -> Result<Vec<u8>, Error> {
85
- use futures_util::{SinkExt, StreamExt};
86
-
87
- /* flush send_buffer exactly once on first read — mirrors Go sync.Once */
88
- if self
89
- .once
90
- .compare_exchange(false, true, Ordering::AcqRel, Ordering::Relaxed)
91
- .is_ok()
92
- {
93
- if let Some(buf) = self.send_buffer.take() {
94
- let _ = self
95
- .conn
96
- .send(Message::Text(String::from_utf8_lossy(&buf).into_owned()))
97
- .await;
98
- }
99
- }
100
-
108
+ use futures_util::StreamExt;
101
109
  loop {
102
110
  match self.conn.next().await {
103
- None => return Err(Error::Closed { code: 1006, reason: String::new() }),
104
- Some(Err(e)) => return Err(Error::Other(e.to_string())),
111
+ None => {
112
+ self.fire_close("");
113
+ return Err(Error::Closed { code: 1006, reason: String::new() });
114
+ }
115
+ Some(Err(e)) => {
116
+ let msg = e.to_string();
117
+ self.fanout("error", msg.as_bytes());
118
+ return Err(Error::Other(msg));
119
+ }
105
120
  Some(Ok(msg)) => {
106
121
  let data = match msg {
107
122
  Message::Text(t) => t.into_bytes(),
@@ -111,7 +126,8 @@ impl TypedWebSocket {
111
126
  Some(f) => (u16::from(f.code), f.reason.into_owned()),
112
127
  None => (1005, String::new()),
113
128
  };
114
- return Err(Error::Closed { code, reason })
129
+ self.fire_close(&reason);
130
+ return Err(Error::Closed { code, reason });
115
131
  }
116
132
  _ => continue,
117
133
  };
@@ -125,19 +141,27 @@ impl TypedWebSocket {
125
141
  /// on registers an event handler for a named event.
126
142
  /// Supported events: "message", "close", "error", "open".
127
143
  pub fn on(&mut self, event: &str, handler: WsHandler) {
128
- let mut handlers = self.handlers.lock().unwrap();
144
+ let mut handlers = self.handlers.lock().unwrap_or_else(|p| p.into_inner());
129
145
  handlers
130
146
  .entry(event.to_string())
131
147
  .or_default()
132
- .push(handler);
148
+ .push(std::sync::Arc::from(handler));
133
149
  }
134
150
 
151
+ fn fire_close(&self, reason: &str) {
152
+ if !self.closed.swap(true, Ordering::AcqRel) {
153
+ self.fanout("close", reason.as_bytes());
154
+ }
155
+ }
156
+
157
+ /// fanout calls handlers outside the lock, so a panicking handler cannot poison it.
135
158
  fn fanout(&self, event: &str, data: &[u8]) {
136
- let handlers = self.handlers.lock().unwrap();
137
- if let Some(hs) = handlers.get(event) {
138
- for h in hs {
139
- h(data);
140
- }
159
+ let hs: Vec<SharedHandler> = {
160
+ let handlers = self.handlers.lock().unwrap_or_else(|p| p.into_inner());
161
+ handlers.get(event).cloned().unwrap_or_default()
162
+ };
163
+ for h in hs {
164
+ h(data);
141
165
  }
142
166
  }
143
167
  }