@lovrozagar/honey 0.6.5 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (674) hide show
  1. package/README.md +514 -192
  2. package/bin/honey.js +25 -0
  3. package/dist/accepts.d.ts +7 -1
  4. package/dist/accepts.d.ts.map +1 -1
  5. package/dist/accepts.js +126 -0
  6. package/dist/accepts.js.map +1 -0
  7. package/dist/body-kind.d.ts +26 -0
  8. package/dist/body-kind.d.ts.map +1 -0
  9. package/dist/body-kind.js +70 -0
  10. package/dist/body-kind.js.map +1 -0
  11. package/dist/body-limit.d.ts +5 -1
  12. package/dist/body-limit.d.ts.map +1 -1
  13. package/dist/body-limit.js +126 -0
  14. package/dist/body-limit.js.map +1 -0
  15. package/dist/build/index.d.ts +19 -3
  16. package/dist/build/index.d.ts.map +1 -1
  17. package/dist/build/index.js +173 -0
  18. package/dist/build/index.js.map +1 -0
  19. package/dist/cli-args.d.ts +33 -0
  20. package/dist/cli-args.d.ts.map +1 -0
  21. package/dist/cli-args.js +102 -0
  22. package/dist/cli-args.js.map +1 -0
  23. package/dist/cli-go/auth.go +26 -0
  24. package/dist/cli-go/config.go +192 -0
  25. package/dist/cli-go/errors.go +75 -0
  26. package/dist/cli-go/multipart.go +79 -0
  27. package/dist/cli-go/output.go +163 -0
  28. package/dist/cli-go/root.go +30 -0
  29. package/dist/cli-go/stream.go +88 -0
  30. package/dist/cli-go/version.go +5 -0
  31. package/dist/cli.d.ts +1 -1
  32. package/dist/cli.js +209 -0
  33. package/dist/cli.js.map +1 -0
  34. package/dist/client/defaults.js +48 -0
  35. package/dist/client/defaults.js.map +1 -0
  36. package/dist/client/error.d.ts +35 -0
  37. package/dist/client/error.d.ts.map +1 -1
  38. package/dist/client/error.js +71 -0
  39. package/dist/client/error.js.map +1 -0
  40. package/dist/client/http.d.ts +67 -8
  41. package/dist/client/http.d.ts.map +1 -1
  42. package/dist/client/http.js +571 -0
  43. package/dist/client/http.js.map +1 -0
  44. package/dist/client/index.d.ts +3 -2
  45. package/dist/client/index.d.ts.map +1 -1
  46. package/dist/client/index.js +95 -0
  47. package/dist/client/index.js.map +1 -0
  48. package/dist/client/path.d.ts +26 -0
  49. package/dist/client/path.d.ts.map +1 -0
  50. package/dist/client/path.js +163 -0
  51. package/dist/client/path.js.map +1 -0
  52. package/dist/client/redirect-policy.d.ts +12 -0
  53. package/dist/client/redirect-policy.d.ts.map +1 -0
  54. package/dist/client/redirect-policy.js +20 -0
  55. package/dist/client/redirect-policy.js.map +1 -0
  56. package/dist/client/sdk.d.ts +36 -0
  57. package/dist/client/sdk.d.ts.map +1 -1
  58. package/dist/client/sdk.js +292 -0
  59. package/dist/client/sdk.js.map +1 -0
  60. package/dist/client/sse.d.ts +13 -0
  61. package/dist/client/sse.d.ts.map +1 -1
  62. package/dist/client/sse.js +129 -0
  63. package/dist/client/sse.js.map +1 -0
  64. package/dist/client/types.js +2 -0
  65. package/dist/client/types.js.map +1 -0
  66. package/dist/client/ws.d.ts +9 -2
  67. package/dist/client/ws.d.ts.map +1 -1
  68. package/dist/client/ws.js +112 -0
  69. package/dist/client/ws.js.map +1 -0
  70. package/dist/client-go/errors.go +236 -0
  71. package/dist/client-go/export.go +44 -0
  72. package/dist/client-go/invalidation.go +371 -0
  73. package/dist/client-go/nullable.go +62 -0
  74. package/dist/client-go/realtime.go +354 -0
  75. package/dist/client-go/result.go +20 -0
  76. package/dist/client-go/runtime.go +975 -0
  77. package/dist/client-go/sse.go +159 -0
  78. package/dist/client-go/transport.go +495 -0
  79. package/dist/client-go/ws.go +128 -0
  80. package/dist/client-info.d.ts +36 -0
  81. package/dist/client-info.d.ts.map +1 -0
  82. package/dist/client-info.js +53 -0
  83. package/dist/client-info.js.map +1 -0
  84. package/dist/client-mcp/README.md +10 -0
  85. package/dist/client-mcp/server.ts +221 -0
  86. package/dist/client-mcp/types.ts +19 -0
  87. package/dist/client-python/_errors.py +115 -0
  88. package/dist/client-python/_invalidation.py +494 -0
  89. package/dist/client-python/_realtime.py +179 -0
  90. package/dist/client-python/_runtime.py +860 -0
  91. package/dist/client-python/_sse.py +155 -0
  92. package/dist/client-python/_transport.py +366 -0
  93. package/dist/client-python/_ws.py +159 -0
  94. package/dist/client-python/py.typed +0 -0
  95. package/dist/client-rust/errors.rs +220 -0
  96. package/dist/client-rust/invalidation.rs +412 -0
  97. package/dist/client-rust/invalidation_sync.rs +93 -0
  98. package/dist/client-rust/nullable.rs +17 -0
  99. package/dist/client-rust/realtime.rs +702 -0
  100. package/dist/client-rust/result.rs +22 -0
  101. package/dist/client-rust/runtime.rs +980 -0
  102. package/dist/client-rust/runtime_sync.rs +484 -0
  103. package/dist/client-rust/sse.rs +188 -0
  104. package/dist/client-rust/ws.rs +167 -0
  105. package/dist/codegen-go-cli.d.ts.map +1 -1
  106. package/dist/codegen-go-cli.js +964 -0
  107. package/dist/codegen-go-cli.js.map +1 -0
  108. package/dist/codegen-go.d.ts +15 -3
  109. package/dist/codegen-go.d.ts.map +1 -1
  110. package/dist/codegen-go.js +872 -0
  111. package/dist/codegen-go.js.map +1 -0
  112. package/dist/codegen-hash.js +9 -0
  113. package/dist/codegen-hash.js.map +1 -0
  114. package/dist/codegen-ir.d.ts +69 -2
  115. package/dist/codegen-ir.d.ts.map +1 -1
  116. package/dist/codegen-ir.js +661 -0
  117. package/dist/codegen-ir.js.map +1 -0
  118. package/dist/codegen-lang.d.ts +65 -0
  119. package/dist/codegen-lang.d.ts.map +1 -0
  120. package/dist/codegen-lang.js +526 -0
  121. package/dist/codegen-lang.js.map +1 -0
  122. package/dist/codegen-load.d.ts +31 -0
  123. package/dist/codegen-load.d.ts.map +1 -0
  124. package/dist/codegen-load.js +138 -0
  125. package/dist/codegen-load.js.map +1 -0
  126. package/dist/codegen-loaders.js +55 -0
  127. package/dist/codegen-loaders.js.map +1 -0
  128. package/dist/codegen-mcp.d.ts.map +1 -1
  129. package/dist/codegen-mcp.js +368 -0
  130. package/dist/codegen-mcp.js.map +1 -0
  131. package/dist/codegen-python.d.ts +13 -1
  132. package/dist/codegen-python.d.ts.map +1 -1
  133. package/dist/codegen-python.js +828 -0
  134. package/dist/codegen-python.js.map +1 -0
  135. package/dist/codegen-route-tree-intern.d.ts +15 -5
  136. package/dist/codegen-route-tree-intern.d.ts.map +1 -1
  137. package/dist/codegen-route-tree-intern.js +221 -0
  138. package/dist/codegen-route-tree-intern.js.map +1 -0
  139. package/dist/codegen-rust.d.ts.map +1 -1
  140. package/dist/codegen-rust.js +1293 -0
  141. package/dist/codegen-rust.js.map +1 -0
  142. package/dist/codegen-sanitize.d.ts.map +1 -1
  143. package/dist/codegen-sanitize.js +56 -0
  144. package/dist/codegen-sanitize.js.map +1 -0
  145. package/dist/codegen-schema-naming.d.ts +5 -0
  146. package/dist/codegen-schema-naming.d.ts.map +1 -1
  147. package/dist/codegen-schema-naming.js +150 -0
  148. package/dist/codegen-schema-naming.js.map +1 -0
  149. package/dist/codegen-sdk-model.d.ts +71 -0
  150. package/dist/codegen-sdk-model.d.ts.map +1 -0
  151. package/dist/codegen-sdk-model.js +179 -0
  152. package/dist/codegen-sdk-model.js.map +1 -0
  153. package/dist/codegen.d.ts +41 -23
  154. package/dist/codegen.d.ts.map +1 -1
  155. package/dist/codegen.js +4610 -0
  156. package/dist/codegen.js.map +1 -0
  157. package/dist/context.d.ts +36 -6
  158. package/dist/context.d.ts.map +1 -1
  159. package/dist/context.js +242 -0
  160. package/dist/context.js.map +1 -0
  161. package/dist/cookie-sign.d.ts +16 -2
  162. package/dist/cookie-sign.d.ts.map +1 -1
  163. package/dist/cookie-sign.js +104 -0
  164. package/dist/cookie-sign.js.map +1 -0
  165. package/dist/cookie.d.ts +12 -0
  166. package/dist/cookie.d.ts.map +1 -1
  167. package/dist/cookie.js +138 -0
  168. package/dist/cookie.js.map +1 -0
  169. package/dist/cors.d.ts +1 -0
  170. package/dist/cors.d.ts.map +1 -1
  171. package/dist/cors.js +87 -0
  172. package/dist/cors.js.map +1 -0
  173. package/dist/crypto.d.ts +6 -1
  174. package/dist/crypto.d.ts.map +1 -1
  175. package/dist/crypto.js +38 -0
  176. package/dist/crypto.js.map +1 -0
  177. package/dist/csrf.d.ts +19 -0
  178. package/dist/csrf.d.ts.map +1 -1
  179. package/dist/csrf.js +79 -0
  180. package/dist/csrf.js.map +1 -0
  181. package/dist/curl-logger.d.ts +14 -3
  182. package/dist/curl-logger.d.ts.map +1 -1
  183. package/dist/curl-logger.js +199 -0
  184. package/dist/curl-logger.js.map +1 -0
  185. package/dist/detect-runtime.js +13 -0
  186. package/dist/detect-runtime.js.map +1 -0
  187. package/dist/dict.d.ts +11 -0
  188. package/dist/dict.d.ts.map +1 -0
  189. package/dist/dict.js +13 -0
  190. package/dist/dict.js.map +1 -0
  191. package/dist/error.d.ts.map +1 -1
  192. package/dist/error.js +44 -0
  193. package/dist/error.js.map +1 -0
  194. package/dist/errors.js +39 -0
  195. package/dist/errors.js.map +1 -0
  196. package/dist/etag.d.ts +2 -0
  197. package/dist/etag.d.ts.map +1 -1
  198. package/dist/etag.js +82 -0
  199. package/dist/etag.js.map +1 -0
  200. package/dist/feature-detect.d.ts +25 -0
  201. package/dist/feature-detect.d.ts.map +1 -0
  202. package/dist/feature-detect.js +144 -0
  203. package/dist/feature-detect.js.map +1 -0
  204. package/dist/feature-load.js +36 -0
  205. package/dist/feature-load.js.map +1 -0
  206. package/dist/feature-slots.d.ts +44 -0
  207. package/dist/feature-slots.d.ts.map +1 -0
  208. package/dist/feature-slots.js +48 -0
  209. package/dist/feature-slots.js.map +1 -0
  210. package/dist/fetch-request.d.ts +10 -0
  211. package/dist/fetch-request.d.ts.map +1 -0
  212. package/dist/fetch-request.js +13 -0
  213. package/dist/fetch-request.js.map +1 -0
  214. package/dist/gen-process.d.ts +15 -0
  215. package/dist/gen-process.d.ts.map +1 -0
  216. package/dist/gen-process.js +43 -0
  217. package/dist/gen-process.js.map +1 -0
  218. package/dist/gen-write.d.ts +19 -0
  219. package/dist/gen-write.d.ts.map +1 -0
  220. package/dist/gen-write.js +120 -0
  221. package/dist/gen-write.js.map +1 -0
  222. package/dist/glob.d.ts +21 -0
  223. package/dist/glob.d.ts.map +1 -0
  224. package/dist/glob.js +115 -0
  225. package/dist/glob.js.map +1 -0
  226. package/dist/go-type-emitter.d.ts +18 -4
  227. package/dist/go-type-emitter.d.ts.map +1 -1
  228. package/dist/go-type-emitter.js +594 -0
  229. package/dist/go-type-emitter.js.map +1 -0
  230. package/dist/honey-response.d.ts.map +1 -1
  231. package/dist/honey-response.js +338 -0
  232. package/dist/honey-response.js.map +1 -0
  233. package/dist/i18n-slot.d.ts +8 -0
  234. package/dist/i18n-slot.d.ts.map +1 -1
  235. package/dist/i18n-slot.js +14 -0
  236. package/dist/i18n-slot.js.map +1 -0
  237. package/dist/i18n.d.ts +3 -0
  238. package/dist/i18n.d.ts.map +1 -1
  239. package/dist/i18n.js +250 -0
  240. package/dist/i18n.js.map +1 -0
  241. package/dist/index.d.ts +410 -149
  242. package/dist/index.d.ts.map +1 -1
  243. package/dist/index.js +2324 -0
  244. package/dist/index.js.map +1 -0
  245. package/dist/init.d.ts +3 -5
  246. package/dist/init.d.ts.map +1 -1
  247. package/dist/init.js +140 -0
  248. package/dist/init.js.map +1 -0
  249. package/dist/input.js +4 -0
  250. package/dist/input.js.map +1 -0
  251. package/dist/invalidate-check.d.ts +11 -0
  252. package/dist/invalidate-check.d.ts.map +1 -1
  253. package/dist/invalidate-check.js +163 -0
  254. package/dist/invalidate-check.js.map +1 -0
  255. package/dist/invoke-user.d.ts +35 -0
  256. package/dist/invoke-user.d.ts.map +1 -0
  257. package/dist/invoke-user.js +73 -0
  258. package/dist/invoke-user.js.map +1 -0
  259. package/dist/ip-restrict.d.ts +13 -1
  260. package/dist/ip-restrict.d.ts.map +1 -1
  261. package/dist/ip-restrict.js +60 -0
  262. package/dist/ip-restrict.js.map +1 -0
  263. package/dist/ip.d.ts +39 -0
  264. package/dist/ip.d.ts.map +1 -0
  265. package/dist/ip.js +209 -0
  266. package/dist/ip.js.map +1 -0
  267. package/dist/logger.d.ts.map +1 -1
  268. package/dist/logger.js +113 -0
  269. package/dist/logger.js.map +1 -0
  270. package/dist/media-type.d.ts +30 -0
  271. package/dist/media-type.d.ts.map +1 -0
  272. package/dist/media-type.js +97 -0
  273. package/dist/media-type.js.map +1 -0
  274. package/dist/meta-spec-merge.d.ts +32 -0
  275. package/dist/meta-spec-merge.d.ts.map +1 -0
  276. package/dist/meta-spec-merge.js +68 -0
  277. package/dist/meta-spec-merge.js.map +1 -0
  278. package/dist/meta-spec.d.ts +16 -3
  279. package/dist/meta-spec.d.ts.map +1 -1
  280. package/dist/meta-spec.js +535 -0
  281. package/dist/meta-spec.js.map +1 -0
  282. package/dist/middleware.d.ts +23 -6
  283. package/dist/middleware.d.ts.map +1 -1
  284. package/dist/middleware.js +253 -0
  285. package/dist/middleware.js.map +1 -0
  286. package/dist/node-request.d.ts +57 -12
  287. package/dist/node-request.d.ts.map +1 -1
  288. package/dist/node-request.js +407 -0
  289. package/dist/node-request.js.map +1 -0
  290. package/dist/node.d.ts +20 -3
  291. package/dist/node.d.ts.map +1 -1
  292. package/dist/node.js +396 -0
  293. package/dist/node.js.map +1 -0
  294. package/dist/openapi/collect.d.ts +6 -3
  295. package/dist/openapi/collect.d.ts.map +1 -1
  296. package/dist/openapi/collect.js +30 -0
  297. package/dist/openapi/collect.js.map +1 -0
  298. package/dist/openapi/docs-page.d.ts +42 -0
  299. package/dist/openapi/docs-page.d.ts.map +1 -0
  300. package/dist/openapi/docs-page.js +80 -0
  301. package/dist/openapi/docs-page.js.map +1 -0
  302. package/dist/openapi/document.d.ts +4 -0
  303. package/dist/openapi/document.d.ts.map +1 -1
  304. package/dist/openapi/document.js +785 -0
  305. package/dist/openapi/document.js.map +1 -0
  306. package/dist/openapi/json-schema-slot.d.ts +7 -0
  307. package/dist/openapi/json-schema-slot.d.ts.map +1 -1
  308. package/dist/openapi/json-schema-slot.js +38 -0
  309. package/dist/openapi/json-schema-slot.js.map +1 -0
  310. package/dist/openapi/register.d.ts.map +1 -1
  311. package/dist/openapi/register.js +20 -0
  312. package/dist/openapi/register.js.map +1 -0
  313. package/dist/openapi/scalar.d.ts +3 -1
  314. package/dist/openapi/scalar.d.ts.map +1 -1
  315. package/dist/openapi/scalar.js +21 -0
  316. package/dist/openapi/scalar.js.map +1 -0
  317. package/dist/openapi/serve.d.ts +9 -0
  318. package/dist/openapi/serve.d.ts.map +1 -0
  319. package/dist/openapi/serve.js +36 -0
  320. package/dist/openapi/serve.js.map +1 -0
  321. package/dist/openapi/spec-factory.d.ts +30 -1
  322. package/dist/openapi/spec-factory.d.ts.map +1 -1
  323. package/dist/openapi/spec-factory.js +52 -0
  324. package/dist/openapi/spec-factory.js.map +1 -0
  325. package/dist/openapi/spec.d.ts +14 -5
  326. package/dist/openapi/spec.d.ts.map +1 -1
  327. package/dist/openapi/spec.js +50 -0
  328. package/dist/openapi/spec.js.map +1 -0
  329. package/dist/openapi/swagger.d.ts +3 -1
  330. package/dist/openapi/swagger.d.ts.map +1 -1
  331. package/dist/openapi/swagger.js +22 -0
  332. package/dist/openapi/swagger.js.map +1 -0
  333. package/dist/pattern.d.ts +71 -0
  334. package/dist/pattern.d.ts.map +1 -0
  335. package/dist/pattern.js +239 -0
  336. package/dist/pattern.js.map +1 -0
  337. package/dist/peer.d.ts +17 -0
  338. package/dist/peer.d.ts.map +1 -0
  339. package/dist/peer.js +50 -0
  340. package/dist/peer.js.map +1 -0
  341. package/dist/plugin.d.ts +67 -16
  342. package/dist/plugin.d.ts.map +1 -1
  343. package/dist/plugin.js +649 -0
  344. package/dist/plugin.js.map +1 -0
  345. package/dist/powered-by.d.ts.map +1 -1
  346. package/dist/powered-by.js +11 -0
  347. package/dist/powered-by.js.map +1 -0
  348. package/dist/pretty-json.d.ts.map +1 -1
  349. package/dist/pretty-json.js +47 -0
  350. package/dist/pretty-json.js.map +1 -0
  351. package/dist/producer-stream.d.ts +47 -0
  352. package/dist/producer-stream.d.ts.map +1 -0
  353. package/dist/producer-stream.js +267 -0
  354. package/dist/producer-stream.js.map +1 -0
  355. package/dist/proxy.d.ts +47 -8
  356. package/dist/proxy.d.ts.map +1 -1
  357. package/dist/proxy.js +274 -0
  358. package/dist/proxy.js.map +1 -0
  359. package/dist/python-type-emitter.d.ts +14 -1
  360. package/dist/python-type-emitter.d.ts.map +1 -1
  361. package/dist/python-type-emitter.js +157 -0
  362. package/dist/python-type-emitter.js.map +1 -0
  363. package/dist/realtime/bus.d.ts +17 -1
  364. package/dist/realtime/bus.d.ts.map +1 -1
  365. package/dist/realtime/bus.js +112 -0
  366. package/dist/realtime/bus.js.map +1 -0
  367. package/dist/realtime/register.d.ts +3 -0
  368. package/dist/realtime/register.d.ts.map +1 -0
  369. package/dist/realtime/register.js +10 -0
  370. package/dist/realtime/register.js.map +1 -0
  371. package/dist/realtime/route.d.ts +65 -26
  372. package/dist/realtime/route.d.ts.map +1 -1
  373. package/dist/realtime/route.js +72 -0
  374. package/dist/realtime/route.js.map +1 -0
  375. package/dist/realtime/server.d.ts +43 -0
  376. package/dist/realtime/server.d.ts.map +1 -0
  377. package/dist/realtime/server.js +255 -0
  378. package/dist/realtime/server.js.map +1 -0
  379. package/dist/request-id.d.ts +7 -0
  380. package/dist/request-id.d.ts.map +1 -1
  381. package/dist/request-id.js +16 -0
  382. package/dist/request-id.js.map +1 -0
  383. package/dist/request-limits.d.ts +3 -0
  384. package/dist/request-limits.d.ts.map +1 -0
  385. package/dist/request-limits.js +3 -0
  386. package/dist/request-limits.js.map +1 -0
  387. package/dist/request-path.d.ts +33 -0
  388. package/dist/request-path.d.ts.map +1 -0
  389. package/dist/request-path.js +178 -0
  390. package/dist/request-path.js.map +1 -0
  391. package/dist/request-to-curl.d.ts +7 -1
  392. package/dist/request-to-curl.d.ts.map +1 -1
  393. package/dist/request-to-curl.js +48 -0
  394. package/dist/request-to-curl.js.map +1 -0
  395. package/dist/response.d.ts +25 -2
  396. package/dist/response.d.ts.map +1 -1
  397. package/dist/response.js +313 -0
  398. package/dist/response.js.map +1 -0
  399. package/dist/rust-type-emitter.d.ts +14 -2
  400. package/dist/rust-type-emitter.d.ts.map +1 -1
  401. package/dist/rust-type-emitter.js +463 -0
  402. package/dist/rust-type-emitter.js.map +1 -0
  403. package/dist/secure-headers.d.ts.map +1 -1
  404. package/dist/secure-headers.js +53 -0
  405. package/dist/secure-headers.js.map +1 -0
  406. package/dist/serve-register.d.ts +4 -0
  407. package/dist/serve-register.d.ts.map +1 -1
  408. package/dist/serve-register.js +9 -0
  409. package/dist/serve-register.js.map +1 -0
  410. package/dist/serve-slot.d.ts +3 -0
  411. package/dist/serve-slot.d.ts.map +1 -1
  412. package/dist/serve-slot.js +52 -0
  413. package/dist/serve-slot.js.map +1 -0
  414. package/dist/serve.d.ts +18 -1
  415. package/dist/serve.d.ts.map +1 -1
  416. package/dist/serve.js +157 -0
  417. package/dist/serve.js.map +1 -0
  418. package/dist/server-timing.d.ts.map +1 -1
  419. package/dist/server-timing.js +51 -0
  420. package/dist/server-timing.js.map +1 -0
  421. package/dist/static.d.ts +9 -0
  422. package/dist/static.d.ts.map +1 -1
  423. package/dist/static.js +102 -0
  424. package/dist/static.js.map +1 -0
  425. package/dist/telemetry/otel.d.ts +2 -0
  426. package/dist/telemetry/otel.d.ts.map +1 -1
  427. package/dist/telemetry/otel.js +135 -0
  428. package/dist/telemetry/otel.js.map +1 -0
  429. package/dist/testing.d.ts +12 -0
  430. package/dist/testing.d.ts.map +1 -1
  431. package/dist/testing.js +124 -0
  432. package/dist/testing.js.map +1 -0
  433. package/dist/timeout.d.ts +6 -0
  434. package/dist/timeout.d.ts.map +1 -1
  435. package/dist/timeout.js +36 -0
  436. package/dist/timeout.js.map +1 -0
  437. package/dist/tree.d.ts +133 -36
  438. package/dist/tree.d.ts.map +1 -1
  439. package/dist/tree.js +437 -0
  440. package/dist/tree.js.map +1 -0
  441. package/dist/trust.d.ts +21 -0
  442. package/dist/trust.d.ts.map +1 -0
  443. package/dist/trust.js +100 -0
  444. package/dist/trust.js.map +1 -0
  445. package/dist/ts-type-emitter.d.ts.map +1 -1
  446. package/dist/ts-type-emitter.js +150 -0
  447. package/dist/ts-type-emitter.js.map +1 -0
  448. package/dist/type-emitter.d.ts +16 -2
  449. package/dist/type-emitter.d.ts.map +1 -1
  450. package/dist/type-emitter.js +729 -0
  451. package/dist/type-emitter.js.map +1 -0
  452. package/dist/type-extractor.d.ts +8 -4
  453. package/dist/type-extractor.d.ts.map +1 -1
  454. package/dist/type-extractor.js +776 -0
  455. package/dist/type-extractor.js.map +1 -0
  456. package/dist/types.d.ts +7 -0
  457. package/dist/types.d.ts.map +1 -1
  458. package/dist/types.js +96 -0
  459. package/dist/types.js.map +1 -0
  460. package/dist/validation.d.ts +14 -2
  461. package/dist/validation.d.ts.map +1 -1
  462. package/dist/validation.js +335 -0
  463. package/dist/validation.js.map +1 -0
  464. package/dist/with-headers.d.ts +15 -0
  465. package/dist/with-headers.d.ts.map +1 -0
  466. package/dist/with-headers.js +45 -0
  467. package/dist/with-headers.js.map +1 -0
  468. package/dist/ws/bun.d.ts +11 -5
  469. package/dist/ws/bun.d.ts.map +1 -1
  470. package/dist/ws/bun.js +82 -0
  471. package/dist/ws/bun.js.map +1 -0
  472. package/dist/ws/cloudflare.d.ts +25 -3
  473. package/dist/ws/cloudflare.d.ts.map +1 -1
  474. package/dist/ws/cloudflare.js +117 -0
  475. package/dist/ws/cloudflare.js.map +1 -0
  476. package/dist/ws/deno.d.ts +4 -4
  477. package/dist/ws/deno.d.ts.map +1 -1
  478. package/dist/ws/deno.js +133 -0
  479. package/dist/ws/deno.js.map +1 -0
  480. package/dist/ws/node.d.ts +20 -3
  481. package/dist/ws/node.d.ts.map +1 -1
  482. package/dist/ws/node.js +173 -0
  483. package/dist/ws/node.js.map +1 -0
  484. package/dist/ws/session.d.ts +11 -0
  485. package/dist/ws/session.d.ts.map +1 -0
  486. package/dist/ws/session.js +60 -0
  487. package/dist/ws/session.js.map +1 -0
  488. package/dist/ws/shared.d.ts +65 -0
  489. package/dist/ws/shared.d.ts.map +1 -0
  490. package/dist/ws/shared.js +103 -0
  491. package/dist/ws/shared.js.map +1 -0
  492. package/dist/ws-origin.d.ts +20 -0
  493. package/dist/ws-origin.d.ts.map +1 -0
  494. package/dist/ws-origin.js +41 -0
  495. package/dist/ws-origin.js.map +1 -0
  496. package/dist/yaml.d.ts +15 -1
  497. package/dist/yaml.d.ts.map +1 -1
  498. package/dist/yaml.js +101 -0
  499. package/dist/yaml.js.map +1 -0
  500. package/docs/invalidate-spec.md +13 -1
  501. package/docs/meta-spec.md +36 -12
  502. package/docs/packaging.md +43 -24
  503. package/docs/regression-matrix/README.md +32 -0
  504. package/docs/regression-matrix/review.md +44 -0
  505. package/docs/regression-matrix/ws1-3.md +97 -0
  506. package/docs/regression-matrix/ws4-8.md +107 -0
  507. package/docs/regression-matrix/ws9-12.md +266 -0
  508. package/docs/sdk.md +102 -52
  509. package/package.json +183 -52
  510. package/src/accepts.ts +91 -33
  511. package/src/body-kind.ts +67 -0
  512. package/src/body-limit.ts +102 -87
  513. package/src/build/index.ts +104 -54
  514. package/src/cli-args.ts +123 -0
  515. package/src/cli-go/auth.go +12 -1
  516. package/src/cli-go/config.go +29 -2
  517. package/src/cli-go/errors.go +28 -10
  518. package/src/cli-go/multipart.go +51 -27
  519. package/src/cli-go/output.go +58 -4
  520. package/src/cli-go/root.go +1 -1
  521. package/src/cli-go/version.go +2 -2
  522. package/src/cli.ts +154 -148
  523. package/src/client/error.ts +56 -1
  524. package/src/client/http.ts +479 -256
  525. package/src/client/index.ts +55 -17
  526. package/src/client/path.ts +169 -0
  527. package/src/client/redirect-policy.ts +19 -0
  528. package/src/client/sdk.ts +180 -101
  529. package/src/client/sse.ts +92 -66
  530. package/src/client/ws.ts +67 -31
  531. package/src/client-go/errors.go +41 -12
  532. package/src/client-go/export.go +44 -0
  533. package/src/client-go/invalidation.go +52 -54
  534. package/src/client-go/nullable.go +62 -0
  535. package/src/client-go/realtime.go +147 -110
  536. package/src/client-go/runtime.go +646 -88
  537. package/src/client-go/sse.go +104 -94
  538. package/src/client-go/transport.go +67 -27
  539. package/src/client-go/ws.go +49 -25
  540. package/src/client-info.ts +79 -0
  541. package/src/client-mcp/server.ts +133 -3
  542. package/src/client-python/_invalidation.py +207 -291
  543. package/src/client-python/_realtime.py +63 -40
  544. package/src/client-python/_runtime.py +501 -119
  545. package/src/client-python/_sse.py +130 -74
  546. package/src/client-python/_transport.py +37 -9
  547. package/src/client-python/_ws.py +50 -22
  548. package/src/client-rust/errors.rs +21 -1
  549. package/src/client-rust/invalidation.rs +202 -231
  550. package/src/client-rust/invalidation_sync.rs +16 -229
  551. package/src/client-rust/nullable.rs +17 -0
  552. package/src/client-rust/realtime.rs +217 -217
  553. package/src/client-rust/runtime.rs +602 -177
  554. package/src/client-rust/runtime_sync.rs +169 -145
  555. package/src/client-rust/sse.rs +142 -121
  556. package/src/client-rust/ws.rs +61 -37
  557. package/src/codegen-go-cli.ts +607 -728
  558. package/src/codegen-go.ts +710 -770
  559. package/src/codegen-ir.ts +381 -75
  560. package/src/codegen-lang.ts +517 -0
  561. package/src/codegen-load.ts +150 -0
  562. package/src/codegen-mcp.ts +207 -108
  563. package/src/codegen-python.ts +684 -816
  564. package/src/codegen-route-tree-intern.ts +51 -25
  565. package/src/codegen-rust.ts +946 -1240
  566. package/src/codegen-sanitize.ts +0 -4
  567. package/src/codegen-schema-naming.ts +19 -6
  568. package/src/codegen-sdk-model.ts +228 -0
  569. package/src/codegen.ts +1488 -1140
  570. package/src/context.ts +130 -11
  571. package/src/cookie-sign.ts +85 -16
  572. package/src/cookie.ts +66 -11
  573. package/src/cors.ts +55 -54
  574. package/src/crypto.ts +27 -5
  575. package/src/csrf.ts +57 -25
  576. package/src/curl-logger.ts +155 -114
  577. package/src/dict.ts +12 -0
  578. package/src/error.ts +4 -2
  579. package/src/etag.ts +58 -34
  580. package/src/feature-detect.ts +147 -0
  581. package/src/feature-slots.ts +70 -0
  582. package/src/fetch-request.ts +13 -0
  583. package/src/gen-process.ts +42 -0
  584. package/src/gen-write.ts +127 -0
  585. package/src/glob.ts +109 -0
  586. package/src/go-type-emitter.ts +406 -155
  587. package/src/honey-response.ts +36 -9
  588. package/src/i18n-slot.ts +10 -0
  589. package/src/i18n.ts +98 -23
  590. package/src/index.ts +1893 -1761
  591. package/src/init.ts +40 -28
  592. package/src/invalidate-check.ts +42 -4
  593. package/src/invoke-user.ts +95 -0
  594. package/src/ip-restrict.ts +47 -161
  595. package/src/ip.ts +194 -0
  596. package/src/logger.ts +65 -36
  597. package/src/media-type.ts +104 -0
  598. package/src/meta-spec-merge.ts +80 -0
  599. package/src/meta-spec.ts +0 -0
  600. package/src/middleware.ts +112 -12
  601. package/src/node-request.ts +242 -52
  602. package/src/node.ts +318 -75
  603. package/src/openapi/collect.ts +19 -44
  604. package/src/openapi/docs-page.ts +89 -0
  605. package/src/openapi/document.ts +503 -224
  606. package/src/openapi/json-schema-slot.ts +40 -0
  607. package/src/openapi/register.ts +7 -2
  608. package/src/openapi/scalar.ts +11 -10
  609. package/src/openapi/serve.ts +39 -0
  610. package/src/openapi/spec-factory.ts +50 -1
  611. package/src/openapi/spec.ts +53 -30
  612. package/src/openapi/swagger.ts +12 -11
  613. package/src/pattern.ts +245 -0
  614. package/src/peer.ts +53 -0
  615. package/src/plugin.ts +270 -185
  616. package/src/powered-by.ts +2 -2
  617. package/src/pretty-json.ts +25 -9
  618. package/src/producer-stream.ts +296 -0
  619. package/src/proxy.ts +271 -55
  620. package/src/python-type-emitter.ts +68 -56
  621. package/src/realtime/bus.ts +56 -9
  622. package/src/realtime/register.ts +13 -0
  623. package/src/realtime/route.ts +129 -80
  624. package/src/realtime/server.ts +298 -0
  625. package/src/request-id.ts +13 -3
  626. package/src/request-limits.ts +2 -0
  627. package/src/request-path.ts +165 -0
  628. package/src/request-to-curl.ts +28 -7
  629. package/src/response.ts +143 -103
  630. package/src/rust-type-emitter.ts +265 -170
  631. package/src/secure-headers.ts +8 -4
  632. package/src/serve-register.ts +4 -0
  633. package/src/serve-slot.ts +38 -0
  634. package/src/serve.ts +113 -25
  635. package/src/server-timing.ts +11 -7
  636. package/src/static.ts +85 -32
  637. package/src/telemetry/otel.ts +29 -7
  638. package/src/testing.ts +76 -14
  639. package/src/timeout.ts +15 -7
  640. package/src/tree.ts +405 -333
  641. package/src/trust.ts +117 -0
  642. package/src/ts-type-emitter.ts +18 -12
  643. package/src/type-emitter.ts +227 -89
  644. package/src/type-extractor.ts +562 -424
  645. package/src/types.ts +8 -0
  646. package/src/validation.ts +221 -96
  647. package/src/with-headers.ts +45 -0
  648. package/src/ws/bun.ts +53 -15
  649. package/src/ws/cloudflare.ts +81 -19
  650. package/src/ws/deno.ts +124 -36
  651. package/src/ws/node.ts +173 -79
  652. package/src/ws/session.ts +73 -0
  653. package/src/ws/shared.ts +140 -0
  654. package/src/ws-origin.ts +53 -0
  655. package/src/yaml.ts +45 -22
  656. package/dist/client-mcp/server.d.ts +0 -10
  657. package/dist/client-mcp/server.d.ts.map +0 -1
  658. package/dist/client-mcp/types.d.ts +0 -16
  659. package/dist/client-mcp/types.d.ts.map +0 -1
  660. package/dist/cloudflare/realtime.d.ts +0 -30
  661. package/dist/cloudflare/realtime.d.ts.map +0 -1
  662. package/dist/realtime/buffer.d.ts +0 -18
  663. package/dist/realtime/buffer.d.ts.map +0 -1
  664. package/dist/realtime/longpoll.d.ts +0 -23
  665. package/dist/realtime/longpoll.d.ts.map +0 -1
  666. package/dist/realtime/protocol.d.ts +0 -50
  667. package/dist/realtime/protocol.d.ts.map +0 -1
  668. package/dist/realtime/runtime.d.ts +0 -74
  669. package/dist/realtime/runtime.d.ts.map +0 -1
  670. package/src/cloudflare/realtime.ts +0 -234
  671. package/src/realtime/buffer.ts +0 -101
  672. package/src/realtime/longpoll.ts +0 -148
  673. package/src/realtime/protocol.ts +0 -128
  674. package/src/realtime/runtime.ts +0 -427
package/src/client/sdk.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { ClientConfig, RequestMeta } from "./http.ts"
2
- import { HTTPClient, interpolatePath } from "./http.ts"
2
+ import { HTTPClient } from "./http.ts"
3
+ import { compilePattern, hasPlaceholder, interpolatePartial, interpolatePath } from "./path.ts"
3
4
  import { createTypedWebSocket } from "./ws.ts"
4
5
 
5
6
  type ServiceEntry = {
@@ -27,57 +28,147 @@ function bridge<T>(value: object): T {
27
28
  return value as T
28
29
  }
29
30
 
30
- /* convert OpenAPI {param} to :param for HTTPClient */
31
- function toColonParams(path: string): string {
32
- return path.replace(/\{(\w+)\}/g, ":$1")
31
+ function own<T>(record: Record<string, T>, key: string): T | undefined {
32
+ return Object.hasOwn(record, key) ? record[key] : undefined
33
33
  }
34
34
 
35
- /* resolve invalidation targets by substituting mutation params */
35
+ /**
36
+ * Resolve invalidation targets by substituting the mutation's params. Params that are absent
37
+ * stay placeholders, so a partially resolved target is a narrower pattern, never dropped:
38
+ * `PUT /orgs/{org}` invalidating `GET /orgs/:org/members/:id` marks `GET /orgs/acme/members/:id`.
39
+ */
36
40
  export function resolveInvalidationTargets(
37
41
  targets: readonly string[],
38
42
  params: Record<string, string> | undefined,
39
43
  ): string[] {
40
44
  const resolved: string[] = []
41
45
  for (const target of targets) {
42
- if (!params || !target.includes(":")) {
46
+ const spaceIdx = target.indexOf(" ")
47
+ if (spaceIdx === -1 || !params) {
43
48
  resolved.push(target)
44
49
  continue
45
50
  }
46
- const spaceIdx = target.indexOf(" ")
47
51
  const targetMethod = target.slice(0, spaceIdx)
48
52
  const targetPath = target.slice(spaceIdx + 1)
49
- let hasUnresolved = false
50
- const replaced = targetPath.replace(/:(\w+)/g, (match, key: string) => {
51
- const val = params[key]
52
- if (val === undefined) {
53
- hasUnresolved = true
54
- return match
55
- }
56
- return encodeURIComponent(val)
57
- })
58
- if (hasUnresolved) continue
59
- resolved.push(`${targetMethod} ${replaced}`)
53
+ try {
54
+ resolved.push(`${targetMethod} ${interpolatePartial(targetPath, params)}`)
55
+ } catch {
56
+ /* a param value that is not a path segment cannot address a resource; keep the pattern */
57
+ resolved.push(target)
58
+ }
60
59
  }
61
60
  return resolved
62
61
  }
63
62
 
64
- /* cache compiled pattern regexes — hot path for invalidation lookups */
65
- const patternRegexCache = new Map<string, RegExp>()
66
-
67
- /* test if a concrete path matches a route pattern; escapes regex metacharacters in the pattern */
63
+ /** Test if a concrete path matches a route pattern (`:name`, `{name}`, `*`); literal text is escaped. */
68
64
  export function pathMatchesPattern(concretePath: string, pattern: string): boolean {
69
- let re = patternRegexCache.get(pattern)
70
- if (!re) {
71
- /* split on :param placeholders, escape each literal segment's metachars, rejoin with [^/]+ */
72
- const parts = pattern.split(/:[^/]+/g)
73
- const escaped = parts.map((p) => p.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("[^/]+")
74
- re = new RegExp(`^${escaped}$`)
75
- patternRegexCache.set(pattern, re)
65
+ return compilePattern(pattern).test(concretePath)
66
+ }
67
+
68
+ /* Bound memory: an entry remembers the last N mutations that marked it, and which concrete
69
+ paths have already refreshed against a pattern-level mark. */
70
+ const MAX_INVALIDATED_BY = 32
71
+ const MAX_REFRESHED = 1024
72
+
73
+ type StaleEntry = {
74
+ by: Set<string>
75
+ /** Concrete paths that have read once since this pattern was marked (pattern entries only). */
76
+ refreshed?: Set<string>
77
+ seq: number
78
+ until: number
79
+ }
80
+
81
+ /**
82
+ * Stale marks, split by kind so a concrete key is never re-read as a pattern (a path may
83
+ * contain `:`), and a lookup scans only patterns for its own method.
84
+ */
85
+ export class StaleIndex {
86
+ readonly exact = new Map<string, StaleEntry>()
87
+ readonly patterns = new Map<string, Map<string, StaleEntry>>()
88
+
89
+ mark(target: string, mutation: string, seq: number, until: number): void {
90
+ const spaceIdx = target.indexOf(" ")
91
+ const method = target.slice(0, spaceIdx)
92
+ const path = target.slice(spaceIdx + 1)
93
+ const isPattern = hasPlaceholder(path)
94
+ let table: Map<string, StaleEntry>
95
+ if (isPattern) {
96
+ table = this.patterns.get(method) ?? new Map()
97
+ this.patterns.set(method, table)
98
+ } else {
99
+ table = this.exact
100
+ }
101
+ const existing = table.get(target)
102
+ if (existing) {
103
+ existing.by.delete(mutation)
104
+ existing.by.add(mutation)
105
+ if (existing.by.size > MAX_INVALIDATED_BY) {
106
+ const oldest = existing.by.values().next().value
107
+ if (oldest !== undefined) existing.by.delete(oldest)
108
+ }
109
+ existing.until = until
110
+ existing.seq = seq
111
+ /* a new mutation re-marks every instance */
112
+ if (existing.refreshed) existing.refreshed.clear()
113
+ } else {
114
+ table.set(target, { by: new Set([mutation]), refreshed: isPattern ? new Set() : undefined, seq, until })
115
+ }
116
+ }
117
+
118
+ lookup(
119
+ concreteSelector: string,
120
+ concretePath: string,
121
+ method: string,
122
+ now: number,
123
+ ): { by: string[]; isStale: boolean } {
124
+ const by = new Set<string>()
125
+ const exact = this.exact.get(concreteSelector)
126
+ if (exact) {
127
+ if (exact.until > now) for (const m of exact.by) by.add(m)
128
+ else this.exact.delete(concreteSelector)
129
+ }
130
+ const table = this.patterns.get(method)
131
+ if (table) {
132
+ for (const [key, entry] of table) {
133
+ if (entry.until <= now) {
134
+ table.delete(key)
135
+ continue
136
+ }
137
+ if (entry.refreshed?.has(concretePath)) continue
138
+ if (pathMatchesPattern(concretePath, key.slice(key.indexOf(" ") + 1))) {
139
+ for (const m of entry.by) by.add(m)
140
+ }
141
+ }
142
+ }
143
+ return { by: [...by], isStale: by.size > 0 }
144
+ }
145
+
146
+ /**
147
+ * A successful stale read clears the mark for that resource only: the exact entry, and this
148
+ * concrete path's share of any pattern entry. Marks newer than the read's snapshot stay.
149
+ */
150
+ clear(concreteSelector: string, concretePath: string, method: string, snapshot: number): void {
151
+ const exact = this.exact.get(concreteSelector)
152
+ if (exact && exact.seq <= snapshot) this.exact.delete(concreteSelector)
153
+ const table = this.patterns.get(method)
154
+ if (!table) return
155
+ for (const [key, entry] of table) {
156
+ if (entry.seq > snapshot || !entry.refreshed) continue
157
+ if (!pathMatchesPattern(concretePath, key.slice(key.indexOf(" ") + 1))) continue
158
+ if (entry.refreshed.size >= MAX_REFRESHED) {
159
+ const oldest = entry.refreshed.values().next().value
160
+ if (oldest !== undefined) entry.refreshed.delete(oldest)
161
+ }
162
+ entry.refreshed.add(concretePath)
163
+ }
76
164
  }
77
- return re.test(concretePath)
78
165
  }
79
166
 
80
- /* two-tier stale lookup: exact concrete match, then pattern fallback; sweeps expired entries in one pass */
167
+ /**
168
+ * Two-tier stale lookup over a flat map (kept for compatibility): exact concrete match, then
169
+ * pattern entries for the same method. Keys are classified by their template placeholders,
170
+ * not by containing `:`. Expired entries are swept.
171
+ */
81
172
  export function lookupStale(
82
173
  staleMap: Map<string, { by: string[]; seq: number; until: number }>,
83
174
  concreteSelector: string,
@@ -85,30 +176,33 @@ export function lookupStale(
85
176
  method: string,
86
177
  now: number,
87
178
  ): { by: string[]; isStale: boolean } {
88
- const allBy: string[] = []
89
- const expired: string[] = []
90
-
91
- const exact = staleMap.get(concreteSelector)
92
- if (exact && exact.until > now) allBy.push(...exact.by)
93
- else if (exact) expired.push(concreteSelector)
94
-
179
+ const allBy = new Set<string>()
95
180
  for (const [key, entry] of staleMap) {
96
181
  if (entry.until <= now) {
97
- expired.push(key)
182
+ staleMap.delete(key)
183
+ continue
184
+ }
185
+ if (key === concreteSelector) {
186
+ for (const m of entry.by) allBy.add(m)
98
187
  continue
99
188
  }
100
- if (!key.includes(":")) continue
101
189
  const spaceIdx = key.indexOf(" ")
102
- const keyMethod = key.slice(0, spaceIdx)
190
+ if (key.slice(0, spaceIdx) !== method) continue
103
191
  const keyPattern = key.slice(spaceIdx + 1)
104
- if (keyMethod !== method) continue
105
- if (pathMatchesPattern(concretePath, keyPattern)) {
106
- allBy.push(...entry.by)
192
+ if (hasPlaceholder(keyPattern) && pathMatchesPattern(concretePath, keyPattern)) {
193
+ for (const m of entry.by) allBy.add(m)
107
194
  }
108
195
  }
109
- for (const key of expired) staleMap.delete(key)
196
+ return { by: [...allBy], isStale: allBy.size > 0 }
197
+ }
110
198
 
111
- return { by: [...new Set(allBy)], isStale: allBy.length > 0 }
199
+ function isServiceEntry(node: unknown): node is ServiceEntry {
200
+ return (
201
+ typeof node === "object" &&
202
+ node !== null &&
203
+ typeof (node as Record<string, unknown>)["method"] === "string" &&
204
+ typeof (node as Record<string, unknown>)["path"] === "string"
205
+ )
112
206
  }
113
207
 
114
208
  export function createSDK<T = Record<string, Record<string, (...args: unknown[]) => unknown>>>(
@@ -117,15 +211,15 @@ export function createSDK<T = Record<string, Record<string, (...args: unknown[])
117
211
  ): T {
118
212
  const http = new HTTPClient(config)
119
213
  const staleTime = config.invalidation?.staleTime ?? 0
120
- const hasInvalidation = staleTime > 0
121
- const staleUntil = hasInvalidation ? new Map<string, { by: string[]; seq: number; until: number }>() : null
214
+ const stale = staleTime > 0 ? new StaleIndex() : null
122
215
 
123
216
  let invalidationSeq = 0
124
217
 
125
218
  const rootCache = new Map<string, object>()
126
219
 
127
220
  function buildLeafFn(entry: ServiceEntry, namePath: string[]): Function {
128
- const path = toColonParams(entry.path)
221
+ /* Paths keep their template; HTTPClient interpolates `{name}` and `:name` alike. */
222
+ const path = entry.path
129
223
  const method = entry.method
130
224
  let fn: Function
131
225
 
@@ -151,13 +245,12 @@ export function createSDK<T = Record<string, Record<string, (...args: unknown[])
151
245
  fn = async (input?: Record<string, unknown>) => {
152
246
  const opts = input ?? {}
153
247
  const params = opts["params"] as Record<string, string> | undefined
154
- const concretePath = params ? interpolatePath(path, params) : path
248
+ const concretePath = interpolatePath(path, params ?? {})
155
249
  const concreteSelector = `${method} ${concretePath}`
156
250
  let requestMeta: RequestMeta | undefined
157
251
 
158
- if (staleUntil) {
159
- const now = Date.now()
160
- const { by, isStale } = lookupStale(staleUntil, concreteSelector, concretePath, method, now)
252
+ if (stale) {
253
+ const { by, isStale } = stale.lookup(concreteSelector, concretePath, method, Date.now())
161
254
  requestMeta = { invalidatedBy: by, isStale, selector: concreteSelector, seqSnapshot: invalidationSeq }
162
255
  }
163
256
 
@@ -166,7 +259,7 @@ export function createSDK<T = Record<string, Record<string, (...args: unknown[])
166
259
  ? await http.request(method, path, opts, requestMeta)
167
260
  : await http.requestSafe(method, path, opts, requestMeta)
168
261
 
169
- if (staleUntil) {
262
+ if (stale) {
170
263
  const isSuccess =
171
264
  config.throwOnError === true
172
265
  ? true
@@ -176,34 +269,13 @@ export function createSDK<T = Record<string, Record<string, (...args: unknown[])
176
269
  if (entry.invalidate && entry.invalidate.length > 0) {
177
270
  const seq = ++invalidationSeq
178
271
  const until = Date.now() + staleTime
179
- const mutationSelector = concreteSelector
180
- const resolved = resolveInvalidationTargets(entry.invalidate, params)
181
- for (const target of resolved) {
182
- const existing = staleUntil.get(target)
183
- if (existing) {
184
- if (!existing.by.includes(mutationSelector)) existing.by.push(mutationSelector)
185
- existing.until = until
186
- existing.seq = seq
187
- } else {
188
- staleUntil.set(target, { by: [mutationSelector], seq, until })
189
- }
272
+ for (const target of resolveInvalidationTargets(entry.invalidate, params)) {
273
+ stale.mark(target, concreteSelector, seq, until)
190
274
  }
191
275
  }
192
276
 
193
277
  if (requestMeta?.isStale) {
194
- const snapshot = requestMeta.seqSnapshot
195
- const exact = staleUntil.get(concreteSelector)
196
- if (exact && exact.seq <= snapshot) staleUntil.delete(concreteSelector)
197
- const toDelete: string[] = []
198
- for (const [key, staleEntry] of staleUntil) {
199
- if (staleEntry.seq > snapshot) continue
200
- if (!key.includes(":")) continue
201
- const spaceIdx = key.indexOf(" ")
202
- const keyMethod = key.slice(0, spaceIdx)
203
- const keyPattern = key.slice(spaceIdx + 1)
204
- if (keyMethod === method && pathMatchesPattern(concretePath, keyPattern)) toDelete.push(key)
205
- }
206
- for (const key of toDelete) staleUntil.delete(key)
278
+ stale.clear(concreteSelector, concretePath, method, requestMeta.seqSnapshot)
207
279
  }
208
280
  }
209
281
  }
@@ -216,27 +288,39 @@ export function createSDK<T = Record<string, Record<string, (...args: unknown[])
216
288
  return fn
217
289
  }
218
290
 
291
+ /** Own keys only: names like `toString` or `constructor` must not resolve through the prototype. */
292
+ function resolveChild(node: Record<string, unknown>, key: string | symbol, namePath: string[]): unknown {
293
+ if (typeof key === "symbol" || key === "then") return undefined
294
+ const child = own(node, key)
295
+ if (child === undefined) {
296
+ if (key === "toString" || key === "toJSON")
297
+ return () => `[object HoneySDK${namePath.length ? ` ${namePath.join(".")}` : ""}]`
298
+ return undefined
299
+ }
300
+ return child
301
+ }
302
+
219
303
  function makeNodeProxy(node: ServiceMapNode, namePath: string[]): object {
220
304
  const actionCache = new Map<string, Function>()
221
305
  const childCache = new Map<string, object>()
222
306
  return new Proxy({} as Record<string, unknown>, {
223
307
  get(_, key: string | symbol) {
224
- if (typeof key === "symbol") return undefined
225
- const child = (node as Record<string, unknown>)[key]
226
- if (child === undefined) return undefined
308
+ const child = resolveChild(node as Record<string, unknown>, key, namePath)
309
+ if (child === undefined || typeof child === "function") return child
310
+ const name = key as string
227
311
 
228
- if (typeof (child as Record<string, unknown>)["method"] === "string") {
229
- const cached = actionCache.get(key)
312
+ if (isServiceEntry(child)) {
313
+ const cached = actionCache.get(name)
230
314
  if (cached) return cached
231
- const fn = buildLeafFn(child as ServiceEntry, [...namePath, key])
232
- actionCache.set(key, fn)
315
+ const fn = buildLeafFn(child, [...namePath, name])
316
+ actionCache.set(name, fn)
233
317
  return fn
234
318
  }
235
319
 
236
- const cached = childCache.get(key)
320
+ const cached = childCache.get(name)
237
321
  if (cached) return cached
238
- const childProxy = makeNodeProxy(child as ServiceMapNode, [...namePath, key])
239
- childCache.set(key, childProxy)
322
+ const childProxy = makeNodeProxy(child as ServiceMapNode, [...namePath, name])
323
+ childCache.set(name, childProxy)
240
324
  return childProxy
241
325
  },
242
326
  })
@@ -247,23 +331,18 @@ export function createSDK<T = Record<string, Record<string, (...args: unknown[])
247
331
  {},
248
332
  {
249
333
  get(_target, key: string | symbol) {
250
- if (typeof key === "symbol") return undefined
334
+ const node = resolveChild(serviceMap as Record<string, unknown>, key, [])
335
+ if (node === undefined || typeof node === "function") return node
336
+ const name = key as string
251
337
 
252
- const cached = rootCache.get(key as string)
338
+ const cached = rootCache.get(name)
253
339
  if (cached) return cached
254
340
 
255
- const node = serviceMap[key as string]
256
- if (node === undefined) return undefined
257
-
258
- let result: object
259
- if (typeof (node as Record<string, unknown>)["method"] === "string") {
260
- const fn = buildLeafFn(node as ServiceEntry, [key as string])
261
- result = fn as unknown as object
262
- } else {
263
- result = makeNodeProxy(node, [key as string])
264
- }
341
+ const result = isServiceEntry(node)
342
+ ? (buildLeafFn(node, [name]) as unknown as object)
343
+ : makeNodeProxy(node as ServiceMapNode, [name])
265
344
 
266
- rootCache.set(key as string, result)
345
+ rootCache.set(name, result)
267
346
  return result
268
347
  },
269
348
  },
package/src/client/sse.ts CHANGED
@@ -1,102 +1,128 @@
1
1
  export type SSEEvent = {
2
2
  data: string
3
3
  event?: string
4
+ /** The last event ID (sticky across events, as `EventSource.lastEventId`). Absent while empty. */
4
5
  id?: string
5
6
  retry?: number
6
7
  }
7
8
 
8
- function parseBlock(block: string): SSEEvent | undefined {
9
- const lines = block.split(/\r\n|\r|\n/)
10
- let isComment = true
11
- let data: string | undefined
9
+ const DEFAULT_MAX_BUFFER = 1024 * 1024
10
+
11
+ /**
12
+ * Parse a `text/event-stream` body per the WHATWG HTML "event stream interpretation" rules:
13
+ *
14
+ * - lines end at CRLF, LF or CR (a CR at a chunk boundary waits for a possible LF);
15
+ * - a leading BOM is skipped;
16
+ * - `id` persists across events until changed, and an `id` containing NUL is ignored;
17
+ * - `retry` is accepted only when it is all ASCII digits;
18
+ * - an event still open when the stream ends is discarded, never dispatched.
19
+ *
20
+ * `maxBufferSize` caps both an unterminated line and the data of one event (UTF-16 code
21
+ * units); exceeding it throws.
22
+ */
23
+ export async function* parseSSEStream(
24
+ stream: ReadableStream<Uint8Array>,
25
+ opts?: { maxBufferSize?: number },
26
+ ): AsyncGenerator<SSEEvent, void, undefined> {
27
+ const decoder = new TextDecoder()
28
+ const reader = stream.getReader()
29
+ const maxBuffer = opts?.maxBufferSize ?? DEFAULT_MAX_BUFFER
30
+
31
+ let pending = ""
32
+ let first = true
33
+ let data: string[] = []
34
+ let dataSize = 0
35
+ let hasData = false
12
36
  let event: string | undefined
13
- let id: string | undefined
37
+ let lastId = ""
14
38
  let retry: number | undefined
15
39
 
16
- for (const line of lines) {
17
- if (line.startsWith(":")) continue
18
- isComment = false
19
-
20
- const colonIdx = line.indexOf(":")
21
- let field: string
22
- let val: string
23
- if (colonIdx === -1) {
24
- field = line
25
- val = ""
26
- } else {
27
- field = line.slice(0, colonIdx)
28
- val = line.slice(colonIdx + 1)
29
- if (val.startsWith(" ")) val = val.slice(1)
40
+ const dispatch = (): SSEEvent | undefined => {
41
+ const out = hasData ? ({ data: data.join("\n") } as SSEEvent) : undefined
42
+ if (out) {
43
+ if (event !== undefined && event !== "") out.event = event
44
+ if (lastId !== "") out.id = lastId
45
+ if (retry !== undefined) out.retry = retry
46
+ retry = undefined
30
47
  }
48
+ data = []
49
+ dataSize = 0
50
+ hasData = false
51
+ event = undefined
52
+ return out
53
+ }
31
54
 
55
+ const processLine = (line: string): void => {
56
+ if (line.charCodeAt(0) === 58 /* : */) return
57
+ const colon = line.indexOf(":")
58
+ const field = colon === -1 ? line : line.slice(0, colon)
59
+ let value = colon === -1 ? "" : line.slice(colon + 1)
60
+ if (value.charCodeAt(0) === 32) value = value.slice(1)
32
61
  switch (field) {
33
62
  case "data":
34
- data = data === undefined ? val : `${data}\n${val}`
63
+ dataSize += value.length + 1
64
+ if (dataSize > maxBuffer) throw new Error(`SSE event exceeded ${maxBuffer} characters`)
65
+ data.push(value)
66
+ hasData = true
35
67
  break
36
68
  case "event":
37
- event = val
69
+ event = value
38
70
  break
39
71
  case "id":
40
- /* per spec: id containing null byte must be ignored */
41
- if (!val.includes("\0")) id = val
72
+ if (!value.includes("\0")) lastId = value
42
73
  break
43
- case "retry": {
44
- const n = Number(val)
45
- if (Number.isFinite(n) && n >= 0) retry = n
74
+ case "retry":
75
+ if (/^\d+$/.test(value)) retry = Number(value)
46
76
  break
47
- }
48
77
  }
49
78
  }
50
79
 
51
- if (isComment || data === undefined) return undefined
52
-
53
- const sse: SSEEvent = { data }
54
- if (event !== undefined) sse.event = event
55
- if (id !== undefined) sse.id = id
56
- if (retry !== undefined) sse.retry = retry
57
- return sse
58
- }
59
-
60
- const DEFAULT_MAX_BUFFER = 1024 * 1024
61
-
62
- export async function* parseSSEStream(
63
- stream: ReadableStream<Uint8Array>,
64
- opts?: { maxBufferSize?: number },
65
- ): AsyncGenerator<SSEEvent, void, undefined> {
66
- const decoder = new TextDecoder()
67
- const reader = stream.getReader()
68
- let buffer = ""
69
- const maxBuffer = opts?.maxBufferSize ?? DEFAULT_MAX_BUFFER
70
-
71
80
  try {
72
81
  while (true) {
73
82
  const { done, value } = await reader.read()
74
83
  if (done) break
75
- buffer += decoder.decode(value, { stream: true })
76
-
77
- if (buffer.length > maxBuffer) {
78
- throw new Error(`SSE buffer exceeded ${maxBuffer} characters`)
84
+ pending += decoder.decode(value, { stream: true })
85
+ if (first && pending.length > 0) {
86
+ if (pending.charCodeAt(0) === 0xfeff) pending = pending.slice(1)
87
+ first = false
79
88
  }
80
89
 
81
- /* split on double-newline (any combo of \r\n, \r, \n) */
82
- const blocks = buffer.split(/\r\n\r\n|\r\n\r|\r\n\n|\r\r\n|\n\r\n|\n\r|\r\r|\n\n/)
83
- /* last element is incomplete — keep in buffer */
84
- buffer = blocks.pop() ?? ""
85
-
86
- for (const block of blocks) {
87
- if (block.trim() === "") continue
88
- const event = parseBlock(block)
89
- if (event) yield event
90
+ let start = 0
91
+ while (start < pending.length) {
92
+ let end = start
93
+ while (end < pending.length) {
94
+ const c = pending.charCodeAt(end)
95
+ if (c === 10 || c === 13) break
96
+ end++
97
+ }
98
+ if (end === pending.length) break
99
+ /* A CR as the last character may be the first half of CRLF. */
100
+ if (pending.charCodeAt(end) === 13 && end === pending.length - 1) break
101
+ const line = pending.slice(start, end)
102
+ start = end + (pending.charCodeAt(end) === 13 && pending.charCodeAt(end + 1) === 10 ? 2 : 1)
103
+ if (line === "") {
104
+ const out = dispatch()
105
+ if (out) yield out
106
+ } else {
107
+ processLine(line)
108
+ }
109
+ }
110
+ pending = pending.slice(start)
111
+ if (pending.length > maxBuffer) {
112
+ throw new Error(`SSE buffer exceeded ${maxBuffer} characters`)
90
113
  }
91
114
  }
92
-
93
- /* flush remaining buffer */
94
- if (buffer.trim() !== "") {
95
- const event = parseBlock(buffer)
96
- if (event) yield event
115
+ /* A lone CR held back at the end of the stream still terminates its line. */
116
+ if (pending.endsWith("\r")) {
117
+ const line = pending.slice(0, -1)
118
+ if (line === "") {
119
+ const out = dispatch()
120
+ if (out) yield out
121
+ }
97
122
  }
123
+ /* Anything else still open is an incomplete event: discard it. */
98
124
  } finally {
99
- await reader.cancel()
125
+ await reader.cancel().catch(() => {})
100
126
  reader.releaseLock()
101
127
  }
102
128
  }