pi-cursor-sdk 0.1.47 → 0.1.49

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 (291) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +2 -2
  3. package/node_modules/@connectrpc/connect-node/README.md +141 -0
  4. package/node_modules/@connectrpc/connect-node/dist/cjs/compression.d.ts +15 -0
  5. package/node_modules/@connectrpc/connect-node/dist/cjs/compression.js +89 -0
  6. package/node_modules/@connectrpc/connect-node/dist/cjs/connect-node-adapter.d.ts +42 -0
  7. package/node_modules/@connectrpc/connect-node/dist/cjs/connect-node-adapter.js +61 -0
  8. package/node_modules/@connectrpc/connect-node/dist/cjs/connect-transport.d.ts +100 -0
  9. package/node_modules/@connectrpc/connect-node/dist/cjs/connect-transport.js +25 -0
  10. package/node_modules/@connectrpc/connect-node/dist/cjs/grpc-transport.d.ts +96 -0
  11. package/node_modules/@connectrpc/connect-node/dist/cjs/grpc-transport.js +25 -0
  12. package/node_modules/@connectrpc/connect-node/dist/cjs/grpc-web-transport.d.ts +96 -0
  13. package/node_modules/@connectrpc/connect-node/dist/cjs/grpc-web-transport.js +25 -0
  14. package/node_modules/@connectrpc/connect-node/dist/cjs/http2-session-manager.d.ts +146 -0
  15. package/node_modules/@connectrpc/connect-node/dist/cjs/http2-session-manager.js +536 -0
  16. package/node_modules/@connectrpc/connect-node/dist/cjs/index.d.ts +15 -0
  17. package/node_modules/@connectrpc/connect-node/dist/cjs/index.js +36 -0
  18. package/node_modules/@connectrpc/connect-node/dist/cjs/node-error.d.ts +45 -0
  19. package/node_modules/@connectrpc/connect-node/dist/cjs/node-error.js +154 -0
  20. package/node_modules/@connectrpc/connect-node/dist/cjs/node-headers-polyfill.d.ts +1 -0
  21. package/node_modules/@connectrpc/connect-node/dist/cjs/node-headers-polyfill.js +29 -0
  22. package/node_modules/@connectrpc/connect-node/dist/cjs/node-transport-options.d.ts +89 -0
  23. package/node_modules/@connectrpc/connect-node/dist/cjs/node-transport-options.js +58 -0
  24. package/node_modules/@connectrpc/connect-node/dist/cjs/node-universal-client.d.ts +54 -0
  25. package/node_modules/@connectrpc/connect-node/dist/cjs/node-universal-client.js +326 -0
  26. package/node_modules/@connectrpc/connect-node/dist/cjs/node-universal-handler.d.ts +41 -0
  27. package/node_modules/@connectrpc/connect-node/dist/cjs/node-universal-handler.js +234 -0
  28. package/node_modules/@connectrpc/connect-node/dist/cjs/node-universal-header.d.ts +19 -0
  29. package/node_modules/@connectrpc/connect-node/dist/cjs/node-universal-header.js +97 -0
  30. package/node_modules/@connectrpc/connect-node/dist/cjs/package.json +1 -0
  31. package/node_modules/@connectrpc/connect-node/dist/esm/compression.d.ts +15 -0
  32. package/node_modules/@connectrpc/connect-node/dist/esm/compression.js +86 -0
  33. package/node_modules/@connectrpc/connect-node/dist/esm/connect-node-adapter.d.ts +42 -0
  34. package/node_modules/@connectrpc/connect-node/dist/esm/connect-node-adapter.js +58 -0
  35. package/node_modules/@connectrpc/connect-node/dist/esm/connect-transport.d.ts +100 -0
  36. package/node_modules/@connectrpc/connect-node/dist/esm/connect-transport.js +22 -0
  37. package/node_modules/@connectrpc/connect-node/dist/esm/grpc-transport.d.ts +96 -0
  38. package/node_modules/@connectrpc/connect-node/dist/esm/grpc-transport.js +22 -0
  39. package/node_modules/@connectrpc/connect-node/dist/esm/grpc-web-transport.d.ts +96 -0
  40. package/node_modules/@connectrpc/connect-node/dist/esm/grpc-web-transport.js +22 -0
  41. package/node_modules/@connectrpc/connect-node/dist/esm/http2-session-manager.d.ts +146 -0
  42. package/node_modules/@connectrpc/connect-node/dist/esm/http2-session-manager.js +532 -0
  43. package/node_modules/@connectrpc/connect-node/dist/esm/index.d.ts +15 -0
  44. package/node_modules/@connectrpc/connect-node/dist/esm/index.js +23 -0
  45. package/node_modules/@connectrpc/connect-node/dist/esm/node-error.d.ts +45 -0
  46. package/node_modules/@connectrpc/connect-node/dist/esm/node-error.js +147 -0
  47. package/node_modules/@connectrpc/connect-node/dist/esm/node-headers-polyfill.d.ts +1 -0
  48. package/node_modules/@connectrpc/connect-node/dist/esm/node-headers-polyfill.js +27 -0
  49. package/node_modules/@connectrpc/connect-node/dist/esm/node-transport-options.d.ts +89 -0
  50. package/node_modules/@connectrpc/connect-node/dist/esm/node-transport-options.js +58 -0
  51. package/node_modules/@connectrpc/connect-node/dist/esm/node-universal-client.d.ts +54 -0
  52. package/node_modules/@connectrpc/connect-node/dist/esm/node-universal-client.js +324 -0
  53. package/node_modules/@connectrpc/connect-node/dist/esm/node-universal-handler.d.ts +41 -0
  54. package/node_modules/@connectrpc/connect-node/dist/esm/node-universal-handler.js +230 -0
  55. package/node_modules/@connectrpc/connect-node/dist/esm/node-universal-header.d.ts +19 -0
  56. package/node_modules/@connectrpc/connect-node/dist/esm/node-universal-header.js +93 -0
  57. package/node_modules/@connectrpc/connect-node/package.json +46 -0
  58. package/node_modules/undici/LICENSE +21 -0
  59. package/node_modules/undici/README.md +741 -0
  60. package/node_modules/undici/docs/docs/api/Agent.md +84 -0
  61. package/node_modules/undici/docs/docs/api/BalancedPool.md +99 -0
  62. package/node_modules/undici/docs/docs/api/CacheStorage.md +30 -0
  63. package/node_modules/undici/docs/docs/api/CacheStore.md +164 -0
  64. package/node_modules/undici/docs/docs/api/Client.md +288 -0
  65. package/node_modules/undici/docs/docs/api/ClientStats.md +27 -0
  66. package/node_modules/undici/docs/docs/api/Connector.md +115 -0
  67. package/node_modules/undici/docs/docs/api/ContentType.md +57 -0
  68. package/node_modules/undici/docs/docs/api/Cookies.md +128 -0
  69. package/node_modules/undici/docs/docs/api/Debug.md +62 -0
  70. package/node_modules/undici/docs/docs/api/DiagnosticsChannel.md +315 -0
  71. package/node_modules/undici/docs/docs/api/Dispatcher.md +1392 -0
  72. package/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +159 -0
  73. package/node_modules/undici/docs/docs/api/Errors.md +49 -0
  74. package/node_modules/undici/docs/docs/api/EventSource.md +45 -0
  75. package/node_modules/undici/docs/docs/api/Fetch.md +60 -0
  76. package/node_modules/undici/docs/docs/api/GlobalInstallation.md +139 -0
  77. package/node_modules/undici/docs/docs/api/H2CClient.md +263 -0
  78. package/node_modules/undici/docs/docs/api/MockAgent.md +603 -0
  79. package/node_modules/undici/docs/docs/api/MockCallHistory.md +197 -0
  80. package/node_modules/undici/docs/docs/api/MockCallHistoryLog.md +43 -0
  81. package/node_modules/undici/docs/docs/api/MockClient.md +81 -0
  82. package/node_modules/undici/docs/docs/api/MockErrors.md +12 -0
  83. package/node_modules/undici/docs/docs/api/MockPool.md +555 -0
  84. package/node_modules/undici/docs/docs/api/Pool.md +84 -0
  85. package/node_modules/undici/docs/docs/api/PoolStats.md +35 -0
  86. package/node_modules/undici/docs/docs/api/ProxyAgent.md +229 -0
  87. package/node_modules/undici/docs/docs/api/RedirectHandler.md +93 -0
  88. package/node_modules/undici/docs/docs/api/RetryAgent.md +50 -0
  89. package/node_modules/undici/docs/docs/api/RetryHandler.md +118 -0
  90. package/node_modules/undici/docs/docs/api/RoundRobinPool.md +145 -0
  91. package/node_modules/undici/docs/docs/api/SnapshotAgent.md +616 -0
  92. package/node_modules/undici/docs/docs/api/Socks5ProxyAgent.md +275 -0
  93. package/node_modules/undici/docs/docs/api/Util.md +25 -0
  94. package/node_modules/undici/docs/docs/api/WebSocket.md +141 -0
  95. package/node_modules/undici/docs/docs/api/api-lifecycle.md +91 -0
  96. package/node_modules/undici/docs/docs/best-practices/client-certificate.md +64 -0
  97. package/node_modules/undici/docs/docs/best-practices/crawling.md +58 -0
  98. package/node_modules/undici/docs/docs/best-practices/mocking-request.md +190 -0
  99. package/node_modules/undici/docs/docs/best-practices/proxy.md +127 -0
  100. package/node_modules/undici/docs/docs/best-practices/undici-vs-builtin-fetch.md +224 -0
  101. package/node_modules/undici/docs/docs/best-practices/writing-tests.md +63 -0
  102. package/node_modules/undici/index-fetch.js +65 -0
  103. package/node_modules/undici/index.d.ts +3 -0
  104. package/node_modules/undici/index.js +234 -0
  105. package/node_modules/undici/lib/api/abort-signal.js +59 -0
  106. package/node_modules/undici/lib/api/api-connect.js +110 -0
  107. package/node_modules/undici/lib/api/api-pipeline.js +252 -0
  108. package/node_modules/undici/lib/api/api-request.js +214 -0
  109. package/node_modules/undici/lib/api/api-stream.js +209 -0
  110. package/node_modules/undici/lib/api/api-upgrade.js +111 -0
  111. package/node_modules/undici/lib/api/index.js +7 -0
  112. package/node_modules/undici/lib/api/readable.js +580 -0
  113. package/node_modules/undici/lib/cache/memory-cache-store.js +234 -0
  114. package/node_modules/undici/lib/cache/sqlite-cache-store.js +461 -0
  115. package/node_modules/undici/lib/core/connect.js +153 -0
  116. package/node_modules/undici/lib/core/constants.js +143 -0
  117. package/node_modules/undici/lib/core/diagnostics.js +227 -0
  118. package/node_modules/undici/lib/core/errors.js +477 -0
  119. package/node_modules/undici/lib/core/request.js +453 -0
  120. package/node_modules/undici/lib/core/socks5-client.js +422 -0
  121. package/node_modules/undici/lib/core/socks5-utils.js +212 -0
  122. package/node_modules/undici/lib/core/symbols.js +75 -0
  123. package/node_modules/undici/lib/core/tree.js +160 -0
  124. package/node_modules/undici/lib/core/util.js +992 -0
  125. package/node_modules/undici/lib/dispatcher/agent.js +158 -0
  126. package/node_modules/undici/lib/dispatcher/balanced-pool.js +219 -0
  127. package/node_modules/undici/lib/dispatcher/client-h1.js +1722 -0
  128. package/node_modules/undici/lib/dispatcher/client-h2.js +995 -0
  129. package/node_modules/undici/lib/dispatcher/client.js +664 -0
  130. package/node_modules/undici/lib/dispatcher/dispatcher-base.js +184 -0
  131. package/node_modules/undici/lib/dispatcher/dispatcher.js +48 -0
  132. package/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +146 -0
  133. package/node_modules/undici/lib/dispatcher/fixed-queue.js +135 -0
  134. package/node_modules/undici/lib/dispatcher/h2c-client.js +51 -0
  135. package/node_modules/undici/lib/dispatcher/pool-base.js +214 -0
  136. package/node_modules/undici/lib/dispatcher/pool.js +118 -0
  137. package/node_modules/undici/lib/dispatcher/proxy-agent.js +319 -0
  138. package/node_modules/undici/lib/dispatcher/retry-agent.js +35 -0
  139. package/node_modules/undici/lib/dispatcher/round-robin-pool.js +137 -0
  140. package/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +260 -0
  141. package/node_modules/undici/lib/encoding/index.js +33 -0
  142. package/node_modules/undici/lib/global.js +59 -0
  143. package/node_modules/undici/lib/handler/cache-handler.js +578 -0
  144. package/node_modules/undici/lib/handler/cache-revalidation-handler.js +124 -0
  145. package/node_modules/undici/lib/handler/decorator-handler.js +67 -0
  146. package/node_modules/undici/lib/handler/deduplication-handler.js +460 -0
  147. package/node_modules/undici/lib/handler/redirect-handler.js +238 -0
  148. package/node_modules/undici/lib/handler/retry-handler.js +394 -0
  149. package/node_modules/undici/lib/handler/unwrap-handler.js +106 -0
  150. package/node_modules/undici/lib/handler/wrap-handler.js +105 -0
  151. package/node_modules/undici/lib/interceptor/cache.js +495 -0
  152. package/node_modules/undici/lib/interceptor/decompress.js +259 -0
  153. package/node_modules/undici/lib/interceptor/deduplicate.js +117 -0
  154. package/node_modules/undici/lib/interceptor/dns.js +571 -0
  155. package/node_modules/undici/lib/interceptor/dump.js +112 -0
  156. package/node_modules/undici/lib/interceptor/redirect.js +21 -0
  157. package/node_modules/undici/lib/interceptor/response-error.js +95 -0
  158. package/node_modules/undici/lib/interceptor/retry.js +19 -0
  159. package/node_modules/undici/lib/llhttp/.gitkeep +0 -0
  160. package/node_modules/undici/lib/llhttp/constants.d.ts +195 -0
  161. package/node_modules/undici/lib/llhttp/constants.js +531 -0
  162. package/node_modules/undici/lib/llhttp/llhttp-wasm.js +15 -0
  163. package/node_modules/undici/lib/llhttp/llhttp_simd-wasm.js +15 -0
  164. package/node_modules/undici/lib/llhttp/utils.d.ts +2 -0
  165. package/node_modules/undici/lib/llhttp/utils.js +12 -0
  166. package/node_modules/undici/lib/mock/mock-agent.js +232 -0
  167. package/node_modules/undici/lib/mock/mock-call-history.js +248 -0
  168. package/node_modules/undici/lib/mock/mock-client.js +68 -0
  169. package/node_modules/undici/lib/mock/mock-errors.js +29 -0
  170. package/node_modules/undici/lib/mock/mock-interceptor.js +209 -0
  171. package/node_modules/undici/lib/mock/mock-pool.js +68 -0
  172. package/node_modules/undici/lib/mock/mock-symbols.js +32 -0
  173. package/node_modules/undici/lib/mock/mock-utils.js +486 -0
  174. package/node_modules/undici/lib/mock/pending-interceptors-formatter.js +43 -0
  175. package/node_modules/undici/lib/mock/snapshot-agent.js +353 -0
  176. package/node_modules/undici/lib/mock/snapshot-recorder.js +588 -0
  177. package/node_modules/undici/lib/mock/snapshot-utils.js +158 -0
  178. package/node_modules/undici/lib/util/cache.js +414 -0
  179. package/node_modules/undici/lib/util/date.js +653 -0
  180. package/node_modules/undici/lib/util/promise.js +28 -0
  181. package/node_modules/undici/lib/util/runtime-features.js +124 -0
  182. package/node_modules/undici/lib/util/stats.js +32 -0
  183. package/node_modules/undici/lib/util/timers.js +425 -0
  184. package/node_modules/undici/lib/web/cache/cache.js +864 -0
  185. package/node_modules/undici/lib/web/cache/cachestorage.js +152 -0
  186. package/node_modules/undici/lib/web/cache/util.js +45 -0
  187. package/node_modules/undici/lib/web/cookies/constants.js +12 -0
  188. package/node_modules/undici/lib/web/cookies/index.js +199 -0
  189. package/node_modules/undici/lib/web/cookies/parse.js +314 -0
  190. package/node_modules/undici/lib/web/cookies/util.js +282 -0
  191. package/node_modules/undici/lib/web/eventsource/eventsource-stream.js +399 -0
  192. package/node_modules/undici/lib/web/eventsource/eventsource.js +501 -0
  193. package/node_modules/undici/lib/web/eventsource/util.js +29 -0
  194. package/node_modules/undici/lib/web/fetch/LICENSE +21 -0
  195. package/node_modules/undici/lib/web/fetch/body.js +509 -0
  196. package/node_modules/undici/lib/web/fetch/constants.js +131 -0
  197. package/node_modules/undici/lib/web/fetch/data-url.js +596 -0
  198. package/node_modules/undici/lib/web/fetch/formdata-parser.js +586 -0
  199. package/node_modules/undici/lib/web/fetch/formdata.js +259 -0
  200. package/node_modules/undici/lib/web/fetch/global.js +40 -0
  201. package/node_modules/undici/lib/web/fetch/headers.js +719 -0
  202. package/node_modules/undici/lib/web/fetch/index.js +2413 -0
  203. package/node_modules/undici/lib/web/fetch/request.js +1115 -0
  204. package/node_modules/undici/lib/web/fetch/response.js +641 -0
  205. package/node_modules/undici/lib/web/fetch/util.js +1522 -0
  206. package/node_modules/undici/lib/web/infra/index.js +229 -0
  207. package/node_modules/undici/lib/web/subresource-integrity/Readme.md +9 -0
  208. package/node_modules/undici/lib/web/subresource-integrity/subresource-integrity.js +307 -0
  209. package/node_modules/undici/lib/web/webidl/index.js +1006 -0
  210. package/node_modules/undici/lib/web/websocket/connection.js +329 -0
  211. package/node_modules/undici/lib/web/websocket/constants.js +126 -0
  212. package/node_modules/undici/lib/web/websocket/events.js +331 -0
  213. package/node_modules/undici/lib/web/websocket/frame.js +133 -0
  214. package/node_modules/undici/lib/web/websocket/permessage-deflate.js +100 -0
  215. package/node_modules/undici/lib/web/websocket/receiver.js +507 -0
  216. package/node_modules/undici/lib/web/websocket/sender.js +109 -0
  217. package/node_modules/undici/lib/web/websocket/stream/websocketerror.js +104 -0
  218. package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +498 -0
  219. package/node_modules/undici/lib/web/websocket/util.js +347 -0
  220. package/node_modules/undici/lib/web/websocket/websocket.js +758 -0
  221. package/node_modules/undici/package.json +152 -0
  222. package/node_modules/undici/scripts/strip-comments.js +10 -0
  223. package/node_modules/undici/types/README.md +6 -0
  224. package/node_modules/undici/types/agent.d.ts +32 -0
  225. package/node_modules/undici/types/api.d.ts +43 -0
  226. package/node_modules/undici/types/balanced-pool.d.ts +30 -0
  227. package/node_modules/undici/types/cache-interceptor.d.ts +179 -0
  228. package/node_modules/undici/types/cache.d.ts +36 -0
  229. package/node_modules/undici/types/client-stats.d.ts +15 -0
  230. package/node_modules/undici/types/client.d.ts +139 -0
  231. package/node_modules/undici/types/connector.d.ts +36 -0
  232. package/node_modules/undici/types/content-type.d.ts +21 -0
  233. package/node_modules/undici/types/cookies.d.ts +30 -0
  234. package/node_modules/undici/types/diagnostics-channel.d.ts +74 -0
  235. package/node_modules/undici/types/dispatcher.d.ts +275 -0
  236. package/node_modules/undici/types/env-http-proxy-agent.d.ts +22 -0
  237. package/node_modules/undici/types/errors.d.ts +177 -0
  238. package/node_modules/undici/types/eventsource.d.ts +66 -0
  239. package/node_modules/undici/types/fetch.d.ts +231 -0
  240. package/node_modules/undici/types/formdata.d.ts +114 -0
  241. package/node_modules/undici/types/global-dispatcher.d.ts +9 -0
  242. package/node_modules/undici/types/global-origin.d.ts +7 -0
  243. package/node_modules/undici/types/h2c-client.d.ts +73 -0
  244. package/node_modules/undici/types/handlers.d.ts +14 -0
  245. package/node_modules/undici/types/header.d.ts +160 -0
  246. package/node_modules/undici/types/index.d.ts +91 -0
  247. package/node_modules/undici/types/interceptors.d.ts +80 -0
  248. package/node_modules/undici/types/mock-agent.d.ts +68 -0
  249. package/node_modules/undici/types/mock-call-history.d.ts +111 -0
  250. package/node_modules/undici/types/mock-client.d.ts +27 -0
  251. package/node_modules/undici/types/mock-errors.d.ts +12 -0
  252. package/node_modules/undici/types/mock-interceptor.d.ts +94 -0
  253. package/node_modules/undici/types/mock-pool.d.ts +27 -0
  254. package/node_modules/undici/types/patch.d.ts +29 -0
  255. package/node_modules/undici/types/pool-stats.d.ts +19 -0
  256. package/node_modules/undici/types/pool.d.ts +41 -0
  257. package/node_modules/undici/types/proxy-agent.d.ts +29 -0
  258. package/node_modules/undici/types/readable.d.ts +68 -0
  259. package/node_modules/undici/types/retry-agent.d.ts +8 -0
  260. package/node_modules/undici/types/retry-handler.d.ts +125 -0
  261. package/node_modules/undici/types/round-robin-pool.d.ts +41 -0
  262. package/node_modules/undici/types/snapshot-agent.d.ts +109 -0
  263. package/node_modules/undici/types/socks5-proxy-agent.d.ts +25 -0
  264. package/node_modules/undici/types/util.d.ts +18 -0
  265. package/node_modules/undici/types/utility.d.ts +7 -0
  266. package/node_modules/undici/types/webidl.d.ts +347 -0
  267. package/node_modules/undici/types/websocket.d.ts +188 -0
  268. package/package.json +161 -156
  269. package/src/context.ts +1 -1
  270. package/src/cursor-context-tools.ts +1 -1
  271. package/src/cursor-live-run-accounting.ts +1 -1
  272. package/src/cursor-live-run-coordinator.ts +1 -1
  273. package/src/cursor-native-replay-routing.ts +1 -1
  274. package/src/cursor-partial-content-emitter.ts +1 -1
  275. package/src/cursor-pi-tool-bridge-mcp.ts +1 -1
  276. package/src/cursor-pi-tool-bridge-run.ts +1 -1
  277. package/src/cursor-pi-tool-bridge-types.ts +1 -1
  278. package/src/cursor-provider-lazy.ts +1 -1
  279. package/src/cursor-provider-live-run-drain.ts +1 -1
  280. package/src/cursor-provider-run-finalizer.ts +1 -1
  281. package/src/cursor-provider-turn-coordinator.ts +1 -1
  282. package/src/cursor-provider-turn-lifecycle-emitter.ts +1 -1
  283. package/src/cursor-provider-turn-prepare.ts +1 -1
  284. package/src/cursor-provider-turn-types.ts +1 -1
  285. package/src/cursor-provider.ts +1 -1
  286. package/src/cursor-run-final-text.ts +1 -1
  287. package/src/cursor-sdk-event-debug.ts +1 -1
  288. package/src/cursor-session-agent.ts +1 -1
  289. package/src/cursor-session-send-policy.ts +1 -1
  290. package/src/cursor-usage-accounting.ts +1 -1
  291. package/src/model-discovery.ts +1 -1
@@ -0,0 +1,507 @@
1
+ 'use strict'
2
+
3
+ const { Writable } = require('node:stream')
4
+ const assert = require('node:assert')
5
+ const { parserStates, opcodes, states, emptyBuffer, sentCloseFrameState } = require('./constants')
6
+ const {
7
+ isValidStatusCode,
8
+ isValidOpcode,
9
+ websocketMessageReceived,
10
+ utf8Decode,
11
+ isControlFrame,
12
+ isTextBinaryFrame,
13
+ isContinuationFrame
14
+ } = require('./util')
15
+ const { failWebsocketConnection } = require('./connection')
16
+ const { WebsocketFrameSend } = require('./frame')
17
+ const { PerMessageDeflate } = require('./permessage-deflate')
18
+ const { MessageSizeExceededError } = require('../../core/errors')
19
+
20
+ // This code was influenced by ws released under the MIT license.
21
+ // Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>
22
+ // Copyright (c) 2013 Arnout Kazemier and contributors
23
+ // Copyright (c) 2016 Luigi Pinca and contributors
24
+
25
+ class ByteParser extends Writable {
26
+ #buffers = []
27
+ #fragmentsBytes = 0
28
+ #byteOffset = 0
29
+ #loop = false
30
+
31
+ #state = parserStates.INFO
32
+
33
+ #info = {}
34
+ #fragments = []
35
+
36
+ /** @type {Map<string, PerMessageDeflate>} */
37
+ #extensions
38
+
39
+ /** @type {import('./websocket').Handler} */
40
+ #handler
41
+
42
+ /** @type {number} */
43
+ #maxFragments
44
+
45
+ /** @type {number} */
46
+ #maxPayloadSize
47
+
48
+ /**
49
+ * @param {import('./websocket').Handler} handler
50
+ * @param {Map<string, string>|null} extensions
51
+ * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options]
52
+ */
53
+ constructor (handler, extensions, options = {}) {
54
+ super()
55
+
56
+ this.#handler = handler
57
+ this.#extensions = extensions == null ? new Map() : extensions
58
+ this.#maxFragments = options.maxFragments ?? 0
59
+ this.#maxPayloadSize = options.maxPayloadSize ?? 0
60
+
61
+ if (this.#extensions.has('permessage-deflate')) {
62
+ this.#extensions.set('permessage-deflate', new PerMessageDeflate(extensions, options))
63
+ }
64
+ }
65
+
66
+ /**
67
+ * @param {Buffer} chunk
68
+ * @param {() => void} callback
69
+ */
70
+ _write (chunk, _, callback) {
71
+ this.#buffers.push(chunk)
72
+ this.#byteOffset += chunk.length
73
+ this.#loop = true
74
+
75
+ this.run(callback)
76
+ }
77
+
78
+ #validatePayloadLength () {
79
+ if (
80
+ this.#maxPayloadSize > 0 &&
81
+ !isControlFrame(this.#info.opcode) &&
82
+ this.#info.payloadLength + this.#fragmentsBytes > this.#maxPayloadSize
83
+ ) {
84
+ failWebsocketConnection(this.#handler, 1009, 'Payload size exceeds maximum allowed size')
85
+ return false
86
+ }
87
+
88
+ return true
89
+ }
90
+
91
+ /**
92
+ * Runs whenever a new chunk is received.
93
+ * Callback is called whenever there are no more chunks buffering,
94
+ * or not enough bytes are buffered to parse.
95
+ */
96
+ run (callback) {
97
+ while (this.#loop) {
98
+ if (this.#state === parserStates.INFO) {
99
+ // If there aren't enough bytes to parse the payload length, etc.
100
+ if (this.#byteOffset < 2) {
101
+ return callback()
102
+ }
103
+
104
+ const buffer = this.consume(2)
105
+ const fin = (buffer[0] & 0x80) !== 0
106
+ const opcode = buffer[0] & 0x0F
107
+ const masked = (buffer[1] & 0x80) === 0x80
108
+
109
+ const fragmented = !fin && opcode !== opcodes.CONTINUATION
110
+ const payloadLength = buffer[1] & 0x7F
111
+
112
+ const rsv1 = buffer[0] & 0x40
113
+ const rsv2 = buffer[0] & 0x20
114
+ const rsv3 = buffer[0] & 0x10
115
+
116
+ if (!isValidOpcode(opcode)) {
117
+ failWebsocketConnection(this.#handler, 1002, 'Invalid opcode received')
118
+ return callback()
119
+ }
120
+
121
+ if (masked) {
122
+ failWebsocketConnection(this.#handler, 1002, 'Frame cannot be masked')
123
+ return callback()
124
+ }
125
+
126
+ // MUST be 0 unless an extension is negotiated that defines meanings
127
+ // for non-zero values. If a nonzero value is received and none of
128
+ // the negotiated extensions defines the meaning of such a nonzero
129
+ // value, the receiving endpoint MUST _Fail the WebSocket
130
+ // Connection_.
131
+ // This document allocates the RSV1 bit of the WebSocket header for
132
+ // PMCEs and calls the bit the "Per-Message Compressed" bit. On a
133
+ // WebSocket connection where a PMCE is in use, this bit indicates
134
+ // whether a message is compressed or not.
135
+ if (rsv1 !== 0 && !this.#extensions.has('permessage-deflate')) {
136
+ failWebsocketConnection(this.#handler, 1002, 'Expected RSV1 to be clear.')
137
+ return
138
+ }
139
+
140
+ if (rsv2 !== 0 || rsv3 !== 0) {
141
+ failWebsocketConnection(this.#handler, 1002, 'RSV1, RSV2, RSV3 must be clear')
142
+ return
143
+ }
144
+
145
+ if (fragmented && !isTextBinaryFrame(opcode)) {
146
+ // Only text and binary frames can be fragmented
147
+ failWebsocketConnection(this.#handler, 1002, 'Invalid frame type was fragmented.')
148
+ return
149
+ }
150
+
151
+ // If we are already parsing a text/binary frame and do not receive either
152
+ // a continuation frame or close frame, fail the connection.
153
+ if (isTextBinaryFrame(opcode) && this.#fragments.length > 0) {
154
+ failWebsocketConnection(this.#handler, 1002, 'Expected continuation frame')
155
+ return
156
+ }
157
+
158
+ if (this.#info.fragmented && fragmented) {
159
+ // A fragmented frame can't be fragmented itself
160
+ failWebsocketConnection(this.#handler, 1002, 'Fragmented frame exceeded 125 bytes.')
161
+ return
162
+ }
163
+
164
+ // "All control frames MUST have a payload length of 125 bytes or less
165
+ // and MUST NOT be fragmented."
166
+ if ((payloadLength > 125 || fragmented) && isControlFrame(opcode)) {
167
+ failWebsocketConnection(this.#handler, 1002, 'Control frame either too large or fragmented')
168
+ return
169
+ }
170
+
171
+ if (isContinuationFrame(opcode) && this.#fragments.length === 0 && !this.#info.compressed) {
172
+ failWebsocketConnection(this.#handler, 1002, 'Unexpected continuation frame')
173
+ return
174
+ }
175
+
176
+ if (payloadLength <= 125) {
177
+ this.#info.payloadLength = payloadLength
178
+ this.#state = parserStates.READ_DATA
179
+
180
+ if (!this.#validatePayloadLength()) {
181
+ return
182
+ }
183
+ } else if (payloadLength === 126) {
184
+ this.#state = parserStates.PAYLOADLENGTH_16
185
+ } else if (payloadLength === 127) {
186
+ this.#state = parserStates.PAYLOADLENGTH_64
187
+ }
188
+
189
+ if (isTextBinaryFrame(opcode)) {
190
+ this.#info.binaryType = opcode
191
+ this.#info.compressed = rsv1 !== 0
192
+ }
193
+
194
+ this.#info.opcode = opcode
195
+ this.#info.masked = masked
196
+ this.#info.fin = fin
197
+ this.#info.fragmented = fragmented
198
+ } else if (this.#state === parserStates.PAYLOADLENGTH_16) {
199
+ if (this.#byteOffset < 2) {
200
+ return callback()
201
+ }
202
+
203
+ const buffer = this.consume(2)
204
+
205
+ this.#info.payloadLength = buffer.readUInt16BE(0)
206
+ this.#state = parserStates.READ_DATA
207
+
208
+ if (!this.#validatePayloadLength()) {
209
+ return
210
+ }
211
+ } else if (this.#state === parserStates.PAYLOADLENGTH_64) {
212
+ if (this.#byteOffset < 8) {
213
+ return callback()
214
+ }
215
+
216
+ const buffer = this.consume(8)
217
+ const upper = buffer.readUInt32BE(0)
218
+ const lower = buffer.readUInt32BE(4)
219
+
220
+ // 2^31 is the maximum bytes an arraybuffer can contain
221
+ // on 32-bit systems. Although, on 64-bit systems, this is
222
+ // 2^53-1 bytes.
223
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Invalid_array_length
224
+ // https://source.chromium.org/chromium/chromium/src/+/main:v8/src/common/globals.h;drc=1946212ac0100668f14eb9e2843bdd846e510a1e;bpv=1;bpt=1;l=1275
225
+ // https://source.chromium.org/chromium/chromium/src/+/main:v8/src/objects/js-array-buffer.h;l=34;drc=1946212ac0100668f14eb9e2843bdd846e510a1e
226
+ if (upper !== 0 || lower > 2 ** 31 - 1) {
227
+ failWebsocketConnection(this.#handler, 1009, 'Received payload length > 2^31 bytes.')
228
+ return
229
+ }
230
+
231
+ this.#info.payloadLength = lower
232
+ this.#state = parserStates.READ_DATA
233
+
234
+ if (!this.#validatePayloadLength()) {
235
+ return
236
+ }
237
+ } else if (this.#state === parserStates.READ_DATA) {
238
+ if (this.#byteOffset < this.#info.payloadLength) {
239
+ return callback()
240
+ }
241
+
242
+ const body = this.consume(this.#info.payloadLength)
243
+
244
+ if (isControlFrame(this.#info.opcode)) {
245
+ this.#loop = this.parseControlFrame(body)
246
+ this.#state = parserStates.INFO
247
+ } else {
248
+ if (!this.#info.compressed) {
249
+ if (!this.writeFragments(body)) {
250
+ return
251
+ }
252
+
253
+ // If the frame is not fragmented, a message has been received.
254
+ // If the frame is fragmented, it will terminate with a fin bit set
255
+ // and an opcode of 0 (continuation), therefore we handle that when
256
+ // parsing continuation frames, not here.
257
+ if (!this.#info.fragmented && this.#info.fin) {
258
+ websocketMessageReceived(this.#handler, this.#info.binaryType, this.consumeFragments())
259
+ }
260
+
261
+ this.#state = parserStates.INFO
262
+ } else {
263
+ this.#extensions.get('permessage-deflate').decompress(
264
+ body,
265
+ this.#info.fin,
266
+ (error, data) => {
267
+ if (error) {
268
+ const code = error instanceof MessageSizeExceededError ? 1009 : 1007
269
+ failWebsocketConnection(this.#handler, code, error.message)
270
+ return
271
+ }
272
+
273
+ if (!this.writeFragments(data)) {
274
+ return
275
+ }
276
+
277
+ // Check cumulative fragment size
278
+ if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) {
279
+ failWebsocketConnection(this.#handler, 1009, new MessageSizeExceededError().message)
280
+ return
281
+ }
282
+
283
+ if (!this.#info.fin) {
284
+ this.#state = parserStates.INFO
285
+ this.#loop = true
286
+ this.run(callback)
287
+ return
288
+ }
289
+
290
+ websocketMessageReceived(this.#handler, this.#info.binaryType, this.consumeFragments())
291
+
292
+ this.#loop = true
293
+ this.#state = parserStates.INFO
294
+ this.run(callback)
295
+ },
296
+ this.#fragmentsBytes
297
+ )
298
+
299
+ this.#loop = false
300
+ break
301
+ }
302
+ }
303
+ }
304
+ }
305
+ }
306
+
307
+ /**
308
+ * Take n bytes from the buffered Buffers
309
+ * @param {number} n
310
+ * @returns {Buffer}
311
+ */
312
+ consume (n) {
313
+ if (n > this.#byteOffset) {
314
+ throw new Error('Called consume() before buffers satiated.')
315
+ } else if (n === 0) {
316
+ return emptyBuffer
317
+ }
318
+
319
+ this.#byteOffset -= n
320
+
321
+ const first = this.#buffers[0]
322
+
323
+ if (first.length > n) {
324
+ // replace with remaining buffer
325
+ this.#buffers[0] = first.subarray(n, first.length)
326
+ return first.subarray(0, n)
327
+ } else if (first.length === n) {
328
+ // prefect match
329
+ return this.#buffers.shift()
330
+ } else {
331
+ let offset = 0
332
+ // If Buffer.allocUnsafe is used, extra copies will be made because the offset is non-zero.
333
+ const buffer = Buffer.allocUnsafeSlow(n)
334
+ while (offset !== n) {
335
+ const next = this.#buffers[0]
336
+ const length = next.length
337
+
338
+ if (length + offset === n) {
339
+ buffer.set(this.#buffers.shift(), offset)
340
+ break
341
+ } else if (length + offset > n) {
342
+ buffer.set(next.subarray(0, n - offset), offset)
343
+ this.#buffers[0] = next.subarray(n - offset)
344
+ break
345
+ } else {
346
+ buffer.set(this.#buffers.shift(), offset)
347
+ offset += length
348
+ }
349
+ }
350
+
351
+ return buffer
352
+ }
353
+ }
354
+
355
+ writeFragments (fragment) {
356
+ if (
357
+ this.#maxFragments > 0 &&
358
+ this.#fragments.length === this.#maxFragments
359
+ ) {
360
+ failWebsocketConnection(this.#handler, 1008, 'Too many message fragments')
361
+ return false
362
+ }
363
+
364
+ this.#fragmentsBytes += fragment.length
365
+ this.#fragments.push(fragment)
366
+ return true
367
+ }
368
+
369
+ consumeFragments () {
370
+ const fragments = this.#fragments
371
+
372
+ if (fragments.length === 1) {
373
+ // single fragment
374
+ this.#fragmentsBytes = 0
375
+ return fragments.shift()
376
+ }
377
+
378
+ let offset = 0
379
+ // If Buffer.allocUnsafe is used, extra copies will be made because the offset is non-zero.
380
+ const output = Buffer.allocUnsafeSlow(this.#fragmentsBytes)
381
+
382
+ for (let i = 0; i < fragments.length; ++i) {
383
+ const buffer = fragments[i]
384
+ output.set(buffer, offset)
385
+ offset += buffer.length
386
+ }
387
+
388
+ this.#fragments = []
389
+ this.#fragmentsBytes = 0
390
+
391
+ return output
392
+ }
393
+
394
+ parseCloseBody (data) {
395
+ assert(data.length !== 1)
396
+
397
+ // https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.5
398
+ /** @type {number|undefined} */
399
+ let code
400
+
401
+ if (data.length >= 2) {
402
+ // _The WebSocket Connection Close Code_ is
403
+ // defined as the status code (Section 7.4) contained in the first Close
404
+ // control frame received by the application
405
+ code = data.readUInt16BE(0)
406
+ }
407
+
408
+ if (code !== undefined && !isValidStatusCode(code)) {
409
+ return { code: 1002, reason: 'Invalid status code', error: true }
410
+ }
411
+
412
+ // https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.6
413
+ /** @type {Buffer} */
414
+ let reason = data.subarray(2)
415
+
416
+ // Remove BOM
417
+ if (reason[0] === 0xEF && reason[1] === 0xBB && reason[2] === 0xBF) {
418
+ reason = reason.subarray(3)
419
+ }
420
+
421
+ try {
422
+ reason = utf8Decode(reason)
423
+ } catch {
424
+ return { code: 1007, reason: 'Invalid UTF-8', error: true }
425
+ }
426
+
427
+ return { code, reason, error: false }
428
+ }
429
+
430
+ /**
431
+ * Parses control frames.
432
+ * @param {Buffer} body
433
+ */
434
+ parseControlFrame (body) {
435
+ const { opcode, payloadLength } = this.#info
436
+
437
+ if (opcode === opcodes.CLOSE) {
438
+ if (payloadLength === 1) {
439
+ failWebsocketConnection(this.#handler, 1002, 'Received close frame with a 1-byte body.')
440
+ return false
441
+ }
442
+
443
+ this.#info.closeInfo = this.parseCloseBody(body)
444
+
445
+ if (this.#info.closeInfo.error) {
446
+ const { code, reason } = this.#info.closeInfo
447
+
448
+ failWebsocketConnection(this.#handler, code, reason)
449
+ return false
450
+ }
451
+
452
+ // Upon receiving such a frame, the other peer sends a
453
+ // Close frame in response, if it hasn't already sent one.
454
+ if (!this.#handler.closeState.has(sentCloseFrameState.SENT) && !this.#handler.closeState.has(sentCloseFrameState.RECEIVED)) {
455
+ // If an endpoint receives a Close frame and did not previously send a
456
+ // Close frame, the endpoint MUST send a Close frame in response. (When
457
+ // sending a Close frame in response, the endpoint typically echos the
458
+ // status code it received.)
459
+ let body = emptyBuffer
460
+ if (this.#info.closeInfo.code) {
461
+ body = Buffer.allocUnsafe(2)
462
+ body.writeUInt16BE(this.#info.closeInfo.code, 0)
463
+ }
464
+ const closeFrame = new WebsocketFrameSend(body)
465
+
466
+ this.#handler.socket.write(closeFrame.createFrame(opcodes.CLOSE))
467
+ this.#handler.closeState.add(sentCloseFrameState.SENT)
468
+ }
469
+
470
+ // Upon either sending or receiving a Close control frame, it is said
471
+ // that _The WebSocket Closing Handshake is Started_ and that the
472
+ // WebSocket connection is in the CLOSING state.
473
+ this.#handler.readyState = states.CLOSING
474
+ this.#handler.closeState.add(sentCloseFrameState.RECEIVED)
475
+
476
+ return false
477
+ } else if (opcode === opcodes.PING) {
478
+ // Upon receipt of a Ping frame, an endpoint MUST send a Pong frame in
479
+ // response, unless it already received a Close frame.
480
+ // A Pong frame sent in response to a Ping frame must have identical
481
+ // "Application data"
482
+
483
+ if (!this.#handler.closeState.has(sentCloseFrameState.RECEIVED)) {
484
+ const frame = new WebsocketFrameSend(body)
485
+
486
+ this.#handler.socket.write(frame.createFrame(opcodes.PONG))
487
+
488
+ this.#handler.onPing(body)
489
+ }
490
+ } else if (opcode === opcodes.PONG) {
491
+ // A Pong frame MAY be sent unsolicited. This serves as a
492
+ // unidirectional heartbeat. A response to an unsolicited Pong frame is
493
+ // not expected.
494
+ this.#handler.onPong(body)
495
+ }
496
+
497
+ return true
498
+ }
499
+
500
+ get closingInfo () {
501
+ return this.#info.closeInfo
502
+ }
503
+ }
504
+
505
+ module.exports = {
506
+ ByteParser
507
+ }
@@ -0,0 +1,109 @@
1
+ 'use strict'
2
+
3
+ const { WebsocketFrameSend } = require('./frame')
4
+ const { opcodes, sendHints } = require('./constants')
5
+ const FixedQueue = require('../../dispatcher/fixed-queue')
6
+
7
+ /**
8
+ * @typedef {object} SendQueueNode
9
+ * @property {Promise<void> | null} promise
10
+ * @property {((...args: any[]) => any)} callback
11
+ * @property {Buffer | null} frame
12
+ */
13
+
14
+ class SendQueue {
15
+ /**
16
+ * @type {FixedQueue}
17
+ */
18
+ #queue = new FixedQueue()
19
+
20
+ /**
21
+ * @type {boolean}
22
+ */
23
+ #running = false
24
+
25
+ /** @type {import('node:net').Socket} */
26
+ #socket
27
+
28
+ constructor (socket) {
29
+ this.#socket = socket
30
+ }
31
+
32
+ add (item, cb, hint) {
33
+ if (hint !== sendHints.blob) {
34
+ if (!this.#running) {
35
+ // TODO(@tsctx): support fast-path for string on running
36
+ if (hint === sendHints.text) {
37
+ // special fast-path for string
38
+ const { 0: head, 1: body } = WebsocketFrameSend.createFastTextFrame(item)
39
+ this.#socket.cork()
40
+ this.#socket.write(head)
41
+ this.#socket.write(body, cb)
42
+ this.#socket.uncork()
43
+ } else {
44
+ // direct writing
45
+ this.#socket.write(createFrame(item, hint), cb)
46
+ }
47
+ } else {
48
+ /** @type {SendQueueNode} */
49
+ const node = {
50
+ promise: null,
51
+ callback: cb,
52
+ frame: createFrame(item, hint)
53
+ }
54
+ this.#queue.push(node)
55
+ }
56
+ return
57
+ }
58
+
59
+ /** @type {SendQueueNode} */
60
+ const node = {
61
+ promise: item.arrayBuffer().then((ab) => {
62
+ node.promise = null
63
+ node.frame = createFrame(ab, hint)
64
+ }),
65
+ callback: cb,
66
+ frame: null
67
+ }
68
+
69
+ this.#queue.push(node)
70
+
71
+ if (!this.#running) {
72
+ this.#run()
73
+ }
74
+ }
75
+
76
+ async #run () {
77
+ this.#running = true
78
+ const queue = this.#queue
79
+ while (!queue.isEmpty()) {
80
+ const node = queue.shift()
81
+ // wait pending promise
82
+ if (node.promise !== null) {
83
+ await node.promise
84
+ }
85
+ // write
86
+ this.#socket.write(node.frame, node.callback)
87
+ // cleanup
88
+ node.callback = node.frame = null
89
+ }
90
+ this.#running = false
91
+ }
92
+ }
93
+
94
+ function createFrame (data, hint) {
95
+ return new WebsocketFrameSend(toBuffer(data, hint)).createFrame(hint === sendHints.text ? opcodes.TEXT : opcodes.BINARY)
96
+ }
97
+
98
+ function toBuffer (data, hint) {
99
+ switch (hint) {
100
+ case sendHints.text:
101
+ case sendHints.typedArray:
102
+ return new Uint8Array(data.buffer, data.byteOffset, data.byteLength)
103
+ case sendHints.arrayBuffer:
104
+ case sendHints.blob:
105
+ return new Uint8Array(data)
106
+ }
107
+ }
108
+
109
+ module.exports = { SendQueue }