@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
@@ -0,0 +1,155 @@
1
+ from __future__ import annotations
2
+
3
+ import codecs
4
+ from typing import AsyncIterator, Iterable, Iterator, TypedDict
5
+
6
+ import httpx
7
+
8
+
9
+ class SSEEvent(TypedDict, total=False):
10
+ data: str
11
+ event: str
12
+ id: str
13
+ retry: int
14
+
15
+
16
+ DEFAULT_MAX_BUFFER = 1024 * 1024
17
+ MAX_EVENT_DATA = 8 * 1024 * 1024
18
+
19
+
20
+ class SSEParser:
21
+ """WHATWG event-stream parser.
22
+
23
+ Lines end in CRLF, LF or CR only (never U+2028 and friends, which
24
+ ``str.splitlines`` would also split on). A blank line dispatches the event;
25
+ a final event without its blank line is discarded; the id is sticky across
26
+ events; ``retry`` needs ASCII digits. Each chunk is scanned once.
27
+ """
28
+
29
+ def __init__(self, max_line: int = DEFAULT_MAX_BUFFER) -> None:
30
+ self._max_line = max_line
31
+ self._decoder = codecs.getincrementaldecoder("utf-8")("replace")
32
+ self._line: list[str] = []
33
+ self._line_len = 0
34
+ self._pending_cr = False
35
+ self._first = True
36
+ self._data: list[str] = []
37
+ self._data_len = 0
38
+ self._has_data = False
39
+ self._event: str | None = None
40
+ self._last_id: str | None = None
41
+ self._retry: int | None = None
42
+
43
+ def feed(self, chunk: bytes) -> Iterator[SSEEvent]:
44
+ yield from self._feed_text(self._decoder.decode(chunk))
45
+
46
+ def feed_text(self, text: str) -> Iterator[SSEEvent]:
47
+ yield from self._feed_text(text)
48
+
49
+ def _feed_text(self, text: str) -> Iterator[SSEEvent]:
50
+ start = 0
51
+ for i, ch in enumerate(text):
52
+ if i < start or (ch != "\r" and ch != "\n"):
53
+ continue
54
+ if ch == "\n" and self._pending_cr and i == start:
55
+ # LF completing a CRLF split across chunks
56
+ self._pending_cr = False
57
+ start = i + 1
58
+ continue
59
+ self._pending_cr = False
60
+ self._append(text[start:i])
61
+ line = "".join(self._line)
62
+ self._line = []
63
+ self._line_len = 0
64
+ if ch == "\r":
65
+ if i + 1 < len(text):
66
+ if text[i + 1] == "\n":
67
+ start = i + 2
68
+ event = self._process(line)
69
+ if event is not None:
70
+ yield event
71
+ continue
72
+ else:
73
+ self._pending_cr = True
74
+ start = i + 1
75
+ event = self._process(line)
76
+ if event is not None:
77
+ yield event
78
+ if start < len(text):
79
+ self._pending_cr = False
80
+ self._append(text[start:])
81
+
82
+ def _append(self, part: str) -> None:
83
+ if not part:
84
+ return
85
+ self._line_len += len(part)
86
+ if self._line_len > self._max_line:
87
+ raise RuntimeError(f"SSE line exceeded {self._max_line} characters")
88
+ self._line.append(part)
89
+
90
+ def _process(self, line: str) -> SSEEvent | None:
91
+ if self._first:
92
+ self._first = False
93
+ if line.startswith("\ufeff"):
94
+ line = line[1:]
95
+ if line == "":
96
+ return self._dispatch()
97
+ if line.startswith(":"):
98
+ return None
99
+ name, sep, value = line.partition(":")
100
+ if sep and value.startswith(" "):
101
+ value = value[1:]
102
+ if name == "data":
103
+ self._data_len += len(value) + 1
104
+ if self._data_len > MAX_EVENT_DATA:
105
+ raise RuntimeError(f"SSE event exceeded {MAX_EVENT_DATA} characters")
106
+ self._data.append(value)
107
+ self._has_data = True
108
+ elif name == "event":
109
+ self._event = value
110
+ elif name == "id":
111
+ if "\0" not in value:
112
+ self._last_id = value
113
+ elif name == "retry":
114
+ if value and value.isascii() and value.isdigit():
115
+ self._retry = int(value)
116
+ return None
117
+
118
+ def _dispatch(self) -> SSEEvent | None:
119
+ event: SSEEvent | None = None
120
+ if self._has_data:
121
+ event = {"data": "\n".join(self._data)}
122
+ if self._event is not None:
123
+ event["event"] = self._event
124
+ if self._last_id is not None:
125
+ event["id"] = self._last_id
126
+ if self._retry is not None:
127
+ event["retry"] = self._retry
128
+ self._data = []
129
+ self._data_len = 0
130
+ self._has_data = False
131
+ self._event = None
132
+ self._retry = None
133
+ return event
134
+
135
+
136
+ def parse_sse_text(chunks: Iterable[str]) -> list[SSEEvent]:
137
+ """Parse already-decoded text chunks; used by the conformance vectors."""
138
+ parser = SSEParser()
139
+ out: list[SSEEvent] = []
140
+ for chunk in chunks:
141
+ out.extend(parser.feed_text(chunk))
142
+ return out
143
+
144
+
145
+ async def parse_sse_stream(
146
+ response: httpx.Response,
147
+ max_buffer_size: int = DEFAULT_MAX_BUFFER,
148
+ ) -> AsyncIterator[SSEEvent]:
149
+ parser = SSEParser(max_buffer_size)
150
+ async for chunk in response.aiter_bytes():
151
+ for event in parser.feed(chunk):
152
+ yield event
153
+
154
+
155
+ __all__ = ["SSEEvent", "SSEParser", "parse_sse_stream", "parse_sse_text"]
@@ -0,0 +1,366 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import uuid
5
+ from dataclasses import dataclass, field
6
+ from enum import Enum
7
+ from typing import Any, Protocol, cast, runtime_checkable
8
+ from urllib.parse import urlencode
9
+
10
+ try:
11
+ import websockets
12
+ except ImportError:
13
+ websockets = None # type: ignore[assignment]
14
+
15
+ try:
16
+ import httpx
17
+ except ImportError:
18
+ httpx = None # type: ignore[assignment]
19
+
20
+ from ._sse import parse_sse_stream
21
+
22
+
23
+ class TransportKind(str, Enum):
24
+ WS = "ws"
25
+ SSE = "sse"
26
+ LONGPOLL = "longpoll"
27
+
28
+
29
+ @dataclass
30
+ class TransportOpts:
31
+ """Options for each transport connect.
32
+
33
+ ``max_reconnect_attempts`` caps consecutive failed reconnects (0 or less:
34
+ unlimited); ``reconnect_delay_ms`` is the first backoff delay. ``headers``
35
+ are sent on every transport (the generated SDK fills in config headers and
36
+ auth). ``max_message_bytes`` caps one WebSocket message.
37
+ """
38
+
39
+ reconnect_token: str | None = None
40
+ last_event_id: str | None = None
41
+ headers: dict[str, str] | None = None
42
+ max_reconnect_attempts: int = 5
43
+ reconnect_delay_ms: int = 1000
44
+ protocols: list[str] | None = None
45
+ max_message_bytes: int = 16 * 1024 * 1024
46
+
47
+
48
+ @runtime_checkable
49
+ class TransportConn(Protocol):
50
+ async def recv(self) -> Any: ...
51
+ async def send(self, data: Any) -> None: ...
52
+ async def close(self) -> None: ...
53
+ def kind(self) -> TransportKind: ...
54
+
55
+
56
+ @runtime_checkable
57
+ class TransportAdapter(Protocol):
58
+ def name(self) -> str: ...
59
+ def kind(self) -> TransportKind: ...
60
+ async def connect(self, url: str, opts: TransportOpts) -> TransportConn: ...
61
+
62
+
63
+ class _StubConn:
64
+ """Shared stub retained from 8.b.2 for backward compat.
65
+
66
+ Real wire conns below (_WsConn/_SseConn/_LongpollConn) supersede it
67
+ inside the default adapters. Still importable for consumer-authored
68
+ tests that stub before the real impls landed.
69
+ """
70
+
71
+ def __init__(self, kind: TransportKind) -> None:
72
+ self._kind = kind
73
+
74
+ async def recv(self) -> Any:
75
+ raise NotImplementedError(
76
+ "_StubConn.recv is a placeholder; use WsAdapter/SseAdapter/LongpollAdapter",
77
+ )
78
+
79
+ async def send(self, data: Any) -> None:
80
+ raise NotImplementedError(
81
+ "_StubConn.send is a placeholder; use WsAdapter/SseAdapter/LongpollAdapter",
82
+ )
83
+
84
+ async def close(self) -> None:
85
+ return None
86
+
87
+ def kind(self) -> TransportKind:
88
+ return self._kind
89
+
90
+
91
+ def _to_ws_url(url: str) -> str:
92
+ if url.startswith("https://"):
93
+ return "wss://" + url[len("https://") :]
94
+ if url.startswith("http://"):
95
+ return "ws://" + url[len("http://") :]
96
+ return url
97
+
98
+
99
+ class _WsConn:
100
+ def __init__(self, conn: Any) -> None:
101
+ self._conn = conn
102
+
103
+ async def recv(self) -> Any:
104
+ msg = await self._conn.recv()
105
+ if isinstance(msg, (bytes, bytearray)):
106
+ msg = msg.decode("utf-8")
107
+ try:
108
+ return json.loads(msg)
109
+ except (ValueError, TypeError):
110
+ return msg
111
+
112
+ async def send(self, data: Any) -> None:
113
+ if isinstance(data, (str, bytes, bytearray)):
114
+ payload: Any = data
115
+ else:
116
+ payload = json.dumps(data)
117
+ await self._conn.send(payload)
118
+
119
+ async def close(self) -> None:
120
+ try:
121
+ await self._conn.close()
122
+ except Exception:
123
+ """ swallow — close must never raise """
124
+ pass
125
+
126
+ def kind(self) -> TransportKind:
127
+ return TransportKind.WS
128
+
129
+
130
+ @dataclass
131
+ class WsAdapter:
132
+ """Default WebSocket adapter using `websockets.connect`."""
133
+
134
+ subprotocols: list[str] = field(default_factory=list)
135
+
136
+ def name(self) -> str:
137
+ return "ws"
138
+
139
+ def kind(self) -> TransportKind:
140
+ return TransportKind.WS
141
+
142
+ async def connect(self, url: str, opts: TransportOpts) -> TransportConn:
143
+ if websockets is None:
144
+ raise RuntimeError(
145
+ "pip install websockets to use the default WsAdapter",
146
+ )
147
+ ws_url = _to_ws_url(url)
148
+ query: dict[str, str] = {}
149
+ if opts.reconnect_token is not None:
150
+ query["reconnect_token"] = opts.reconnect_token
151
+ if opts.last_event_id is not None:
152
+ query["last_event_id"] = opts.last_event_id
153
+ if query:
154
+ sep = "&" if "?" in ws_url else "?"
155
+ ws_url = f"{ws_url}{sep}{urlencode(query)}"
156
+ subprotocols = opts.protocols or (self.subprotocols or None)
157
+ headers = opts.headers or None
158
+ conn = await websockets.connect(
159
+ ws_url,
160
+ subprotocols=cast(Any, subprotocols),
161
+ additional_headers=headers,
162
+ max_size=opts.max_message_bytes,
163
+ )
164
+ return _WsConn(conn)
165
+
166
+
167
+ class _SseConn:
168
+ def __init__(
169
+ self,
170
+ client: Any,
171
+ owns_client: bool,
172
+ ctx: Any,
173
+ response: Any,
174
+ ) -> None:
175
+ self._client = client
176
+ self._owns_client = owns_client
177
+ self._ctx = ctx
178
+ self._response = response
179
+ self._iter = parse_sse_stream(response)
180
+
181
+ async def recv(self) -> Any:
182
+ event = await self._iter.__anext__()
183
+ data = event.get("data")
184
+ if data is None:
185
+ return event
186
+ try:
187
+ return json.loads(data)
188
+ except (ValueError, TypeError):
189
+ return data
190
+
191
+ async def send(self, data: Any) -> None:
192
+ raise RuntimeError("SSE transport is receive-only")
193
+
194
+ async def close(self) -> None:
195
+ try:
196
+ await self._ctx.__aexit__(None, None, None)
197
+ except Exception:
198
+ pass
199
+ if self._owns_client:
200
+ try:
201
+ await self._client.aclose()
202
+ except Exception:
203
+ pass
204
+
205
+ def kind(self) -> TransportKind:
206
+ return TransportKind.SSE
207
+
208
+
209
+ @dataclass
210
+ class SseAdapter:
211
+ """Default SSE adapter using `httpx.AsyncClient.stream`."""
212
+
213
+ http_client: Any | None = None
214
+
215
+ def name(self) -> str:
216
+ return "sse"
217
+
218
+ def kind(self) -> TransportKind:
219
+ return TransportKind.SSE
220
+
221
+ async def connect(self, url: str, opts: TransportOpts) -> TransportConn:
222
+ if httpx is None:
223
+ raise RuntimeError(
224
+ "pip install httpx to use the default SseAdapter",
225
+ )
226
+ params: dict[str, str] = {}
227
+ if opts.reconnect_token is not None:
228
+ params["reconnect_token"] = opts.reconnect_token
229
+ headers = dict(opts.headers or {})
230
+ headers.setdefault("Accept", "text/event-stream")
231
+ if opts.last_event_id is not None:
232
+ headers["Last-Event-ID"] = opts.last_event_id
233
+ if not any(k.lower() == "x-request-id" for k in headers):
234
+ headers["x-request-id"] = str(uuid.uuid4())
235
+ client = self.http_client or httpx.AsyncClient()
236
+ owns_client = self.http_client is None
237
+ # a stream may idle between events: no read timeout
238
+ ctx = client.stream(
239
+ "GET",
240
+ url,
241
+ params=params or None,
242
+ headers=headers,
243
+ timeout=httpx.Timeout(30.0, read=None),
244
+ )
245
+ try:
246
+ response = await ctx.__aenter__()
247
+ except BaseException:
248
+ if owns_client:
249
+ await client.aclose()
250
+ raise
251
+ try:
252
+ response.raise_for_status()
253
+ except BaseException:
254
+ await ctx.__aexit__(None, None, None)
255
+ if owns_client:
256
+ await client.aclose()
257
+ raise
258
+ return _SseConn(
259
+ client=client,
260
+ owns_client=owns_client,
261
+ ctx=ctx,
262
+ response=response,
263
+ )
264
+
265
+
266
+ class _LongpollConn:
267
+ def __init__(
268
+ self,
269
+ client: Any,
270
+ owns_client: bool,
271
+ url: str,
272
+ headers: dict[str, str],
273
+ reconnect_token: str | None,
274
+ last_event_id: str | None,
275
+ ) -> None:
276
+ self._client = client
277
+ self._owns_client = owns_client
278
+ self._url = url
279
+ self._headers = headers
280
+ self._reconnect_token = reconnect_token
281
+ self._last_event_id = last_event_id
282
+ self._closed = False
283
+
284
+ async def recv(self) -> Any:
285
+ if self._closed:
286
+ raise RuntimeError("longpoll connection closed")
287
+ params: dict[str, str] = {}
288
+ if self._reconnect_token is not None:
289
+ params["reconnect_token"] = self._reconnect_token
290
+ if self._last_event_id is not None:
291
+ params["last_event_id"] = self._last_event_id
292
+ resp = await self._client.get(
293
+ self._url,
294
+ headers=self._headers or None,
295
+ params=params or None,
296
+ )
297
+ resp.raise_for_status()
298
+ payload: Any
299
+ try:
300
+ payload = resp.json()
301
+ except Exception:
302
+ payload = resp.text
303
+ if isinstance(payload, dict):
304
+ new_token = payload.get("reconnect_token")
305
+ if isinstance(new_token, str):
306
+ self._reconnect_token = new_token
307
+ new_id = payload.get("id") or payload.get("last_event_id")
308
+ if isinstance(new_id, (str, int)):
309
+ self._last_event_id = str(new_id)
310
+ return payload
311
+
312
+ async def send(self, data: Any) -> None:
313
+ raise RuntimeError("longpoll transport is receive-only")
314
+
315
+ async def close(self) -> None:
316
+ self._closed = True
317
+ if self._owns_client:
318
+ try:
319
+ await self._client.aclose()
320
+ except Exception:
321
+ pass
322
+
323
+ def kind(self) -> TransportKind:
324
+ return TransportKind.LONGPOLL
325
+
326
+
327
+ @dataclass
328
+ class LongpollAdapter:
329
+ """Default long-poll adapter using repeated `httpx.AsyncClient.get`."""
330
+
331
+ http_client: Any | None = None
332
+ poll_timeout: float = 30.0
333
+
334
+ def name(self) -> str:
335
+ return "longpoll"
336
+
337
+ def kind(self) -> TransportKind:
338
+ return TransportKind.LONGPOLL
339
+
340
+ async def connect(self, url: str, opts: TransportOpts) -> TransportConn:
341
+ if httpx is None:
342
+ raise RuntimeError(
343
+ "pip install httpx to use the default LongpollAdapter",
344
+ )
345
+ client = self.http_client or httpx.AsyncClient(timeout=self.poll_timeout)
346
+ owns_client = self.http_client is None
347
+ return _LongpollConn(
348
+ client=client,
349
+ owns_client=owns_client,
350
+ url=url,
351
+ headers=dict(opts.headers or {}),
352
+ reconnect_token=opts.reconnect_token,
353
+ last_event_id=opts.last_event_id,
354
+ )
355
+
356
+
357
+ __all__ = [
358
+ "LongpollAdapter",
359
+ "SseAdapter",
360
+ "TransportAdapter",
361
+ "TransportConn",
362
+ "TransportKind",
363
+ "TransportOpts",
364
+ "WsAdapter",
365
+ "_StubConn",
366
+ ]
@@ -0,0 +1,159 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from typing import Any, AsyncIterator, Callable, cast
5
+
6
+ try:
7
+ import websockets
8
+ except ImportError:
9
+ websockets = None # type: ignore[assignment]
10
+
11
+ _VALID_EVENTS = frozenset({"open", "close", "error", "message"})
12
+
13
+
14
+ class _TypedWebSocket:
15
+ """Async context-manager wrapping a websockets connection.
16
+
17
+ Parity notes (Phase 10 WS audit):
18
+ - Remote close code + reason surfaced via close_code / close_reason after
19
+ __aexit__ or after the iterator terminates; also passed to "close"
20
+ handlers registered via .on().
21
+ - Auth handshake: caller passes query-string params (e.g. ?token=) to the
22
+ emitted method; server rejects via close frame which this class fires
23
+ as a "close" event plus sets close_code.
24
+ """
25
+
26
+ def __init__(
27
+ self,
28
+ url: str,
29
+ protocols: list[str] | None = None,
30
+ extra_headers: dict[str, str] | None = None,
31
+ ) -> None:
32
+ if websockets is None:
33
+ raise ImportError("pip install honey-sdk[ws] to use WebSocket methods")
34
+ self._url = url
35
+ self._protocols = protocols or []
36
+ self._extra_headers = extra_headers or {}
37
+ self._conn: Any = None
38
+ self._handlers: dict[str, list[Callable[..., Any]]] = {
39
+ "open": [],
40
+ "close": [],
41
+ "error": [],
42
+ "message": [],
43
+ }
44
+ self.close_code: int | None = None
45
+ self.close_reason: str | None = None
46
+ self._close_fired = False
47
+
48
+ async def __aenter__(self) -> _TypedWebSocket:
49
+ if websockets is None:
50
+ raise ImportError("pip install honey-sdk[ws] to use WebSocket methods")
51
+ self._conn = await _connect(self._url, self._protocols, self._extra_headers)
52
+ for handler in self._handlers["open"]:
53
+ try:
54
+ handler()
55
+ except Exception:
56
+ pass
57
+ return self
58
+
59
+ async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
60
+ if self._conn is not None:
61
+ try:
62
+ await self._conn.close()
63
+ except Exception:
64
+ pass
65
+ self._capture_close()
66
+ self._fire_close(
67
+ self.close_code if self.close_code is not None else 1000,
68
+ self.close_reason if self.close_reason is not None else "",
69
+ )
70
+
71
+ def __aiter__(self) -> AsyncIterator[str | bytes]:
72
+ return self._iter_messages()
73
+
74
+ async def _iter_messages(self) -> AsyncIterator[str | bytes]:
75
+ try:
76
+ async for msg in self._conn:
77
+ for handler in self._handlers["message"]:
78
+ try:
79
+ handler(msg)
80
+ except Exception:
81
+ pass
82
+ yield msg
83
+ except Exception as exc:
84
+ closed_ok = websockets is not None and isinstance(
85
+ exc, getattr(websockets.exceptions, "ConnectionClosedOK", ())
86
+ )
87
+ if not closed_ok:
88
+ for handler in self._handlers["error"]:
89
+ try:
90
+ handler(exc)
91
+ except Exception:
92
+ pass
93
+ raise
94
+ finally:
95
+ self._capture_close()
96
+ if self.close_code is not None:
97
+ self._fire_close(self.close_code, self.close_reason or "")
98
+
99
+ def _fire_close(self, code: int, reason: str) -> None:
100
+ if self._close_fired:
101
+ return
102
+ self._close_fired = True
103
+ for handler in self._handlers["close"]:
104
+ try:
105
+ handler(code, reason)
106
+ except Exception:
107
+ pass
108
+
109
+ def _capture_close(self) -> None:
110
+ """Read close code/reason from the underlying websockets.Connection once
111
+ the peer sends a Close frame. websockets exposes these as attributes on
112
+ the connection object after the receive loop sees Close."""
113
+ if self._conn is None:
114
+ return
115
+ code = getattr(self._conn, "close_code", None)
116
+ reason = getattr(self._conn, "close_reason", None)
117
+ if code is not None and self.close_code is None:
118
+ self.close_code = int(code)
119
+ if reason is not None and self.close_reason is None:
120
+ self.close_reason = str(reason)
121
+
122
+ def on(self, event: str, callback: Callable[..., Any]) -> None:
123
+ """Register a callback for open, close, error, or message events."""
124
+ if event not in _VALID_EVENTS:
125
+ raise ValueError(
126
+ f"event must be one of {sorted(_VALID_EVENTS)}, got {event!r}",
127
+ )
128
+ self._handlers[event].append(callback)
129
+
130
+ async def send(self, data: Any) -> None:
131
+ """Send str/bytes as-is; anything else (dict, list, numbers) as JSON text."""
132
+ if not isinstance(data, (str, bytes, bytearray)):
133
+ data = json.dumps(data)
134
+ await self._conn.send(data)
135
+
136
+ async def close(self, code: int = 1000, reason: str = "") -> None:
137
+ if self._conn is not None:
138
+ await self._conn.close(code, reason)
139
+
140
+
141
+ async def _connect(url: str, protocols: list[str], headers: dict[str, str]) -> Any:
142
+ """websockets >= 14 takes ``additional_headers``; older releases take
143
+ ``extra_headers``."""
144
+ assert websockets is not None
145
+ try:
146
+ return await websockets.connect(
147
+ url,
148
+ subprotocols=cast(Any, protocols or None),
149
+ additional_headers=headers or None,
150
+ )
151
+ except TypeError:
152
+ return await websockets.connect(
153
+ url,
154
+ subprotocols=cast(Any, protocols or None),
155
+ extra_headers=headers or None,
156
+ )
157
+
158
+
159
+ __all__ = ["_TypedWebSocket"]
File without changes