pi-cursor-sdk 0.1.49 → 0.1.51

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 (278) hide show
  1. package/CHANGELOG.md +36 -1
  2. package/README.md +2 -2
  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 +6 -15
  9. package/src/cursor-fallback-models.generated.ts +536 -302
  10. package/src/cursor-provider-errors.ts +29 -0
  11. package/src/cursor-provider-overflow.ts +96 -0
  12. package/src/cursor-tool-manifest.ts +1 -1
  13. package/src/index.ts +4 -1
  14. package/node_modules/@connectrpc/connect-node/README.md +0 -141
  15. package/node_modules/@connectrpc/connect-node/dist/cjs/compression.d.ts +0 -15
  16. package/node_modules/@connectrpc/connect-node/dist/cjs/compression.js +0 -89
  17. package/node_modules/@connectrpc/connect-node/dist/cjs/connect-node-adapter.d.ts +0 -42
  18. package/node_modules/@connectrpc/connect-node/dist/cjs/connect-node-adapter.js +0 -61
  19. package/node_modules/@connectrpc/connect-node/dist/cjs/connect-transport.d.ts +0 -100
  20. package/node_modules/@connectrpc/connect-node/dist/cjs/connect-transport.js +0 -25
  21. package/node_modules/@connectrpc/connect-node/dist/cjs/grpc-transport.d.ts +0 -96
  22. package/node_modules/@connectrpc/connect-node/dist/cjs/grpc-transport.js +0 -25
  23. package/node_modules/@connectrpc/connect-node/dist/cjs/grpc-web-transport.d.ts +0 -96
  24. package/node_modules/@connectrpc/connect-node/dist/cjs/grpc-web-transport.js +0 -25
  25. package/node_modules/@connectrpc/connect-node/dist/cjs/http2-session-manager.d.ts +0 -146
  26. package/node_modules/@connectrpc/connect-node/dist/cjs/http2-session-manager.js +0 -536
  27. package/node_modules/@connectrpc/connect-node/dist/cjs/index.d.ts +0 -15
  28. package/node_modules/@connectrpc/connect-node/dist/cjs/index.js +0 -36
  29. package/node_modules/@connectrpc/connect-node/dist/cjs/node-error.d.ts +0 -45
  30. package/node_modules/@connectrpc/connect-node/dist/cjs/node-error.js +0 -154
  31. package/node_modules/@connectrpc/connect-node/dist/cjs/node-headers-polyfill.d.ts +0 -1
  32. package/node_modules/@connectrpc/connect-node/dist/cjs/node-headers-polyfill.js +0 -29
  33. package/node_modules/@connectrpc/connect-node/dist/cjs/node-transport-options.d.ts +0 -89
  34. package/node_modules/@connectrpc/connect-node/dist/cjs/node-transport-options.js +0 -58
  35. package/node_modules/@connectrpc/connect-node/dist/cjs/node-universal-client.d.ts +0 -54
  36. package/node_modules/@connectrpc/connect-node/dist/cjs/node-universal-client.js +0 -326
  37. package/node_modules/@connectrpc/connect-node/dist/cjs/node-universal-handler.d.ts +0 -41
  38. package/node_modules/@connectrpc/connect-node/dist/cjs/node-universal-handler.js +0 -234
  39. package/node_modules/@connectrpc/connect-node/dist/cjs/node-universal-header.d.ts +0 -19
  40. package/node_modules/@connectrpc/connect-node/dist/cjs/node-universal-header.js +0 -97
  41. package/node_modules/@connectrpc/connect-node/dist/cjs/package.json +0 -1
  42. package/node_modules/@connectrpc/connect-node/dist/esm/compression.d.ts +0 -15
  43. package/node_modules/@connectrpc/connect-node/dist/esm/compression.js +0 -86
  44. package/node_modules/@connectrpc/connect-node/dist/esm/connect-node-adapter.d.ts +0 -42
  45. package/node_modules/@connectrpc/connect-node/dist/esm/connect-node-adapter.js +0 -58
  46. package/node_modules/@connectrpc/connect-node/dist/esm/connect-transport.d.ts +0 -100
  47. package/node_modules/@connectrpc/connect-node/dist/esm/connect-transport.js +0 -22
  48. package/node_modules/@connectrpc/connect-node/dist/esm/grpc-transport.d.ts +0 -96
  49. package/node_modules/@connectrpc/connect-node/dist/esm/grpc-transport.js +0 -22
  50. package/node_modules/@connectrpc/connect-node/dist/esm/grpc-web-transport.d.ts +0 -96
  51. package/node_modules/@connectrpc/connect-node/dist/esm/grpc-web-transport.js +0 -22
  52. package/node_modules/@connectrpc/connect-node/dist/esm/http2-session-manager.d.ts +0 -146
  53. package/node_modules/@connectrpc/connect-node/dist/esm/http2-session-manager.js +0 -532
  54. package/node_modules/@connectrpc/connect-node/dist/esm/index.d.ts +0 -15
  55. package/node_modules/@connectrpc/connect-node/dist/esm/index.js +0 -23
  56. package/node_modules/@connectrpc/connect-node/dist/esm/node-error.d.ts +0 -45
  57. package/node_modules/@connectrpc/connect-node/dist/esm/node-error.js +0 -147
  58. package/node_modules/@connectrpc/connect-node/dist/esm/node-headers-polyfill.d.ts +0 -1
  59. package/node_modules/@connectrpc/connect-node/dist/esm/node-headers-polyfill.js +0 -27
  60. package/node_modules/@connectrpc/connect-node/dist/esm/node-transport-options.d.ts +0 -89
  61. package/node_modules/@connectrpc/connect-node/dist/esm/node-transport-options.js +0 -58
  62. package/node_modules/@connectrpc/connect-node/dist/esm/node-universal-client.d.ts +0 -54
  63. package/node_modules/@connectrpc/connect-node/dist/esm/node-universal-client.js +0 -324
  64. package/node_modules/@connectrpc/connect-node/dist/esm/node-universal-handler.d.ts +0 -41
  65. package/node_modules/@connectrpc/connect-node/dist/esm/node-universal-handler.js +0 -230
  66. package/node_modules/@connectrpc/connect-node/dist/esm/node-universal-header.d.ts +0 -19
  67. package/node_modules/@connectrpc/connect-node/dist/esm/node-universal-header.js +0 -93
  68. package/node_modules/@connectrpc/connect-node/package.json +0 -46
  69. package/node_modules/undici/LICENSE +0 -21
  70. package/node_modules/undici/README.md +0 -741
  71. package/node_modules/undici/docs/docs/api/Agent.md +0 -84
  72. package/node_modules/undici/docs/docs/api/BalancedPool.md +0 -99
  73. package/node_modules/undici/docs/docs/api/CacheStorage.md +0 -30
  74. package/node_modules/undici/docs/docs/api/CacheStore.md +0 -164
  75. package/node_modules/undici/docs/docs/api/Client.md +0 -288
  76. package/node_modules/undici/docs/docs/api/ClientStats.md +0 -27
  77. package/node_modules/undici/docs/docs/api/Connector.md +0 -115
  78. package/node_modules/undici/docs/docs/api/ContentType.md +0 -57
  79. package/node_modules/undici/docs/docs/api/Cookies.md +0 -128
  80. package/node_modules/undici/docs/docs/api/Debug.md +0 -62
  81. package/node_modules/undici/docs/docs/api/DiagnosticsChannel.md +0 -315
  82. package/node_modules/undici/docs/docs/api/Dispatcher.md +0 -1392
  83. package/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +0 -159
  84. package/node_modules/undici/docs/docs/api/Errors.md +0 -49
  85. package/node_modules/undici/docs/docs/api/EventSource.md +0 -45
  86. package/node_modules/undici/docs/docs/api/Fetch.md +0 -60
  87. package/node_modules/undici/docs/docs/api/GlobalInstallation.md +0 -139
  88. package/node_modules/undici/docs/docs/api/H2CClient.md +0 -263
  89. package/node_modules/undici/docs/docs/api/MockAgent.md +0 -603
  90. package/node_modules/undici/docs/docs/api/MockCallHistory.md +0 -197
  91. package/node_modules/undici/docs/docs/api/MockCallHistoryLog.md +0 -43
  92. package/node_modules/undici/docs/docs/api/MockClient.md +0 -81
  93. package/node_modules/undici/docs/docs/api/MockErrors.md +0 -12
  94. package/node_modules/undici/docs/docs/api/MockPool.md +0 -555
  95. package/node_modules/undici/docs/docs/api/Pool.md +0 -84
  96. package/node_modules/undici/docs/docs/api/PoolStats.md +0 -35
  97. package/node_modules/undici/docs/docs/api/ProxyAgent.md +0 -229
  98. package/node_modules/undici/docs/docs/api/RedirectHandler.md +0 -93
  99. package/node_modules/undici/docs/docs/api/RetryAgent.md +0 -50
  100. package/node_modules/undici/docs/docs/api/RetryHandler.md +0 -118
  101. package/node_modules/undici/docs/docs/api/RoundRobinPool.md +0 -145
  102. package/node_modules/undici/docs/docs/api/SnapshotAgent.md +0 -616
  103. package/node_modules/undici/docs/docs/api/Socks5ProxyAgent.md +0 -275
  104. package/node_modules/undici/docs/docs/api/Util.md +0 -25
  105. package/node_modules/undici/docs/docs/api/WebSocket.md +0 -141
  106. package/node_modules/undici/docs/docs/api/api-lifecycle.md +0 -91
  107. package/node_modules/undici/docs/docs/best-practices/client-certificate.md +0 -64
  108. package/node_modules/undici/docs/docs/best-practices/crawling.md +0 -58
  109. package/node_modules/undici/docs/docs/best-practices/mocking-request.md +0 -190
  110. package/node_modules/undici/docs/docs/best-practices/proxy.md +0 -127
  111. package/node_modules/undici/docs/docs/best-practices/undici-vs-builtin-fetch.md +0 -224
  112. package/node_modules/undici/docs/docs/best-practices/writing-tests.md +0 -63
  113. package/node_modules/undici/index-fetch.js +0 -65
  114. package/node_modules/undici/index.d.ts +0 -3
  115. package/node_modules/undici/index.js +0 -234
  116. package/node_modules/undici/lib/api/abort-signal.js +0 -59
  117. package/node_modules/undici/lib/api/api-connect.js +0 -110
  118. package/node_modules/undici/lib/api/api-pipeline.js +0 -252
  119. package/node_modules/undici/lib/api/api-request.js +0 -214
  120. package/node_modules/undici/lib/api/api-stream.js +0 -209
  121. package/node_modules/undici/lib/api/api-upgrade.js +0 -111
  122. package/node_modules/undici/lib/api/index.js +0 -7
  123. package/node_modules/undici/lib/api/readable.js +0 -580
  124. package/node_modules/undici/lib/cache/memory-cache-store.js +0 -234
  125. package/node_modules/undici/lib/cache/sqlite-cache-store.js +0 -461
  126. package/node_modules/undici/lib/core/connect.js +0 -153
  127. package/node_modules/undici/lib/core/constants.js +0 -143
  128. package/node_modules/undici/lib/core/diagnostics.js +0 -227
  129. package/node_modules/undici/lib/core/errors.js +0 -477
  130. package/node_modules/undici/lib/core/request.js +0 -453
  131. package/node_modules/undici/lib/core/socks5-client.js +0 -422
  132. package/node_modules/undici/lib/core/socks5-utils.js +0 -212
  133. package/node_modules/undici/lib/core/symbols.js +0 -75
  134. package/node_modules/undici/lib/core/tree.js +0 -160
  135. package/node_modules/undici/lib/core/util.js +0 -992
  136. package/node_modules/undici/lib/dispatcher/agent.js +0 -158
  137. package/node_modules/undici/lib/dispatcher/balanced-pool.js +0 -219
  138. package/node_modules/undici/lib/dispatcher/client-h1.js +0 -1722
  139. package/node_modules/undici/lib/dispatcher/client-h2.js +0 -995
  140. package/node_modules/undici/lib/dispatcher/client.js +0 -664
  141. package/node_modules/undici/lib/dispatcher/dispatcher-base.js +0 -184
  142. package/node_modules/undici/lib/dispatcher/dispatcher.js +0 -48
  143. package/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +0 -146
  144. package/node_modules/undici/lib/dispatcher/fixed-queue.js +0 -135
  145. package/node_modules/undici/lib/dispatcher/h2c-client.js +0 -51
  146. package/node_modules/undici/lib/dispatcher/pool-base.js +0 -214
  147. package/node_modules/undici/lib/dispatcher/pool.js +0 -118
  148. package/node_modules/undici/lib/dispatcher/proxy-agent.js +0 -319
  149. package/node_modules/undici/lib/dispatcher/retry-agent.js +0 -35
  150. package/node_modules/undici/lib/dispatcher/round-robin-pool.js +0 -137
  151. package/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +0 -260
  152. package/node_modules/undici/lib/encoding/index.js +0 -33
  153. package/node_modules/undici/lib/global.js +0 -59
  154. package/node_modules/undici/lib/handler/cache-handler.js +0 -578
  155. package/node_modules/undici/lib/handler/cache-revalidation-handler.js +0 -124
  156. package/node_modules/undici/lib/handler/decorator-handler.js +0 -67
  157. package/node_modules/undici/lib/handler/deduplication-handler.js +0 -460
  158. package/node_modules/undici/lib/handler/redirect-handler.js +0 -238
  159. package/node_modules/undici/lib/handler/retry-handler.js +0 -394
  160. package/node_modules/undici/lib/handler/unwrap-handler.js +0 -106
  161. package/node_modules/undici/lib/handler/wrap-handler.js +0 -105
  162. package/node_modules/undici/lib/interceptor/cache.js +0 -495
  163. package/node_modules/undici/lib/interceptor/decompress.js +0 -259
  164. package/node_modules/undici/lib/interceptor/deduplicate.js +0 -117
  165. package/node_modules/undici/lib/interceptor/dns.js +0 -571
  166. package/node_modules/undici/lib/interceptor/dump.js +0 -112
  167. package/node_modules/undici/lib/interceptor/redirect.js +0 -21
  168. package/node_modules/undici/lib/interceptor/response-error.js +0 -95
  169. package/node_modules/undici/lib/interceptor/retry.js +0 -19
  170. package/node_modules/undici/lib/llhttp/.gitkeep +0 -0
  171. package/node_modules/undici/lib/llhttp/constants.d.ts +0 -195
  172. package/node_modules/undici/lib/llhttp/constants.js +0 -531
  173. package/node_modules/undici/lib/llhttp/llhttp-wasm.js +0 -15
  174. package/node_modules/undici/lib/llhttp/llhttp_simd-wasm.js +0 -15
  175. package/node_modules/undici/lib/llhttp/utils.d.ts +0 -2
  176. package/node_modules/undici/lib/llhttp/utils.js +0 -12
  177. package/node_modules/undici/lib/mock/mock-agent.js +0 -232
  178. package/node_modules/undici/lib/mock/mock-call-history.js +0 -248
  179. package/node_modules/undici/lib/mock/mock-client.js +0 -68
  180. package/node_modules/undici/lib/mock/mock-errors.js +0 -29
  181. package/node_modules/undici/lib/mock/mock-interceptor.js +0 -209
  182. package/node_modules/undici/lib/mock/mock-pool.js +0 -68
  183. package/node_modules/undici/lib/mock/mock-symbols.js +0 -32
  184. package/node_modules/undici/lib/mock/mock-utils.js +0 -486
  185. package/node_modules/undici/lib/mock/pending-interceptors-formatter.js +0 -43
  186. package/node_modules/undici/lib/mock/snapshot-agent.js +0 -353
  187. package/node_modules/undici/lib/mock/snapshot-recorder.js +0 -588
  188. package/node_modules/undici/lib/mock/snapshot-utils.js +0 -158
  189. package/node_modules/undici/lib/util/cache.js +0 -414
  190. package/node_modules/undici/lib/util/date.js +0 -653
  191. package/node_modules/undici/lib/util/promise.js +0 -28
  192. package/node_modules/undici/lib/util/runtime-features.js +0 -124
  193. package/node_modules/undici/lib/util/stats.js +0 -32
  194. package/node_modules/undici/lib/util/timers.js +0 -425
  195. package/node_modules/undici/lib/web/cache/cache.js +0 -864
  196. package/node_modules/undici/lib/web/cache/cachestorage.js +0 -152
  197. package/node_modules/undici/lib/web/cache/util.js +0 -45
  198. package/node_modules/undici/lib/web/cookies/constants.js +0 -12
  199. package/node_modules/undici/lib/web/cookies/index.js +0 -199
  200. package/node_modules/undici/lib/web/cookies/parse.js +0 -314
  201. package/node_modules/undici/lib/web/cookies/util.js +0 -282
  202. package/node_modules/undici/lib/web/eventsource/eventsource-stream.js +0 -399
  203. package/node_modules/undici/lib/web/eventsource/eventsource.js +0 -501
  204. package/node_modules/undici/lib/web/eventsource/util.js +0 -29
  205. package/node_modules/undici/lib/web/fetch/LICENSE +0 -21
  206. package/node_modules/undici/lib/web/fetch/body.js +0 -509
  207. package/node_modules/undici/lib/web/fetch/constants.js +0 -131
  208. package/node_modules/undici/lib/web/fetch/data-url.js +0 -596
  209. package/node_modules/undici/lib/web/fetch/formdata-parser.js +0 -586
  210. package/node_modules/undici/lib/web/fetch/formdata.js +0 -259
  211. package/node_modules/undici/lib/web/fetch/global.js +0 -40
  212. package/node_modules/undici/lib/web/fetch/headers.js +0 -719
  213. package/node_modules/undici/lib/web/fetch/index.js +0 -2413
  214. package/node_modules/undici/lib/web/fetch/request.js +0 -1115
  215. package/node_modules/undici/lib/web/fetch/response.js +0 -641
  216. package/node_modules/undici/lib/web/fetch/util.js +0 -1522
  217. package/node_modules/undici/lib/web/infra/index.js +0 -229
  218. package/node_modules/undici/lib/web/subresource-integrity/Readme.md +0 -9
  219. package/node_modules/undici/lib/web/subresource-integrity/subresource-integrity.js +0 -307
  220. package/node_modules/undici/lib/web/webidl/index.js +0 -1006
  221. package/node_modules/undici/lib/web/websocket/connection.js +0 -329
  222. package/node_modules/undici/lib/web/websocket/constants.js +0 -126
  223. package/node_modules/undici/lib/web/websocket/events.js +0 -331
  224. package/node_modules/undici/lib/web/websocket/frame.js +0 -133
  225. package/node_modules/undici/lib/web/websocket/permessage-deflate.js +0 -100
  226. package/node_modules/undici/lib/web/websocket/receiver.js +0 -507
  227. package/node_modules/undici/lib/web/websocket/sender.js +0 -109
  228. package/node_modules/undici/lib/web/websocket/stream/websocketerror.js +0 -104
  229. package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +0 -498
  230. package/node_modules/undici/lib/web/websocket/util.js +0 -347
  231. package/node_modules/undici/lib/web/websocket/websocket.js +0 -758
  232. package/node_modules/undici/package.json +0 -152
  233. package/node_modules/undici/scripts/strip-comments.js +0 -10
  234. package/node_modules/undici/types/README.md +0 -6
  235. package/node_modules/undici/types/agent.d.ts +0 -32
  236. package/node_modules/undici/types/api.d.ts +0 -43
  237. package/node_modules/undici/types/balanced-pool.d.ts +0 -30
  238. package/node_modules/undici/types/cache-interceptor.d.ts +0 -179
  239. package/node_modules/undici/types/cache.d.ts +0 -36
  240. package/node_modules/undici/types/client-stats.d.ts +0 -15
  241. package/node_modules/undici/types/client.d.ts +0 -139
  242. package/node_modules/undici/types/connector.d.ts +0 -36
  243. package/node_modules/undici/types/content-type.d.ts +0 -21
  244. package/node_modules/undici/types/cookies.d.ts +0 -30
  245. package/node_modules/undici/types/diagnostics-channel.d.ts +0 -74
  246. package/node_modules/undici/types/dispatcher.d.ts +0 -275
  247. package/node_modules/undici/types/env-http-proxy-agent.d.ts +0 -22
  248. package/node_modules/undici/types/errors.d.ts +0 -177
  249. package/node_modules/undici/types/eventsource.d.ts +0 -66
  250. package/node_modules/undici/types/fetch.d.ts +0 -231
  251. package/node_modules/undici/types/formdata.d.ts +0 -114
  252. package/node_modules/undici/types/global-dispatcher.d.ts +0 -9
  253. package/node_modules/undici/types/global-origin.d.ts +0 -7
  254. package/node_modules/undici/types/h2c-client.d.ts +0 -73
  255. package/node_modules/undici/types/handlers.d.ts +0 -14
  256. package/node_modules/undici/types/header.d.ts +0 -160
  257. package/node_modules/undici/types/index.d.ts +0 -91
  258. package/node_modules/undici/types/interceptors.d.ts +0 -80
  259. package/node_modules/undici/types/mock-agent.d.ts +0 -68
  260. package/node_modules/undici/types/mock-call-history.d.ts +0 -111
  261. package/node_modules/undici/types/mock-client.d.ts +0 -27
  262. package/node_modules/undici/types/mock-errors.d.ts +0 -12
  263. package/node_modules/undici/types/mock-interceptor.d.ts +0 -94
  264. package/node_modules/undici/types/mock-pool.d.ts +0 -27
  265. package/node_modules/undici/types/patch.d.ts +0 -29
  266. package/node_modules/undici/types/pool-stats.d.ts +0 -19
  267. package/node_modules/undici/types/pool.d.ts +0 -41
  268. package/node_modules/undici/types/proxy-agent.d.ts +0 -29
  269. package/node_modules/undici/types/readable.d.ts +0 -68
  270. package/node_modules/undici/types/retry-agent.d.ts +0 -8
  271. package/node_modules/undici/types/retry-handler.d.ts +0 -125
  272. package/node_modules/undici/types/round-robin-pool.d.ts +0 -41
  273. package/node_modules/undici/types/snapshot-agent.d.ts +0 -109
  274. package/node_modules/undici/types/socks5-proxy-agent.d.ts +0 -25
  275. package/node_modules/undici/types/util.d.ts +0 -18
  276. package/node_modules/undici/types/utility.d.ts +0 -7
  277. package/node_modules/undici/types/webidl.d.ts +0 -347
  278. 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
- }