pi-cursor-sdk 0.1.50 → 0.1.52

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 (279) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +1 -1
  3. package/docs/cursor-live-smoke-checklist.md +4 -4
  4. package/docs/cursor-model-ux-spec.md +5 -5
  5. package/docs/cursor-native-tool-replay.md +2 -2
  6. package/docs/cursor-native-tool-visual-audit.md +1 -1
  7. package/docs/cursor-testing-lessons.md +1 -1
  8. package/package.json +3 -12
  9. package/src/cursor-fallback-models.generated.ts +536 -302
  10. package/src/cursor-provider-errors.ts +29 -0
  11. package/src/cursor-provider-turn-runner.ts +1 -1
  12. package/src/cursor-provider.ts +9 -2
  13. package/src/cursor-session-turn-queue.ts +52 -0
  14. package/src/cursor-tool-manifest.ts +1 -1
  15. package/node_modules/@connectrpc/connect-node/README.md +0 -141
  16. package/node_modules/@connectrpc/connect-node/dist/cjs/compression.d.ts +0 -15
  17. package/node_modules/@connectrpc/connect-node/dist/cjs/compression.js +0 -89
  18. package/node_modules/@connectrpc/connect-node/dist/cjs/connect-node-adapter.d.ts +0 -42
  19. package/node_modules/@connectrpc/connect-node/dist/cjs/connect-node-adapter.js +0 -61
  20. package/node_modules/@connectrpc/connect-node/dist/cjs/connect-transport.d.ts +0 -100
  21. package/node_modules/@connectrpc/connect-node/dist/cjs/connect-transport.js +0 -25
  22. package/node_modules/@connectrpc/connect-node/dist/cjs/grpc-transport.d.ts +0 -96
  23. package/node_modules/@connectrpc/connect-node/dist/cjs/grpc-transport.js +0 -25
  24. package/node_modules/@connectrpc/connect-node/dist/cjs/grpc-web-transport.d.ts +0 -96
  25. package/node_modules/@connectrpc/connect-node/dist/cjs/grpc-web-transport.js +0 -25
  26. package/node_modules/@connectrpc/connect-node/dist/cjs/http2-session-manager.d.ts +0 -146
  27. package/node_modules/@connectrpc/connect-node/dist/cjs/http2-session-manager.js +0 -536
  28. package/node_modules/@connectrpc/connect-node/dist/cjs/index.d.ts +0 -15
  29. package/node_modules/@connectrpc/connect-node/dist/cjs/index.js +0 -36
  30. package/node_modules/@connectrpc/connect-node/dist/cjs/node-error.d.ts +0 -45
  31. package/node_modules/@connectrpc/connect-node/dist/cjs/node-error.js +0 -154
  32. package/node_modules/@connectrpc/connect-node/dist/cjs/node-headers-polyfill.d.ts +0 -1
  33. package/node_modules/@connectrpc/connect-node/dist/cjs/node-headers-polyfill.js +0 -29
  34. package/node_modules/@connectrpc/connect-node/dist/cjs/node-transport-options.d.ts +0 -89
  35. package/node_modules/@connectrpc/connect-node/dist/cjs/node-transport-options.js +0 -58
  36. package/node_modules/@connectrpc/connect-node/dist/cjs/node-universal-client.d.ts +0 -54
  37. package/node_modules/@connectrpc/connect-node/dist/cjs/node-universal-client.js +0 -326
  38. package/node_modules/@connectrpc/connect-node/dist/cjs/node-universal-handler.d.ts +0 -41
  39. package/node_modules/@connectrpc/connect-node/dist/cjs/node-universal-handler.js +0 -234
  40. package/node_modules/@connectrpc/connect-node/dist/cjs/node-universal-header.d.ts +0 -19
  41. package/node_modules/@connectrpc/connect-node/dist/cjs/node-universal-header.js +0 -97
  42. package/node_modules/@connectrpc/connect-node/dist/cjs/package.json +0 -1
  43. package/node_modules/@connectrpc/connect-node/dist/esm/compression.d.ts +0 -15
  44. package/node_modules/@connectrpc/connect-node/dist/esm/compression.js +0 -86
  45. package/node_modules/@connectrpc/connect-node/dist/esm/connect-node-adapter.d.ts +0 -42
  46. package/node_modules/@connectrpc/connect-node/dist/esm/connect-node-adapter.js +0 -58
  47. package/node_modules/@connectrpc/connect-node/dist/esm/connect-transport.d.ts +0 -100
  48. package/node_modules/@connectrpc/connect-node/dist/esm/connect-transport.js +0 -22
  49. package/node_modules/@connectrpc/connect-node/dist/esm/grpc-transport.d.ts +0 -96
  50. package/node_modules/@connectrpc/connect-node/dist/esm/grpc-transport.js +0 -22
  51. package/node_modules/@connectrpc/connect-node/dist/esm/grpc-web-transport.d.ts +0 -96
  52. package/node_modules/@connectrpc/connect-node/dist/esm/grpc-web-transport.js +0 -22
  53. package/node_modules/@connectrpc/connect-node/dist/esm/http2-session-manager.d.ts +0 -146
  54. package/node_modules/@connectrpc/connect-node/dist/esm/http2-session-manager.js +0 -532
  55. package/node_modules/@connectrpc/connect-node/dist/esm/index.d.ts +0 -15
  56. package/node_modules/@connectrpc/connect-node/dist/esm/index.js +0 -23
  57. package/node_modules/@connectrpc/connect-node/dist/esm/node-error.d.ts +0 -45
  58. package/node_modules/@connectrpc/connect-node/dist/esm/node-error.js +0 -147
  59. package/node_modules/@connectrpc/connect-node/dist/esm/node-headers-polyfill.d.ts +0 -1
  60. package/node_modules/@connectrpc/connect-node/dist/esm/node-headers-polyfill.js +0 -27
  61. package/node_modules/@connectrpc/connect-node/dist/esm/node-transport-options.d.ts +0 -89
  62. package/node_modules/@connectrpc/connect-node/dist/esm/node-transport-options.js +0 -58
  63. package/node_modules/@connectrpc/connect-node/dist/esm/node-universal-client.d.ts +0 -54
  64. package/node_modules/@connectrpc/connect-node/dist/esm/node-universal-client.js +0 -324
  65. package/node_modules/@connectrpc/connect-node/dist/esm/node-universal-handler.d.ts +0 -41
  66. package/node_modules/@connectrpc/connect-node/dist/esm/node-universal-handler.js +0 -230
  67. package/node_modules/@connectrpc/connect-node/dist/esm/node-universal-header.d.ts +0 -19
  68. package/node_modules/@connectrpc/connect-node/dist/esm/node-universal-header.js +0 -93
  69. package/node_modules/@connectrpc/connect-node/package.json +0 -46
  70. package/node_modules/undici/LICENSE +0 -21
  71. package/node_modules/undici/README.md +0 -741
  72. package/node_modules/undici/docs/docs/api/Agent.md +0 -84
  73. package/node_modules/undici/docs/docs/api/BalancedPool.md +0 -99
  74. package/node_modules/undici/docs/docs/api/CacheStorage.md +0 -30
  75. package/node_modules/undici/docs/docs/api/CacheStore.md +0 -164
  76. package/node_modules/undici/docs/docs/api/Client.md +0 -288
  77. package/node_modules/undici/docs/docs/api/ClientStats.md +0 -27
  78. package/node_modules/undici/docs/docs/api/Connector.md +0 -115
  79. package/node_modules/undici/docs/docs/api/ContentType.md +0 -57
  80. package/node_modules/undici/docs/docs/api/Cookies.md +0 -128
  81. package/node_modules/undici/docs/docs/api/Debug.md +0 -62
  82. package/node_modules/undici/docs/docs/api/DiagnosticsChannel.md +0 -315
  83. package/node_modules/undici/docs/docs/api/Dispatcher.md +0 -1392
  84. package/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +0 -159
  85. package/node_modules/undici/docs/docs/api/Errors.md +0 -49
  86. package/node_modules/undici/docs/docs/api/EventSource.md +0 -45
  87. package/node_modules/undici/docs/docs/api/Fetch.md +0 -60
  88. package/node_modules/undici/docs/docs/api/GlobalInstallation.md +0 -139
  89. package/node_modules/undici/docs/docs/api/H2CClient.md +0 -263
  90. package/node_modules/undici/docs/docs/api/MockAgent.md +0 -603
  91. package/node_modules/undici/docs/docs/api/MockCallHistory.md +0 -197
  92. package/node_modules/undici/docs/docs/api/MockCallHistoryLog.md +0 -43
  93. package/node_modules/undici/docs/docs/api/MockClient.md +0 -81
  94. package/node_modules/undici/docs/docs/api/MockErrors.md +0 -12
  95. package/node_modules/undici/docs/docs/api/MockPool.md +0 -555
  96. package/node_modules/undici/docs/docs/api/Pool.md +0 -84
  97. package/node_modules/undici/docs/docs/api/PoolStats.md +0 -35
  98. package/node_modules/undici/docs/docs/api/ProxyAgent.md +0 -229
  99. package/node_modules/undici/docs/docs/api/RedirectHandler.md +0 -93
  100. package/node_modules/undici/docs/docs/api/RetryAgent.md +0 -50
  101. package/node_modules/undici/docs/docs/api/RetryHandler.md +0 -118
  102. package/node_modules/undici/docs/docs/api/RoundRobinPool.md +0 -145
  103. package/node_modules/undici/docs/docs/api/SnapshotAgent.md +0 -616
  104. package/node_modules/undici/docs/docs/api/Socks5ProxyAgent.md +0 -275
  105. package/node_modules/undici/docs/docs/api/Util.md +0 -25
  106. package/node_modules/undici/docs/docs/api/WebSocket.md +0 -141
  107. package/node_modules/undici/docs/docs/api/api-lifecycle.md +0 -91
  108. package/node_modules/undici/docs/docs/best-practices/client-certificate.md +0 -64
  109. package/node_modules/undici/docs/docs/best-practices/crawling.md +0 -58
  110. package/node_modules/undici/docs/docs/best-practices/mocking-request.md +0 -190
  111. package/node_modules/undici/docs/docs/best-practices/proxy.md +0 -127
  112. package/node_modules/undici/docs/docs/best-practices/undici-vs-builtin-fetch.md +0 -224
  113. package/node_modules/undici/docs/docs/best-practices/writing-tests.md +0 -63
  114. package/node_modules/undici/index-fetch.js +0 -65
  115. package/node_modules/undici/index.d.ts +0 -3
  116. package/node_modules/undici/index.js +0 -234
  117. package/node_modules/undici/lib/api/abort-signal.js +0 -59
  118. package/node_modules/undici/lib/api/api-connect.js +0 -110
  119. package/node_modules/undici/lib/api/api-pipeline.js +0 -252
  120. package/node_modules/undici/lib/api/api-request.js +0 -214
  121. package/node_modules/undici/lib/api/api-stream.js +0 -209
  122. package/node_modules/undici/lib/api/api-upgrade.js +0 -111
  123. package/node_modules/undici/lib/api/index.js +0 -7
  124. package/node_modules/undici/lib/api/readable.js +0 -580
  125. package/node_modules/undici/lib/cache/memory-cache-store.js +0 -234
  126. package/node_modules/undici/lib/cache/sqlite-cache-store.js +0 -461
  127. package/node_modules/undici/lib/core/connect.js +0 -153
  128. package/node_modules/undici/lib/core/constants.js +0 -143
  129. package/node_modules/undici/lib/core/diagnostics.js +0 -227
  130. package/node_modules/undici/lib/core/errors.js +0 -477
  131. package/node_modules/undici/lib/core/request.js +0 -453
  132. package/node_modules/undici/lib/core/socks5-client.js +0 -422
  133. package/node_modules/undici/lib/core/socks5-utils.js +0 -212
  134. package/node_modules/undici/lib/core/symbols.js +0 -75
  135. package/node_modules/undici/lib/core/tree.js +0 -160
  136. package/node_modules/undici/lib/core/util.js +0 -992
  137. package/node_modules/undici/lib/dispatcher/agent.js +0 -158
  138. package/node_modules/undici/lib/dispatcher/balanced-pool.js +0 -219
  139. package/node_modules/undici/lib/dispatcher/client-h1.js +0 -1722
  140. package/node_modules/undici/lib/dispatcher/client-h2.js +0 -995
  141. package/node_modules/undici/lib/dispatcher/client.js +0 -664
  142. package/node_modules/undici/lib/dispatcher/dispatcher-base.js +0 -184
  143. package/node_modules/undici/lib/dispatcher/dispatcher.js +0 -48
  144. package/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +0 -146
  145. package/node_modules/undici/lib/dispatcher/fixed-queue.js +0 -135
  146. package/node_modules/undici/lib/dispatcher/h2c-client.js +0 -51
  147. package/node_modules/undici/lib/dispatcher/pool-base.js +0 -214
  148. package/node_modules/undici/lib/dispatcher/pool.js +0 -118
  149. package/node_modules/undici/lib/dispatcher/proxy-agent.js +0 -319
  150. package/node_modules/undici/lib/dispatcher/retry-agent.js +0 -35
  151. package/node_modules/undici/lib/dispatcher/round-robin-pool.js +0 -137
  152. package/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +0 -260
  153. package/node_modules/undici/lib/encoding/index.js +0 -33
  154. package/node_modules/undici/lib/global.js +0 -59
  155. package/node_modules/undici/lib/handler/cache-handler.js +0 -578
  156. package/node_modules/undici/lib/handler/cache-revalidation-handler.js +0 -124
  157. package/node_modules/undici/lib/handler/decorator-handler.js +0 -67
  158. package/node_modules/undici/lib/handler/deduplication-handler.js +0 -460
  159. package/node_modules/undici/lib/handler/redirect-handler.js +0 -238
  160. package/node_modules/undici/lib/handler/retry-handler.js +0 -394
  161. package/node_modules/undici/lib/handler/unwrap-handler.js +0 -106
  162. package/node_modules/undici/lib/handler/wrap-handler.js +0 -105
  163. package/node_modules/undici/lib/interceptor/cache.js +0 -495
  164. package/node_modules/undici/lib/interceptor/decompress.js +0 -259
  165. package/node_modules/undici/lib/interceptor/deduplicate.js +0 -117
  166. package/node_modules/undici/lib/interceptor/dns.js +0 -571
  167. package/node_modules/undici/lib/interceptor/dump.js +0 -112
  168. package/node_modules/undici/lib/interceptor/redirect.js +0 -21
  169. package/node_modules/undici/lib/interceptor/response-error.js +0 -95
  170. package/node_modules/undici/lib/interceptor/retry.js +0 -19
  171. package/node_modules/undici/lib/llhttp/.gitkeep +0 -0
  172. package/node_modules/undici/lib/llhttp/constants.d.ts +0 -195
  173. package/node_modules/undici/lib/llhttp/constants.js +0 -531
  174. package/node_modules/undici/lib/llhttp/llhttp-wasm.js +0 -15
  175. package/node_modules/undici/lib/llhttp/llhttp_simd-wasm.js +0 -15
  176. package/node_modules/undici/lib/llhttp/utils.d.ts +0 -2
  177. package/node_modules/undici/lib/llhttp/utils.js +0 -12
  178. package/node_modules/undici/lib/mock/mock-agent.js +0 -232
  179. package/node_modules/undici/lib/mock/mock-call-history.js +0 -248
  180. package/node_modules/undici/lib/mock/mock-client.js +0 -68
  181. package/node_modules/undici/lib/mock/mock-errors.js +0 -29
  182. package/node_modules/undici/lib/mock/mock-interceptor.js +0 -209
  183. package/node_modules/undici/lib/mock/mock-pool.js +0 -68
  184. package/node_modules/undici/lib/mock/mock-symbols.js +0 -32
  185. package/node_modules/undici/lib/mock/mock-utils.js +0 -486
  186. package/node_modules/undici/lib/mock/pending-interceptors-formatter.js +0 -43
  187. package/node_modules/undici/lib/mock/snapshot-agent.js +0 -353
  188. package/node_modules/undici/lib/mock/snapshot-recorder.js +0 -588
  189. package/node_modules/undici/lib/mock/snapshot-utils.js +0 -158
  190. package/node_modules/undici/lib/util/cache.js +0 -414
  191. package/node_modules/undici/lib/util/date.js +0 -653
  192. package/node_modules/undici/lib/util/promise.js +0 -28
  193. package/node_modules/undici/lib/util/runtime-features.js +0 -124
  194. package/node_modules/undici/lib/util/stats.js +0 -32
  195. package/node_modules/undici/lib/util/timers.js +0 -425
  196. package/node_modules/undici/lib/web/cache/cache.js +0 -864
  197. package/node_modules/undici/lib/web/cache/cachestorage.js +0 -152
  198. package/node_modules/undici/lib/web/cache/util.js +0 -45
  199. package/node_modules/undici/lib/web/cookies/constants.js +0 -12
  200. package/node_modules/undici/lib/web/cookies/index.js +0 -199
  201. package/node_modules/undici/lib/web/cookies/parse.js +0 -314
  202. package/node_modules/undici/lib/web/cookies/util.js +0 -282
  203. package/node_modules/undici/lib/web/eventsource/eventsource-stream.js +0 -399
  204. package/node_modules/undici/lib/web/eventsource/eventsource.js +0 -501
  205. package/node_modules/undici/lib/web/eventsource/util.js +0 -29
  206. package/node_modules/undici/lib/web/fetch/LICENSE +0 -21
  207. package/node_modules/undici/lib/web/fetch/body.js +0 -509
  208. package/node_modules/undici/lib/web/fetch/constants.js +0 -131
  209. package/node_modules/undici/lib/web/fetch/data-url.js +0 -596
  210. package/node_modules/undici/lib/web/fetch/formdata-parser.js +0 -586
  211. package/node_modules/undici/lib/web/fetch/formdata.js +0 -259
  212. package/node_modules/undici/lib/web/fetch/global.js +0 -40
  213. package/node_modules/undici/lib/web/fetch/headers.js +0 -719
  214. package/node_modules/undici/lib/web/fetch/index.js +0 -2413
  215. package/node_modules/undici/lib/web/fetch/request.js +0 -1115
  216. package/node_modules/undici/lib/web/fetch/response.js +0 -641
  217. package/node_modules/undici/lib/web/fetch/util.js +0 -1522
  218. package/node_modules/undici/lib/web/infra/index.js +0 -229
  219. package/node_modules/undici/lib/web/subresource-integrity/Readme.md +0 -9
  220. package/node_modules/undici/lib/web/subresource-integrity/subresource-integrity.js +0 -307
  221. package/node_modules/undici/lib/web/webidl/index.js +0 -1006
  222. package/node_modules/undici/lib/web/websocket/connection.js +0 -329
  223. package/node_modules/undici/lib/web/websocket/constants.js +0 -126
  224. package/node_modules/undici/lib/web/websocket/events.js +0 -331
  225. package/node_modules/undici/lib/web/websocket/frame.js +0 -133
  226. package/node_modules/undici/lib/web/websocket/permessage-deflate.js +0 -100
  227. package/node_modules/undici/lib/web/websocket/receiver.js +0 -507
  228. package/node_modules/undici/lib/web/websocket/sender.js +0 -109
  229. package/node_modules/undici/lib/web/websocket/stream/websocketerror.js +0 -104
  230. package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +0 -498
  231. package/node_modules/undici/lib/web/websocket/util.js +0 -347
  232. package/node_modules/undici/lib/web/websocket/websocket.js +0 -758
  233. package/node_modules/undici/package.json +0 -152
  234. package/node_modules/undici/scripts/strip-comments.js +0 -10
  235. package/node_modules/undici/types/README.md +0 -6
  236. package/node_modules/undici/types/agent.d.ts +0 -32
  237. package/node_modules/undici/types/api.d.ts +0 -43
  238. package/node_modules/undici/types/balanced-pool.d.ts +0 -30
  239. package/node_modules/undici/types/cache-interceptor.d.ts +0 -179
  240. package/node_modules/undici/types/cache.d.ts +0 -36
  241. package/node_modules/undici/types/client-stats.d.ts +0 -15
  242. package/node_modules/undici/types/client.d.ts +0 -139
  243. package/node_modules/undici/types/connector.d.ts +0 -36
  244. package/node_modules/undici/types/content-type.d.ts +0 -21
  245. package/node_modules/undici/types/cookies.d.ts +0 -30
  246. package/node_modules/undici/types/diagnostics-channel.d.ts +0 -74
  247. package/node_modules/undici/types/dispatcher.d.ts +0 -275
  248. package/node_modules/undici/types/env-http-proxy-agent.d.ts +0 -22
  249. package/node_modules/undici/types/errors.d.ts +0 -177
  250. package/node_modules/undici/types/eventsource.d.ts +0 -66
  251. package/node_modules/undici/types/fetch.d.ts +0 -231
  252. package/node_modules/undici/types/formdata.d.ts +0 -114
  253. package/node_modules/undici/types/global-dispatcher.d.ts +0 -9
  254. package/node_modules/undici/types/global-origin.d.ts +0 -7
  255. package/node_modules/undici/types/h2c-client.d.ts +0 -73
  256. package/node_modules/undici/types/handlers.d.ts +0 -14
  257. package/node_modules/undici/types/header.d.ts +0 -160
  258. package/node_modules/undici/types/index.d.ts +0 -91
  259. package/node_modules/undici/types/interceptors.d.ts +0 -80
  260. package/node_modules/undici/types/mock-agent.d.ts +0 -68
  261. package/node_modules/undici/types/mock-call-history.d.ts +0 -111
  262. package/node_modules/undici/types/mock-client.d.ts +0 -27
  263. package/node_modules/undici/types/mock-errors.d.ts +0 -12
  264. package/node_modules/undici/types/mock-interceptor.d.ts +0 -94
  265. package/node_modules/undici/types/mock-pool.d.ts +0 -27
  266. package/node_modules/undici/types/patch.d.ts +0 -29
  267. package/node_modules/undici/types/pool-stats.d.ts +0 -19
  268. package/node_modules/undici/types/pool.d.ts +0 -41
  269. package/node_modules/undici/types/proxy-agent.d.ts +0 -29
  270. package/node_modules/undici/types/readable.d.ts +0 -68
  271. package/node_modules/undici/types/retry-agent.d.ts +0 -8
  272. package/node_modules/undici/types/retry-handler.d.ts +0 -125
  273. package/node_modules/undici/types/round-robin-pool.d.ts +0 -41
  274. package/node_modules/undici/types/snapshot-agent.d.ts +0 -109
  275. package/node_modules/undici/types/socks5-proxy-agent.d.ts +0 -25
  276. package/node_modules/undici/types/util.d.ts +0 -18
  277. package/node_modules/undici/types/utility.d.ts +0 -7
  278. package/node_modules/undici/types/webidl.d.ts +0 -347
  279. package/node_modules/undici/types/websocket.d.ts +0 -188
@@ -1,586 +0,0 @@
1
- 'use strict'
2
-
3
- const { bufferToLowerCasedHeaderName } = require('../../core/util')
4
- const { HTTP_TOKEN_CODEPOINTS } = require('./data-url')
5
- const { makeEntry } = require('./formdata')
6
- const { webidl } = require('../webidl')
7
- const assert = require('node:assert')
8
- const { isomorphicDecode } = require('../infra')
9
-
10
- const dd = Buffer.from('--')
11
- const decoder = new TextDecoder()
12
- const decoderIgnoreBOM = new TextDecoder('utf-8', { ignoreBOM: true })
13
-
14
- /**
15
- * @param {string} chars
16
- */
17
- function isAsciiString (chars) {
18
- for (let i = 0; i < chars.length; ++i) {
19
- if ((chars.charCodeAt(i) & ~0x7F) !== 0) {
20
- return false
21
- }
22
- }
23
- return true
24
- }
25
-
26
- /**
27
- * @see https://andreubotella.github.io/multipart-form-data/#multipart-form-data-boundary
28
- * @param {string} boundary
29
- */
30
- function validateBoundary (boundary) {
31
- const length = boundary.length
32
-
33
- // - its length is greater or equal to 27 and lesser or equal to 70, and
34
- if (length < 27 || length > 70) {
35
- return false
36
- }
37
-
38
- // - it is composed by bytes in the ranges 0x30 to 0x39, 0x41 to 0x5A, or
39
- // 0x61 to 0x7A, inclusive (ASCII alphanumeric), or which are 0x27 ('),
40
- // 0x2D (-) or 0x5F (_).
41
- for (let i = 0; i < length; ++i) {
42
- const cp = boundary.charCodeAt(i)
43
-
44
- if (!(
45
- (cp >= 0x30 && cp <= 0x39) ||
46
- (cp >= 0x41 && cp <= 0x5a) ||
47
- (cp >= 0x61 && cp <= 0x7a) ||
48
- cp === 0x27 ||
49
- cp === 0x2d ||
50
- cp === 0x5f
51
- )) {
52
- return false
53
- }
54
- }
55
-
56
- return true
57
- }
58
-
59
- /**
60
- * @see https://andreubotella.github.io/multipart-form-data/#multipart-form-data-parser
61
- * @param {Buffer} input
62
- * @param {ReturnType<import('./data-url')['parseMIMEType']>} mimeType
63
- */
64
- function multipartFormDataParser (input, mimeType) {
65
- // 1. Assert: mimeType’s essence is "multipart/form-data".
66
- assert(mimeType !== 'failure' && mimeType.essence === 'multipart/form-data')
67
-
68
- const boundaryString = mimeType.parameters.get('boundary')
69
-
70
- // 2. If mimeType’s parameters["boundary"] does not exist, return failure.
71
- // Otherwise, let boundary be the result of UTF-8 decoding mimeType’s
72
- // parameters["boundary"].
73
- if (boundaryString === undefined) {
74
- throw parsingError('missing boundary in content-type header')
75
- }
76
-
77
- const boundary = Buffer.from(`--${boundaryString}`, 'utf8')
78
-
79
- // 3. Let entry list be an empty entry list.
80
- const entryList = []
81
-
82
- // 4. Let position be a pointer to a byte in input, initially pointing at
83
- // the first byte.
84
- const position = { position: 0 }
85
-
86
- // Note: Per RFC 2046 Section 5.1.1, we must ignore anything before the
87
- // first boundary delimiter line (preamble). Search for the first boundary.
88
- const firstBoundaryIndex = input.indexOf(boundary)
89
-
90
- if (firstBoundaryIndex === -1) {
91
- throw parsingError('no boundary found in multipart body')
92
- }
93
-
94
- // Start parsing from the first boundary, ignoring any preamble
95
- position.position = firstBoundaryIndex
96
-
97
- // 5. While true:
98
- while (true) {
99
- // 5.1. If position points to a sequence of bytes starting with 0x2D 0x2D
100
- // (`--`) followed by boundary, advance position by 2 + the length of
101
- // boundary. Otherwise, return failure.
102
- // Note: boundary is padded with 2 dashes already, no need to add 2.
103
- if (input.subarray(position.position, position.position + boundary.length).equals(boundary)) {
104
- position.position += boundary.length
105
- } else {
106
- throw parsingError('expected a value starting with -- and the boundary')
107
- }
108
-
109
- // 5.2. If position points to the sequence of bytes 0x2D 0x2D 0x0D 0x0A
110
- // (`--` followed by CR LF) followed by the end of input, return entry list.
111
- // Note: Per RFC 2046 Section 5.1.1, we must ignore anything after the
112
- // final boundary delimiter (epilogue). Check for -- or --CRLF and return
113
- // regardless of what follows.
114
- if (bufferStartsWith(input, dd, position)) {
115
- // Found closing boundary delimiter (--), ignore any epilogue
116
- return entryList
117
- }
118
-
119
- // 5.3. If position does not point to a sequence of bytes starting with 0x0D
120
- // 0x0A (CR LF), return failure.
121
- if (input[position.position] !== 0x0d || input[position.position + 1] !== 0x0a) {
122
- throw parsingError('expected CRLF')
123
- }
124
-
125
- // 5.4. Advance position by 2. (This skips past the newline.)
126
- position.position += 2
127
-
128
- // 5.5. Let name, filename and contentType be the result of parsing
129
- // multipart/form-data headers on input and position, if the result
130
- // is not failure. Otherwise, return failure.
131
- const result = parseMultipartFormDataHeaders(input, position)
132
-
133
- let { name, filename, contentType, encoding } = result
134
-
135
- // 5.6. Advance position by 2. (This skips past the empty line that marks
136
- // the end of the headers.)
137
- position.position += 2
138
-
139
- // 5.7. Let body be the empty byte sequence.
140
- let body
141
-
142
- // 5.8. Body loop: While position is not past the end of input:
143
- // TODO: the steps here are completely wrong
144
- {
145
- const boundaryIndex = input.indexOf(boundary.subarray(2), position.position)
146
-
147
- if (boundaryIndex === -1) {
148
- throw parsingError('expected boundary after body')
149
- }
150
-
151
- body = input.subarray(position.position, boundaryIndex - 4)
152
-
153
- position.position += body.length
154
-
155
- // Note: position must be advanced by the body's length before being
156
- // decoded, otherwise the parsing will fail.
157
- if (encoding === 'base64') {
158
- body = Buffer.from(body.toString(), 'base64')
159
- }
160
- }
161
-
162
- // 5.9. If position does not point to a sequence of bytes starting with
163
- // 0x0D 0x0A (CR LF), return failure. Otherwise, advance position by 2.
164
- if (input[position.position] !== 0x0d || input[position.position + 1] !== 0x0a) {
165
- throw parsingError('expected CRLF')
166
- } else {
167
- position.position += 2
168
- }
169
-
170
- // 5.10. If filename is not null:
171
- let value
172
-
173
- if (filename !== null) {
174
- // 5.10.1. If contentType is null, set contentType to "text/plain".
175
- contentType ??= 'text/plain'
176
-
177
- // 5.10.2. If contentType is not an ASCII string, set contentType to the empty string.
178
-
179
- // Note: `buffer.isAscii` can be used at zero-cost, but converting a string to a buffer is a high overhead.
180
- // Content-Type is a relatively small string, so it is faster to use `String#charCodeAt`.
181
- if (!isAsciiString(contentType)) {
182
- contentType = ''
183
- }
184
-
185
- // 5.10.3. Let value be a new File object with name filename, type contentType, and body body.
186
- value = new File([body], filename, { type: contentType })
187
- } else {
188
- // 5.11. Otherwise:
189
-
190
- // 5.11.1. Let value be the UTF-8 decoding without BOM of body.
191
- value = decoderIgnoreBOM.decode(Buffer.from(body))
192
- }
193
-
194
- // 5.12. Assert: name is a scalar value string and value is either a scalar value string or a File object.
195
- assert(webidl.is.USVString(name))
196
- assert((typeof value === 'string' && webidl.is.USVString(value)) || webidl.is.File(value))
197
-
198
- // 5.13. Create an entry with name and value, and append it to entry list.
199
- entryList.push(makeEntry(name, value, filename))
200
- }
201
- }
202
-
203
- /**
204
- * Parses content-disposition attributes (e.g., name="value" or filename*=utf-8''encoded)
205
- * @param {Buffer} input
206
- * @param {{ position: number }} position
207
- * @returns {{ name: string, value: string, extended: boolean } | null}
208
- */
209
- function parseContentDispositionAttribute (input, position) {
210
- // Skip leading semicolon and whitespace
211
- if (input[position.position] === 0x3b /* ; */) {
212
- position.position++
213
- }
214
-
215
- // Skip whitespace
216
- collectASequenceOfBytes(
217
- (char) => char === 0x20 || char === 0x09,
218
- input,
219
- position
220
- )
221
-
222
- // Collect attribute name (token characters)
223
- const attributeName = collectASequenceOfBytes(
224
- (char) => isToken(char) && char !== 0x3d && char !== 0x2a, // not = or *
225
- input,
226
- position
227
- )
228
-
229
- if (attributeName.length === 0) {
230
- return null
231
- }
232
-
233
- const attrNameStr = attributeName.toString('ascii').toLowerCase()
234
-
235
- // Check for extended notation (attribute*)
236
- const isExtended = input[position.position] === 0x2a /* * */
237
- if (isExtended) {
238
- position.position++ // skip *
239
- }
240
-
241
- // Expect = sign
242
- if (input[position.position] !== 0x3d /* = */) {
243
- return null
244
- }
245
- position.position++ // skip =
246
-
247
- // Skip whitespace
248
- collectASequenceOfBytes(
249
- (char) => char === 0x20 || char === 0x09,
250
- input,
251
- position
252
- )
253
-
254
- let value
255
-
256
- if (isExtended) {
257
- // Extended attribute format: charset'language'encoded-value
258
- const headerValue = collectASequenceOfBytes(
259
- (char) => char !== 0x20 && char !== 0x0d && char !== 0x0a && char !== 0x3b, // not space, CRLF, or ;
260
- input,
261
- position
262
- )
263
-
264
- // Check for utf-8'' prefix (case insensitive)
265
- if (
266
- (headerValue[0] !== 0x75 && headerValue[0] !== 0x55) || // u or U
267
- (headerValue[1] !== 0x74 && headerValue[1] !== 0x54) || // t or T
268
- (headerValue[2] !== 0x66 && headerValue[2] !== 0x46) || // f or F
269
- headerValue[3] !== 0x2d || // -
270
- headerValue[4] !== 0x38 // 8
271
- ) {
272
- throw parsingError('unknown encoding, expected utf-8\'\'')
273
- }
274
-
275
- // Skip utf-8'' and decode the rest
276
- value = decodeURIComponent(decoder.decode(headerValue.subarray(7)))
277
- } else if (input[position.position] === 0x22 /* " */) {
278
- // Quoted string
279
- position.position++ // skip opening quote
280
-
281
- const quotedValue = collectASequenceOfBytes(
282
- (char) => char !== 0x0a && char !== 0x0d && char !== 0x22, // not LF, CR, or "
283
- input,
284
- position
285
- )
286
-
287
- if (input[position.position] !== 0x22) {
288
- throw parsingError('Closing quote not found')
289
- }
290
- position.position++ // skip closing quote
291
-
292
- value = decoder.decode(quotedValue)
293
- .replace(/%0A/ig, '\n')
294
- .replace(/%0D/ig, '\r')
295
- .replace(/%22/g, '"')
296
- } else {
297
- // Token value (no quotes)
298
- const tokenValue = collectASequenceOfBytes(
299
- (char) => isToken(char) && char !== 0x3b, // not ;
300
- input,
301
- position
302
- )
303
-
304
- value = decoder.decode(tokenValue)
305
- }
306
-
307
- return { name: attrNameStr, value, extended: isExtended }
308
- }
309
-
310
- /**
311
- * @see https://andreubotella.github.io/multipart-form-data/#parse-multipart-form-data-headers
312
- * @param {Buffer} input
313
- * @param {{ position: number }} position
314
- */
315
- function parseMultipartFormDataHeaders (input, position) {
316
- // 1. Let name, filename and contentType be null.
317
- let name = null
318
- let filename = null
319
- let contentType = null
320
- let encoding = null
321
-
322
- // 2. While true:
323
- while (true) {
324
- // 2.1. If position points to a sequence of bytes starting with 0x0D 0x0A (CR LF):
325
- if (input[position.position] === 0x0d && input[position.position + 1] === 0x0a) {
326
- // 2.1.1. If name is null, return failure.
327
- if (name === null) {
328
- throw parsingError('header name is null')
329
- }
330
-
331
- // 2.1.2. Return name, filename and contentType.
332
- return { name, filename, contentType, encoding }
333
- }
334
-
335
- // 2.2. Let header name be the result of collecting a sequence of bytes that are
336
- // not 0x0A (LF), 0x0D (CR) or 0x3A (:), given position.
337
- let headerName = collectASequenceOfBytes(
338
- (char) => char !== 0x0a && char !== 0x0d && char !== 0x3a,
339
- input,
340
- position
341
- )
342
-
343
- // 2.3. Remove any HTTP tab or space bytes from the start or end of header name.
344
- headerName = removeChars(headerName, true, true, (char) => char === 0x9 || char === 0x20)
345
-
346
- // 2.4. If header name does not match the field-name token production, return failure.
347
- if (!HTTP_TOKEN_CODEPOINTS.test(headerName.toString())) {
348
- throw parsingError('header name does not match the field-name token production')
349
- }
350
-
351
- // 2.5. If the byte at position is not 0x3A (:), return failure.
352
- if (input[position.position] !== 0x3a) {
353
- throw parsingError('expected :')
354
- }
355
-
356
- // 2.6. Advance position by 1.
357
- position.position++
358
-
359
- // 2.7. Collect a sequence of bytes that are HTTP tab or space bytes given position.
360
- // (Do nothing with those bytes.)
361
- collectASequenceOfBytes(
362
- (char) => char === 0x20 || char === 0x09,
363
- input,
364
- position
365
- )
366
-
367
- // 2.8. Byte-lowercase header name and switch on the result:
368
- switch (bufferToLowerCasedHeaderName(headerName)) {
369
- case 'content-disposition': {
370
- name = filename = null
371
- // Track whether filename was set from the extended (RFC 5987) form so
372
- // a subsequent legacy `filename` attribute does not override it.
373
- let filenameIsExtended = false
374
-
375
- // Collect the disposition type (should be "form-data")
376
- const dispositionType = collectASequenceOfBytes(
377
- (char) => isToken(char),
378
- input,
379
- position
380
- )
381
-
382
- if (dispositionType.toString('ascii').toLowerCase() !== 'form-data') {
383
- throw parsingError('expected form-data for content-disposition header')
384
- }
385
-
386
- // Parse attributes recursively until CRLF
387
- while (
388
- position.position < input.length &&
389
- (input[position.position] !== 0x0d ||
390
- input[position.position + 1] !== 0x0a)
391
- ) {
392
- const attribute = parseContentDispositionAttribute(input, position)
393
-
394
- if (!attribute) {
395
- break
396
- }
397
-
398
- if (attribute.name === 'name') {
399
- name = attribute.value
400
- } else if (attribute.name === 'filename') {
401
- // Per RFC 5987 §4.1, when both legacy and extended forms of the
402
- // same parameter are present, the extended (filename*) form takes
403
- // precedence regardless of the order they appear in.
404
- if (attribute.extended) {
405
- filename = attribute.value
406
- filenameIsExtended = true
407
- } else if (!filenameIsExtended) {
408
- filename = attribute.value
409
- }
410
- }
411
- }
412
-
413
- if (name === null) {
414
- throw parsingError('name attribute is required in content-disposition header')
415
- }
416
-
417
- break
418
- }
419
- case 'content-type': {
420
- // 1. Let header value be the result of collecting a sequence of bytes that are
421
- // not 0x0A (LF) or 0x0D (CR), given position.
422
- let headerValue = collectASequenceOfBytes(
423
- (char) => char !== 0x0a && char !== 0x0d,
424
- input,
425
- position
426
- )
427
-
428
- // 2. Remove any HTTP tab or space bytes from the end of header value.
429
- headerValue = removeChars(headerValue, false, true, (char) => char === 0x9 || char === 0x20)
430
-
431
- // 3. Set contentType to the isomorphic decoding of header value.
432
- contentType = isomorphicDecode(headerValue)
433
-
434
- break
435
- }
436
- case 'content-transfer-encoding': {
437
- let headerValue = collectASequenceOfBytes(
438
- (char) => char !== 0x0a && char !== 0x0d,
439
- input,
440
- position
441
- )
442
-
443
- headerValue = removeChars(headerValue, false, true, (char) => char === 0x9 || char === 0x20)
444
-
445
- encoding = isomorphicDecode(headerValue)
446
-
447
- break
448
- }
449
- default: {
450
- // Collect a sequence of bytes that are not 0x0A (LF) or 0x0D (CR), given position.
451
- // (Do nothing with those bytes.)
452
- collectASequenceOfBytes(
453
- (char) => char !== 0x0a && char !== 0x0d,
454
- input,
455
- position
456
- )
457
- }
458
- }
459
-
460
- // 2.9. If position does not point to a sequence of bytes starting with 0x0D 0x0A
461
- // (CR LF), return failure. Otherwise, advance position by 2 (past the newline).
462
- if (input[position.position] !== 0x0d || input[position.position + 1] !== 0x0a) {
463
- throw parsingError('expected CRLF')
464
- } else {
465
- position.position += 2
466
- }
467
- }
468
- }
469
-
470
- /**
471
- * @param {(char: number) => boolean} condition
472
- * @param {Buffer} input
473
- * @param {{ position: number }} position
474
- */
475
- function collectASequenceOfBytes (condition, input, position) {
476
- let start = position.position
477
-
478
- while (start < input.length && condition(input[start])) {
479
- ++start
480
- }
481
-
482
- return input.subarray(position.position, (position.position = start))
483
- }
484
-
485
- /**
486
- * @param {Buffer} buf
487
- * @param {boolean} leading
488
- * @param {boolean} trailing
489
- * @param {(charCode: number) => boolean} predicate
490
- * @returns {Buffer}
491
- */
492
- function removeChars (buf, leading, trailing, predicate) {
493
- let lead = 0
494
- let trail = buf.length - 1
495
-
496
- if (leading) {
497
- while (lead < buf.length && predicate(buf[lead])) lead++
498
- }
499
-
500
- if (trailing) {
501
- while (trail > 0 && predicate(buf[trail])) trail--
502
- }
503
-
504
- return lead === 0 && trail === buf.length - 1 ? buf : buf.subarray(lead, trail + 1)
505
- }
506
-
507
- /**
508
- * Checks if {@param buffer} starts with {@param start}
509
- * @param {Buffer} buffer
510
- * @param {Buffer} start
511
- * @param {{ position: number }} position
512
- */
513
- function bufferStartsWith (buffer, start, position) {
514
- if (buffer.length < start.length) {
515
- return false
516
- }
517
-
518
- for (let i = 0; i < start.length; i++) {
519
- if (start[i] !== buffer[position.position + i]) {
520
- return false
521
- }
522
- }
523
-
524
- return true
525
- }
526
-
527
- function parsingError (cause) {
528
- return new TypeError('Failed to parse body as FormData.', { cause: new TypeError(cause) })
529
- }
530
-
531
- /**
532
- * CTL = <any US-ASCII control character
533
- * (octets 0 - 31) and DEL (127)>
534
- * @param {number} char
535
- */
536
- function isCTL (char) {
537
- return char <= 0x1f || char === 0x7f
538
- }
539
-
540
- /**
541
- * tspecials := "(" / ")" / "<" / ">" / "@" /
542
- * "," / ";" / ":" / "\" / <">
543
- * "/" / "[" / "]" / "?" / "="
544
- * ; Must be in quoted-string,
545
- * ; to use within parameter values
546
- * @param {number} char
547
- */
548
- function isTSpecial (char) {
549
- return (
550
- char === 0x28 || // (
551
- char === 0x29 || // )
552
- char === 0x3c || // <
553
- char === 0x3e || // >
554
- char === 0x40 || // @
555
- char === 0x2c || // ,
556
- char === 0x3b || // ;
557
- char === 0x3a || // :
558
- char === 0x5c || // \
559
- char === 0x22 || // "
560
- char === 0x2f || // /
561
- char === 0x5b || // [
562
- char === 0x5d || // ]
563
- char === 0x3f || // ?
564
- char === 0x3d // +
565
- )
566
- }
567
-
568
- /**
569
- * token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
570
- * or tspecials>
571
- * @param {number} char
572
- */
573
- function isToken (char) {
574
- return (
575
- char <= 0x7f && // ascii
576
- char !== 0x20 && // space
577
- char !== 0x09 &&
578
- !isCTL(char) &&
579
- !isTSpecial(char)
580
- )
581
- }
582
-
583
- module.exports = {
584
- multipartFormDataParser,
585
- validateBoundary
586
- }