@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
@@ -5,6 +5,7 @@ package sdk
5
5
  import (
6
6
  "bufio"
7
7
  "context"
8
+ "errors"
8
9
  "io"
9
10
  "iter"
10
11
  "net/http"
@@ -12,7 +13,8 @@ import (
12
13
  "strings"
13
14
  )
14
15
 
15
- // SSEEvent represents a single server-sent event.
16
+ // SSEEvent represents a single server-sent event. ID is the last event ID seen
17
+ // on the stream so far (the spec's sticky "last event ID buffer").
16
18
  type SSEEvent struct {
17
19
  Data string
18
20
  Event string
@@ -20,130 +22,138 @@ type SSEEvent struct {
20
22
  Retry int
21
23
  }
22
24
 
23
- const sseMaxBuffer = 1024 * 1024
25
+ // sseMaxLine caps one line, and sseMaxEvent the data of one event.
26
+ const (
27
+ sseMaxLine = 1024 * 1024
28
+ sseMaxEvent = 8 * 1024 * 1024
29
+ )
30
+
31
+ // ErrSSELineTooLong is returned when a single SSE line exceeds the cap.
32
+ var ErrSSELineTooLong = errors.New("honey: sse line exceeds 1 MiB")
24
33
 
25
34
  // parseSSEStream returns an iter.Seq2 that yields SSEEvent values read from resp.Body.
26
35
  // On non-2xx response it yields a typed error immediately then terminates.
27
36
  // The response body is closed when the iterator returns.
28
- //
29
- // Ported from public/honey/core/src/client/sse.ts:62-102 — bufio.Scanner with
30
- // double-newline split mirrors the TextDecoder+split(/\r\n\r\n|…/) approach.
31
37
  func parseSSEStream(ctx context.Context, resp *http.Response) iter.Seq2[SSEEvent, error] {
32
38
  return func(yield func(SSEEvent, error) bool) {
33
39
  defer resp.Body.Close()
34
40
 
35
41
  if resp.StatusCode < 200 || resp.StatusCode >= 300 {
36
- body, _ := io.ReadAll(resp.Body)
37
- apiErr := raiseForStatus(resp, body)
38
- yield(SSEEvent{}, apiErr)
42
+ body, _ := readBody(resp.Body, 64<<10)
43
+ yield(SSEEvent{}, raiseForStatus(resp, body))
39
44
  return
40
45
  }
41
46
 
42
- scanner := bufio.NewScanner(resp.Body)
43
- scanner.Buffer(make([]byte, 0, 4096), sseMaxBuffer)
44
- scanner.Split(splitDoubleNewline)
45
-
46
- for scanner.Scan() {
47
+ for ev, err := range parseSSE(resp.Body) {
47
48
  if ctx.Err() != nil {
48
49
  return
49
50
  }
50
- block := scanner.Text()
51
- if strings.TrimSpace(block) == "" {
52
- continue
53
- }
54
- ev, ok := parseSSEBlock(block)
55
- if !ok {
56
- continue
57
- }
58
- if !yield(ev, nil) {
51
+ if !yield(ev, err) || err != nil {
59
52
  return
60
53
  }
61
54
  }
62
-
63
- if err := scanner.Err(); err != nil {
64
- yield(SSEEvent{}, err)
65
- }
66
55
  }
67
56
  }
68
57
 
69
- // splitDoubleNewline is a bufio.SplitFunc that splits on \r\n\r\n, \n\n, or \r\r.
70
- func splitDoubleNewline(data []byte, atEOF bool) (advance int, token []byte, err error) {
71
- delimiters := []string{"\r\n\r\n", "\n\n", "\r\r"}
72
- for _, d := range delimiters {
73
- db := []byte(d)
74
- for i := 0; i <= len(data)-len(db); i++ {
75
- match := true
76
- for j := range db {
77
- if data[i+j] != db[j] {
78
- match = false
79
- break
58
+ // parseSSE implements the WHATWG event-stream parser: lines end in CRLF, LF or
59
+ // CR; a blank line dispatches; a final event without its blank line is
60
+ // discarded; the id is sticky across events; retry needs only ASCII digits.
61
+ func parseSSE(r io.Reader) iter.Seq2[SSEEvent, error] {
62
+ return func(yield func(SSEEvent, error) bool) {
63
+ br := bufio.NewReaderSize(r, 64*1024)
64
+ var (
65
+ data strings.Builder
66
+ hasData bool
67
+ event string
68
+ lastID string
69
+ retry int
70
+ firstLine = true
71
+ )
72
+ for {
73
+ line, err := readSSELine(br)
74
+ if err != nil {
75
+ if !errors.Is(err, io.EOF) {
76
+ yield(SSEEvent{}, err)
77
+ }
78
+ return
79
+ }
80
+ if firstLine {
81
+ line = strings.TrimPrefix(line, string(rune(0xFEFF)))
82
+ firstLine = false
83
+ }
84
+ if line == "" {
85
+ if hasData {
86
+ ev := SSEEvent{Data: data.String(), Event: event, ID: lastID, Retry: retry}
87
+ if !yield(ev, nil) {
88
+ return
89
+ }
80
90
  }
91
+ data.Reset()
92
+ hasData = false
93
+ event = ""
94
+ retry = 0
95
+ continue
96
+ }
97
+ if strings.HasPrefix(line, ":") {
98
+ continue
81
99
  }
82
- if match {
83
- return i + len(db), data[:i], nil
100
+ field, value := line, ""
101
+ if i := strings.IndexByte(line, ':'); i >= 0 {
102
+ field, value = line[:i], strings.TrimPrefix(line[i+1:], " ")
103
+ }
104
+ switch field {
105
+ case "data":
106
+ if hasData {
107
+ data.WriteByte('\n')
108
+ }
109
+ if data.Len()+len(value) > sseMaxEvent {
110
+ yield(SSEEvent{}, errors.New("honey: sse event exceeds 8 MiB"))
111
+ return
112
+ }
113
+ data.WriteString(value)
114
+ hasData = true
115
+ case "event":
116
+ event = value
117
+ case "id":
118
+ if !strings.ContainsRune(value, 0) {
119
+ lastID = value
120
+ }
121
+ case "retry":
122
+ if value != "" && strings.Trim(value, "0123456789") == "" {
123
+ if n, convErr := strconv.Atoi(value); convErr == nil {
124
+ retry = n
125
+ }
126
+ }
84
127
  }
85
128
  }
86
129
  }
87
- if atEOF && len(data) > 0 {
88
- return len(data), data, nil
89
- }
90
- return 0, nil, nil
91
130
  }
92
131
 
93
- func parseSSEBlock(block string) (SSEEvent, bool) {
94
- lines := strings.Split(block, "\n")
95
- isComment := true
96
- var data string
97
- hasData := false
98
- var event string
99
- var id string
100
- retry := 0
101
-
102
- for _, rawLine := range lines {
103
- line := strings.TrimRight(rawLine, "\r")
104
- if strings.HasPrefix(line, ":") {
105
- continue
106
- }
107
- isComment = false
108
-
109
- colonIdx := strings.IndexByte(line, ':')
110
- var field, val string
111
- if colonIdx == -1 {
112
- field = line
113
- val = ""
114
- } else {
115
- field = line[:colonIdx]
116
- val = line[colonIdx+1:]
117
- if strings.HasPrefix(val, " ") {
118
- val = val[1:]
132
+ // readSSELine reads one line without its terminator. A CR may be followed by
133
+ // an LF that belongs to the same terminator. io.EOF is returned only when no
134
+ // complete line remains, so a truncated final line is never parsed.
135
+ func readSSELine(br *bufio.Reader) (string, error) {
136
+ var b strings.Builder
137
+ for {
138
+ c, err := br.ReadByte()
139
+ if err != nil {
140
+ if errors.Is(err, io.EOF) {
141
+ return "", io.EOF
119
142
  }
143
+ return "", err
120
144
  }
121
-
122
- switch field {
123
- case "data":
124
- if !hasData {
125
- data = val
126
- } else {
127
- data = data + "\n" + val
128
- }
129
- hasData = true
130
- case "event":
131
- event = val
132
- case "id":
133
- /* per spec: id containing null byte must be ignored */
134
- if !strings.ContainsRune(val, 0) {
135
- id = val
136
- }
137
- case "retry":
138
- if n, err := strconv.Atoi(val); err == nil && n >= 0 {
139
- retry = n
145
+ switch c {
146
+ case '\n':
147
+ return b.String(), nil
148
+ case '\r':
149
+ if next, peekErr := br.Peek(1); peekErr == nil && next[0] == '\n' {
150
+ _, _ = br.ReadByte()
140
151
  }
152
+ return b.String(), nil
141
153
  }
154
+ if b.Len() >= sseMaxLine {
155
+ return "", ErrSSELineTooLong
156
+ }
157
+ b.WriteByte(c)
142
158
  }
143
-
144
- if isComment || !hasData {
145
- return SSEEvent{}, false
146
- }
147
-
148
- return SSEEvent{Data: data, Event: event, ID: id, Retry: retry}, true
149
159
  }
@@ -12,6 +12,7 @@ import (
12
12
  "net/url"
13
13
  "strings"
14
14
  "sync"
15
+ "time"
15
16
 
16
17
  "nhooyr.io/websocket"
17
18
  )
@@ -28,6 +29,9 @@ const (
28
29
 
29
30
  // TransportOpts is handed to each Transport.Connect call. Mirrors the TS
30
31
  // TransportOpts plus per-language extras (HTTPClient for SSE/longpoll dial).
32
+ //
33
+ // MaxMessageBytes caps one inbound WebSocket message (zero means 16 MiB).
34
+ // PollTimeout bounds one long-poll request (zero means 60s).
31
35
  type TransportOpts struct {
32
36
  ReconnectToken string
33
37
  LastEventID string
@@ -36,6 +40,20 @@ type TransportOpts struct {
36
40
  ReconnectDelayMs int
37
41
  Protocols []string
38
42
  HTTPClient *http.Client
43
+ MaxMessageBytes int64
44
+ PollTimeout time.Duration
45
+ }
46
+
47
+ const (
48
+ defaultMaxMessageBytes = 16 << 20
49
+ defaultPollTimeout = 60 * time.Second
50
+ )
51
+
52
+ func (o *TransportOpts) maxMessageBytes() int64 {
53
+ if o == nil || o.MaxMessageBytes <= 0 {
54
+ return defaultMaxMessageBytes
55
+ }
56
+ return o.MaxMessageBytes
39
57
  }
40
58
 
41
59
  // TransportConn is the live per-transport connection object. Each built-in
@@ -106,6 +124,7 @@ func (t *WsTransport) Connect(ctx context.Context, rawURL string, opts *Transpor
106
124
  if len(opts.Headers) > 0 {
107
125
  dialOpts.HTTPHeader = opts.Headers.Clone()
108
126
  }
127
+ dialOpts.HTTPClient = opts.HTTPClient
109
128
  }
110
129
  if dialOpts.Subprotocols == nil && len(t.Subprotocols) > 0 {
111
130
  dialOpts.Subprotocols = t.Subprotocols
@@ -114,6 +133,7 @@ func (t *WsTransport) Connect(ctx context.Context, rawURL string, opts *Transpor
114
133
  if err != nil {
115
134
  return nil, err
116
135
  }
136
+ conn.SetReadLimit(opts.maxMessageBytes())
117
137
  return &wsConn{conn: conn}, nil
118
138
  }
119
139
 
@@ -155,6 +175,7 @@ func (c *wsConn) Close() error {
155
175
  return c.conn.Close(websocket.StatusNormalClosure, "client close")
156
176
  }
157
177
 
178
+ // toWsURL swaps the scheme only; a URL inside the query string is untouched.
158
179
  func toWsURL(u string) string {
159
180
  if strings.HasPrefix(u, "https://") {
160
181
  return "wss://" + u[len("https://"):]
@@ -199,8 +220,13 @@ func (t *SseTransport) Connect(ctx context.Context, rawURL string, opts *Transpo
199
220
  }
200
221
  u = u + sep + "reconnect_token=" + url.QueryEscape(opts.ReconnectToken)
201
222
  }
202
- req, err := http.NewRequestWithContext(ctx, "GET", u, nil)
223
+ /* ctx bounds the open only; the stream lives until Close cancels streamCtx */
224
+ streamCtx, cancel := context.WithCancel(context.Background())
225
+ stop := context.AfterFunc(ctx, cancel)
226
+ req, err := http.NewRequestWithContext(streamCtx, "GET", u, nil)
203
227
  if err != nil {
228
+ stop()
229
+ cancel()
204
230
  return nil, err
205
231
  }
206
232
  req.Header.Set("Accept", "text/event-stream")
@@ -218,19 +244,34 @@ func (t *SseTransport) Connect(ctx context.Context, rawURL string, opts *Transpo
218
244
  req.Header.Set("X-Request-Id", newUUIDv4())
219
245
  }
220
246
  resp, err := client.Do(req)
247
+ opened := stop()
221
248
  if err != nil {
249
+ cancel()
222
250
  return nil, err
223
251
  }
252
+ if !opened {
253
+ /* ctx ended while the headers arrived */
254
+ _ = resp.Body.Close()
255
+ cancel()
256
+ return nil, ctx.Err()
257
+ }
224
258
  if resp.StatusCode < 200 || resp.StatusCode >= 300 {
225
259
  _ = resp.Body.Close()
260
+ cancel()
226
261
  return nil, fmt.Errorf("honey: sse transport: status %d", resp.StatusCode)
227
262
  }
263
+ if ct := resp.Header.Get("Content-Type"); !strings.HasPrefix(strings.ToLower(ct), "text/event-stream") {
264
+ _ = resp.Body.Close()
265
+ cancel()
266
+ return nil, fmt.Errorf("honey: sse transport: unexpected content type %q", ct)
267
+ }
228
268
  sc := &sseConn{
229
- resp: resp,
230
- next: make(chan sseResult, 1),
231
- done: make(chan struct{}),
269
+ resp: resp,
270
+ next: make(chan sseResult, 1),
271
+ done: make(chan struct{}),
272
+ cancel: cancel,
232
273
  }
233
- go sc.run(ctx)
274
+ go sc.run(streamCtx)
234
275
  return sc, nil
235
276
  }
236
277
 
@@ -243,8 +284,10 @@ type sseConn struct {
243
284
  resp *http.Response
244
285
  next chan sseResult
245
286
  done chan struct{}
287
+ cancel context.CancelFunc
246
288
  mu sync.Mutex
247
289
  closed bool
290
+ once sync.Once
248
291
  }
249
292
 
250
293
  func (c *sseConn) Kind() TransportKind { return TransportSse }
@@ -303,21 +346,11 @@ func (c *sseConn) Send(ctx context.Context, data any) error {
303
346
  }
304
347
 
305
348
  func (c *sseConn) Close() error {
306
- c.mu.Lock()
307
- alreadyClosed := c.closed
308
- c.mu.Unlock()
309
- /* signal producer, then close body — parseSSEStream closes body on its own
310
- * iterator exit, but bodyClose here is idempotent for the already-closed
311
- * case via Body.Close()'s stdlib contract. */
312
- select {
313
- case <-c.done:
314
- default:
349
+ c.once.Do(func() {
315
350
  close(c.done)
316
- }
317
- if !alreadyClosed {
318
- return c.resp.Body.Close()
319
- }
320
- return nil
351
+ c.cancel()
352
+ })
353
+ return c.resp.Body.Close()
321
354
  }
322
355
 
323
356
  /* ──────────────────────────── Longpoll adapter ─────────────────────────── */
@@ -346,9 +379,13 @@ func (t *LongpollTransport) Connect(ctx context.Context, rawURL string, opts *Tr
346
379
  client = http.DefaultClient
347
380
  }
348
381
  lp := &longpollConn{
349
- client: client,
350
- url: rawURL,
351
- headers: http.Header{},
382
+ client: client,
383
+ url: rawURL,
384
+ headers: http.Header{},
385
+ pollTimeout: defaultPollTimeout,
386
+ }
387
+ if opts != nil && opts.PollTimeout > 0 {
388
+ lp.pollTimeout = opts.PollTimeout
352
389
  }
353
390
  if opts != nil {
354
391
  lp.reconnectToken = opts.ReconnectToken
@@ -361,6 +398,7 @@ func (t *LongpollTransport) Connect(ctx context.Context, rawURL string, opts *Tr
361
398
  }
362
399
 
363
400
  type longpollConn struct {
401
+ pollTimeout time.Duration
364
402
  client *http.Client
365
403
  url string
366
404
  headers http.Header
@@ -398,7 +436,9 @@ func (c *longpollConn) Recv(ctx context.Context) (any, error) {
398
436
  }
399
437
  u = u + sep + q.Encode()
400
438
  }
401
- req, err := http.NewRequestWithContext(ctx, "GET", u, nil)
439
+ pollCtx, cancel := context.WithTimeout(ctx, c.pollTimeout)
440
+ defer cancel()
441
+ req, err := http.NewRequestWithContext(pollCtx, "GET", u, nil)
402
442
  if err != nil {
403
443
  return nil, err
404
444
  }
@@ -412,13 +452,13 @@ func (c *longpollConn) Recv(ctx context.Context) (any, error) {
412
452
  return nil, err
413
453
  }
414
454
  defer resp.Body.Close()
415
- body, err := io.ReadAll(resp.Body)
416
- if err != nil {
417
- return nil, err
418
- }
419
455
  if resp.StatusCode < 200 || resp.StatusCode >= 300 {
420
456
  return nil, fmt.Errorf("honey: longpoll transport: status %d", resp.StatusCode)
421
457
  }
458
+ body, err := readBody(resp.Body, defaultMaxMessageBytes)
459
+ if err != nil {
460
+ return nil, err
461
+ }
422
462
  var v any
423
463
  if jsonErr := json.Unmarshal(body, &v); jsonErr != nil {
424
464
  v = string(body)
@@ -5,6 +5,7 @@ package sdk
5
5
  import (
6
6
  "context"
7
7
  "encoding/json"
8
+ "errors"
8
9
  "sync"
9
10
 
10
11
  "nhooyr.io/websocket"
@@ -19,31 +20,35 @@ const WSStatusGoingAway = websocket.StatusGoingAway
19
20
  // WSStatusProtocolError is the protocol error close code (1002).
20
21
  const WSStatusProtocolError = websocket.StatusProtocolError
21
22
 
22
- // TypedWebSocket wraps a nhooyr.io/websocket connection with a buffered send
23
- // queue (pre-OPEN) and an event fanout system that mirrors the TS client's .on()
24
- // escape hatch.
25
- //
26
- // Pre-OPEN buffering: sends before the first read are queued in sendBuffer and
27
- // flushed on the first successful read via sync.Once — matches TS client.ws.ts.
23
+ // defaultWSReadLimit replaces nhooyr's 32 KiB default, which closes the
24
+ // connection on any larger frame.
25
+ const defaultWSReadLimit = 16 << 20
26
+
27
+ // TypedWebSocket wraps a nhooyr.io/websocket connection with an event fanout
28
+ // system that mirrors the TS client's .on() escape hatch.
28
29
  type TypedWebSocket struct {
29
- conn *websocket.Conn
30
- sendBuffer []byte
31
- once sync.Once
32
- mu sync.Mutex
33
- handlers map[string][]func(data []byte)
34
- dialOptions websocket.DialOptions
30
+ conn *websocket.Conn
31
+ mu sync.Mutex
32
+ handlers map[string][]func(data []byte)
33
+ closed bool
35
34
  }
36
35
 
37
36
  // newTypedWebSocket constructs a TypedWebSocket from an already-dialled conn.
38
37
  func newTypedWebSocket(conn *websocket.Conn) *TypedWebSocket {
38
+ conn.SetReadLimit(defaultWSReadLimit)
39
39
  return &TypedWebSocket{
40
40
  conn: conn,
41
41
  handlers: make(map[string][]func(data []byte)),
42
42
  }
43
43
  }
44
44
 
45
- // Send serialises data to JSON when it is a struct or map, passes []byte and
46
- // string through as-is. Sends are buffered until the first Read call flushes them.
45
+ // SetReadLimit sets the largest inbound message, in bytes (default 16 MiB).
46
+ func (w *TypedWebSocket) SetReadLimit(n int64) {
47
+ w.conn.SetReadLimit(n)
48
+ }
49
+
50
+ // Send serialises data to JSON when it is a struct or map, and passes []byte
51
+ // (binary frame) and string (text frame) through as-is.
47
52
  func (w *TypedWebSocket) Send(ctx context.Context, data interface{}) error {
48
53
  switch v := data.(type) {
49
54
  case []byte:
@@ -60,28 +65,35 @@ func (w *TypedWebSocket) Send(ctx context.Context, data interface{}) error {
60
65
  }
61
66
 
62
67
  // Close sends a WebSocket close frame with the given status code and reason.
68
+ // A reason over 123 bytes is truncated to fit the frame.
63
69
  func (w *TypedWebSocket) Close(code websocket.StatusCode, reason string) error {
64
- return w.conn.Close(code, reason)
70
+ if len(reason) > 123 {
71
+ reason = reason[:123]
72
+ }
73
+ err := w.conn.Close(code, reason)
74
+ w.fireClose(int(code), reason)
75
+ return err
65
76
  }
66
77
 
67
- // Read reads the next message from the connection.
68
- // On the first call, any pre-OPEN buffered send is flushed via sync.Once.
78
+ // Read reads the next message from the connection. On a close frame it fires
79
+ // "close" handlers (data is the close reason); on any other failure it fires
80
+ // "error" handlers (data is the error text).
69
81
  func (w *TypedWebSocket) Read(ctx context.Context) ([]byte, error) {
70
- w.once.Do(func() {
71
- if len(w.sendBuffer) > 0 {
72
- _ = w.conn.Write(ctx, websocket.MessageText, w.sendBuffer)
73
- w.sendBuffer = nil
74
- }
75
- })
76
82
  _, msg, err := w.conn.Read(ctx)
77
83
  if err != nil {
84
+ var ce websocket.CloseError
85
+ if errors.As(err, &ce) {
86
+ w.fireClose(int(ce.Code), ce.Reason)
87
+ } else {
88
+ w.fanout("error", []byte(err.Error()))
89
+ }
78
90
  return nil, err
79
91
  }
80
92
  w.fanout("message", msg)
81
93
  return msg, nil
82
94
  }
83
95
 
84
- // On registers an event handler. Supported events: "message", "close", "error", "open".
96
+ // On registers an event handler. Supported events: "message", "close", "error".
85
97
  // The handler receives the raw message bytes; callers unmarshal as needed.
86
98
  // This is an escape hatch — prefer ranging over Read for typed message dispatch.
87
99
  func (w *TypedWebSocket) On(event string, handler func(data []byte)) {
@@ -90,9 +102,21 @@ func (w *TypedWebSocket) On(event string, handler func(data []byte)) {
90
102
  w.handlers[event] = append(w.handlers[event], handler)
91
103
  }
92
104
 
105
+ func (w *TypedWebSocket) fireClose(code int, reason string) {
106
+ w.mu.Lock()
107
+ if w.closed {
108
+ w.mu.Unlock()
109
+ return
110
+ }
111
+ w.closed = true
112
+ w.mu.Unlock()
113
+ _ = code
114
+ w.fanout("close", []byte(reason))
115
+ }
116
+
93
117
  func (w *TypedWebSocket) fanout(event string, data []byte) {
94
118
  w.mu.Lock()
95
- handlers := w.handlers[event]
119
+ handlers := append([]func([]byte){}, w.handlers[event]...)
96
120
  w.mu.Unlock()
97
121
  for _, h := range handlers {
98
122
  h(data)
@@ -0,0 +1,79 @@
1
+ import { canonicalIp } from "./ip.ts"
2
+
3
+ /**
4
+ * Who sent a request, and over what, as the core sees it without `app.trustProxy()`: the peer
5
+ * the runtime reports is the client, and forwarding headers are client-controlled text. Trusting
6
+ * reverse proxies (hop counts, CIDR lists) lives in `trust.ts`, which `trustProxy()` loads.
7
+ */
8
+ export type ClientInfo = {
9
+ /** Canonical client address, or `null` when it is unknown or a trusted header holds garbage. */
10
+ ip: string | null
11
+ /** Host the client asked for (`host[:port]`), or `null`. */
12
+ host: string | null
13
+ protocol: "http" | "https"
14
+ }
15
+
16
+ /**
17
+ * The app's compiled `trustProxy()` setting. Anything but `off` carries its own resolver, so
18
+ * the core never imports the hop and range logic.
19
+ */
20
+ export type TrustSetting =
21
+ | { readonly kind: "off" }
22
+ | {
23
+ readonly kind: "hops" | "ranges"
24
+ readonly resolve: (req: Request, peer: string | null) => ClientInfo
25
+ }
26
+
27
+ export const TRUST_OFF: TrustSetting = Object.freeze({ kind: "off" })
28
+
29
+ const HOST = /^(?:\[[0-9A-Fa-f:.]+\]|[A-Za-z0-9](?:[A-Za-z0-9.-]*[A-Za-z0-9])?\.?)(?::\d{1,5})?$/
30
+
31
+ /** `host[:port]` as RFC 9110 allows it in `Host`; nothing that could change a URL's meaning. */
32
+ export function isValidHost(host: string): boolean {
33
+ if (!HOST.test(host)) return false
34
+ const colon = host.lastIndexOf(":")
35
+ if (colon !== -1 && host.lastIndexOf("]") < colon) {
36
+ const port = Number(host.slice(colon + 1))
37
+ if (port > 65535) return false
38
+ }
39
+ return true
40
+ }
41
+
42
+ /**
43
+ * Bun before 1.4 builds `request.url` by concatenating `Host` and the request target, so a
44
+ * `Host: x/admin?` picks the routed path. Later versions hand over the target alone.
45
+ */
46
+ export const BUN_URL_FROM_HOST: boolean = (() => {
47
+ const version = (globalThis as { Bun?: { version?: string } }).Bun?.version
48
+ if (version === undefined) return false
49
+ const [major = 0, minor = 0] = version.split(".").map(Number)
50
+ return major < 1 || (major === 1 && minor < 4)
51
+ })()
52
+
53
+ /** `false` when the request carries a `Host` header that is not `host[:port]`. */
54
+ export function hasValidHost(req: Request): boolean {
55
+ const host = req.headers.get("host")
56
+ return host === null || isValidHost(host)
57
+ }
58
+
59
+ function hostOfUrl(url: string): string | null {
60
+ const start = url.indexOf("//")
61
+ if (start === -1) return null
62
+ let end = url.indexOf("/", start + 2)
63
+ if (end === -1) end = url.length
64
+ const host = url.slice(start + 2, end)
65
+ return host === "" ? null : host
66
+ }
67
+
68
+ /** The client as the connection shows it: the peer, the URL's host, the transport's scheme. */
69
+ export function directClientInfo(req: Request, peer: string | null): ClientInfo {
70
+ return {
71
+ host: hostOfUrl(req.url),
72
+ ip: peer === null ? null : canonicalIp(peer),
73
+ protocol: req.url.startsWith("https:") ? "https" : "http",
74
+ }
75
+ }
76
+
77
+ export function resolveClient(trust: TrustSetting, req: Request, peer: string | null): ClientInfo {
78
+ return trust.kind === "off" ? directClientInfo(req, peer) : trust.resolve(req, peer)
79
+ }