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