@lovrozagar/honey 0.6.8 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (674) hide show
  1. package/README.md +514 -192
  2. package/bin/honey.js +25 -0
  3. package/dist/accepts.d.ts +7 -1
  4. package/dist/accepts.d.ts.map +1 -1
  5. package/dist/accepts.js +126 -0
  6. package/dist/accepts.js.map +1 -0
  7. package/dist/body-kind.d.ts +26 -0
  8. package/dist/body-kind.d.ts.map +1 -0
  9. package/dist/body-kind.js +70 -0
  10. package/dist/body-kind.js.map +1 -0
  11. package/dist/body-limit.d.ts +5 -1
  12. package/dist/body-limit.d.ts.map +1 -1
  13. package/dist/body-limit.js +126 -0
  14. package/dist/body-limit.js.map +1 -0
  15. package/dist/build/index.d.ts +19 -3
  16. package/dist/build/index.d.ts.map +1 -1
  17. package/dist/build/index.js +173 -0
  18. package/dist/build/index.js.map +1 -0
  19. package/dist/cli-args.d.ts +33 -0
  20. package/dist/cli-args.d.ts.map +1 -0
  21. package/dist/cli-args.js +102 -0
  22. package/dist/cli-args.js.map +1 -0
  23. package/dist/cli-go/auth.go +26 -0
  24. package/dist/cli-go/config.go +192 -0
  25. package/dist/cli-go/errors.go +75 -0
  26. package/dist/cli-go/multipart.go +79 -0
  27. package/dist/cli-go/output.go +163 -0
  28. package/dist/cli-go/root.go +30 -0
  29. package/dist/cli-go/stream.go +88 -0
  30. package/dist/cli-go/version.go +5 -0
  31. package/dist/cli.d.ts +1 -1
  32. package/dist/cli.js +209 -0
  33. package/dist/cli.js.map +1 -0
  34. package/dist/client/defaults.js +48 -0
  35. package/dist/client/defaults.js.map +1 -0
  36. package/dist/client/error.d.ts +35 -0
  37. package/dist/client/error.d.ts.map +1 -1
  38. package/dist/client/error.js +71 -0
  39. package/dist/client/error.js.map +1 -0
  40. package/dist/client/http.d.ts +67 -8
  41. package/dist/client/http.d.ts.map +1 -1
  42. package/dist/client/http.js +571 -0
  43. package/dist/client/http.js.map +1 -0
  44. package/dist/client/index.d.ts +3 -2
  45. package/dist/client/index.d.ts.map +1 -1
  46. package/dist/client/index.js +95 -0
  47. package/dist/client/index.js.map +1 -0
  48. package/dist/client/path.d.ts +26 -0
  49. package/dist/client/path.d.ts.map +1 -0
  50. package/dist/client/path.js +163 -0
  51. package/dist/client/path.js.map +1 -0
  52. package/dist/client/redirect-policy.d.ts +12 -0
  53. package/dist/client/redirect-policy.d.ts.map +1 -0
  54. package/dist/client/redirect-policy.js +20 -0
  55. package/dist/client/redirect-policy.js.map +1 -0
  56. package/dist/client/sdk.d.ts +36 -0
  57. package/dist/client/sdk.d.ts.map +1 -1
  58. package/dist/client/sdk.js +292 -0
  59. package/dist/client/sdk.js.map +1 -0
  60. package/dist/client/sse.d.ts +13 -0
  61. package/dist/client/sse.d.ts.map +1 -1
  62. package/dist/client/sse.js +129 -0
  63. package/dist/client/sse.js.map +1 -0
  64. package/dist/client/types.js +2 -0
  65. package/dist/client/types.js.map +1 -0
  66. package/dist/client/ws.d.ts +9 -2
  67. package/dist/client/ws.d.ts.map +1 -1
  68. package/dist/client/ws.js +112 -0
  69. package/dist/client/ws.js.map +1 -0
  70. package/dist/client-go/errors.go +236 -0
  71. package/dist/client-go/export.go +44 -0
  72. package/dist/client-go/invalidation.go +371 -0
  73. package/dist/client-go/nullable.go +62 -0
  74. package/dist/client-go/realtime.go +354 -0
  75. package/dist/client-go/result.go +20 -0
  76. package/dist/client-go/runtime.go +975 -0
  77. package/dist/client-go/sse.go +159 -0
  78. package/dist/client-go/transport.go +495 -0
  79. package/dist/client-go/ws.go +128 -0
  80. package/dist/client-info.d.ts +36 -0
  81. package/dist/client-info.d.ts.map +1 -0
  82. package/dist/client-info.js +53 -0
  83. package/dist/client-info.js.map +1 -0
  84. package/dist/client-mcp/README.md +10 -0
  85. package/dist/client-mcp/server.ts +221 -0
  86. package/dist/client-mcp/types.ts +19 -0
  87. package/dist/client-python/_errors.py +115 -0
  88. package/dist/client-python/_invalidation.py +494 -0
  89. package/dist/client-python/_realtime.py +179 -0
  90. package/dist/client-python/_runtime.py +860 -0
  91. package/dist/client-python/_sse.py +155 -0
  92. package/dist/client-python/_transport.py +366 -0
  93. package/dist/client-python/_ws.py +159 -0
  94. package/dist/client-python/py.typed +0 -0
  95. package/dist/client-rust/errors.rs +220 -0
  96. package/dist/client-rust/invalidation.rs +412 -0
  97. package/dist/client-rust/invalidation_sync.rs +93 -0
  98. package/dist/client-rust/nullable.rs +17 -0
  99. package/dist/client-rust/realtime.rs +702 -0
  100. package/dist/client-rust/result.rs +22 -0
  101. package/dist/client-rust/runtime.rs +980 -0
  102. package/dist/client-rust/runtime_sync.rs +484 -0
  103. package/dist/client-rust/sse.rs +188 -0
  104. package/dist/client-rust/ws.rs +167 -0
  105. package/dist/codegen-go-cli.d.ts.map +1 -1
  106. package/dist/codegen-go-cli.js +964 -0
  107. package/dist/codegen-go-cli.js.map +1 -0
  108. package/dist/codegen-go.d.ts +15 -3
  109. package/dist/codegen-go.d.ts.map +1 -1
  110. package/dist/codegen-go.js +872 -0
  111. package/dist/codegen-go.js.map +1 -0
  112. package/dist/codegen-hash.js +9 -0
  113. package/dist/codegen-hash.js.map +1 -0
  114. package/dist/codegen-ir.d.ts +69 -2
  115. package/dist/codegen-ir.d.ts.map +1 -1
  116. package/dist/codegen-ir.js +661 -0
  117. package/dist/codegen-ir.js.map +1 -0
  118. package/dist/codegen-lang.d.ts +65 -0
  119. package/dist/codegen-lang.d.ts.map +1 -0
  120. package/dist/codegen-lang.js +526 -0
  121. package/dist/codegen-lang.js.map +1 -0
  122. package/dist/codegen-load.d.ts +31 -0
  123. package/dist/codegen-load.d.ts.map +1 -0
  124. package/dist/codegen-load.js +138 -0
  125. package/dist/codegen-load.js.map +1 -0
  126. package/dist/codegen-loaders.js +55 -0
  127. package/dist/codegen-loaders.js.map +1 -0
  128. package/dist/codegen-mcp.d.ts.map +1 -1
  129. package/dist/codegen-mcp.js +368 -0
  130. package/dist/codegen-mcp.js.map +1 -0
  131. package/dist/codegen-python.d.ts +13 -1
  132. package/dist/codegen-python.d.ts.map +1 -1
  133. package/dist/codegen-python.js +828 -0
  134. package/dist/codegen-python.js.map +1 -0
  135. package/dist/codegen-route-tree-intern.d.ts +15 -5
  136. package/dist/codegen-route-tree-intern.d.ts.map +1 -1
  137. package/dist/codegen-route-tree-intern.js +221 -0
  138. package/dist/codegen-route-tree-intern.js.map +1 -0
  139. package/dist/codegen-rust.d.ts.map +1 -1
  140. package/dist/codegen-rust.js +1293 -0
  141. package/dist/codegen-rust.js.map +1 -0
  142. package/dist/codegen-sanitize.d.ts.map +1 -1
  143. package/dist/codegen-sanitize.js +56 -0
  144. package/dist/codegen-sanitize.js.map +1 -0
  145. package/dist/codegen-schema-naming.d.ts +5 -0
  146. package/dist/codegen-schema-naming.d.ts.map +1 -1
  147. package/dist/codegen-schema-naming.js +150 -0
  148. package/dist/codegen-schema-naming.js.map +1 -0
  149. package/dist/codegen-sdk-model.d.ts +71 -0
  150. package/dist/codegen-sdk-model.d.ts.map +1 -0
  151. package/dist/codegen-sdk-model.js +179 -0
  152. package/dist/codegen-sdk-model.js.map +1 -0
  153. package/dist/codegen.d.ts +41 -23
  154. package/dist/codegen.d.ts.map +1 -1
  155. package/dist/codegen.js +4610 -0
  156. package/dist/codegen.js.map +1 -0
  157. package/dist/context.d.ts +36 -6
  158. package/dist/context.d.ts.map +1 -1
  159. package/dist/context.js +242 -0
  160. package/dist/context.js.map +1 -0
  161. package/dist/cookie-sign.d.ts +16 -2
  162. package/dist/cookie-sign.d.ts.map +1 -1
  163. package/dist/cookie-sign.js +104 -0
  164. package/dist/cookie-sign.js.map +1 -0
  165. package/dist/cookie.d.ts +12 -0
  166. package/dist/cookie.d.ts.map +1 -1
  167. package/dist/cookie.js +138 -0
  168. package/dist/cookie.js.map +1 -0
  169. package/dist/cors.d.ts +1 -0
  170. package/dist/cors.d.ts.map +1 -1
  171. package/dist/cors.js +87 -0
  172. package/dist/cors.js.map +1 -0
  173. package/dist/crypto.d.ts +6 -1
  174. package/dist/crypto.d.ts.map +1 -1
  175. package/dist/crypto.js +38 -0
  176. package/dist/crypto.js.map +1 -0
  177. package/dist/csrf.d.ts +19 -0
  178. package/dist/csrf.d.ts.map +1 -1
  179. package/dist/csrf.js +79 -0
  180. package/dist/csrf.js.map +1 -0
  181. package/dist/curl-logger.d.ts +14 -3
  182. package/dist/curl-logger.d.ts.map +1 -1
  183. package/dist/curl-logger.js +199 -0
  184. package/dist/curl-logger.js.map +1 -0
  185. package/dist/detect-runtime.js +13 -0
  186. package/dist/detect-runtime.js.map +1 -0
  187. package/dist/dict.d.ts +11 -0
  188. package/dist/dict.d.ts.map +1 -0
  189. package/dist/dict.js +13 -0
  190. package/dist/dict.js.map +1 -0
  191. package/dist/error.d.ts.map +1 -1
  192. package/dist/error.js +44 -0
  193. package/dist/error.js.map +1 -0
  194. package/dist/errors.js +39 -0
  195. package/dist/errors.js.map +1 -0
  196. package/dist/etag.d.ts +2 -0
  197. package/dist/etag.d.ts.map +1 -1
  198. package/dist/etag.js +82 -0
  199. package/dist/etag.js.map +1 -0
  200. package/dist/feature-detect.d.ts +25 -0
  201. package/dist/feature-detect.d.ts.map +1 -0
  202. package/dist/feature-detect.js +144 -0
  203. package/dist/feature-detect.js.map +1 -0
  204. package/dist/feature-load.js +36 -0
  205. package/dist/feature-load.js.map +1 -0
  206. package/dist/feature-slots.d.ts +44 -0
  207. package/dist/feature-slots.d.ts.map +1 -0
  208. package/dist/feature-slots.js +48 -0
  209. package/dist/feature-slots.js.map +1 -0
  210. package/dist/fetch-request.d.ts +10 -0
  211. package/dist/fetch-request.d.ts.map +1 -0
  212. package/dist/fetch-request.js +13 -0
  213. package/dist/fetch-request.js.map +1 -0
  214. package/dist/gen-process.d.ts +15 -0
  215. package/dist/gen-process.d.ts.map +1 -0
  216. package/dist/gen-process.js +43 -0
  217. package/dist/gen-process.js.map +1 -0
  218. package/dist/gen-write.d.ts +19 -0
  219. package/dist/gen-write.d.ts.map +1 -0
  220. package/dist/gen-write.js +120 -0
  221. package/dist/gen-write.js.map +1 -0
  222. package/dist/glob.d.ts +21 -0
  223. package/dist/glob.d.ts.map +1 -0
  224. package/dist/glob.js +115 -0
  225. package/dist/glob.js.map +1 -0
  226. package/dist/go-type-emitter.d.ts +18 -4
  227. package/dist/go-type-emitter.d.ts.map +1 -1
  228. package/dist/go-type-emitter.js +594 -0
  229. package/dist/go-type-emitter.js.map +1 -0
  230. package/dist/honey-response.d.ts.map +1 -1
  231. package/dist/honey-response.js +338 -0
  232. package/dist/honey-response.js.map +1 -0
  233. package/dist/i18n-slot.d.ts +8 -0
  234. package/dist/i18n-slot.d.ts.map +1 -1
  235. package/dist/i18n-slot.js +14 -0
  236. package/dist/i18n-slot.js.map +1 -0
  237. package/dist/i18n.d.ts +3 -0
  238. package/dist/i18n.d.ts.map +1 -1
  239. package/dist/i18n.js +250 -0
  240. package/dist/i18n.js.map +1 -0
  241. package/dist/index.d.ts +408 -148
  242. package/dist/index.d.ts.map +1 -1
  243. package/dist/index.js +2324 -0
  244. package/dist/index.js.map +1 -0
  245. package/dist/init.d.ts +3 -5
  246. package/dist/init.d.ts.map +1 -1
  247. package/dist/init.js +140 -0
  248. package/dist/init.js.map +1 -0
  249. package/dist/input.js +4 -0
  250. package/dist/input.js.map +1 -0
  251. package/dist/invalidate-check.d.ts +11 -0
  252. package/dist/invalidate-check.d.ts.map +1 -1
  253. package/dist/invalidate-check.js +163 -0
  254. package/dist/invalidate-check.js.map +1 -0
  255. package/dist/invoke-user.d.ts +35 -0
  256. package/dist/invoke-user.d.ts.map +1 -0
  257. package/dist/invoke-user.js +73 -0
  258. package/dist/invoke-user.js.map +1 -0
  259. package/dist/ip-restrict.d.ts +13 -1
  260. package/dist/ip-restrict.d.ts.map +1 -1
  261. package/dist/ip-restrict.js +60 -0
  262. package/dist/ip-restrict.js.map +1 -0
  263. package/dist/ip.d.ts +39 -0
  264. package/dist/ip.d.ts.map +1 -0
  265. package/dist/ip.js +209 -0
  266. package/dist/ip.js.map +1 -0
  267. package/dist/logger.d.ts.map +1 -1
  268. package/dist/logger.js +113 -0
  269. package/dist/logger.js.map +1 -0
  270. package/dist/media-type.d.ts +30 -0
  271. package/dist/media-type.d.ts.map +1 -0
  272. package/dist/media-type.js +97 -0
  273. package/dist/media-type.js.map +1 -0
  274. package/dist/meta-spec-merge.d.ts +32 -0
  275. package/dist/meta-spec-merge.d.ts.map +1 -0
  276. package/dist/meta-spec-merge.js +68 -0
  277. package/dist/meta-spec-merge.js.map +1 -0
  278. package/dist/meta-spec.d.ts +16 -3
  279. package/dist/meta-spec.d.ts.map +1 -1
  280. package/dist/meta-spec.js +535 -0
  281. package/dist/meta-spec.js.map +1 -0
  282. package/dist/middleware.d.ts +23 -6
  283. package/dist/middleware.d.ts.map +1 -1
  284. package/dist/middleware.js +253 -0
  285. package/dist/middleware.js.map +1 -0
  286. package/dist/node-request.d.ts +57 -12
  287. package/dist/node-request.d.ts.map +1 -1
  288. package/dist/node-request.js +407 -0
  289. package/dist/node-request.js.map +1 -0
  290. package/dist/node.d.ts +20 -3
  291. package/dist/node.d.ts.map +1 -1
  292. package/dist/node.js +396 -0
  293. package/dist/node.js.map +1 -0
  294. package/dist/openapi/collect.d.ts +6 -3
  295. package/dist/openapi/collect.d.ts.map +1 -1
  296. package/dist/openapi/collect.js +30 -0
  297. package/dist/openapi/collect.js.map +1 -0
  298. package/dist/openapi/docs-page.d.ts +42 -0
  299. package/dist/openapi/docs-page.d.ts.map +1 -0
  300. package/dist/openapi/docs-page.js +80 -0
  301. package/dist/openapi/docs-page.js.map +1 -0
  302. package/dist/openapi/document.d.ts +4 -0
  303. package/dist/openapi/document.d.ts.map +1 -1
  304. package/dist/openapi/document.js +785 -0
  305. package/dist/openapi/document.js.map +1 -0
  306. package/dist/openapi/json-schema-slot.d.ts +7 -0
  307. package/dist/openapi/json-schema-slot.d.ts.map +1 -1
  308. package/dist/openapi/json-schema-slot.js +38 -0
  309. package/dist/openapi/json-schema-slot.js.map +1 -0
  310. package/dist/openapi/register.d.ts.map +1 -1
  311. package/dist/openapi/register.js +20 -0
  312. package/dist/openapi/register.js.map +1 -0
  313. package/dist/openapi/scalar.d.ts +3 -1
  314. package/dist/openapi/scalar.d.ts.map +1 -1
  315. package/dist/openapi/scalar.js +21 -0
  316. package/dist/openapi/scalar.js.map +1 -0
  317. package/dist/openapi/serve.d.ts +9 -0
  318. package/dist/openapi/serve.d.ts.map +1 -0
  319. package/dist/openapi/serve.js +36 -0
  320. package/dist/openapi/serve.js.map +1 -0
  321. package/dist/openapi/spec-factory.d.ts +30 -1
  322. package/dist/openapi/spec-factory.d.ts.map +1 -1
  323. package/dist/openapi/spec-factory.js +52 -0
  324. package/dist/openapi/spec-factory.js.map +1 -0
  325. package/dist/openapi/spec.d.ts +14 -5
  326. package/dist/openapi/spec.d.ts.map +1 -1
  327. package/dist/openapi/spec.js +50 -0
  328. package/dist/openapi/spec.js.map +1 -0
  329. package/dist/openapi/swagger.d.ts +3 -1
  330. package/dist/openapi/swagger.d.ts.map +1 -1
  331. package/dist/openapi/swagger.js +22 -0
  332. package/dist/openapi/swagger.js.map +1 -0
  333. package/dist/pattern.d.ts +71 -0
  334. package/dist/pattern.d.ts.map +1 -0
  335. package/dist/pattern.js +239 -0
  336. package/dist/pattern.js.map +1 -0
  337. package/dist/peer.d.ts +17 -0
  338. package/dist/peer.d.ts.map +1 -0
  339. package/dist/peer.js +50 -0
  340. package/dist/peer.js.map +1 -0
  341. package/dist/plugin.d.ts +67 -16
  342. package/dist/plugin.d.ts.map +1 -1
  343. package/dist/plugin.js +649 -0
  344. package/dist/plugin.js.map +1 -0
  345. package/dist/powered-by.d.ts.map +1 -1
  346. package/dist/powered-by.js +11 -0
  347. package/dist/powered-by.js.map +1 -0
  348. package/dist/pretty-json.d.ts.map +1 -1
  349. package/dist/pretty-json.js +47 -0
  350. package/dist/pretty-json.js.map +1 -0
  351. package/dist/producer-stream.d.ts +47 -0
  352. package/dist/producer-stream.d.ts.map +1 -0
  353. package/dist/producer-stream.js +267 -0
  354. package/dist/producer-stream.js.map +1 -0
  355. package/dist/proxy.d.ts +47 -8
  356. package/dist/proxy.d.ts.map +1 -1
  357. package/dist/proxy.js +274 -0
  358. package/dist/proxy.js.map +1 -0
  359. package/dist/python-type-emitter.d.ts +14 -1
  360. package/dist/python-type-emitter.d.ts.map +1 -1
  361. package/dist/python-type-emitter.js +157 -0
  362. package/dist/python-type-emitter.js.map +1 -0
  363. package/dist/realtime/bus.d.ts +17 -1
  364. package/dist/realtime/bus.d.ts.map +1 -1
  365. package/dist/realtime/bus.js +112 -0
  366. package/dist/realtime/bus.js.map +1 -0
  367. package/dist/realtime/register.d.ts +3 -0
  368. package/dist/realtime/register.d.ts.map +1 -0
  369. package/dist/realtime/register.js +10 -0
  370. package/dist/realtime/register.js.map +1 -0
  371. package/dist/realtime/route.d.ts +65 -26
  372. package/dist/realtime/route.d.ts.map +1 -1
  373. package/dist/realtime/route.js +72 -0
  374. package/dist/realtime/route.js.map +1 -0
  375. package/dist/realtime/server.d.ts +43 -0
  376. package/dist/realtime/server.d.ts.map +1 -0
  377. package/dist/realtime/server.js +255 -0
  378. package/dist/realtime/server.js.map +1 -0
  379. package/dist/request-id.d.ts +7 -0
  380. package/dist/request-id.d.ts.map +1 -1
  381. package/dist/request-id.js +16 -0
  382. package/dist/request-id.js.map +1 -0
  383. package/dist/request-limits.d.ts +3 -0
  384. package/dist/request-limits.d.ts.map +1 -0
  385. package/dist/request-limits.js +3 -0
  386. package/dist/request-limits.js.map +1 -0
  387. package/dist/request-path.d.ts +33 -0
  388. package/dist/request-path.d.ts.map +1 -0
  389. package/dist/request-path.js +178 -0
  390. package/dist/request-path.js.map +1 -0
  391. package/dist/request-to-curl.d.ts +7 -1
  392. package/dist/request-to-curl.d.ts.map +1 -1
  393. package/dist/request-to-curl.js +48 -0
  394. package/dist/request-to-curl.js.map +1 -0
  395. package/dist/response.d.ts +25 -2
  396. package/dist/response.d.ts.map +1 -1
  397. package/dist/response.js +313 -0
  398. package/dist/response.js.map +1 -0
  399. package/dist/rust-type-emitter.d.ts +14 -2
  400. package/dist/rust-type-emitter.d.ts.map +1 -1
  401. package/dist/rust-type-emitter.js +463 -0
  402. package/dist/rust-type-emitter.js.map +1 -0
  403. package/dist/secure-headers.d.ts.map +1 -1
  404. package/dist/secure-headers.js +53 -0
  405. package/dist/secure-headers.js.map +1 -0
  406. package/dist/serve-register.d.ts +4 -0
  407. package/dist/serve-register.d.ts.map +1 -1
  408. package/dist/serve-register.js +9 -0
  409. package/dist/serve-register.js.map +1 -0
  410. package/dist/serve-slot.d.ts +3 -0
  411. package/dist/serve-slot.d.ts.map +1 -1
  412. package/dist/serve-slot.js +52 -0
  413. package/dist/serve-slot.js.map +1 -0
  414. package/dist/serve.d.ts +18 -1
  415. package/dist/serve.d.ts.map +1 -1
  416. package/dist/serve.js +157 -0
  417. package/dist/serve.js.map +1 -0
  418. package/dist/server-timing.d.ts.map +1 -1
  419. package/dist/server-timing.js +51 -0
  420. package/dist/server-timing.js.map +1 -0
  421. package/dist/static.d.ts +9 -0
  422. package/dist/static.d.ts.map +1 -1
  423. package/dist/static.js +102 -0
  424. package/dist/static.js.map +1 -0
  425. package/dist/telemetry/otel.d.ts +2 -0
  426. package/dist/telemetry/otel.d.ts.map +1 -1
  427. package/dist/telemetry/otel.js +135 -0
  428. package/dist/telemetry/otel.js.map +1 -0
  429. package/dist/testing.d.ts +12 -0
  430. package/dist/testing.d.ts.map +1 -1
  431. package/dist/testing.js +124 -0
  432. package/dist/testing.js.map +1 -0
  433. package/dist/timeout.d.ts +6 -0
  434. package/dist/timeout.d.ts.map +1 -1
  435. package/dist/timeout.js +36 -0
  436. package/dist/timeout.js.map +1 -0
  437. package/dist/tree.d.ts +133 -36
  438. package/dist/tree.d.ts.map +1 -1
  439. package/dist/tree.js +437 -0
  440. package/dist/tree.js.map +1 -0
  441. package/dist/trust.d.ts +21 -0
  442. package/dist/trust.d.ts.map +1 -0
  443. package/dist/trust.js +100 -0
  444. package/dist/trust.js.map +1 -0
  445. package/dist/ts-type-emitter.d.ts.map +1 -1
  446. package/dist/ts-type-emitter.js +150 -0
  447. package/dist/ts-type-emitter.js.map +1 -0
  448. package/dist/type-emitter.d.ts +16 -2
  449. package/dist/type-emitter.d.ts.map +1 -1
  450. package/dist/type-emitter.js +729 -0
  451. package/dist/type-emitter.js.map +1 -0
  452. package/dist/type-extractor.d.ts +8 -4
  453. package/dist/type-extractor.d.ts.map +1 -1
  454. package/dist/type-extractor.js +819 -0
  455. package/dist/type-extractor.js.map +1 -0
  456. package/dist/types.d.ts +7 -0
  457. package/dist/types.d.ts.map +1 -1
  458. package/dist/types.js +96 -0
  459. package/dist/types.js.map +1 -0
  460. package/dist/validation.d.ts +14 -2
  461. package/dist/validation.d.ts.map +1 -1
  462. package/dist/validation.js +335 -0
  463. package/dist/validation.js.map +1 -0
  464. package/dist/with-headers.d.ts +15 -0
  465. package/dist/with-headers.d.ts.map +1 -0
  466. package/dist/with-headers.js +45 -0
  467. package/dist/with-headers.js.map +1 -0
  468. package/dist/ws/bun.d.ts +11 -5
  469. package/dist/ws/bun.d.ts.map +1 -1
  470. package/dist/ws/bun.js +82 -0
  471. package/dist/ws/bun.js.map +1 -0
  472. package/dist/ws/cloudflare.d.ts +25 -3
  473. package/dist/ws/cloudflare.d.ts.map +1 -1
  474. package/dist/ws/cloudflare.js +117 -0
  475. package/dist/ws/cloudflare.js.map +1 -0
  476. package/dist/ws/deno.d.ts +4 -4
  477. package/dist/ws/deno.d.ts.map +1 -1
  478. package/dist/ws/deno.js +133 -0
  479. package/dist/ws/deno.js.map +1 -0
  480. package/dist/ws/node.d.ts +20 -3
  481. package/dist/ws/node.d.ts.map +1 -1
  482. package/dist/ws/node.js +173 -0
  483. package/dist/ws/node.js.map +1 -0
  484. package/dist/ws/session.d.ts +11 -0
  485. package/dist/ws/session.d.ts.map +1 -0
  486. package/dist/ws/session.js +60 -0
  487. package/dist/ws/session.js.map +1 -0
  488. package/dist/ws/shared.d.ts +65 -0
  489. package/dist/ws/shared.d.ts.map +1 -0
  490. package/dist/ws/shared.js +103 -0
  491. package/dist/ws/shared.js.map +1 -0
  492. package/dist/ws-origin.d.ts +20 -0
  493. package/dist/ws-origin.d.ts.map +1 -0
  494. package/dist/ws-origin.js +41 -0
  495. package/dist/ws-origin.js.map +1 -0
  496. package/dist/yaml.d.ts +15 -1
  497. package/dist/yaml.d.ts.map +1 -1
  498. package/dist/yaml.js +101 -0
  499. package/dist/yaml.js.map +1 -0
  500. package/docs/invalidate-spec.md +13 -1
  501. package/docs/meta-spec.md +36 -12
  502. package/docs/packaging.md +43 -24
  503. package/docs/regression-matrix/README.md +32 -0
  504. package/docs/regression-matrix/review.md +44 -0
  505. package/docs/regression-matrix/ws1-3.md +97 -0
  506. package/docs/regression-matrix/ws4-8.md +107 -0
  507. package/docs/regression-matrix/ws9-12.md +266 -0
  508. package/docs/sdk.md +102 -52
  509. package/package.json +183 -52
  510. package/src/accepts.ts +91 -33
  511. package/src/body-kind.ts +67 -0
  512. package/src/body-limit.ts +102 -87
  513. package/src/build/index.ts +104 -54
  514. package/src/cli-args.ts +123 -0
  515. package/src/cli-go/auth.go +12 -1
  516. package/src/cli-go/config.go +29 -2
  517. package/src/cli-go/errors.go +28 -10
  518. package/src/cli-go/multipart.go +51 -27
  519. package/src/cli-go/output.go +58 -4
  520. package/src/cli-go/root.go +1 -1
  521. package/src/cli-go/version.go +2 -2
  522. package/src/cli.ts +154 -148
  523. package/src/client/error.ts +56 -1
  524. package/src/client/http.ts +479 -256
  525. package/src/client/index.ts +55 -17
  526. package/src/client/path.ts +169 -0
  527. package/src/client/redirect-policy.ts +19 -0
  528. package/src/client/sdk.ts +180 -101
  529. package/src/client/sse.ts +92 -66
  530. package/src/client/ws.ts +67 -31
  531. package/src/client-go/errors.go +41 -12
  532. package/src/client-go/export.go +44 -0
  533. package/src/client-go/invalidation.go +52 -54
  534. package/src/client-go/nullable.go +62 -0
  535. package/src/client-go/realtime.go +147 -110
  536. package/src/client-go/runtime.go +646 -88
  537. package/src/client-go/sse.go +104 -94
  538. package/src/client-go/transport.go +67 -27
  539. package/src/client-go/ws.go +49 -25
  540. package/src/client-info.ts +79 -0
  541. package/src/client-mcp/server.ts +133 -3
  542. package/src/client-python/_invalidation.py +207 -291
  543. package/src/client-python/_realtime.py +63 -40
  544. package/src/client-python/_runtime.py +501 -119
  545. package/src/client-python/_sse.py +130 -74
  546. package/src/client-python/_transport.py +37 -9
  547. package/src/client-python/_ws.py +50 -22
  548. package/src/client-rust/errors.rs +21 -1
  549. package/src/client-rust/invalidation.rs +202 -231
  550. package/src/client-rust/invalidation_sync.rs +16 -229
  551. package/src/client-rust/nullable.rs +17 -0
  552. package/src/client-rust/realtime.rs +217 -217
  553. package/src/client-rust/runtime.rs +602 -177
  554. package/src/client-rust/runtime_sync.rs +169 -145
  555. package/src/client-rust/sse.rs +142 -121
  556. package/src/client-rust/ws.rs +61 -37
  557. package/src/codegen-go-cli.ts +607 -728
  558. package/src/codegen-go.ts +710 -770
  559. package/src/codegen-ir.ts +381 -75
  560. package/src/codegen-lang.ts +517 -0
  561. package/src/codegen-load.ts +150 -0
  562. package/src/codegen-mcp.ts +207 -108
  563. package/src/codegen-python.ts +684 -816
  564. package/src/codegen-route-tree-intern.ts +51 -25
  565. package/src/codegen-rust.ts +946 -1240
  566. package/src/codegen-sanitize.ts +0 -4
  567. package/src/codegen-schema-naming.ts +19 -6
  568. package/src/codegen-sdk-model.ts +228 -0
  569. package/src/codegen.ts +1488 -1140
  570. package/src/context.ts +130 -11
  571. package/src/cookie-sign.ts +85 -16
  572. package/src/cookie.ts +66 -11
  573. package/src/cors.ts +55 -54
  574. package/src/crypto.ts +27 -5
  575. package/src/csrf.ts +57 -25
  576. package/src/curl-logger.ts +155 -114
  577. package/src/dict.ts +12 -0
  578. package/src/error.ts +4 -2
  579. package/src/etag.ts +58 -34
  580. package/src/feature-detect.ts +147 -0
  581. package/src/feature-slots.ts +70 -0
  582. package/src/fetch-request.ts +13 -0
  583. package/src/gen-process.ts +42 -0
  584. package/src/gen-write.ts +127 -0
  585. package/src/glob.ts +109 -0
  586. package/src/go-type-emitter.ts +406 -155
  587. package/src/honey-response.ts +36 -9
  588. package/src/i18n-slot.ts +10 -0
  589. package/src/i18n.ts +98 -23
  590. package/src/index.ts +1887 -1756
  591. package/src/init.ts +40 -28
  592. package/src/invalidate-check.ts +42 -4
  593. package/src/invoke-user.ts +95 -0
  594. package/src/ip-restrict.ts +47 -161
  595. package/src/ip.ts +194 -0
  596. package/src/logger.ts +65 -36
  597. package/src/media-type.ts +104 -0
  598. package/src/meta-spec-merge.ts +80 -0
  599. package/src/meta-spec.ts +0 -0
  600. package/src/middleware.ts +112 -12
  601. package/src/node-request.ts +242 -52
  602. package/src/node.ts +318 -75
  603. package/src/openapi/collect.ts +19 -44
  604. package/src/openapi/docs-page.ts +89 -0
  605. package/src/openapi/document.ts +503 -224
  606. package/src/openapi/json-schema-slot.ts +40 -0
  607. package/src/openapi/register.ts +7 -2
  608. package/src/openapi/scalar.ts +11 -10
  609. package/src/openapi/serve.ts +39 -0
  610. package/src/openapi/spec-factory.ts +50 -1
  611. package/src/openapi/spec.ts +53 -30
  612. package/src/openapi/swagger.ts +12 -11
  613. package/src/pattern.ts +245 -0
  614. package/src/peer.ts +53 -0
  615. package/src/plugin.ts +270 -185
  616. package/src/powered-by.ts +2 -2
  617. package/src/pretty-json.ts +25 -9
  618. package/src/producer-stream.ts +296 -0
  619. package/src/proxy.ts +253 -55
  620. package/src/python-type-emitter.ts +68 -56
  621. package/src/realtime/bus.ts +56 -9
  622. package/src/realtime/register.ts +13 -0
  623. package/src/realtime/route.ts +129 -80
  624. package/src/realtime/server.ts +298 -0
  625. package/src/request-id.ts +13 -3
  626. package/src/request-limits.ts +2 -0
  627. package/src/request-path.ts +165 -0
  628. package/src/request-to-curl.ts +28 -7
  629. package/src/response.ts +143 -103
  630. package/src/rust-type-emitter.ts +265 -170
  631. package/src/secure-headers.ts +8 -4
  632. package/src/serve-register.ts +4 -0
  633. package/src/serve-slot.ts +38 -0
  634. package/src/serve.ts +113 -25
  635. package/src/server-timing.ts +11 -7
  636. package/src/static.ts +85 -32
  637. package/src/telemetry/otel.ts +29 -7
  638. package/src/testing.ts +76 -14
  639. package/src/timeout.ts +15 -7
  640. package/src/tree.ts +405 -333
  641. package/src/trust.ts +117 -0
  642. package/src/ts-type-emitter.ts +18 -12
  643. package/src/type-emitter.ts +227 -89
  644. package/src/type-extractor.ts +603 -423
  645. package/src/types.ts +8 -0
  646. package/src/validation.ts +221 -96
  647. package/src/with-headers.ts +45 -0
  648. package/src/ws/bun.ts +53 -15
  649. package/src/ws/cloudflare.ts +81 -19
  650. package/src/ws/deno.ts +124 -36
  651. package/src/ws/node.ts +173 -79
  652. package/src/ws/session.ts +73 -0
  653. package/src/ws/shared.ts +140 -0
  654. package/src/ws-origin.ts +53 -0
  655. package/src/yaml.ts +45 -22
  656. package/dist/client-mcp/server.d.ts +0 -10
  657. package/dist/client-mcp/server.d.ts.map +0 -1
  658. package/dist/client-mcp/types.d.ts +0 -16
  659. package/dist/client-mcp/types.d.ts.map +0 -1
  660. package/dist/cloudflare/realtime.d.ts +0 -30
  661. package/dist/cloudflare/realtime.d.ts.map +0 -1
  662. package/dist/realtime/buffer.d.ts +0 -18
  663. package/dist/realtime/buffer.d.ts.map +0 -1
  664. package/dist/realtime/longpoll.d.ts +0 -23
  665. package/dist/realtime/longpoll.d.ts.map +0 -1
  666. package/dist/realtime/protocol.d.ts +0 -50
  667. package/dist/realtime/protocol.d.ts.map +0 -1
  668. package/dist/realtime/runtime.d.ts +0 -74
  669. package/dist/realtime/runtime.d.ts.map +0 -1
  670. package/src/cloudflare/realtime.ts +0 -234
  671. package/src/realtime/buffer.ts +0 -101
  672. package/src/realtime/longpoll.ts +0 -148
  673. package/src/realtime/protocol.ts +0 -128
  674. package/src/realtime/runtime.ts +0 -427
package/src/ws/node.ts CHANGED
@@ -1,36 +1,58 @@
1
- export { type RawSocket, type WSAdapter, type WSContext, WSContextImpl, type WSHandler } from "./cloudflare.ts"
1
+ export {
2
+ type RawSocket,
3
+ type WSAdapter,
4
+ type WSAdapterOptions,
5
+ type WSContext,
6
+ WSContextImpl,
7
+ type WSHandler,
8
+ } from "./cloudflare.ts"
2
9
 
3
10
  import type { WSAdapter, WSHandler } from "./cloudflare.ts"
4
- import { WSContextImpl } from "./cloudflare.ts"
11
+ import { fireHandler, WSContextImpl } from "./cloudflare.ts"
12
+ import {
13
+ type ResolvedWSOptions,
14
+ resolveWSOptions,
15
+ selectProtocol,
16
+ toArrayBuffer,
17
+ type WSAdapterOptions,
18
+ } from "./shared.ts"
19
+
20
+ type WebSocketServerOptions = {
21
+ handleProtocols?: (protocols: Set<string>, req: unknown) => string | false
22
+ maxPayload: number
23
+ noServer: true
24
+ perMessageDeflate: boolean
25
+ }
5
26
 
6
27
  type WsModule = {
7
- WebSocketServer: new (opts: { noServer: true; perMessageDeflate: boolean }) => {
8
- handleUpgrade(req: unknown, socket: unknown, head: unknown, cb: (ws: NodeWS) => void): void
9
- }
28
+ WebSocketServer: new (opts: WebSocketServerOptions) => WssInstance
10
29
  }
11
30
 
12
31
  type NodeWS = {
32
+ binaryType: string
33
+ bufferedAmount: number
13
34
  close(code?: number, reason?: string): void
14
35
  on(event: "close", cb: (code: number, reason: Buffer) => void): void
15
36
  on(event: "error", cb: (err: unknown) => void): void
16
- on(event: "message", cb: (data: Buffer | ArrayBuffer | Buffer[], isBinary: boolean) => void): void
17
- on(event: "pong", cb: () => void): void
37
+ on(event: "message", cb: (data: ArrayBuffer | Buffer | Buffer[], isBinary: boolean) => void): void
38
+ on(event: "pong" | "ping", cb: () => void): void
18
39
  ping(): void
19
40
  readyState: number
20
41
  send(data: ArrayBuffer | Buffer | Uint8Array | string): void
42
+ terminate(): void
21
43
  }
22
44
 
23
- type NodeUpgradeData = {
45
+ /**
46
+ * What the Node adapter (`serve()`) puts on `env.__nodeUpgrade`. `upgraded` turns true once the
47
+ * 101 is written: from then on the socket belongs to `ws`, and the adapter must not write to it.
48
+ */
49
+ export type NodeUpgradeData = {
24
50
  head: Buffer
25
51
  req: unknown
26
52
  socket: unknown
53
+ upgraded: boolean
27
54
  }
28
55
 
29
- /**
30
- * Node.js WebSocket adapter.
31
- * Requires the `ws` package. Creates a no-server WebSocketServer internally.
32
- * Reads __nodeUpgrade from env (placed there by serve()).
33
- */
34
56
  type WssInstance = {
35
57
  handleUpgrade(req: unknown, socket: unknown, head: unknown, cb: (ws: NodeWS) => void): void
36
58
  }
@@ -40,96 +62,166 @@ type KeepaliveConfig = {
40
62
  timeout: number
41
63
  }
42
64
 
43
- export function nodeWebSocket(opts?: { keepalive?: KeepaliveConfig }): WSAdapter {
65
+ export type NodeWebSocketOptions = WSAdapterOptions & {
66
+ /** Ping every `interval` ms; a pong missing after `timeout` ms terminates the connection. */
67
+ keepalive?: KeepaliveConfig
68
+ }
69
+
70
+ const WS_MISSING =
71
+ 'WebSocket routes on Node need the "ws" package, which is an optional peer dependency of honey. Install it: npm install ws'
72
+
73
+ /**
74
+ * Node.js WebSocket adapter, on the `ws` package (an optional peer dependency). It reads
75
+ * `env.__nodeUpgrade`, which honey's `serve()` puts there for an upgrade request.
76
+ */
77
+ export function nodeWebSocket(opts?: NodeWebSocketOptions): WSAdapter {
78
+ const options: ResolvedWSOptions = resolveWSOptions(opts)
79
+ const keepalive = opts?.keepalive
80
+ if (keepalive !== undefined && !(keepalive.interval > 0 && keepalive.timeout > 0)) {
81
+ throw new TypeError("nodeWebSocket: keepalive.interval and keepalive.timeout must be positive")
82
+ }
44
83
  let wss: WssInstance | null = null
45
- let wssReady: Promise<void> | null = null
84
+ let wssReady: Promise<WssInstance> | null = null
85
+ const open = new Set<NodeWS>()
86
+ /* the Request being upgraded, for the protocol callback (ws hands it the IncomingMessage) */
87
+ let upgrading: Request | null = null
46
88
 
47
- const ensureWss = async (): Promise<WssInstance> => {
48
- if (wss) return wss
89
+ const ensureWss = (): Promise<WssInstance> => {
90
+ if (wss) return Promise.resolve(wss)
49
91
  if (!wssReady) {
50
- wssReady = import("ws").then((mod) => {
51
- const wsModule = mod as unknown as WsModule
52
- wss = new wsModule.WebSocketServer({ noServer: true, perMessageDeflate: false })
53
- })
92
+ wssReady = import("ws").then(
93
+ (mod) => {
94
+ const wsModule = mod as unknown as WsModule
95
+ wss = new wsModule.WebSocketServer({
96
+ handleProtocols: (protocols) => {
97
+ if (protocols.size === 0 || upgrading === null) return false
98
+ return selectProtocol(upgrading, options) ?? false
99
+ },
100
+ maxPayload: options.maxPayload,
101
+ noServer: true,
102
+ perMessageDeflate: false,
103
+ })
104
+ return wss
105
+ },
106
+ (err: unknown) => {
107
+ /* not cached: installing ws later works without a restart */
108
+ wssReady = null
109
+ throw new Error(WS_MISSING, { cause: err })
110
+ },
111
+ )
54
112
  }
55
- await wssReady
56
- if (!wss) throw new Error("Failed to initialize WebSocketServer")
57
- return wss
113
+ return wssReady
114
+ }
115
+
116
+ const watch = (ws: NodeWS): void => {
117
+ let pingTimer: ReturnType<typeof setInterval> | undefined
118
+ let pongTimeout: ReturnType<typeof setTimeout> | undefined
119
+ let idleTimer: ReturnType<typeof setInterval> | undefined
120
+ let lastSeen = Date.now()
121
+ const seen = (): void => {
122
+ lastSeen = Date.now()
123
+ }
124
+
125
+ ws.on("pong", () => {
126
+ seen()
127
+ if (pongTimeout !== undefined) {
128
+ clearTimeout(pongTimeout)
129
+ pongTimeout = undefined
130
+ }
131
+ })
132
+ ws.on("ping", seen)
133
+
134
+ if (keepalive) {
135
+ pingTimer = setInterval(() => {
136
+ if (ws.readyState !== 1) return
137
+ /* one pong outstanding at a time: a slow pong must not stack timers */
138
+ if (pongTimeout !== undefined) return
139
+ ws.ping()
140
+ pongTimeout = setTimeout(() => ws.terminate(), keepalive.timeout)
141
+ }, keepalive.interval)
142
+ }
143
+
144
+ const idle = options.idleTimeout
145
+ if (idle > 0) {
146
+ const tick = Math.max(Math.floor(idle / 2), 1)
147
+ idleTimer = setInterval(() => {
148
+ if (ws.readyState !== 1) return
149
+ const quiet = Date.now() - lastSeen
150
+ if (quiet >= idle) ws.terminate()
151
+ else if (quiet >= tick) ws.ping()
152
+ }, tick)
153
+ }
154
+
155
+ const stop = (): void => {
156
+ if (pingTimer !== undefined) clearInterval(pingTimer)
157
+ if (pongTimeout !== undefined) clearTimeout(pongTimeout)
158
+ if (idleTimer !== undefined) clearInterval(idleTimer)
159
+ pingTimer = pongTimeout = idleTimer = undefined
160
+ }
161
+ ws.on("close", stop)
162
+ ws.on("error", stop)
58
163
  }
59
164
 
60
165
  return {
61
- async upgrade(_req: Request, env: unknown, handler: WSHandler<unknown>) {
166
+ closeAll(code: number, reason: string) {
167
+ for (const ws of open) {
168
+ try {
169
+ ws.close(code, reason)
170
+ } catch {
171
+ ws.terminate()
172
+ }
173
+ }
174
+ },
175
+ options,
176
+ async upgrade(req: Request, env: unknown, handler: WSHandler<unknown>) {
62
177
  const server = await ensureWss()
63
-
64
- const nodeEnv = env as Record<string, unknown>
65
- const upgrade = nodeEnv.__nodeUpgrade as NodeUpgradeData
178
+ const upgrade = (env as Record<string, unknown>).__nodeUpgrade as NodeUpgradeData | undefined
179
+ if (upgrade === undefined) {
180
+ throw new Error("nodeWebSocket: no upgrade socket; serve the app with honey's serve() on Node")
181
+ }
66
182
 
67
183
  return new Promise((resolve, reject) => {
184
+ /* ws answers a malformed handshake itself and never calls back: fail instead of hanging */
185
+ const sock = upgrade.socket as { once?(event: "close", cb: () => void): void }
186
+ sock.once?.("close", () => {
187
+ if (!upgrade.upgraded) reject(new Error("WebSocket handshake failed"))
188
+ })
189
+ upgrading = req
68
190
  try {
69
191
  server.handleUpgrade(upgrade.req, upgrade.socket, upgrade.head, (ws: NodeWS) => {
70
- const socket = new WSContextImpl(ws)
192
+ upgrade.upgraded = true
193
+ ws.binaryType = "arraybuffer"
194
+ open.add(ws)
195
+ const socket = new WSContextImpl(ws, options)
71
196
 
72
- ws.on("message", (data: Buffer | ArrayBuffer | Buffer[], isBinary: boolean) => {
197
+ ws.on("message", (data: ArrayBuffer | Buffer | Buffer[], isBinary: boolean) => {
198
+ let payload: ArrayBuffer | string
73
199
  if (!isBinary) {
74
- /* text frame — decode to string to match other runtimes */
75
- const text = Buffer.isBuffer(data) ? data.toString("utf-8") : String(data)
76
- handler.onMessage?.(undefined, socket, text)
77
- } else if (Buffer.isBuffer(data)) {
78
- /* binary frame — slice from pool to get exact bytes */
79
- handler.onMessage?.(
80
- undefined,
81
- socket,
82
- data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength) as ArrayBuffer,
83
- )
84
- } else if (Array.isArray(data)) {
85
- const merged = Buffer.concat(data)
86
- handler.onMessage?.(
87
- undefined,
88
- socket,
89
- merged.buffer.slice(merged.byteOffset, merged.byteOffset + merged.byteLength) as ArrayBuffer,
90
- )
200
+ /* text frame: a string, as on every other runtime */
201
+ payload = Buffer.isBuffer(data)
202
+ ? data.toString("utf-8")
203
+ : data instanceof ArrayBuffer
204
+ ? Buffer.from(data).toString("utf-8")
205
+ : Buffer.concat(data).toString("utf-8")
206
+ } else if (data instanceof ArrayBuffer) {
207
+ payload = data
91
208
  } else {
92
- handler.onMessage?.(undefined, socket, data)
209
+ payload = toArrayBuffer(Array.isArray(data) ? Buffer.concat(data) : data)
93
210
  }
211
+ fireHandler("message", () => handler.onMessage?.(undefined, socket, payload))
94
212
  })
95
-
96
- /* keepalive ping/pong */
97
- let pingTimer: ReturnType<typeof setInterval> | undefined
98
- let pongTimeout: ReturnType<typeof setTimeout> | undefined
99
-
100
- if (opts?.keepalive) {
101
- const { interval, timeout } = opts.keepalive
102
- ws.on("pong", () => {
103
- if (pongTimeout !== undefined) {
104
- clearTimeout(pongTimeout)
105
- pongTimeout = undefined
106
- }
107
- })
108
- pingTimer = setInterval(() => {
109
- if (ws.readyState !== 1) {
110
- clearInterval(pingTimer)
111
- return
112
- }
113
- ws.ping()
114
- pongTimeout = setTimeout(() => {
115
- ws.close(1001, "keepalive timeout")
116
- }, timeout)
117
- }, interval)
118
- }
213
+ watch(ws)
119
214
 
120
215
  ws.on("close", (code: number, reason: Buffer) => {
121
- if (pingTimer !== undefined) clearInterval(pingTimer)
122
- if (pongTimeout !== undefined) clearTimeout(pongTimeout)
123
- handler.onClose?.(undefined, socket, code, reason.toString())
216
+ open.delete(ws)
217
+ fireHandler("close", () => handler.onClose?.(undefined, socket, code, reason.toString()))
124
218
  })
125
219
 
126
220
  ws.on("error", (err: unknown) => {
127
- if (pingTimer !== undefined) clearInterval(pingTimer)
128
- if (pongTimeout !== undefined) clearTimeout(pongTimeout)
129
- handler.onError?.(undefined, socket, err)
221
+ fireHandler("error", () => handler.onError?.(undefined, socket, err))
130
222
  })
131
223
 
132
- handler.onOpen?.(undefined, socket)
224
+ fireHandler("open", () => handler.onOpen?.(undefined, socket))
133
225
 
134
226
  /* Node's Response rejects status 101 (Fetch spec: 200-599 only).
135
227
  Create a valid Response and override status for the sentinel check. */
@@ -139,6 +231,8 @@ export function nodeWebSocket(opts?: { keepalive?: KeepaliveConfig }): WSAdapter
139
231
  })
140
232
  } catch (err) {
141
233
  reject(err)
234
+ } finally {
235
+ upgrading = null
142
236
  }
143
237
  })
144
238
  },
@@ -0,0 +1,73 @@
1
+ /**
2
+ * The server side of one websocket route connection: the user's callbacks run on one ordered
3
+ * queue (open, then messages, then close), each contained, with a cap on waiting messages.
4
+ * Every honey adapter imports this module, which registers it, so the core never bundles it
5
+ * for an app without websockets.
6
+ */
7
+ import { registerFeature } from "../feature-slots.ts"
8
+ import { createEventQueue, invokeUser, type InvokeLogger } from "../invoke-user.ts"
9
+ import { originAllowed } from "../ws-origin.ts"
10
+ import type { WSContext, WSHandler } from "./cloudflare.ts"
11
+
12
+ /** Messages one websocket connection may have waiting for its handler; more close it with 1008. */
13
+ const WS_PENDING_MAX = 1024
14
+
15
+ /** `callbacks` are the route's own; each receives the route's request context `ctx` first. */
16
+ export function createWsSession(opts: {
17
+ callbacks: WSHandler<unknown>
18
+ ctx: unknown
19
+ log: InvokeLogger | null
20
+ reconnectToken: string | null
21
+ route: string
22
+ }): WSHandler<unknown> {
23
+ const { callbacks, ctx, log, reconnectToken, route } = opts
24
+ const { onClose, onError, onMessage, onOpen, onReconnect } = callbacks
25
+ const queue = createEventQueue()
26
+ let pending = 0
27
+
28
+ const run = (phase: string, ws: WSContext, fn: () => unknown): Promise<unknown> =>
29
+ invokeUser(fn, {
30
+ fields: { route },
31
+ log,
32
+ onError: onError ? (err) => onError(ctx, ws, err) : null,
33
+ phase: `websocket ${phase}`,
34
+ })
35
+
36
+ return {
37
+ onClose: (_ctx, ws, code, reason) => {
38
+ if (onClose) void queue.push(() => run("close", ws, () => onClose(ctx, ws, code, reason)))
39
+ },
40
+ /* a transport error: tell onError once; if onError throws, that is logged */
41
+ onError: (_ctx, ws, error) => {
42
+ void queue.push(() =>
43
+ invokeUser(() => (onError ? onError(ctx, ws, error) : Promise.reject(error)), {
44
+ fields: { route },
45
+ log,
46
+ phase: "websocket error",
47
+ }),
48
+ )
49
+ },
50
+ onMessage: (_ctx, ws, data) => {
51
+ if (!onMessage) return
52
+ if (pending >= WS_PENDING_MAX) {
53
+ ws.close(1008, "too many pending messages")
54
+ return
55
+ }
56
+ pending++
57
+ void queue.push(() =>
58
+ run("message", ws, () => onMessage(ctx, ws, data)).finally(() => {
59
+ pending--
60
+ }),
61
+ )
62
+ },
63
+ onOpen: (_ctx, ws) => {
64
+ if (reconnectToken && onReconnect) {
65
+ void queue.push(() => run("open", ws, () => onReconnect(ctx, ws, reconnectToken)))
66
+ } else if (onOpen) {
67
+ void queue.push(() => run("open", ws, () => onOpen(ctx, ws)))
68
+ }
69
+ },
70
+ }
71
+ }
72
+
73
+ registerFeature("ws", { createWsSession, originAllowed })
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Options every WebSocket adapter takes, with the same meaning and defaults on Node, Bun, Deno
3
+ * and Workers. Each adapter enforces what its runtime does not.
4
+ */
5
+ export type WSAdapterOptions = {
6
+ /**
7
+ * Largest inbound message in bytes. A bigger one closes the connection with 1009.
8
+ * Default 1 MiB.
9
+ */
10
+ maxPayload?: number
11
+ /**
12
+ * Outbound bytes a socket may hold unsent before `backpressurePolicy` applies to the next
13
+ * `send()`. Default 8 MiB.
14
+ */
15
+ backpressureLimit?: number
16
+ /**
17
+ * Over `backpressureLimit`: `"close"` closes the connection with 1013 (try again later),
18
+ * `"drop"` discards the message. Default `"close"`.
19
+ */
20
+ backpressurePolicy?: "close" | "drop"
21
+ /**
22
+ * Close a connection that has received nothing (no message, no pong) for this many
23
+ * milliseconds. Idle peers are pinged first where the runtime allows it. `0` disables.
24
+ * Default 120 000 (Bun's default). Deno and Bun take whole seconds.
25
+ */
26
+ idleTimeout?: number
27
+ /**
28
+ * Choose the subprotocol from the ones the client offered (`Sec-WebSocket-Protocol`).
29
+ * Return `null` or `undefined` for none. Default: the first one offered.
30
+ */
31
+ protocol?: (offered: string[], req: Request) => string | null | undefined
32
+ }
33
+
34
+ export type ResolvedWSOptions = {
35
+ backpressureLimit: number
36
+ backpressurePolicy: "close" | "drop"
37
+ idleTimeout: number
38
+ maxPayload: number
39
+ protocol: (offered: string[], req: Request) => string | null | undefined
40
+ }
41
+
42
+ export const DEFAULT_MAX_PAYLOAD = 1024 * 1024
43
+ export const DEFAULT_BACKPRESSURE_LIMIT = 8 * 1024 * 1024
44
+ export const DEFAULT_IDLE_TIMEOUT = 120_000
45
+
46
+ /** Close codes the adapters and the realtime server use. */
47
+ export const CLOSE_NORMAL = 1000
48
+ export const CLOSE_GOING_AWAY = 1001
49
+ export const CLOSE_POLICY = 1008
50
+ export const CLOSE_TOO_BIG = 1009
51
+ export const CLOSE_INTERNAL = 1011
52
+ export const CLOSE_TRY_AGAIN = 1013
53
+
54
+ /** Longest close reason a frame can carry (125-byte control payload minus the 2-byte code). */
55
+ export const MAX_CLOSE_REASON = 123
56
+
57
+ const firstOffered = (offered: string[]): string | null => offered[0] ?? null
58
+
59
+ function nonNegative(name: string, value: number | undefined, fallback: number): number {
60
+ if (value === undefined) return fallback
61
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
62
+ throw new TypeError(`WebSocket adapter: ${name} must be a non-negative number`)
63
+ }
64
+ return value
65
+ }
66
+
67
+ export function resolveWSOptions(opts: WSAdapterOptions | undefined): ResolvedWSOptions {
68
+ const policy = opts?.backpressurePolicy ?? "close"
69
+ if (policy !== "close" && policy !== "drop") {
70
+ throw new TypeError('WebSocket adapter: backpressurePolicy must be "close" or "drop"')
71
+ }
72
+ const maxPayload = nonNegative("maxPayload", opts?.maxPayload, DEFAULT_MAX_PAYLOAD)
73
+ if (maxPayload === 0) throw new TypeError("WebSocket adapter: maxPayload must be positive")
74
+ return {
75
+ backpressureLimit: nonNegative("backpressureLimit", opts?.backpressureLimit, DEFAULT_BACKPRESSURE_LIMIT),
76
+ backpressurePolicy: policy,
77
+ idleTimeout: nonNegative("idleTimeout", opts?.idleTimeout, DEFAULT_IDLE_TIMEOUT),
78
+ maxPayload,
79
+ protocol: opts?.protocol ?? firstOffered,
80
+ }
81
+ }
82
+
83
+ /** The subprotocols the client offered, in order. */
84
+ export function offeredProtocols(req: Request): string[] {
85
+ const raw = req.headers.get("sec-websocket-protocol")
86
+ if (raw === null) return []
87
+ const out: string[] = []
88
+ for (const part of raw.split(",")) {
89
+ const p = part.trim()
90
+ if (p !== "") out.push(p)
91
+ }
92
+ return out
93
+ }
94
+
95
+ /** The subprotocol to answer with, or `null`. A choice the client did not offer is ignored. */
96
+ export function selectProtocol(req: Request, opts: ResolvedWSOptions): string | null {
97
+ const offered = offeredProtocols(req)
98
+ if (offered.length === 0) return null
99
+ const chosen = opts.protocol(offered, req)
100
+ return typeof chosen === "string" && offered.includes(chosen) ? chosen : null
101
+ }
102
+
103
+ /** Outbound bytes the runtime holds for this socket, when it reports them. */
104
+ export function bufferedAmountOf(raw: unknown): number {
105
+ if (raw === null || typeof raw !== "object") return 0
106
+ const r = raw as { bufferedAmount?: unknown; getBufferedAmount?: () => unknown }
107
+ if (typeof r.getBufferedAmount === "function") {
108
+ const n = r.getBufferedAmount()
109
+ return typeof n === "number" ? n : 0
110
+ }
111
+ return typeof r.bufferedAmount === "number" ? r.bufferedAmount : 0
112
+ }
113
+
114
+ /** Whether an inbound message is larger than `limit` bytes. */
115
+ export function exceedsPayload(data: ArrayBuffer | ArrayBufferView | Blob | string, limit: number): boolean {
116
+ if (typeof data === "string") {
117
+ if (data.length > limit) return true
118
+ /* a UTF-16 unit is at most 3 UTF-8 bytes, so most strings need no encode */
119
+ if (data.length * 3 <= limit) return false
120
+ return new TextEncoder().encode(data).byteLength > limit
121
+ }
122
+ if (typeof Blob !== "undefined" && data instanceof Blob) return data.size > limit
123
+ return (data as ArrayBuffer | ArrayBufferView).byteLength > limit
124
+ }
125
+
126
+ /** `data` as an `ArrayBuffer` holding exactly its bytes (a pooled Buffer's backing store is larger). */
127
+ export function toArrayBuffer(data: ArrayBuffer | ArrayBufferView): ArrayBuffer {
128
+ if (data instanceof ArrayBuffer) return data
129
+ const { buffer, byteLength, byteOffset } = data
130
+ if (byteOffset === 0 && byteLength === buffer.byteLength && buffer instanceof ArrayBuffer) return buffer
131
+ return buffer.slice(byteOffset, byteOffset + byteLength) as ArrayBuffer
132
+ }
133
+
134
+ /** A close code a server may send: 1000, 1001-1014 except the reserved ones, or 3000-4999. */
135
+ export function sendableCloseCode(code: number | undefined): number {
136
+ if (code === undefined) return 1000
137
+ if (code === 1000 || (code >= 3000 && code <= 4999)) return code
138
+ if (code >= 1001 && code <= 1014 && code !== 1004 && code !== 1005 && code !== 1006) return code
139
+ return 1000
140
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Which browser origins may open a WebSocket. A browser lets any page open a socket to any host
3
+ * and sends that host's cookies with it, so a cookie-authenticated socket is open to cross-site
4
+ * hijacking unless the server checks `Origin`.
5
+ *
6
+ * - `"*"`: every origin.
7
+ * - a list: those exact origins (`https://app.example.com`), plus same-origin.
8
+ * - a function: called with the `Origin` value; same-origin always passes.
9
+ * - unset (the default): same-origin always passes; a cross-origin upgrade is rejected when it
10
+ * carries credentials (`Cookie` or `Authorization`), since that is what hijacking needs. A
11
+ * request without `Origin` (not a browser) passes.
12
+ */
13
+ export type WSOriginPolicy = "*" | readonly string[] | ((origin: string) => boolean)
14
+
15
+ function originHost(origin: string): string | null {
16
+ if (origin === "null") return null
17
+ try {
18
+ return new URL(origin).host.toLowerCase()
19
+ } catch {
20
+ return null
21
+ }
22
+ }
23
+
24
+ export function validateOriginPolicy(policy: unknown): WSOriginPolicy {
25
+ if (policy === "*" || typeof policy === "function") return policy as WSOriginPolicy
26
+ if (Array.isArray(policy) && policy.every((o) => typeof o === "string")) {
27
+ for (const o of policy as string[]) {
28
+ if (originHost(o) === null)
29
+ throw new TypeError(`allowedOrigins: "${o}" is not an origin like https://example.com`)
30
+ }
31
+ return Object.freeze([...(policy as string[])])
32
+ }
33
+ throw new TypeError('allowedOrigins must be "*", a list of origins, or a function')
34
+ }
35
+
36
+ /**
37
+ * Whether an upgrade from `origin` may proceed. `host` is the host the client asked for
38
+ * (`clientInfo(ctx).host`, which follows `trustProxy`).
39
+ */
40
+ export function originAllowed(
41
+ policy: WSOriginPolicy | null,
42
+ origin: string | null,
43
+ host: string | null,
44
+ hasCredentials: boolean,
45
+ ): boolean {
46
+ if (policy === "*") return true
47
+ if (origin === null) return true
48
+ const oh = originHost(origin)
49
+ if (oh !== null && host !== null && oh === host.toLowerCase()) return true
50
+ if (policy === null) return !hasCredentials
51
+ if (typeof policy === "function") return policy(origin) === true
52
+ return policy.includes(origin)
53
+ }
package/src/yaml.ts CHANGED
@@ -1,4 +1,10 @@
1
- /** JSON-compatible YAML 1.2 emitter — same document as JSON.stringify, different encoding. */
1
+ /**
2
+ * JSON-compatible YAML 1.2 emitter: the same document as `JSON.stringify`, in a
3
+ * different encoding. Input is first normalized through JSON (so `undefined` keys
4
+ * are skipped, `Date` becomes its ISO string, `NaN` becomes `null`), then every
5
+ * string that is not plainly safe is written as a double-quoted scalar, which
6
+ * also reads the same under YAML 1.1 parsers.
7
+ */
2
8
 
3
9
  const INDENT = " "
4
10
 
@@ -7,38 +13,55 @@ export function yamlSiblingPath(jsonPath: string): string {
7
13
  return jsonPath.endsWith(".json") ? `${jsonPath.slice(0, -5)}.yaml` : `${jsonPath}.yaml`
8
14
  }
9
15
 
16
+ /**
17
+ * Where an OpenAPI output configured at `path` is written. A `.yaml`/`.yml` path is that YAML file
18
+ * alone; any other path is JSON there plus its YAML sibling.
19
+ */
20
+ export function openApiOutputPaths(path: string): { json: string | null; yaml: string } {
21
+ if (path.endsWith(".yaml") || path.endsWith(".yml")) return { json: null, yaml: path }
22
+ return { json: path, yaml: yamlSiblingPath(path) }
23
+ }
24
+
10
25
  export function toYaml(value: unknown): string {
11
- return `${emit(value, 0)}\n`
26
+ const json = JSON.stringify(value)
27
+ /* JSON.stringify(undefined) is undefined; emit the JSON equivalent of "nothing". */
28
+ const normalized: unknown = json === undefined ? null : JSON.parse(json)
29
+ return `${emit(normalized, 0)}\n`
12
30
  }
13
31
 
14
32
  function emit(value: unknown, indent: number): string {
15
- if (value === null || value === undefined) return "null"
33
+ if (value === null) return "null"
16
34
  if (typeof value === "boolean") return value ? "true" : "false"
17
- if (typeof value === "number") {
18
- if (!Number.isFinite(value)) return JSON.stringify(String(value))
19
- return Object.is(value, -0) ? "-0" : String(value)
20
- }
35
+ if (typeof value === "number") return String(value)
21
36
  if (typeof value === "string") return emitString(value)
22
37
  if (Array.isArray(value)) return emitArray(value, indent)
23
- if (typeof value === "object") return emitObject(value as Record<string, unknown>, indent)
24
- return JSON.stringify(String(value))
38
+ return emitObject(value as Record<string, unknown>, indent)
25
39
  }
26
40
 
41
+ /*
42
+ * A plain scalar is used only for a conservative shape: starts with a letter,
43
+ * `_`, `/` or `$`; contains only word characters, `.`, `/`, `$`, `-`, `+`,
44
+ * `{}`, `()` and inner spaces. That excludes every indicator, `: `, ` #`,
45
+ * leading digits (numbers, YAML 1.1 octal and sexagesimal), and `.inf`/`.nan`.
46
+ */
47
+ const PLAIN_RE = /^[A-Za-z_/$](?:[\w./${}()+-]| (?! ))*$/
48
+ /* Words YAML 1.1 or 1.2 resolves to null or a boolean. */
49
+ const RESERVED_RE = /^(?:y|n|yes|no|on|off|true|false|null|~)$/i
50
+
27
51
  function emitString(value: string): string {
28
- if (value === "") return '""'
29
- if (needsQuotes(value)) return JSON.stringify(value)
30
- return value
52
+ if (PLAIN_RE.test(value) && !value.endsWith(" ") && !RESERVED_RE.test(value)) return value
53
+ return quote(value)
31
54
  }
32
55
 
33
- function needsQuotes(value: string): boolean {
34
- if (/^[-?:{},[\],&*#|!>'%@`]/.test(value)) return true
35
- if (/[\n\r\t]/.test(value)) return true
36
- if (/^\s|\s$/.test(value)) return true
37
- if (value.includes(": ") || value.includes(" #")) return true
38
- if (/^(true|false|null|yes|no|on|off)$/i.test(value)) return true
39
- if (/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/.test(value)) return true
40
- if (/^\d/.test(value)) return true
41
- return false
56
+ /*
57
+ * JSON string syntax is a valid YAML double-quoted scalar, except that YAML
58
+ * forbids raw DEL, C1 controls (other than NEL) and the BOM/non-characters.
59
+ */
60
+ function quote(value: string): string {
61
+ return JSON.stringify(value).replace(
62
+ /[\u007f-\u0084\u0086-\u009f￾￿]/g,
63
+ (ch) => `\\u${ch.charCodeAt(0).toString(16).padStart(4, "0")}`,
64
+ )
42
65
  }
43
66
 
44
67
  function isNonEmptyCollection(value: unknown): boolean {
@@ -70,7 +93,7 @@ function emitObject(value: Record<string, unknown>, indent: number): string {
70
93
  return keys
71
94
  .map((key) => {
72
95
  const child = value[key]
73
- const renderedKey = needsQuotes(key) || key === "" ? JSON.stringify(key) : key
96
+ const renderedKey = emitString(key)
74
97
  if (isNonEmptyCollection(child)) {
75
98
  return `${pad}${renderedKey}:\n${emit(child, indent + 1)}`
76
99
  }