Mirror: A Node.js fetch shim using built-in Request, Response, and Headers (but without native fetch)

Compare changes

Choose any two refs to compare.

+1160 -254
+25
.github/workflows/mirror.yml
··· 1 + name: Mirror 2 + on: 3 + push: 4 + branches: 5 + - main 6 + jobs: 7 + mirror: 8 + runs-on: ubuntu-latest 9 + steps: 10 + - name: Checkout repository 11 + uses: actions/checkout@v4 12 + with: 13 + fetch-depth: 0 14 + fetch-tags: true 15 + - name: Mirror 16 + env: 17 + MIRROR_SSH_KEY: ${{ secrets.MIRROR_SSH_KEY }} 18 + GIT_SSH_COMMAND: 'ssh -o StrictHostKeyChecking=yes' 19 + run: | 20 + mkdir -p ~/.ssh 21 + echo "$MIRROR_SSH_KEY" > ~/.ssh/id_rsa 22 + chmod 600 ~/.ssh/id_rsa 23 + ssh-keyscan -H knot.kitten.sh >> ~/.ssh/known_hosts 24 + git remote add mirror "git@knot.kitten.sh:kitten.sh/${GITHUB_REPOSITORY#*/}" 25 + git push --mirror mirror
+7 -6
.github/workflows/release.yml
··· 7 7 jobs: 8 8 release: 9 9 name: Release 10 - runs-on: ubuntu-20.04 10 + runs-on: ubuntu-latest 11 11 timeout-minutes: 20 12 12 permissions: 13 13 contents: write ··· 32 32 - name: Setup Node 33 33 uses: actions/setup-node@v4 34 34 with: 35 - node-version: 22 35 + node-version: 20 36 + registry-url: 'https://registry.npmjs.org' 36 37 cache: 'pnpm' 37 38 38 39 - name: Install Dependencies 39 40 run: pnpm install --frozen-lockfile --prefer-offline 40 41 42 + - name: Update npm 43 + run: npm install -g npm@11.6 44 + 41 45 - name: PR or Publish 42 46 id: changesets 43 - uses: changesets/action@v1.4.5 47 + uses: changesets/action@v1.5.3 44 48 with: 45 49 version: pnpm changeset:version 46 50 publish: pnpm changeset:publish 47 51 env: 48 - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 49 52 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 50 53 51 54 - name: Publish Prerelease 52 55 if: steps.changesets.outputs.published != 'true' 53 56 env: 54 - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 55 57 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 56 58 run: | 57 - npm config set "//registry.npmjs.org/:_authToken" "$NPM_TOKEN" 58 59 git reset --hard origin/main 59 60 pnpm changeset version --no-git-tag --snapshot canary 60 61 pnpm changeset publish --no-git-tag --snapshot canary --tag canary
+86
CHANGELOG.md
··· 1 1 # minifetch 2 2 3 + ## 0.4.6 4 + 5 + ### Patch Changes 6 + 7 + - Replace undici `Response` with `node:stream/consumers` in body helper 8 + Submitted by [@kitten](https://github.com/kitten) (See [#32](https://github.com/kitten/fetch-nodeshim/pull/32)) 9 + 10 + ## 0.4.5 11 + 12 + ### Patch Changes 13 + 14 + - โš ๏ธ Fix `Content-Type` being overridden for string inputs when it's already set 15 + Submitted by [@kitten](https://github.com/kitten) (See [#30](https://github.com/kitten/fetch-nodeshim/pull/30)) 16 + 17 + ## 0.4.4 18 + 19 + ### Patch Changes 20 + 21 + - Limit state in which `incoming.socket` is unrefed and instead `.ref()` it when the body is being read, and `.unref()` it again when reading stops 22 + Submitted by [@kitten](https://github.com/kitten) (See [#28](https://github.com/kitten/fetch-nodeshim/pull/28)) 23 + 24 + ## 0.4.3 25 + 26 + ### Patch Changes 27 + 28 + - โš ๏ธ Fix typo in `NO_PROXY` construction 29 + Submitted by [@kitten](https://github.com/kitten) (See [#18](https://github.com/kitten/fetch-nodeshim/pull/18)) 30 + - Set `Content-Length: 0` when `response.body` is `null` for `PATCH` as well 31 + Submitted by [@kitten](https://github.com/kitten) (See [#23](https://github.com/kitten/fetch-nodeshim/pull/23)) 32 + - Protect against invalid `Location` URI 33 + Submitted by [@kitten](https://github.com/kitten) (See [#26](https://github.com/kitten/fetch-nodeshim/pull/26)) 34 + - Issue an explicit `ETIMEDOUT` when the request times out 35 + Submitted by [@kitten](https://github.com/kitten) (See [#24](https://github.com/kitten/fetch-nodeshim/pull/24)) 36 + - โš ๏ธ Fix `Set-Cookie` list handling by capturing them with `Headers#append` 37 + Submitted by [@kitten](https://github.com/kitten) (See [#20](https://github.com/kitten/fetch-nodeshim/pull/20)) 38 + - Reset `requestOptions.agent` on retry/redirect 39 + Submitted by [@kitten](https://github.com/kitten) (See [#27](https://github.com/kitten/fetch-nodeshim/pull/27)) 40 + - โš ๏ธ Fix `_final` on `InflateStream` calling `callback` before full flush 41 + Submitted by [@kitten](https://github.com/kitten) (See [#25](https://github.com/kitten/fetch-nodeshim/pull/25)) 42 + - Propagate errors for duplex request/response streams, and ensure early errors propagate to the Response stream 43 + Submitted by [@kitten](https://github.com/kitten) (See [#16](https://github.com/kitten/fetch-nodeshim/pull/16)) 44 + - Protect against missing `Symbol.toStringTag` 45 + Submitted by [@kitten](https://github.com/kitten) (See [#19](https://github.com/kitten/fetch-nodeshim/pull/19)) 46 + 47 + ## 0.4.2 48 + 49 + ### Patch Changes 50 + 51 + - Unref the incoming socket when the timeout is disabled, to prevent body streams that never start from keeping processes alive 52 + Submitted by [@kitten](https://github.com/kitten) (See [#14](https://github.com/kitten/fetch-nodeshim/pull/14)) 53 + 54 + ## 0.4.1 55 + 56 + ### Patch Changes 57 + 58 + - Add sane default timeout to `http.request` 59 + Submitted by [@kitten](https://github.com/kitten) (See [#12](https://github.com/kitten/fetch-nodeshim/pull/12)) 60 + 61 + ## 0.4.0 62 + 63 + ### Minor Changes 64 + 65 + - Add automatic configuration for `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` similar to the upcoming Node 24+ built-in support. Agents will automatically be created and used when these environment variables are set 66 + Submitted by [@kitten](https://github.com/kitten) (See [#8](https://github.com/kitten/fetch-nodeshim/pull/8)) 67 + 68 + ### Patch Changes 69 + 70 + - Prevent outright error when `--no-experimental-fetch` is set, which causes `Request`, `Response`, `FormData`, and `Headers` to not be available globally 71 + Submitted by [@kitten](https://github.com/kitten) (See [#11](https://github.com/kitten/fetch-nodeshim/pull/11)) 72 + - Update rollup config for reduced output and exclude sources from sourcemaps 73 + Submitted by [@kitten](https://github.com/kitten) (See [#9](https://github.com/kitten/fetch-nodeshim/pull/9)) 74 + 75 + ## 0.3.0 76 + 77 + ### Minor Changes 78 + 79 + - Add `Body` mixin as export 80 + Submitted by [@kitten](https://github.com/kitten) (See [#6](https://github.com/kitten/fetch-nodeshim/pull/6)) 81 + 82 + ## 0.2.1 83 + 84 + ### Patch Changes 85 + 86 + - Provenance Release 87 + Submitted by [@kitten](https://github.com/kitten) (See [#4](https://github.com/kitten/fetch-nodeshim/pull/4)) 88 + 3 89 ## 0.2.0 4 90 5 91 ### Minor Changes
+1
LICENSE.md
··· 1 1 MIT License 2 2 3 3 Copyright (c) Phil Pluckthun, 4 + Copyright (c) 650 Industries, Inc. (aka Expo), 4 5 Copyright (c) 2016 - 2020 Node Fetch Team, 5 6 Copyright (c) Remix Software Inc. 2020-2021, 6 7 Copyright (c) Shopify Inc. 2022-2024
+11 -2
package.json
··· 1 1 { 2 2 "name": "fetch-nodeshim", 3 - "version": "0.2.0", 3 + "version": "0.4.6", 4 4 "description": "A Node.js fetch shim using built-in Request, Response, and Headers (but without native fetch)", 5 5 "author": "Phil Pluckthun <phil@kitten.sh>", 6 6 "source": "./src/index.ts", ··· 47 47 }, 48 48 "keywords": [], 49 49 "license": "MIT", 50 + "repository": "https://github.com/kitten/fetch-nodeshim", 51 + "bugs": { 52 + "url": "https://github.com/kitten/fetch-nodeshim/issues" 53 + }, 50 54 "devDependencies": { 51 55 "@babel/plugin-transform-block-scoping": "^7.25.9", 52 56 "@babel/plugin-transform-typescript": "^7.26.7", 53 - "@changesets/cli": "^2.27.1", 57 + "@changesets/cli": "^2.29.6", 54 58 "@changesets/get-github-info": "^0.6.0", 55 59 "@rollup/plugin-babel": "^6.0.4", 56 60 "@rollup/plugin-commonjs": "^28.0.2", ··· 65 69 "lint-staged": "^15.4.3", 66 70 "npm-run-all": "^4.1.5", 67 71 "prettier": "^3.4.2", 72 + "proxy-chain": "^2.7.1", 68 73 "rimraf": "^6.0.1", 69 74 "rollup": "^4.32.1", 70 75 "rollup-plugin-cjs-check": "^1.0.3", ··· 72 77 "typescript": "^5.7.3", 73 78 "undici-types": "^6.20.0", 74 79 "vitest": "^3.0.4" 80 + }, 81 + "publishConfig": { 82 + "access": "public", 83 + "provenance": true 75 84 } 76 85 }
+348 -165
pnpm-lock.yaml
··· 15 15 specifier: ^7.26.7 16 16 version: 7.26.7(@babel/core@7.26.7) 17 17 '@changesets/cli': 18 - specifier: ^2.27.1 19 - version: 2.27.12 18 + specifier: ^2.29.6 19 + version: 2.29.6(@types/node@22.12.0) 20 20 '@changesets/get-github-info': 21 21 specifier: ^0.6.0 22 22 version: 0.6.0 ··· 59 59 prettier: 60 60 specifier: ^3.4.2 61 61 version: 3.4.2 62 + proxy-chain: 63 + specifier: ^2.7.1 64 + version: 2.7.1 62 65 rimraf: 63 66 specifier: ^6.0.1 64 67 version: 6.0.1 ··· 91 94 resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} 92 95 engines: {node: '>=6.9.0'} 93 96 94 - '@babel/compat-data@7.26.5': 95 - resolution: {integrity: sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==} 97 + '@babel/code-frame@7.27.1': 98 + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} 99 + engines: {node: '>=6.9.0'} 100 + 101 + '@babel/compat-data@7.28.0': 102 + resolution: {integrity: sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==} 96 103 engines: {node: '>=6.9.0'} 97 104 98 105 '@babel/core@7.26.7': ··· 103 110 resolution: {integrity: sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==} 104 111 engines: {node: '>=6.9.0'} 105 112 113 + '@babel/generator@7.28.3': 114 + resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} 115 + engines: {node: '>=6.9.0'} 116 + 106 117 '@babel/helper-annotate-as-pure@7.25.9': 107 118 resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==} 108 119 engines: {node: '>=6.9.0'} 109 120 110 - '@babel/helper-compilation-targets@7.26.5': 111 - resolution: {integrity: sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==} 121 + '@babel/helper-compilation-targets@7.27.2': 122 + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} 112 123 engines: {node: '>=6.9.0'} 113 124 114 125 '@babel/helper-create-class-features-plugin@7.25.9': ··· 117 128 peerDependencies: 118 129 '@babel/core': ^7.0.0 119 130 131 + '@babel/helper-globals@7.28.0': 132 + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} 133 + engines: {node: '>=6.9.0'} 134 + 120 135 '@babel/helper-member-expression-to-functions@7.25.9': 121 136 resolution: {integrity: sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==} 122 137 engines: {node: '>=6.9.0'} ··· 125 140 resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} 126 141 engines: {node: '>=6.9.0'} 127 142 128 - '@babel/helper-module-transforms@7.26.0': 129 - resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} 143 + '@babel/helper-module-imports@7.27.1': 144 + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} 145 + engines: {node: '>=6.9.0'} 146 + 147 + '@babel/helper-module-transforms@7.28.3': 148 + resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} 130 149 engines: {node: '>=6.9.0'} 131 150 peerDependencies: 132 151 '@babel/core': ^7.0.0 ··· 153 172 resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} 154 173 engines: {node: '>=6.9.0'} 155 174 175 + '@babel/helper-string-parser@7.27.1': 176 + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} 177 + engines: {node: '>=6.9.0'} 178 + 156 179 '@babel/helper-validator-identifier@7.25.9': 157 180 resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} 158 181 engines: {node: '>=6.9.0'} 159 182 160 - '@babel/helper-validator-option@7.25.9': 161 - resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} 183 + '@babel/helper-validator-identifier@7.27.1': 184 + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} 162 185 engines: {node: '>=6.9.0'} 163 186 164 - '@babel/helpers@7.26.7': 165 - resolution: {integrity: sha512-8NHiL98vsi0mbPQmYAGWwfcFaOy4j2HY49fXJCfuDcdE7fMIsH9a7GdaeXpIBsbT7307WU8KCMp5pUVDNL4f9A==} 187 + '@babel/helper-validator-option@7.27.1': 188 + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} 189 + engines: {node: '>=6.9.0'} 190 + 191 + '@babel/helpers@7.28.3': 192 + resolution: {integrity: sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==} 166 193 engines: {node: '>=6.9.0'} 167 194 168 195 '@babel/parser@7.26.7': 169 196 resolution: {integrity: sha512-kEvgGGgEjRUutvdVvZhbn/BxVt+5VSpwXz1j3WYXQbXDo8KzFOPNG2GQbdAiNq8g6wn1yKk7C/qrke03a84V+w==} 197 + engines: {node: '>=6.0.0'} 198 + hasBin: true 199 + 200 + '@babel/parser@7.28.3': 201 + resolution: {integrity: sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==} 170 202 engines: {node: '>=6.0.0'} 171 203 hasBin: true 172 204 ··· 196 228 resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} 197 229 engines: {node: '>=6.9.0'} 198 230 231 + '@babel/template@7.27.2': 232 + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} 233 + engines: {node: '>=6.9.0'} 234 + 199 235 '@babel/traverse@7.26.7': 200 236 resolution: {integrity: sha512-1x1sgeyRLC3r5fQOM0/xtQKsYjyxmFjaOrLJNtZ81inNjyJHGIolTULPiSc/2qe1/qfpFLisLQYFnnZl7QoedA==} 201 237 engines: {node: '>=6.9.0'} 202 238 239 + '@babel/traverse@7.28.3': 240 + resolution: {integrity: sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==} 241 + engines: {node: '>=6.9.0'} 242 + 203 243 '@babel/types@7.26.7': 204 244 resolution: {integrity: sha512-t8kDRGrKXyp6+tjUh7hw2RLyclsW4TRoRvRHtSyAX9Bb5ldlFh+90YAYY6awRXrlB4G5G2izNeGySpATlFzmOg==} 205 245 engines: {node: '>=6.9.0'} 206 246 207 - '@changesets/apply-release-plan@7.0.8': 208 - resolution: {integrity: sha512-qjMUj4DYQ1Z6qHawsn7S71SujrExJ+nceyKKyI9iB+M5p9lCL55afuEd6uLBPRpLGWQwkwvWegDHtwHJb1UjpA==} 247 + '@babel/types@7.28.2': 248 + resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} 249 + engines: {node: '>=6.9.0'} 209 250 210 - '@changesets/assemble-release-plan@6.0.5': 211 - resolution: {integrity: sha512-IgvBWLNKZd6k4t72MBTBK3nkygi0j3t3zdC1zrfusYo0KpdsvnDjrMM9vPnTCLCMlfNs55jRL4gIMybxa64FCQ==} 251 + '@changesets/apply-release-plan@7.0.12': 252 + resolution: {integrity: sha512-EaET7As5CeuhTzvXTQCRZeBUcisoYPDDcXvgTE/2jmmypKp0RC7LxKj/yzqeh/1qFTZI7oDGFcL1PHRuQuketQ==} 212 253 213 - '@changesets/changelog-git@0.2.0': 214 - resolution: {integrity: sha512-bHOx97iFI4OClIT35Lok3sJAwM31VbUM++gnMBV16fdbtBhgYu4dxsphBF/0AZZsyAHMrnM0yFcj5gZM1py6uQ==} 254 + '@changesets/assemble-release-plan@6.0.9': 255 + resolution: {integrity: sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ==} 215 256 216 - '@changesets/cli@2.27.12': 217 - resolution: {integrity: sha512-9o3fOfHYOvBnyEn0mcahB7wzaA3P4bGJf8PNqGit5PKaMEFdsRixik+txkrJWd2VX+O6wRFXpxQL8j/1ANKE9g==} 257 + '@changesets/changelog-git@0.2.1': 258 + resolution: {integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==} 259 + 260 + '@changesets/cli@2.29.6': 261 + resolution: {integrity: sha512-6qCcVsIG1KQLhpQ5zE8N0PckIx4+9QlHK3z6/lwKnw7Tir71Bjw8BeOZaxA/4Jt00pcgCnCSWZnyuZf5Il05QQ==} 218 262 hasBin: true 219 263 220 - '@changesets/config@3.0.5': 221 - resolution: {integrity: sha512-QyXLSSd10GquX7hY0Mt4yQFMEeqnO5z/XLpbIr4PAkNNoQNKwDyiSrx4yd749WddusH1v3OSiA0NRAYmH/APpQ==} 264 + '@changesets/config@3.1.1': 265 + resolution: {integrity: sha512-bd+3Ap2TKXxljCggI0mKPfzCQKeV/TU4yO2h2C6vAihIo8tzseAn2e7klSuiyYYXvgu53zMN1OeYMIQkaQoWnA==} 222 266 223 267 '@changesets/errors@0.2.0': 224 268 resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} 225 269 226 - '@changesets/get-dependents-graph@2.1.2': 227 - resolution: {integrity: sha512-sgcHRkiBY9i4zWYBwlVyAjEM9sAzs4wYVwJUdnbDLnVG3QwAaia1Mk5P8M7kraTOZN+vBET7n8KyB0YXCbFRLQ==} 270 + '@changesets/get-dependents-graph@2.1.3': 271 + resolution: {integrity: sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==} 228 272 229 273 '@changesets/get-github-info@0.6.0': 230 274 resolution: {integrity: sha512-v/TSnFVXI8vzX9/w3DU2Ol+UlTZcu3m0kXTjTT4KlAdwSvwutcByYwyYn9hwerPWfPkT2JfpoX0KgvCEi8Q/SA==} 231 275 232 - '@changesets/get-release-plan@4.0.6': 233 - resolution: {integrity: sha512-FHRwBkY7Eili04Y5YMOZb0ezQzKikTka4wL753vfUA5COSebt7KThqiuCN9BewE4/qFGgF/5t3AuzXx1/UAY4w==} 276 + '@changesets/get-release-plan@4.0.13': 277 + resolution: {integrity: sha512-DWG1pus72FcNeXkM12tx+xtExyH/c9I1z+2aXlObH3i9YA7+WZEVaiHzHl03thpvAgWTRaH64MpfHxozfF7Dvg==} 234 278 235 279 '@changesets/get-version-range-type@0.4.0': 236 280 resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==} 237 281 238 - '@changesets/git@3.0.2': 239 - resolution: {integrity: sha512-r1/Kju9Y8OxRRdvna+nxpQIsMsRQn9dhhAZt94FLDeu0Hij2hnOozW8iqnHBgvu+KdnJppCveQwK4odwfw/aWQ==} 282 + '@changesets/git@3.0.4': 283 + resolution: {integrity: sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==} 240 284 241 285 '@changesets/logger@0.1.1': 242 286 resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==} 243 287 244 - '@changesets/parse@0.4.0': 245 - resolution: {integrity: sha512-TS/9KG2CdGXS27S+QxbZXgr8uPsP4yNJYb4BC2/NeFUj80Rni3TeD2qwWmabymxmrLo7JEsytXH1FbpKTbvivw==} 288 + '@changesets/parse@0.4.1': 289 + resolution: {integrity: sha512-iwksMs5Bf/wUItfcg+OXrEpravm5rEd9Bf4oyIPL4kVTmJQ7PNDSd6MDYkpSJR1pn7tz/k8Zf2DhTCqX08Ou+Q==} 246 290 247 - '@changesets/pre@2.0.1': 248 - resolution: {integrity: sha512-vvBJ/If4jKM4tPz9JdY2kGOgWmCowUYOi5Ycv8dyLnEE8FgpYYUo1mgJZxcdtGGP3aG8rAQulGLyyXGSLkIMTQ==} 291 + '@changesets/pre@2.0.2': 292 + resolution: {integrity: sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==} 249 293 250 - '@changesets/read@0.6.2': 251 - resolution: {integrity: sha512-wjfQpJvryY3zD61p8jR87mJdyx2FIhEcdXhKUqkja87toMrP/3jtg/Yg29upN+N4Ckf525/uvV7a4tzBlpk6gg==} 294 + '@changesets/read@0.6.5': 295 + resolution: {integrity: sha512-UPzNGhsSjHD3Veb0xO/MwvasGe8eMyNrR/sT9gR8Q3DhOQZirgKhhXv/8hVsI0QpPjR004Z9iFxoJU6in3uGMg==} 252 296 253 - '@changesets/should-skip-package@0.1.1': 254 - resolution: {integrity: sha512-H9LjLbF6mMHLtJIc/eHR9Na+MifJ3VxtgP/Y+XLn4BF7tDTEN1HNYtH6QMcjP1uxp9sjaFYmW8xqloaCi/ckTg==} 297 + '@changesets/should-skip-package@0.1.2': 298 + resolution: {integrity: sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==} 255 299 256 300 '@changesets/types@4.1.0': 257 301 resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==} 258 302 259 - '@changesets/types@6.0.0': 260 - resolution: {integrity: sha512-b1UkfNulgKoWfqyHtzKS5fOZYSJO+77adgL7DLRDr+/7jhChN+QcHnbjiQVOz/U+Ts3PGNySq7diAItzDgugfQ==} 303 + '@changesets/types@6.1.0': 304 + resolution: {integrity: sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==} 261 305 262 - '@changesets/write@0.3.2': 263 - resolution: {integrity: sha512-kDxDrPNpUgsjDbWBvUo27PzKX4gqeKOlhibaOXDJA6kuBisGqNHv/HwGJrAu8U/dSf8ZEFIeHIPtvSlZI1kULw==} 306 + '@changesets/write@0.4.0': 307 + resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} 264 308 265 309 '@esbuild/aix-ppc64@0.24.2': 266 310 resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} ··· 412 456 cpu: [x64] 413 457 os: [win32] 414 458 459 + '@inquirer/external-editor@1.0.1': 460 + resolution: {integrity: sha512-Oau4yL24d2B5IL4ma4UpbQigkVhzPDXLoqy1ggK4gnHg/stmkffJE4oOXHXF3uz0UEpywG68KcyXsyYpA1Re/Q==} 461 + engines: {node: '>=18'} 462 + peerDependencies: 463 + '@types/node': '>=18' 464 + peerDependenciesMeta: 465 + '@types/node': 466 + optional: true 467 + 415 468 '@isaacs/cliui@8.0.2': 416 469 resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} 417 470 engines: {node: '>=12'} 471 + 472 + '@jridgewell/gen-mapping@0.3.13': 473 + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} 418 474 419 475 '@jridgewell/gen-mapping@0.3.8': 420 476 resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} ··· 434 490 '@jridgewell/sourcemap-codec@1.5.0': 435 491 resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} 436 492 493 + '@jridgewell/sourcemap-codec@1.5.5': 494 + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} 495 + 437 496 '@jridgewell/trace-mapping@0.3.25': 438 497 resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} 498 + 499 + '@jridgewell/trace-mapping@0.3.30': 500 + resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==} 439 501 440 502 '@manypkg/find-root@1.1.0': 441 503 resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} ··· 651 713 engines: {node: '>=0.4.0'} 652 714 hasBin: true 653 715 716 + agent-base@7.1.4: 717 + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} 718 + engines: {node: '>= 14'} 719 + 654 720 ansi-colors@4.1.3: 655 721 resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} 656 722 engines: {node: '>=6'} ··· 726 792 resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} 727 793 engines: {node: '>=8'} 728 794 729 - browserslist@4.24.4: 730 - resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==} 795 + browserslist@4.25.4: 796 + resolution: {integrity: sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg==} 731 797 engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} 732 798 hasBin: true 733 799 ··· 754 820 resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} 755 821 engines: {node: '>= 0.4'} 756 822 757 - caniuse-lite@1.0.30001696: 758 - resolution: {integrity: sha512-pDCPkvzfa39ehJtJ+OwGT/2yvT2SbjfHhiIW2LWOAcMQ7BzwxT/XuyUp4OTOd0XFWA6BKw0JalnBHgSi5DGJBQ==} 823 + caniuse-lite@1.0.30001737: 824 + resolution: {integrity: sha512-BiloLiXtQNrY5UyF0+1nSJLXUENuhka2pzy2Fx5pGxqavdrxSCW4U6Pn/PoG3Efspi2frRbHpBV2XsrPE6EDlw==} 759 825 760 826 chai@5.1.2: 761 827 resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==} ··· 769 835 resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} 770 836 engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} 771 837 772 - chardet@0.7.0: 773 - resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} 838 + chardet@2.1.0: 839 + resolution: {integrity: sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==} 774 840 775 841 check-error@2.1.1: 776 842 resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} ··· 859 925 supports-color: 860 926 optional: true 861 927 928 + debug@4.4.1: 929 + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} 930 + engines: {node: '>=6.0'} 931 + peerDependencies: 932 + supports-color: '*' 933 + peerDependenciesMeta: 934 + supports-color: 935 + optional: true 936 + 862 937 deep-eql@5.0.2: 863 938 resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} 864 939 engines: {node: '>=6'} ··· 902 977 eastasianwidth@0.2.0: 903 978 resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 904 979 905 - electron-to-chromium@1.5.90: 906 - resolution: {integrity: sha512-C3PN4aydfW91Natdyd449Kw+BzhLmof6tzy5W1pFC5SpQxVXT+oyiyOG9AgYYSN9OdA/ik3YkCrpwqI8ug5Tug==} 980 + electron-to-chromium@1.5.211: 981 + resolution: {integrity: sha512-IGBvimJkotaLzFnwIVgW9/UD/AOJ2tByUmeOrtqBfACSbAw5b1G0XpvdaieKyc7ULmbwXVx+4e4Be8pOPBrYkw==} 907 982 908 983 emoji-regex@10.4.0: 909 984 resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} ··· 989 1064 990 1065 extendable-error@0.1.7: 991 1066 resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} 992 - 993 - external-editor@3.1.0: 994 - resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} 995 - engines: {node: '>=4'} 996 1067 997 1068 fast-glob@3.3.3: 998 1069 resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} ··· 1134 1205 hosted-git-info@2.8.9: 1135 1206 resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} 1136 1207 1137 - human-id@1.0.2: 1138 - resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} 1208 + human-id@4.1.1: 1209 + resolution: {integrity: sha512-3gKm/gCSUipeLsRYZbbdA1BD83lBoWUkZ7G9VFrhWPAU76KwYo5KR8V28bpoPm/ygy0x5/GCbpRQdY7VLYCoIg==} 1210 + hasBin: true 1139 1211 1140 1212 human-signals@5.0.0: 1141 1213 resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} 1142 1214 engines: {node: '>=16.17.0'} 1143 1215 1144 - iconv-lite@0.4.24: 1145 - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} 1216 + iconv-lite@0.6.3: 1217 + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} 1146 1218 engines: {node: '>=0.10.0'} 1147 1219 1148 1220 ignore@5.3.2: ··· 1152 1224 internal-slot@1.1.0: 1153 1225 resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} 1154 1226 engines: {node: '>= 0.4'} 1227 + 1228 + ip-address@10.1.0: 1229 + resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} 1230 + engines: {node: '>= 12'} 1155 1231 1156 1232 is-array-buffer@3.0.5: 1157 1233 resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} ··· 1461 1537 resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} 1462 1538 engines: {node: '>=18'} 1463 1539 1464 - os-tmpdir@1.0.2: 1465 - resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} 1466 - engines: {node: '>=0.10.0'} 1467 - 1468 1540 outdent@0.5.0: 1469 1541 resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} 1470 1542 ··· 1587 1659 engines: {node: '>=14'} 1588 1660 hasBin: true 1589 1661 1662 + proxy-chain@2.7.1: 1663 + resolution: {integrity: sha512-LtXu0miohJYrHWJxv8wA6EoGreRcX1hxKb7qlE1pMFH+BXE7bqMvpyhzR/JvR6M5SzYKzyHFpvfmYJrZeMtwAg==} 1664 + engines: {node: '>=14'} 1665 + 1590 1666 queue-microtask@1.2.3: 1591 1667 resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 1592 1668 ··· 1759 1835 resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==} 1760 1836 engines: {node: '>=18'} 1761 1837 1838 + smart-buffer@4.2.0: 1839 + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} 1840 + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} 1841 + 1762 1842 smob@1.5.0: 1763 1843 resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} 1844 + 1845 + socks-proxy-agent@8.0.5: 1846 + resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} 1847 + engines: {node: '>= 14'} 1848 + 1849 + socks@2.8.7: 1850 + resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} 1851 + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} 1764 1852 1765 1853 source-map-js@1.2.1: 1766 1854 resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} ··· 1884 1972 resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} 1885 1973 engines: {node: '>=14.0.0'} 1886 1974 1887 - tmp@0.0.33: 1888 - resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} 1889 - engines: {node: '>=0.6.0'} 1890 - 1891 1975 to-regex-range@5.0.1: 1892 1976 resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 1893 1977 engines: {node: '>=8.0'} 1894 1978 1895 1979 tr46@0.0.3: 1896 1980 resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} 1981 + 1982 + tslib@2.8.1: 1983 + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} 1897 1984 1898 1985 typed-array-buffer@1.0.3: 1899 1986 resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} ··· 1933 2020 resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} 1934 2021 engines: {node: '>= 4.0.0'} 1935 2022 1936 - update-browserslist-db@1.1.2: 1937 - resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==} 2023 + update-browserslist-db@1.1.3: 2024 + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} 1938 2025 hasBin: true 1939 2026 peerDependencies: 1940 2027 browserslist: '>= 4.21.0' ··· 2075 2162 2076 2163 '@ampproject/remapping@2.3.0': 2077 2164 dependencies: 2078 - '@jridgewell/gen-mapping': 0.3.8 2079 - '@jridgewell/trace-mapping': 0.3.25 2165 + '@jridgewell/gen-mapping': 0.3.13 2166 + '@jridgewell/trace-mapping': 0.3.30 2080 2167 2081 2168 '@babel/code-frame@7.26.2': 2082 2169 dependencies: ··· 2084 2171 js-tokens: 4.0.0 2085 2172 picocolors: 1.1.1 2086 2173 2087 - '@babel/compat-data@7.26.5': {} 2174 + '@babel/code-frame@7.27.1': 2175 + dependencies: 2176 + '@babel/helper-validator-identifier': 7.27.1 2177 + js-tokens: 4.0.0 2178 + picocolors: 1.1.1 2179 + 2180 + '@babel/compat-data@7.28.0': {} 2088 2181 2089 2182 '@babel/core@7.26.7': 2090 2183 dependencies: 2091 2184 '@ampproject/remapping': 2.3.0 2092 - '@babel/code-frame': 7.26.2 2093 - '@babel/generator': 7.26.5 2094 - '@babel/helper-compilation-targets': 7.26.5 2095 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.7) 2096 - '@babel/helpers': 7.26.7 2097 - '@babel/parser': 7.26.7 2098 - '@babel/template': 7.25.9 2099 - '@babel/traverse': 7.26.7 2100 - '@babel/types': 7.26.7 2185 + '@babel/code-frame': 7.27.1 2186 + '@babel/generator': 7.28.3 2187 + '@babel/helper-compilation-targets': 7.27.2 2188 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.26.7) 2189 + '@babel/helpers': 7.28.3 2190 + '@babel/parser': 7.28.3 2191 + '@babel/template': 7.27.2 2192 + '@babel/traverse': 7.28.3 2193 + '@babel/types': 7.28.2 2101 2194 convert-source-map: 2.0.0 2102 - debug: 4.4.0 2195 + debug: 4.4.1 2103 2196 gensync: 1.0.0-beta.2 2104 2197 json5: 2.2.3 2105 2198 semver: 6.3.1 ··· 2114 2207 '@jridgewell/trace-mapping': 0.3.25 2115 2208 jsesc: 3.1.0 2116 2209 2210 + '@babel/generator@7.28.3': 2211 + dependencies: 2212 + '@babel/parser': 7.28.3 2213 + '@babel/types': 7.28.2 2214 + '@jridgewell/gen-mapping': 0.3.13 2215 + '@jridgewell/trace-mapping': 0.3.30 2216 + jsesc: 3.1.0 2217 + 2117 2218 '@babel/helper-annotate-as-pure@7.25.9': 2118 2219 dependencies: 2119 2220 '@babel/types': 7.26.7 2120 2221 2121 - '@babel/helper-compilation-targets@7.26.5': 2222 + '@babel/helper-compilation-targets@7.27.2': 2122 2223 dependencies: 2123 - '@babel/compat-data': 7.26.5 2124 - '@babel/helper-validator-option': 7.25.9 2125 - browserslist: 4.24.4 2224 + '@babel/compat-data': 7.28.0 2225 + '@babel/helper-validator-option': 7.27.1 2226 + browserslist: 4.25.4 2126 2227 lru-cache: 5.1.1 2127 2228 semver: 6.3.1 2128 2229 ··· 2138 2239 semver: 6.3.1 2139 2240 transitivePeerDependencies: 2140 2241 - supports-color 2242 + 2243 + '@babel/helper-globals@7.28.0': {} 2141 2244 2142 2245 '@babel/helper-member-expression-to-functions@7.25.9': 2143 2246 dependencies: ··· 2153 2256 transitivePeerDependencies: 2154 2257 - supports-color 2155 2258 2156 - '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.7)': 2259 + '@babel/helper-module-imports@7.27.1': 2260 + dependencies: 2261 + '@babel/traverse': 7.28.3 2262 + '@babel/types': 7.28.2 2263 + transitivePeerDependencies: 2264 + - supports-color 2265 + 2266 + '@babel/helper-module-transforms@7.28.3(@babel/core@7.26.7)': 2157 2267 dependencies: 2158 2268 '@babel/core': 7.26.7 2159 - '@babel/helper-module-imports': 7.25.9 2160 - '@babel/helper-validator-identifier': 7.25.9 2161 - '@babel/traverse': 7.26.7 2269 + '@babel/helper-module-imports': 7.27.1 2270 + '@babel/helper-validator-identifier': 7.27.1 2271 + '@babel/traverse': 7.28.3 2162 2272 transitivePeerDependencies: 2163 2273 - supports-color 2164 2274 ··· 2186 2296 2187 2297 '@babel/helper-string-parser@7.25.9': {} 2188 2298 2299 + '@babel/helper-string-parser@7.27.1': {} 2300 + 2189 2301 '@babel/helper-validator-identifier@7.25.9': {} 2190 2302 2191 - '@babel/helper-validator-option@7.25.9': {} 2303 + '@babel/helper-validator-identifier@7.27.1': {} 2192 2304 2193 - '@babel/helpers@7.26.7': 2305 + '@babel/helper-validator-option@7.27.1': {} 2306 + 2307 + '@babel/helpers@7.28.3': 2194 2308 dependencies: 2195 - '@babel/template': 7.25.9 2196 - '@babel/types': 7.26.7 2309 + '@babel/template': 7.27.2 2310 + '@babel/types': 7.28.2 2197 2311 2198 2312 '@babel/parser@7.26.7': 2199 2313 dependencies: 2200 2314 '@babel/types': 7.26.7 2315 + 2316 + '@babel/parser@7.28.3': 2317 + dependencies: 2318 + '@babel/types': 7.28.2 2201 2319 2202 2320 '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.7)': 2203 2321 dependencies: ··· 2230 2348 '@babel/parser': 7.26.7 2231 2349 '@babel/types': 7.26.7 2232 2350 2351 + '@babel/template@7.27.2': 2352 + dependencies: 2353 + '@babel/code-frame': 7.27.1 2354 + '@babel/parser': 7.28.3 2355 + '@babel/types': 7.28.2 2356 + 2233 2357 '@babel/traverse@7.26.7': 2234 2358 dependencies: 2235 2359 '@babel/code-frame': 7.26.2 ··· 2242 2366 transitivePeerDependencies: 2243 2367 - supports-color 2244 2368 2369 + '@babel/traverse@7.28.3': 2370 + dependencies: 2371 + '@babel/code-frame': 7.27.1 2372 + '@babel/generator': 7.28.3 2373 + '@babel/helper-globals': 7.28.0 2374 + '@babel/parser': 7.28.3 2375 + '@babel/template': 7.27.2 2376 + '@babel/types': 7.28.2 2377 + debug: 4.4.1 2378 + transitivePeerDependencies: 2379 + - supports-color 2380 + 2245 2381 '@babel/types@7.26.7': 2246 2382 dependencies: 2247 2383 '@babel/helper-string-parser': 7.25.9 2248 2384 '@babel/helper-validator-identifier': 7.25.9 2249 2385 2250 - '@changesets/apply-release-plan@7.0.8': 2386 + '@babel/types@7.28.2': 2251 2387 dependencies: 2252 - '@changesets/config': 3.0.5 2388 + '@babel/helper-string-parser': 7.27.1 2389 + '@babel/helper-validator-identifier': 7.27.1 2390 + 2391 + '@changesets/apply-release-plan@7.0.12': 2392 + dependencies: 2393 + '@changesets/config': 3.1.1 2253 2394 '@changesets/get-version-range-type': 0.4.0 2254 - '@changesets/git': 3.0.2 2255 - '@changesets/should-skip-package': 0.1.1 2256 - '@changesets/types': 6.0.0 2395 + '@changesets/git': 3.0.4 2396 + '@changesets/should-skip-package': 0.1.2 2397 + '@changesets/types': 6.1.0 2257 2398 '@manypkg/get-packages': 1.1.3 2258 2399 detect-indent: 6.1.0 2259 2400 fs-extra: 7.0.1 ··· 2263 2404 resolve-from: 5.0.0 2264 2405 semver: 7.7.0 2265 2406 2266 - '@changesets/assemble-release-plan@6.0.5': 2407 + '@changesets/assemble-release-plan@6.0.9': 2267 2408 dependencies: 2268 2409 '@changesets/errors': 0.2.0 2269 - '@changesets/get-dependents-graph': 2.1.2 2270 - '@changesets/should-skip-package': 0.1.1 2271 - '@changesets/types': 6.0.0 2410 + '@changesets/get-dependents-graph': 2.1.3 2411 + '@changesets/should-skip-package': 0.1.2 2412 + '@changesets/types': 6.1.0 2272 2413 '@manypkg/get-packages': 1.1.3 2273 2414 semver: 7.7.0 2274 2415 2275 - '@changesets/changelog-git@0.2.0': 2416 + '@changesets/changelog-git@0.2.1': 2276 2417 dependencies: 2277 - '@changesets/types': 6.0.0 2418 + '@changesets/types': 6.1.0 2278 2419 2279 - '@changesets/cli@2.27.12': 2420 + '@changesets/cli@2.29.6(@types/node@22.12.0)': 2280 2421 dependencies: 2281 - '@changesets/apply-release-plan': 7.0.8 2282 - '@changesets/assemble-release-plan': 6.0.5 2283 - '@changesets/changelog-git': 0.2.0 2284 - '@changesets/config': 3.0.5 2422 + '@changesets/apply-release-plan': 7.0.12 2423 + '@changesets/assemble-release-plan': 6.0.9 2424 + '@changesets/changelog-git': 0.2.1 2425 + '@changesets/config': 3.1.1 2285 2426 '@changesets/errors': 0.2.0 2286 - '@changesets/get-dependents-graph': 2.1.2 2287 - '@changesets/get-release-plan': 4.0.6 2288 - '@changesets/git': 3.0.2 2427 + '@changesets/get-dependents-graph': 2.1.3 2428 + '@changesets/get-release-plan': 4.0.13 2429 + '@changesets/git': 3.0.4 2289 2430 '@changesets/logger': 0.1.1 2290 - '@changesets/pre': 2.0.1 2291 - '@changesets/read': 0.6.2 2292 - '@changesets/should-skip-package': 0.1.1 2293 - '@changesets/types': 6.0.0 2294 - '@changesets/write': 0.3.2 2431 + '@changesets/pre': 2.0.2 2432 + '@changesets/read': 0.6.5 2433 + '@changesets/should-skip-package': 0.1.2 2434 + '@changesets/types': 6.1.0 2435 + '@changesets/write': 0.4.0 2436 + '@inquirer/external-editor': 1.0.1(@types/node@22.12.0) 2295 2437 '@manypkg/get-packages': 1.1.3 2296 2438 ansi-colors: 4.1.3 2297 2439 ci-info: 3.9.0 2298 2440 enquirer: 2.4.1 2299 - external-editor: 3.1.0 2300 2441 fs-extra: 7.0.1 2301 2442 mri: 1.2.0 2302 2443 p-limit: 2.3.0 ··· 2306 2447 semver: 7.7.0 2307 2448 spawndamnit: 3.0.1 2308 2449 term-size: 2.2.1 2450 + transitivePeerDependencies: 2451 + - '@types/node' 2309 2452 2310 - '@changesets/config@3.0.5': 2453 + '@changesets/config@3.1.1': 2311 2454 dependencies: 2312 2455 '@changesets/errors': 0.2.0 2313 - '@changesets/get-dependents-graph': 2.1.2 2456 + '@changesets/get-dependents-graph': 2.1.3 2314 2457 '@changesets/logger': 0.1.1 2315 - '@changesets/types': 6.0.0 2458 + '@changesets/types': 6.1.0 2316 2459 '@manypkg/get-packages': 1.1.3 2317 2460 fs-extra: 7.0.1 2318 2461 micromatch: 4.0.8 ··· 2321 2464 dependencies: 2322 2465 extendable-error: 0.1.7 2323 2466 2324 - '@changesets/get-dependents-graph@2.1.2': 2467 + '@changesets/get-dependents-graph@2.1.3': 2325 2468 dependencies: 2326 - '@changesets/types': 6.0.0 2469 + '@changesets/types': 6.1.0 2327 2470 '@manypkg/get-packages': 1.1.3 2328 2471 picocolors: 1.1.1 2329 2472 semver: 7.7.0 ··· 2335 2478 transitivePeerDependencies: 2336 2479 - encoding 2337 2480 2338 - '@changesets/get-release-plan@4.0.6': 2481 + '@changesets/get-release-plan@4.0.13': 2339 2482 dependencies: 2340 - '@changesets/assemble-release-plan': 6.0.5 2341 - '@changesets/config': 3.0.5 2342 - '@changesets/pre': 2.0.1 2343 - '@changesets/read': 0.6.2 2344 - '@changesets/types': 6.0.0 2483 + '@changesets/assemble-release-plan': 6.0.9 2484 + '@changesets/config': 3.1.1 2485 + '@changesets/pre': 2.0.2 2486 + '@changesets/read': 0.6.5 2487 + '@changesets/types': 6.1.0 2345 2488 '@manypkg/get-packages': 1.1.3 2346 2489 2347 2490 '@changesets/get-version-range-type@0.4.0': {} 2348 2491 2349 - '@changesets/git@3.0.2': 2492 + '@changesets/git@3.0.4': 2350 2493 dependencies: 2351 2494 '@changesets/errors': 0.2.0 2352 2495 '@manypkg/get-packages': 1.1.3 ··· 2358 2501 dependencies: 2359 2502 picocolors: 1.1.1 2360 2503 2361 - '@changesets/parse@0.4.0': 2504 + '@changesets/parse@0.4.1': 2362 2505 dependencies: 2363 - '@changesets/types': 6.0.0 2506 + '@changesets/types': 6.1.0 2364 2507 js-yaml: 3.14.1 2365 2508 2366 - '@changesets/pre@2.0.1': 2509 + '@changesets/pre@2.0.2': 2367 2510 dependencies: 2368 2511 '@changesets/errors': 0.2.0 2369 - '@changesets/types': 6.0.0 2512 + '@changesets/types': 6.1.0 2370 2513 '@manypkg/get-packages': 1.1.3 2371 2514 fs-extra: 7.0.1 2372 2515 2373 - '@changesets/read@0.6.2': 2516 + '@changesets/read@0.6.5': 2374 2517 dependencies: 2375 - '@changesets/git': 3.0.2 2518 + '@changesets/git': 3.0.4 2376 2519 '@changesets/logger': 0.1.1 2377 - '@changesets/parse': 0.4.0 2378 - '@changesets/types': 6.0.0 2520 + '@changesets/parse': 0.4.1 2521 + '@changesets/types': 6.1.0 2379 2522 fs-extra: 7.0.1 2380 2523 p-filter: 2.1.0 2381 2524 picocolors: 1.1.1 2382 2525 2383 - '@changesets/should-skip-package@0.1.1': 2526 + '@changesets/should-skip-package@0.1.2': 2384 2527 dependencies: 2385 - '@changesets/types': 6.0.0 2528 + '@changesets/types': 6.1.0 2386 2529 '@manypkg/get-packages': 1.1.3 2387 2530 2388 2531 '@changesets/types@4.1.0': {} 2389 2532 2390 - '@changesets/types@6.0.0': {} 2533 + '@changesets/types@6.1.0': {} 2391 2534 2392 - '@changesets/write@0.3.2': 2535 + '@changesets/write@0.4.0': 2393 2536 dependencies: 2394 - '@changesets/types': 6.0.0 2537 + '@changesets/types': 6.1.0 2395 2538 fs-extra: 7.0.1 2396 - human-id: 1.0.2 2539 + human-id: 4.1.1 2397 2540 prettier: 2.8.8 2398 2541 2399 2542 '@esbuild/aix-ppc64@0.24.2': ··· 2471 2614 '@esbuild/win32-x64@0.24.2': 2472 2615 optional: true 2473 2616 2617 + '@inquirer/external-editor@1.0.1(@types/node@22.12.0)': 2618 + dependencies: 2619 + chardet: 2.1.0 2620 + iconv-lite: 0.6.3 2621 + optionalDependencies: 2622 + '@types/node': 22.12.0 2623 + 2474 2624 '@isaacs/cliui@8.0.2': 2475 2625 dependencies: 2476 2626 string-width: 5.1.2 ··· 2479 2629 strip-ansi-cjs: strip-ansi@6.0.1 2480 2630 wrap-ansi: 8.1.0 2481 2631 wrap-ansi-cjs: wrap-ansi@7.0.0 2632 + 2633 + '@jridgewell/gen-mapping@0.3.13': 2634 + dependencies: 2635 + '@jridgewell/sourcemap-codec': 1.5.5 2636 + '@jridgewell/trace-mapping': 0.3.30 2482 2637 2483 2638 '@jridgewell/gen-mapping@0.3.8': 2484 2639 dependencies: ··· 2497 2652 2498 2653 '@jridgewell/sourcemap-codec@1.5.0': {} 2499 2654 2655 + '@jridgewell/sourcemap-codec@1.5.5': {} 2656 + 2500 2657 '@jridgewell/trace-mapping@0.3.25': 2501 2658 dependencies: 2502 2659 '@jridgewell/resolve-uri': 3.1.2 2503 2660 '@jridgewell/sourcemap-codec': 1.5.0 2661 + 2662 + '@jridgewell/trace-mapping@0.3.30': 2663 + dependencies: 2664 + '@jridgewell/resolve-uri': 3.1.2 2665 + '@jridgewell/sourcemap-codec': 1.5.5 2504 2666 2505 2667 '@manypkg/find-root@1.1.0': 2506 2668 dependencies: ··· 2695 2857 2696 2858 acorn@8.14.0: {} 2697 2859 2860 + agent-base@7.1.4: {} 2861 + 2698 2862 ansi-colors@4.1.3: {} 2699 2863 2700 2864 ansi-escapes@7.0.0: ··· 2765 2929 dependencies: 2766 2930 fill-range: 7.1.1 2767 2931 2768 - browserslist@4.24.4: 2932 + browserslist@4.25.4: 2769 2933 dependencies: 2770 - caniuse-lite: 1.0.30001696 2771 - electron-to-chromium: 1.5.90 2934 + caniuse-lite: 1.0.30001737 2935 + electron-to-chromium: 1.5.211 2772 2936 node-releases: 2.0.19 2773 - update-browserslist-db: 1.1.2(browserslist@4.24.4) 2937 + update-browserslist-db: 1.1.3(browserslist@4.25.4) 2774 2938 2775 2939 buffer-from@1.1.2: {} 2776 2940 ··· 2797 2961 call-bind-apply-helpers: 1.0.1 2798 2962 get-intrinsic: 1.2.7 2799 2963 2800 - caniuse-lite@1.0.30001696: {} 2964 + caniuse-lite@1.0.30001737: {} 2801 2965 2802 2966 chai@5.1.2: 2803 2967 dependencies: ··· 2815 2979 2816 2980 chalk@5.4.1: {} 2817 2981 2818 - chardet@0.7.0: {} 2982 + chardet@2.1.0: {} 2819 2983 2820 2984 check-error@2.1.1: {} 2821 2985 ··· 2898 3062 dependencies: 2899 3063 ms: 2.1.3 2900 3064 3065 + debug@4.4.1: 3066 + dependencies: 3067 + ms: 2.1.3 3068 + 2901 3069 deep-eql@5.0.2: {} 2902 3070 2903 3071 deepmerge@4.3.1: {} ··· 2936 3104 2937 3105 eastasianwidth@0.2.0: {} 2938 3106 2939 - electron-to-chromium@1.5.90: {} 3107 + electron-to-chromium@1.5.211: {} 2940 3108 2941 3109 emoji-regex@10.4.0: {} 2942 3110 ··· 3090 3258 3091 3259 extendable-error@0.1.7: {} 3092 3260 3093 - external-editor@3.1.0: 3094 - dependencies: 3095 - chardet: 0.7.0 3096 - iconv-lite: 0.4.24 3097 - tmp: 0.0.33 3098 - 3099 3261 fast-glob@3.3.3: 3100 3262 dependencies: 3101 3263 '@nodelib/fs.stat': 2.0.5 ··· 3251 3413 3252 3414 hosted-git-info@2.8.9: {} 3253 3415 3254 - human-id@1.0.2: {} 3416 + human-id@4.1.1: {} 3255 3417 3256 3418 human-signals@5.0.0: {} 3257 3419 3258 - iconv-lite@0.4.24: 3420 + iconv-lite@0.6.3: 3259 3421 dependencies: 3260 3422 safer-buffer: 2.1.2 3261 3423 ··· 3266 3428 es-errors: 1.3.0 3267 3429 hasown: 2.0.2 3268 3430 side-channel: 1.1.0 3431 + 3432 + ip-address@10.1.0: {} 3269 3433 3270 3434 is-array-buffer@3.0.5: 3271 3435 dependencies: ··· 3571 3735 dependencies: 3572 3736 mimic-function: 5.0.1 3573 3737 3574 - os-tmpdir@1.0.2: {} 3575 - 3576 3738 outdent@0.5.0: {} 3577 3739 3578 3740 own-keys@1.0.1: ··· 3657 3819 3658 3820 prettier@3.4.2: {} 3659 3821 3822 + proxy-chain@2.7.1: 3823 + dependencies: 3824 + socks: 2.8.7 3825 + socks-proxy-agent: 8.0.5 3826 + tslib: 2.8.1 3827 + transitivePeerDependencies: 3828 + - supports-color 3829 + 3660 3830 queue-microtask@1.2.3: {} 3661 3831 3662 3832 randombytes@2.1.0: ··· 3876 4046 ansi-styles: 6.2.1 3877 4047 is-fullwidth-code-point: 5.0.0 3878 4048 4049 + smart-buffer@4.2.0: {} 4050 + 3879 4051 smob@1.5.0: {} 4052 + 4053 + socks-proxy-agent@8.0.5: 4054 + dependencies: 4055 + agent-base: 7.1.4 4056 + debug: 4.4.1 4057 + socks: 2.8.7 4058 + transitivePeerDependencies: 4059 + - supports-color 4060 + 4061 + socks@2.8.7: 4062 + dependencies: 4063 + ip-address: 10.1.0 4064 + smart-buffer: 4.2.0 3880 4065 3881 4066 source-map-js@1.2.1: {} 3882 4067 ··· 4001 4186 4002 4187 tinyspy@3.0.2: {} 4003 4188 4004 - tmp@0.0.33: 4005 - dependencies: 4006 - os-tmpdir: 1.0.2 4007 - 4008 4189 to-regex-range@5.0.1: 4009 4190 dependencies: 4010 4191 is-number: 7.0.0 4011 4192 4012 4193 tr46@0.0.3: {} 4194 + 4195 + tslib@2.8.1: {} 4013 4196 4014 4197 typed-array-buffer@1.0.3: 4015 4198 dependencies: ··· 4061 4244 4062 4245 universalify@0.1.2: {} 4063 4246 4064 - update-browserslist-db@1.1.2(browserslist@4.24.4): 4247 + update-browserslist-db@1.1.3(browserslist@4.25.4): 4065 4248 dependencies: 4066 - browserslist: 4.24.4 4249 + browserslist: 4.25.4 4067 4250 escalade: 3.2.0 4068 4251 picocolors: 1.1.1 4069 4252
+6 -3
scripts/rollup.config.mjs
··· 93 93 dir: './', 94 94 exports: 'auto', 95 95 sourcemap: true, 96 - sourcemapExcludeSources: false, 96 + sourcemapExcludeSources: true, 97 97 hoistTransitiveImports: false, 98 98 indent: false, 99 99 freeze: false, ··· 188 188 keep_fnames: true, 189 189 ie8: false, 190 190 compress: { 191 + passes: 2, 191 192 pure_getters: true, 192 193 toplevel: true, 193 194 booleans_as_integers: false, ··· 199 200 loops: false, 200 201 conditionals: false, 201 202 join_vars: false, 203 + reduce_vars: true, 202 204 }, 203 205 mangle: { 204 206 module: true, ··· 224 226 exclude: 'node_modules/**', 225 227 presets: [], 226 228 plugins: [ 227 - '@babel/plugin-transform-typescript', 228 - '@babel/plugin-transform-block-scoping', 229 + ['@babel/plugin-transform-typescript', { 230 + optimizeConstEnums: true, 231 + }], 229 232 ], 230 233 }), 231 234 ],
+107
src/__tests__/fetch-errors.test.ts
··· 1 + import { describe, it, expect, beforeEach, afterEach } from 'vitest'; 2 + import { Readable } from 'node:stream'; 3 + 4 + import TestServer from './utils/server.js'; 5 + import { fetch } from '../fetch'; 6 + 7 + describe('fetch error handling', () => { 8 + const server = new TestServer(); 9 + 10 + beforeEach(() => server.start()); 11 + afterEach(() => server.stop()); 12 + 13 + describe('incoming stream errors', () => { 14 + it('should propagate error when connection resets mid-body', async () => { 15 + const url = server.mock((_req, res) => { 16 + res.writeHead(200, { 'Content-Length': '1000' }); 17 + res.write('partial'); 18 + setTimeout(() => res.destroy(), 10); 19 + }); 20 + 21 + const response = await fetch(url); 22 + expect(response.ok).toBe(true); 23 + await expect(response.text()).rejects.toThrow(); 24 + }); 25 + 26 + it('should not cause unhandled errors on incoming stream', async () => { 27 + const errors: Error[] = []; 28 + const handler = (e: Error) => errors.push(e); 29 + process.on('uncaughtException', handler); 30 + 31 + const url = server.mock((_req, res) => { 32 + res.writeHead(200, { 'Transfer-Encoding': 'chunked' }); 33 + res.write('data'); 34 + setTimeout(() => res.destroy(), 10); 35 + }); 36 + 37 + const response = await fetch(url); 38 + try { 39 + await response.text(); 40 + } catch {} 41 + await new Promise(r => setTimeout(r, 50)); 42 + 43 + process.off('uncaughtException', handler); 44 + expect(errors).toHaveLength(0); 45 + }); 46 + }); 47 + 48 + describe('request body pipeline errors', () => { 49 + it('should reject when request body stream errors', async () => { 50 + const body = new Readable({ 51 + read() { 52 + this.push('data'); 53 + setTimeout(() => this.destroy(new Error('stream error')), 10); 54 + }, 55 + }); 56 + 57 + const url = server.mock((req, res) => { 58 + req.on('data', () => {}); 59 + req.on('end', () => res.end('ok')); 60 + req.on('error', () => {}); 61 + }); 62 + 63 + await expect(fetch(url, { method: 'POST', body })).rejects.toThrow( 64 + 'stream error' 65 + ); 66 + }); 67 + }); 68 + 69 + describe('decompression errors', () => { 70 + it('should propagate gzip decompression errors', async () => { 71 + const url = server.mock((_req, res) => { 72 + res.writeHead(200, { 'Content-Encoding': 'gzip' }); 73 + res.end('not gzip'); 74 + }); 75 + 76 + const response = await fetch(url); 77 + expect(response.ok).toBe(true); 78 + await expect(response.text()).rejects.toThrow(); 79 + }); 80 + 81 + it('should propagate brotli decompression errors', async () => { 82 + const url = server.mock((_req, res) => { 83 + res.writeHead(200, { 'Content-Encoding': 'br' }); 84 + res.end('not brotli'); 85 + }); 86 + 87 + const response = await fetch(url); 88 + await expect(response.text()).rejects.toThrow(); 89 + }); 90 + }); 91 + 92 + describe('abort handling', () => { 93 + it('should abort during response streaming', async () => { 94 + const controller = new AbortController(); 95 + 96 + const url = server.mock((_req, res) => { 97 + res.writeHead(200, { 'Transfer-Encoding': 'chunked' }); 98 + const id = setInterval(() => res.write('x'), 10); 99 + res.on('close', () => clearInterval(id)); 100 + }); 101 + 102 + const response = await fetch(url, { signal: controller.signal }); 103 + setTimeout(() => controller.abort(), 30); 104 + await expect(response.text()).rejects.toThrow(); 105 + }); 106 + }); 107 + });
+77
src/__tests__/fetch-proxied.test.ts
··· 1 + import { describe, it, expect, beforeEach, afterEach, afterAll } from 'vitest'; 2 + import { Server as ProxyServer } from 'proxy-chain'; 3 + 4 + import TestServer from './utils/server.js'; 5 + import { fetch } from '../fetch'; 6 + 7 + async function startHttpProxy() { 8 + const server = new ProxyServer(); 9 + const port = await new Promise(resolve => { 10 + server.listen(() => { 11 + resolve(server.port); 12 + }); 13 + }); 14 + 15 + return { 16 + url: `http://localhost:${port}`, 17 + close() { 18 + return new Promise<void>((resolve, reject) => { 19 + server.close(true, err => { 20 + if (err) { 21 + reject(err); 22 + } else { 23 + resolve(); 24 + } 25 + }); 26 + }); 27 + }, 28 + }; 29 + } 30 + 31 + const proxy = await startHttpProxy(); 32 + const local = new TestServer(); 33 + let baseURL: string; 34 + 35 + beforeEach(async () => { 36 + await local.start(); 37 + baseURL = `http://${local.hostname}:${local.port}/`; 38 + }); 39 + 40 + afterEach(async () => { 41 + delete process.env.HTTP_PROXY; 42 + delete process.env.HTTPS_PROXY; 43 + await local.stop(); 44 + }); 45 + 46 + afterAll(async () => { 47 + await proxy.close(); 48 + }); 49 + 50 + const testCI = process.env.CI ? it : it.skip; 51 + 52 + describe('fetch via HTTP proxy', () => { 53 + it('performs an HTTP request when HTTP_PROXY is set (tunnel via CONNECT to HTTP)', async () => { 54 + process.env.HTTP_PROXY = proxy.url; 55 + const response = await fetch(new URL('inspect', baseURL)); 56 + expect(response.status).toBe(200); 57 + expect(await response.json()).toEqual({ 58 + body: '', 59 + headers: expect.objectContaining({ 60 + connection: 'keep-alive', 61 + }), 62 + inspect: true, 63 + method: 'GET', 64 + url: '/inspect', 65 + }); 66 + }); 67 + 68 + testCI( 69 + 'performs an HTTPs request when HTTPS_PROXY is set (tunnel via CONNECT to HTTPs)', 70 + async () => { 71 + process.env.HTTPS_PROXY = proxy.url; 72 + const response = await fetch('https://api.expo.dev'); 73 + expect(response.status).toBe(200); 74 + expect(await response.text()).toBe('OK'); 75 + } 76 + ); 77 + });
+34 -17
src/__tests__/fetch.test.ts
··· 122 122 }); 123 123 }); 124 124 125 + it('should send custom Content-Type with body', async () => { 126 + const response = await fetch(new URL('inspect', baseURL), { 127 + headers: { 'content-type': 'some/magic' }, 128 + body: 'test', 129 + }); 130 + expect(await response.json()).toMatchObject({ 131 + headers: expect.objectContaining({ 'content-type': 'some/magic' }), 132 + }); 133 + }); 134 + 125 135 it('should prefer init headers when Request is passed', async () => { 126 136 const request = new Request(new URL('inspect', baseURL), { 127 137 headers: { 'x-custom-header': 'abc' }, ··· 290 300 }); 291 301 }); 292 302 293 - it.each([['follow'], ['manual']] as const)( 294 - 'should treat broken redirect as ordinary response (%s)', 295 - async redirect => { 296 - const response = await fetch(new URL('redirect/no-location', baseURL), { 297 - redirect, 298 - }); 299 - expect(response.status).toBe(301); 300 - expect(response.headers.has('location')).toBe(false); 301 - } 302 - ); 303 + it('should treat broken redirect as ordinary response for redirect: "manual"', async () => { 304 + const response = await fetch(new URL('redirect/no-location', baseURL), { 305 + redirect: 'manual', 306 + }); 307 + expect(response.status).toBe(301); 308 + expect(response.headers.has('location')).toBe(false); 309 + }); 310 + 311 + it('should throw on broken redirects for redirect: "follow"', async () => { 312 + await expect(() => 313 + fetch(new URL('redirect/no-location', baseURL), { 314 + redirect: 'follow', 315 + }) 316 + ).rejects.toThrowErrorMatchingInlineSnapshot( 317 + `[Error: URI requested responds with an invalid redirect URL]` 318 + ); 319 + }); 303 320 304 321 it('should throw a TypeError on an invalid redirect option', async () => { 305 322 await expect(() => ··· 595 612 }); 596 613 setTimeout(() => controller.abort(), 100); 597 614 await expect(response$).rejects.toThrowErrorMatchingInlineSnapshot( 598 - `[AbortError: The operation was aborted]` 615 + `[AbortError: This operation was aborted]` 599 616 ); 600 617 }); 601 618 ··· 613 630 ]; 614 631 setTimeout(() => controller.abort(), 100); 615 632 await expect(fetches[0]).rejects.toThrowErrorMatchingInlineSnapshot( 616 - `[AbortError: The operation was aborted]` 633 + `[AbortError: This operation was aborted]` 617 634 ); 618 635 await expect(fetches[1]).rejects.toThrowErrorMatchingInlineSnapshot( 619 - `[AbortError: The operation was aborted]` 636 + `[AbortError: This operation was aborted]` 620 637 ); 621 638 }); 622 639 ··· 627 644 signal: controller.signal, 628 645 }); 629 646 }).rejects.toThrowErrorMatchingInlineSnapshot( 630 - `[AbortError: The operation was aborted]` 647 + `[AbortError: This operation was aborted]` 631 648 ); 632 649 }); 633 650 ··· 639 656 await expect(() => 640 657 fetch(request) 641 658 ).rejects.toThrowErrorMatchingInlineSnapshot( 642 - `[AbortError: The operation was aborted]` 659 + `[AbortError: This operation was aborted]` 643 660 ); 644 661 }); 645 662 ··· 672 689 }); 673 690 controller.abort(); 674 691 await expect(response$).rejects.toThrowErrorMatchingInlineSnapshot( 675 - `[AbortError: The operation was aborted]` 692 + `[AbortError: This operation was aborted]` 676 693 ); 677 694 }); 678 695 ··· 708 725 controller.abort(); 709 726 await bodyError$; 710 727 await expect(response$).rejects.toMatchInlineSnapshot( 711 - `[AbortError: The operation was aborted]` 728 + `[AbortError: This operation was aborted]` 712 729 ); 713 730 }); 714 731
+40 -28
src/__tests__/utils/server.js
··· 3 3 import http from 'http'; 4 4 import zlib from 'zlib'; 5 5 import Busboy from 'busboy'; 6 - import {once} from 'events'; 6 + import { once } from 'events'; 7 7 8 8 export default class TestServer { 9 9 constructor() { ··· 42 42 return `http://${this.hostname}:${this.port}/mocked`; 43 43 } 44 44 45 + mock(handler) { 46 + this.server.nextResponseHandler = handler; 47 + return `http://${this.hostname}:${this.port}/mocked`; 48 + } 49 + 45 50 router(request, res) { 46 51 const p = request.url; 47 52 48 53 if (p === '/mocked') { 49 54 if (this.nextResponseHandler) { 50 - this.nextResponseHandler(res); 55 + this.nextResponseHandler(request, res); 51 56 this.nextResponseHandler = undefined; 52 57 } else { 53 - throw new Error('No mocked response. Use โ€™TestServer.mockResponse()โ€™.'); 58 + throw new Error("No mocked response. Use 'TestServer.mockResponse()'."); 54 59 } 55 60 } 56 61 ··· 91 96 if (p === '/json') { 92 97 res.statusCode = 200; 93 98 res.setHeader('Content-Type', 'application/json'); 94 - res.end(JSON.stringify({ 95 - name: 'value' 96 - })); 99 + res.end( 100 + JSON.stringify({ 101 + name: 'value', 102 + }) 103 + ); 97 104 } 98 105 99 106 if (p === '/gzip') { ··· 244 251 } 245 252 246 253 if (p === '/redirect/301/rn') { 247 - res.statusCode = 301 248 - res.setHeader('Location', '/403') 254 + res.statusCode = 301; 255 + res.setHeader('Location', '/403'); 249 256 res.write('301 Permanently moved.\r\n'); 250 257 res.end(); 251 258 } ··· 321 328 if (p === '/redirect/chunked') { 322 329 res.writeHead(301, { 323 330 Location: '/inspect', 324 - 'Transfer-Encoding': 'chunked' 331 + 'Transfer-Encoding': 'chunked', 325 332 }); 326 333 setTimeout(() => res.end(), 10); 327 334 } ··· 349 356 } 350 357 351 358 if (p === '/error/premature') { 352 - res.writeHead(200, {'content-length': 50}); 359 + res.writeHead(200, { 'content-length': 50 }); 353 360 res.write('foo'); 354 361 setTimeout(() => { 355 362 res.destroy(); ··· 359 366 if (p === '/error/premature/chunked') { 360 367 res.writeHead(200, { 361 368 'Content-Type': 'application/json', 362 - 'Transfer-Encoding': 'chunked' 369 + 'Transfer-Encoding': 'chunked', 363 370 }); 364 371 365 - res.write(`${JSON.stringify({data: 'hi'})}\n`); 372 + res.write(`${JSON.stringify({ data: 'hi' })}\n`); 366 373 367 374 setTimeout(() => { 368 - res.write(`${JSON.stringify({data: 'bye'})}\n`); 375 + res.write(`${JSON.stringify({ data: 'bye' })}\n`); 369 376 }, 50); 370 377 371 378 setTimeout(() => { ··· 435 442 body += c; 436 443 }); 437 444 request.on('end', () => { 438 - res.end(JSON.stringify({ 439 - inspect: true, 440 - method: request.method, 441 - url: request.url, 442 - headers: request.headers, 443 - body 444 - })); 445 + res.end( 446 + JSON.stringify({ 447 + inspect: true, 448 + method: request.method, 449 + url: request.url, 450 + headers: request.headers, 451 + body, 452 + }) 453 + ); 445 454 }); 446 455 } 447 456 448 457 if (p === '/multipart') { 449 458 res.statusCode = 200; 450 459 res.setHeader('Content-Type', 'application/json'); 451 - const busboy = new Busboy({headers: request.headers}); 460 + const busboy = new Busboy({ headers: request.headers }); 452 461 let body = ''; 453 462 busboy.on('file', async (fieldName, file, fileName) => { 454 463 body += `${fieldName}=${fileName}`; 455 464 // consume file data 456 465 // eslint-disable-next-line no-empty, no-unused-vars 457 - for await (const c of file) { } 466 + for await (const c of file) { 467 + } 458 468 }); 459 469 460 470 busboy.on('field', (fieldName, value) => { 461 471 body += `${fieldName}=${value}`; 462 472 }); 463 473 busboy.on('finish', () => { 464 - res.end(JSON.stringify({ 465 - method: request.method, 466 - url: request.url, 467 - headers: request.headers, 468 - body 469 - })); 474 + res.end( 475 + JSON.stringify({ 476 + method: request.method, 477 + url: request.url, 478 + headers: request.headers, 479 + body, 480 + }) 481 + ); 470 482 }); 471 483 request.pipe(busboy); 472 484 }
+258
src/agent.ts
··· 1 + import * as https from 'node:https'; 2 + import * as http from 'node:http'; 3 + import * as net from 'node:net'; 4 + 5 + declare module 'https' { 6 + interface Agent { 7 + createConnection( 8 + opts: https.RequestOptions, 9 + callback?: (err: Error | null, socket: net.Socket | null) => void 10 + ): net.Socket | null; 11 + } 12 + } 13 + 14 + declare module 'net' { 15 + export function _normalizeArgs( 16 + options: unknown 17 + ): asserts options is net.NetConnectOpts; 18 + } 19 + 20 + const getHttpProxyUrl = () => process.env.HTTP_PROXY ?? process.env.http_proxy; 21 + const getHttpsProxyUrl = () => 22 + process.env.HTTPS_PROXY ?? process.env.https_proxy; 23 + const getNoProxy = () => process.env.NO_PROXY ?? process.env.no_proxy; 24 + 25 + const createProxyPattern = (pattern: string): RegExp | null => { 26 + pattern = pattern.trim(); 27 + if (!pattern.startsWith('.')) pattern = `^${pattern}`; 28 + if (!pattern.endsWith('.') || pattern.includes(':')) pattern += '$'; 29 + pattern = pattern.replace(/\./g, '\\.').replace(/\*/g, '[\\w.]+'); 30 + return pattern ? new RegExp(pattern, 'i') : null; 31 + }; 32 + 33 + const matchesNoProxy = (options: { 34 + host?: string | null; 35 + hostname?: string | null; 36 + port?: string | number | null; 37 + defaultPort?: string | number; 38 + }): boolean => { 39 + const NO_PROXY = getNoProxy(); 40 + if (NO_PROXY === '*' || NO_PROXY === '1' || NO_PROXY === 'true') { 41 + return true; 42 + } else if (NO_PROXY) { 43 + for (const noProxyPattern of NO_PROXY.split(',')) { 44 + const hostPattern = createProxyPattern(noProxyPattern); 45 + if (hostPattern) { 46 + const hostname = options.hostname || options.host; 47 + const origin = 48 + hostname && 49 + `${hostname}:${options.port || options.defaultPort || 80}`; 50 + if ( 51 + (hostname && hostPattern.test(hostname)) || 52 + (origin && hostPattern.test(origin)) 53 + ) { 54 + return true; 55 + } 56 + } 57 + } 58 + return false; 59 + } else { 60 + return false; 61 + } 62 + }; 63 + 64 + export const defaultAgentOpts = { 65 + keepAlive: true, 66 + keepAliveMsecs: 1000, 67 + }; 68 + 69 + let _httpAgentUrl: string | undefined; 70 + let _httpAgent: http.Agent | undefined; 71 + 72 + export const getHttpAgent = ( 73 + options: http.RequestOptions 74 + ): http.RequestOptions['agent'] => { 75 + const HTTP_PROXY = getHttpProxyUrl(); 76 + if (!HTTP_PROXY) { 77 + _httpAgent = undefined; 78 + return undefined; 79 + } else if (matchesNoProxy(options)) { 80 + return undefined; 81 + } else if (!_httpAgentUrl || _httpAgentUrl !== HTTP_PROXY) { 82 + _httpAgent = undefined; 83 + try { 84 + _httpAgentUrl = HTTP_PROXY; 85 + _httpAgent = new HttpProxyAgent(new URL(HTTP_PROXY), defaultAgentOpts); 86 + } catch (error: any) { 87 + const wrapped = new Error( 88 + `Invalid HTTP_PROXY URL: "${HTTP_PROXY}".\n` + error?.message || error 89 + ); 90 + (wrapped as any).cause = error; 91 + throw wrapped; 92 + } 93 + return _httpAgent; 94 + } else { 95 + return _httpAgent; 96 + } 97 + }; 98 + 99 + let _httpsAgentUrl: string | undefined; 100 + let _httpsAgent: https.Agent | undefined; 101 + 102 + export const getHttpsAgent = ( 103 + options: https.RequestOptions 104 + ): https.RequestOptions['agent'] => { 105 + const HTTPS_PROXY = getHttpsProxyUrl() ?? getHttpProxyUrl(); 106 + if (!HTTPS_PROXY) { 107 + _httpsAgent = undefined; 108 + return undefined; 109 + } else if (matchesNoProxy(options)) { 110 + return undefined; 111 + } else if (!_httpsAgentUrl || _httpsAgentUrl !== HTTPS_PROXY) { 112 + _httpsAgent = undefined; 113 + try { 114 + _httpsAgentUrl = HTTPS_PROXY; 115 + _httpsAgent = new HttpsProxyAgent(new URL(HTTPS_PROXY), defaultAgentOpts); 116 + } catch (error: any) { 117 + const wrapped = new Error( 118 + `Invalid HTTPS_PROXY URL: "${HTTPS_PROXY}".\n` + error?.message || error 119 + ); 120 + (wrapped as any).cause = error; 121 + throw wrapped; 122 + } 123 + return _httpsAgent; 124 + } else { 125 + return _httpsAgent; 126 + } 127 + }; 128 + 129 + const createRequestOptions = ( 130 + proxy: URL, 131 + keepAlive: boolean, 132 + options: http.RequestOptions 133 + ) => { 134 + const proxyHeaders: Record<string, string> = { 135 + host: `${options.host}:${options.port}`, 136 + connection: keepAlive ? 'keep-alive' : 'close', 137 + }; 138 + if (proxy.username || proxy.password) { 139 + const username = decodeURIComponent(proxy.username || ''); 140 + const password = decodeURIComponent(proxy.password || ''); 141 + const auth = Buffer.from(`${username}:${password}`).toString('base64'); 142 + proxyHeaders['proxy-authorization'] = `Basic ${auth}`; 143 + } 144 + return { 145 + method: 'CONNECT', 146 + host: proxy.hostname, 147 + port: proxy.port, 148 + path: `${options.host}:${options.port}`, 149 + setHost: false, 150 + agent: false, 151 + proxyEnv: {}, 152 + timeout: 5_000, 153 + headers: proxyHeaders, 154 + servername: proxy.protocol === 'https:' ? proxy.hostname : undefined, 155 + }; 156 + }; 157 + 158 + // See: https://github.com/delvedor/hpagent 159 + // `hpagent` served as a template for how to create proxy agents like below minimally 160 + // MIT License, Copyright (c) 2020 Tomas Della Vedova 161 + 162 + class HttpProxyAgent extends http.Agent { 163 + _keepAlive: boolean; 164 + _proxy: URL; 165 + 166 + constructor(proxy: URL, options: http.AgentOptions) { 167 + super(options); 168 + this._proxy = proxy; 169 + this._keepAlive = !!options.keepAlive; 170 + } 171 + 172 + createConnection( 173 + options: http.RequestOptions, 174 + callback: (err: Error | null, socket: net.Socket | null) => void 175 + ): void { 176 + const request = (this._proxy.protocol === 'http:' ? http : https).request( 177 + createRequestOptions(this._proxy, this._keepAlive, options) 178 + ); 179 + 180 + request.once('connect', (response, socket, _head) => { 181 + request.removeAllListeners(); 182 + socket.removeAllListeners(); 183 + if (response.statusCode === 200) { 184 + callback(null, socket); 185 + } else { 186 + socket.destroy(); 187 + callback( 188 + new Error( 189 + `HTTP Proxy Network Error: ${response.statusMessage || response.statusCode}` 190 + ), 191 + null 192 + ); 193 + } 194 + }); 195 + 196 + request.once('timeout', () => { 197 + request.destroy(new Error('HTTP Proxy timed out')); 198 + }); 199 + 200 + request.once('error', error => { 201 + request.removeAllListeners(); 202 + callback(error, null); 203 + }); 204 + 205 + request.end(); 206 + } 207 + } 208 + 209 + class HttpsProxyAgent extends https.Agent { 210 + _proxy: URL; 211 + _keepAlive: boolean; 212 + 213 + constructor(proxy: URL, options: https.AgentOptions) { 214 + super(options); 215 + this._proxy = proxy; 216 + this._keepAlive = !!options.keepAlive; 217 + } 218 + 219 + createConnection( 220 + options: https.RequestOptions, 221 + callback?: (err: Error | null, socket: net.Socket | null) => void 222 + ): net.Socket | null { 223 + const request = (this._proxy.protocol === 'http:' ? http : https).request( 224 + createRequestOptions(this._proxy, this._keepAlive, options) 225 + ); 226 + 227 + request.once('connect', (response, socket, _head) => { 228 + request.removeAllListeners(); 229 + socket.removeAllListeners(); 230 + if (response.statusCode === 200) { 231 + const netOpts = { ...options, socket }; 232 + net._normalizeArgs(netOpts); 233 + const secureSocket = super.createConnection(netOpts); 234 + callback?.(null, secureSocket); 235 + } else { 236 + socket.destroy(); 237 + callback?.( 238 + new Error( 239 + `HTTP Proxy Network Error: ${response.statusMessage || response.statusCode}` 240 + ), 241 + null 242 + ); 243 + } 244 + }); 245 + 246 + request.once('timeout', () => { 247 + request.destroy(new Error('HTTP Proxy timed out')); 248 + }); 249 + 250 + request.once('error', err => { 251 + request.removeAllListeners(); 252 + callback?.(err, null); 253 + }); 254 + 255 + request.end(); 256 + return request.socket; 257 + } 258 + }
+62 -3
src/body.ts
··· 1 1 import { Readable } from 'node:stream'; 2 + import { arrayBuffer, blob, text } from 'node:stream/consumers'; 2 3 import { isAnyArrayBuffer } from 'node:util/types'; 3 4 import { randomBytes } from 'node:crypto'; 4 - import { Blob, FormData, URLSearchParams } from './webstd'; 5 + import { Response, Blob, FormData, URLSearchParams } from './webstd'; 5 6 6 7 export type BodyInit = 7 8 | Exclude<RequestInit['body'], undefined | null> ··· 77 78 typeof object.stream === 'function' && 78 79 typeof object.constructor === 'function' 79 80 ) { 80 - const tag = object[Symbol.toStringTag]; 81 - return tag.startsWith('Blob') || tag.startsWith('File'); 81 + const tag = object[Symbol.toStringTag] as string | undefined; 82 + return !!tag && (tag.startsWith('Blob') || tag.startsWith('File')); 82 83 } else { 83 84 return false; 84 85 } ··· 196 197 body, 197 198 }; 198 199 }; 200 + 201 + const kBodyInternals = Symbol('kBodyInternals'); 202 + 203 + export class Body { 204 + private [kBodyInternals]: BodyState; 205 + 206 + constructor(init: BodyInit | null) { 207 + this[kBodyInternals] = extractBody(init); 208 + } 209 + 210 + get body() { 211 + return this[kBodyInternals].body; 212 + } 213 + 214 + get bodyUsed() { 215 + const { body } = this[kBodyInternals]; 216 + if (isReadable(body)) { 217 + return Readable.isDisturbed(body); 218 + } else if (isReadableStream(body)) { 219 + return body.locked; 220 + } else { 221 + return false; 222 + } 223 + } 224 + 225 + async arrayBuffer() { 226 + const { body } = this[kBodyInternals]; 227 + return body != null && !isAnyArrayBuffer(body) ? arrayBuffer(body) : body; 228 + } 229 + 230 + async formData() { 231 + const { body, contentLength, contentType } = this[kBodyInternals]; 232 + const headers = {}; 233 + if (contentLength) headers['Content-Length'] = contentLength; 234 + if (contentType) headers['Content-Type'] = contentType; 235 + return new Response(body, { headers }).formData(); 236 + } 237 + 238 + async blob() { 239 + const { body, contentType } = this[kBodyInternals]; 240 + const chunks = 241 + body !== null ? [!isAnyArrayBuffer(body) ? await blob(body) : body] : []; 242 + return new Blob(chunks, { 243 + type: contentType ?? undefined, 244 + }); 245 + } 246 + 247 + async json() { 248 + return JSON.parse(await this.text()); 249 + } 250 + 251 + async text() { 252 + const { body } = this[kBodyInternals]; 253 + return body == null || isAnyArrayBuffer(body) 254 + ? new TextDecoder().decode(await this.arrayBuffer()) 255 + : text(body); 256 + } 257 + }
+3 -1
src/encoding.ts
··· 37 37 38 38 _final(callback: TransformCallback) { 39 39 if (this._inflate) { 40 + this._inflate.once('finish', callback); 40 41 this._inflate.end(); 41 42 this._inflate = undefined; 43 + } else { 44 + callback(); 42 45 } 43 - callback(); 44 46 } 45 47 } 46 48
+85 -25
src/fetch.ts
··· 1 1 import { Stream, Readable, pipeline } from 'node:stream'; 2 + import { Socket } from 'node:net'; 2 3 import * as https from 'node:https'; 3 4 import * as http from 'node:http'; 4 5 import * as url from 'node:url'; ··· 6 7 import { extractBody } from './body'; 7 8 import { createContentDecoder } from './encoding'; 8 9 import { URL, Request, RequestInit, Response } from './webstd'; 10 + import { getHttpsAgent, getHttpAgent } from './agent'; 9 11 10 12 /** Maximum allowed redirects (matching Chromium's limit) */ 11 13 const MAX_REDIRECTS = 20; 12 14 15 + const parseURL = (input: string, base?: string | URL): URL | null => { 16 + try { 17 + return new URL(input, base); 18 + } catch { 19 + return null; 20 + } 21 + }; 22 + 13 23 /** Convert Node.js raw headers array to Headers */ 14 24 const headersOfRawHeaders = (rawHeaders: readonly string[]): Headers => { 15 25 const headers = new Headers(); 16 26 for (let i = 0; i < rawHeaders.length; i += 2) 17 - headers.set(rawHeaders[i], rawHeaders[i + 1]); 27 + headers.append(rawHeaders[i], rawHeaders[i + 1]); 18 28 return headers; 19 29 }; 20 30 ··· 103 113 return response; 104 114 } 105 115 116 + function attachRefLifetime(body: Readable, socket: Socket): void { 117 + const { _read } = body; 118 + body.on('close', () => { 119 + socket.unref(); 120 + }); 121 + body._read = function _readRef(...args: Parameters<Readable['_read']>) { 122 + body._read = _read; 123 + socket.ref(); 124 + return _read.apply(this, args); 125 + }; 126 + } 127 + 106 128 async function _fetch( 107 129 input: string | URL | Request, 108 130 requestInit?: RequestInit ··· 126 148 ); 127 149 const requestOptions = { 128 150 ...urlToHttpOptions(requestUrl), 151 + timeout: 5_000, 129 152 method: methodToHttpOption( 130 153 initFromRequest ? input.method : requestInit?.method 131 154 ), ··· 136 159 resolve: (response: Response | Promise<Response>) => void, 137 160 reject: (reason?: any) => void 138 161 ) { 162 + requestOptions.agent = 163 + requestOptions.protocol === 'https:' 164 + ? getHttpsAgent(requestOptions) 165 + : getHttpAgent(requestOptions); 139 166 const method = requestOptions.method; 140 167 const protocol = requestOptions.protocol === 'https:' ? https : http; 141 168 const outgoing = protocol.request(requestOptions); 142 169 143 - outgoing.on('response', incoming => { 170 + let incoming: http.IncomingMessage | undefined; 171 + 172 + const destroy = (reason?: any) => { 173 + if (reason) { 174 + outgoing?.destroy(signal?.aborted ? signal.reason : reason); 175 + incoming?.destroy(signal?.aborted ? signal.reason : reason); 176 + reject(signal?.aborted ? signal.reason : reason); 177 + } 178 + signal?.removeEventListener('abort', destroy); 179 + }; 180 + 181 + signal?.addEventListener('abort', destroy); 182 + 183 + outgoing.on('timeout', () => { 184 + if (!incoming) { 185 + const error = new Error('Request timed out') as NodeJS.ErrnoException; 186 + error.code = 'ETIMEDOUT'; 187 + destroy(error); 188 + } 189 + }); 190 + 191 + outgoing.on('response', _incoming => { 192 + if (signal?.aborted) { 193 + return; 194 + } 195 + 196 + incoming = _incoming; 144 197 incoming.setTimeout(0); // Forcefully disable timeout 198 + incoming.socket.unref(); 199 + incoming.on('error', destroy); 145 200 146 201 const init = { 147 202 status: incoming.statusCode, ··· 152 207 if (isRedirectCode(init.status)) { 153 208 const location = init.headers.get('Location'); 154 209 const locationURL = 155 - location != null ? new URL(location, requestUrl) : null; 210 + location != null ? parseURL(location, requestUrl) : null; 156 211 if (redirect === 'error') { 157 - // TODO: do we need a special Error instance here? 158 212 reject( 159 213 new Error( 160 214 'URI requested responds with a redirect, redirect mode is set to error' 161 215 ) 162 216 ); 163 217 return; 164 - } else if (redirect === 'manual' && locationURL !== null) { 165 - init.headers.set('Location', locationURL.toString()); 166 - } else if (redirect === 'follow' && locationURL !== null) { 167 - if (++redirects > MAX_REDIRECTS) { 218 + } else if (redirect === 'manual' && location) { 219 + init.headers.set('Location', locationURL?.href ?? location); 220 + } else if (redirect === 'follow') { 221 + if (locationURL === null) { 222 + reject( 223 + new Error('URI requested responds with an invalid redirect URL') 224 + ); 225 + return; 226 + } else if (++redirects > MAX_REDIRECTS) { 168 227 reject(new Error(`maximum redirect reached at: ${requestUrl}`)); 169 228 return; 170 229 } else if ( ··· 201 260 } 202 261 } 203 262 204 - const destroy = (reason?: any) => { 205 - signal?.removeEventListener('abort', destroy); 206 - if (reason) { 207 - incoming.destroy(signal?.aborted ? signal.reason : reason); 208 - reject(signal?.aborted ? signal.reason : reason); 209 - } 210 - }; 211 - 212 - signal?.addEventListener('abort', destroy); 213 - 214 263 let body: Readable | null = incoming; 215 264 const encoding = init.headers.get('Content-Encoding')?.toLowerCase(); 216 265 if (method === 'HEAD' || init.status === 204 || init.status === 304) { ··· 218 267 } else if (encoding != null) { 219 268 init.headers.set('Content-Encoding', encoding); 220 269 body = pipeline(body, createContentDecoder(encoding), destroy); 270 + outgoing.on('error', destroy); 271 + } 272 + 273 + // Re-ref the socket when the body starts being consumed to prevent 274 + // early process exit, then unref when done to allow normal exit. 275 + if (body != null) { 276 + attachRefLifetime(body, incoming.socket); 221 277 } 222 278 223 279 resolve( ··· 229 285 ); 230 286 }); 231 287 232 - outgoing.on('error', reject); 288 + outgoing.on('error', destroy); 233 289 234 - if (!requestHeaders.has('Accept')) requestHeaders.set('Accept', '*/*'); 235 - if (requestBody.contentType) 290 + if (!requestHeaders.has('Accept')) { 291 + requestHeaders.set('Accept', '*/*'); 292 + } 293 + if (!requestHeaders.has('Content-Type') && requestBody.contentType) { 236 294 requestHeaders.set('Content-Type', requestBody.contentType); 295 + } 237 296 238 - if (requestBody.body == null && (method === 'POST' || method === 'PUT')) { 297 + if ( 298 + requestBody.body == null && 299 + (method === 'POST' || method === 'PUT' || method === 'PATCH') 300 + ) { 239 301 requestHeaders.set('Content-Length', '0'); 240 302 } else if (requestBody.body != null && requestBody.contentLength != null) { 241 303 requestHeaders.set('Content-Length', `${requestBody.contentLength}`); ··· 253 315 requestBody.body instanceof Stream 254 316 ? requestBody.body 255 317 : Readable.fromWeb(requestBody.body); 256 - pipeline(body, outgoing, error => { 257 - if (error) reject(error); 258 - }); 318 + pipeline(body, outgoing, destroy); 259 319 } 260 320 } 261 321
+1
src/index.ts
··· 1 1 export { fetch, fetch as default } from './fetch'; 2 + export { Body } from './body'; 2 3 export * from './webstd';
+9 -4
src/webstd.ts
··· 81 81 init?: _RequestInit | Or<RequestInit, globalThis.RequestInit> 82 82 ): _Request; 83 83 } 84 - const _Request: RequestClass = Request; 85 84 86 85 interface _Response extends Or<Response, globalThis.Response> {} 87 86 interface ResponseClass 88 87 extends Or<typeof Response, typeof globalThis.Response> { 89 88 new (body?: BodyInit, init?: _ResponseInit): _Response; 90 89 } 91 - const _Response: ResponseClass = Response; 92 90 93 91 interface _Headers extends Or<Headers, globalThis.Headers> {} 94 92 interface HeadersClass extends Or<typeof Headers, typeof globalThis.Headers> { 95 93 new (init?: HeadersInit): _Headers; 96 94 } 97 - const _Headers: HeadersClass = Headers; 98 95 99 96 interface _FormData 100 97 extends Or< ··· 103 100 > {} 104 101 interface FormDataClass 105 102 extends Or<typeof FormData, typeof globalThis.FormData> {} 106 - const _FormData: FormDataClass = FormData; 103 + 104 + let _Request: RequestClass; 105 + let _Response: ResponseClass; 106 + let _Headers: HeadersClass; 107 + let _FormData: FormDataClass; 108 + if (typeof Request !== 'undefined') _Request = Request; 109 + if (typeof Response !== 'undefined') _Response = Response; 110 + if (typeof Headers !== 'undefined') _Headers = Headers; 111 + if (typeof FormData !== 'undefined') _FormData = FormData; 107 112 108 113 export { 109 114 type _RequestInit as RequestInit,