Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c7a76ddbf2 | ||
|
|
914bc2605a | ||
|
|
0912bde937 | ||
|
|
8b68491d04 | ||
|
|
62f6281660 | ||
|
|
c44f4d728b | ||
|
|
34d137cbae | ||
|
|
9f992a8eb9 | ||
|
|
9df2cd3df7 | ||
|
|
f53ebf2198 | ||
|
|
772a4e54ec | ||
|
|
4b071371be | ||
|
|
51e57b39db | ||
|
|
fba1a77930 | ||
|
|
0bf6e28eac | ||
|
|
8107157c57 | ||
|
|
e66530e330 | ||
|
|
49f23cbfe4 | ||
|
|
363185461b | ||
|
|
fb3befb6da | ||
|
|
8023035109 | ||
|
|
36bebd1c88 | ||
|
|
e52994ff40 | ||
|
|
173efa3b8d | ||
|
|
923ae8f9c5 | ||
|
|
71f14b7fdc | ||
|
|
2f52f6b13b | ||
|
|
23fcd5f278 | ||
|
|
054c1f30fd | ||
|
|
395a1604be | ||
|
|
64d02a195a | ||
|
|
3ca13062ee | ||
|
|
e4bd759def | ||
|
|
26f8e5796a | ||
|
|
947f7091d8 | ||
|
|
a04dd96dbb | ||
|
|
e9a1db9d9b | ||
|
|
ebf3036932 | ||
|
|
a5881813d3 | ||
|
|
a40f8d3398 | ||
|
|
e2bed7f84d | ||
|
|
a7f41f5bb5 | ||
|
|
2d14d8a300 | ||
|
|
4950ff6017 | ||
|
|
7173706380 | ||
|
|
3ec6858bd4 | ||
|
|
391ed22d01 | ||
|
|
53fa6fe03c | ||
|
|
0902502fd5 | ||
|
|
0c139622c4 | ||
|
|
d79317f35f |
4
.github/dependabot.yml
vendored
@ -11,6 +11,8 @@ updates:
|
||||
- 'type::automated-pr'
|
||||
schedule:
|
||||
interval: 'weekly'
|
||||
cooldown:
|
||||
default-days: 7
|
||||
- package-ecosystem: 'npm'
|
||||
directory: '/'
|
||||
schedule:
|
||||
@ -33,3 +35,5 @@ updates:
|
||||
labels:
|
||||
- 'commit::chore'
|
||||
- 'type::automated-pr'
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
6
.github/workflows/moderator.yml
vendored
@ -16,8 +16,10 @@ jobs:
|
||||
models: read
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: github/ai-moderator@v1
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: github/ai-moderator@81159c370785e295c97461ade67d7c33576e9319 # v1.1.4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
spam-label: 'spam'
|
||||
|
||||
15
.github/workflows/publish.yml
vendored
@ -6,26 +6,27 @@ on:
|
||||
- 'v1.*.*'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
environment: npm-publish
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version: 24.x
|
||||
cache: npm
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
package-manager-cache: false
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
run: npm ci --ignore-scripts
|
||||
- name: Build project
|
||||
run: npm run build
|
||||
- name: Publish to NPM
|
||||
run: npm publish --provenance --access public
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
131
.github/workflows/release-branch.yml
vendored
@ -17,8 +17,7 @@ on:
|
||||
default: false
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build-and-run-vitest:
|
||||
@ -26,16 +25,16 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: true
|
||||
persist-credentials: false
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version: 24.x
|
||||
cache: npm
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
run: npm ci --ignore-scripts
|
||||
- name: Build project
|
||||
run: npm run build
|
||||
- name: Install Playwright with deps
|
||||
@ -47,7 +46,7 @@ jobs:
|
||||
- name: Pack npm tarball
|
||||
run: npm pack
|
||||
- name: Upload npm pack artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: axios-tarball
|
||||
path: axios-*.tgz
|
||||
@ -64,23 +63,23 @@ jobs:
|
||||
node-version: [12, 14, 16, 18]
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: true
|
||||
persist-credentials: false
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: npm
|
||||
cache-dependency-path: tests/smoke/cjs/package-lock.json
|
||||
- name: Download npm pack artifact
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: axios-tarball
|
||||
path: artifacts
|
||||
- name: Install CJS smoke test dependencies
|
||||
working-directory: tests/smoke/cjs
|
||||
run: npm install
|
||||
run: npm install --ignore-scripts
|
||||
- name: Install packed axios
|
||||
working-directory: tests/smoke/cjs
|
||||
run: npm install --no-save ../../../artifacts/axios-*.tgz
|
||||
@ -98,23 +97,23 @@ jobs:
|
||||
node-version: [20, 22, 24]
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: true
|
||||
persist-credentials: false
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: npm
|
||||
cache-dependency-path: tests/smoke/esm/package-lock.json
|
||||
- name: Download npm pack artifact
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: axios-tarball
|
||||
path: artifacts
|
||||
- name: Install ESM smoke test dependencies
|
||||
working-directory: tests/smoke/esm
|
||||
run: npm install
|
||||
run: npm install --ignore-scripts
|
||||
- name: Install packed axios
|
||||
working-directory: tests/smoke/esm
|
||||
run: npm install --no-save ../../../artifacts/axios-*.tgz
|
||||
@ -132,23 +131,23 @@ jobs:
|
||||
node-version: [12, 14, 16, 18]
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: true
|
||||
persist-credentials: false
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: npm
|
||||
cache-dependency-path: tests/module/cjs/package-lock.json
|
||||
- name: Download npm pack artifact
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: axios-tarball
|
||||
path: artifacts
|
||||
- name: Install CJS module test dependencies
|
||||
working-directory: tests/module/cjs
|
||||
run: npm install
|
||||
run: npm install --ignore-scripts
|
||||
- name: Install packed axios
|
||||
working-directory: tests/module/cjs
|
||||
run: npm install --no-save ../../../artifacts/axios-*.tgz
|
||||
@ -166,23 +165,23 @@ jobs:
|
||||
node-version: [20, 22, 24]
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: true
|
||||
persist-credentials: false
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: npm
|
||||
cache-dependency-path: tests/module/esm/package-lock.json
|
||||
- name: Download npm pack artifact
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: axios-tarball
|
||||
path: artifacts
|
||||
- name: Install ESM module test dependencies
|
||||
working-directory: tests/module/esm
|
||||
run: npm install
|
||||
run: npm install --ignore-scripts
|
||||
- name: Install packed axios
|
||||
working-directory: tests/module/esm
|
||||
run: npm install --no-save ../../../artifacts/axios-*.tgz
|
||||
@ -190,22 +189,80 @@ jobs:
|
||||
working-directory: tests/module/esm
|
||||
run: npm run test:module:esm
|
||||
|
||||
bump-version-and-create-pr:
|
||||
name: Bump version and create PR
|
||||
needs: [build-and-run-vitest, cjs-smoke-tests, esm-smoke-tests]
|
||||
bun-smoke-tests:
|
||||
name: Bun smoke tests
|
||||
needs: build-and-run-vitest
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup bun
|
||||
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
|
||||
- name: Download npm pack artifact
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: axios-tarball
|
||||
path: artifacts
|
||||
- name: Install packed axios
|
||||
env:
|
||||
TMPDIR: ${{ runner.temp }}
|
||||
BUN_INSTALL_CACHE_DIR: ${{ runner.temp }}/bun-cache
|
||||
run: |
|
||||
mkdir -p "$BUN_INSTALL_CACHE_DIR"
|
||||
mv artifacts/axios-*.tgz artifacts/axios.tgz
|
||||
cd tests/smoke/bun
|
||||
bun add file:../../../artifacts/axios.tgz
|
||||
- name: Run Bun smoke tests
|
||||
working-directory: tests/smoke/bun
|
||||
run: bun test
|
||||
|
||||
deno-smoke-tests:
|
||||
name: Deno smoke tests
|
||||
needs: build-and-run-vitest
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup deno
|
||||
uses: denoland/setup-deno@667a34cdef165d8d2b2e98dde39547c9daac7282 # v2.0.4
|
||||
- name: Download npm pack artifact
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: axios-tarball
|
||||
path: artifacts
|
||||
- name: Prepare packed axios dist
|
||||
run: mkdir -p dist && tar -xzf artifacts/axios-*.tgz -C artifacts && cp -R artifacts/package/dist/. ./dist
|
||||
- name: Install Deno smoke test dependencies
|
||||
working-directory: tests/smoke/deno
|
||||
run: deno install
|
||||
- name: Run Deno smoke tests
|
||||
working-directory: tests/smoke/deno
|
||||
run: deno task test
|
||||
|
||||
bump-version-and-create-pr:
|
||||
name: Bump version and create PR
|
||||
needs:
|
||||
[build-and-run-vitest, cjs-smoke-tests, esm-smoke-tests, bun-smoke-tests, deno-smoke-tests]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version: 24.x
|
||||
cache: npm
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
run: npm ci --ignore-scripts
|
||||
- name: Configure git identity
|
||||
run: |
|
||||
git config --global user.name "github-actions[bot]"
|
||||
@ -213,10 +270,12 @@ jobs:
|
||||
- name: Bump version with NPM version
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
INPUT_TYPE: ${{ github.event.inputs.type }}
|
||||
INPUT_BETA: ${{ github.event.inputs.beta }}
|
||||
id: bump-version
|
||||
run: |
|
||||
TYPE=${{ github.event.inputs.type }}
|
||||
BETA=${{ github.event.inputs.beta }}
|
||||
TYPE="${INPUT_TYPE}"
|
||||
BETA="${INPUT_BETA}"
|
||||
if [ "$TYPE" = "auto" ]; then
|
||||
npm version $(npm version | grep -Eo 'patch|minor|major' | head -1)
|
||||
else
|
||||
@ -234,7 +293,7 @@ jobs:
|
||||
- name: Build project
|
||||
run: npm run build
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v8
|
||||
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
|
||||
with:
|
||||
branch: 'release'
|
||||
commit-message: 'chore(release): prepare release ${{ steps.bump-version.outputs.newTag }}'
|
||||
|
||||
107
.github/workflows/run-ci.yml
vendored
@ -6,7 +6,6 @@ on:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@ -18,16 +17,16 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: true
|
||||
persist-credentials: false
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version: 24.x
|
||||
cache: npm
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
run: npm ci --ignore-scripts
|
||||
- name: Build project
|
||||
run: npm run build
|
||||
- name: Install Playwright with deps
|
||||
@ -39,9 +38,9 @@ jobs:
|
||||
- name: Pack npm tarball
|
||||
run: npm pack
|
||||
- name: Dependency Review
|
||||
uses: actions/dependency-review-action@v4
|
||||
uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0
|
||||
- name: Upload npm pack artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: axios-tarball
|
||||
path: axios-*.tgz
|
||||
@ -58,23 +57,23 @@ jobs:
|
||||
node-version: [12, 14, 16, 18]
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: true
|
||||
persist-credentials: false
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: npm
|
||||
cache-dependency-path: tests/smoke/cjs/package-lock.json
|
||||
- name: Download npm pack artifact
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: axios-tarball
|
||||
path: artifacts
|
||||
- name: Install CJS smoke test dependencies
|
||||
working-directory: tests/smoke/cjs
|
||||
run: npm install
|
||||
run: npm install --ignore-scripts
|
||||
- name: Install packed axios
|
||||
working-directory: tests/smoke/cjs
|
||||
run: npm install --no-save ../../../artifacts/axios-*.tgz
|
||||
@ -92,23 +91,23 @@ jobs:
|
||||
node-version: [20, 22, 24]
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: true
|
||||
persist-credentials: false
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: npm
|
||||
cache-dependency-path: tests/smoke/esm/package-lock.json
|
||||
- name: Download npm pack artifact
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: axios-tarball
|
||||
path: artifacts
|
||||
- name: Install ESM smoke test dependencies
|
||||
working-directory: tests/smoke/esm
|
||||
run: npm install
|
||||
run: npm install --ignore-scripts
|
||||
- name: Install packed axios
|
||||
working-directory: tests/smoke/esm
|
||||
run: npm install --no-save ../../../artifacts/axios-*.tgz
|
||||
@ -126,23 +125,23 @@ jobs:
|
||||
node-version: [12, 14, 16, 18]
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: true
|
||||
persist-credentials: false
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: npm
|
||||
cache-dependency-path: tests/module/cjs/package-lock.json
|
||||
- name: Download npm pack artifact
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: axios-tarball
|
||||
path: artifacts
|
||||
- name: Install CJS module test dependencies
|
||||
working-directory: tests/module/cjs
|
||||
run: npm install
|
||||
run: npm install --ignore-scripts
|
||||
- name: Install packed axios
|
||||
working-directory: tests/module/cjs
|
||||
run: npm install --no-save ../../../artifacts/axios-*.tgz
|
||||
@ -160,26 +159,80 @@ jobs:
|
||||
node-version: [20, 22, 24]
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: true
|
||||
persist-credentials: false
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: npm
|
||||
cache-dependency-path: tests/module/esm/package-lock.json
|
||||
- name: Download npm pack artifact
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: axios-tarball
|
||||
path: artifacts
|
||||
- name: Install ESM module test dependencies
|
||||
working-directory: tests/module/esm
|
||||
run: npm install
|
||||
run: npm install --ignore-scripts
|
||||
- name: Install packed axios
|
||||
working-directory: tests/module/esm
|
||||
run: npm install --no-save ../../../artifacts/axios-*.tgz
|
||||
- name: Run ESM module tests
|
||||
working-directory: tests/module/esm
|
||||
run: npm run test:module:esm
|
||||
|
||||
bun-smoke-tests:
|
||||
name: Bun smoke tests
|
||||
needs: build-and-run-vitest
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup bun
|
||||
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
|
||||
- name: Download npm pack artifact
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: axios-tarball
|
||||
path: artifacts
|
||||
- name: Install packed axios
|
||||
env:
|
||||
TMPDIR: ${{ runner.temp }}
|
||||
BUN_INSTALL_CACHE_DIR: ${{ runner.temp }}/bun-cache
|
||||
run: |
|
||||
mkdir -p "$BUN_INSTALL_CACHE_DIR"
|
||||
mv artifacts/axios-*.tgz artifacts/axios.tgz
|
||||
cd tests/smoke/bun
|
||||
bun add file:../../../artifacts/axios.tgz
|
||||
- name: Run Bun smoke tests
|
||||
working-directory: tests/smoke/bun
|
||||
run: bun test
|
||||
|
||||
deno-smoke-tests:
|
||||
name: Deno smoke tests
|
||||
needs: build-and-run-vitest
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup deno
|
||||
uses: denoland/setup-deno@667a34cdef165d8d2b2e98dde39547c9daac7282 # v2.0.4
|
||||
- name: Download npm pack artifact
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: axios-tarball
|
||||
path: artifacts
|
||||
- name: Prepare packed axios dist
|
||||
run: mkdir -p dist && tar -xzf artifacts/axios-*.tgz -C artifacts && cp -R artifacts/package/dist/. ./dist
|
||||
- name: Install Deno smoke test dependencies
|
||||
working-directory: tests/smoke/deno
|
||||
run: deno install
|
||||
- name: Run Deno smoke tests
|
||||
working-directory: tests/smoke/deno
|
||||
run: deno task test
|
||||
|
||||
32
.github/workflows/update-sponsor-block.yml
vendored
@ -6,7 +6,7 @@ on:
|
||||
types:
|
||||
- webhook
|
||||
schedule:
|
||||
- cron: "0 1 * * *"
|
||||
- cron: '0 1 * * *'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
@ -14,44 +14,54 @@ permissions:
|
||||
|
||||
jobs:
|
||||
sponsors:
|
||||
if: github.repository == 'axios/axios'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
- name: git config
|
||||
run: |
|
||||
git config user.name "${GITHUB_ACTOR}"
|
||||
git config user.email "${GITHUB_ACTOR}@users.noreply.github.com"
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version: 24.x
|
||||
cache: npm
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
run: npm ci --ignore-scripts
|
||||
- name: Check if sponsors require updates
|
||||
id: sponsors-requires-update
|
||||
run: node ./bin/sponsors.js
|
||||
run: node ./scripts/update-readme-sponsors.mjs
|
||||
- name: Check tracked README sponsor diff
|
||||
id: readme-tracked-change
|
||||
run: |
|
||||
if git diff --quiet -- README.md; then
|
||||
echo "readme_changed=false" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "readme_changed=true" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
- name: Read sponsors.md file content
|
||||
run: |
|
||||
echo 'CONTENT<<EOF' >> $GITHUB_ENV
|
||||
cat ./temp/sponsors.md >> $GITHUB_ENV
|
||||
echo 'EOF' >> $GITHUB_ENV
|
||||
shell: bash
|
||||
if: steps.sponsors-requires-update.outputs.changed == 'true'
|
||||
if: steps.sponsors-requires-update.outputs.changed == 'true' && steps.readme-tracked-change.outputs.readme_changed == 'true'
|
||||
- name: Echo sponsors content
|
||||
run: |
|
||||
echo "$CONTENT"
|
||||
if: steps.sponsors-requires-update.outputs.changed == 'true'
|
||||
if: steps.sponsors-requires-update.outputs.changed == 'true' && steps.readme-tracked-change.outputs.readme_changed == 'true'
|
||||
- name: Create pull request
|
||||
uses: peter-evans/create-pull-request@v8
|
||||
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
|
||||
with:
|
||||
branch: sponsors
|
||||
delete-branch: true
|
||||
commit-message: "chore(sponsor): update sponsor block"
|
||||
title: "chore(docs): update sponsor block"
|
||||
commit-message: 'chore(sponsor): update sponsor block'
|
||||
title: 'chore(docs): update sponsor block'
|
||||
body: |
|
||||
**New sponsor block update:**
|
||||
${{ env.CONTENT }}
|
||||
@ -61,4 +71,4 @@ jobs:
|
||||
type::automated-pr
|
||||
signoff: false
|
||||
draft: false
|
||||
if: steps.sponsors-requires-update.outputs.changed == 'true'
|
||||
if: steps.sponsors-requires-update.outputs.changed == 'true' && steps.readme-tracked-change.outputs.readme_changed == 'true'
|
||||
|
||||
24
.github/workflows/zizmor.yml
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
name: GitHub Actions Security Analysis with zizmor
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [v1.x]
|
||||
pull_request:
|
||||
branches: ["**"]
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
zizmor:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
security-events: write
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Run zizmor
|
||||
uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2
|
||||
|
||||
5
.gitignore
vendored
@ -13,4 +13,7 @@ backup/
|
||||
.env
|
||||
dist/
|
||||
.vscode/
|
||||
docs/
|
||||
openspec/
|
||||
.opencode/
|
||||
docs/.vitepress/dist
|
||||
docs/.vitepress/cache
|
||||
|
||||
@ -180,7 +180,7 @@
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- form-data npm pakcage ([#6970](https://github.com/axios/axios/issues/6970)) ([e72c193](https://github.com/axios/axios/commit/e72c193722530db538b19e5ddaaa4544d226b253))
|
||||
- form-data npm package ([#6970](https://github.com/axios/axios/issues/6970)) ([e72c193](https://github.com/axios/axios/commit/e72c193722530db538b19e5ddaaa4544d226b253))
|
||||
- prevent RangeError when using large Buffers ([#6961](https://github.com/axios/axios/issues/6961)) ([a2214ca](https://github.com/axios/axios/commit/a2214ca1bc60540baf2c80573cea3a0ff91ba9d1))
|
||||
- **types:** resolve type discrepancies between ESM and CJS TypeScript declaration files ([#6956](https://github.com/axios/axios/issues/6956)) ([8517aa1](https://github.com/axios/axios/commit/8517aa16f8d082fc1d5309c642220fa736159110))
|
||||
|
||||
|
||||
107
README.md
@ -1,4 +1,6 @@
|
||||
<h3 align="center"> 💎 Platinum sponsors <br> </h3> <table align="center"><tr><td align="center" width="50%"> <a href="https://thanks.dev/?utm_source=axios&utm_medium=sponsorlist&utm_campaign=sponsorship" style="padding: 10px; display: inline-block" target="_blank"> <img width="90px" height="90px" src="https://axios-http.com/assets/sponsors/opencollective/ed51c2ee8f1b70aa3484d6dd678652134079a036.png" alt="THANKS.DEV"/> </a> <p align="center" title="We're passionate about making open source sustainable. Scan your dependancy tree to better understand which open source projects need funding the most. Maintainers can also register their projects to become eligible for funding.">We're passionate about making open source sustainable. Scan your dependancy tree to better understand which open source projects need funding the...</p> <p align="center"> <a href="https://thanks.dev/?utm_source=axios&utm_medium=readme_sponsorlist&utm_campaign=sponsorship" target="_blank"><b>thanks.dev</b></a> </p>
|
||||
</td><td align="center" width="50%"> <a href="https://opencollective.com/hopper-security?utm_source=axios&utm_medium=sponsorlist&utm_campaign=sponsorship" style="padding: 10px; display: inline-block" target="_blank"> <img width="90px" height="90px" src="https://axios-http.com/assets/sponsors/opencollective/180d02a83ee99448f850e39eed6dbb95f56000ba.png" alt="Hopper Security"/> </a> <p align="center">Hopper provides a secure open-source registry where every component is verified against malware and continuously remediated for vulnerabilities across any version. In simple terms, Hopper removes the need to manage software supply chain risk altogether.</p><p align="center"> <a href="https://hopper.security/?utm_source=axios&utm_medium=readme_sponsorlist&utm_campaign=sponsorship" target="_blank"><b>Hopper.Security</b></a> </p>
|
||||
</td></tr></table><table align="center"><tr><td align="center" width="50%"> <a href="https://opencollective.com/axios/contribute" target="_blank" >💜 Become a sponsor</a>
|
||||
</td><td align="center" width="50%"> <a href="https://opencollective.com/axios/contribute" target="_blank" >💜 Become a sponsor</a>
|
||||
</td></tr></table>
|
||||
<h3 align="center"> 🥇 Gold sponsors <br> </h3> <table align="center" width="100%"><tr width="33.333333333333336%"><td align="center" width="33.333333333333336%"> <a href="https://www.principal.com/about-us?utm_source=axios&utm_medium=sponsorlist&utm_campaign=sponsorship" style="padding: 10px; display: inline-block" target="_blank"> <img width="133px" height="43px" src="https://axios-http.com/assets/sponsors/principal.svg" alt="Principal Financial Group"/> </a> <p align="center" title="We’re bound by one common purpose: to give you the financial tools, resources and information you need to live your best life.">We’re bound by one common purpose: to give you the financial tools, resources and information you ne...</p> <p align="center"> <a href="https://www.principal.com/about-us?utm_source=axios&utm_medium=readme_sponsorlist&utm_campaign=sponsorship" target="_blank"><b>www.principal.com</b></a> </p>
|
||||
@ -8,7 +10,7 @@
|
||||
</td><td align="center" width="33.333333333333336%"> <a href="https://buzzoid.com/buy-instagram-followers/?utm_source=axios&utm_medium=sponsorlist&utm_campaign=sponsorship" style="padding: 10px; display: inline-block" target="_blank"> <img width="62px" height="70px" src="https://axios-http.com/assets/sponsors/opencollective/e1625cb54e10ee40180c99d1495a462e9d6664a4.png" alt="Buzzoid - Buy Instagram Followers"/> </a> <p align="center" title="At Buzzoid, you can buy Instagram followers quickly, safely, and easily with just a few clicks. Rated world's #1 IG service since 2012.">At Buzzoid, you can buy Instagram followers quickly, safely, and easily with just a few clicks. Rate...</p> <p align="center"> <a href="https://buzzoid.com/buy-instagram-followers/?utm_source=axios&utm_medium=readme_sponsorlist&utm_campaign=sponsorship" target="_blank"><b>buzzoid.com</b></a> </p>
|
||||
</td><td align="center" width="33.333333333333336%"> <a href="https://poprey.com/?utm_source=axios&utm_medium=sponsorlist&utm_campaign=sponsorship" style="padding: 10px; display: inline-block" target="_blank"> <img width="70px" height="70px" src="https://axios-http.com/assets/sponsors/opencollective/e699ec99f7df3a203ddbc49d3c7712a907e628ea.png" alt="Poprey - Buy Instagram Likes"/> </a> <p align="center" title="Buy Instagram Likes">Buy Instagram Likes</p> <p align="center"> <a href="https://poprey.com/?utm_source=axios&utm_medium=readme_sponsorlist&utm_campaign=sponsorship" target="_blank"><b>poprey.com</b></a> </p>
|
||||
</td></tr><tr width="33.333333333333336%"><td align="center" width="33.333333333333336%"> <a href="https://requestly.com/?utm_source=axios&utm_medium=sponsorlist&utm_campaign=sponsorship" style="padding: 10px; display: inline-block" target="_blank"> <img width="71px" height="70px" src="https://axios-http.com/assets/sponsors/opencollective/16450b4dc0deb9dab5a511bf2bc8b8b4ac33412f.png" alt="Requestly"/> </a> <p align="center" title="A lightweight open-source API Development, Testing & Mocking platform">A lightweight open-source API Development, Testing & Mocking platform</p> <p align="center"> <a href="https://requestly.com/?utm_source=axios&utm_medium=readme_sponsorlist&utm_campaign=sponsorship" target="_blank"><b>requestly.com</b></a> </p>
|
||||
</td><td align="center" width="33.333333333333336%"> <a href="https://opencollective.com/axios/contribute" target="_blank" >💜 Become a sponsor</a>
|
||||
</td><td align="center" width="33.333333333333336%"> <a href="https://rxdb.info/?utm_source=opencollective&utm_medium=banner&utm_campaign=opencollective_sponsor&utm_content=logo" style="padding: 10px; display: inline-block" target="_blank"> <img width="158px" height="70px" src="https://axios-http.com/assets/sponsors/opencollective/b28cc6ed919b414cb5f3d4a6d666cb8e06c5ff07.png" alt="RxDB"/> </a> <p align="center" title="RxDB is a fast, local-first NoSQL-database for JavaScript Applications like Websites, hybrid Apps, Electron-Apps, Progressive Web Apps and Node.js">RxDB is a fast, local-first NoSQL-database for JavaScript Applications like Websites, hybrid Apps, E...</p> <p align="center"> <a href="https://rxdb.info/?utm_source=opencollective&utm_medium=banner&utm_campaign=opencollective_sponsor&utm_content=logo" target="_blank"><b>rxdb.info</b></a> </p>
|
||||
</td><td align="center" width="33.333333333333336%"> <a href="https://opencollective.com/axios/contribute" target="_blank" >💜 Become a sponsor</a>
|
||||
</td></tr></table>
|
||||
|
||||
@ -458,6 +460,8 @@ These are the available config options for making requests. Only the `url` is re
|
||||
|
||||
// `withCredentials` indicates whether or not cross-site Access-Control requests
|
||||
// should be made using credentials
|
||||
// This only controls whether the browser sends credentials.
|
||||
// It does not control whether the XSRF header is added.
|
||||
withCredentials: false, // default
|
||||
|
||||
// `adapter` allows custom handling of requests which makes testing easier.
|
||||
@ -497,7 +501,11 @@ These are the available config options for making requests. Only the `url` is re
|
||||
// `xsrfHeaderName` is the name of the http header that carries the xsrf token value
|
||||
xsrfHeaderName: 'X-XSRF-TOKEN', // default
|
||||
|
||||
// `withXSRFToken` defines whether to send the XSRF header in browser requests.
|
||||
// `undefined` (default) - set XSRF header only for the same origin requests
|
||||
// `true` - always set XSRF header, including for cross-origin requests
|
||||
// `false` - never set XSRF header
|
||||
// function - resolve with custom logic; receives the internal config object
|
||||
withXSRFToken: boolean | undefined | ((config: InternalAxiosRequestConfig) => boolean | undefined),
|
||||
|
||||
// `withXSRFToken` controls whether Axios reads the XSRF cookie and sets the XSRF header.
|
||||
@ -552,11 +560,27 @@ These are the available config options for making requests. Only the `url` is re
|
||||
// to inspect the latest response headers,
|
||||
// or to cancel the request by throwing an error
|
||||
// If maxRedirects is set to 0, `beforeRedirect` is not used.
|
||||
|
||||
beforeRedirect: (options, { headers }) => {
|
||||
if (options.hostname === "example.com") {
|
||||
if (
|
||||
options.hostname === "example.com" &&
|
||||
options.protocol === "https:"
|
||||
) {
|
||||
options.auth = "user:password";
|
||||
}
|
||||
},
|
||||
// Security note:
|
||||
// The `beforeRedirect` hook runs after sensitive headers are stripped during redirects.
|
||||
//The `follow-redirects` library removes credentials on protocol downgrade (HTTPS → HTTP) for security.
|
||||
//Since `beforeRedirect` runs after this, re-injecting credentials without checking the protocol can expose sensitive data.
|
||||
//Always ensure credentials are only added for trusted HTTPS destinations.
|
||||
|
||||
// Security note:
|
||||
// The beforeRedirect hook runs after sensitive headers are stripped during redirects.
|
||||
// Re-injecting credentials without checking the destination can expose sensitive data.
|
||||
// Only add credentials for trusted HTTPS destinations.
|
||||
// Avoid re-adding credentials on downgraded redirects.
|
||||
|
||||
|
||||
// `socketPath` defines a UNIX Socket to be used in node.js.
|
||||
// e.g. '/var/run/docker.sock' to send requests to the docker daemon.
|
||||
@ -664,6 +688,15 @@ These are the available config options for making requests. Only the `url` is re
|
||||
]
|
||||
}
|
||||
```
|
||||
## 🔥 HTTP/2 Support
|
||||
|
||||
Axios has experimental HTTP/2 support available via the Node.js HTTP adapter.
|
||||
|
||||
Support depends on the runtime environment and Node.js version. Features like redirects and some behaviors may not be fully supported with HTTP/2.
|
||||
|
||||
Options like `httpVersion` and `http2Options` are adapter-specific and may not work consistently across all environments.
|
||||
|
||||
If HTTP/2 functionality is required, ensure your runtime environment supports it or consider using alternative libraries or custom adapters.
|
||||
|
||||
## Response Schema
|
||||
|
||||
@ -994,15 +1027,25 @@ async function fetchWithTimeout() {
|
||||
try {
|
||||
const response = await axios.get("https://example.com/data", {
|
||||
timeout: 5000, // 5 seconds
|
||||
transitional: {
|
||||
// set to true if you prefer ETIMEDOUT over ECONNABORTED
|
||||
clarifyTimeoutError: false,
|
||||
},
|
||||
});
|
||||
|
||||
console.log("Response:", response.data);
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error) && error.code === "ECONNABORTED") {
|
||||
console.error("❌ Request timed out!");
|
||||
} else {
|
||||
console.error("❌ Error:", error.message);
|
||||
if (axios.isAxiosError(error)) {
|
||||
if (error.code === "ECONNABORTED" || error.code === "ETIMEDOUT") {
|
||||
console.error("Request timed out. Please try again.");
|
||||
return;
|
||||
}
|
||||
|
||||
console.error("Axios error:", error.message);
|
||||
return;
|
||||
}
|
||||
|
||||
console.error("Unexpected error:", error);
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -1553,6 +1596,38 @@ for (const [header, value] of headers) {
|
||||
// baz 3
|
||||
```
|
||||
|
||||
### Preserving a specific header case
|
||||
|
||||
Header names are case-insensitive, but `AxiosHeaders` keeps the case of the first matching key it sees.
|
||||
If you need a specific case for non-standard case-sensitive servers, define a case preset with `undefined` and then set the value later:
|
||||
|
||||
```js
|
||||
const api = axios.create();
|
||||
|
||||
api.defaults.headers.common = {
|
||||
'content-type': undefined,
|
||||
accept: undefined,
|
||||
};
|
||||
|
||||
await api.put(url, data, {
|
||||
headers: {
|
||||
'Content-Type': 'application/octet-stream',
|
||||
Accept: 'application/json',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
You can also compose the same behavior with `AxiosHeaders.concat`:
|
||||
|
||||
```js
|
||||
const headers = axios.AxiosHeaders.concat(
|
||||
{ 'content-type': undefined },
|
||||
{ 'Content-Type': 'application/octet-stream' }
|
||||
);
|
||||
|
||||
await axios.put(url, data, { headers });
|
||||
```
|
||||
|
||||
### new AxiosHeaders(headers?)
|
||||
|
||||
Constructs a new `AxiosHeaders` instance.
|
||||
@ -1843,12 +1918,15 @@ export async function load({ fetch }) {
|
||||
}
|
||||
```
|
||||
|
||||
## 🔥 HTTP2
|
||||
#### HTTP/2 Support
|
||||
|
||||
In version `1.13.0`, experimental `HTTP2` support was added to the `http` adapter.
|
||||
The `httpVersion` option is now available to select the protocol version used.
|
||||
Additional native options for the internal `session.request()` call can be passed via the `http2Options` config.
|
||||
This config also includes the custom `sessionTimeout` parameter, which defaults to `1000ms`.
|
||||
Axios supports HTTP/2 via the Node.js `http` adapter (introduced in v1.13.0).
|
||||
|
||||
This support depends on the runtime environment. Since Axios relies on Node.js APIs, HTTP/2 functionality is available in supported Node.js versions, but may not work in other environments (such as Bun or Deno).
|
||||
|
||||
Options like `httpVersion` and `http2Options` are adapter-specific and may not behave consistently across all environments.
|
||||
|
||||
Note: HTTP/2 redirects are currently not supported by the HTTP/2 adapter.
|
||||
|
||||
```js
|
||||
const form = new FormData();
|
||||
@ -1859,11 +1937,6 @@ const { data, headers, status } = await axios.post(
|
||||
"https://httpbin.org/post",
|
||||
form,
|
||||
{
|
||||
httpVersion: 2,
|
||||
http2Options: {
|
||||
// rejectUnauthorized: false,
|
||||
// sessionTimeout: 1000
|
||||
},
|
||||
onUploadProgress(e) {
|
||||
console.log("upload progress", e);
|
||||
},
|
||||
@ -1871,7 +1944,7 @@ const { data, headers, status } = await axios.post(
|
||||
console.log("download progress", e);
|
||||
},
|
||||
responseType: "arraybuffer",
|
||||
},
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
20
SECURITY.md
@ -11,4 +11,22 @@ The following versions will receive security updates promptly based on the maint
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
To report a vulnerability, please use the GitHub disclosure in the security tab to alert us to a security issue.
|
||||
If you believe you have found a security vulnerability in the project, please report it to us as described below. We take all security vulnerabilities seriously. If you have found a vulnerability in a third-party library, please report it to the maintainers of that library.
|
||||
|
||||
## Reporting Process
|
||||
|
||||
Please do not report security vulnerabilities through public GitHub issues. Please use the official security channel on GitHub by logging a [security advisory](https://github.com/axios/axios/security).
|
||||
## Disclosure Policy
|
||||
|
||||
When we receive a security vulnerability report, we will assign it a primary handler. This person is responsible for the vulnerability report. The handler will confirm the problem and determine the affected versions. The handler will then evaluate the problem and determine the severity of the issue. The handler will develop a fix for the problem and prepare a release. The handler will notify the reporter when the fix is ready to be announced.
|
||||
|
||||
## Security Updates
|
||||
|
||||
Security updates will be released as soon as possible after the patch has been developed and tested. We will notify users of the release via the project’s GitHub repository. We will also publish the release notes and security advisories on the project’s GitHub releases page. We will also deprecate all versions that contain the security vulnerability.
|
||||
|
||||
## Security Partners and Acknowledgements
|
||||
|
||||
We would like to thank the following security researchers for working with us to help make the project safe for everyone:
|
||||
|
||||
- [Socket Dev](https://socket.dev/)
|
||||
- [GitHub Security Lab](https://securitylab.github.com/)
|
||||
|
||||
157
bin/GithubAPI.js
@ -1,157 +0,0 @@
|
||||
import util from 'util';
|
||||
import cp from 'child_process';
|
||||
import { parseVersion } from './helpers/parser.js';
|
||||
import githubAxios from './githubAxios.js';
|
||||
import memoize from 'memoizee';
|
||||
|
||||
const exec = util.promisify(cp.exec);
|
||||
|
||||
export default class GithubAPI {
|
||||
constructor(owner, repo) {
|
||||
if (!owner) {
|
||||
throw new Error('repo owner must be specified');
|
||||
}
|
||||
|
||||
if (!repo) {
|
||||
throw new Error('repo must be specified');
|
||||
}
|
||||
|
||||
this.repo = repo;
|
||||
this.owner = owner;
|
||||
this.axios = githubAxios.create({
|
||||
baseURL: `https://api.github.com/repos/${this.owner}/${this.repo}/`,
|
||||
});
|
||||
}
|
||||
|
||||
async createComment(issue, body) {
|
||||
return (await this.axios.post(`/issues/${issue}/comments`, { body })).data;
|
||||
}
|
||||
|
||||
async getComments(issue, { desc = false, per_page = 100, page = 1 } = {}) {
|
||||
return (
|
||||
await this.axios.get(`/issues/${issue}/comments`, {
|
||||
params: { direction: desc ? 'desc' : 'asc', per_page, page },
|
||||
})
|
||||
).data;
|
||||
}
|
||||
|
||||
async getComment(id) {
|
||||
return (await this.axios.get(`/issues/comments/${id}`)).data;
|
||||
}
|
||||
|
||||
async updateComment(id, body) {
|
||||
return (await this.axios.patch(`/issues/comments/${id}`, { body })).data;
|
||||
}
|
||||
|
||||
async appendLabels(issue, labels) {
|
||||
return (await this.axios.post(`/issues/${issue}/labels`, { labels })).data;
|
||||
}
|
||||
|
||||
async getUser(user) {
|
||||
return (await githubAxios.get(`/users/${user}`)).data;
|
||||
}
|
||||
|
||||
async isCollaborator(user) {
|
||||
try {
|
||||
return (await this.axios.get(`/collaborators/${user}`)).status === 204;
|
||||
} catch (e) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
async deleteLabel(issue, label) {
|
||||
return (await this.axios.delete(`/issues/${issue}/labels/${label}`)).data;
|
||||
}
|
||||
|
||||
async getIssue(issue) {
|
||||
return (await this.axios.get(`/issues/${issue}`)).data;
|
||||
}
|
||||
|
||||
async getPR(issue) {
|
||||
return (await this.axios.get(`/pulls/${issue}`)).data;
|
||||
}
|
||||
|
||||
async getIssues({
|
||||
state = 'open',
|
||||
labels,
|
||||
sort = 'created',
|
||||
desc = false,
|
||||
per_page = 100,
|
||||
page = 1,
|
||||
}) {
|
||||
return (
|
||||
await this.axios.get(`/issues`, {
|
||||
params: { state, labels, sort, direction: desc ? 'desc' : 'asc', per_page, page },
|
||||
})
|
||||
).data;
|
||||
}
|
||||
|
||||
async updateIssue(issue, data) {
|
||||
return (await this.axios.patch(`/issues/${issue}`, data)).data;
|
||||
}
|
||||
|
||||
async closeIssue(issue) {
|
||||
return this.updateIssue(issue, {
|
||||
state: 'closed',
|
||||
});
|
||||
}
|
||||
|
||||
async getReleases({ per_page = 30, page = 1 } = {}) {
|
||||
return (await this.axios.get(`/releases`, { params: { per_page, page } })).data;
|
||||
}
|
||||
|
||||
async getRelease(release = 'latest') {
|
||||
return (
|
||||
await this.axios.get(
|
||||
parseVersion(release) ? `/releases/tags/${release}` : `/releases/${release}`
|
||||
)
|
||||
).data;
|
||||
}
|
||||
|
||||
async getTags({ per_page = 30, page = 1 } = {}) {
|
||||
return (await this.axios.get(`/tags`, { params: { per_page, page } })).data;
|
||||
}
|
||||
|
||||
async reopenIssue(issue) {
|
||||
return this.updateIssue(issue, {
|
||||
state: 'open',
|
||||
});
|
||||
}
|
||||
|
||||
static async getTagRef(tag) {
|
||||
try {
|
||||
return (await exec(`git show-ref --tags "refs/tags/${tag}"`)).stdout.split(' ')[0];
|
||||
} catch (e) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
static async getLatestTag() {
|
||||
try {
|
||||
const { stdout } = await exec(
|
||||
`git for-each-ref refs/tags --sort=-taggerdate --format='%(refname)' --count=1`
|
||||
);
|
||||
|
||||
return stdout.split('/').pop();
|
||||
} catch (e) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
static normalizeTag(tag) {
|
||||
return tag ? 'v' + tag.replace(/^v/, '') : '';
|
||||
}
|
||||
}
|
||||
|
||||
const { prototype } = GithubAPI;
|
||||
|
||||
['getUser', 'isCollaborator'].forEach((methodName) => {
|
||||
prototype[methodName] = memoize(prototype[methodName], { promise: true });
|
||||
});
|
||||
|
||||
['get', 'post', 'put', 'delete', 'isAxiosError'].forEach(
|
||||
(method) =>
|
||||
(prototype[method] = function (...args) {
|
||||
return this.axios[method](...args);
|
||||
})
|
||||
);
|
||||
134
bin/RepoBot.js
@ -1,134 +0,0 @@
|
||||
import GithubAPI from './GithubAPI.js';
|
||||
import api from './api.js';
|
||||
import Handlebars from 'handlebars';
|
||||
import fs from 'fs/promises';
|
||||
import { colorize } from './helpers/colorize.js';
|
||||
import { getReleaseInfo } from './contributors.js';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
const NOTIFY_PR_TEMPLATE = path.resolve(__dirname, '../templates/pr_published.hbs');
|
||||
|
||||
const normalizeTag = (tag) => (tag ? 'v' + tag.replace(/^v/, '') : '');
|
||||
|
||||
const GITHUB_BOT_LOGIN = 'github-actions[bot]';
|
||||
|
||||
const skipCollaboratorPRs = true;
|
||||
|
||||
class RepoBot {
|
||||
constructor(options) {
|
||||
const { owner, repo, templates } = options || {};
|
||||
|
||||
this.templates = {
|
||||
published: NOTIFY_PR_TEMPLATE,
|
||||
...templates,
|
||||
};
|
||||
|
||||
this.github = api || new GithubAPI(owner, repo);
|
||||
|
||||
this.owner = this.github.owner;
|
||||
this.repo = this.github.repo;
|
||||
}
|
||||
|
||||
async addComment(targetId, message) {
|
||||
return this.github.createComment(targetId, message);
|
||||
}
|
||||
|
||||
async notifyPRPublished(id, tag) {
|
||||
let pr;
|
||||
|
||||
try {
|
||||
pr = await this.github.getPR(id);
|
||||
} catch (err) {
|
||||
if (err.response?.status === 404) {
|
||||
throw new Error(`PR #${id} not found (404)`);
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
tag = normalizeTag(tag);
|
||||
|
||||
const {
|
||||
merged,
|
||||
labels,
|
||||
user: { login, type },
|
||||
} = pr;
|
||||
|
||||
const isBot = type === 'Bot';
|
||||
|
||||
if (!merged) {
|
||||
return false;
|
||||
}
|
||||
|
||||
await this.github.appendLabels(id, [tag]);
|
||||
|
||||
if (
|
||||
isBot ||
|
||||
labels.find(({ name }) => name === 'automated pr') ||
|
||||
(skipCollaboratorPRs && (await this.github.isCollaborator(login)))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const comments = await this.github.getComments(id, { desc: true });
|
||||
|
||||
const comment = comments.find(
|
||||
({ body, user }) => user.login === GITHUB_BOT_LOGIN && body.indexOf('published in') >= 0
|
||||
);
|
||||
|
||||
if (comment) {
|
||||
console.log(colorize()`Release comment [${comment.html_url}] already exists in #${pr.id}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const author = await this.github.getUser(login);
|
||||
|
||||
author.isBot = isBot;
|
||||
|
||||
const message = await this.constructor.renderTemplate(this.templates.published, {
|
||||
id,
|
||||
author,
|
||||
release: {
|
||||
tag,
|
||||
url: `https://github.com/${this.owner}/${this.repo}/releases/tag/${tag}`,
|
||||
},
|
||||
});
|
||||
|
||||
return await this.addComment(id, message);
|
||||
}
|
||||
|
||||
async notifyPublishedPRs(tag) {
|
||||
tag = normalizeTag(tag);
|
||||
|
||||
const release = await getReleaseInfo(tag);
|
||||
|
||||
if (!release) {
|
||||
throw Error(colorize()`Can't get release info for ${tag}`);
|
||||
}
|
||||
|
||||
const { merges } = release;
|
||||
|
||||
console.log(colorize()`Found ${merges.length} PRs in ${tag}:`);
|
||||
|
||||
let i = 0;
|
||||
|
||||
for (const pr of merges) {
|
||||
try {
|
||||
console.log(colorize()`${i++}) Notify PR #${pr.id}`);
|
||||
const result = await this.notifyPRPublished(pr.id, tag);
|
||||
console.log('✔️', result ? 'Label, comment' : 'Label');
|
||||
} catch (err) {
|
||||
console.warn(colorize('green', 'red')`❌ Failed notify PR ${pr.id}: ${err.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static async renderTemplate(template, data) {
|
||||
return Handlebars.compile(String(await fs.readFile(template)))(data);
|
||||
}
|
||||
}
|
||||
|
||||
export default RepoBot;
|
||||
@ -1,26 +0,0 @@
|
||||
import minimist from 'minimist';
|
||||
import RepoBot from '../RepoBot.js';
|
||||
import fs from 'fs/promises';
|
||||
|
||||
const argv = minimist(process.argv.slice(2));
|
||||
console.log(argv);
|
||||
|
||||
let { tag } = argv;
|
||||
|
||||
(async () => {
|
||||
if (!tag || tag === true) {
|
||||
const { version } = JSON.parse((await fs.readFile('./package.json')).toString());
|
||||
|
||||
tag = 'v' + version;
|
||||
} else if (typeof tag !== 'string') {
|
||||
throw new Error('tag must be a string');
|
||||
}
|
||||
|
||||
const bot = new RepoBot();
|
||||
|
||||
try {
|
||||
await bot.notifyPublishedPRs(tag);
|
||||
} catch (err) {
|
||||
console.warn('Error:', err.message);
|
||||
}
|
||||
})();
|
||||
@ -1,3 +0,0 @@
|
||||
import GithubAPI from './GithubAPI.js';
|
||||
|
||||
export default new GithubAPI('axios', 'axios');
|
||||
@ -1,27 +0,0 @@
|
||||
import fs from 'fs';
|
||||
import assert from 'assert';
|
||||
import axios from '../index.js';
|
||||
import axiosBuild from '../dist/node/axios.cjs';
|
||||
|
||||
const { version } = JSON.parse(fs.readFileSync('./package.json'));
|
||||
|
||||
console.log('Checking versions...\n----------------------------');
|
||||
|
||||
console.log(`Package version: v${version}`);
|
||||
console.log(`Axios version: v${axios.VERSION}`);
|
||||
console.log(`Axios build version: v${axiosBuild.VERSION}`);
|
||||
console.log(`----------------------------`);
|
||||
|
||||
assert.strictEqual(
|
||||
version,
|
||||
axios.VERSION,
|
||||
`Version mismatch between package and Axios ${version} != ${axios.VERSION}`
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
version,
|
||||
axiosBuild.VERSION,
|
||||
`Version mismatch between package and build ${version} != ${axiosBuild.VERSION}`
|
||||
);
|
||||
|
||||
console.log('✔️ PASSED\n');
|
||||
@ -1,247 +0,0 @@
|
||||
import axios from './githubAxios.js';
|
||||
import util from 'util';
|
||||
import cp from 'child_process';
|
||||
import Handlebars from 'handlebars';
|
||||
import fs from 'fs/promises';
|
||||
import { colorize } from './helpers/colorize.js';
|
||||
|
||||
const exec = util.promisify(cp.exec);
|
||||
|
||||
const ONE_MB = 1024 * 1024;
|
||||
|
||||
const removeExtraLineBreaks = (str) => str.replace(/(?:\r\n|\r|\n){3,}/gm, '\r\n\r\n');
|
||||
|
||||
const cleanTemplate = (template) =>
|
||||
template
|
||||
.replace(/\n +/g, '\n')
|
||||
.replace(/^ +/, '')
|
||||
.replace(/\n\n\n+/g, '\n\n')
|
||||
.replace(/\n\n$/, '\n');
|
||||
|
||||
const getUserFromCommit = ((commitCache) => async (sha) => {
|
||||
try {
|
||||
if (commitCache[sha] !== undefined) {
|
||||
return commitCache[sha];
|
||||
}
|
||||
|
||||
console.log(colorize()`fetch github commit info (${sha})`);
|
||||
|
||||
const { data } = await axios.get(`https://api.github.com/repos/axios/axios/commits/${sha}`);
|
||||
|
||||
return (commitCache[sha] = {
|
||||
...data.commit.author,
|
||||
...data.author,
|
||||
avatar_url_sm: data.author.avatar_url ? data.author.avatar_url + '&s=18' : '',
|
||||
});
|
||||
} catch (err) {
|
||||
return (commitCache[sha] = null);
|
||||
}
|
||||
})({});
|
||||
|
||||
const getIssueById = ((cache) => async (id) => {
|
||||
if (cache[id] !== undefined) {
|
||||
return cache[id];
|
||||
}
|
||||
|
||||
try {
|
||||
const { data } = await axios.get(`https://api.github.com/repos/axios/axios/issues/${id}`);
|
||||
|
||||
return (cache[id] = data);
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
})({});
|
||||
|
||||
const getUserInfo = ((userCache) => async (userEntry) => {
|
||||
const { email, commits } = userEntry;
|
||||
|
||||
if (userCache[email] !== undefined) {
|
||||
return userCache[email];
|
||||
}
|
||||
|
||||
console.log(colorize()`fetch github user info [${userEntry.name}]`);
|
||||
|
||||
return (userCache[email] = {
|
||||
...userEntry,
|
||||
...(await getUserFromCommit(commits[0].hash)),
|
||||
});
|
||||
})({});
|
||||
|
||||
const deduplicate = (authors) => {
|
||||
const loginsMap = {};
|
||||
const combined = {};
|
||||
|
||||
const assign = (a, b) => {
|
||||
const { insertions, _deletions, _points, ...rest } = b;
|
||||
|
||||
Object.assign(a, rest);
|
||||
|
||||
a.insertions += insertions;
|
||||
a.deletions += insertions;
|
||||
a.insertions += insertions;
|
||||
};
|
||||
|
||||
for (const [email, user] of Object.entries(authors)) {
|
||||
const { login } = user;
|
||||
let entry;
|
||||
|
||||
if (login && (entry = loginsMap[login])) {
|
||||
assign(entry, user);
|
||||
} else {
|
||||
login && (loginsMap[login] = user);
|
||||
combined[email] = user;
|
||||
}
|
||||
}
|
||||
|
||||
return combined;
|
||||
};
|
||||
|
||||
const getReleaseInfo = ((releaseCache) => async (tag) => {
|
||||
if (releaseCache[tag] !== undefined) {
|
||||
return releaseCache[tag];
|
||||
}
|
||||
|
||||
const isUnreleasedTag = !tag;
|
||||
|
||||
const version = 'v' + tag.replace(/^v/, '');
|
||||
|
||||
const command = isUnreleasedTag
|
||||
? `npx auto-changelog --unreleased-only --stdout --commit-limit false --template json`
|
||||
: `npx auto-changelog ${
|
||||
version ? '--starting-version ' + version + ' --ending-version ' + version : ''
|
||||
} --stdout --commit-limit false --template json`;
|
||||
|
||||
console.log(command);
|
||||
|
||||
const { stdout } = await exec(command, { maxBuffer: 10 * ONE_MB });
|
||||
|
||||
const release = JSON.parse(stdout)[0];
|
||||
|
||||
if (release) {
|
||||
const authors = {};
|
||||
|
||||
const commits = [
|
||||
...release.commits,
|
||||
...release.fixes.map((fix) => fix.commit),
|
||||
...release.merges.map((fix) => fix.commit),
|
||||
].filter(Boolean);
|
||||
|
||||
const commitMergeMap = {};
|
||||
|
||||
for (const merge of release.merges) {
|
||||
commitMergeMap[merge.commit.hash] = merge.id;
|
||||
}
|
||||
|
||||
for (const { hash, author, email, insertions, deletions } of commits) {
|
||||
const entry = (authors[email] = authors[email] || {
|
||||
name: author,
|
||||
prs: [],
|
||||
email,
|
||||
commits: [],
|
||||
insertions: 0,
|
||||
deletions: 0,
|
||||
});
|
||||
|
||||
entry.commits.push({ hash });
|
||||
|
||||
let pr;
|
||||
|
||||
if ((pr = commitMergeMap[hash])) {
|
||||
entry.prs.push(pr);
|
||||
}
|
||||
|
||||
console.log(colorize()`Found commit [${hash}]`);
|
||||
|
||||
entry.displayName = entry.name || author || entry.login;
|
||||
|
||||
entry.github = entry.login ? `https://github.com/${encodeURIComponent(entry.login)}` : '';
|
||||
|
||||
entry.insertions += insertions;
|
||||
entry.deletions += deletions;
|
||||
entry.points = entry.insertions + entry.deletions;
|
||||
}
|
||||
|
||||
for (const [email, author] of Object.entries(authors)) {
|
||||
const entry = (authors[email] = await getUserInfo(author));
|
||||
|
||||
entry.isBot = entry.type === 'Bot';
|
||||
}
|
||||
|
||||
release.authors = Object.values(deduplicate(authors)).sort((a, b) => b.points - a.points);
|
||||
|
||||
release.allCommits = commits;
|
||||
}
|
||||
|
||||
releaseCache[tag] = release;
|
||||
|
||||
return release;
|
||||
})({});
|
||||
|
||||
const renderContributorsList = async (tag, template) => {
|
||||
const release = await getReleaseInfo(tag);
|
||||
|
||||
const compile = Handlebars.compile(String(await fs.readFile(template)));
|
||||
|
||||
const content = compile(release);
|
||||
|
||||
return removeExtraLineBreaks(cleanTemplate(content));
|
||||
};
|
||||
|
||||
const renderPRsList = async (
|
||||
tag,
|
||||
template,
|
||||
{ comments_threshold = 5, awesome_threshold = 5, label = 'add_to_changelog' } = {}
|
||||
) => {
|
||||
const release = await getReleaseInfo(tag);
|
||||
|
||||
const prs = {};
|
||||
|
||||
for (const merge of release.merges) {
|
||||
const pr = await getIssueById(merge.id);
|
||||
|
||||
if (pr && pr.labels.find(({ name }) => name === label)) {
|
||||
const { reactions, body } = pr;
|
||||
prs[pr.number] = pr;
|
||||
pr.isHot = pr.comments > comments_threshold;
|
||||
const points =
|
||||
reactions['+1'] +
|
||||
reactions['hooray'] +
|
||||
reactions['rocket'] +
|
||||
reactions['heart'] +
|
||||
reactions['laugh'] -
|
||||
reactions['-1'];
|
||||
|
||||
pr.isAwesome = points > awesome_threshold;
|
||||
|
||||
let match;
|
||||
|
||||
pr.messages = [];
|
||||
|
||||
if (body) {
|
||||
const reg = /```+changelog\n*(.+?)?\n*```/gms;
|
||||
|
||||
while ((match = reg.exec(body))) {
|
||||
match[1] && pr.messages.push(match[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
release.prs = Object.values(prs);
|
||||
|
||||
const compile = Handlebars.compile(String(await fs.readFile(template)));
|
||||
|
||||
const content = compile(release);
|
||||
|
||||
return removeExtraLineBreaks(cleanTemplate(content));
|
||||
};
|
||||
|
||||
const getTagRef = async (tag) => {
|
||||
try {
|
||||
return (await exec(`git show-ref --tags "refs/tags/${tag}"`)).stdout.split(' ')[0];
|
||||
} catch (e) {
|
||||
// Do nothing
|
||||
}
|
||||
};
|
||||
|
||||
export { renderContributorsList, getReleaseInfo, renderPRsList, getTagRef };
|
||||
@ -1,16 +0,0 @@
|
||||
import chalk from 'chalk';
|
||||
|
||||
export const colorize = (...colors) => {
|
||||
if (!colors.length) {
|
||||
colors = ['green', 'cyan', 'magenta', 'blue', 'yellow', 'red'];
|
||||
}
|
||||
|
||||
const colorsCount = colors.length;
|
||||
|
||||
return (strings, ...values) => {
|
||||
const { length } = values;
|
||||
return strings
|
||||
.map((str, i) => (i < length ? str + chalk[colors[i % colorsCount]].bold(values[i]) : str))
|
||||
.join('');
|
||||
};
|
||||
};
|
||||
@ -1,13 +0,0 @@
|
||||
export const matchAll = (text, regexp, cb) => {
|
||||
let match;
|
||||
|
||||
while ((match = regexp.exec(text))) {
|
||||
cb(match);
|
||||
}
|
||||
};
|
||||
|
||||
export const parseSection = (body, name, cb) => {
|
||||
matchAll(body, new RegExp(`^(#+)\\s+${name}?(.*?)^\\1\\s+\\w+`, 'gims'), cb);
|
||||
};
|
||||
|
||||
export const parseVersion = (rawVersion) => /^v?(\d+).(\d+).(\d+)/.exec(rawVersion);
|
||||
@ -1,74 +0,0 @@
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import { renderContributorsList, getTagRef, renderPRsList } from './contributors.js';
|
||||
import asyncReplace from 'string-replace-async';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { colorize } from './helpers/colorize.js';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
const CONTRIBUTORS_TEMPLATE = path.resolve(__dirname, '../templates/contributors.hbs');
|
||||
const PRS_TEMPLATE = path.resolve(__dirname, '../templates/prs.hbs');
|
||||
|
||||
const injectSection = async (name, contributorsRE, injector, infile = '../CHANGELOG.md') => {
|
||||
console.log(colorize()`Checking ${name} sections in ${infile}`);
|
||||
|
||||
infile = path.resolve(__dirname, infile);
|
||||
|
||||
const content = String(await fs.readFile(infile));
|
||||
const headerRE = /^#+\s+\[([-_\d.\w]+)].+?$/gim;
|
||||
|
||||
let tag;
|
||||
let index = 0;
|
||||
let isFirstTag = true;
|
||||
|
||||
const newContent = await asyncReplace(content, headerRE, async (match, nextTag, offset) => {
|
||||
const releaseContent = content.slice(index, offset);
|
||||
|
||||
const hasSection = contributorsRE.test(releaseContent);
|
||||
|
||||
const currentTag = tag;
|
||||
|
||||
tag = nextTag;
|
||||
index = offset + match.length;
|
||||
|
||||
if (currentTag) {
|
||||
if (hasSection) {
|
||||
console.log(colorize()`[${currentTag}]: ✓ OK`);
|
||||
} else {
|
||||
const target = isFirstTag && !(await getTagRef(currentTag)) ? '' : currentTag;
|
||||
|
||||
console.log(colorize()`[${currentTag}]: ❌ MISSED` + (!target ? ' (UNRELEASED)' : ''));
|
||||
|
||||
isFirstTag = false;
|
||||
|
||||
console.log(`Generating section...`);
|
||||
|
||||
const section = await injector(target);
|
||||
|
||||
if (!section) {
|
||||
return match;
|
||||
}
|
||||
|
||||
console.log(colorize()`\nRENDERED SECTION [${name}] for [${currentTag}]:`);
|
||||
console.log('-------------BEGIN--------------\n');
|
||||
console.log(section);
|
||||
console.log('--------------END---------------\n');
|
||||
|
||||
return section + '\n' + match;
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
});
|
||||
|
||||
await fs.writeFile(infile, newContent);
|
||||
};
|
||||
|
||||
await injectSection('PRs', /^\s*### PRs/im, (tag) =>
|
||||
tag ? '' : renderPRsList(tag, PRS_TEMPLATE, { awesome_threshold: 5, comments_threshold: 7 })
|
||||
);
|
||||
|
||||
await injectSection('contributors', /^\s*### Contributors/im, (tag) =>
|
||||
renderContributorsList(tag, CONTRIBUTORS_TEMPLATE)
|
||||
);
|
||||
139
bin/pr.js
@ -1,139 +0,0 @@
|
||||
import Handlebars from 'handlebars';
|
||||
import fs from 'fs/promises';
|
||||
import prettyBytes from 'pretty-bytes';
|
||||
import { getBlobHistory } from './repo.js';
|
||||
import pacote from 'pacote';
|
||||
import zlib from 'zlib';
|
||||
import tar from 'tar-stream';
|
||||
import { Readable } from 'stream';
|
||||
|
||||
const FILE_SIZE_DIFF_THRESHOLD = 512; // 0.5KB
|
||||
|
||||
const readJSONFile = async (file) => JSON.parse(String(await fs.readFile(file)));
|
||||
|
||||
const { version } = await readJSONFile('./package.json');
|
||||
|
||||
const parseVersion = (tag) => {
|
||||
const [, major, minor, patch] = /^v?(\d+)\.(\d+)\.(\d+)/.exec(tag) || [];
|
||||
return [major, minor, patch];
|
||||
};
|
||||
|
||||
const [MAJOR_NUMBER] = parseVersion(version);
|
||||
|
||||
async function getFilesFromNPM(pkg) {
|
||||
const tgzData = await pacote.tarball(pkg); // Buffer з npm
|
||||
const files = {};
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const extract = tar.extract();
|
||||
|
||||
extract.on('entry', (header, stream, next) => {
|
||||
const buffers = [];
|
||||
|
||||
stream.on('data', (buffer) => {
|
||||
buffers.push(buffer);
|
||||
});
|
||||
|
||||
stream.on('end', () => {
|
||||
const content = Buffer.concat(buffers);
|
||||
|
||||
const gzipped = zlib.gzipSync(content);
|
||||
|
||||
files[header.name.replace(/^package\//, '')] = {
|
||||
gzip: gzipped.length,
|
||||
compressed: header.size ? gzipped.length / header.size : 1,
|
||||
...header,
|
||||
};
|
||||
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
Readable.from(tgzData)
|
||||
.pipe(zlib.createGunzip())
|
||||
.pipe(extract)
|
||||
.on('error', reject)
|
||||
.on('finish', () => resolve(files));
|
||||
});
|
||||
}
|
||||
|
||||
const generateFileReport = async (files, historyCount = 3) => {
|
||||
const allFilesStat = {};
|
||||
const commits = (await getBlobHistory('package.json', historyCount)).filter(({ tag }) => {
|
||||
return MAJOR_NUMBER === parseVersion(tag)[0];
|
||||
});
|
||||
const warns = [];
|
||||
|
||||
const npmHistory = {};
|
||||
|
||||
await Promise.all(
|
||||
commits.map(async ({ tag }) => {
|
||||
npmHistory[tag] = await getFilesFromNPM(`axios@${tag.replace(/^v/, '')}`);
|
||||
})
|
||||
);
|
||||
|
||||
for (const [name, filename] of Object.entries(files)) {
|
||||
const file = await fs.stat(filename).catch(console.warn);
|
||||
const gzip = file ? zlib.gzipSync(await fs.readFile(filename)).length : 0;
|
||||
|
||||
const stat = (allFilesStat[filename] = file
|
||||
? {
|
||||
name,
|
||||
size: file.size,
|
||||
path: filename,
|
||||
gzip,
|
||||
compressed: file.size ? gzip / file.size : 1,
|
||||
history: commits.map(({ tag }) => {
|
||||
const files = npmHistory[tag];
|
||||
const file = (files && files[filename]) || null;
|
||||
|
||||
return {
|
||||
tag,
|
||||
...file,
|
||||
};
|
||||
}),
|
||||
}
|
||||
: null);
|
||||
|
||||
if (stat.history[0]) {
|
||||
const diff = stat.gzip - stat.history[0].gzip;
|
||||
|
||||
if (diff > FILE_SIZE_DIFF_THRESHOLD) {
|
||||
warns.push({
|
||||
filename,
|
||||
sizeReport: true,
|
||||
diff,
|
||||
percent: stat.gzip ? diff / stat.gzip : 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
version,
|
||||
files: allFilesStat,
|
||||
warns,
|
||||
};
|
||||
};
|
||||
|
||||
const generateBody = async ({ files, template = './templates/pr.hbs' } = {}) => {
|
||||
const data = await generateFileReport(files);
|
||||
|
||||
Handlebars.registerHelper('filesize', (bytes) =>
|
||||
bytes != null ? prettyBytes(bytes) : '<unknown>'
|
||||
);
|
||||
Handlebars.registerHelper('percent', (value) =>
|
||||
Number.isFinite(value) ? `${(value * 100).toFixed(1)}%` : `---`
|
||||
);
|
||||
|
||||
return Handlebars.compile(String(await fs.readFile(template)))(data);
|
||||
};
|
||||
|
||||
console.log(
|
||||
await generateBody({
|
||||
files: {
|
||||
'Browser build (UMD)': 'dist/axios.min.js',
|
||||
'Browser build (ESM)': 'dist/esm/axios.min.js',
|
||||
},
|
||||
})
|
||||
);
|
||||
40
bin/repo.js
@ -1,40 +0,0 @@
|
||||
import util from 'util';
|
||||
import cp from 'child_process';
|
||||
|
||||
export const exec = util.promisify(cp.exec);
|
||||
|
||||
export const getBlobSize = async (filepath, sha = 'HEAD') => {
|
||||
const size = (await exec(`git cat-file -s ${sha}:${filepath}`)).stdout;
|
||||
|
||||
return size ? +size : 0;
|
||||
};
|
||||
|
||||
export const getBlobHistory = async (filepath, maxCount = 5) => {
|
||||
const log = (
|
||||
await exec(
|
||||
`git log --max-count=${maxCount} --no-walk --tags=v* --oneline --format=%H%d -- ${filepath}`
|
||||
)
|
||||
).stdout;
|
||||
|
||||
const commits = [];
|
||||
|
||||
let match;
|
||||
|
||||
const regexp = /^(\w+) \(tag: (v?[.\d]+)\)$/gm;
|
||||
|
||||
while ((match = regexp.exec(log))) {
|
||||
commits.push({
|
||||
sha: match[1],
|
||||
tag: match[2],
|
||||
size: await getBlobSize(filepath, match[1]),
|
||||
});
|
||||
}
|
||||
|
||||
return commits;
|
||||
};
|
||||
|
||||
export const getTags = async (pattern = 'v*', sort = '-v:refname') => {
|
||||
const log = (await exec(`git tag -l ${pattern} --sort=${sort}`)).stdout;
|
||||
|
||||
return log.split(/\r?\n/);
|
||||
};
|
||||
@ -1,20 +0,0 @@
|
||||
import { exec, getTags } from './repo.js';
|
||||
import fs from 'fs';
|
||||
import { colorize } from './helpers/colorize.js';
|
||||
|
||||
const { version } = JSON.parse(fs.readFileSync('./package.json'));
|
||||
|
||||
const [major] = version.split('.');
|
||||
const tags = await getTags();
|
||||
const latestTag = (tags[0] || '').replace(/^v/, '');
|
||||
|
||||
const isBeta = !/^v?(\d+).(\d)+.(\d)+$/.test(version);
|
||||
const isLatest = latestTag === version;
|
||||
|
||||
let tag = isBeta ? 'next' : isLatest ? 'latest' : `v${major}`;
|
||||
|
||||
console.log(
|
||||
colorize()`Version [${version}] [${isBeta ? 'prerelease' : 'release'}] latest [${latestTag}]=> NPM Tag [${tag}]`
|
||||
);
|
||||
|
||||
await exec(`echo "tag=${tag}" >> $GITHUB_OUTPUT`);
|
||||
@ -1,37 +0,0 @@
|
||||
import { startTestServer, stopHTTPServer } from '../test/helpers/server.js';
|
||||
import { spawn } from 'child_process';
|
||||
import chalk from 'chalk';
|
||||
|
||||
let server;
|
||||
|
||||
async function run() {
|
||||
console.log(chalk.red.bold(`[ Starting HTTP server... ]`));
|
||||
|
||||
server = await startTestServer(3000);
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
console.log('Starting karma runner...');
|
||||
|
||||
const karma = spawn('npx', ['karma', 'start', 'karma.conf.cjs', '--single-run'], {
|
||||
stdio: 'inherit',
|
||||
shell: true,
|
||||
env: { ...process.env, LISTEN_ADDR: '0.0.0.0' },
|
||||
});
|
||||
|
||||
karma.on('exit', (code) => {
|
||||
code ? reject(new Error(`Karma tests failed with exit code ${code}`)) : resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
await run();
|
||||
} finally {
|
||||
if (server) {
|
||||
console.log(chalk.red.bold(`[ Terminating HTTP server... ]`));
|
||||
|
||||
await stopHTTPServer(server);
|
||||
}
|
||||
}
|
||||
})();
|
||||
@ -1,24 +0,0 @@
|
||||
import { spawn } from 'child_process';
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
console.log(`Running ${args.join(' ')} on ${process.version}\n`);
|
||||
|
||||
const match = /v(\d+)/.exec(process.version);
|
||||
|
||||
const isHotfixNeeded = match && match[1] > 16;
|
||||
|
||||
isHotfixNeeded && console.warn('Setting --openssl-legacy-provider as ssl hotfix');
|
||||
|
||||
const test = spawn(
|
||||
'cross-env',
|
||||
isHotfixNeeded ? ['NODE_OPTIONS=--openssl-legacy-provider', ...args] : args,
|
||||
{
|
||||
shell: true,
|
||||
stdio: 'inherit',
|
||||
}
|
||||
);
|
||||
|
||||
test.on('exit', function (code) {
|
||||
process.exit(code);
|
||||
});
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "axios",
|
||||
"main": "./dist/axios.js",
|
||||
"version": "1.14.0",
|
||||
"version": "1.15.0",
|
||||
"homepage": "https://axios-http.com",
|
||||
"authors": [
|
||||
"Matt Zabriskie"
|
||||
|
||||
128
docs/.vitepress/config.mts
Normal file
@ -0,0 +1,128 @@
|
||||
import { defineConfig } from 'vitepress';
|
||||
|
||||
// https://vitepress.dev/reference/site-config
|
||||
export default defineConfig({
|
||||
lang: 'en-US',
|
||||
title: 'axios | Promise based HTTP client',
|
||||
description: 'Documentation for the axios HTTP project',
|
||||
head: [
|
||||
['link', { rel: 'icon', href: '/favicon.ico' }],
|
||||
['link', { rel: 'apple-touch-icon', sizes: '180x180', href: '/apple-touch-icon.png' }],
|
||||
['link', { rel: 'icon', type: 'image/png', sizes: '32x32', href: '/favicon-32x32.png' }],
|
||||
['link', { rel: 'icon', type: 'image/png', sizes: '16x16', href: '/favicon-16x16.png' }],
|
||||
['link', { rel: 'manifest', href: '/site.webmanifest' }],
|
||||
],
|
||||
themeConfig: {
|
||||
logo: {
|
||||
dark: '/words.svg',
|
||||
light: '/words-light.svg',
|
||||
},
|
||||
siteTitle: false,
|
||||
nav: [
|
||||
{ text: 'Guide', link: '/pages/getting-started/first-steps' },
|
||||
{ text: 'API', link: '/pages/advanced/api-reference' },
|
||||
{ text: 'Sponsors', link: '/pages/misc/sponsors' },
|
||||
{ text: 'v1.x', link: '#' },
|
||||
],
|
||||
sidebar: [
|
||||
{
|
||||
text: 'Getting Started',
|
||||
items: [
|
||||
{ text: 'First steps', link: '/pages/getting-started/first-steps' },
|
||||
{ text: 'Features', link: '/pages/getting-started/features' },
|
||||
{
|
||||
text: 'Examples',
|
||||
items: [
|
||||
{
|
||||
text: 'JavaScript',
|
||||
link: '/pages/getting-started/examples/commonjs',
|
||||
},
|
||||
{
|
||||
text: 'TypeScript',
|
||||
link: '/pages/getting-started/examples/typescript',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Upgrade guide v0.x -> v1.x',
|
||||
link: '/pages/getting-started/upgrade-guide',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Advanced',
|
||||
items: [
|
||||
{ text: 'Public API', link: '/pages/advanced/api-reference' },
|
||||
{
|
||||
text: 'Request method aliases',
|
||||
link: '/pages/advanced/request-method-aliases',
|
||||
},
|
||||
{
|
||||
text: 'Creating an instance',
|
||||
link: '/pages/advanced/create-an-instance',
|
||||
},
|
||||
{ text: 'Request config', link: '/pages/advanced/request-config' },
|
||||
{ text: 'Adapters', link: '/pages/advanced/adapters' },
|
||||
{ text: 'Response schema', link: '/pages/advanced/response-schema' },
|
||||
{ text: 'Config defaults', link: '/pages/advanced/config-defaults' },
|
||||
{ text: 'Interceptors', link: '/pages/advanced/interceptors' },
|
||||
{ text: 'Error handling', link: '/pages/advanced/error-handling' },
|
||||
{ text: 'Cancellation', link: '/pages/advanced/cancellation' },
|
||||
{ text: 'Authentication', link: '/pages/advanced/authentication' },
|
||||
{ text: 'Retry & error recovery', link: '/pages/advanced/retry' },
|
||||
{ text: 'Testing', link: '/pages/advanced/testing' },
|
||||
{
|
||||
text: 'x-www-form-urlencoded format',
|
||||
link: '/pages/advanced/x-www-form-urlencoded-format',
|
||||
},
|
||||
{
|
||||
text: 'Multipart/form-data format',
|
||||
link: '/pages/advanced/multipart-form-data-format',
|
||||
},
|
||||
{ text: 'File posting', link: '/pages/advanced/file-posting' },
|
||||
{
|
||||
text: 'HTML form processing 🔥',
|
||||
link: '/pages/advanced/html-form-processing',
|
||||
},
|
||||
{
|
||||
text: 'Progress capturing 🔥',
|
||||
link: '/pages/advanced/progress-capturing',
|
||||
},
|
||||
{ text: 'Rate limiting 🔥', link: '/pages/advanced/rate-limiting' },
|
||||
{
|
||||
text: 'Headers 🔥',
|
||||
items: [
|
||||
{
|
||||
text: 'General usage',
|
||||
link: '/pages/advanced/headers',
|
||||
},
|
||||
{
|
||||
text: 'Methods',
|
||||
link: '/pages/advanced/header-methods',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Fetch adapter 🔥',
|
||||
link: '/pages/advanced/fetch-adapter',
|
||||
},
|
||||
{ text: 'HTTP2 🔥', link: '/pages/advanced/http2' },
|
||||
{ text: 'Promises', link: '/pages/advanced/promises' },
|
||||
{ text: 'TypeScript', link: '/pages/advanced/type-script' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Miscellaneous',
|
||||
items: [
|
||||
{ text: 'SemVer', link: '/pages/misc/semver' },
|
||||
{ text: 'Security', link: '/pages/misc/security' },
|
||||
],
|
||||
},
|
||||
],
|
||||
socialLinks: [{ icon: 'github', link: 'https://github.com/axios/axios' }],
|
||||
footer: {
|
||||
message: 'axios is provided under MIT license',
|
||||
copyright: 'Copyright © 2015-present axios collective',
|
||||
},
|
||||
},
|
||||
});
|
||||
17
docs/.vitepress/theme/index.ts
Normal file
@ -0,0 +1,17 @@
|
||||
// https://vitepress.dev/guide/custom-theme
|
||||
import { h } from 'vue'
|
||||
import type { Theme } from 'vitepress'
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import './style.css'
|
||||
|
||||
export default {
|
||||
extends: DefaultTheme,
|
||||
Layout: () => {
|
||||
return h(DefaultTheme.Layout, null, {
|
||||
// https://vitepress.dev/guide/extending-default-theme#layout-slots
|
||||
})
|
||||
},
|
||||
enhanceApp({ app, router, siteData }) {
|
||||
// ...
|
||||
}
|
||||
} satisfies Theme
|
||||
139
docs/.vitepress/theme/style.css
Normal file
@ -0,0 +1,139 @@
|
||||
/**
|
||||
* Customize default theme styling by overriding CSS variables:
|
||||
* https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css
|
||||
*/
|
||||
|
||||
/**
|
||||
* Colors
|
||||
*
|
||||
* Each colors have exact same color scale system with 3 levels of solid
|
||||
* colors with different brightness, and 1 soft color.
|
||||
*
|
||||
* - `XXX-1`: The most solid color used mainly for colored text. It must
|
||||
* satisfy the contrast ratio against when used on top of `XXX-soft`.
|
||||
*
|
||||
* - `XXX-2`: The color used mainly for hover state of the button.
|
||||
*
|
||||
* - `XXX-3`: The color for solid background, such as bg color of the button.
|
||||
* It must satisfy the contrast ratio with pure white (#ffffff) text on
|
||||
* top of it.
|
||||
*
|
||||
* - `XXX-soft`: The color used for subtle background such as custom container
|
||||
* or badges. It must satisfy the contrast ratio when putting `XXX-1` colors
|
||||
* on top of it.
|
||||
*
|
||||
* The soft color must be semi transparent alpha channel. This is crucial
|
||||
* because it allows adding multiple "soft" colors on top of each other
|
||||
* to create a accent, such as when having inline code block inside
|
||||
* custom containers.
|
||||
*
|
||||
* - `default`: The color used purely for subtle indication without any
|
||||
* special meanings attached to it such as bg color for menu hover state.
|
||||
*
|
||||
* - `brand`: Used for primary brand colors, such as link text, button with
|
||||
* brand theme, etc.
|
||||
*
|
||||
* - `tip`: Used to indicate useful information. The default theme uses the
|
||||
* brand color for this by default.
|
||||
*
|
||||
* - `warning`: Used to indicate warning to the users. Used in custom
|
||||
* container, badges, etc.
|
||||
*
|
||||
* - `danger`: Used to show error, or dangerous message to the users. Used
|
||||
* in custom container, badges, etc.
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
:root {
|
||||
--vp-c-default-1: var(--vp-c-gray-1);
|
||||
--vp-c-default-2: var(--vp-c-gray-2);
|
||||
--vp-c-default-3: var(--vp-c-gray-3);
|
||||
--vp-c-default-soft: var(--vp-c-gray-soft);
|
||||
|
||||
--vp-c-brand-1: var(--vp-c-indigo-1);
|
||||
--vp-c-brand-2: var(--vp-c-indigo-2);
|
||||
--vp-c-brand-3: var(--vp-c-indigo-3);
|
||||
--vp-c-brand-soft: var(--vp-c-indigo-soft);
|
||||
|
||||
--vp-c-tip-1: var(--vp-c-brand-1);
|
||||
--vp-c-tip-2: var(--vp-c-brand-2);
|
||||
--vp-c-tip-3: var(--vp-c-brand-3);
|
||||
--vp-c-tip-soft: var(--vp-c-brand-soft);
|
||||
|
||||
--vp-c-warning-1: var(--vp-c-yellow-1);
|
||||
--vp-c-warning-2: var(--vp-c-yellow-2);
|
||||
--vp-c-warning-3: var(--vp-c-yellow-3);
|
||||
--vp-c-warning-soft: var(--vp-c-yellow-soft);
|
||||
|
||||
--vp-c-danger-1: var(--vp-c-red-1);
|
||||
--vp-c-danger-2: var(--vp-c-red-2);
|
||||
--vp-c-danger-3: var(--vp-c-red-3);
|
||||
--vp-c-danger-soft: var(--vp-c-red-soft);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component: Button
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
:root {
|
||||
--vp-button-brand-border: transparent;
|
||||
--vp-button-brand-text: var(--vp-c-white);
|
||||
--vp-button-brand-bg: var(--vp-c-brand-3);
|
||||
--vp-button-brand-hover-border: transparent;
|
||||
--vp-button-brand-hover-text: var(--vp-c-white);
|
||||
--vp-button-brand-hover-bg: var(--vp-c-brand-2);
|
||||
--vp-button-brand-active-border: transparent;
|
||||
--vp-button-brand-active-text: var(--vp-c-white);
|
||||
--vp-button-brand-active-bg: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component: Home
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
:root {
|
||||
--vp-home-hero-name-color: transparent;
|
||||
--vp-home-hero-name-background: -webkit-linear-gradient(
|
||||
120deg,
|
||||
#bd34fe 30%,
|
||||
#41d1ff
|
||||
);
|
||||
|
||||
--vp-home-hero-image-background-image: linear-gradient(
|
||||
-45deg,
|
||||
#bd34fe 50%,
|
||||
#47caff 50%
|
||||
);
|
||||
--vp-home-hero-image-filter: blur(44px);
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
:root {
|
||||
--vp-home-hero-image-filter: blur(56px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
:root {
|
||||
--vp-home-hero-image-filter: blur(68px);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Component: Custom Block
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
:root {
|
||||
--vp-custom-block-tip-border: transparent;
|
||||
--vp-custom-block-tip-text: var(--vp-c-text-1);
|
||||
--vp-custom-block-tip-bg: var(--vp-c-brand-soft);
|
||||
--vp-custom-block-tip-code-bg: var(--vp-c-brand-soft);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component: Algolia
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
.DocSearch {
|
||||
--docsearch-primary-color: var(--vp-c-brand-1) !important;
|
||||
}
|
||||
|
||||
1872
docs/data/sponsors.json
Normal file
BIN
docs/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
329
docs/index.md
Normal file
@ -0,0 +1,329 @@
|
||||
---
|
||||
# https://vitepress.dev/reference/default-theme-home-page
|
||||
layout: home
|
||||
|
||||
hero:
|
||||
name: 'axios docs'
|
||||
text: 'axios is a simple HTTP client for the browser and Node.js'
|
||||
image:
|
||||
dark: /logo.svg
|
||||
light: /logo-light.svg
|
||||
alt: axios
|
||||
actions:
|
||||
- theme: brand
|
||||
text: Get started
|
||||
link: /pages/getting-started/first-steps
|
||||
- theme: alt
|
||||
text: API reference
|
||||
link: /pages/advanced/api-reference
|
||||
|
||||
features:
|
||||
- title: Simple implementation
|
||||
details: Getting started with axios is as simple as a single line of code. Making simple API requests can be done in 2 lines of code.
|
||||
- title: Powerful interceptors
|
||||
details: Our innovative interceptor system allows you to control the request and response lifecycle. You can modify requests, responses, and errors.
|
||||
- title: TypeScript support
|
||||
details: axios declares types and has full support for TypeScript. This means you can use axios with confidence in your TypeScript projects.
|
||||
---
|
||||
|
||||
<script setup>
|
||||
import Splide from '@splidejs/splide';
|
||||
import { onMounted } from 'vue';
|
||||
import allSponsors from './data/sponsors.json';
|
||||
|
||||
onMounted(() => {
|
||||
new Splide(
|
||||
'.splide',
|
||||
{
|
||||
type: 'loop',
|
||||
autoplay: true,
|
||||
interval: 3000,
|
||||
perPage: 5,
|
||||
perMove: 1,
|
||||
gap: 10,
|
||||
snap: true,
|
||||
pagination: false,
|
||||
breakpoints: {
|
||||
1200: {
|
||||
perPage: 4,
|
||||
},
|
||||
960: {
|
||||
perPage: 3,
|
||||
},
|
||||
640: {
|
||||
perPage: 2,
|
||||
},
|
||||
480: {
|
||||
perPage: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
).mount();
|
||||
});
|
||||
|
||||
const activePlatinumSponsors = allSponsors.platinum.filter((sponsor) => sponsor.active);
|
||||
const activeGoldSponsors = allSponsors.gold.filter((sponsor) => sponsor.active);
|
||||
const activeSilverSponsors = allSponsors.silver.filter((sponsor) => sponsor.active);
|
||||
|
||||
const sponsors = [...activePlatinumSponsors, ...activeGoldSponsors, ...activeSilverSponsors];
|
||||
|
||||
const capitalizeFirstLetter = (word) => {
|
||||
return String(word).charAt(0).toUpperCase() + String(word).slice(1);
|
||||
};
|
||||
</script>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@splidejs/splide@4.1.4/dist/css/splide.min.css">
|
||||
|
||||
<div style="margin: 0 auto; max-width: 1200px;">
|
||||
<h3 style="line-height: 64px;font-size: 28px;letter-spacing: -0.4px;font-weight: 600;margin-top: 2rem;">Sponsors</h3>
|
||||
</div>
|
||||
<div v-if="sponsors.length > 0" :class="$style.container" class="splide">
|
||||
<div class="splide__track">
|
||||
<div role="list" class="splide__list">
|
||||
<div v-for="(sponsor, key) in sponsors" :key="sponsor.name" :class="$style.cardWrapper" :style="key === 0 ? 'margin-left: 0.5rem' : key === sponsors.length - 1 ? 'margin-right: 0.5rem' : ''" class="splide__slide">
|
||||
<div :class="$style.imgWrapper">
|
||||
<img :class="$style.img" :src="sponsor.imageUrl" alt="" />
|
||||
</div>
|
||||
<div style="padding-left: 0.5rem; padding-right: 0.5rem; height: 100%;">
|
||||
<p :class="$style.heading">{{ sponsor.name }}</p>
|
||||
<dl :class="$style.cardDl">
|
||||
<dd style="margin-top: 0.75rem; margin-inline-start: 0px;">
|
||||
<span :class="$style[`tagSponsor${capitalizeFirstLetter(sponsor.tier)}`]">{{ capitalizeFirstLetter(sponsor.tier) }}</span>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div>
|
||||
<div :class="$style.linksWrapper">
|
||||
<div :class="$style.link">
|
||||
<a :href="sponsor.website" :class="$style.rightLink" target="_blank">
|
||||
<div :class="$style.linkIcon">
|
||||
<svg data-slot="icon" fill="none" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m20.893 13.393-1.135-1.135a2.252 2.252 0 0 1-.421-.585l-1.08-2.16a.414.414 0 0 0-.663-.107.827.827 0 0 1-.812.21l-1.273-.363a.89.89 0 0 0-.738 1.595l.587.39c.59.395.674 1.23.172 1.732l-.2.2c-.212.212-.33.498-.33.796v.41c0 .409-.11.809-.32 1.158l-1.315 2.191a2.11 2.11 0 0 1-1.81 1.025 1.055 1.055 0 0 1-1.055-1.055v-1.172c0-.92-.56-1.747-1.414-2.089l-.655-.261a2.25 2.25 0 0 1-1.383-2.46l.007-.042a2.25 2.25 0 0 1 .29-.787l.09-.15a2.25 2.25 0 0 1 2.37-1.048l1.178.236a1.125 1.125 0 0 0 1.302-.795l.208-.73a1.125 1.125 0 0 0-.578-1.315l-.665-.332-.091.091a2.25 2.25 0 0 1-1.591.659h-.18c-.249 0-.487.1-.662.274a.931.931 0 0 1-1.458-1.137l1.411-2.353a2.25 2.25 0 0 0 .286-.76m11.928 9.869A9 9 0 0 0 8.965 3.525m11.928 9.868A9 9 0 1 1 8.965 3.525"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div v-if="sponsor.twitter" :class="$style.link" style="margin-left: -1px;">
|
||||
<a :href="sponsor.twitter" :class="$style.leftLink" target="_blank">
|
||||
<div :class="$style.linkIcon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" fill="currentColor" image-rendering="optimizeQuality" fill-rule="evenodd" clip-rule="evenodd" viewBox="0 0 512 462.799"><path fill-rule="nonzero" d="M403.229 0h78.506L310.219 196.04 512 462.799H354.002L230.261 301.007 88.669 462.799h-78.56l183.455-209.683L0 0h161.999l111.856 147.88L403.229 0zm-27.556 415.805h43.505L138.363 44.527h-46.68l283.99 371.278z"/></svg>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style module>
|
||||
.container {
|
||||
display: flex;
|
||||
margin: 0 auto;
|
||||
max-width: 1200px;
|
||||
}
|
||||
|
||||
.cardWrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
grid-column: span 1 / span 1;
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid var(--vp-c-gutter) !important;
|
||||
text-align: center;
|
||||
background-color: var(--card-background-color) !important;
|
||||
width: 100%;
|
||||
max-width: 11.5rem;
|
||||
scroll-snap-align: center;
|
||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
||||
flex-shrink: 0 !important;
|
||||
margin-bottom: 0.5rem !important;
|
||||
margin-top: 0.5rem !important;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.imgWrapper {
|
||||
display: flex;
|
||||
padding: 1.75rem;
|
||||
padding-bottom: 0.75rem;
|
||||
flex-direction: column;
|
||||
flex: 1 1 0%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.img {
|
||||
width: 8rem;
|
||||
height: 8rem;
|
||||
}
|
||||
|
||||
.heading {
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
height: 3rem;
|
||||
margin-top: 1rem !important;
|
||||
font-size: 1rem !important;
|
||||
line-height: 1.5rem !important;
|
||||
font-weight: 600 !important;
|
||||
color: var(--vp-c-text-1) !important;
|
||||
text-wrap-style: pretty;
|
||||
display: -webkit-box;
|
||||
}
|
||||
|
||||
.cardDl {
|
||||
display: flex;
|
||||
margin-top: 0.25rem;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.tagSponsorPlatinum {
|
||||
display: inline-flex;
|
||||
padding-top: 0.25rem;
|
||||
padding-bottom: 0.25rem;
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
align-items: center;
|
||||
border-radius: 9999px;
|
||||
box-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||
--tw-ring-inset: inset;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1rem;
|
||||
font-weight: 500;
|
||||
color: #000;
|
||||
background-color: #E5E7EB;
|
||||
}
|
||||
|
||||
.tagSponsorGold {
|
||||
display: inline-flex;
|
||||
padding-top: 0.25rem;
|
||||
padding-bottom: 0.25rem;
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
align-items: center;
|
||||
border-radius: 9999px;
|
||||
box-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||
--tw-ring-inset: inset;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1rem;
|
||||
font-weight: 500;
|
||||
color: #FFF;
|
||||
background-color: #F59E0B;
|
||||
}
|
||||
|
||||
.tagSponsorSilver {
|
||||
display: inline-flex;
|
||||
padding-top: 0.25rem;
|
||||
padding-bottom: 0.25rem;
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
align-items: center;
|
||||
border-radius: 9999px;
|
||||
box-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||
--tw-ring-inset: inset;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1rem;
|
||||
font-weight: 500;
|
||||
color: #FFF;
|
||||
background-color: #9CA3AF;
|
||||
}
|
||||
.tagSponsorBronze {
|
||||
display: inline-flex;
|
||||
padding-top: 0.25rem;
|
||||
padding-bottom: 0.25rem;
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
align-items: center;
|
||||
border-radius: 9999px;
|
||||
box-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||
--tw-ring-inset: inset;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1rem;
|
||||
font-weight: 500;
|
||||
color: #FFF;
|
||||
background-color: #854D0E;
|
||||
}
|
||||
|
||||
.tagSponsorBacker {
|
||||
display: inline-flex;
|
||||
padding-top: 0.25rem;
|
||||
padding-bottom: 0.25rem;
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
align-items: center;
|
||||
border-radius: 9999px;
|
||||
box-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||
--tw-ring-inset: inset;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1rem;
|
||||
font-weight: 500;
|
||||
color: #FFF;
|
||||
background-color: #2563EB;
|
||||
}
|
||||
|
||||
.linksWrapper {
|
||||
display: flex;
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.link {
|
||||
display: flex;
|
||||
flex: 1 1 0%;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.rightLink {
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
margin-right: -1px;
|
||||
flex: 1 1 0%;
|
||||
column-gap: 0.75rem;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-bottom-left-radius: 0.5rem;
|
||||
border-top: 1px;
|
||||
border-right: 1px;
|
||||
border-left: 0px;
|
||||
border-bottom: 0px;
|
||||
border-style: solid;
|
||||
border-color: var(--vp-c-gutter);
|
||||
width: 0;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.leftLink {
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
flex: 1 1 0%;
|
||||
column-gap: 0.75rem;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-bottom-right-radius: 0.5rem;
|
||||
border-top: 1px;
|
||||
border-left: 0px;
|
||||
border-bottom: 0px;
|
||||
border-right: 0px;
|
||||
border-style: solid;
|
||||
border-color: var(--vp-c-gutter);
|
||||
width: 0;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.linkIcon {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
color: #9CA3AF;
|
||||
}
|
||||
</style>
|
||||
3326
docs/package-lock.json
generated
Normal file
30
docs/package.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "axios",
|
||||
"version": "1.0.0",
|
||||
"description": "Documentation for the Axios HTTP client",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docs:dev": "vitepress dev",
|
||||
"docs:build": "vitepress build",
|
||||
"docs:preview": "vitepress preview",
|
||||
"docs:update:sponsors": "node ./scripts/process-sponsors.js",
|
||||
"prod:build": "npm run docs:update:sponsors && npm run docs:build",
|
||||
"postinstall": "patch-package --exclude nothing"
|
||||
},
|
||||
"dependencies": {
|
||||
"@splidejs/splide": "^4.1.4",
|
||||
"axios": "^1.14.0",
|
||||
"vitepress": "^1.6.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chalk": "^5.3.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"patch-package": "^8.0.1",
|
||||
"vue": "^3.5.32"
|
||||
},
|
||||
"overrides": {
|
||||
"esbuild": "^0.25.0"
|
||||
}
|
||||
}
|
||||
88
docs/pages/advanced/adapters.md
Normal file
@ -0,0 +1,88 @@
|
||||
# Adapters
|
||||
|
||||
Adapters allow you to customize the way axios handles the request data. By default, axios uses an ordered priority list of `['xhr', 'http', 'fetch']` and selects the first adapter that is supported by the current environment. In practice this means `xhr` is used in browsers, `http` in Node.js, and `fetch` in environments where neither is available (such as Cloudflare Workers or Deno).
|
||||
|
||||
Writing your own adapter lets you fully control how axios makes a request and processes the response — useful for testing, custom transports, or non-standard environments.
|
||||
|
||||
## Built-in adapters
|
||||
|
||||
You can select a built-in adapter by name using the `adapter` config option:
|
||||
|
||||
```js
|
||||
// Use the fetch adapter
|
||||
const instance = axios.create({ adapter: "fetch" });
|
||||
|
||||
// Use the XHR adapter (browser default)
|
||||
const instance = axios.create({ adapter: "xhr" });
|
||||
|
||||
// Use the HTTP adapter (Node.js default)
|
||||
const instance = axios.create({ adapter: "http" });
|
||||
```
|
||||
|
||||
You can also pass an array of adapter names. axios will use the first one supported by the current environment:
|
||||
|
||||
```js
|
||||
const instance = axios.create({ adapter: ["fetch", "xhr", "http"] });
|
||||
```
|
||||
|
||||
For more details on the `fetch` adapter, see the [Fetch adapter](/pages/advanced/fetch-adapter) page.
|
||||
|
||||
## Creating a custom adapter
|
||||
|
||||
To create a custom adapter, write a function that accepts a `config` object and returns a Promise that resolves to a valid axios response object.
|
||||
|
||||
```js
|
||||
import axios from "axios";
|
||||
import { settle } from "axios/unsafe/core/settle.js";
|
||||
|
||||
function myAdapter(config) {
|
||||
/**
|
||||
* At this point:
|
||||
* - config has been merged with defaults
|
||||
* - request transformers have run
|
||||
* - request interceptors have run
|
||||
*
|
||||
* The adapter is now responsible for making the request
|
||||
* and returning a valid response object.
|
||||
*/
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// Perform your custom request logic here.
|
||||
// This example uses the native fetch API as a starting point.
|
||||
fetch(config.url, {
|
||||
method: config.method?.toUpperCase() ?? "GET",
|
||||
headers: config.headers?.toJSON() ?? {},
|
||||
body: config.data,
|
||||
signal: config.signal,
|
||||
})
|
||||
.then(async (fetchResponse) => {
|
||||
const responseData = await fetchResponse.text();
|
||||
|
||||
const response = {
|
||||
data: responseData,
|
||||
status: fetchResponse.status,
|
||||
statusText: fetchResponse.statusText,
|
||||
headers: Object.fromEntries(fetchResponse.headers.entries()),
|
||||
config,
|
||||
request: null,
|
||||
};
|
||||
|
||||
// settle resolves or rejects the promise based on the HTTP status
|
||||
settle(resolve, reject, response);
|
||||
|
||||
/**
|
||||
* After this point:
|
||||
* - response transformers will run
|
||||
* - response interceptors will run
|
||||
*/
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
const instance = axios.create({ adapter: myAdapter });
|
||||
```
|
||||
|
||||
::: tip
|
||||
The `settle` helper resolves the promise for 2xx status codes and rejects it for everything else, matching axios's default behaviour. If you want custom status validation, use the `validateStatus` config option instead.
|
||||
:::
|
||||
331
docs/pages/advanced/api-reference.md
Normal file
@ -0,0 +1,331 @@
|
||||
# API reference
|
||||
|
||||
Below is a list of all the available functions and classes in the axios package. These functions may be used and imported in your project. All of these functions and classes are protected by our renewed promise to follow semantic versioning. This means that you can rely on these functions and classes to remain stable and unchanged in future releases unless a major version change is made.
|
||||
|
||||
## Instance
|
||||
|
||||
The `axios` instance is the main object that you will use to make HTTP requests. It is a factory function that creates a new instance of the `Axios` class. The `axios` instance has a number of methods that you can use to make HTTP requests. These methods are documented in the [Request aliases section](/pages/advanced/request-method-aliases) of the documentation.
|
||||
|
||||
## Classes
|
||||
|
||||
### `Axios`
|
||||
|
||||
The `Axios` class is the main class that you will use to make HTTP requests. It is a factory function that creates a new instance of the `Axios` class. The `Axios` class has a number of methods that you can use to make HTTP requests. These methods are documented in the [Request aliases section](/pages/advanced/request-method-aliases) of the documentation.
|
||||
|
||||
#### `constructor`
|
||||
|
||||
Creates a new instance of the `Axios` class. The constructor takes an optional configuration object as an argument.
|
||||
|
||||
```ts
|
||||
constructor(instanceConfig?: AxiosRequestConfig);
|
||||
```
|
||||
|
||||
#### `request`
|
||||
|
||||
Handles request invocation and response resolution. This is the main method that you will use to make HTTP requests. It takes a configuration object as an argument and returns a promise that resolves to the response object.
|
||||
|
||||
```ts
|
||||
request(configOrUrl: string | AxiosRequestConfig<D>, config: AxiosRequestConfig<D>): Promise<AxiosResponse<T>>;
|
||||
```
|
||||
|
||||
### `CancelToken` <Badge type="danger" text="Deprecated in favour of AbortController" />
|
||||
|
||||
The `CancelToken` class was based on the `tc39/proposal-cancelable-promises` proposal. It was used to create a token that could be used to cancel an HTTP request. The `CancelToken` class is now deprecated in favour of the `AbortController` API.
|
||||
|
||||
As of version 0.22.0, the `CancelToken` class is deprecated and will be removed in a future release. It is recommended that you use the `AbortController` API instead.
|
||||
|
||||
The class is exported mainly for backwards compatibility and will be removed in a future release. We also strongly discourage its use in new projects, we therefore are not documenting the API as use is discouraged.
|
||||
|
||||
## Functions
|
||||
|
||||
### `AxiosError`
|
||||
|
||||
The `AxiosError` class is an error class that is thrown when an HTTP request fails. It extends the `Error` class and adds additional properties to the error object.
|
||||
|
||||
#### `constructor`
|
||||
|
||||
Creates a new instance of the `AxiosError` class. The constructor takes an optional message, code, config, request, and response as arguments.
|
||||
|
||||
```ts
|
||||
constructor(message?: string, code?: string, config?: InternalAxiosRequestConfig<D>, request?: any, response?: AxiosResponse<T, D>);
|
||||
```
|
||||
|
||||
#### `properties`
|
||||
|
||||
The `AxiosError` class provides the following properties:
|
||||
|
||||
```ts
|
||||
// Config instance.
|
||||
config?: InternalAxiosRequestConfig<D>;
|
||||
|
||||
// Error code.
|
||||
code?: string;
|
||||
|
||||
// Request instance.
|
||||
request?: any;
|
||||
|
||||
// Response instance.
|
||||
response?: AxiosResponse<T, D>;
|
||||
|
||||
// Boolean indicating if the error is an `AxiosError`.
|
||||
isAxiosError: boolean;
|
||||
|
||||
// Error status code.
|
||||
status?: number;
|
||||
|
||||
// Helper method to convert the error to a JSON object.
|
||||
toJSON: () => object;
|
||||
|
||||
// Error cause.
|
||||
cause?: Error;
|
||||
```
|
||||
|
||||
### `AxiosHeaders`
|
||||
|
||||
The `AxiosHeaders` class is a utility class that is used to manage HTTP headers. It provides methods for manipulating headers, such as adding, removing, and getting headers.
|
||||
|
||||
Only the main methods are documented here. For a full list of methods, please refer to the type declaration file.
|
||||
|
||||
#### `constructor`
|
||||
|
||||
Creates a new instance of the `AxiosHeaders` class. The constructor takes an optional headers object as an argument.
|
||||
|
||||
```ts
|
||||
constructor(headers?: RawAxiosHeaders | AxiosHeaders | string);
|
||||
```
|
||||
|
||||
#### `set`
|
||||
|
||||
Adds a header to the headers object.
|
||||
|
||||
```ts
|
||||
set(headerName?: string, value?: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
|
||||
set(headers?: RawAxiosHeaders | AxiosHeaders | string, rewrite?: boolean): AxiosHeaders;
|
||||
```
|
||||
|
||||
#### `get`
|
||||
|
||||
Gets a header from the headers object.
|
||||
|
||||
```ts
|
||||
get(headerName: string, parser: RegExp): RegExpExecArray | null;
|
||||
get(headerName: string, matcher?: true | AxiosHeaderParser): AxiosHeaderValue;
|
||||
```
|
||||
|
||||
#### `has`
|
||||
|
||||
Checks if a header exists in the headers object.
|
||||
|
||||
```ts
|
||||
has(header: string, matcher?: AxiosHeaderMatcher): boolean;
|
||||
```
|
||||
|
||||
#### `delete`
|
||||
|
||||
Removes a header from the headers object.
|
||||
|
||||
```ts
|
||||
delete(header: string | string[], matcher?: AxiosHeaderMatcher): boolean;
|
||||
```
|
||||
|
||||
#### `clear`
|
||||
|
||||
Removes all headers from the headers object.
|
||||
|
||||
```ts
|
||||
clear(matcher?: AxiosHeaderMatcher): boolean;
|
||||
```
|
||||
|
||||
#### `normalize`
|
||||
|
||||
Normalizes the headers object.
|
||||
|
||||
```ts
|
||||
normalize(format: boolean): AxiosHeaders;
|
||||
```
|
||||
|
||||
#### `concat`
|
||||
|
||||
Concatenates headers objects.
|
||||
|
||||
```ts
|
||||
concat(...targets: Array<AxiosHeaders | RawAxiosHeaders | string | undefined | null>): AxiosHeaders;
|
||||
```
|
||||
|
||||
#### `toJSON`
|
||||
|
||||
Converts the headers object to a JSON object.
|
||||
|
||||
```ts
|
||||
toJSON(asStrings?: boolean): RawAxiosHeaders;
|
||||
```
|
||||
|
||||
### `CanceledError` <Badge type="tip" text="Extended AxiosError" />
|
||||
|
||||
The `CanceledError` class is an error class that is thrown when an HTTP request is canceled. It extends the `AxiosError` class.
|
||||
|
||||
### `Cancel` <Badge type="tip" text="Alias for CanceledError" />
|
||||
|
||||
The `Cancel` class is an alias for the `CanceledError` class. It is exported for backwards compatibility and will be removed in a future release.
|
||||
|
||||
### `isCancel`
|
||||
|
||||
A function that checks if an error is a `CanceledError`. Useful for distinguishing intentional cancellations from unexpected errors.
|
||||
|
||||
```ts
|
||||
isCancel(value: any): boolean;
|
||||
```
|
||||
|
||||
```js
|
||||
import axios from "axios";
|
||||
|
||||
const controller = new AbortController();
|
||||
|
||||
axios.get("/api/data", { signal: controller.signal }).catch((error) => {
|
||||
if (axios.isCancel(error)) {
|
||||
console.log("Request was cancelled:", error.message);
|
||||
} else {
|
||||
console.error("Unexpected error:", error);
|
||||
}
|
||||
});
|
||||
|
||||
controller.abort("User navigated away");
|
||||
```
|
||||
|
||||
### `isAxiosError`
|
||||
|
||||
A function that checks if an error is an `AxiosError`. Use this in `catch` blocks to safely access axios-specific error properties like `error.response` and `error.config`.
|
||||
|
||||
```ts
|
||||
isAxiosError(value: any): value is AxiosError;
|
||||
```
|
||||
|
||||
```js
|
||||
import axios from "axios";
|
||||
|
||||
try {
|
||||
await axios.get("/api/resource");
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
// error.response, error.config, error.code are all available
|
||||
console.error("HTTP error", error.response?.status, error.message);
|
||||
} else {
|
||||
// A non-axios error (e.g. a programming mistake)
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `all` <Badge type="danger" text="Deprecated in favour of Promise.all" />
|
||||
|
||||
The `all` function is a utility function that takes an array of promises and returns a single promise that resolves when all of the promises in the array have resolved. The `all` function is now deprecated in favour of the `Promise.all` method. It is recommended that you use the `Promise.all` method instead.
|
||||
|
||||
As of version 0.22.0, the `all` function is deprecated and will be removed in a future release. It is recommended that you use the `Promise.all` method instead.
|
||||
|
||||
### `spread`
|
||||
|
||||
The `spread` function is a utility function that can be used to spread an array of arguments into a function call. This is useful when you have an array of arguments that you want to pass to a function that takes multiple arguments.
|
||||
|
||||
```ts
|
||||
spread<T, R>(callback: (...args: T[]) => R): (array: T[]) => R;
|
||||
```
|
||||
|
||||
### `toFormData`
|
||||
|
||||
Converts a plain JavaScript object (or a nested one) to a `FormData` instance. Useful when you want to programmatically build multipart form data from an object.
|
||||
|
||||
```ts
|
||||
toFormData(sourceObj: object, formData?: FormData, options?: FormSerializerOptions): FormData;
|
||||
```
|
||||
|
||||
```js
|
||||
import { toFormData } from "axios";
|
||||
|
||||
const data = { name: "Jay", avatar: fileBlob };
|
||||
const form = toFormData(data);
|
||||
// form is now a FormData instance ready to post
|
||||
await axios.post("/api/users", form);
|
||||
```
|
||||
|
||||
### `formToJSON`
|
||||
|
||||
Converts a `FormData` instance back to a plain JavaScript object. Useful for reading form data in a structured format.
|
||||
|
||||
```ts
|
||||
formToJSON(form: FormData): object;
|
||||
```
|
||||
|
||||
```js
|
||||
import { formToJSON } from "axios";
|
||||
|
||||
const form = new FormData();
|
||||
form.append("name", "Jay");
|
||||
form.append("role", "admin");
|
||||
|
||||
const obj = formToJSON(form);
|
||||
console.log(obj); // { name: "Jay", role: "admin" }
|
||||
```
|
||||
|
||||
### `getAdapter`
|
||||
|
||||
Resolves and returns an adapter function by name or by passing an array of candidate names. axios uses this internally to select the best available adapter for the current environment.
|
||||
|
||||
```ts
|
||||
getAdapter(adapters: string | string[]): AxiosAdapter;
|
||||
```
|
||||
|
||||
```js
|
||||
import { getAdapter } from "axios";
|
||||
|
||||
// Get the fetch adapter explicitly
|
||||
const fetchAdapter = getAdapter("fetch");
|
||||
|
||||
// Get the best available adapter from a priority list
|
||||
const adapter = getAdapter(["fetch", "xhr", "http"]);
|
||||
```
|
||||
|
||||
### `mergeConfig`
|
||||
|
||||
Merges two axios config objects together, applying the same deep-merge strategy that axios uses internally when combining defaults with per-request options. Later values take precedence.
|
||||
|
||||
```ts
|
||||
mergeConfig<T>(config1: AxiosRequestConfig<T>, config2: AxiosRequestConfig<T>): AxiosRequestConfig<T>;
|
||||
```
|
||||
|
||||
```js
|
||||
import { mergeConfig } from "axios";
|
||||
|
||||
const base = { baseURL: "https://api.example.com", timeout: 5000 };
|
||||
const override = { timeout: 10000, headers: { "X-Custom": "value" } };
|
||||
|
||||
const merged = mergeConfig(base, override);
|
||||
// { baseURL: "https://api.example.com", timeout: 10000, headers: { "X-Custom": "value" } }
|
||||
```
|
||||
|
||||
## Constants
|
||||
|
||||
### `HttpStatusCode`
|
||||
|
||||
An object that contains a list of HTTP status codes as named constants. Use this to write readable conditionals instead of bare numbers.
|
||||
|
||||
```js
|
||||
import axios, { HttpStatusCode } from "axios";
|
||||
|
||||
try {
|
||||
const response = await axios.get("/api/resource");
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
if (error.response?.status === HttpStatusCode.NotFound) {
|
||||
console.error("Resource not found");
|
||||
} else if (error.response?.status === HttpStatusCode.Unauthorized) {
|
||||
console.error("Authentication required");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Miscellaneous
|
||||
|
||||
### `VERSION`
|
||||
|
||||
The current version of the `axios` package. This is a string that represents the version number of the package. It is updated with each release of the package.
|
||||
142
docs/pages/advanced/authentication.md
Normal file
@ -0,0 +1,142 @@
|
||||
# Authentication
|
||||
|
||||
Most APIs require some form of authentication. This page covers the most common patterns for attaching credentials to axios requests.
|
||||
|
||||
## Bearer tokens (JWT)
|
||||
|
||||
The most common approach is to attach a JWT in the `Authorization` header. The cleanest way to do this is via a request interceptor on your axios instance, so the token is read fresh on every request:
|
||||
|
||||
```js
|
||||
import axios from "axios";
|
||||
|
||||
const api = axios.create({ baseURL: "https://api.example.com" });
|
||||
|
||||
api.interceptors.request.use((config) => {
|
||||
const token = localStorage.getItem("access_token");
|
||||
if (token) {
|
||||
config.headers.set("Authorization", `Bearer ${token}`);
|
||||
}
|
||||
return config;
|
||||
});
|
||||
```
|
||||
|
||||
## HTTP Basic auth
|
||||
|
||||
For APIs that use HTTP Basic authentication, pass the `auth` option. axios will encode the credentials and set the `Authorization` header automatically:
|
||||
|
||||
```js
|
||||
const response = await axios.get("https://api.example.com/data", {
|
||||
auth: {
|
||||
username: "myUser",
|
||||
password: "myPassword",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
::: tip
|
||||
For Bearer tokens and API keys, use a custom `Authorization` header rather than the `auth` option — `auth` is only for HTTP Basic.
|
||||
:::
|
||||
|
||||
## API keys
|
||||
|
||||
API keys are typically passed as a header or a query parameter, depending on what the API expects:
|
||||
|
||||
```js
|
||||
// As a header
|
||||
const api = axios.create({
|
||||
baseURL: "https://api.example.com",
|
||||
headers: { "X-API-Key": "your-api-key-here" },
|
||||
});
|
||||
|
||||
// As a query parameter
|
||||
const response = await axios.get("https://api.example.com/data", {
|
||||
params: { apiKey: "your-api-key-here" },
|
||||
});
|
||||
```
|
||||
|
||||
## Token refresh
|
||||
|
||||
When access tokens expire, you need to silently refresh them and retry the failed request. A response interceptor is the right place to implement this:
|
||||
|
||||
```js
|
||||
import axios from "axios";
|
||||
|
||||
const api = axios.create({ baseURL: "https://api.example.com" });
|
||||
|
||||
// Track whether a refresh is already in progress to avoid parallel refresh calls
|
||||
let isRefreshing = false;
|
||||
let failedQueue = [];
|
||||
|
||||
const processQueue = (error, token = null) => {
|
||||
failedQueue.forEach((prom) => {
|
||||
if (error) {
|
||||
prom.reject(error);
|
||||
} else {
|
||||
prom.resolve(token);
|
||||
}
|
||||
});
|
||||
failedQueue = [];
|
||||
};
|
||||
|
||||
api.interceptors.response.use(
|
||||
(response) => response,
|
||||
async (error) => {
|
||||
const originalRequest = error.config;
|
||||
|
||||
if (error.response?.status === 401 && !originalRequest._retry) {
|
||||
if (isRefreshing) {
|
||||
// Queue the request until the refresh completes
|
||||
return new Promise((resolve, reject) => {
|
||||
failedQueue.push({ resolve, reject });
|
||||
})
|
||||
.then((token) => {
|
||||
originalRequest.headers["Authorization"] = `Bearer ${token}`;
|
||||
return api(originalRequest);
|
||||
})
|
||||
.catch((err) => Promise.reject(err));
|
||||
}
|
||||
|
||||
originalRequest._retry = true;
|
||||
isRefreshing = true;
|
||||
|
||||
try {
|
||||
const { data } = await axios.post("/auth/refresh", {
|
||||
refreshToken: localStorage.getItem("refresh_token"),
|
||||
});
|
||||
|
||||
const newToken = data.access_token;
|
||||
localStorage.setItem("access_token", newToken);
|
||||
api.defaults.headers.common["Authorization"] = `Bearer ${newToken}`;
|
||||
|
||||
processQueue(null, newToken);
|
||||
return api(originalRequest);
|
||||
} catch (refreshError) {
|
||||
processQueue(refreshError, null);
|
||||
// Redirect to login or emit an event
|
||||
localStorage.removeItem("access_token");
|
||||
window.location.href = "/login";
|
||||
return Promise.reject(refreshError);
|
||||
} finally {
|
||||
isRefreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## Cookie-based authentication
|
||||
|
||||
For session-based APIs that rely on cookies, set `withCredentials: true` to include cookies in cross-origin requests:
|
||||
|
||||
```js
|
||||
const api = axios.create({
|
||||
baseURL: "https://api.example.com",
|
||||
withCredentials: true, // send cookies with every request
|
||||
});
|
||||
```
|
||||
|
||||
::: warning
|
||||
`withCredentials: true` requires the server to respond with `Access-Control-Allow-Credentials: true` and a specific (non-wildcard) `Access-Control-Allow-Origin`.
|
||||
:::
|
||||
70
docs/pages/advanced/cancellation.md
Normal file
@ -0,0 +1,70 @@
|
||||
# Cancellation
|
||||
|
||||
Starting from v0.22.0 Axios supports AbortController to cancel requests in a clean way. This feature is available in the browser and in Node.js when using a version of Axios that supports AbortController. To cancel a request, you need to create an instance of `AbortController` and pass its `signal` to the request's `signal` option.
|
||||
|
||||
```js
|
||||
const controller = new AbortController();
|
||||
|
||||
axios
|
||||
.get("/foo/bar", {
|
||||
signal: controller.signal,
|
||||
})
|
||||
.then(function (response) {
|
||||
//...
|
||||
});
|
||||
// cancel the request
|
||||
controller.abort();
|
||||
```
|
||||
|
||||
## CancelToken <Badge type="danger" text="Deprecated" />
|
||||
|
||||
You can also use the `CancelToken` API to cancel requests. This API is deprecated and will be removed in the next major release. It is recommended to use `AbortController` instead. You can create a cancel token using the `CancelToken.source` factory as shown below:
|
||||
|
||||
```js
|
||||
const CancelToken = axios.CancelToken;
|
||||
const source = CancelToken.source();
|
||||
|
||||
axios
|
||||
.get("/user/12345", {
|
||||
cancelToken: source.token,
|
||||
})
|
||||
.catch(function (thrown) {
|
||||
if (axios.isCancel(thrown)) {
|
||||
console.log("Request canceled", thrown.message);
|
||||
} else {
|
||||
// handle error
|
||||
}
|
||||
});
|
||||
|
||||
axios.post(
|
||||
"/user/12345",
|
||||
{
|
||||
name: "new name",
|
||||
},
|
||||
{
|
||||
cancelToken: source.token,
|
||||
}
|
||||
);
|
||||
|
||||
// cancel the request (the message parameter is optional)
|
||||
source.cancel("Operation canceled by the user.");
|
||||
```
|
||||
|
||||
You can also create a cancel token by passing an executor function to the `CancelToken` constructor:
|
||||
|
||||
```js
|
||||
const CancelToken = axios.CancelToken;
|
||||
let cancel;
|
||||
|
||||
axios.get("/user/12345", {
|
||||
cancelToken: new CancelToken(function executor(c) {
|
||||
// An executor function receives a cancel function as a parameter
|
||||
cancel = c;
|
||||
}),
|
||||
});
|
||||
|
||||
// cancel the request
|
||||
cancel();
|
||||
```
|
||||
|
||||
You can cancel several requests with the same cancel token/abort controller. If a cancellation token is already cancelled at the moment of starting an Axios request, then the request is cancelled immediately, without any attempts to make a real request.
|
||||
48
docs/pages/advanced/config-defaults.md
Normal file
@ -0,0 +1,48 @@
|
||||
# Config defaults
|
||||
|
||||
axios allows you to specify config defaults that will be applied to ever request. You can specify defaults for the `baseURL`, `headers`, `timeout`, and other properties. An example of using config defaults is shown below:
|
||||
|
||||
```js
|
||||
axios.defaults.baseURL = "https://jsonplaceholder.typicode.com/posts";
|
||||
axios.defaults.headers.common["Authorization"] = AUTH_TOKEN;
|
||||
axios.defaults.headers.post["Content-Type"] =
|
||||
"application/x-www-form-urlencoded";
|
||||
```
|
||||
|
||||
## Custom instance defaults
|
||||
|
||||
axios instances are declared with their own defaults when created. These defaults may be overridden setting the `defaults` property to the instance. An example of using custom instance defaults is shown below:
|
||||
|
||||
```js
|
||||
var instance = axios.create({
|
||||
baseURL: "https://jsonplaceholder.typicode.com/posts",
|
||||
timeout: 1000,
|
||||
headers: { Authorization: "foobar" },
|
||||
});
|
||||
|
||||
instance.defaults.headers.common["Authorization"] = AUTH_TOKEN;
|
||||
```
|
||||
|
||||
## Config order of precedence
|
||||
|
||||
Config will be merged with an order of precedence. The order is as follows, first the library defaults are set, then default properties of the instance, and finally config argument for the request. An example of the order of precedence is shown below:
|
||||
|
||||
First lets create an instance with the defaults provided by the library. At this point the timeout config value is `0` as is the default for the library.
|
||||
|
||||
```js
|
||||
const instance = axios.create();
|
||||
```
|
||||
|
||||
Now we will override the timeout default for the instance to `2500` milliseconds. Now all requests using this instance will wait 2.5 seconds before timing out.
|
||||
|
||||
```js
|
||||
instance.defaults.timeout = 2500;
|
||||
```
|
||||
|
||||
Finally we will make a request with a timeout of `5000` milliseconds. This request will wait 5 seconds before timing out.
|
||||
|
||||
```js
|
||||
instance.get("/longRequest", {
|
||||
timeout: 5000,
|
||||
});
|
||||
```
|
||||
87
docs/pages/advanced/create-an-instance.md
Normal file
@ -0,0 +1,87 @@
|
||||
# Creating an instance
|
||||
|
||||
`axios.create()` lets you create a pre-configured axios instance. The instance shares the same request and response API as the default `axios` object, but uses the config you provide as its baseline for every request. This is the recommended way to use axios in any application larger than a single file.
|
||||
|
||||
```ts
|
||||
import axios from "axios";
|
||||
|
||||
const instance = axios.create({
|
||||
baseURL: "https://api.example.com",
|
||||
timeout: 5000,
|
||||
headers: { "X-Custom-Header": "foobar" },
|
||||
});
|
||||
```
|
||||
|
||||
The `create` method accepts the full [Request Config](/pages/advanced/request-config) object. You can then use the instance just like the default axios object:
|
||||
|
||||
```js
|
||||
const response = await instance.get("/users/1");
|
||||
```
|
||||
|
||||
## Why use an instance?
|
||||
|
||||
### Per-service base URL
|
||||
|
||||
In most apps you talk to more than one API. Creating a separate instance per service avoids repeating the base URL on every call:
|
||||
|
||||
```js
|
||||
const githubApi = axios.create({ baseURL: "https://api.github.com" });
|
||||
const internalApi = axios.create({ baseURL: "https://api.internal.example.com" });
|
||||
|
||||
const { data: repos } = await githubApi.get("/users/axios/repos");
|
||||
const { data: users } = await internalApi.get("/users");
|
||||
```
|
||||
|
||||
### Shared authentication headers
|
||||
|
||||
Attach an auth token to every request from one instance without touching others:
|
||||
|
||||
```js
|
||||
const authApi = axios.create({
|
||||
baseURL: "https://api.example.com",
|
||||
headers: {
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Per-service timeouts and retries
|
||||
|
||||
Different services have different reliability characteristics. Set a tight timeout for real-time services and a relaxed one for batch jobs:
|
||||
|
||||
```js
|
||||
const realtimeApi = axios.create({ baseURL: "https://realtime.example.com", timeout: 2000 });
|
||||
const batchApi = axios.create({ baseURL: "https://batch.example.com", timeout: 60000 });
|
||||
```
|
||||
|
||||
### Isolated interceptors
|
||||
|
||||
Interceptors added to an instance only apply to that instance, keeping your concerns separate:
|
||||
|
||||
```js
|
||||
const loggingApi = axios.create({ baseURL: "https://api.example.com" });
|
||||
|
||||
loggingApi.interceptors.request.use((config) => {
|
||||
console.log(`→ ${config.method?.toUpperCase()} ${config.url}`);
|
||||
return config;
|
||||
});
|
||||
```
|
||||
|
||||
## Overriding defaults per request
|
||||
|
||||
Config passed at request time always overrides the instance defaults:
|
||||
|
||||
```js
|
||||
const api = axios.create({ timeout: 5000 });
|
||||
|
||||
// This specific request uses a 30-second timeout instead
|
||||
await api.get("/slow-endpoint", { timeout: 30000 });
|
||||
```
|
||||
|
||||
::: tip
|
||||
Instance defaults can also be changed after creation by writing to `instance.defaults`:
|
||||
|
||||
```js
|
||||
instance.defaults.headers.common["Authorization"] = `Bearer ${newToken}`;
|
||||
```
|
||||
:::
|
||||
72
docs/pages/advanced/error-handling.md
Normal file
@ -0,0 +1,72 @@
|
||||
# Error handling
|
||||
|
||||
axios may throw many different types of errors. Some of these errors are caused by axios itself, while others are caused by the server or the client. The following table lists the general structure of the thrown error:
|
||||
|
||||
| Property | Definition |
|
||||
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| message | A quick summary of the error message and the status it failed with. |
|
||||
| name | This defines where the error originated from. For axios, it will always be an `AxiosError`. |
|
||||
| stack | Provides the stack trace of the error. |
|
||||
| config | An axios config object with specific instance configurations defined by the user from when the request was made. |
|
||||
| code | Represents an axios identified error. The table below lists out specific definitions for internal axios error. |
|
||||
| status | HTTP response status code. See [here](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) for common HTTP response status code meanings. |
|
||||
|
||||
Below is a list of potential axios identified error
|
||||
|
||||
| Code | Definition |
|
||||
| ------------------------- | --------------------------------------------------------------------------------------------- |
|
||||
| ERR_BAD_OPTION_VALUE | Invalid or unsupported value provided in axios configuration. |
|
||||
| ERR_BAD_OPTION | Invalid option provided in axios configuration. |
|
||||
| ECONNABORTED | Typically indicates that the request has been timed out (unless `transitional.clarifyTimeoutError` is set) or aborted by the browser or its plugin. |
|
||||
| ETIMEDOUT | Request timed out due to exceeding the default axios timelimit. `transitional.clarifyTimeoutError` must be set to `true`, otherwise a generic `ECONNABORTED` error will be thrown instead |
|
||||
| ERR_NETWORK | Network-related issue. In the browser, this error can also be caused by a [CORS](https://developer.mozilla.org/ru/docs/Web/HTTP/Guides/CORS) or [Mixed Content](https://developer.mozilla.org/en-US/docs/Web/Security/Mixed_content) policy violation. The browser does not allow the JS code to clarify the real reason for the error caused by security issues, so please check the console. |
|
||||
| ERR_FR_TOO_MANY_REDIRECTS | Request is redirected too many times; exceeds max redirects specified in axios configuration. |
|
||||
| ERR_DEPRECATED | Deprecated feature or method used in axios. |
|
||||
| ERR_BAD_RESPONSE | Response cannot be parsed properly or is in an unexpected format. Usually related to a response with `5xx` status code. |
|
||||
| ERR_BAD_REQUEST | The request has an unexpected format or is missing required parameters. Usually related to a response with `4xx` status code. |
|
||||
| ERR_CANCELED | Feature or method is canceled explicitly by the user using an AbortSignal (or a CancelToken). |
|
||||
| ERR_NOT_SUPPORT | Feature or method not supported in the current axios environment. |
|
||||
| ERR_INVALID_URL | Invalid URL provided for axios request. |
|
||||
|
||||
## Handling errors
|
||||
|
||||
The default behaviour of axios is to reject the promise if the request fails. However, you can also catch the error and handle it as you see fit. Below is an example of how to catch an error:
|
||||
|
||||
```js
|
||||
axios.get("/user/12345").catch(function (error) {
|
||||
if (error.response) {
|
||||
// The request was made and the server responded with a status code
|
||||
// that falls out of the range of 2xx
|
||||
console.log(error.response.data);
|
||||
console.log(error.response.status);
|
||||
console.log(error.response.headers);
|
||||
} else if (error.request) {
|
||||
// The request was made but no response was received
|
||||
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
|
||||
// http.ClientRequest in node.js
|
||||
console.log(error.request);
|
||||
} else {
|
||||
// Something happened in setting up the request that triggered an Error
|
||||
console.log("Error", error.message);
|
||||
}
|
||||
console.log(error.config);
|
||||
});
|
||||
```
|
||||
|
||||
Using the `validateStatus` config option, you can override the default condition (status >= 200 && status < 300) and define HTTP code(s) that should throw an error.
|
||||
|
||||
```js
|
||||
axios.get("/user/12345", {
|
||||
validateStatus: function (status) {
|
||||
return status < 500; // Resolve only if the status code is less than 500
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Using the `toJSON` method, you can get a object with more information about the error.
|
||||
|
||||
```js
|
||||
axios.get("/user/12345").catch(function (error) {
|
||||
console.log(error.toJSON());
|
||||
});
|
||||
```
|
||||
81
docs/pages/advanced/fetch-adapter.md
Normal file
@ -0,0 +1,81 @@
|
||||
# Fetch adapter <Badge type="tip" text="New" />
|
||||
|
||||
The `fetch` adapter is a new adapter that we have introduced as of version 1.7.0. This provides a way to use axios with the `fetch` API thus giving you the best of both worlds. By default, `fetch` will be used if `xhr` and `http` adapters are not available in the build, or not supported by the environment. To use it by default, it must be selected explicitly by setting the `adapter` option to `fetch` when creating an instance of axios.
|
||||
|
||||
```js
|
||||
import axios from 'axios';
|
||||
|
||||
const instance = axios.create({
|
||||
adapter: 'fetch',
|
||||
});
|
||||
```
|
||||
|
||||
The adapter supports the same functionality as the `xhr` adapter, including upload and download progress capturing. It also supports additional response types such as `stream` and `formdata` (if supported by the environment).
|
||||
|
||||
## Custom fetch <Badge type="tip" text="v1.12.0+" />
|
||||
|
||||
Starting from `v1.12.0`, you can customise the fetch adapter to use a custom `fetch` function instead of the environment global. You can pass a custom `fetch` function, `Request`, and `Response` constructors via the `env` config option. This is useful when working with custom environments or app frameworks that provide their own `fetch` implementation.
|
||||
|
||||
::: info
|
||||
When using a custom `fetch` function, you may also need to supply matching `Request` and `Response` constructors. If you omit them, the global constructors will be used. If your custom `fetch` is incompatible with the globals, pass `null` to disable them.
|
||||
|
||||
**Note:** Setting `Request` and `Response` to `null` will make it impossible for the fetch adapter to capture upload and download progress.
|
||||
:::
|
||||
|
||||
### Basic example
|
||||
|
||||
```js
|
||||
import customFetchFunction from 'customFetchModule';
|
||||
|
||||
const instance = axios.create({
|
||||
adapter: 'fetch',
|
||||
onDownloadProgress(e) {
|
||||
console.log('downloadProgress', e);
|
||||
},
|
||||
env: {
|
||||
fetch: customFetchFunction,
|
||||
Request: null, // null -> disable the constructor
|
||||
Response: null,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Using with Tauri
|
||||
|
||||
[Tauri](https://tauri.app/plugin/http-client/) provides a platform `fetch` function that bypasses browser CORS restrictions for requests made from the native layer. The example below shows a minimal setup for using axios inside a Tauri app with that custom fetch.
|
||||
|
||||
```js
|
||||
import { fetch } from '@tauri-apps/plugin-http';
|
||||
import axios from 'axios';
|
||||
|
||||
const instance = axios.create({
|
||||
adapter: 'fetch',
|
||||
onDownloadProgress(e) {
|
||||
console.log('downloadProgress', e);
|
||||
},
|
||||
env: {
|
||||
fetch,
|
||||
},
|
||||
});
|
||||
|
||||
const { data } = await instance.get('https://google.com');
|
||||
```
|
||||
|
||||
### Using with SvelteKit
|
||||
|
||||
[SvelteKit](https://svelte.dev/docs/kit/web-standards#Fetch-APIs) provides a custom `fetch` implementation for server-side `load` functions that handles cookie forwarding and relative URLs. Because its `fetch` is incompatible with the standard `URL` API, axios must be configured to use it explicitly, and the global `Request` and `Response` constructors must be disabled.
|
||||
|
||||
```js
|
||||
export async function load({ fetch }) {
|
||||
const { data: post } = await axios.get('https://jsonplaceholder.typicode.com/posts/1', {
|
||||
adapter: 'fetch',
|
||||
env: {
|
||||
fetch,
|
||||
Request: null,
|
||||
Response: null,
|
||||
},
|
||||
});
|
||||
|
||||
return { post };
|
||||
}
|
||||
```
|
||||
99
docs/pages/advanced/file-posting.md
Normal file
@ -0,0 +1,99 @@
|
||||
# File posting
|
||||
|
||||
axios makes file uploads straightforward. Use `postForm` or `FormData` when you need `multipart/form-data` uploads.
|
||||
|
||||
## Single file (browser)
|
||||
|
||||
Pass a `File` object directly as a field value — axios will detect it and use the correct content type automatically:
|
||||
|
||||
```js
|
||||
await axios.postForm("https://httpbin.org/post", {
|
||||
description: "My profile photo",
|
||||
file: document.querySelector("#fileInput").files[0],
|
||||
});
|
||||
```
|
||||
|
||||
## Multiple files (browser)
|
||||
|
||||
Pass a `FileList` to upload all selected files at once. They will all be sent under the same field name (`files[]`):
|
||||
|
||||
```js
|
||||
await axios.postForm(
|
||||
"https://httpbin.org/post",
|
||||
document.querySelector("#fileInput").files
|
||||
);
|
||||
```
|
||||
|
||||
To use distinct field names for each file, build a `FormData` object manually:
|
||||
|
||||
```js
|
||||
const formData = new FormData();
|
||||
formData.append("avatar", avatarFile);
|
||||
formData.append("cover", coverFile);
|
||||
|
||||
await axios.post("https://httpbin.org/post", formData);
|
||||
```
|
||||
|
||||
## Tracking upload progress (browser)
|
||||
|
||||
Use the `onUploadProgress` callback to show a progress bar or percentage to your users:
|
||||
|
||||
```js
|
||||
await axios.postForm("https://httpbin.org/post", {
|
||||
file: document.querySelector("#fileInput").files[0],
|
||||
}, {
|
||||
onUploadProgress: (progressEvent) => {
|
||||
const percent = Math.round(
|
||||
(progressEvent.loaded * 100) / progressEvent.total
|
||||
);
|
||||
console.log(`Upload progress: ${percent}%`);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
See [Progress capturing](/pages/advanced/progress-capturing) for the full list of fields available on the progress event.
|
||||
|
||||
## Files in Node.js
|
||||
|
||||
In Node.js, use `fs.createReadStream` to upload a file from the filesystem without loading it entirely into memory:
|
||||
|
||||
```js
|
||||
import fs from "fs";
|
||||
import FormData from "form-data";
|
||||
import axios from "axios";
|
||||
|
||||
const form = new FormData();
|
||||
form.append("file", fs.createReadStream("/path/to/file.jpg"));
|
||||
form.append("description", "My uploaded file");
|
||||
|
||||
await axios.post("https://httpbin.org/post", form);
|
||||
```
|
||||
|
||||
::: tip
|
||||
The `form-data` npm package is required in Node.js environments to create `FormData` objects. In modern Node.js (v18+), the global `FormData` is available natively.
|
||||
:::
|
||||
|
||||
## Uploading a Buffer (Node.js)
|
||||
|
||||
You can also upload an in-memory `Buffer` directly:
|
||||
|
||||
```js
|
||||
const buffer = Buffer.from("Hello, world!");
|
||||
|
||||
const form = new FormData();
|
||||
form.append("file", buffer, {
|
||||
filename: "hello.txt",
|
||||
contentType: "text/plain",
|
||||
knownLength: buffer.length,
|
||||
});
|
||||
|
||||
await axios.post("https://httpbin.org/post", form);
|
||||
```
|
||||
|
||||
::: warning
|
||||
Capturing `FormData` upload progress is not currently supported in Node.js environments.
|
||||
:::
|
||||
|
||||
::: danger
|
||||
When uploading a readable stream in Node.js, set `maxRedirects: 0` to prevent the `follow-redirects` package from buffering the entire stream in RAM.
|
||||
:::
|
||||
188
docs/pages/advanced/header-methods.md
Normal file
@ -0,0 +1,188 @@
|
||||
# Header methods <Badge type="tip" text="New" />
|
||||
|
||||
With the introduction of the new `AxiosHeaders` class, Axios provides a set of methods to manipulate headers. These methods are used to set, get, and delete headers in a more convenient way than directly manipulating the headers object.
|
||||
|
||||
## Constructor `new AxiosHeaders(headers?)`
|
||||
|
||||
The `AxiosHeaders` class constructor accepts an optional object with headers to initialize the instance. The headers object can contain any number of headers, and the keys are case-insensitive.
|
||||
|
||||
```js
|
||||
constructor(headers?: RawAxiosHeaders | AxiosHeaders | string);
|
||||
```
|
||||
|
||||
For convenience, you can pass a string with headers separated by a newline character. The headers are then parsed and added to the instance.
|
||||
|
||||
```js
|
||||
const headers = new AxiosHeaders(`
|
||||
Host: www.bing.com
|
||||
User-Agent: curl/7.54.0
|
||||
Accept: */*`);
|
||||
|
||||
console.log(headers);
|
||||
|
||||
// Object [AxiosHeaders] {
|
||||
// host: 'www.bing.com',
|
||||
// 'user-agent': 'curl/7.54.0',
|
||||
// accept: '*/*'
|
||||
// }
|
||||
```
|
||||
|
||||
## Set
|
||||
|
||||
The `set` method is used to set headers on the instance of `AxiosHeaders`. The method can be called with a single header name and value, an object with multiple headers, or a string with headers separated by a newline character. The method also accepts an optional `rewrite` parameter that controls the behaviour of setting the header.
|
||||
|
||||
```js
|
||||
set(headerName, value: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher);
|
||||
set(headerName, value, rewrite?: (this: AxiosHeaders, value: string, name: string) => boolean);
|
||||
set(headers?: RawAxiosHeaders | AxiosHeaders | string, rewrite?: boolean);
|
||||
```
|
||||
|
||||
The rewrite argument controls the overwriting behaviour:
|
||||
|
||||
- `false` - do not overwrite if header's value is set (is not undefined)
|
||||
- `undefined` (default) - overwrite the header unless its value is set to false
|
||||
- `true` - rewrite anyway
|
||||
|
||||
The option can also accept a user-defined function that determines whether the value should be overwritten or not. The function receives the current value, header name, and the headers object as arguments.
|
||||
|
||||
`AxiosHeaders` keeps the case of the first matching key it sees. You can use this to preserve specific header casing by seeding a key with `undefined` and then setting values later. See [Preserving a specific header case](/pages/advanced/headers#preserving-a-specific-header-case).
|
||||
|
||||
## Get
|
||||
|
||||
The `get` method is used to retrieve the value of a header. The method can be called with a single header name, an optional matcher, or a parser. The matcher is defaulted to `true`. The parser can be a regular expression that is used to extract the value from the header.
|
||||
|
||||
```js
|
||||
get(headerName: string, matcher?: true | AxiosHeaderParser): AxiosHeaderValue;
|
||||
get(headerName: string, parser: RegExp): RegExpExecArray | null;
|
||||
```
|
||||
|
||||
An example of some of the possible usages of the `get` method is shown below:
|
||||
|
||||
```js
|
||||
const headers = new AxiosHeaders({
|
||||
'Content-Type': 'multipart/form-data; boundary=Asrf456BGe4h',
|
||||
});
|
||||
|
||||
console.log(headers.get('Content-Type'));
|
||||
// multipart/form-data; boundary=Asrf456BGe4h
|
||||
|
||||
console.log(headers.get('Content-Type', true)); // parse key-value pairs from a string separated with \s,;= delimiters:
|
||||
// [Object: null prototype] {
|
||||
// 'multipart/form-data': undefined,
|
||||
// boundary: 'Asrf456BGe4h'
|
||||
// }
|
||||
|
||||
console.log(
|
||||
headers.get('Content-Type', (value, name, headers) => {
|
||||
return String(value).replace(/a/g, 'ZZZ');
|
||||
})
|
||||
);
|
||||
// multipZZZrt/form-dZZZtZZZ; boundZZZry=Asrf456BGe4h
|
||||
|
||||
console.log(headers.get('Content-Type', /boundary=(\w+)/)?.[0]);
|
||||
// boundary=Asrf456BGe4h
|
||||
```
|
||||
|
||||
## Has
|
||||
|
||||
The `has` method is used to check if a header exists in the instance of `AxiosHeaders`. The method can be called with a single header name and an optional matcher.
|
||||
|
||||
```js
|
||||
has(header: string, matcher?: AxiosHeaderMatcher): boolean;
|
||||
```
|
||||
|
||||
::: info
|
||||
Returns true if the header is set (has no undefined value).
|
||||
:::
|
||||
|
||||
## Delete
|
||||
|
||||
The `delete` method is used to delete a header from the instance of `AxiosHeaders`. The method can be called with a single header name and an optional matcher.
|
||||
|
||||
```js
|
||||
delete(header: string | string[], matcher?: AxiosHeaderMatcher): boolean;
|
||||
```
|
||||
|
||||
::: info
|
||||
Returns true if at least one header has been removed.
|
||||
:::
|
||||
|
||||
## Clear
|
||||
|
||||
The `clear` method is used to delete all headers from the instance of `AxiosHeaders` if nothing is passed. If a matcher is passed, only the headers that match the matcher are removed, in this case, the matcher is used to match against the header name rather than the value.
|
||||
|
||||
```js
|
||||
clear(matcher?: AxiosHeaderMatcher): boolean;
|
||||
```
|
||||
|
||||
::: info
|
||||
Returns true if at least one header has been cleared.
|
||||
:::
|
||||
|
||||
## Normalize
|
||||
|
||||
If the headers object was changed directly, it can cause duplicates with the same name but in different cases. This method normalizes the headers object by combining duplicate keys into one. Axios uses this method internally after calling each interceptor. Set format to true for converting headers name to lowercase and capitalize the initial letters (cOntEnt-type => Content-Type) or false to keep the original format.
|
||||
|
||||
```js
|
||||
const headers = new AxiosHeaders({
|
||||
foo: '1',
|
||||
});
|
||||
|
||||
headers.Foo = '2';
|
||||
headers.FOO = '3';
|
||||
|
||||
console.log(headers.toJSON()); // [Object: null prototype] { foo: '1', Foo: '2', FOO: '3' }
|
||||
console.log(headers.normalize().toJSON()); // [Object: null prototype] { foo: '3' }
|
||||
console.log(headers.normalize(true).toJSON()); // [Object: null prototype] { Foo: '3' }
|
||||
```
|
||||
|
||||
::: info
|
||||
Returns `this` for chaining.
|
||||
:::
|
||||
|
||||
## Concat
|
||||
|
||||
Merges the instance with targets into a new AxiosHeaders instance. If the target is a string, it will be parsed as RAW HTTP headers. If the target is an AxiosHeaders instance, it will be merged with the current instance.
|
||||
|
||||
This is useful for case presets when composing headers. For example:
|
||||
|
||||
```js
|
||||
const headers = AxiosHeaders.concat(
|
||||
{ 'content-type': undefined },
|
||||
{ 'Content-Type': 'application/octet-stream' }
|
||||
);
|
||||
```
|
||||
|
||||
```js
|
||||
concat(...targets: Array<AxiosHeaders | RawAxiosHeaders | string | undefined | null>): AxiosHeaders;
|
||||
```
|
||||
|
||||
::: info
|
||||
Returns a new AxiosHeaders instance.
|
||||
:::
|
||||
|
||||
## toJSON
|
||||
|
||||
Resolve all internal headers values into a new null prototype object. Set `asStrings` to true to resolve arrays as a string containing all elements, separated by commas.
|
||||
|
||||
```js
|
||||
toJSON(asStrings?: boolean): RawAxiosHeaders;
|
||||
```
|
||||
|
||||
## From
|
||||
|
||||
Returns a new `AxiosHeaders` instance created from the raw headers passed in, or simply returns the given headers object if it's an `AxiosHeaders` instance.
|
||||
|
||||
```js
|
||||
from(thing?: AxiosHeaders | RawAxiosHeaders | string): AxiosHeaders;
|
||||
```
|
||||
|
||||
## Shortcuts
|
||||
|
||||
The following shortcuts are available:
|
||||
|
||||
- `setContentType`, `getContentType`, `hasContentType`
|
||||
- `setContentLength`, `getContentLength`, `hasContentLength`
|
||||
- `setAccept`, `getAccept`, `hasAccept`
|
||||
- `setUserAgent`, `getUserAgent`, `hasUserAgent`
|
||||
- `setContentEncoding`, `getContentEncoding`, `hasContentEncoding`
|
||||
153
docs/pages/advanced/headers.md
Normal file
@ -0,0 +1,153 @@
|
||||
# Headers <Badge type="tip" text="New" />
|
||||
|
||||
Axios exposes its own AxiosHeaders class to manipulate headers using a Map-like API that guarantees case-insensitive keys. This class is used internally by Axios to manage headers, but it's also exposed to the user for convenience. Although HTTP headers are case-insensitive, Axios will retain the case of the original header for stylistic reasons and for a workaround when servers mistakenly consider the header's case. The old method of directly manipulating the headers object is still available, but deprecated and not recommended for future usage.
|
||||
|
||||
## Working with headers
|
||||
|
||||
The AxiosHeaders object instance can contain different types of internal values that control the setting and merging logic. The final headers object is obtained by Axios by calling the toJSON method. The AxiosHeaders object is also iterable, so you can use it in loops or convert it to an array or object.
|
||||
|
||||
The header values can be one of the following types:
|
||||
|
||||
- `string` - normal string value that will be sent to the server
|
||||
- `null` - skip header when converting to JSON
|
||||
- `false` - skip header when converting to JSON, additionally indicates that set method must be called with rewrite option set to true to overwrite this value (Axios uses this internally to allow users to opt out of installing certain headers like User-Agent or Content-Type)
|
||||
- `undefined` - value is not set
|
||||
|
||||
::: warning
|
||||
The header value is considered set if it is not undefined.
|
||||
:::
|
||||
|
||||
The headers object is always initialized inside interceptors and transformers as seen in the following example:
|
||||
|
||||
```js
|
||||
axios.interceptors.request.use((request: InternalAxiosRequestConfig) => {
|
||||
request.headers.set("My-header", "value");
|
||||
|
||||
request.headers.set({
|
||||
"My-set-header1": "my-set-value1",
|
||||
"My-set-header2": "my-set-value2",
|
||||
});
|
||||
|
||||
// Disable subsequent setting of this header by Axios
|
||||
request.headers.set("User-Agent", false);
|
||||
|
||||
request.headers.setContentType("text/plain");
|
||||
|
||||
// Direct access like this is deprecated
|
||||
request.headers["My-set-header2"] = "newValue";
|
||||
|
||||
return request;
|
||||
});
|
||||
```
|
||||
|
||||
You can iterate over an AxiosHeaders using any iterable method, like for-of loop, forEach, or spread operator:
|
||||
|
||||
```js
|
||||
const headers = new AxiosHeaders({
|
||||
foo: '1',
|
||||
bar: '2',
|
||||
baz: '3',
|
||||
});
|
||||
|
||||
for (const [header, value] of headers) {
|
||||
console.log(header, value);
|
||||
}
|
||||
|
||||
// foo 1
|
||||
// bar 2
|
||||
// baz 3
|
||||
```
|
||||
|
||||
## Setting headers on a request
|
||||
|
||||
The most common place to set headers is the `headers` option in your request config or instance config:
|
||||
|
||||
```js
|
||||
// On a single request
|
||||
await axios.get('/api/data', {
|
||||
headers: {
|
||||
'Accept-Language': 'en-US',
|
||||
'X-Request-ID': 'abc123',
|
||||
},
|
||||
});
|
||||
|
||||
// On an instance (applied to every request)
|
||||
const api = axios.create({
|
||||
headers: {
|
||||
'X-App-Version': '2.0.0',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Preserving a specific header case
|
||||
|
||||
Axios header names are case-insensitive, but `AxiosHeaders` keeps the case of the first matching key it sees. If you need a specific case for a server with non-standard case-sensitive behavior, define a case preset in defaults and then set values as usual.
|
||||
|
||||
```js
|
||||
const api = axios.create();
|
||||
|
||||
api.defaults.headers.common = {
|
||||
'content-type': undefined,
|
||||
accept: undefined,
|
||||
};
|
||||
|
||||
await api.put(url, data, {
|
||||
headers: {
|
||||
'Content-Type': 'application/octet-stream',
|
||||
Accept: 'application/json',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
You can also do this with `AxiosHeaders` directly when composing headers:
|
||||
|
||||
```js
|
||||
import axios, { AxiosHeaders } from 'axios';
|
||||
|
||||
const headers = AxiosHeaders.concat(
|
||||
{ 'content-type': undefined },
|
||||
{ 'Content-Type': 'application/octet-stream' }
|
||||
);
|
||||
|
||||
await axios.put(url, data, { headers });
|
||||
```
|
||||
|
||||
## Setting headers in an interceptor
|
||||
|
||||
Interceptors are the right place to attach dynamic headers like auth tokens, because the token may not be available when the instance is first created:
|
||||
|
||||
```js
|
||||
api.interceptors.request.use((config) => {
|
||||
const token = getAuthToken(); // read at request time
|
||||
config.headers.set('Authorization', `Bearer ${token}`);
|
||||
return config;
|
||||
});
|
||||
```
|
||||
|
||||
## Reading response headers
|
||||
|
||||
Response headers are available on `response.headers` as an `AxiosHeaders` instance. All header names are lower-cased:
|
||||
|
||||
```js
|
||||
const response = await axios.get('/api/data');
|
||||
|
||||
console.log(response.headers['content-type']);
|
||||
// application/json; charset=utf-8
|
||||
|
||||
console.log(response.headers.get('x-request-id'));
|
||||
// abc123
|
||||
```
|
||||
|
||||
## Removing a default header
|
||||
|
||||
To opt out of a header that axios sets by default (such as `Content-Type` or `User-Agent`), set its value to `false`:
|
||||
|
||||
```js
|
||||
await axios.post('/api/data', payload, {
|
||||
headers: {
|
||||
'Content-Type': false, // let the browser set it automatically (e.g. for FormData)
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
For more detail on the full `AxiosHeaders` method API, see the [Header methods](/pages/advanced/header-methods) page.
|
||||
57
docs/pages/advanced/html-form-processing.md
Normal file
@ -0,0 +1,57 @@
|
||||
# HTML form posting (browser) <Badge type="tip" text="New" />
|
||||
|
||||
You can also post a form directly from a HTML form element. This is useful when you have a form in your page and you want to submit it without any JavaScript code.
|
||||
|
||||
```js
|
||||
await axios.postForm('https://httpbin.org/post', document.querySelector('#htmlForm'));
|
||||
```
|
||||
|
||||
`FormData` and `HTMLForm` objects can also be posted as `JSON` by explicitly setting the `Content-Type` header to `application/json`:
|
||||
|
||||
```js
|
||||
await axios.post('https://httpbin.org/post', document.querySelector('#htmlForm'), {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
An example of a form that is valid and can be submitted by the above code is:
|
||||
|
||||
```html
|
||||
<form id="htmlForm">
|
||||
<input type="text" name="foo" value="1" />
|
||||
<input type="text" name="deep.prop" value="2" />
|
||||
<input type="text" name="deep prop spaced" value="3" />
|
||||
<input type="text" name="baz" value="4" />
|
||||
<input type="text" name="baz" value="5" />
|
||||
|
||||
<select name="user.age">
|
||||
<option value="value1">Value 1</option>
|
||||
<option value="value2" selected>Value 2</option>
|
||||
<option value="value3">Value 3</option>
|
||||
</select>
|
||||
|
||||
<input type="submit" value="Save" />
|
||||
</form>
|
||||
```
|
||||
|
||||
The above form will be submitted as:
|
||||
|
||||
```json
|
||||
{
|
||||
"foo": "1",
|
||||
"deep": {
|
||||
"prop": "2",
|
||||
"prop spaced": "3"
|
||||
},
|
||||
"baz": ["4", "5"],
|
||||
"user": {
|
||||
"age": "value2"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
::: warning
|
||||
Sending Blobs/Files as JSON (base64) is not currently supported.
|
||||
:::
|
||||
72
docs/pages/advanced/http2.md
Normal file
@ -0,0 +1,72 @@
|
||||
# HTTP2 <Badge type="warning" text="Experimental" /> <Badge type="tip" text="v1.13.0+" />
|
||||
|
||||
Experimental HTTP/2 support was added to the `http` adapter in version `1.13.0`. It is available in Node.js environments only.
|
||||
|
||||
## Basic usage
|
||||
|
||||
Use the `httpVersion` option to select the protocol version for a request. Setting it to `2` enables HTTP/2.
|
||||
|
||||
```js
|
||||
const { data, headers, status } = await axios.post(
|
||||
"https://httpbin.org/post",
|
||||
form,
|
||||
{
|
||||
httpVersion: 2,
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||
## `http2Options`
|
||||
|
||||
Additional native options for the internal `session.request()` call can be passed via the `http2Options` config object. This also includes the custom `sessionTimeout` parameter, which controls how long (in milliseconds) an idle HTTP/2 session is kept alive before being closed. It defaults to `1000ms`.
|
||||
|
||||
```js
|
||||
{
|
||||
httpVersion: 2,
|
||||
http2Options: {
|
||||
rejectUnauthorized: false, // accept self-signed certificates (dev only)
|
||||
sessionTimeout: 5000, // keep idle session alive for 5 seconds
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
::: warning
|
||||
HTTP/2 support is currently experimental. The API may change in future minor or patch releases.
|
||||
:::
|
||||
|
||||
## Full example
|
||||
|
||||
The example below sends a `multipart/form-data` POST request over HTTP/2 and tracks both upload and download progress.
|
||||
|
||||
```js
|
||||
const form = new FormData();
|
||||
form.append("foo", "123");
|
||||
|
||||
const { data, headers, status } = await axios.post(
|
||||
"https://httpbin.org/post",
|
||||
form,
|
||||
{
|
||||
httpVersion: 2,
|
||||
http2Options: {
|
||||
// rejectUnauthorized: false,
|
||||
// sessionTimeout: 1000
|
||||
},
|
||||
onUploadProgress(e) {
|
||||
console.log("upload progress", e);
|
||||
},
|
||||
onDownloadProgress(e) {
|
||||
console.log("download progress", e);
|
||||
},
|
||||
responseType: "arraybuffer",
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||
## Config reference
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `httpVersion` | `number` | `1` | HTTP protocol version to use. Set to `2` to enable HTTP/2. |
|
||||
| `http2Options.sessionTimeout` | `number` | `1000` | Time in milliseconds before an idle HTTP/2 session is closed. |
|
||||
|
||||
All other native `session.request()` options supported by Node.js's built-in `http2` module can also be passed inside `http2Options`.
|
||||
116
docs/pages/advanced/interceptors.md
Normal file
@ -0,0 +1,116 @@
|
||||
# Interceptors
|
||||
|
||||
Interceptors are a powerful mechanism that can be used to intercept and modify HTTP requests and responses. They are very similar to middleware in Express.js. The interceptor is a function that gets executed before a request is sent and before a response is received. Interceptors are useful for a variety of tasks such as logging, modifying request headers, and modifying the response.
|
||||
|
||||
Basic usage of interceptors is as follows:
|
||||
|
||||
```js
|
||||
// Add a request interceptor
|
||||
axios.interceptors.request.use(
|
||||
function (config) {
|
||||
// Do something before request is sent
|
||||
return config;
|
||||
},
|
||||
function (error) {
|
||||
// Do something with request error
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// Add a response interceptor
|
||||
axios.interceptors.response.use(
|
||||
function (response) {
|
||||
// Any status code that lie within the range of 2xx cause this function to trigger
|
||||
// Do something with response data
|
||||
return response;
|
||||
},
|
||||
function (error) {
|
||||
// Any status codes that falls outside the range of 2xx cause this function to trigger
|
||||
// Do something with response error
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## Removing Interceptors
|
||||
|
||||
You can remove any interceptor by using the `eject` method on the interceptor you want to remove. You can also remove all interceptors by calling the `clear` method on the `axios.interceptors` object. Here is an example of how to remove an interceptor:
|
||||
|
||||
```js
|
||||
// Eject the request interceptor
|
||||
const myInterceptor = axios.interceptors.request.use(function () {
|
||||
/*...*/
|
||||
});
|
||||
axios.interceptors.request.eject(myInterceptor);
|
||||
|
||||
// Eject the response interceptor
|
||||
const myInterceptor = axios.interceptors.response.use(function () {
|
||||
/*...*/
|
||||
});
|
||||
axios.interceptors.response.eject(myInterceptor);
|
||||
```
|
||||
|
||||
Here is an example of how to remove all interceptors:
|
||||
|
||||
```js
|
||||
const instance = axios.create();
|
||||
instance.interceptors.request.use(function () {
|
||||
/*...*/
|
||||
});
|
||||
instance.interceptors.request.clear(); // Removes interceptors from requests
|
||||
instance.interceptors.response.use(function () {
|
||||
/*...*/
|
||||
});
|
||||
instance.interceptors.response.clear(); // Removes interceptors from responses
|
||||
```
|
||||
|
||||
## Interceptors default behaviour
|
||||
|
||||
When you add request interceptors, they are presumed to be asynchronous by default. This can cause a delay in the execution of your axios request when the main thread is blocked (a promise is created under the hood for the interceptor and your request gets put on the bottom of the call stack). If your request interceptors are synchronous you can add a flag to the options object that will tell axios to run the code synchronously and avoid any delays in request execution.
|
||||
|
||||
```js
|
||||
axios.interceptors.request.use(
|
||||
function (config) {
|
||||
config.headers.test = "I am only a header!";
|
||||
return config;
|
||||
},
|
||||
null,
|
||||
{ synchronous: true }
|
||||
);
|
||||
```
|
||||
|
||||
## Interceptors using `runWhen`
|
||||
|
||||
If you want to execute a particular interceptor based on a runtime check, you can add a runWhen function to the options object. The interceptor will not be executed if and only if the return of runWhen is false. The function will be called with the config object (don't forget that you can bind your own arguments to it as well.) This can be handy when you have an asynchronous request interceptor that only needs to run at certain times.
|
||||
|
||||
```js
|
||||
function onGetCall(config) {
|
||||
return config.method === "get";
|
||||
}
|
||||
axios.interceptors.request.use(
|
||||
function (config) {
|
||||
config.headers.test = "special get headers";
|
||||
return config;
|
||||
},
|
||||
null,
|
||||
{ runWhen: onGetCall }
|
||||
);
|
||||
```
|
||||
|
||||
## Multiple interceptors
|
||||
|
||||
You may add multiple interceptors to the same request or response. The following will hold true for multiple interceptors in the same chain in the order below:
|
||||
|
||||
- Each interceptor is executed
|
||||
- Request interceptors are executed in reverse order (LIFO).
|
||||
- Response interceptors are executed in the order they were added (FIFO).
|
||||
- only the last interceptor's result is returned
|
||||
- every interceptor receives the result of its predecessor
|
||||
- when the fulfilment-interceptor throws
|
||||
- the following fulfilment-interceptor is not called
|
||||
- the following rejection-interceptor is called
|
||||
- once caught, another following fulfil-interceptor is called again (just like in a promise chain).
|
||||
|
||||
::: tip
|
||||
To gain an in-depth understanding of how interceptors work, you can read the test cases over [here](https://github.com/axios/axios/blob/v1.x/test/specs/interceptors.spec.js).
|
||||
:::
|
||||
120
docs/pages/advanced/multipart-form-data-format.md
Normal file
@ -0,0 +1,120 @@
|
||||
# multipart-form-data format
|
||||
|
||||
axios can send requests in the `multipart/form-data` format. This format is commonly used when uploading files. To send a request in this format, you need to create a `FormData` object and append the data to it. Then you can pass the `FormData` object to the `data` property of the axios request config.
|
||||
|
||||
```js
|
||||
const formData = new FormData();
|
||||
formData.append("foo", "bar");
|
||||
|
||||
axios.post("https://httpbin.org/post", formData);
|
||||
```
|
||||
|
||||
In node.js, you can use the `form-data` library as follows:
|
||||
|
||||
```js
|
||||
const FormData = require("form-data");
|
||||
|
||||
const form = new FormData();
|
||||
form.append("my_field", "my value");
|
||||
form.append("my_buffer", Buffer.alloc(10));
|
||||
form.append("my_file", fs.createReadStream("/foo/bar.jpg"));
|
||||
|
||||
axios.post("https://example.com", form);
|
||||
```
|
||||
|
||||
## Automatic serialization to FormData <Badge type="tip" text="New" />
|
||||
|
||||
Starting from v0.27.0, Axios supports automatic object serialization to a FormData object if the request Content-Type header is set to multipart/form-data. This means that you can pass a JavaScript object directly to the data property of the axios request config. For example when passing data to a POST request:
|
||||
|
||||
```js
|
||||
import axios from "axios";
|
||||
|
||||
axios
|
||||
.post(
|
||||
"https://httpbin.org/post",
|
||||
{ x: 1 },
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
}
|
||||
)
|
||||
.then(({ data }) => console.log(data));
|
||||
```
|
||||
|
||||
In the node.js build, the ([`form-data`](https://github.com/form-data/form-data)) polyfill is used by default. You can overload the FormData class by setting the env.FormData config variable, but you probably won't need it in most cases:
|
||||
|
||||
```js
|
||||
const axios = require("axios");
|
||||
var FormData = require("form-data");
|
||||
|
||||
axios
|
||||
.post(
|
||||
"https://httpbin.org/post",
|
||||
{ x: 1, buf: Buffer.alloc(10) },
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
}
|
||||
)
|
||||
.then(({ data }) => console.log(data));
|
||||
```
|
||||
|
||||
## Supported endings
|
||||
|
||||
Axios FormData serializer supports some special endings to perform the following operations:
|
||||
|
||||
- `{}` - serialize the value with JSON.stringify
|
||||
- `[]` - unwrap the array-like object as separate fields with the same key
|
||||
|
||||
::: warning
|
||||
Note: unwrap/expand operation will be used by default on arrays and FileList objects
|
||||
:::
|
||||
|
||||
## Configuring the FormData serializer
|
||||
|
||||
FormData serializer supports additional options via config.formSerializer: object property to handle rare cases:
|
||||
|
||||
- `visitor: Function` - user-defined visitor function that will be called recursively to serialize the data object to a FormData object by following custom rules.
|
||||
- `dots: boolean = false` - use dot notation instead of brackets to serialize arrays and objects;
|
||||
- `metaTokens: boolean = true` - add the special ending (e.g `user{}: '{"name": "John"}'`) in the FormData key. The back-end body-parser could potentially use this meta-information to automatically parse the value as JSON.
|
||||
- `indexes: null|false|true = false` - controls how indexes will be added to unwrapped keys of flat array-like objects
|
||||
- `null` - don't add brackets (`arr: 1`, `arr: 2`, `arr: 3`)
|
||||
- `false` (default) - add empty brackets (`arr[]: 1`, `arr[]: 2`, `arr[]: 3`)
|
||||
- `true` - add brackets with indexes (`arr[0]: 1`, `arr[1]: 2`, `arr[2]: 3`)
|
||||
|
||||
For example, if we have an object like this:
|
||||
|
||||
```js
|
||||
const obj = {
|
||||
x: 1,
|
||||
arr: [1, 2, 3],
|
||||
arr2: [1, [2], 3],
|
||||
users: [
|
||||
{ name: "Peter", surname: "Griffin" },
|
||||
{ name: "Thomas", surname: "Anderson" },
|
||||
],
|
||||
"obj2{}": [{ x: 1 }],
|
||||
};
|
||||
```
|
||||
|
||||
The following steps will be executed by the Axios serializer internally:
|
||||
|
||||
```js
|
||||
const formData = new FormData();
|
||||
formData.append("x", "1");
|
||||
formData.append("arr[]", "1");
|
||||
formData.append("arr[]", "2");
|
||||
formData.append("arr[]", "3");
|
||||
formData.append("arr2[0]", "1");
|
||||
formData.append("arr2[1][0]", "2");
|
||||
formData.append("arr2[2]", "3");
|
||||
formData.append("users[0][name]", "Peter");
|
||||
formData.append("users[0][surname]", "Griffin");
|
||||
formData.append("users[1][name]", "Thomas");
|
||||
formData.append("users[1][surname]", "Anderson");
|
||||
formData.append("obj2{}", '[{"x":1}]');
|
||||
```
|
||||
|
||||
Axios supports the following shortcut methods: `postForm`, `putForm`, `patchForm` which are just the corresponding http methods with the `Content-Type` header preset to `multipart/form-data`.
|
||||
55
docs/pages/advanced/progress-capturing.md
Normal file
@ -0,0 +1,55 @@
|
||||
# Progress capturing <Badge type="tip" text="New" />
|
||||
|
||||
Axios supports both browser and node environments to capture request upload/download progress. The frequency of progress events is forced to be limited to 3 times per second. This is to prevent the browser from being overwhelmed with progress events. An example of capturing progress events is shown below:
|
||||
|
||||
```js
|
||||
await axios.post(url, data, {
|
||||
onUploadProgress: function (axiosProgressEvent) {
|
||||
/*{
|
||||
loaded: number;
|
||||
total?: number;
|
||||
progress?: number; // in range [0..1]
|
||||
bytes: number; // how many bytes have been transferred since the last trigger (delta)
|
||||
estimated?: number; // estimated time in seconds
|
||||
rate?: number; // upload speed in bytes
|
||||
upload: true; // upload sign
|
||||
}*/
|
||||
},
|
||||
|
||||
onDownloadProgress: function (axiosProgressEvent) {
|
||||
/*{
|
||||
loaded: number;
|
||||
total?: number;
|
||||
progress?: number;
|
||||
bytes: number;
|
||||
estimated?: number;
|
||||
rate?: number; // download speed in bytes
|
||||
download: true; // download sign
|
||||
}*/
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
You can also stream the upload and download progress events to a readable stream in Node.js. This is useful when you want to display the progress in a custom way. An example of streaming progress events is shown below:
|
||||
|
||||
```js
|
||||
const { data } = await axios.post(SERVER_URL, readableStream, {
|
||||
onUploadProgress: ({ progress }) => {
|
||||
console.log((progress * 100).toFixed(2));
|
||||
},
|
||||
|
||||
headers: {
|
||||
"Content-Length": contentLength,
|
||||
},
|
||||
|
||||
maxRedirects: 0, // avoid buffering the entire stream
|
||||
});
|
||||
```
|
||||
|
||||
::: warning
|
||||
Capturing FormData upload progress is not currently supported in node.js environments
|
||||
:::
|
||||
|
||||
::: danger
|
||||
It is recommended to disable redirects by setting maxRedirects: 0 to upload the stream in the node.js environment, as the follow-redirects package will buffer the entire stream in RAM without following the "backpressure" algorithm
|
||||
:::
|
||||
81
docs/pages/advanced/promises.md
Normal file
@ -0,0 +1,81 @@
|
||||
# Promises
|
||||
|
||||
axios is built on top of the native ES6 Promise API. Every axios request returns a Promise that resolves to a response object or rejects with an error. If your environment doesn't support ES6 Promises, you will need to polyfill them — for example with [es6-promise](https://github.com/stefanpenner/es6-promise).
|
||||
|
||||
## then / catch / finally
|
||||
|
||||
Because axios returns a standard Promise, you can use `.then()`, `.catch()`, and `.finally()` to handle the result:
|
||||
|
||||
```js
|
||||
axios.get("/api/users")
|
||||
.then((response) => {
|
||||
console.log(response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Request failed:", error.message);
|
||||
})
|
||||
.finally(() => {
|
||||
console.log("Request finished");
|
||||
});
|
||||
```
|
||||
|
||||
## async / await
|
||||
|
||||
The recommended approach for most codebases is `async/await`, which makes asynchronous code read like synchronous code:
|
||||
|
||||
```js
|
||||
async function fetchUser(id) {
|
||||
try {
|
||||
const response = await axios.get(`/api/users/${id}`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch user:", error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Parallel requests
|
||||
|
||||
Because axios returns a standard Promise, you can use `Promise.all` to make multiple requests at the same time and wait for all of them to complete:
|
||||
|
||||
```js
|
||||
const [users, posts] = await Promise.all([
|
||||
axios.get("/api/users"),
|
||||
axios.get("/api/posts"),
|
||||
]);
|
||||
|
||||
console.log(users.data, posts.data);
|
||||
```
|
||||
|
||||
::: tip
|
||||
`Promise.all` will reject as soon as any one of the requests fails. If you want to handle partial failures, use `Promise.allSettled` instead.
|
||||
:::
|
||||
|
||||
```js
|
||||
const results = await Promise.allSettled([
|
||||
axios.get("/api/users"),
|
||||
axios.get("/api/posts"),
|
||||
]);
|
||||
|
||||
results.forEach((result) => {
|
||||
if (result.status === "fulfilled") {
|
||||
console.log(result.value.data);
|
||||
} else {
|
||||
console.error("Request failed:", result.reason.message);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Chaining requests
|
||||
|
||||
You can chain `.then()` calls to run requests sequentially, passing data from one to the next:
|
||||
|
||||
```js
|
||||
axios.get("/api/user/1")
|
||||
.then(({ data: user }) => axios.get(`/api/posts?userId=${user.id}`))
|
||||
.then(({ data: posts }) => {
|
||||
console.log("Posts for user:", posts);
|
||||
})
|
||||
.catch(console.error);
|
||||
```
|
||||
62
docs/pages/advanced/rate-limiting.md
Normal file
@ -0,0 +1,62 @@
|
||||
# Rate limiting <Badge type="tip" text="New" />
|
||||
|
||||
axios supports bandwidth limiting in the Node.js environment via the HTTP adapter. This lets you cap how fast data is uploaded or downloaded, which is useful for bulk operations, background jobs, or polite scraping that shouldn't saturate a connection.
|
||||
|
||||
## `maxRate`
|
||||
|
||||
The `maxRate` option accepts either a number (bytes per second) or an array where the first value is the upload limit and the second value is the download limit. Use `[uploadRate]` to limit upload only, or `[uploadRate, downloadRate]` to limit both directions. When a single number is passed, the same limit applies to both upload and download.
|
||||
|
||||
```js
|
||||
// Limit both upload and download to 100 KB/s
|
||||
await axios.get(URL, { maxRate: 100 * 1024 });
|
||||
|
||||
// Limit upload to 100 KB/s, download to 500 KB/s
|
||||
await axios.get(URL, { maxRate: [100 * 1024, 500 * 1024] });
|
||||
```
|
||||
|
||||
::: warning
|
||||
`maxRate` is only supported by the Node.js HTTP adapter. It has no effect in browser environments.
|
||||
:::
|
||||
|
||||
## Upload rate limiting
|
||||
|
||||
Cap the upload speed and log progress at the same time:
|
||||
|
||||
```js
|
||||
const { data } = await axios.post(SERVER_URL, myBuffer, {
|
||||
onUploadProgress: ({ progress, rate }) => {
|
||||
const percent = (progress * 100).toFixed(1);
|
||||
const kbps = (rate / 1024).toFixed(1);
|
||||
console.log(`Upload [${percent}%] at ${kbps} KB/s`);
|
||||
},
|
||||
|
||||
maxRate: [100 * 1024], // cap upload at 100 KB/s
|
||||
});
|
||||
```
|
||||
|
||||
## Download rate limiting
|
||||
|
||||
Cap the download speed for large responses:
|
||||
|
||||
```js
|
||||
const { data } = await axios.get(FILE_URL, {
|
||||
onDownloadProgress: ({ progress, rate }) => {
|
||||
const percent = (progress * 100).toFixed(1);
|
||||
const kbps = (rate / 1024).toFixed(1);
|
||||
console.log(`Download [${percent}%] at ${kbps} KB/s`);
|
||||
},
|
||||
|
||||
maxRate: [Infinity, 200 * 1024], // no upload limit, 200 KB/s download limit
|
||||
responseType: "arraybuffer",
|
||||
});
|
||||
```
|
||||
|
||||
## Combined upload and download limiting
|
||||
|
||||
Pass both limits as an array to control both directions simultaneously:
|
||||
|
||||
```js
|
||||
await axios.post(SERVER_URL, largeBuffer, {
|
||||
maxRate: [50 * 1024, 500 * 1024], // 50 KB/s up, 500 KB/s down
|
||||
});
|
||||
```
|
||||
350
docs/pages/advanced/request-config.md
Normal file
@ -0,0 +1,350 @@
|
||||
# Request config
|
||||
|
||||
The request config is used to configure the request. There is a wide range of options available, but the only required option is `url`. If the configuration object does not contain a `method` field, the default method is `GET`.
|
||||
|
||||
### `url`
|
||||
|
||||
The `url` is the URL to which the request is made. It can be a string or an instance of `URL`.
|
||||
|
||||
### `method`
|
||||
|
||||
The `method` is the HTTP method to use for the request. The default method is `GET`.
|
||||
|
||||
### `baseURL`
|
||||
|
||||
The `baseURL` is the base URL to be prepended to the `url` unless the `url` is an absolute URL. This is useful for making requests to the same domain without having to repeat the domain name and any api or version prefix.
|
||||
|
||||
### `allowAbsoluteUrls`
|
||||
|
||||
The `allowAbsoluteUrls` determines whether or not absolute URLs will override a configured `baseUrl`. When set to true (default), absolute values for `url` will override `baseUrl`. When set to false, absolute values for `url` will always be prepended by `baseUrl`.
|
||||
|
||||
### `transformRequest`
|
||||
|
||||
The `transformRequest` function allows you to modify the request data before it is sent to the server. This function is called with the request data as its only argument. This is only applicable for request methods `PUT`, `POST`, `PATCH` and `DELETE`. The last function in the array must return a string or an instance of Buffer, ArrayBuffer FormData or Stream.
|
||||
|
||||
### `transformResponse`
|
||||
|
||||
The `transformResponse` function allows you to modify the response data before it is passed to the `then` or `catch` functions. This function is called with the response data as its only argument.
|
||||
|
||||
### `headers`
|
||||
|
||||
The `headers` are the HTTP headers to be sent with the request. The `Content-Type` header is set to `application/json` by default.
|
||||
|
||||
### `params`
|
||||
|
||||
The `params` are the URL parameters to be sent with the request. This must be a plain object or a URLSearchParams object. If the `url` contains query parameters, they will be merged with the `params` object.
|
||||
|
||||
### `paramsSerializer`
|
||||
|
||||
The `paramsSerializer` function allows you to serialize the `params` object before it is sent to the server. There are a few options available for this function, so please refer to the full request config example at the end of this page.
|
||||
|
||||
### `data`
|
||||
|
||||
The `data` is the data to be sent as the request body. This can be a string, a plain object, a Buffer, ArrayBuffer, FormData, Stream, or URLSearchParams. Only applicable for request methods `PUT`, `POST`, `DELETE` , and `PATCH`. When no `transformRequest` is set, must be of one of the following types:
|
||||
|
||||
- string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
|
||||
- Browser only: FormData, File, Blob
|
||||
- Node only: Stream, Buffer, FormData (form-data package)
|
||||
|
||||
### `timeout`
|
||||
|
||||
The `timeout` is the number of milliseconds before the request times out. If the request takes longer than `timeout`, the request will be aborted.
|
||||
|
||||
### `withCredentials`
|
||||
|
||||
The `withCredentials` property indicates whether or not cross-site Access-Control requests should be made using credentials such as cookies, authorization headers, or TLS client certificates. Setting withCredentials has no effect on same-site requests.
|
||||
|
||||
### `adapter`
|
||||
|
||||
`adapter` allows custom handling of requests which makes testing easier. Return a promise and supply a valid response see [adapters](/pages/advanced/adapters) for more information. We also provide a number of built-in adapters. The default adapter is `http` for node and `xhr` for browsers. The full list of built-in adapters as follows:
|
||||
|
||||
- fetch
|
||||
- http
|
||||
- xhr
|
||||
|
||||
You may also pass an array of adapters to be used, axios will use the first adapter that is supported by the environment.
|
||||
|
||||
### `auth`
|
||||
|
||||
`auth` indicates that HTTP Basic auth should be used, and supplies credentials. This will set an `Authorization` header, overwriting any existing `Authorization` custom headers you have set using `headers`. Please note that only HTTP Basic auth is configurable through this parameter. For Bearer tokens and such, use `Authorization` custom headers instead.
|
||||
|
||||
### `responseType`
|
||||
|
||||
The `responseType` indicates the type of data that the server will respond with. This can be one of the following:
|
||||
|
||||
- arraybuffer
|
||||
- document
|
||||
- json
|
||||
- text
|
||||
- stream
|
||||
- blob (browser only)
|
||||
- formdata (fetch adapter only)
|
||||
|
||||
### `responseEncoding` <Badge type="warning" text="Node.js only" />
|
||||
|
||||
The `responseEncoding` indicates encoding to use for decoding responses. The following options are supported:
|
||||
|
||||
- ascii
|
||||
- ASCII
|
||||
- ansi
|
||||
- ANSI
|
||||
- binary
|
||||
- BINARY
|
||||
- base64
|
||||
- BASE64
|
||||
- base64url
|
||||
- BASE64URL
|
||||
- hex
|
||||
- HEX
|
||||
- latin1
|
||||
- LATIN1
|
||||
- ucs-2
|
||||
- UCS-2
|
||||
- ucs2
|
||||
- UCS2
|
||||
- utf-8
|
||||
- UTF-8
|
||||
- utf8
|
||||
- UTF8
|
||||
- utf16le
|
||||
- UTF16LE
|
||||
|
||||
::: tip
|
||||
Note: Ignored for `responseType` of `stream` or client-side requests
|
||||
:::
|
||||
|
||||
### `xsrfCookieName`
|
||||
|
||||
The `xsrfCookieName` is the name of the cookie to use as a value for `XSRF` token.
|
||||
|
||||
### `xsrfHeaderName`
|
||||
|
||||
The `xsrfHeaderName` is the name of the header to use as a value for `XSRF` token.
|
||||
|
||||
### `withXSRFToken`
|
||||
|
||||
The `withXSRFToken` property indicates whether or not to send the `XSRF` token with the request. This is only applicable for client-side requests. The default value is undefined.
|
||||
|
||||
### `onUploadProgress`
|
||||
|
||||
The `onUploadProgress` function allows you to listen to the progress of an upload.
|
||||
|
||||
### `onDownloadProgress`
|
||||
|
||||
The `onDownloadProgress` function allows you to listen to the progress of a download.
|
||||
|
||||
### `maxContentLength` <Badge type="warning" text="Node.js only" />
|
||||
|
||||
The `maxContentLength` property defines the maximum number of bytes that the server will accept in the response.
|
||||
|
||||
### `maxBodyLength` <Badge type="warning" text="Node.js only" />
|
||||
|
||||
The `maxBodyLength` property defines the maximum number of bytes that the server will accept in the request.
|
||||
|
||||
### `validateStatus`
|
||||
|
||||
The `validateStatus` function allows you to override the default status code validation. By default, axios will reject the promise if the status code is not in the range of 200-299. You can override this behavior by providing a custom `validateStatus` function. The function should return `true` if the status code is within the range you want to accept.
|
||||
|
||||
### `maxRedirects` <Badge type="warning" text="Node.js only" />
|
||||
|
||||
The `maxRedirects` property defines the maximum number of redirects to follow. If set to 0, no redirects will be followed.
|
||||
|
||||
### `beforeRedirect`
|
||||
|
||||
The `beforeRedirect` function allows you to modify the request before it is redirected. Use this to adjust the request options upon redirecting, to inspect the latest response headers, or to cancel the request by throwing an error. If maxRedirects is set to 0, `beforeRedirect` is not used.
|
||||
|
||||
### `socketPath` <Badge type="warning" text="Node.js only" />
|
||||
|
||||
The `socketPath` property defines a UNIX socket to use instead of a TCP connection. e.g. `/var/run/docker.sock` to send requests to the docker daemon. Only `socketPath` or `proxy` can be specified. If both are specified, `socketPath` is used.
|
||||
|
||||
### `transport`
|
||||
|
||||
The `transport` property defines the transport to use for the request. This is useful for making requests over a different protocol, such as `http2`.
|
||||
|
||||
### `httpAgent` and `httpsAgent`
|
||||
|
||||
The `httpAgent` and `httpsAgent` define a custom agent to be used when performing http and https requests, respectively, in node.js. This allows options to be added like `keepAlive` that are not enabled by default.
|
||||
|
||||
### `proxy`
|
||||
|
||||
The `proxy` defines the hostname, port, and protocol of a proxy server you would like to use. You can also define your proxy using the conventional `http_proxy` and `https_proxy` environment variables.
|
||||
|
||||
If you are using environment variables for your proxy configuration, you can also define a `no_proxy` environment variable as a comma-separated list of domains that should not be proxied.
|
||||
|
||||
Use `false` to disable proxies, ignoring environment variables. `auth` indicates that HTTP Basic auth should be used to connect to the proxy, and supplies credentials. This will set an `Proxy-Authorization` header, overwriting any existing `Proxy-Authorization` custom headers you have set using `headers`. If the proxy server uses HTTPS, then you must set the protocol to `https`.
|
||||
|
||||
```js
|
||||
proxy: {
|
||||
protocol: "https",
|
||||
host: "127.0.0.1",
|
||||
hostname: "localhost", // Takes precedence over "host" if both are defined
|
||||
port: 9000,
|
||||
auth: {
|
||||
username: "mikeymike",
|
||||
password: "rapunz3l"
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
### `cancelToken`
|
||||
|
||||
The `cancelToken` property allows you to create a cancel token that can be used to cancel the request. For more information, see the [cancellation](/pages/advanced/cancellation) documentation.
|
||||
|
||||
### `signal`
|
||||
|
||||
The `signal` property allows you to pass an instance of `AbortSignal` to the request. This allows you to cancel the request using the `AbortController` API.
|
||||
|
||||
### `decompress` <Badge type="warning" text="Node.js only" />
|
||||
|
||||
The `decompress` property indicates whether or not to automatically decompress the response data. The default value is `true`.
|
||||
|
||||
### `insecureHTTPParser`
|
||||
|
||||
Indicates where to use an insecure HTTP parser that accepts invalid HTTP headers. This may allow interoperability with non-conformant HTTP implementations. Using the insecure parser should be avoided.
|
||||
|
||||
Please note that the `insecureHTTPParser` option is only available in Node.js 12.10.0 and later. Please read the [Node.js documentation](https://nodejs.org/en/blog/vulnerability/february-2020-security-releases/#strict-http-header-parsing-none) for more information. See the full set of options [here](https://nodejs.org/dist/latest-v12.x/docs/api/http.html#http_http_request_url_options_callback)
|
||||
|
||||
### `transitional`
|
||||
|
||||
The `transitional` property allows you to enable or disable certain transitional features. The following options are available:
|
||||
|
||||
- `silentJSONParsing`: If set to `true`, axios will not log a warning when it encounters invalid JSON responses, setting the return value to null. This is useful when you are working with APIs that return invalid JSON.
|
||||
- `forcedJSONParsing`: Forces axios to parse JSON responses as JSON, even if the response is not valid JSON. This is useful when you are working with APIs that return invalid JSON.
|
||||
- `clarifyTimeoutError`: Clarifies the error message when a request times out. This is useful when you are debugging timeout issues.
|
||||
- `legacyInterceptorReqResOrdering`: When set to true we will use the legacy interceptor request/response ordering.
|
||||
|
||||
### `env`
|
||||
|
||||
The `env` property allows you to set some configuration options. For example the FormData class which is used to automatically serialize the payload into a FormData object.
|
||||
|
||||
- FormData: window?.FormData || global?.FormData
|
||||
|
||||
### `formSerializer`
|
||||
|
||||
The `formSerializer` function allows you to serialize the `data` object before it is sent to the server. There are a few options available for this function, so please refer to the full request config example at the end of this page.
|
||||
|
||||
### `maxRate` <Badge type="warning" text="Node.js only" />
|
||||
|
||||
The `maxRate` property defines the maximum **bandwidth** (in bytes per second) for upload and/or download. It accepts either a single number (applied to both directions) or a two-element array `[uploadRate, downloadRate]` where each element is a byte-per-second limit. For example, `100 * 1024` means 100 KB/s. See [Rate limiting](/pages/advanced/rate-limiting) for examples.
|
||||
|
||||
## Full request config example
|
||||
|
||||
```js
|
||||
{
|
||||
url: "/posts",
|
||||
method: "get",
|
||||
baseURL: "https://jsonplaceholder.typicode.com",
|
||||
allowAbsoluteUrls: true,
|
||||
transformRequest: [function (data, headers) {
|
||||
return data;
|
||||
}],
|
||||
transformResponse: [function (data) {
|
||||
return data;
|
||||
}],
|
||||
headers: {"X-Requested-With": "XMLHttpRequest"},
|
||||
params: {
|
||||
postId: 5
|
||||
},
|
||||
paramsSerializer: {
|
||||
// Custom encoder function which sends key/value pairs in an iterative fashion.
|
||||
encode?: (param: string): string => { /* Do custom operations here and return transformed string */ },
|
||||
|
||||
// Custom serializer function for the entire parameter. Allows user to mimic pre 1.x behaviour.
|
||||
serialize?: (params: Record<string, any>, options?: ParamsSerializerOptions ),
|
||||
|
||||
// Configuration for formatting array indexes in the params.
|
||||
// Three available options:
|
||||
// (1) indexes: null (leads to no brackets)
|
||||
// (2) (default) indexes: false (leads to empty brackets)
|
||||
// (3) indexes: true (leads to brackets with indexes).
|
||||
indexes: false
|
||||
|
||||
},
|
||||
data: {
|
||||
firstName: "Fred"
|
||||
},
|
||||
// Syntax alternative to send data into the body method post only the value is sent, not the key
|
||||
data: "Country=Brasil&City=Belo Horizonte",
|
||||
timeout: 1000,
|
||||
withCredentials: false,
|
||||
adapter: function (config) {
|
||||
// Do whatever you want
|
||||
},
|
||||
adapter: "xhr",
|
||||
auth: {
|
||||
username: "janedoe",
|
||||
password: "s00pers3cret"
|
||||
},
|
||||
responseType: "json",
|
||||
responseEncoding: "utf8",
|
||||
xsrfCookieName: "XSRF-TOKEN",
|
||||
xsrfHeaderName: "X-XSRF-TOKEN",
|
||||
withXSRFToken: boolean | undefined | ((config: InternalAxiosRequestConfig) => boolean | undefined),
|
||||
onUploadProgress: function ({loaded, total, progress, bytes, estimated, rate, upload = true}) {
|
||||
// Do whatever you want with the Axios progress event
|
||||
},
|
||||
onDownloadProgress: function ({loaded, total, progress, bytes, estimated, rate, download = true}) {
|
||||
// Do whatever you want with the Axios progress event
|
||||
},
|
||||
maxContentLength: 2000,
|
||||
maxBodyLength: 2000,
|
||||
validateStatus: function (status) {
|
||||
return status >= 200 && status < 300;
|
||||
},
|
||||
maxRedirects: 21,
|
||||
beforeRedirect: (options, { headers }) => {
|
||||
if (options.hostname === "typicode.com") {
|
||||
options.auth = "user:password";
|
||||
}
|
||||
},
|
||||
socketPath: null,
|
||||
transport: undefined,
|
||||
httpAgent: new http.Agent({ keepAlive: true }),
|
||||
httpsAgent: new https.Agent({ keepAlive: true }),
|
||||
proxy: {
|
||||
protocol: "https",
|
||||
host: "127.0.0.1",
|
||||
// hostname: "127.0.0.1" // Takes precedence over "host" if both are defined
|
||||
port: 9000,
|
||||
auth: {
|
||||
username: "mikeymike",
|
||||
password: "rapunz3l"
|
||||
}
|
||||
},
|
||||
cancelToken: new CancelToken(function (cancel) {
|
||||
cancel("Operation has been canceled.");
|
||||
}),
|
||||
signal: new AbortController().signal,
|
||||
decompress: true,
|
||||
insecureHTTPParser: undefined,
|
||||
transitional: {
|
||||
silentJSONParsing: true,
|
||||
forcedJSONParsing: true,
|
||||
clarifyTimeoutError: false,
|
||||
legacyInterceptorReqResOrdering: true,
|
||||
},
|
||||
env: {
|
||||
FormData: window?.FormData || global?.FormData
|
||||
},
|
||||
formSerializer: {
|
||||
// Custom visitor function to serialize form values
|
||||
visitor: (value, key, path, helpers) => {};
|
||||
|
||||
// Use dots instead of brackets format
|
||||
dots: boolean;
|
||||
|
||||
// Keep special endings like {} in parameter key
|
||||
metaTokens: boolean;
|
||||
|
||||
// Use array indexes format:
|
||||
// null - no brackets
|
||||
// false - empty brackets
|
||||
// true - brackets with indexes
|
||||
indexes: boolean;
|
||||
},
|
||||
maxRate: [
|
||||
100 * 1024, // 100KB/s upload limit,
|
||||
100 * 1024 // 100KB/s download limit
|
||||
]
|
||||
}
|
||||
```
|
||||
130
docs/pages/advanced/request-method-aliases.md
Normal file
@ -0,0 +1,130 @@
|
||||
# Request aliases
|
||||
|
||||
axios provides a set of aliases for making HTTP requests. These aliases are shortcuts for making requests using the `request` method. The aliases are designed to be easy to use and to provide a more convenient way to make requests.
|
||||
|
||||
axios endeavours to follow RFC 7231 and RFC 5789, as closely as possible. The aliases are designed to be consistent with the HTTP methods defined in these RFCs.
|
||||
|
||||
### `axios`
|
||||
|
||||
axios can be used to make HTTP request by passing only the config object. The full config object is documented [here](/pages/advanced/request-config)
|
||||
|
||||
```ts
|
||||
axios(url: string | AxiosRequestConfig, config?: AxiosRequestConfig);
|
||||
```
|
||||
|
||||
## Method aliases
|
||||
|
||||
The following aliases are available for making requests:
|
||||
|
||||
### `request`
|
||||
|
||||
The `request` method is the main method that you will use to make HTTP requests. It takes a configuration object as an argument and returns a promise that resolves to the response object. The `request` method is a generic method that can be used to make any type of HTTP request.
|
||||
|
||||
```ts
|
||||
axios.request(config: AxiosRequestConfig<C>): AxiosResponse<R>;
|
||||
```
|
||||
|
||||
### `get`
|
||||
|
||||
The `get` method is used to make a GET request. It takes a URL and an optional configuration object as arguments and returns a promise that resolves to the response object.
|
||||
|
||||
```ts
|
||||
axios.get(url: string, config?: AxiosRequestConfig<C>): AxiosResponse<R>;
|
||||
```
|
||||
|
||||
### `delete`
|
||||
|
||||
The `delete` method is used to make a DELETE request. It takes a URL and an optional configuration object as arguments and returns a promise that resolves to the response object.
|
||||
|
||||
```ts
|
||||
axios.delete(url: string, config?: AxiosRequestConfig<C>): AxiosResponse<R>;
|
||||
```
|
||||
|
||||
### `head`
|
||||
|
||||
The `head` method is used to make a HEAD request. It takes a URL and an optional configuration object as arguments and returns a promise that resolves to the response object.
|
||||
|
||||
```ts
|
||||
axios.head(url: string, config?: AxiosRequestConfig<C>): AxiosResponse<R>;
|
||||
```
|
||||
|
||||
### `options`
|
||||
|
||||
The `options` method is used to make an OPTIONS request. It takes a URL and an optional configuration object as arguments and returns a promise that resolves to the response object.
|
||||
|
||||
```ts
|
||||
axios.options(url: string, config?: AxiosRequestConfig<C>): AxiosResponse<R>;
|
||||
```
|
||||
|
||||
### `post`
|
||||
|
||||
The `post` method is used to make a POST request. It takes a URL, an optional data object, and an optional configuration object as arguments and returns a promise that resolves to the response object.
|
||||
|
||||
```ts
|
||||
axios.post(url: string, data?: D, config?: AxiosRequestConfig<C>): AxiosResponse<R>;
|
||||
```
|
||||
|
||||
### `put`
|
||||
|
||||
The `put` method is used to make a PUT request. It takes a URL, an optional data object, and an optional configuration object as arguments and returns a promise that resolves to the response object.
|
||||
|
||||
```ts
|
||||
axios.put(url: string, data?: D, config?: AxiosRequestConfig<C>): AxiosResponse<R>;
|
||||
```
|
||||
|
||||
### `patch`
|
||||
|
||||
The `patch` method is used to make a PATCH request. It takes a URL, an optional data object, and an optional configuration object as arguments and returns a promise that resolves to the response object.
|
||||
|
||||
```ts
|
||||
axios.patch(url: string, data?: D, config?: AxiosRequestConfig<C>): AxiosResponse<R>;
|
||||
```
|
||||
|
||||
## Form data shorthand methods
|
||||
|
||||
These methods are equivalent to their counterparts above, but preset `Content-Type` to `multipart/form-data`. They are the recommended way to upload files or submit HTML forms.
|
||||
|
||||
### `postForm`
|
||||
|
||||
```ts
|
||||
axios.postForm(url: string, data?: D, config?: AxiosRequestConfig<C>): AxiosResponse<R>;
|
||||
```
|
||||
|
||||
```js
|
||||
// Upload a file from a browser file input
|
||||
await axios.postForm("/api/upload", {
|
||||
file: document.querySelector("#fileInput").files[0],
|
||||
description: "Profile photo",
|
||||
});
|
||||
```
|
||||
|
||||
### `putForm`
|
||||
|
||||
```ts
|
||||
axios.putForm(url: string, data?: D, config?: AxiosRequestConfig<C>): AxiosResponse<R>;
|
||||
```
|
||||
|
||||
```js
|
||||
// Replace a resource with form data
|
||||
await axios.putForm("/api/users/1/avatar", {
|
||||
avatar: document.querySelector("#avatarInput").files[0],
|
||||
});
|
||||
```
|
||||
|
||||
### `patchForm`
|
||||
|
||||
```ts
|
||||
axios.patchForm(url: string, data?: D, config?: AxiosRequestConfig<C>): AxiosResponse<R>;
|
||||
```
|
||||
|
||||
```js
|
||||
// Update specific fields using form data
|
||||
await axios.patchForm("/api/users/1", {
|
||||
displayName: "New Name",
|
||||
avatar: document.querySelector("#avatarInput").files[0],
|
||||
});
|
||||
```
|
||||
|
||||
::: tip
|
||||
`postForm`, `putForm`, and `patchForm` accept all the same data types as their base methods — plain objects, `FormData`, `FileList`, and `HTMLFormElement`. See [File posting](/pages/advanced/file-posting) for more examples.
|
||||
:::
|
||||
64
docs/pages/advanced/response-schema.md
Normal file
@ -0,0 +1,64 @@
|
||||
# Response schema
|
||||
|
||||
Every axios request resolves to a response object with the following shape. The schema is consistent across both browser and Node.js environments.
|
||||
|
||||
```js
|
||||
{
|
||||
// The response data provided by the server.
|
||||
// When using `transformResponse`, this will be the result of the last transform.
|
||||
data: {},
|
||||
|
||||
// The HTTP status code from the server response (e.g. 200, 404, 500).
|
||||
status: 200,
|
||||
|
||||
// The HTTP status message matching the status code (e.g. "OK", "Not Found").
|
||||
statusText: "OK",
|
||||
|
||||
// The response headers sent by the server.
|
||||
// Header names are lower-cased. You can access them using bracket or dot notation.
|
||||
headers: {},
|
||||
|
||||
// The axios config that was used for this request, including baseURL,
|
||||
// headers, timeout, params, and any other options you provided.
|
||||
config: {},
|
||||
|
||||
// The underlying request object.
|
||||
// In Node.js: the last `http.ClientRequest` instance (after any redirects).
|
||||
// In the browser: the `XMLHttpRequest` instance.
|
||||
request: {},
|
||||
}
|
||||
```
|
||||
|
||||
## Accessing response fields
|
||||
|
||||
In practice you will usually destructure just the parts you need:
|
||||
|
||||
```js
|
||||
const { data, status, headers } = await axios.get("/api/users/1");
|
||||
|
||||
console.log(status); // 200
|
||||
console.log(headers["content-type"]); // "application/json; charset=utf-8"
|
||||
console.log(data); // { id: 1, name: "Jay", email: "jay@example.com" }
|
||||
```
|
||||
|
||||
## Checking the status code
|
||||
|
||||
axios resolves the promise for any 2xx response and rejects for anything outside that range by default. You can customise this with the `validateStatus` config option:
|
||||
|
||||
```js
|
||||
const response = await axios.get("/api/resource", {
|
||||
validateStatus: (status) => status < 500, // resolve for anything below 500
|
||||
});
|
||||
```
|
||||
|
||||
## Accessing response headers
|
||||
|
||||
All response header names are lower-cased, regardless of how the server sent them:
|
||||
|
||||
```js
|
||||
const response = await axios.get("/api/resource");
|
||||
|
||||
// These are equivalent
|
||||
const contentType = response.headers["content-type"];
|
||||
const contentType2 = response.headers.get("content-type");
|
||||
```
|
||||
130
docs/pages/advanced/retry.md
Normal file
@ -0,0 +1,130 @@
|
||||
# Retry and error recovery
|
||||
|
||||
Network requests can fail for transient reasons — a server blip, a brief network drop, or a rate-limit response. Implementing a retry strategy in an interceptor lets you handle these failures transparently, without cluttering your application code.
|
||||
|
||||
## Basic retry with a response interceptor
|
||||
|
||||
The simplest approach is to catch specific error status codes and immediately re-send the original request a limited number of times:
|
||||
|
||||
```js
|
||||
import axios from "axios";
|
||||
|
||||
const api = axios.create({ baseURL: "https://api.example.com" });
|
||||
|
||||
const MAX_RETRIES = 3;
|
||||
|
||||
api.interceptors.response.use(
|
||||
(response) => response,
|
||||
async (error) => {
|
||||
const config = error.config;
|
||||
|
||||
// Only retry on network errors or 5xx server errors
|
||||
const shouldRetry =
|
||||
!error.response || (error.response.status >= 500 && error.response.status < 600);
|
||||
|
||||
if (!shouldRetry) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
config._retryCount = config._retryCount ?? 0;
|
||||
|
||||
if (config._retryCount >= MAX_RETRIES) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
config._retryCount += 1;
|
||||
return api(config);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## Exponential backoff
|
||||
|
||||
Retrying immediately after a failure can overload an already-struggling server. Exponential backoff waits progressively longer between each attempt:
|
||||
|
||||
```js
|
||||
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
api.interceptors.response.use(
|
||||
(response) => response,
|
||||
async (error) => {
|
||||
const config = error.config;
|
||||
|
||||
const shouldRetry =
|
||||
!error.response || (error.response.status >= 500 && error.response.status < 600);
|
||||
|
||||
if (!shouldRetry) return Promise.reject(error);
|
||||
|
||||
config._retryCount = config._retryCount ?? 0;
|
||||
|
||||
if (config._retryCount >= 3) return Promise.reject(error);
|
||||
|
||||
config._retryCount += 1;
|
||||
|
||||
// Wait 200ms, 400ms, 800ms, ... before each retry
|
||||
const backoff = 100 * 2 ** config._retryCount;
|
||||
await delay(backoff);
|
||||
|
||||
return api(config);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## Retrying on 429 (rate limit) with Retry-After
|
||||
|
||||
When the server responds with `429 Too Many Requests`, it often includes a `Retry-After` header telling you exactly how long to wait:
|
||||
|
||||
```js
|
||||
api.interceptors.response.use(
|
||||
(response) => response,
|
||||
async (error) => {
|
||||
const config = error.config;
|
||||
|
||||
if (error.response?.status !== 429) return Promise.reject(error);
|
||||
|
||||
config._retryCount = config._retryCount ?? 0;
|
||||
if (config._retryCount >= 3) return Promise.reject(error);
|
||||
|
||||
config._retryCount += 1;
|
||||
|
||||
const retryAfterHeader = error.response.headers["retry-after"];
|
||||
const waitMs = retryAfterHeader
|
||||
? parseFloat(retryAfterHeader) * 1000 // header is in seconds
|
||||
: 1000; // default to 1 second
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, waitMs));
|
||||
return api(config);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## Opting out of retries per request
|
||||
|
||||
If some requests should never be retried (e.g. non-idempotent mutations you don't want to duplicate), add a flag to the request config:
|
||||
|
||||
```js
|
||||
// Add this to your interceptor before the retry logic:
|
||||
if (config._noRetry) return Promise.reject(error);
|
||||
|
||||
// Then opt out on specific calls:
|
||||
await api.post("/payments/charge", body, { _noRetry: true });
|
||||
```
|
||||
|
||||
## Combining retry with cancellation
|
||||
|
||||
Use an `AbortController` to cancel a request that is waiting for a backoff delay:
|
||||
|
||||
```js
|
||||
const controller = new AbortController();
|
||||
|
||||
try {
|
||||
await api.get("/api/data", { signal: controller.signal });
|
||||
} catch (error) {
|
||||
if (axios.isCancel(error)) {
|
||||
console.log("Request aborted by user");
|
||||
}
|
||||
}
|
||||
|
||||
// Cancel the request (and any pending retry delay) from elsewhere:
|
||||
controller.abort();
|
||||
```
|
||||
145
docs/pages/advanced/testing.md
Normal file
@ -0,0 +1,145 @@
|
||||
# Testing
|
||||
|
||||
Testing code that makes HTTP requests with axios is straightforward. The recommended approach is to mock axios itself so that your tests run without hitting a real network, giving you full control over what responses your code receives.
|
||||
|
||||
## Mocking with Vitest or Jest
|
||||
|
||||
Both Vitest and Jest support module mocking with `vi.mock` / `jest.mock`. You can mock the entire axios module and control what each method returns:
|
||||
|
||||
```js
|
||||
// user-service.js
|
||||
import axios from "axios";
|
||||
|
||||
export async function getUser(id) {
|
||||
const { data } = await axios.get(`/api/users/${id}`);
|
||||
return data;
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
// user-service.test.js
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import axios from "axios";
|
||||
import { getUser } from "./user-service";
|
||||
|
||||
vi.mock("axios");
|
||||
|
||||
describe("getUser", () => {
|
||||
it("returns user data on success", async () => {
|
||||
const mockUser = { id: 1, name: "Jay" };
|
||||
|
||||
// Make axios.get resolve with our fake response
|
||||
axios.get.mockResolvedValueOnce({ data: mockUser });
|
||||
|
||||
const result = await getUser(1);
|
||||
|
||||
expect(result).toEqual(mockUser);
|
||||
expect(axios.get).toHaveBeenCalledWith("/api/users/1");
|
||||
});
|
||||
|
||||
it("throws when the request fails", async () => {
|
||||
axios.get.mockRejectedValueOnce(new Error("Network error"));
|
||||
|
||||
await expect(getUser(1)).rejects.toThrow("Network error");
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Mocking an AxiosError
|
||||
|
||||
To test error-handling paths that inspect `error.response`, create an `AxiosError` instance directly:
|
||||
|
||||
```js
|
||||
import axios, { AxiosError } from "axios";
|
||||
import { vi } from "vitest";
|
||||
|
||||
const mockError = new AxiosError(
|
||||
"Not Found",
|
||||
"ERR_BAD_REQUEST",
|
||||
{}, // config
|
||||
{}, // request
|
||||
{ // response
|
||||
status: 404,
|
||||
statusText: "Not Found",
|
||||
data: { message: "User not found" },
|
||||
headers: {},
|
||||
config: {},
|
||||
}
|
||||
);
|
||||
|
||||
axios.get.mockRejectedValueOnce(mockError);
|
||||
```
|
||||
|
||||
## Using axios-mock-adapter
|
||||
|
||||
[axios-mock-adapter](https://github.com/ctimmerm/axios-mock-adapter) is a library that installs a custom adapter on your axios instance, intercepting requests at the adapter level. This means your interceptors still run, making it better for integration tests.
|
||||
|
||||
```bash
|
||||
npm install --save-dev axios-mock-adapter
|
||||
```
|
||||
|
||||
```js
|
||||
import axios from "axios";
|
||||
import MockAdapter from "axios-mock-adapter";
|
||||
|
||||
const mock = new MockAdapter(axios);
|
||||
|
||||
// Mock a GET request
|
||||
mock.onGet("/api/users/1").reply(200, { id: 1, name: "Jay" });
|
||||
|
||||
// Mock a POST request
|
||||
mock.onPost("/api/users").reply(201, { id: 2, name: "New User" });
|
||||
|
||||
// Mock a network error
|
||||
mock.onGet("/api/failing").networkError();
|
||||
|
||||
// Mock a timeout
|
||||
mock.onGet("/api/slow").timeout();
|
||||
```
|
||||
|
||||
Reset mocks between tests:
|
||||
|
||||
```js
|
||||
afterEach(() => {
|
||||
mock.reset(); // clear all registered handlers
|
||||
});
|
||||
```
|
||||
|
||||
## Testing interceptors
|
||||
|
||||
To test interceptors in isolation, create a fresh axios instance in your test:
|
||||
|
||||
```js
|
||||
import axios from "axios";
|
||||
import MockAdapter from "axios-mock-adapter";
|
||||
|
||||
describe("auth interceptor", () => {
|
||||
it("attaches a Bearer token to every request", async () => {
|
||||
const instance = axios.create();
|
||||
const mock = new MockAdapter(instance);
|
||||
|
||||
// Add your interceptor
|
||||
instance.interceptors.request.use((config) => {
|
||||
config.headers.set("Authorization", "Bearer test-token");
|
||||
return config;
|
||||
});
|
||||
|
||||
// Capture the request config by inspecting what mock received
|
||||
let capturedConfig;
|
||||
mock.onGet("/api/data").reply((config) => {
|
||||
capturedConfig = config;
|
||||
return [200, {}];
|
||||
});
|
||||
|
||||
await instance.get("/api/data");
|
||||
|
||||
expect(capturedConfig.headers["Authorization"]).toBe("Bearer test-token");
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Tips
|
||||
|
||||
- Always mock at the module level (or use `MockAdapter`) — avoid mocking individual methods on a shared instance, as state can leak between tests.
|
||||
- Use `mockResolvedValueOnce` / `mockRejectedValueOnce` in preference to `mockResolvedValue` so that tests are isolated and don't affect one another.
|
||||
- When testing retry logic, use `MockAdapter` so that the interceptor under test actually runs on each attempt.
|
||||
8
docs/pages/advanced/type-script.md
Normal file
@ -0,0 +1,8 @@
|
||||
# TypeScript
|
||||
|
||||
`axios` supports type definitions for TypeScript. These are included in the `axios` npm package by means of the `index.d.ts` file. Because axios dual publishes with an ESM default export and a CJS module.exports, there are some caveats:
|
||||
|
||||
- The recommended setting is to use "moduleResolution": "node16" (this is implied by "module": "node16"). Note that this requires TypeScript 4.7 or greater.
|
||||
- If you use ESM, your settings should be fine.
|
||||
- If you compile TypeScript to CJS and you can’t use "moduleResolution": "node16", you have to enable esModuleInterop.
|
||||
- If you use TypeScript to type check CJS JavaScript code, your only option is to use "moduleResolution": "node16".
|
||||
78
docs/pages/advanced/x-www-form-urlencoded-format.md
Normal file
@ -0,0 +1,78 @@
|
||||
# x-www-form-urlencoded format
|
||||
|
||||
## URLSearchParams
|
||||
|
||||
By default, axios serializes JavaScript objects to `JSON`. To send data in the [`application/x-www-form-urlencoded` format](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST) instead, you can use the [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) API, which is [supported](http://www.caniuse.com/#feat=urlsearchparams) in the vast majority of browsers,and [Node](https://nodejs.org/api/url.html#url_class_urlsearchparams) starting with v10 (released in 2018).
|
||||
|
||||
```js
|
||||
const params = new URLSearchParams({ foo: 'bar' });
|
||||
params.append('extraparam', 'value');
|
||||
axios.post('/foo', params);
|
||||
```
|
||||
|
||||
## Query string <Badge type="danger" text="Very old" />
|
||||
|
||||
For older browsers or environments without `URLSearchParams`, you can use the [`qs`](https://github.com/ljharb/qs) library to serialize objects to the `application/x-www-form-urlencoded` format.
|
||||
|
||||
```js
|
||||
const qs = require('qs');
|
||||
axios.post('/foo', qs.stringify({ bar: 123 }));
|
||||
```
|
||||
|
||||
In very old versions of Node.js, you can use the built-in `querystring` module that ships with Node.js. Note that this module has been deprecated in Node.js v16 — prefer `URLSearchParams` or `qs` for new code.
|
||||
|
||||
```js
|
||||
const querystring = require('querystring');
|
||||
axios.post('https://something.com/', querystring.stringify({ foo: 'bar' }));
|
||||
```
|
||||
|
||||
## Automatic serialization to URLSearchParams <Badge type="tip" text="New" />
|
||||
|
||||
Starting from v0.21.0, axios automatically serializes JavaScript objects to `URLSearchParams` if the `Content-Type` header is set to `application/x-www-form-urlencoded`. This means that you can pass a JavaScript object directly to the `data` property of the axios request config. For example when passing data to a `POST` request:
|
||||
|
||||
```js
|
||||
const data = {
|
||||
x: 1,
|
||||
arr: [1, 2, 3],
|
||||
arr2: [1, [2], 3],
|
||||
users: [
|
||||
{ name: 'Peter', surname: 'Griffin' },
|
||||
{ name: 'Thomas', surname: 'Anderson' },
|
||||
],
|
||||
};
|
||||
|
||||
await axios.postForm('https://postman-echo.com/post', data, {
|
||||
headers: { 'content-type': 'application/x-www-form-urlencoded' },
|
||||
});
|
||||
```
|
||||
|
||||
The `data` object will be automatically serialized to `URLSearchParams` and sent in the `application/x-www-form-urlencoded` format. The server will receive the following data:
|
||||
|
||||
```json
|
||||
{
|
||||
"x": "1",
|
||||
"arr[]": ["1", "2", "3"],
|
||||
"arr2[0]": "1",
|
||||
"arr2[1][0]": "2",
|
||||
"arr2[2]": "3",
|
||||
"users[0][name]": "Peter",
|
||||
"users[0][surname]": "Griffin",
|
||||
"users[1][name]": "Thomas",
|
||||
"users[1][surname]": "Anderson"
|
||||
}
|
||||
```
|
||||
|
||||
If your backend body-parser (like `body-parser` of `express.js`) supports nested objects decoding, you will get the same object on the server-side automatically
|
||||
|
||||
```js
|
||||
var app = express();
|
||||
|
||||
app.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies
|
||||
|
||||
app.post('/', function (req, res, next) {
|
||||
// echo body as JSON
|
||||
res.send(JSON.stringify(req.body));
|
||||
});
|
||||
|
||||
server = app.listen(3000);
|
||||
```
|
||||
226
docs/pages/getting-started/examples/commonjs.md
Normal file
@ -0,0 +1,226 @@
|
||||
# JavaScript examples
|
||||
|
||||
## Importing the library
|
||||
|
||||
To import the library in a CommonJS environment, you can use the `require` function, or the `import` statement if you are using a bundler like Webpack or Rollup.
|
||||
|
||||
#### No bundler
|
||||
|
||||
```js
|
||||
const axios = require("axios");
|
||||
```
|
||||
|
||||
#### With bundler (webpack, rollup, vite, etc)
|
||||
|
||||
```js
|
||||
import axios from "axios";
|
||||
```
|
||||
|
||||
## Using then/catch/finally
|
||||
|
||||
Since axios returns a promise at it's core you can choose to use callbacks with `then`, `catch`, and `finally` to handle your response data, errors, and completion.
|
||||
|
||||
### Get request
|
||||
|
||||
```js
|
||||
axios
|
||||
.get("https://jsonplaceholder.typicode.com/posts", {
|
||||
params: {
|
||||
postId: 5,
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
console.log(response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
})
|
||||
.finally(() => {
|
||||
console.log("Request completed");
|
||||
});
|
||||
```
|
||||
|
||||
### Post request
|
||||
|
||||
```js
|
||||
axios
|
||||
.post("https://jsonplaceholder.typicode.com/posts", {
|
||||
title: "foo",
|
||||
body: "bar",
|
||||
userId: 1,
|
||||
})
|
||||
.then((response) => {
|
||||
console.log(response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
})
|
||||
.finally(() => {
|
||||
console.log("Request completed");
|
||||
});
|
||||
```
|
||||
|
||||
### Put request
|
||||
|
||||
```js
|
||||
axios
|
||||
.put("https://jsonplaceholder.typicode.com/posts/1", {
|
||||
title: "foo",
|
||||
body: "bar",
|
||||
userId: 1,
|
||||
})
|
||||
.then((response) => {
|
||||
console.log(response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
})
|
||||
.finally(() => {
|
||||
console.log("Request completed");
|
||||
});
|
||||
```
|
||||
|
||||
### Patch request
|
||||
|
||||
```js
|
||||
axios
|
||||
.patch("https://jsonplaceholder.typicode.com/posts/1", {
|
||||
title: "foo",
|
||||
})
|
||||
.then((response) => {
|
||||
console.log(response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
})
|
||||
.finally(() => {
|
||||
console.log("Request completed");
|
||||
});
|
||||
```
|
||||
|
||||
### Delete request
|
||||
|
||||
```js
|
||||
axios
|
||||
.delete("https://jsonplaceholder.typicode.com/posts/1")
|
||||
.then((response) => {
|
||||
console.log(response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
})
|
||||
.finally(() => {
|
||||
console.log("Request completed");
|
||||
});
|
||||
```
|
||||
|
||||
## Using async/await
|
||||
|
||||
Another way to handle promises is by using `async` and `await`. This allows you to use try/catch/finally blocks to handle errors and completion. This can make your code more readable and easier to understand, this also helps prevents so called callback hell.
|
||||
|
||||
::: tip
|
||||
Note: async/await is part of ECMAScript 2017 and is not supported in Internet Explorer and older browsers, so use with caution.
|
||||
:::
|
||||
|
||||
### Get request
|
||||
|
||||
```js
|
||||
const getPosts = async () => {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
"https://jsonplaceholder.typicode.com/posts",
|
||||
{
|
||||
params: {
|
||||
postId: 5,
|
||||
},
|
||||
}
|
||||
);
|
||||
console.log(response.data);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
console.log("Request completed");
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Post request
|
||||
|
||||
```js
|
||||
const createPost = async () => {
|
||||
try {
|
||||
const response = await axios.post(
|
||||
"https://jsonplaceholder.typicode.com/posts",
|
||||
{
|
||||
title: "foo",
|
||||
body: "bar",
|
||||
userId: 1,
|
||||
}
|
||||
);
|
||||
console.log(response.data);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
console.log("Request completed");
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Put request
|
||||
|
||||
```js
|
||||
const updatePost = async () => {
|
||||
try {
|
||||
const response = await axios.put(
|
||||
"https://jsonplaceholder.typicode.com/posts/1",
|
||||
{
|
||||
title: "foo",
|
||||
body: "bar",
|
||||
userId: 1,
|
||||
}
|
||||
);
|
||||
console.log(response.data);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
console.log("Request completed");
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Patch request
|
||||
|
||||
```js
|
||||
const updatePost = async () => {
|
||||
try {
|
||||
const response = await axios.patch(
|
||||
"https://jsonplaceholder.typicode.com/posts/1",
|
||||
{
|
||||
title: "foo",
|
||||
}
|
||||
);
|
||||
console.log(response.data);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
console.log("Request completed");
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Delete request
|
||||
|
||||
```js
|
||||
const deletePost = async () => {
|
||||
try {
|
||||
const response = await axios.delete(
|
||||
"https://jsonplaceholder.typicode.com/posts/1"
|
||||
);
|
||||
console.log(response.data);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
console.log("Request completed");
|
||||
}
|
||||
};
|
||||
```
|
||||
139
docs/pages/getting-started/examples/typescript.md
Normal file
@ -0,0 +1,139 @@
|
||||
# TypeScript example
|
||||
|
||||
## Importing types
|
||||
|
||||
axios ships with TypeScript definitions out of the box. You can import the types you need directly from `"axios"`:
|
||||
|
||||
```ts
|
||||
import axios from "axios";
|
||||
import type { AxiosRequestConfig, AxiosResponse, AxiosError } from "axios";
|
||||
```
|
||||
|
||||
## Typing a request
|
||||
|
||||
Use a generic type parameter on the response to tell TypeScript what shape your data will have:
|
||||
|
||||
```ts
|
||||
import axios from "axios";
|
||||
|
||||
type Post = {
|
||||
userId: number;
|
||||
id: number;
|
||||
title: string;
|
||||
body: string;
|
||||
};
|
||||
|
||||
const response = await axios.get<Post>("https://jsonplaceholder.typicode.com/posts/1");
|
||||
|
||||
console.log(response.data.title); // TypeScript knows this is a string
|
||||
```
|
||||
|
||||
## Typing a function
|
||||
|
||||
Wrap requests in functions with explicit return types for maximum type safety:
|
||||
|
||||
```ts
|
||||
import axios, { AxiosResponse } from "axios";
|
||||
|
||||
type Post = {
|
||||
userId: number;
|
||||
id: number;
|
||||
title: string;
|
||||
body: string;
|
||||
};
|
||||
|
||||
const getPost = async (id: number): Promise<Post> => {
|
||||
const response = await axios.get<Post>(
|
||||
`https://jsonplaceholder.typicode.com/posts/${id}`
|
||||
);
|
||||
return response.data;
|
||||
};
|
||||
```
|
||||
|
||||
## Typing a POST request
|
||||
|
||||
You can type both the request body and the expected response:
|
||||
|
||||
```ts
|
||||
type CreatePostBody = {
|
||||
title: string;
|
||||
body: string;
|
||||
userId: number;
|
||||
};
|
||||
|
||||
type CreatePostResponse = CreatePostBody & { id: number };
|
||||
|
||||
const createPost = async (data: CreatePostBody): Promise<CreatePostResponse> => {
|
||||
const response = await axios.post<CreatePostResponse>(
|
||||
"https://jsonplaceholder.typicode.com/posts",
|
||||
data
|
||||
);
|
||||
return response.data;
|
||||
};
|
||||
```
|
||||
|
||||
## Typed axios instance
|
||||
|
||||
Create a typed instance so your base URL and headers are baked in:
|
||||
|
||||
```ts
|
||||
import axios from "axios";
|
||||
import type { AxiosInstance } from "axios";
|
||||
|
||||
const api: AxiosInstance = axios.create({
|
||||
baseURL: "https://api.example.com",
|
||||
timeout: 5000,
|
||||
});
|
||||
```
|
||||
|
||||
## Typed interceptors
|
||||
|
||||
Use `InternalAxiosRequestConfig` (not `AxiosRequestConfig`) for request interceptors in v1.x:
|
||||
|
||||
```ts
|
||||
import axios from "axios";
|
||||
import type { InternalAxiosRequestConfig, AxiosResponse } from "axios";
|
||||
|
||||
api.interceptors.request.use((config: InternalAxiosRequestConfig) => {
|
||||
config.headers.set("Authorization", `Bearer ${getToken()}`);
|
||||
return config;
|
||||
});
|
||||
|
||||
api.interceptors.response.use(
|
||||
(response: AxiosResponse) => response,
|
||||
(error) => Promise.reject(error)
|
||||
);
|
||||
```
|
||||
|
||||
## Typing errors
|
||||
|
||||
Use `axios.isAxiosError()` to narrow the type of a caught error:
|
||||
|
||||
```ts
|
||||
import axios, { AxiosError } from "axios";
|
||||
|
||||
type ApiError = {
|
||||
message: string;
|
||||
code: number;
|
||||
};
|
||||
|
||||
try {
|
||||
await axios.get("/api/protected-resource");
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError<ApiError>(error)) {
|
||||
// error.response?.data is typed as ApiError
|
||||
console.error(error.response?.data.message);
|
||||
console.error(error.response?.status);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## TypeScript configuration notes
|
||||
|
||||
Because axios dual-publishes ESM and CJS, there are a few caveats depending on your setup:
|
||||
|
||||
- The recommended setting is `"moduleResolution": "node16"` (implied by `"module": "node16"`). This requires TypeScript 4.7 or greater.
|
||||
- If you compile TypeScript to CJS and cannot use `"moduleResolution": "node16"`, enable `"esModuleInterop": true`.
|
||||
- If you use TypeScript to type-check CJS JavaScript code, your only option is `"moduleResolution": "node16"`.
|
||||
42
docs/pages/getting-started/features.md
Normal file
@ -0,0 +1,42 @@
|
||||
# Features
|
||||
|
||||
axios is a powerful HTTP client that provides a simple and easy-to-use API for making HTTP requests. It supports all modern browsers and is widely used in the JavaScript community. Here are some of the features that make axios a great choice for your next project.
|
||||
|
||||
## Isomorphic
|
||||
|
||||
axios is a universal HTTP client that can be used in both the browser and Node.js. This means you can use axios to make API requests from your frontend code as well as your backend code. This makes axios a great choice for building progressive web apps, single-page applications, and server-side rendered applications.
|
||||
|
||||
axios is also a great choice for teams that work on both frontend and backend code. By using axios for both frontend and backend code, you can have a consistent API for making HTTP requests, which can help reduce the complexity of your codebase.
|
||||
|
||||
## Fetch support <Badge type="tip" text="New" />
|
||||
|
||||
axios provides first class support for the Fetch API, which is a modern replacement for the XHR API. The adapter is optional and can be used through configuration. The same API is maintained for both the XHR and Fetch adapters, which makes it easy to adopt the Fetch API in your codebase without changing your existing code.
|
||||
|
||||
## Browser support
|
||||
|
||||
axios supports all modern and select older browsers, including Chrome, Firefox, Safari, and Edge. axios is a great choice for building web applications that need to support a wide range of browsers.
|
||||
|
||||
## Node.js support
|
||||
|
||||
axios also supports a wide range Node.js versions with tested compatibility as far back as v12.x, making it a good choice in environments where upgrading to the latest Node.js version might not be possible or practical.
|
||||
|
||||
In addition to Node.js, axios has Bun and Deno smoke tests that validate key runtime behavior and improve confidence in cross-runtime compatibility.
|
||||
|
||||
## Additional features
|
||||
|
||||
- Supports the Promise API
|
||||
- Intercept request and response
|
||||
- Transform request and response data
|
||||
- Abort controller
|
||||
- Timeouts
|
||||
- Query parameters serialization with support for nested entries
|
||||
- Automatic request body serialization to:
|
||||
- JSON (application/json)
|
||||
- Multipart / FormData (multipart/form-data)
|
||||
- URL encoded form (application/x-www-form-urlencoded)
|
||||
- Posting HTML forms as JSON
|
||||
- Automatic JSON data handling in response
|
||||
- Progress capturing for browsers and node.js with extra info (speed rate, remaining time)
|
||||
- Setting bandwidth limits for node.js
|
||||
- Compatible with spec-compliant FormData and Blob (including node.js)
|
||||
- Client side support for protecting against XSRF
|
||||
73
docs/pages/getting-started/first-steps.md
Normal file
@ -0,0 +1,73 @@
|
||||
# First steps
|
||||
|
||||
Welcome to the axios documentation! This guide will help you get started with axios and make your first API request. If you're new to axios, we recommend starting here.
|
||||
|
||||
## Installing
|
||||
|
||||
You can use axios in your project in a few different ways. The most common way is to install it from npm and include it in your project. But we also support jsDelivr, unpkg, and more.
|
||||
|
||||
#### Using npm
|
||||
|
||||
```bash
|
||||
npm install axios
|
||||
```
|
||||
|
||||
#### Using pnpm
|
||||
|
||||
```bash
|
||||
pnpm install axios
|
||||
```
|
||||
|
||||
#### Using yarn
|
||||
|
||||
```bash
|
||||
yarn add axios
|
||||
```
|
||||
|
||||
#### Using bun
|
||||
|
||||
```bash
|
||||
bun add axios
|
||||
```
|
||||
|
||||
#### Using deno
|
||||
|
||||
```bash
|
||||
deno install npm:axios
|
||||
```
|
||||
|
||||
#### Using jsDelivr
|
||||
|
||||
When using jsDelivr we recommend using the minified version as well as pinning the version number to avoid unexpected changes. If you would like to use the latest version you can do so by dropping the version number. This is strongly discouraged for production use as it can lead to unexpected changes in your application.
|
||||
|
||||
```html
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios@<x.x.x>/dist/axios.min.js"></script>
|
||||
```
|
||||
|
||||
#### Using unpkg
|
||||
|
||||
When using unpkg we recommend using the minified version as well as pinning the version number to avoid unexpected changes. If you would like to use the latest version you can do so by dropping the version number. This is strongly discouraged for production use as it can lead to unexpected changes in your application.
|
||||
|
||||
```html
|
||||
<script src="https://unpkg.com/axios@<x.x.x>/dist/axios.min.js"></script>
|
||||
```
|
||||
|
||||
## Making your first request
|
||||
|
||||
An axios request can be made in as few as two lines of code. Making your first request with axios is very simple. You can make a request to any API by providing the URL and method. For example, to make a GET request to the JSONPlaceholder API, you can use the following code:
|
||||
|
||||
```js
|
||||
import axios from "axios";
|
||||
|
||||
const response = await axios.get(
|
||||
"https://jsonplaceholder.typicode.com/posts/1"
|
||||
);
|
||||
|
||||
console.log(response.data);
|
||||
```
|
||||
|
||||
axios provides a simple API for making requests. You can use the `axios.get` method to make a GET request, the `axios.post` method to make a POST request, and so on. You can also use the `axios.request` method to make a request with any method.
|
||||
|
||||
## Next steps
|
||||
|
||||
Now that you've made your first request with axios, you're ready to start exploring the rest of the axios documentation. You can learn more about making requests, handling responses, and using axios in your projects. Check out the rest of the documentation to learn more.
|
||||
92
docs/pages/getting-started/upgrade-guide.md
Normal file
@ -0,0 +1,92 @@
|
||||
# Upgrade guide
|
||||
|
||||
This guide is intended to help you upgrade your project from one version of the framework to another. It is recommended to read the release notes for each major version you are upgrading from/to, as they may contain important information about breaking changes.
|
||||
|
||||
## Upgrading from v0.x to v1.x
|
||||
|
||||
### Changes to the import statement
|
||||
|
||||
In v1.x, the import statement has been changed to use the `default` export. This means that you will need to update your import statements to use the `default` export.
|
||||
|
||||
```diff
|
||||
- import { axios } from "axios";
|
||||
+ import axios from "axios";
|
||||
```
|
||||
|
||||
### Changes to the interceptor system
|
||||
|
||||
In v1.x you need to leverage the type `InternalAxiosRequestConfig` to type the `config` parameter in the `request` interceptor. This is because the `config` parameter is now typed as `InternalAxiosRequestConfig` instead of the public `AxiosRequestConfig` type.
|
||||
|
||||
```diff
|
||||
- axios.interceptors.request.use((config: AxiosRequestConfig) => {
|
||||
+ axios.interceptors.request.use((config: InternalAxiosRequestConfig) => {
|
||||
return config;
|
||||
});
|
||||
```
|
||||
|
||||
### Changes to request headers shape
|
||||
|
||||
In v1.x, the shape of the request headers has been changed to drop the `common` property. This means that you will need to update your code to use the new shape of the request headers as follows:
|
||||
|
||||
```diff
|
||||
- if (request.headers?.common?.Authorization) {
|
||||
- request.headers.common.Authorization = ...
|
||||
+ if (request.headers?.Authorization) {
|
||||
+ request.headers.Authorization = ...
|
||||
```
|
||||
|
||||
Default headers that were previously under `common`, `get`, `post`, etc. are now set directly on `axios.defaults.headers`:
|
||||
|
||||
```diff
|
||||
- axios.defaults.headers.common["Accept"] = "application/json";
|
||||
+ axios.defaults.headers["Accept"] = "application/json";
|
||||
```
|
||||
|
||||
### Multipart form data
|
||||
|
||||
If a request includes a `FormData` payload, the `Content-Type: multipart/form-data` header is now set automatically. Remove any manual header to avoid duplicates:
|
||||
|
||||
```diff
|
||||
- axios.post("/upload", formData, {
|
||||
- headers: { "Content-Type": "multipart/form-data" },
|
||||
- });
|
||||
+ axios.post("/upload", formData);
|
||||
```
|
||||
|
||||
If you explicitly set `Content-Type: application/json`, axios will now automatically serialize the data to JSON.
|
||||
|
||||
### Parameter serialization
|
||||
|
||||
v1.x introduced several breaking changes to how URL parameters are serialized. The most important ones:
|
||||
|
||||
**`params` are now percent-encoded by default.** If your backend expected raw brackets from qs-style encoding, you may need to configure a custom serializer:
|
||||
|
||||
```js
|
||||
import qs from 'qs';
|
||||
|
||||
axios.create({
|
||||
paramsSerializer: {
|
||||
serialize: (params) => qs.stringify(params, { arrayFormat: 'brackets' }),
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
**Nested objects in `params` are now serialized with bracket notation** (`foo[bar]=1`) rather than dot notation. If your backend expected dot notation, use a custom serializer.
|
||||
|
||||
**`null` and `undefined` params** are now handled consistently: `null` values are serialized as empty strings, while `undefined` values are omitted entirely.
|
||||
|
||||
For the full parameter serialization config options, see the [Request config](/pages/advanced/request-config) page.
|
||||
|
||||
### Internals no longer exported
|
||||
|
||||
We have elected to no longer export the internals of axios. This means that you will need to update your code to only use the public API of axios. This change was made to simplify the API and reduce the surface area of axios, allowing us to make changes to the internals without declaring them as breaking changes.
|
||||
|
||||
Please review the [API reference](/pages/advanced/api-reference) on this site for the latest information on the public API of axios.
|
||||
|
||||
### Request config
|
||||
|
||||
We have made changes to the request config object. Please review the [config reference](/pages/advanced/request-config) on this site for the latest information.
|
||||
|
||||
### Missed breaking changes
|
||||
|
||||
This guide is not exhaustive and may not cover all breaking changes. Should you encounter any issue, please open an issue on the [docs GitHub repository](https://github.com/axios/docs) with the label `breaking change`.
|
||||
23
docs/pages/misc/security.md
Normal file
@ -0,0 +1,23 @@
|
||||
# Security policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you believe you have found a security vulnerability in the project, please report it to us as described below. We take all security vulnerabilities seriously. If you have found a vulnerability in a third-party library, please report it to the maintainers of that library.
|
||||
|
||||
## Reporting Process
|
||||
|
||||
Please do not report security vulnerabilities through public GitHub issues. Please use the official security channel on GitHub by logging a [security advisory](https://github.com/axios/axios/security).
|
||||
## Disclosure Policy
|
||||
|
||||
When we receive a security vulnerability report, we will assign it a primary handler. This person is responsible for the vulnerability report. The handler will confirm the problem and determine the affected versions. The handler will then evaluate the problem and determine the severity of the issue. The handler will develop a fix for the problem and prepare a release. The handler will notify the reporter when the fix is ready to be announced.
|
||||
|
||||
## Security Updates
|
||||
|
||||
Security updates will be released as soon as possible after the patch has been developed and tested. We will notify users of the release via the project’s GitHub repository. We will also publish the release notes and security advisories on the project’s GitHub releases page. We will also deprecate all versions that contain the security vulnerability.
|
||||
|
||||
## Security Partners and Acknowledgements
|
||||
|
||||
We would like to thank the following security researchers for working with us to help make the project safe for everyone:
|
||||
|
||||
- [Socket Dev](https://socket.dev/)
|
||||
- [GitHub Security Lab](https://securitylab.github.com/)
|
||||
44
docs/pages/misc/semver.md
Normal file
@ -0,0 +1,44 @@
|
||||
# Semantic versioning
|
||||
|
||||
Semantic versioning is a versioning scheme that is used to communicate the nature of changes in a software package. It is a simple set of rules and requirements that dictate how version numbers are assigned and incremented.
|
||||
|
||||
## axios versioning
|
||||
|
||||
axios follows the semantic versioning scheme. This means that each version of axios is assigned a version number that consists of three parts: major, minor, and patch. The version number is incremented based on the nature of the changes in the release.
|
||||
|
||||
In the past axios may have at times not strictly followed semantic versioning, however going forward there will be a much stricter adherence to the semantic versioning scheme to ensure that users can rely on the version numbers to communicate the nature of changes in the library.
|
||||
|
||||
A brief overview of the versioning scheme is provided below.
|
||||
|
||||
## Version format
|
||||
|
||||
A semantic version number consists of three parts:
|
||||
|
||||
1. Major version
|
||||
2. Minor version
|
||||
3. Patch version
|
||||
|
||||
The version number is written as `MAJOR.MINOR.PATCH`. Each part of the version number has a specific meaning:
|
||||
|
||||
- **Major version**: Incremented when you make incompatible API changes.
|
||||
- **Minor version**: Incremented when you add functionality in a backwards-compatible manner.
|
||||
- **Patch version**: Incremented when you make backwards-compatible bug fixes.
|
||||
|
||||
## Pre-release versions
|
||||
|
||||
In addition to the three parts of the version number, you can append a pre-release version. This is done by adding a hyphen and a series of dot-separated identifiers immediately following the patch version. For example, `1.0.0-alpha.1`.
|
||||
|
||||
Pre-release versions are used to indicate that a version is unstable and might not satisfy the intended compatibility requirements as denoted by the version number. Pre-release versions are ordered based on the order of the identifiers. For example, `1.0.0-alpha.1` comes before `1.0.0-alpha.2`.
|
||||
|
||||
## Version ranges
|
||||
|
||||
When you specify a version range for a package, you can use a variety of operators to specify the range of versions that are acceptable. The following operators are available:
|
||||
|
||||
- `>`: Greater than
|
||||
- `<`: Less than
|
||||
- `>=`: Greater than or equal to
|
||||
- `<=`: Less than or equal to
|
||||
- `~`: Approximately equal to
|
||||
- `^`: Compatible with
|
||||
|
||||
For example, `^1.0.0` means that any version greater than or equal to `1.0.0` and less than `2.0.0` is acceptable.
|
||||
185
docs/pages/misc/sponsors.md
Normal file
@ -0,0 +1,185 @@
|
||||
---
|
||||
layout: page
|
||||
---
|
||||
|
||||
<script setup>
|
||||
import allSponsors from '../../data/sponsors.json';
|
||||
|
||||
const sponsors = [...allSponsors.platinum, ...allSponsors.gold, ...allSponsors.silver, ...allSponsors.bronze, ...allSponsors.backer];
|
||||
|
||||
const capitalizeFirstLetter = (word) => {
|
||||
return String(word).charAt(0).toUpperCase() + String(word).slice(1);
|
||||
};
|
||||
</script>
|
||||
|
||||
<div style="margin: 1rem 7rem; max-width: 1200px;">
|
||||
<h1 style="line-height: 64px; font-size: 32px; letter-spacing: -0.4px; font-weight: 600; margin-top: 2rem;">Sponsors</h1>
|
||||
<p>Axios is supported by the following organizations. If you'd like to sponsor Axios, please see our <a href="https://opencollective.com/axios" target="_blank" style="color: #007bff;">open collective page</a> for more information.</p>
|
||||
|
||||
<div :class="$style.sponsorCloudWrapper">
|
||||
<div :class="$style.sponsorCloudContainer">
|
||||
<div :class="$style.sponsorCloudGrid">
|
||||
<div :class="$style.sponsorCloudImageWrapper" v-for="(sponsor, key) in sponsors" :key="sponsor.name">
|
||||
<img :src="sponsor.imageUrl" :alt="sponsor.name" style="max-height: 72px; width: 100%; object-fit: contain;" />
|
||||
<dl>
|
||||
<dd :class="$style.sponsorTag">
|
||||
<span :class="$style[`tagSponsor${capitalizeFirstLetter(sponsor.tier)}`]">{{ capitalizeFirstLetter(sponsor.tier) }}</span>
|
||||
</dd>
|
||||
</dl>
|
||||
<a :href="sponsor.website" rel="noopener noreferrer" target="_blank" :class="$style.sponsorName">{{ sponsor.name }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style module>
|
||||
.sponsorCloudWrapper {
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.sponsorCloudContainer {
|
||||
max-width: 80rem;
|
||||
}
|
||||
|
||||
.sponsorCloudGrid {
|
||||
display: grid;
|
||||
overflow: hidden;
|
||||
margin-left: -1.5rem;
|
||||
margin-right: -1.5rem;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 0.125rem;
|
||||
}
|
||||
|
||||
.sponsorCloudImageWrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 2rem;
|
||||
background-color: rgb(156 163 175 / 0.05);
|
||||
}
|
||||
|
||||
.sponsorTag {
|
||||
margin-top: 0.75rem;
|
||||
margin-inline-start: 0px;
|
||||
}
|
||||
|
||||
.sponsorName {
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
height: 3rem;
|
||||
margin-top: 1rem !important;
|
||||
font-size: 0.875rem !important;
|
||||
line-height: 1.25rem !important;
|
||||
font-weight: 600 !important;
|
||||
color: var(--vp-c-text-1) !important;
|
||||
text-wrap-style: pretty;
|
||||
display: -webkit-box;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tagSponsorPlatinum {
|
||||
display: inline-flex;
|
||||
padding-top: 0.25rem;
|
||||
padding-bottom: 0.25rem;
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
align-items: center;
|
||||
border-radius: 9999px;
|
||||
box-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||
--tw-ring-inset: inset;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1rem;
|
||||
font-weight: 500;
|
||||
color: #000;
|
||||
background-color: #E5E7EB;
|
||||
}
|
||||
|
||||
.tagSponsorGold {
|
||||
display: inline-flex;
|
||||
padding-top: 0.25rem;
|
||||
padding-bottom: 0.25rem;
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
align-items: center;
|
||||
border-radius: 9999px;
|
||||
box-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||
--tw-ring-inset: inset;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1rem;
|
||||
font-weight: 500;
|
||||
color: #FFF;
|
||||
background-color: #F59E0B;
|
||||
}
|
||||
|
||||
.tagSponsorSilver {
|
||||
display: inline-flex;
|
||||
padding-top: 0.25rem;
|
||||
padding-bottom: 0.25rem;
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
align-items: center;
|
||||
border-radius: 9999px;
|
||||
box-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||
--tw-ring-inset: inset;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1rem;
|
||||
font-weight: 500;
|
||||
color: #FFF;
|
||||
background-color: #9CA3AF;
|
||||
}
|
||||
.tagSponsorBronze {
|
||||
display: inline-flex;
|
||||
padding-top: 0.25rem;
|
||||
padding-bottom: 0.25rem;
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
align-items: center;
|
||||
border-radius: 9999px;
|
||||
box-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||
--tw-ring-inset: inset;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1rem;
|
||||
font-weight: 500;
|
||||
color: #FFF;
|
||||
background-color: #854D0E;
|
||||
}
|
||||
|
||||
.tagSponsorBacker {
|
||||
display: inline-flex;
|
||||
padding-top: 0.25rem;
|
||||
padding-bottom: 0.25rem;
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
align-items: center;
|
||||
border-radius: 9999px;
|
||||
box-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||
--tw-ring-inset: inset;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1rem;
|
||||
font-weight: 500;
|
||||
color: #FFF;
|
||||
background-color: #2563EB;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.sponsorCloudGrid {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
border-radius: 1rem;
|
||||
}
|
||||
|
||||
.sponsorCloudImageWrapper {
|
||||
padding: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.sponsorCloudGrid {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
</style>
|
||||
12
docs/patches/@splidejs+splide+4.1.4.patch
Normal file
@ -0,0 +1,12 @@
|
||||
diff --git a/node_modules/@splidejs/splide/package.json b/node_modules/@splidejs/splide/package.json
|
||||
index 677e6d0..d274e39 100644
|
||||
--- a/node_modules/@splidejs/splide/package.json
|
||||
+++ b/node_modules/@splidejs/splide/package.json
|
||||
@@ -4,6 +4,7 @@
|
||||
"description": "Splide is a lightweight, flexible and accessible slider/carousel. No dependencies, no Lighthouse errors.",
|
||||
"author": "Naotoshi Fujita",
|
||||
"license": "MIT",
|
||||
+ "type": "module",
|
||||
"main": "dist/js/splide.cjs.js",
|
||||
"module": "dist/js/splide.esm.js",
|
||||
"types": "dist/types/index.d.ts",
|
||||
BIN
docs/public/android-chrome-192x192.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
docs/public/android-chrome-512x512.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
docs/public/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
docs/public/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 277 B |
BIN
docs/public/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
docs/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
10
docs/public/logo-light.svg
Normal file
|
After Width: | Height: | Size: 12 KiB |
10
docs/public/logo.svg
Normal file
|
After Width: | Height: | Size: 12 KiB |
19
docs/public/site.webmanifest
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "axios | promise based HTTP client",
|
||||
"short_name": "axios",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#552cdb",
|
||||
"background_color": "#552cdb",
|
||||
"display": "standalone"
|
||||
}
|
||||
1
docs/public/words-light.svg
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
1
docs/public/words.svg
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
294
docs/scripts/process-sponsors.js
Normal file
@ -0,0 +1,294 @@
|
||||
import fs from 'node:fs';
|
||||
import axios from 'axios';
|
||||
import { printSuccessMessage, printErrorMessage, printInfoMessage } from './utils.js';
|
||||
|
||||
/**
|
||||
* Special configuration for processing sponsor data.
|
||||
*/
|
||||
const config = {
|
||||
legacyAgreements: {
|
||||
Stytch: 'gold',
|
||||
Airbnb: 'silver',
|
||||
Descope: 'gold',
|
||||
'Principal Financial Group': 'gold',
|
||||
},
|
||||
sponsorsToIgnore: ['axios'],
|
||||
};
|
||||
|
||||
/**
|
||||
* The GraphQL query to get all sponsors.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
const getAllSponsorsQuery = `
|
||||
query Account {
|
||||
account(githubHandle: "https://github.com/axios") {
|
||||
name
|
||||
slug
|
||||
members(role: BACKER) {
|
||||
totalCount
|
||||
nodes {
|
||||
account {
|
||||
name
|
||||
slug
|
||||
socialLinks {
|
||||
type
|
||||
url
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
website
|
||||
imageUrl
|
||||
legalName
|
||||
description
|
||||
}
|
||||
tier {
|
||||
name
|
||||
}
|
||||
totalDonations {
|
||||
value
|
||||
currency
|
||||
}
|
||||
since
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* The GraphQL query to get all active sponsors.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
const getActiveSponsorsQuery = `
|
||||
query Account {
|
||||
account(githubHandle: "https://github.com/axios") {
|
||||
orders(onlyActiveSubscriptions: true, onlySubscriptions: true, frequency: MONTHLY, status: ACTIVE) {
|
||||
totalCount
|
||||
nodes {
|
||||
tier {
|
||||
name
|
||||
}
|
||||
fromAccount {
|
||||
id
|
||||
name
|
||||
socialLinks {
|
||||
type
|
||||
url
|
||||
}
|
||||
imageUrl
|
||||
legalName
|
||||
description
|
||||
website
|
||||
slug
|
||||
}
|
||||
amount {
|
||||
currency
|
||||
value
|
||||
}
|
||||
totalDonations {
|
||||
value
|
||||
currency
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* Gets all sponsors.
|
||||
*
|
||||
* @returns {Promise<any>} The sponsors.
|
||||
*/
|
||||
const getAllSponsors = async () => {
|
||||
printInfoMessage('getting all sponsors...');
|
||||
const response = await axios.post('https://api.opencollective.com/graphql/v2', {
|
||||
query: getAllSponsorsQuery,
|
||||
});
|
||||
|
||||
return response.data.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets all active sponsors.
|
||||
*
|
||||
* @returns {Promise<any>} The active sponsors.
|
||||
*/
|
||||
const getActiveSponsors = async () => {
|
||||
printInfoMessage('getting active sponsors...');
|
||||
const response = await axios.post('https://api.opencollective.com/graphql/v2', {
|
||||
query: getActiveSponsorsQuery,
|
||||
});
|
||||
|
||||
return response.data.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds a URL with UTM parameters.
|
||||
*
|
||||
* @param {string} url - The URL to build.
|
||||
* @param {boolean} bypass - Whether to bypass UTM parameters.
|
||||
* @returns {string} The URL with UTM parameters.
|
||||
*/
|
||||
const buildLinks = (url, bypass = false) => {
|
||||
if (bypass) {
|
||||
return url;
|
||||
}
|
||||
|
||||
try {
|
||||
const urlObject = new URL(url);
|
||||
|
||||
const { searchParams } = urlObject;
|
||||
|
||||
searchParams.set('utm_source', 'axios_docs_website');
|
||||
searchParams.set('utm_medium', 'website');
|
||||
searchParams.set('utm_campaign', 'axios_open_collective_sponsorship');
|
||||
|
||||
return urlObject.toString();
|
||||
} catch {
|
||||
return url;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats all active sponsors.
|
||||
*
|
||||
* @param {any} sponsorsData - The sponsors data.
|
||||
* @returns {any} The formatted sponsor data.
|
||||
*/
|
||||
const formatActiveSponsorData = (sponsorsData) => {
|
||||
const getSponsorTier = (sponsor) => {
|
||||
if (config.legacyAgreements[sponsor.fromAccount.name]) {
|
||||
return config.legacyAgreements[sponsor.fromAccount.name];
|
||||
}
|
||||
|
||||
if (sponsor.tier?.name.toLowerCase() === 'silver sponsor') {
|
||||
return 'silver';
|
||||
}
|
||||
|
||||
return sponsor.tier?.name.toLowerCase() || 'backer';
|
||||
};
|
||||
|
||||
const processedData = sponsorsData
|
||||
.map((sponsor) => ({
|
||||
name: sponsor.fromAccount.name ?? 'Backer',
|
||||
imageUrl: sponsor.fromAccount.imageUrl ?? null,
|
||||
description: sponsor.fromAccount.description ?? null,
|
||||
tier: getSponsorTier(sponsor),
|
||||
slug: sponsor.fromAccount.slug,
|
||||
website: sponsor.fromAccount.website
|
||||
? buildLinks(sponsor.fromAccount.website)
|
||||
: (buildLinks(
|
||||
sponsor.fromAccount.socialLinks.find((link) => link.type === 'WEBSITE')?.url
|
||||
) ?? null),
|
||||
twitter:
|
||||
buildLinks(sponsor.fromAccount.socialLinks.find((link) => link.type === 'TWITTER')?.url) ??
|
||||
null,
|
||||
}))
|
||||
.filter((sponsor) => !config.sponsorsToIgnore.includes(sponsor.name));
|
||||
|
||||
return processedData;
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats all sponsors irrespective state.
|
||||
*
|
||||
* @param {any} sponsorsData - The sponsors data.
|
||||
* @returns {any} The formatted sponsor data.
|
||||
*/
|
||||
const formatAllSponsorData = (sponsorsData) => {
|
||||
const getSponsorTier = (sponsor) => {
|
||||
if (config.legacyAgreements[sponsor.account.name]) {
|
||||
return config.legacyAgreements[sponsor.account.name];
|
||||
}
|
||||
|
||||
if (sponsor.tier?.name.toLowerCase() === 'silver sponsor') {
|
||||
return 'silver';
|
||||
}
|
||||
|
||||
return sponsor.tier?.name.toLowerCase() || 'backer';
|
||||
};
|
||||
|
||||
const processedData = sponsorsData
|
||||
.map((sponsor) => ({
|
||||
name: sponsor.account.name ?? 'Backer',
|
||||
imageUrl: sponsor.account.imageUrl ?? null,
|
||||
description: sponsor.account.description ?? null,
|
||||
tier: getSponsorTier(sponsor),
|
||||
slug: sponsor.account.slug,
|
||||
website: sponsor.account.website
|
||||
? buildLinks(sponsor.account.website)
|
||||
: (buildLinks(sponsor.account.socialLinks.find((link) => link.type === 'WEBSITE')?.url) ??
|
||||
null),
|
||||
twitter:
|
||||
buildLinks(sponsor.account.socialLinks.find((link) => link.type === 'TWITTER')?.url) ??
|
||||
null,
|
||||
}))
|
||||
.filter((sponsor) => !config.sponsorsToIgnore.includes(sponsor.name));
|
||||
|
||||
return processedData;
|
||||
};
|
||||
|
||||
/**
|
||||
* The main process.
|
||||
*/
|
||||
const mainProcess = async () => {
|
||||
try {
|
||||
const allSponsors = await getAllSponsors();
|
||||
const activeSponsors = await getActiveSponsors();
|
||||
const allSponsorsProcessedData = formatAllSponsorData(allSponsors.account.members.nodes);
|
||||
const activeSponsorsProcessedData = formatActiveSponsorData(
|
||||
activeSponsors.account.orders.nodes
|
||||
);
|
||||
|
||||
const sponsorsByTier = {};
|
||||
|
||||
for (const sponsor of allSponsorsProcessedData) {
|
||||
sponsorsByTier[sponsor.tier] ||= [];
|
||||
|
||||
const isActiveSponsor = activeSponsorsProcessedData.find(
|
||||
(activeSponsor) => activeSponsor.slug === sponsor.slug
|
||||
);
|
||||
|
||||
if (isActiveSponsor) {
|
||||
sponsorsByTier[sponsor.tier].push({
|
||||
...sponsor,
|
||||
active: true,
|
||||
});
|
||||
} else {
|
||||
sponsorsByTier[sponsor.tier].push({
|
||||
...sponsor,
|
||||
active: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (const sponsor of activeSponsorsProcessedData) {
|
||||
const isSponsorInAllSponsors = allSponsorsProcessedData.find(
|
||||
(allSponsor) => allSponsor.slug === sponsor.slug
|
||||
);
|
||||
|
||||
if (!isSponsorInAllSponsors) {
|
||||
if (!sponsorsByTier[sponsor.tier]) {
|
||||
sponsorsByTier[sponsor.tier] ||= [];
|
||||
}
|
||||
|
||||
sponsorsByTier[sponsor.tier].push({
|
||||
...sponsor,
|
||||
active: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync('./data/sponsors.json', JSON.stringify(sponsorsByTier, null, 2));
|
||||
|
||||
printSuccessMessage('processed sponsors successfully!');
|
||||
} catch (_) {
|
||||
printErrorMessage('failed to process sponsors!');
|
||||
console.error(_);
|
||||
}
|
||||
};
|
||||
|
||||
await mainProcess();
|
||||
13
docs/scripts/utils.js
Normal file
@ -0,0 +1,13 @@
|
||||
import chalk from 'chalk';
|
||||
|
||||
export const printSuccessMessage = (message) => {
|
||||
console.log(chalk.green('Success:'), `${message}`);
|
||||
};
|
||||
|
||||
export const printInfoMessage = (message) => {
|
||||
console.log(chalk.blue('Info:'), `${message}`);
|
||||
};
|
||||
|
||||
export const printErrorMessage = (message) => {
|
||||
console.log(chalk.red('Error:'), `${message}`);
|
||||
};
|
||||
19
docs/site.webmanifest
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "axios",
|
||||
"short_name": "axios",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
||||
@ -1,8 +1,13 @@
|
||||
import url from 'url';
|
||||
|
||||
export default function (req, res) {
|
||||
const parsedUrl = url.parse(req.url, true);
|
||||
const delay = parsedUrl.query.delay || 3000;
|
||||
let parsedUrl;
|
||||
try {
|
||||
parsedUrl = new URL(req.url, 'http://localhost');
|
||||
} catch {
|
||||
res.writeHead(400, { 'Content-Type': 'text/plain' });
|
||||
res.end('Invalid URL');
|
||||
return;
|
||||
}
|
||||
const delay = parsedUrl.searchParams.get('delay') || 3000;
|
||||
|
||||
setTimeout(() => {
|
||||
res.writeHead(200, {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import gulp from 'gulp';
|
||||
import fs from 'fs-extra';
|
||||
import axios from './bin/githubAxios.js';
|
||||
import axios from './scripts/axios-build-instance.js';
|
||||
import minimist from 'minimist';
|
||||
|
||||
const argv = minimist(process.argv.slice(2));
|
||||
|
||||
41
index.d.cts
@ -20,7 +20,8 @@ type CommonRequestHeadersList =
|
||||
| 'Content-Length'
|
||||
| 'User-Agent'
|
||||
| 'Content-Encoding'
|
||||
| 'Authorization';
|
||||
| 'Authorization'
|
||||
| 'Location';
|
||||
|
||||
type ContentType =
|
||||
| axios.AxiosHeaderValue
|
||||
@ -38,6 +39,8 @@ type CommonResponseHeadersList =
|
||||
| 'Cache-Control'
|
||||
| 'Content-Encoding';
|
||||
|
||||
type CommonResponseHeaderKey = CommonResponseHeadersList | Lowercase<CommonResponseHeadersList>;
|
||||
|
||||
type BrowserProgressEvent = any;
|
||||
|
||||
declare class AxiosHeaders {
|
||||
@ -306,7 +309,7 @@ declare namespace axios {
|
||||
type AxiosHeaderValue = AxiosHeaders | string | string[] | number | boolean | null;
|
||||
|
||||
type RawCommonResponseHeaders = {
|
||||
[Key in CommonResponseHeadersList]: AxiosHeaderValue;
|
||||
[Key in CommonResponseHeaderKey]: AxiosHeaderValue;
|
||||
} & {
|
||||
'set-cookie': string[];
|
||||
};
|
||||
@ -344,56 +347,38 @@ declare namespace axios {
|
||||
protocol?: string;
|
||||
}
|
||||
|
||||
type Method =
|
||||
| 'get'
|
||||
type UppercaseMethod =
|
||||
| 'GET'
|
||||
| 'delete'
|
||||
| 'DELETE'
|
||||
| 'head'
|
||||
| 'HEAD'
|
||||
| 'options'
|
||||
| 'OPTIONS'
|
||||
| 'post'
|
||||
| 'POST'
|
||||
| 'put'
|
||||
| 'PUT'
|
||||
| 'patch'
|
||||
| 'PATCH'
|
||||
| 'purge'
|
||||
| 'PURGE'
|
||||
| 'link'
|
||||
| 'LINK'
|
||||
| 'unlink'
|
||||
| 'UNLINK';
|
||||
|
||||
type Method = (UppercaseMethod | Lowercase<UppercaseMethod>) & {};
|
||||
|
||||
type ResponseType = 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream' | 'formdata';
|
||||
|
||||
type responseEncoding =
|
||||
| 'ascii'
|
||||
type UppercaseResponseEncoding =
|
||||
| 'ASCII'
|
||||
| 'ansi'
|
||||
| 'ANSI'
|
||||
| 'binary'
|
||||
| 'BINARY'
|
||||
| 'base64'
|
||||
| 'BASE64'
|
||||
| 'base64url'
|
||||
| 'BASE64URL'
|
||||
| 'hex'
|
||||
| 'HEX'
|
||||
| 'latin1'
|
||||
| 'LATIN1'
|
||||
| 'ucs-2'
|
||||
| 'UCS-2'
|
||||
| 'ucs2'
|
||||
| 'UCS2'
|
||||
| 'utf-8'
|
||||
| 'UTF-8'
|
||||
| 'utf8'
|
||||
| 'UTF8'
|
||||
| 'utf16le'
|
||||
| 'UTF16LE';
|
||||
|
||||
type responseEncoding = (UppercaseResponseEncoding | Lowercase<UppercaseResponseEncoding>) & {};
|
||||
|
||||
interface TransitionalOptions {
|
||||
silentJSONParsing?: boolean;
|
||||
forcedJSONParsing?: boolean;
|
||||
@ -628,7 +613,7 @@ declare namespace axios {
|
||||
|
||||
interface AxiosInterceptorOptions {
|
||||
synchronous?: boolean;
|
||||
runWhen?: (config: InternalAxiosRequestConfig) => boolean;
|
||||
runWhen?: ((config: InternalAxiosRequestConfig) => boolean) | null;
|
||||
}
|
||||
|
||||
type AxiosInterceptorFulfilled<T> = (value: T) => T | Promise<T>;
|
||||
@ -649,7 +634,7 @@ declare namespace axios {
|
||||
fulfilled: AxiosInterceptorFulfilled<T>;
|
||||
rejected?: AxiosInterceptorRejected;
|
||||
synchronous: boolean;
|
||||
runWhen?: (config: AxiosRequestConfig) => boolean;
|
||||
runWhen?: ((config: InternalAxiosRequestConfig) => boolean) | null;
|
||||
}
|
||||
|
||||
interface AxiosInterceptorManager<V> {
|
||||
|
||||
355
index.d.ts
vendored
@ -1,13 +1,7 @@
|
||||
// TypeScript Version: 4.7
|
||||
type StringLiteralsOrString<Literals extends string> = Literals | (string & {});
|
||||
|
||||
export type AxiosHeaderValue =
|
||||
| AxiosHeaders
|
||||
| string
|
||||
| string[]
|
||||
| number
|
||||
| boolean
|
||||
| null;
|
||||
export type AxiosHeaderValue = AxiosHeaders | string | string[] | number | boolean | null;
|
||||
|
||||
interface RawAxiosHeaders {
|
||||
[key: string]: AxiosHeaderValue;
|
||||
@ -24,11 +18,7 @@ type AxiosHeaderMatcher =
|
||||
| RegExp
|
||||
| ((this: AxiosHeaders, value: string, name: string) => boolean);
|
||||
|
||||
type AxiosHeaderParser = (
|
||||
this: AxiosHeaders,
|
||||
value: AxiosHeaderValue,
|
||||
header: string,
|
||||
) => any;
|
||||
type AxiosHeaderParser = (this: AxiosHeaders, value: AxiosHeaderValue, header: string) => any;
|
||||
|
||||
export class AxiosHeaders {
|
||||
constructor(headers?: RawAxiosHeaders | AxiosHeaders | string);
|
||||
@ -38,12 +28,9 @@ export class AxiosHeaders {
|
||||
set(
|
||||
headerName?: string,
|
||||
value?: AxiosHeaderValue,
|
||||
rewrite?: boolean | AxiosHeaderMatcher,
|
||||
): AxiosHeaders;
|
||||
set(
|
||||
headers?: RawAxiosHeaders | AxiosHeaders | string,
|
||||
rewrite?: boolean,
|
||||
rewrite?: boolean | AxiosHeaderMatcher
|
||||
): AxiosHeaders;
|
||||
set(headers?: RawAxiosHeaders | AxiosHeaders | string, rewrite?: boolean): AxiosHeaders;
|
||||
|
||||
get(headerName: string, parser: RegExp): RegExpExecArray | null;
|
||||
get(headerName: string, matcher?: true | AxiosHeaderParser): AxiosHeaderValue;
|
||||
@ -57,9 +44,7 @@ export class AxiosHeaders {
|
||||
normalize(format: boolean): AxiosHeaders;
|
||||
|
||||
concat(
|
||||
...targets: Array<
|
||||
AxiosHeaders | RawAxiosHeaders | string | undefined | null
|
||||
>
|
||||
...targets: Array<AxiosHeaders | RawAxiosHeaders | string | undefined | null>
|
||||
): AxiosHeaders;
|
||||
|
||||
toJSON(asStrings?: boolean): RawAxiosHeaders;
|
||||
@ -69,55 +54,35 @@ export class AxiosHeaders {
|
||||
static accessor(header: string | string[]): AxiosHeaders;
|
||||
|
||||
static concat(
|
||||
...targets: Array<
|
||||
AxiosHeaders | RawAxiosHeaders | string | undefined | null
|
||||
>
|
||||
...targets: Array<AxiosHeaders | RawAxiosHeaders | string | undefined | null>
|
||||
): AxiosHeaders;
|
||||
|
||||
setContentType(
|
||||
value: ContentType,
|
||||
rewrite?: boolean | AxiosHeaderMatcher,
|
||||
): AxiosHeaders;
|
||||
setContentType(value: ContentType, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
|
||||
getContentType(parser?: RegExp): RegExpExecArray | null;
|
||||
getContentType(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
|
||||
hasContentType(matcher?: AxiosHeaderMatcher): boolean;
|
||||
|
||||
setContentLength(
|
||||
value: AxiosHeaderValue,
|
||||
rewrite?: boolean | AxiosHeaderMatcher,
|
||||
): AxiosHeaders;
|
||||
setContentLength(value: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
|
||||
getContentLength(parser?: RegExp): RegExpExecArray | null;
|
||||
getContentLength(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
|
||||
hasContentLength(matcher?: AxiosHeaderMatcher): boolean;
|
||||
|
||||
setAccept(
|
||||
value: AxiosHeaderValue,
|
||||
rewrite?: boolean | AxiosHeaderMatcher,
|
||||
): AxiosHeaders;
|
||||
setAccept(value: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
|
||||
getAccept(parser?: RegExp): RegExpExecArray | null;
|
||||
getAccept(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
|
||||
hasAccept(matcher?: AxiosHeaderMatcher): boolean;
|
||||
|
||||
setUserAgent(
|
||||
value: AxiosHeaderValue,
|
||||
rewrite?: boolean | AxiosHeaderMatcher,
|
||||
): AxiosHeaders;
|
||||
setUserAgent(value: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
|
||||
getUserAgent(parser?: RegExp): RegExpExecArray | null;
|
||||
getUserAgent(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
|
||||
hasUserAgent(matcher?: AxiosHeaderMatcher): boolean;
|
||||
|
||||
setContentEncoding(
|
||||
value: AxiosHeaderValue,
|
||||
rewrite?: boolean | AxiosHeaderMatcher,
|
||||
): AxiosHeaders;
|
||||
setContentEncoding(value: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
|
||||
getContentEncoding(parser?: RegExp): RegExpExecArray | null;
|
||||
getContentEncoding(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
|
||||
hasContentEncoding(matcher?: AxiosHeaderMatcher): boolean;
|
||||
|
||||
setAuthorization(
|
||||
value: AxiosHeaderValue,
|
||||
rewrite?: boolean | AxiosHeaderMatcher,
|
||||
): AxiosHeaders;
|
||||
setAuthorization(value: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
|
||||
getAuthorization(parser?: RegExp): RegExpExecArray | null;
|
||||
getAuthorization(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
|
||||
hasAuthorization(matcher?: AxiosHeaderMatcher): boolean;
|
||||
@ -128,56 +93,53 @@ export class AxiosHeaders {
|
||||
}
|
||||
|
||||
type CommonRequestHeadersList =
|
||||
| "Accept"
|
||||
| "Content-Length"
|
||||
| "User-Agent"
|
||||
| "Content-Encoding"
|
||||
| "Authorization";
|
||||
| 'Accept'
|
||||
| 'Content-Length'
|
||||
| 'User-Agent'
|
||||
| 'Content-Encoding'
|
||||
| 'Authorization'
|
||||
| 'Location';
|
||||
|
||||
type ContentType =
|
||||
| AxiosHeaderValue
|
||||
| "text/html"
|
||||
| "text/plain"
|
||||
| "multipart/form-data"
|
||||
| "application/json"
|
||||
| "application/x-www-form-urlencoded"
|
||||
| "application/octet-stream";
|
||||
| 'text/html'
|
||||
| 'text/plain'
|
||||
| 'multipart/form-data'
|
||||
| 'application/json'
|
||||
| 'application/x-www-form-urlencoded'
|
||||
| 'application/octet-stream';
|
||||
|
||||
export type RawAxiosRequestHeaders = Partial<
|
||||
RawAxiosHeaders & {
|
||||
[Key in CommonRequestHeadersList]: AxiosHeaderValue;
|
||||
} & {
|
||||
"Content-Type": ContentType;
|
||||
'Content-Type': ContentType;
|
||||
}
|
||||
>;
|
||||
|
||||
export type AxiosRequestHeaders = RawAxiosRequestHeaders & AxiosHeaders;
|
||||
|
||||
type CommonResponseHeadersList =
|
||||
| "Server"
|
||||
| "Content-Type"
|
||||
| "Content-Length"
|
||||
| "Cache-Control"
|
||||
| "Content-Encoding";
|
||||
| 'Server'
|
||||
| 'Content-Type'
|
||||
| 'Content-Length'
|
||||
| 'Cache-Control'
|
||||
| 'Content-Encoding';
|
||||
|
||||
type CommonResponseHeaderKey = CommonResponseHeadersList | Lowercase<CommonResponseHeadersList>;
|
||||
|
||||
type RawCommonResponseHeaders = {
|
||||
[Key in CommonResponseHeadersList]: AxiosHeaderValue;
|
||||
[Key in CommonResponseHeaderKey]: AxiosHeaderValue;
|
||||
} & {
|
||||
"set-cookie": string[];
|
||||
'set-cookie': string[];
|
||||
};
|
||||
|
||||
export type RawAxiosResponseHeaders = Partial<
|
||||
RawAxiosHeaders & RawCommonResponseHeaders
|
||||
>;
|
||||
export type RawAxiosResponseHeaders = Partial<RawAxiosHeaders & RawCommonResponseHeaders>;
|
||||
|
||||
export type AxiosResponseHeaders = RawAxiosResponseHeaders & AxiosHeaders;
|
||||
|
||||
export interface AxiosRequestTransformer {
|
||||
(
|
||||
this: InternalAxiosRequestConfig,
|
||||
data: any,
|
||||
headers: AxiosRequestHeaders,
|
||||
): any;
|
||||
(this: InternalAxiosRequestConfig, data: any, headers: AxiosRequestHeaders): any;
|
||||
}
|
||||
|
||||
export interface AxiosResponseTransformer {
|
||||
@ -185,7 +147,7 @@ export interface AxiosResponseTransformer {
|
||||
this: InternalAxiosRequestConfig,
|
||||
data: any,
|
||||
headers: AxiosResponseHeaders,
|
||||
status?: number,
|
||||
status?: number
|
||||
): any;
|
||||
}
|
||||
|
||||
@ -271,62 +233,47 @@ export enum HttpStatusCode {
|
||||
NetworkAuthenticationRequired = 511,
|
||||
}
|
||||
|
||||
export type Method =
|
||||
| "get"
|
||||
| "GET"
|
||||
| "delete"
|
||||
| "DELETE"
|
||||
| "head"
|
||||
| "HEAD"
|
||||
| "options"
|
||||
| "OPTIONS"
|
||||
| "post"
|
||||
| "POST"
|
||||
| "put"
|
||||
| "PUT"
|
||||
| "patch"
|
||||
| "PATCH"
|
||||
| "purge"
|
||||
| "PURGE"
|
||||
| "link"
|
||||
| "LINK"
|
||||
| "unlink"
|
||||
| "UNLINK";
|
||||
type UppercaseMethod =
|
||||
| 'GET'
|
||||
| 'DELETE'
|
||||
| 'HEAD'
|
||||
| 'OPTIONS'
|
||||
| 'POST'
|
||||
| 'PUT'
|
||||
| 'PATCH'
|
||||
| 'PURGE'
|
||||
| 'LINK'
|
||||
| 'UNLINK';
|
||||
|
||||
export type Method = (UppercaseMethod | Lowercase<UppercaseMethod>) & {};
|
||||
|
||||
export type ResponseType =
|
||||
| "arraybuffer"
|
||||
| "blob"
|
||||
| "document"
|
||||
| "json"
|
||||
| "text"
|
||||
| "stream"
|
||||
| "formdata";
|
||||
| 'arraybuffer'
|
||||
| 'blob'
|
||||
| 'document'
|
||||
| 'json'
|
||||
| 'text'
|
||||
| 'stream'
|
||||
| 'formdata';
|
||||
|
||||
export type responseEncoding =
|
||||
| "ascii"
|
||||
| "ASCII"
|
||||
| "ansi"
|
||||
| "ANSI"
|
||||
| "binary"
|
||||
| "BINARY"
|
||||
| "base64"
|
||||
| "BASE64"
|
||||
| "base64url"
|
||||
| "BASE64URL"
|
||||
| "hex"
|
||||
| "HEX"
|
||||
| "latin1"
|
||||
| "LATIN1"
|
||||
| "ucs-2"
|
||||
| "UCS-2"
|
||||
| "ucs2"
|
||||
| "UCS2"
|
||||
| "utf-8"
|
||||
| "UTF-8"
|
||||
| "utf8"
|
||||
| "UTF8"
|
||||
| "utf16le"
|
||||
| "UTF16LE";
|
||||
type UppercaseResponseEncoding =
|
||||
| 'ASCII'
|
||||
| 'ANSI'
|
||||
| 'BINARY'
|
||||
| 'BASE64'
|
||||
| 'BASE64URL'
|
||||
| 'HEX'
|
||||
| 'LATIN1'
|
||||
| 'UCS-2'
|
||||
| 'UCS2'
|
||||
| 'UTF-8'
|
||||
| 'UTF8'
|
||||
| 'UTF16LE';
|
||||
|
||||
export type responseEncoding = (
|
||||
| UppercaseResponseEncoding
|
||||
| Lowercase<UppercaseResponseEncoding>
|
||||
) & {};
|
||||
|
||||
export interface TransitionalOptions {
|
||||
silentJSONParsing?: boolean;
|
||||
@ -354,7 +301,7 @@ export interface SerializerVisitor {
|
||||
value: any,
|
||||
key: string | number,
|
||||
path: null | Array<string | number>,
|
||||
helpers: FormDataVisitorHelpers,
|
||||
helpers: FormDataVisitorHelpers
|
||||
): boolean;
|
||||
}
|
||||
|
||||
@ -402,7 +349,7 @@ export interface AxiosProgressEvent {
|
||||
|
||||
type Milliseconds = number;
|
||||
|
||||
type AxiosAdapterName = StringLiteralsOrString<"xhr" | "http" | "fetch">;
|
||||
type AxiosAdapterName = StringLiteralsOrString<'xhr' | 'http' | 'fetch'>;
|
||||
|
||||
type AxiosAdapterConfig = AxiosAdapter | AxiosAdapterName;
|
||||
|
||||
@ -447,7 +394,7 @@ export interface AxiosRequestConfig<D = any> {
|
||||
responseDetails: {
|
||||
headers: Record<string, string>;
|
||||
statusCode: HttpStatusCode;
|
||||
},
|
||||
}
|
||||
) => void;
|
||||
socketPath?: string | null;
|
||||
transport?: any;
|
||||
@ -461,24 +408,11 @@ export interface AxiosRequestConfig<D = any> {
|
||||
insecureHTTPParser?: boolean;
|
||||
env?: {
|
||||
FormData?: new (...args: any[]) => object;
|
||||
fetch?: (
|
||||
input: URL | Request | string,
|
||||
init?: RequestInit,
|
||||
) => Promise<Response>;
|
||||
Request?: new (
|
||||
input: URL | Request | string,
|
||||
init?: RequestInit,
|
||||
) => Request;
|
||||
fetch?: (input: URL | Request | string, init?: RequestInit) => Promise<Response>;
|
||||
Request?: new (input: URL | Request | string, init?: RequestInit) => Request;
|
||||
Response?: new (
|
||||
body?:
|
||||
| ArrayBuffer
|
||||
| ArrayBufferView
|
||||
| Blob
|
||||
| FormData
|
||||
| URLSearchParams
|
||||
| string
|
||||
| null,
|
||||
init?: ResponseInit,
|
||||
body?: ArrayBuffer | ArrayBufferView | Blob | FormData | URLSearchParams | string | null,
|
||||
init?: ResponseInit
|
||||
) => Response;
|
||||
};
|
||||
formSerializer?: FormSerializerOptions;
|
||||
@ -490,26 +424,18 @@ export interface AxiosRequestConfig<D = any> {
|
||||
cb: (
|
||||
err: Error | null,
|
||||
address: LookupAddress | LookupAddress[],
|
||||
family?: AddressFamily,
|
||||
) => void,
|
||||
family?: AddressFamily
|
||||
) => void
|
||||
) => void)
|
||||
| ((
|
||||
hostname: string,
|
||||
options: object,
|
||||
options: object
|
||||
) => Promise<
|
||||
| [
|
||||
address: LookupAddressEntry | LookupAddressEntry[],
|
||||
family?: AddressFamily,
|
||||
]
|
||||
| LookupAddress
|
||||
[address: LookupAddressEntry | LookupAddressEntry[], family?: AddressFamily] | LookupAddress
|
||||
>);
|
||||
withXSRFToken?:
|
||||
| boolean
|
||||
| ((config: InternalAxiosRequestConfig) => boolean | undefined);
|
||||
withXSRFToken?: boolean | ((config: InternalAxiosRequestConfig) => boolean | undefined);
|
||||
parseReviver?: (this: any, key: string, value: any) => any;
|
||||
fetchOptions?:
|
||||
| Omit<RequestInit, "body" | "headers" | "method" | "signal">
|
||||
| Record<string, any>;
|
||||
fetchOptions?: Omit<RequestInit, 'body' | 'headers' | 'method' | 'signal'> | Record<string, any>;
|
||||
httpVersion?: 1 | 2;
|
||||
http2Options?: Record<string, any> & {
|
||||
sessionTimeout?: number;
|
||||
@ -519,9 +445,7 @@ export interface AxiosRequestConfig<D = any> {
|
||||
// Alias
|
||||
export type RawAxiosRequestConfig<D = any> = AxiosRequestConfig<D>;
|
||||
|
||||
export interface InternalAxiosRequestConfig<
|
||||
D = any,
|
||||
> extends AxiosRequestConfig<D> {
|
||||
export interface InternalAxiosRequestConfig<D = any> extends AxiosRequestConfig<D> {
|
||||
headers: AxiosRequestHeaders;
|
||||
}
|
||||
|
||||
@ -539,17 +463,11 @@ export interface HeadersDefaults {
|
||||
unlink?: RawAxiosRequestHeaders;
|
||||
}
|
||||
|
||||
export interface AxiosDefaults<D = any> extends Omit<
|
||||
AxiosRequestConfig<D>,
|
||||
"headers"
|
||||
> {
|
||||
export interface AxiosDefaults<D = any> extends Omit<AxiosRequestConfig<D>, 'headers'> {
|
||||
headers: HeadersDefaults;
|
||||
}
|
||||
|
||||
export interface CreateAxiosDefaults<D = any> extends Omit<
|
||||
AxiosRequestConfig<D>,
|
||||
"headers"
|
||||
> {
|
||||
export interface CreateAxiosDefaults<D = any> extends Omit<AxiosRequestConfig<D>, 'headers'> {
|
||||
headers?: RawAxiosRequestHeaders | AxiosHeaders | Partial<HeadersDefaults>;
|
||||
}
|
||||
|
||||
@ -568,7 +486,7 @@ export class AxiosError<T = unknown, D = any> extends Error {
|
||||
code?: string,
|
||||
config?: InternalAxiosRequestConfig<D>,
|
||||
request?: any,
|
||||
response?: AxiosResponse<T, D>,
|
||||
response?: AxiosResponse<T, D>
|
||||
);
|
||||
|
||||
config?: InternalAxiosRequestConfig<D>;
|
||||
@ -586,24 +504,24 @@ export class AxiosError<T = unknown, D = any> extends Error {
|
||||
config?: InternalAxiosRequestConfig<D>,
|
||||
request?: any,
|
||||
response?: AxiosResponse<T, D>,
|
||||
customProps?: object,
|
||||
customProps?: object
|
||||
): AxiosError<T, D>;
|
||||
static readonly ERR_FR_TOO_MANY_REDIRECTS = "ERR_FR_TOO_MANY_REDIRECTS";
|
||||
static readonly ERR_BAD_OPTION_VALUE = "ERR_BAD_OPTION_VALUE";
|
||||
static readonly ERR_BAD_OPTION = "ERR_BAD_OPTION";
|
||||
static readonly ERR_NETWORK = "ERR_NETWORK";
|
||||
static readonly ERR_DEPRECATED = "ERR_DEPRECATED";
|
||||
static readonly ERR_BAD_RESPONSE = "ERR_BAD_RESPONSE";
|
||||
static readonly ERR_BAD_REQUEST = "ERR_BAD_REQUEST";
|
||||
static readonly ERR_NOT_SUPPORT = "ERR_NOT_SUPPORT";
|
||||
static readonly ERR_INVALID_URL = "ERR_INVALID_URL";
|
||||
static readonly ERR_CANCELED = "ERR_CANCELED";
|
||||
static readonly ECONNABORTED = "ECONNABORTED";
|
||||
static readonly ETIMEDOUT = "ETIMEDOUT";
|
||||
static readonly ERR_FR_TOO_MANY_REDIRECTS = 'ERR_FR_TOO_MANY_REDIRECTS';
|
||||
static readonly ERR_BAD_OPTION_VALUE = 'ERR_BAD_OPTION_VALUE';
|
||||
static readonly ERR_BAD_OPTION = 'ERR_BAD_OPTION';
|
||||
static readonly ERR_NETWORK = 'ERR_NETWORK';
|
||||
static readonly ERR_DEPRECATED = 'ERR_DEPRECATED';
|
||||
static readonly ERR_BAD_RESPONSE = 'ERR_BAD_RESPONSE';
|
||||
static readonly ERR_BAD_REQUEST = 'ERR_BAD_REQUEST';
|
||||
static readonly ERR_NOT_SUPPORT = 'ERR_NOT_SUPPORT';
|
||||
static readonly ERR_INVALID_URL = 'ERR_INVALID_URL';
|
||||
static readonly ERR_CANCELED = 'ERR_CANCELED';
|
||||
static readonly ECONNABORTED = 'ECONNABORTED';
|
||||
static readonly ETIMEDOUT = 'ETIMEDOUT';
|
||||
}
|
||||
|
||||
export class CanceledError<T> extends AxiosError<T> {
|
||||
readonly name: "CanceledError";
|
||||
readonly name: 'CanceledError';
|
||||
}
|
||||
|
||||
export type AxiosPromise<T = any> = Promise<AxiosResponse<T>>;
|
||||
@ -638,7 +556,7 @@ export interface CancelTokenSource {
|
||||
|
||||
export interface AxiosInterceptorOptions {
|
||||
synchronous?: boolean;
|
||||
runWhen?: (config: InternalAxiosRequestConfig) => boolean;
|
||||
runWhen?: ((config: InternalAxiosRequestConfig) => boolean) | null;
|
||||
}
|
||||
|
||||
type AxiosInterceptorFulfilled<T> = (value: T) => T | Promise<T>;
|
||||
@ -647,25 +565,23 @@ type AxiosInterceptorRejected = (error: any) => any;
|
||||
type AxiosRequestInterceptorUse<T> = (
|
||||
onFulfilled?: AxiosInterceptorFulfilled<T> | null,
|
||||
onRejected?: AxiosInterceptorRejected | null,
|
||||
options?: AxiosInterceptorOptions,
|
||||
options?: AxiosInterceptorOptions
|
||||
) => number;
|
||||
|
||||
type AxiosResponseInterceptorUse<T> = (
|
||||
onFulfilled?: AxiosInterceptorFulfilled<T> | null,
|
||||
onRejected?: AxiosInterceptorRejected | null,
|
||||
onRejected?: AxiosInterceptorRejected | null
|
||||
) => number;
|
||||
|
||||
interface AxiosInterceptorHandler<T> {
|
||||
fulfilled: AxiosInterceptorFulfilled<T>;
|
||||
rejected?: AxiosInterceptorRejected;
|
||||
synchronous: boolean;
|
||||
runWhen: (config: AxiosRequestConfig) => boolean | null;
|
||||
runWhen?: ((config: InternalAxiosRequestConfig) => boolean) | null;
|
||||
}
|
||||
|
||||
export interface AxiosInterceptorManager<V> {
|
||||
use: V extends AxiosResponse
|
||||
? AxiosResponseInterceptorUse<V>
|
||||
: AxiosRequestInterceptorUse<V>;
|
||||
use: V extends AxiosResponse ? AxiosResponseInterceptorUse<V> : AxiosRequestInterceptorUse<V>;
|
||||
eject(id: number): void;
|
||||
clear(): void;
|
||||
handlers?: Array<AxiosInterceptorHandler<V>>;
|
||||
@ -679,68 +595,61 @@ export class Axios {
|
||||
response: AxiosInterceptorManager<AxiosResponse>;
|
||||
};
|
||||
getUri(config?: AxiosRequestConfig): string;
|
||||
request<T = any, R = AxiosResponse<T>, D = any>(
|
||||
config: AxiosRequestConfig<D>,
|
||||
): Promise<R>;
|
||||
request<T = any, R = AxiosResponse<T>, D = any>(config: AxiosRequestConfig<D>): Promise<R>;
|
||||
get<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
config?: AxiosRequestConfig<D>,
|
||||
config?: AxiosRequestConfig<D>
|
||||
): Promise<R>;
|
||||
delete<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
config?: AxiosRequestConfig<D>,
|
||||
config?: AxiosRequestConfig<D>
|
||||
): Promise<R>;
|
||||
head<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
config?: AxiosRequestConfig<D>,
|
||||
config?: AxiosRequestConfig<D>
|
||||
): Promise<R>;
|
||||
options<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
config?: AxiosRequestConfig<D>,
|
||||
config?: AxiosRequestConfig<D>
|
||||
): Promise<R>;
|
||||
post<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
data?: D,
|
||||
config?: AxiosRequestConfig<D>,
|
||||
config?: AxiosRequestConfig<D>
|
||||
): Promise<R>;
|
||||
put<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
data?: D,
|
||||
config?: AxiosRequestConfig<D>,
|
||||
config?: AxiosRequestConfig<D>
|
||||
): Promise<R>;
|
||||
patch<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
data?: D,
|
||||
config?: AxiosRequestConfig<D>,
|
||||
config?: AxiosRequestConfig<D>
|
||||
): Promise<R>;
|
||||
postForm<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
data?: D,
|
||||
config?: AxiosRequestConfig<D>,
|
||||
config?: AxiosRequestConfig<D>
|
||||
): Promise<R>;
|
||||
putForm<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
data?: D,
|
||||
config?: AxiosRequestConfig<D>,
|
||||
config?: AxiosRequestConfig<D>
|
||||
): Promise<R>;
|
||||
patchForm<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
data?: D,
|
||||
config?: AxiosRequestConfig<D>,
|
||||
config?: AxiosRequestConfig<D>
|
||||
): Promise<R>;
|
||||
}
|
||||
|
||||
export interface AxiosInstance extends Axios {
|
||||
<T = any, R = AxiosResponse<T>, D = any>(
|
||||
config: AxiosRequestConfig<D>,
|
||||
): Promise<R>;
|
||||
<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
config?: AxiosRequestConfig<D>,
|
||||
): Promise<R>;
|
||||
<T = any, R = AxiosResponse<T>, D = any>(config: AxiosRequestConfig<D>): Promise<R>;
|
||||
<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>;
|
||||
|
||||
create(config?: CreateAxiosDefaults): AxiosInstance;
|
||||
defaults: Omit<AxiosDefaults, "headers"> & {
|
||||
defaults: Omit<AxiosDefaults, 'headers'> & {
|
||||
headers: HeadersDefaults & {
|
||||
[key: string]: AxiosHeaderValue;
|
||||
};
|
||||
@ -758,22 +667,18 @@ export interface GenericHTMLFormElement {
|
||||
}
|
||||
|
||||
export function getAdapter(
|
||||
adapters: AxiosAdapterConfig | AxiosAdapterConfig[] | undefined,
|
||||
adapters: AxiosAdapterConfig | AxiosAdapterConfig[] | undefined
|
||||
): AxiosAdapter;
|
||||
|
||||
export function toFormData(
|
||||
sourceObj: object,
|
||||
targetFormData?: GenericFormData,
|
||||
options?: FormSerializerOptions,
|
||||
options?: FormSerializerOptions
|
||||
): GenericFormData;
|
||||
|
||||
export function formToJSON(
|
||||
form: GenericFormData | GenericHTMLFormElement,
|
||||
): object;
|
||||
export function formToJSON(form: GenericFormData | GenericHTMLFormElement): object;
|
||||
|
||||
export function isAxiosError<T = any, D = any>(
|
||||
payload: any,
|
||||
): payload is AxiosError<T, D>;
|
||||
export function isAxiosError<T = any, D = any>(payload: any): payload is AxiosError<T, D>;
|
||||
|
||||
export function spread<T, R>(callback: (...args: T[]) => R): (array: T[]) => R;
|
||||
|
||||
@ -783,7 +688,7 @@ export function all<T>(values: Array<T | Promise<T>>): Promise<T[]>;
|
||||
|
||||
export function mergeConfig<D = any>(
|
||||
config1: AxiosRequestConfig<D>,
|
||||
config2: AxiosRequestConfig<D>,
|
||||
config2: AxiosRequestConfig<D>
|
||||
): AxiosRequestConfig<D>;
|
||||
|
||||
export interface AxiosStatic extends AxiosInstance {
|
||||
|
||||
@ -221,6 +221,19 @@ const factory = (env) => {
|
||||
// see https://github.com/cloudflare/workerd/issues/902
|
||||
const isCredentialsSupported = isRequestSupported && 'credentials' in Request.prototype;
|
||||
|
||||
// If data is FormData and Content-Type is multipart/form-data without boundary,
|
||||
// delete it so fetch can set it correctly with the boundary
|
||||
if (utils.isFormData(data)) {
|
||||
const contentType = headers.getContentType();
|
||||
if (
|
||||
contentType &&
|
||||
/^multipart\/form-data/i.test(contentType) &&
|
||||
!/boundary=/i.test(contentType)
|
||||
) {
|
||||
headers.delete('content-type');
|
||||
}
|
||||
}
|
||||
|
||||
const resolvedOptions = {
|
||||
...fetchOptions,
|
||||
signal: composedSignal,
|
||||
|
||||
@ -23,6 +23,7 @@ import formDataToStream from '../helpers/formDataToStream.js';
|
||||
import readBlob from '../helpers/readBlob.js';
|
||||
import ZlibHeaderTransformStream from '../helpers/ZlibHeaderTransformStream.js';
|
||||
import callbackify from '../helpers/callbackify.js';
|
||||
import shouldBypassProxy from '../helpers/shouldBypassProxy.js';
|
||||
import {
|
||||
progressEventReducer,
|
||||
progressEventDecorator,
|
||||
@ -192,7 +193,9 @@ function setProxy(options, configProxy, location) {
|
||||
if (!proxy && proxy !== false) {
|
||||
const proxyUrl = getProxyForUrl(location);
|
||||
if (proxyUrl) {
|
||||
proxy = new URL(proxyUrl);
|
||||
if (!shouldBypassProxy(location)) {
|
||||
proxy = new URL(proxyUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (proxy) {
|
||||
@ -668,7 +671,6 @@ export default isHttpAdapterSupported &&
|
||||
protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path
|
||||
);
|
||||
}
|
||||
|
||||
let transport;
|
||||
const isHttpsRequest = isHttps.test(options.protocol);
|
||||
options.agent = isHttpsRequest ? config.httpsAgent : config.httpAgent;
|
||||
@ -873,6 +875,21 @@ export default isHttpAdapterSupported &&
|
||||
req.on('socket', function handleRequestSocket(socket) {
|
||||
// default interval of sending ack packet is 1 minute
|
||||
socket.setKeepAlive(true, 1000 * 60);
|
||||
|
||||
const removeSocketErrorListener = () => {
|
||||
socket.removeListener('error', handleRequestSocketError);
|
||||
};
|
||||
|
||||
function handleRequestSocketError(err) {
|
||||
removeSocketErrorListener();
|
||||
|
||||
if (!req.destroyed) {
|
||||
req.destroy(err);
|
||||
}
|
||||
}
|
||||
|
||||
socket.on('error', handleRequestSocketError);
|
||||
req.once('close', removeSocketErrorListener);
|
||||
});
|
||||
|
||||
// Handle request timeout
|
||||
|
||||
@ -46,13 +46,29 @@ class Axios {
|
||||
Error.captureStackTrace ? Error.captureStackTrace(dummy) : (dummy = new Error());
|
||||
|
||||
// slice off the Error: ... line
|
||||
const stack = dummy.stack ? dummy.stack.replace(/^.+\n/, '') : '';
|
||||
const stack = (() => {
|
||||
if (!dummy.stack) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const firstNewlineIndex = dummy.stack.indexOf('\n');
|
||||
|
||||
return firstNewlineIndex === -1 ? '' : dummy.stack.slice(firstNewlineIndex + 1);
|
||||
})();
|
||||
try {
|
||||
if (!err.stack) {
|
||||
err.stack = stack;
|
||||
// match without the 2 top stack lines
|
||||
} else if (stack && !String(err.stack).endsWith(stack.replace(/^.+\n.+\n/, ''))) {
|
||||
err.stack += '\n' + stack;
|
||||
} else if (stack) {
|
||||
const firstNewlineIndex = stack.indexOf('\n');
|
||||
const secondNewlineIndex =
|
||||
firstNewlineIndex === -1 ? -1 : stack.indexOf('\n', firstNewlineIndex + 1);
|
||||
const stackWithoutTwoTopLines =
|
||||
secondNewlineIndex === -1 ? '' : stack.slice(secondNewlineIndex + 1);
|
||||
|
||||
if (!String(err.stack).endsWith(stackWithoutTwoTopLines)) {
|
||||
err.stack += '\n' + stack;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore the case where "stack" is an un-writable property
|
||||
|
||||
@ -5,18 +5,49 @@ import parseHeaders from '../helpers/parseHeaders.js';
|
||||
|
||||
const $internals = Symbol('internals');
|
||||
|
||||
const isValidHeaderValue = (value) => !/[\r\n]/.test(value);
|
||||
|
||||
function assertValidHeaderValue(value, header) {
|
||||
if (value === false || value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (utils.isArray(value)) {
|
||||
value.forEach((v) => assertValidHeaderValue(v, header));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isValidHeaderValue(String(value))) {
|
||||
throw new Error(`Invalid character in header content ["${header}"]`);
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeHeader(header) {
|
||||
return header && String(header).trim().toLowerCase();
|
||||
}
|
||||
|
||||
function stripTrailingCRLF(str) {
|
||||
let end = str.length;
|
||||
|
||||
while (end > 0) {
|
||||
const charCode = str.charCodeAt(end - 1);
|
||||
|
||||
if (charCode !== 10 && charCode !== 13) {
|
||||
break;
|
||||
}
|
||||
|
||||
end -= 1;
|
||||
}
|
||||
|
||||
return end === str.length ? str : str.slice(0, end);
|
||||
}
|
||||
|
||||
function normalizeValue(value) {
|
||||
if (value === false || value == null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return utils.isArray(value)
|
||||
? value.map(normalizeValue)
|
||||
: String(value).replace(/[\r\n]+$/, '');
|
||||
return utils.isArray(value) ? value.map(normalizeValue) : stripTrailingCRLF(String(value));
|
||||
}
|
||||
|
||||
function parseTokens(str) {
|
||||
@ -98,6 +129,7 @@ class AxiosHeaders {
|
||||
_rewrite === true ||
|
||||
(_rewrite === undefined && self[key] !== false)
|
||||
) {
|
||||
assertValidHeaderValue(_value, _header);
|
||||
self[key || _header] = normalizeValue(_value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ import combineURLs from '../helpers/combineURLs.js';
|
||||
*/
|
||||
export default function buildFullPath(baseURL, requestedURL, allowAbsoluteUrls) {
|
||||
let isRelativeUrl = !isAbsoluteURL(requestedURL);
|
||||
if (baseURL && (isRelativeUrl || allowAbsoluteUrls == false)) {
|
||||
if (baseURL && (isRelativeUrl || allowAbsoluteUrls === false)) {
|
||||
return combineURLs(baseURL, requestedURL);
|
||||
}
|
||||
return requestedURL;
|
||||
|
||||
2
lib/env/data.js
vendored
@ -1 +1 @@
|
||||
export const VERSION = "1.14.0";
|
||||
export const VERSION = "1.15.0";
|
||||
@ -58,7 +58,9 @@ function formDataToJSON(formData) {
|
||||
|
||||
if (isLast) {
|
||||
if (utils.hasOwnProp(target, name)) {
|
||||
target[name] = [target[name], value];
|
||||
target[name] = utils.isArray(target[name])
|
||||
? target[name].concat(value)
|
||||
: [target[name], value];
|
||||
} else {
|
||||
target[name] = value;
|
||||
}
|
||||
|
||||
@ -7,13 +7,13 @@ export const progressEventReducer = (listener, isDownloadStream, freq = 3) => {
|
||||
const _speedometer = speedometer(50, 250);
|
||||
|
||||
return throttle((e) => {
|
||||
const loaded = e.loaded;
|
||||
const rawLoaded = e.loaded;
|
||||
const total = e.lengthComputable ? e.total : undefined;
|
||||
const progressBytes = loaded - bytesNotified;
|
||||
const loaded = total != null ? Math.min(rawLoaded, total) : rawLoaded;
|
||||
const progressBytes = Math.max(0, loaded - bytesNotified);
|
||||
const rate = _speedometer(progressBytes);
|
||||
const inRange = loaded <= total;
|
||||
|
||||
bytesNotified = loaded;
|
||||
bytesNotified = Math.max(bytesNotified, loaded);
|
||||
|
||||
const data = {
|
||||
loaded,
|
||||
@ -21,7 +21,7 @@ export const progressEventReducer = (listener, isDownloadStream, freq = 3) => {
|
||||
progress: total ? loaded / total : undefined,
|
||||
bytes: progressBytes,
|
||||
rate: rate ? rate : undefined,
|
||||
estimated: rate && total && inRange ? (total - loaded) / rate : undefined,
|
||||
estimated: rate && total ? (total - loaded) / rate : undefined,
|
||||
event: e,
|
||||
lengthComputable: total != null,
|
||||
[isDownloadStream ? 'download' : 'upload']: true,
|
||||
|
||||
106
lib/helpers/shouldBypassProxy.js
Normal file
@ -0,0 +1,106 @@
|
||||
const DEFAULT_PORTS = {
|
||||
http: 80,
|
||||
https: 443,
|
||||
ws: 80,
|
||||
wss: 443,
|
||||
ftp: 21,
|
||||
};
|
||||
|
||||
const parseNoProxyEntry = (entry) => {
|
||||
let entryHost = entry;
|
||||
let entryPort = 0;
|
||||
|
||||
if (entryHost.charAt(0) === '[') {
|
||||
const bracketIndex = entryHost.indexOf(']');
|
||||
|
||||
if (bracketIndex !== -1) {
|
||||
const host = entryHost.slice(1, bracketIndex);
|
||||
const rest = entryHost.slice(bracketIndex + 1);
|
||||
|
||||
if (rest.charAt(0) === ':' && /^\d+$/.test(rest.slice(1))) {
|
||||
entryPort = Number.parseInt(rest.slice(1), 10);
|
||||
}
|
||||
|
||||
return [host, entryPort];
|
||||
}
|
||||
}
|
||||
|
||||
const firstColon = entryHost.indexOf(':');
|
||||
const lastColon = entryHost.lastIndexOf(':');
|
||||
|
||||
if (
|
||||
firstColon !== -1 &&
|
||||
firstColon === lastColon &&
|
||||
/^\d+$/.test(entryHost.slice(lastColon + 1))
|
||||
) {
|
||||
entryPort = Number.parseInt(entryHost.slice(lastColon + 1), 10);
|
||||
entryHost = entryHost.slice(0, lastColon);
|
||||
}
|
||||
|
||||
return [entryHost, entryPort];
|
||||
};
|
||||
|
||||
const normalizeNoProxyHost = (hostname) => {
|
||||
if (!hostname) {
|
||||
return hostname;
|
||||
}
|
||||
|
||||
if (hostname.charAt(0) === '[' && hostname.charAt(hostname.length - 1) === ']') {
|
||||
hostname = hostname.slice(1, -1);
|
||||
}
|
||||
|
||||
return hostname.replace(/\.+$/, '');
|
||||
};
|
||||
|
||||
export default function shouldBypassProxy(location) {
|
||||
let parsed;
|
||||
|
||||
try {
|
||||
parsed = new URL(location);
|
||||
} catch (_err) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const noProxy = (process.env.no_proxy || process.env.NO_PROXY || '').toLowerCase();
|
||||
|
||||
if (!noProxy) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (noProxy === '*') {
|
||||
return true;
|
||||
}
|
||||
|
||||
const port =
|
||||
Number.parseInt(parsed.port, 10) || DEFAULT_PORTS[parsed.protocol.split(':', 1)[0]] || 0;
|
||||
|
||||
const hostname = normalizeNoProxyHost(parsed.hostname.toLowerCase());
|
||||
|
||||
return noProxy.split(/[\s,]+/).some((entry) => {
|
||||
if (!entry) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let [entryHost, entryPort] = parseNoProxyEntry(entry);
|
||||
|
||||
entryHost = normalizeNoProxyHost(entryHost);
|
||||
|
||||
if (!entryHost) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entryPort && entryPort !== port) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entryHost.charAt(0) === '*') {
|
||||
entryHost = entryHost.slice(1);
|
||||
}
|
||||
|
||||
if (entryHost.charAt(0) === '.') {
|
||||
return hostname.endsWith(entryHost);
|
||||
}
|
||||
|
||||
return hostname === entryHost;
|
||||
});
|
||||
}
|
||||
518
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "axios",
|
||||
"version": "1.14.0",
|
||||
"version": "1.15.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "axios",
|
||||
"version": "1.14.0",
|
||||
"version": "1.15.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.11",
|
||||
@ -2277,20 +2277,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@napi-rs/wasm-runtime": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz",
|
||||
"integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==",
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.2.tgz",
|
||||
"integrity": "sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/core": "^1.7.1",
|
||||
"@emnapi/runtime": "^1.7.1",
|
||||
"@tybys/wasm-util": "^0.10.1"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/Brooooooklyn"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emnapi/core": "^1.7.1",
|
||||
"@emnapi/runtime": "^1.7.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/hashes": {
|
||||
@ -2632,9 +2634,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@oxc-project/types": {
|
||||
"version": "0.122.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.122.0.tgz",
|
||||
"integrity": "sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==",
|
||||
"version": "0.123.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.123.0.tgz",
|
||||
"integrity": "sha512-YtECP/y8Mj1lSHiUWGSRzy/C6teUKlS87dEfuVKT09LgQbUsBW1rNg+MiJ4buGu3yuADV60gbIvo9/HplA56Ew==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
@ -2818,9 +2820,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@rolldown/binding-android-arm64": {
|
||||
"version": "1.0.0-rc.11",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.11.tgz",
|
||||
"integrity": "sha512-SJ+/g+xNnOh6NqYxD0V3uVN4W3VfnrGsC9/hoglicgTNfABFG9JjISvkkU0dNY84MNHLWyOgxP9v9Y9pX4S7+A==",
|
||||
"version": "1.0.0-rc.13",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.13.tgz",
|
||||
"integrity": "sha512-5ZiiecKH2DXAVJTNN13gNMUcCDg4Jy8ZjbXEsPnqa248wgOVeYRX0iqXXD5Jz4bI9BFHgKsI2qmyJynstbmr+g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -2835,9 +2837,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-darwin-arm64": {
|
||||
"version": "1.0.0-rc.11",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.11.tgz",
|
||||
"integrity": "sha512-7WQgR8SfOPwmDZGFkThUvsmd/nwAWv91oCO4I5LS7RKrssPZmOt7jONN0cW17ydGC1n/+puol1IpoieKqQidmg==",
|
||||
"version": "1.0.0-rc.13",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.13.tgz",
|
||||
"integrity": "sha512-tz/v/8G77seu8zAB3A5sK3UFoOl06zcshEzhUO62sAEtrEuW/H1CcyoupOrD+NbQJytYgA4CppXPzlrmp4JZKA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -2852,9 +2854,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-darwin-x64": {
|
||||
"version": "1.0.0-rc.11",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.11.tgz",
|
||||
"integrity": "sha512-39Ks6UvIHq4rEogIfQBoBRusj0Q0nPVWIvqmwBLaT6aqQGIakHdESBVOPRRLacy4WwUPIx4ZKzfZ9PMW+IeyUQ==",
|
||||
"version": "1.0.0-rc.13",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.13.tgz",
|
||||
"integrity": "sha512-8DakphqOz8JrMYWTJmWA+vDJxut6LijZ8Xcdc4flOlAhU7PNVwo2MaWBF9iXjJAPo5rC/IxEFZDhJ3GC7NHvug==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -2869,9 +2871,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-freebsd-x64": {
|
||||
"version": "1.0.0-rc.11",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.11.tgz",
|
||||
"integrity": "sha512-jfsm0ZHfhiqrvWjJAmzsqiIFPz5e7mAoCOPBNTcNgkiid/LaFKiq92+0ojH+nmJmKYkre4t71BWXUZDNp7vsag==",
|
||||
"version": "1.0.0-rc.13",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.13.tgz",
|
||||
"integrity": "sha512-4wBQFfjDuXYN/SVI8inBF3Aa+isq40rc6VMFbk5jcpolUBTe5cYnMsHZ51nFWsx3PVyyNN3vgoESki0Hmr/4BA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -2886,9 +2888,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
|
||||
"version": "1.0.0-rc.11",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.11.tgz",
|
||||
"integrity": "sha512-zjQaUtSyq1nVe3nxmlSCuR96T1LPlpvmJ0SZy0WJFEsV4kFbXcq2u68L4E6O0XeFj4aex9bEauqjW8UQBeAvfQ==",
|
||||
"version": "1.0.0-rc.13",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.13.tgz",
|
||||
"integrity": "sha512-JW/e4yPIXLms+jmnbwwy5LA/LxVwZUWLN8xug+V200wzaVi5TEGIWQlh8o91gWYFxW609euI98OCCemmWGuPrw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@ -2903,9 +2905,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm64-gnu": {
|
||||
"version": "1.0.0-rc.11",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.11.tgz",
|
||||
"integrity": "sha512-WMW1yE6IOnehTcFE9eipFkm3XN63zypWlrJQ2iF7NrQ9b2LDRjumFoOGJE8RJJTJCTBAdmLMnJ8uVitACUUo1Q==",
|
||||
"version": "1.0.0-rc.13",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.13.tgz",
|
||||
"integrity": "sha512-ZfKWpXiUymDnavepCaM6KG/uGydJ4l2nBmMxg60Ci4CbeefpqjPWpfaZM7PThOhk2dssqBAcwLc6rAyr0uTdXg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -2920,9 +2922,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm64-musl": {
|
||||
"version": "1.0.0-rc.11",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.11.tgz",
|
||||
"integrity": "sha512-jfndI9tsfm4APzjNt6QdBkYwre5lRPUgHeDHoI7ydKUuJvz3lZeCfMsI56BZj+7BYqiKsJm7cfd/6KYV7ubrBg==",
|
||||
"version": "1.0.0-rc.13",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.13.tgz",
|
||||
"integrity": "sha512-bmRg3O6Z0gq9yodKKWCIpnlH051sEfdVwt+6m5UDffAQMUUqU0xjnQqqAUm+Gu7ofAAly9DqiQDtKu2nPDEABA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -2937,9 +2939,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
|
||||
"version": "1.0.0-rc.11",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.11.tgz",
|
||||
"integrity": "sha512-ZlFgw46NOAGMgcdvdYwAGu2Q+SLFA9LzbJLW+iyMOJyhj5wk6P3KEE9Gct4xWwSzFoPI7JCdYmYMzVtlgQ+zfw==",
|
||||
"version": "1.0.0-rc.13",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.13.tgz",
|
||||
"integrity": "sha512-8Wtnbw4k7pMYN9B/mOEAsQ8HOiq7AZ31Ig4M9BKn2So4xRaFEhtCSa4ZJaOutOWq50zpgR4N5+L/opnlaCx8wQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@ -2954,9 +2956,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-s390x-gnu": {
|
||||
"version": "1.0.0-rc.11",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.11.tgz",
|
||||
"integrity": "sha512-hIOYmuT6ofM4K04XAZd3OzMySEO4K0/nc9+jmNcxNAxRi6c5UWpqfw3KMFV4MVFWL+jQsSh+bGw2VqmaPMTLyw==",
|
||||
"version": "1.0.0-rc.13",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.13.tgz",
|
||||
"integrity": "sha512-D/0Nlo8mQuxSMohNJUF2lDXWRsFDsHldfRRgD9bRgktj+EndGPj4DOV37LqDKPYS+osdyhZEH7fTakTAEcW7qg==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@ -2971,9 +2973,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
||||
"version": "1.0.0-rc.11",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.11.tgz",
|
||||
"integrity": "sha512-qXBQQO9OvkjjQPLdUVr7Nr2t3QTZI7s4KZtfw7HzBgjbmAPSFwSv4rmET9lLSgq3rH/ndA3ngv3Qb8l2njoPNA==",
|
||||
"version": "1.0.0-rc.13",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.13.tgz",
|
||||
"integrity": "sha512-eRrPvat2YaVQcwwKi/JzOP6MKf1WRnOCr+VaI3cTWz3ZoLcP/654z90lVCJ4dAuMEpPdke0n+qyAqXDZdIC4rA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -2988,9 +2990,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-x64-musl": {
|
||||
"version": "1.0.0-rc.11",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.11.tgz",
|
||||
"integrity": "sha512-/tpFfoSTzUkH9LPY+cYbqZBDyyX62w5fICq9qzsHLL8uTI6BHip3Q9Uzft0wylk/i8OOwKik8OxW+QAhDmzwmg==",
|
||||
"version": "1.0.0-rc.13",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.13.tgz",
|
||||
"integrity": "sha512-PsdONiFRp8hR8KgVjTWjZ9s7uA3uueWL0t74/cKHfM4dR5zXYv4AjB8BvA+QDToqxAFg4ZkcVEqeu5F7inoz5w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -3005,9 +3007,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-openharmony-arm64": {
|
||||
"version": "1.0.0-rc.11",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.11.tgz",
|
||||
"integrity": "sha512-mcp3Rio2w72IvdZG0oQ4bM2c2oumtwHfUfKncUM6zGgz0KgPz4YmDPQfnXEiY5t3+KD/i8HG2rOB/LxdmieK2g==",
|
||||
"version": "1.0.0-rc.13",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.13.tgz",
|
||||
"integrity": "sha512-hCNXgC5dI3TVOLrPT++PKFNZ+1EtS0mLQwfXXXSUD/+rGlB65gZDwN/IDuxLpQP4x8RYYHqGomlUXzpO8aVI2w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -3022,9 +3024,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-wasm32-wasi": {
|
||||
"version": "1.0.0-rc.11",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.11.tgz",
|
||||
"integrity": "sha512-LXk5Hii1Ph9asuGRjBuz8TUxdc1lWzB7nyfdoRgI0WGPZKmCxvlKk8KfYysqtr4MfGElu/f/pEQRh8fcEgkrWw==",
|
||||
"version": "1.0.0-rc.13",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.13.tgz",
|
||||
"integrity": "sha512-viLS5C5et8NFtLWw9Sw3M/w4vvnVkbWkO7wSNh3C+7G1+uCkGpr6PcjNDSFcNtmXY/4trjPBqUfcOL+P3sWy/g==",
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
@ -3032,16 +3034,18 @@
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@napi-rs/wasm-runtime": "^1.1.1"
|
||||
"@emnapi/core": "1.9.1",
|
||||
"@emnapi/runtime": "1.9.1",
|
||||
"@napi-rs/wasm-runtime": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-win32-arm64-msvc": {
|
||||
"version": "1.0.0-rc.11",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.11.tgz",
|
||||
"integrity": "sha512-dDwf5otnx0XgRY1yqxOC4ITizcdzS/8cQ3goOWv3jFAo4F+xQYni+hnMuO6+LssHHdJW7+OCVL3CoU4ycnh35Q==",
|
||||
"version": "1.0.0-rc.13",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.13.tgz",
|
||||
"integrity": "sha512-Fqa3Tlt1xL4wzmAYxGNFV36Hb+VfPc9PYU+E25DAnswXv3ODDu/yyWjQDbXMo5AGWkQVjLgQExuVu8I/UaZhPQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -3056,9 +3060,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
||||
"version": "1.0.0-rc.11",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.11.tgz",
|
||||
"integrity": "sha512-LN4/skhSggybX71ews7dAj6r2geaMJfm3kMbK2KhFMg9B10AZXnKoLCVVgzhMHL0S+aKtr4p8QbAW8k+w95bAA==",
|
||||
"version": "1.0.0-rc.13",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.13.tgz",
|
||||
"integrity": "sha512-/pLI5kPkGEi44TDlnbio3St/5gUFeN51YWNAk/Gnv6mEQBOahRBh52qVFVBpmrnU01n2yysvBML9Ynu7K4kGAQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -3073,9 +3077,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/pluginutils": {
|
||||
"version": "1.0.0-rc.11",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.11.tgz",
|
||||
"integrity": "sha512-xQO9vbwBecJRv9EUcQ/y0dzSTJgA7Q6UVN7xp6B81+tBGSLVAK03yJ9NkJaUA7JFD91kbjxRSC/mDnmvXzbHoQ==",
|
||||
"version": "1.0.0-rc.13",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.13.tgz",
|
||||
"integrity": "sha512-3ngTAv6F/Py35BsYbeeLeecvhMKdsKm4AoOETVhAA+Qc8nrA2I0kF7oa93mE9qnIurngOSpMnQ0x2nQY2FPviA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@ -3244,9 +3248,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.0.tgz",
|
||||
"integrity": "sha512-WOhNW9K8bR3kf4zLxbfg6Pxu2ybOUbB2AjMDHSQx86LIF4rH4Ft7vmMwNt0loO0eonglSNy4cpD3MKXXKQu0/A==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.1.tgz",
|
||||
"integrity": "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@ -3258,9 +3262,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.0.tgz",
|
||||
"integrity": "sha512-u6JHLll5QKRvjciE78bQXDmqRqNs5M/3GVqZeMwvmjaNODJih/WIrJlFVEihvV0MiYFmd+ZyPr9wxOVbPAG2Iw==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.1.tgz",
|
||||
"integrity": "sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -3272,9 +3276,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.0.tgz",
|
||||
"integrity": "sha512-qEF7CsKKzSRc20Ciu2Zw1wRrBz4g56F7r/vRwY430UPp/nt1x21Q/fpJ9N5l47WWvJlkNCPJz3QRVw008fi7yA==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.1.tgz",
|
||||
"integrity": "sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -3286,9 +3290,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.0.tgz",
|
||||
"integrity": "sha512-WADYozJ4QCnXCH4wPB+3FuGmDPoFseVCUrANmA5LWwGmC6FL14BWC7pcq+FstOZv3baGX65tZ378uT6WG8ynTw==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.1.tgz",
|
||||
"integrity": "sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -3300,9 +3304,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.0.tgz",
|
||||
"integrity": "sha512-6b8wGHJlDrGeSE3aH5mGNHBjA0TTkxdoNHik5EkvPHCt351XnigA4pS7Wsj/Eo9Y8RBU6f35cjN9SYmCFBtzxw==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.1.tgz",
|
||||
"integrity": "sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -3314,9 +3318,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.0.tgz",
|
||||
"integrity": "sha512-h25Ga0t4jaylMB8M/JKAyrvvfxGRjnPQIR8lnCayyzEjEOx2EJIlIiMbhpWxDRKGKF8jbNH01NnN663dH638mA==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.1.tgz",
|
||||
"integrity": "sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -3328,9 +3332,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.0.tgz",
|
||||
"integrity": "sha512-RzeBwv0B3qtVBWtcuABtSuCzToo2IEAIQrcyB/b2zMvBWVbjo8bZDjACUpnaafaxhTw2W+imQbP2BD1usasK4g==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.1.tgz",
|
||||
"integrity": "sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@ -3342,9 +3346,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.0.tgz",
|
||||
"integrity": "sha512-Sf7zusNI2CIU1HLzuu9Tc5YGAHEZs5Lu7N1ssJG4Tkw6e0MEsN7NdjUDDfGNHy2IU+ENyWT+L2obgWiguWibWQ==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.1.tgz",
|
||||
"integrity": "sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@ -3356,9 +3360,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.0.tgz",
|
||||
"integrity": "sha512-DX2x7CMcrJzsE91q7/O02IJQ5/aLkVtYFryqCjduJhUfGKG6yJV8hxaw8pZa93lLEpPTP/ohdN4wFz7yp/ry9A==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.1.tgz",
|
||||
"integrity": "sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -3370,9 +3374,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.0.tgz",
|
||||
"integrity": "sha512-09EL+yFVbJZlhcQfShpswwRZ0Rg+z/CsSELFCnPt3iK+iqwGsI4zht3secj5vLEs957QvFFXnzAT0FFPIxSrkQ==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.1.tgz",
|
||||
"integrity": "sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -3384,9 +3388,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loong64-gnu": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.0.tgz",
|
||||
"integrity": "sha512-i9IcCMPr3EXm8EQg5jnja0Zyc1iFxJjZWlb4wr7U2Wx/GrddOuEafxRdMPRYVaXjgbhvqalp6np07hN1w9kAKw==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.1.tgz",
|
||||
"integrity": "sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@ -3398,9 +3402,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loong64-musl": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.0.tgz",
|
||||
"integrity": "sha512-DGzdJK9kyJ+B78MCkWeGnpXJ91tK/iKA6HwHxF4TAlPIY7GXEvMe8hBFRgdrR9Ly4qebR/7gfUs9y2IoaVEyog==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.1.tgz",
|
||||
"integrity": "sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@ -3412,9 +3416,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.0.tgz",
|
||||
"integrity": "sha512-RwpnLsqC8qbS8z1H1AxBA1H6qknR4YpPR9w2XX0vo2Sz10miu57PkNcnHVaZkbqyw/kUWfKMI73jhmfi9BRMUQ==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.1.tgz",
|
||||
"integrity": "sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@ -3426,9 +3430,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-musl": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.0.tgz",
|
||||
"integrity": "sha512-Z8pPf54Ly3aqtdWC3G4rFigZgNvd+qJlOE52fmko3KST9SoGfAdSRCwyoyG05q1HrrAblLbk1/PSIV+80/pxLg==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.1.tgz",
|
||||
"integrity": "sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@ -3440,9 +3444,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.0.tgz",
|
||||
"integrity": "sha512-3a3qQustp3COCGvnP4SvrMHnPQ9d1vzCakQVRTliaz8cIp/wULGjiGpbcqrkv0WrHTEp8bQD/B3HBjzujVWLOA==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.1.tgz",
|
||||
"integrity": "sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@ -3454,9 +3458,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.0.tgz",
|
||||
"integrity": "sha512-pjZDsVH/1VsghMJ2/kAaxt6dL0psT6ZexQVrijczOf+PeP2BUqTHYejk3l6TlPRydggINOeNRhvpLa0AYpCWSQ==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.1.tgz",
|
||||
"integrity": "sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@ -3468,9 +3472,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.0.tgz",
|
||||
"integrity": "sha512-3ObQs0BhvPgiUVZrN7gqCSvmFuMWvWvsjG5ayJ3Lraqv+2KhOsp+pUbigqbeWqueGIsnn+09HBw27rJ+gYK4VQ==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.1.tgz",
|
||||
"integrity": "sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@ -3482,9 +3486,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.0.tgz",
|
||||
"integrity": "sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.1.tgz",
|
||||
"integrity": "sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -3496,9 +3500,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.0.tgz",
|
||||
"integrity": "sha512-k09oiRCi/bHU9UVFqD17r3eJR9bn03TyKraCrlz5ULFJGdJGi7VOmm9jl44vOJvRJ6P7WuBi/s2A97LxxHGIdw==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.1.tgz",
|
||||
"integrity": "sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -3510,9 +3514,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-openbsd-x64": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.0.tgz",
|
||||
"integrity": "sha512-1o/0/pIhozoSaDJoDcec+IVLbnRtQmHwPV730+AOD29lHEEo4F5BEUB24H0OBdhbBBDwIOSuf7vgg0Ywxdfiiw==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.1.tgz",
|
||||
"integrity": "sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -3524,9 +3528,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-openharmony-arm64": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.0.tgz",
|
||||
"integrity": "sha512-pESDkos/PDzYwtyzB5p/UoNU/8fJo68vcXM9ZW2V0kjYayj1KaaUfi1NmTUTUpMn4UhU4gTuK8gIaFO4UGuMbA==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.1.tgz",
|
||||
"integrity": "sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -3538,9 +3542,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.0.tgz",
|
||||
"integrity": "sha512-hj1wFStD7B1YBeYmvY+lWXZ7ey73YGPcViMShYikqKT1GtstIKQAtfUI6yrzPjAy/O7pO0VLXGmUVWXQMaYgTQ==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.1.tgz",
|
||||
"integrity": "sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -3552,9 +3556,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.0.tgz",
|
||||
"integrity": "sha512-SyaIPFoxmUPlNDq5EHkTbiKzmSEmq/gOYFI/3HHJ8iS/v1mbugVa7dXUzcJGQfoytp9DJFLhHH4U3/eTy2Bq4w==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.1.tgz",
|
||||
"integrity": "sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@ -3566,9 +3570,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-gnu": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.0.tgz",
|
||||
"integrity": "sha512-RdcryEfzZr+lAr5kRm2ucN9aVlCCa2QNq4hXelZxb8GG0NJSazq44Z3PCCc8wISRuCVnGs0lQJVX5Vp6fKA+IA==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.1.tgz",
|
||||
"integrity": "sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -3580,9 +3584,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.0.tgz",
|
||||
"integrity": "sha512-PrsWNQ8BuE00O3Xsx3ALh2Df8fAj9+cvvX9AIA6o4KpATR98c9mud4XtDWVvsEuyia5U4tVSTKygawyJkjm60w==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.1.tgz",
|
||||
"integrity": "sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -3848,45 +3852,45 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vitest/browser": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.1.1.tgz",
|
||||
"integrity": "sha512-gjjrFC4+kPVK/fN9URDJWrssU5Gqh8Az8pKG/NSfQ2V+ky8b/y1BgBg0Ug13+hOGp5pzInonmGRPn7vOgSLgzA==",
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.1.2.tgz",
|
||||
"integrity": "sha512-CwdIf90LNf1Zitgqy63ciMAzmyb4oIGs8WZ40VGYrWkssQKeEKr32EzO8MKUrDPPcPVHFI9oQ5ni2Hp24NaNRQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@blazediff/core": "1.9.1",
|
||||
"@vitest/mocker": "4.1.1",
|
||||
"@vitest/utils": "4.1.1",
|
||||
"@vitest/mocker": "4.1.2",
|
||||
"@vitest/utils": "4.1.2",
|
||||
"magic-string": "^0.30.21",
|
||||
"pngjs": "^7.0.0",
|
||||
"sirv": "^3.0.2",
|
||||
"tinyrainbow": "^3.0.3",
|
||||
"tinyrainbow": "^3.1.0",
|
||||
"ws": "^8.19.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vitest": "4.1.1"
|
||||
"vitest": "4.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/browser-playwright": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.1.1.tgz",
|
||||
"integrity": "sha512-dtVSBZZha2k/7P7EAXXrEAoxuIKl8Yv9f2Dk4GN/DGfmhf4DQvkvu+57okR2wq/gan1xppKjL/aBxK/kbYrbGw==",
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.1.2.tgz",
|
||||
"integrity": "sha512-N0Z2HzMLvMR6k/tWPTS6Q/DaRscrkax/f2f9DIbNQr+Cd1l4W4wTf/I6S983PAMr0tNqqoTL+xNkLh9M5vbkLg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/browser": "4.1.1",
|
||||
"@vitest/mocker": "4.1.1",
|
||||
"tinyrainbow": "^3.0.3"
|
||||
"@vitest/browser": "4.1.2",
|
||||
"@vitest/mocker": "4.1.2",
|
||||
"tinyrainbow": "^3.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"playwright": "*",
|
||||
"vitest": "4.1.1"
|
||||
"vitest": "4.1.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"playwright": {
|
||||
@ -3895,31 +3899,31 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/expect": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.1.tgz",
|
||||
"integrity": "sha512-xAV0fqBTk44Rn6SjJReEQkHP3RrqbJo6JQ4zZ7/uVOiJZRarBtblzrOfFIZeYUrukp2YD6snZG6IBqhOoHTm+A==",
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.2.tgz",
|
||||
"integrity": "sha512-gbu+7B0YgUJ2nkdsRJrFFW6X7NTP44WlhiclHniUhxADQJH5Szt9mZ9hWnJPJ8YwOK5zUOSSlSvyzRf0u1DSBQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@standard-schema/spec": "^1.1.0",
|
||||
"@types/chai": "^5.2.2",
|
||||
"@vitest/spy": "4.1.1",
|
||||
"@vitest/utils": "4.1.1",
|
||||
"@vitest/spy": "4.1.2",
|
||||
"@vitest/utils": "4.1.2",
|
||||
"chai": "^6.2.2",
|
||||
"tinyrainbow": "^3.0.3"
|
||||
"tinyrainbow": "^3.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/mocker": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.1.tgz",
|
||||
"integrity": "sha512-h3BOylsfsCLPeceuCPAAJ+BvNwSENgJa4hXoXu4im0bs9Lyp4URc4JYK4pWLZ4pG/UQn7AT92K6IByi6rE6g3A==",
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.2.tgz",
|
||||
"integrity": "sha512-Ize4iQtEALHDttPRCmN+FKqOl2vxTiNUhzobQFFt/BM1lRUTG7zRCLOykG/6Vo4E4hnUdfVLo5/eqKPukcWW7Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/spy": "4.1.1",
|
||||
"@vitest/spy": "4.1.2",
|
||||
"estree-walker": "^3.0.3",
|
||||
"magic-string": "^0.30.21"
|
||||
},
|
||||
@ -3950,26 +3954,26 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/pretty-format": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.1.tgz",
|
||||
"integrity": "sha512-GM+TEQN5WhOygr1lp7skeVjdLPqqWMHsfzXrcHAqZJi/lIVh63H0kaRCY8MDhNWikx19zBUK8ceaLB7X5AH9NQ==",
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.2.tgz",
|
||||
"integrity": "sha512-dwQga8aejqeuB+TvXCMzSQemvV9hNEtDDpgUKDzOmNQayl2OG241PSWeJwKRH3CiC+sESrmoFd49rfnq7T4RnA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tinyrainbow": "^3.0.3"
|
||||
"tinyrainbow": "^3.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/runner": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.1.tgz",
|
||||
"integrity": "sha512-f7+FPy75vN91QGWsITueq0gedwUZy1fLtHOCMeQpjs8jTekAHeKP80zfDEnhrleviLHzVSDXIWuCIOFn3D3f8A==",
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.2.tgz",
|
||||
"integrity": "sha512-Gr+FQan34CdiYAwpGJmQG8PgkyFVmARK8/xSijia3eTFgVfpcpztWLuP6FttGNfPLJhaZVP/euvujeNYar36OQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/utils": "4.1.1",
|
||||
"@vitest/utils": "4.1.2",
|
||||
"pathe": "^2.0.3"
|
||||
},
|
||||
"funding": {
|
||||
@ -3977,14 +3981,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/snapshot": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.1.tgz",
|
||||
"integrity": "sha512-kMVSgcegWV2FibXEx9p9WIKgje58lcTbXgnJixfcg15iK8nzCXhmalL0ZLtTWLW9PH1+1NEDShiFFedB3tEgWg==",
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.2.tgz",
|
||||
"integrity": "sha512-g7yfUmxYS4mNxk31qbOYsSt2F4m1E02LFqO53Xpzg3zKMhLAPZAjjfyl9e6z7HrW6LvUdTwAQR3HHfLjpko16A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "4.1.1",
|
||||
"@vitest/utils": "4.1.1",
|
||||
"@vitest/pretty-format": "4.1.2",
|
||||
"@vitest/utils": "4.1.2",
|
||||
"magic-string": "^0.30.21",
|
||||
"pathe": "^2.0.3"
|
||||
},
|
||||
@ -3993,9 +3997,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/spy": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.1.tgz",
|
||||
"integrity": "sha512-6Ti/KT5OVaiupdIZEuZN7l3CZcR0cxnxt70Z0//3CtwgObwA6jZhmVBA3yrXSVN3gmwjgd7oDNLlsXz526gpRA==",
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.2.tgz",
|
||||
"integrity": "sha512-DU4fBnbVCJGNBwVA6xSToNXrkZNSiw59H8tcuUspVMsBDBST4nfvsPsEHDHGtWRRnqBERBQu7TrTKskmjqTXKA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
@ -4003,15 +4007,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/utils": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.1.tgz",
|
||||
"integrity": "sha512-cNxAlaB3sHoCdL6pj6yyUXv9Gry1NHNg0kFTXdvSIZXLHsqKH7chiWOkwJ5s5+d/oMwcoG9T0bKU38JZWKusrQ==",
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.2.tgz",
|
||||
"integrity": "sha512-xw2/TiX82lQHA06cgbqRKFb5lCAy3axQ4H4SoUFhUsg+wztiet+co86IAMDtF6Vm1hc7J6j09oh/rgDn+JdKIQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "4.1.1",
|
||||
"@vitest/pretty-format": "4.1.2",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"tinyrainbow": "^3.0.3"
|
||||
"tinyrainbow": "^3.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
@ -7006,9 +7010,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/handlebars": {
|
||||
"version": "4.7.8",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
|
||||
"integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
|
||||
"version": "4.7.9",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz",
|
||||
"integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -9501,9 +9505,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -10034,14 +10038,14 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/rolldown": {
|
||||
"version": "1.0.0-rc.11",
|
||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.11.tgz",
|
||||
"integrity": "sha512-NRjoKMusSjfRbSYiH3VSumlkgFe7kYAa3pzVOsVYVFY3zb5d7nS+a3KGQ7hJKXuYWbzJKPVQ9Wxq2UvyK+ENpw==",
|
||||
"version": "1.0.0-rc.13",
|
||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.13.tgz",
|
||||
"integrity": "sha512-bvVj8YJmf0rq4pSFmH7laLa6pYrhghv3PRzrCdRAr23g66zOKVJ4wkvFtgohtPLWmthgg8/rkaqRHrpUEh0Zbw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@oxc-project/types": "=0.122.0",
|
||||
"@rolldown/pluginutils": "1.0.0-rc.11"
|
||||
"@oxc-project/types": "=0.123.0",
|
||||
"@rolldown/pluginutils": "1.0.0-rc.13"
|
||||
},
|
||||
"bin": {
|
||||
"rolldown": "bin/cli.mjs"
|
||||
@ -10050,27 +10054,27 @@
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rolldown/binding-android-arm64": "1.0.0-rc.11",
|
||||
"@rolldown/binding-darwin-arm64": "1.0.0-rc.11",
|
||||
"@rolldown/binding-darwin-x64": "1.0.0-rc.11",
|
||||
"@rolldown/binding-freebsd-x64": "1.0.0-rc.11",
|
||||
"@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.11",
|
||||
"@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.11",
|
||||
"@rolldown/binding-linux-arm64-musl": "1.0.0-rc.11",
|
||||
"@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.11",
|
||||
"@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.11",
|
||||
"@rolldown/binding-linux-x64-gnu": "1.0.0-rc.11",
|
||||
"@rolldown/binding-linux-x64-musl": "1.0.0-rc.11",
|
||||
"@rolldown/binding-openharmony-arm64": "1.0.0-rc.11",
|
||||
"@rolldown/binding-wasm32-wasi": "1.0.0-rc.11",
|
||||
"@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.11",
|
||||
"@rolldown/binding-win32-x64-msvc": "1.0.0-rc.11"
|
||||
"@rolldown/binding-android-arm64": "1.0.0-rc.13",
|
||||
"@rolldown/binding-darwin-arm64": "1.0.0-rc.13",
|
||||
"@rolldown/binding-darwin-x64": "1.0.0-rc.13",
|
||||
"@rolldown/binding-freebsd-x64": "1.0.0-rc.13",
|
||||
"@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.13",
|
||||
"@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.13",
|
||||
"@rolldown/binding-linux-arm64-musl": "1.0.0-rc.13",
|
||||
"@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.13",
|
||||
"@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.13",
|
||||
"@rolldown/binding-linux-x64-gnu": "1.0.0-rc.13",
|
||||
"@rolldown/binding-linux-x64-musl": "1.0.0-rc.13",
|
||||
"@rolldown/binding-openharmony-arm64": "1.0.0-rc.13",
|
||||
"@rolldown/binding-wasm32-wasi": "1.0.0-rc.13",
|
||||
"@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.13",
|
||||
"@rolldown/binding-win32-x64-msvc": "1.0.0-rc.13"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.60.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.0.tgz",
|
||||
"integrity": "sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==",
|
||||
"version": "4.60.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz",
|
||||
"integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -10084,31 +10088,31 @@
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.60.0",
|
||||
"@rollup/rollup-android-arm64": "4.60.0",
|
||||
"@rollup/rollup-darwin-arm64": "4.60.0",
|
||||
"@rollup/rollup-darwin-x64": "4.60.0",
|
||||
"@rollup/rollup-freebsd-arm64": "4.60.0",
|
||||
"@rollup/rollup-freebsd-x64": "4.60.0",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.60.0",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.60.0",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.60.0",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.60.0",
|
||||
"@rollup/rollup-linux-loong64-gnu": "4.60.0",
|
||||
"@rollup/rollup-linux-loong64-musl": "4.60.0",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.60.0",
|
||||
"@rollup/rollup-linux-ppc64-musl": "4.60.0",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.60.0",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.60.0",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.60.0",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.60.0",
|
||||
"@rollup/rollup-linux-x64-musl": "4.60.0",
|
||||
"@rollup/rollup-openbsd-x64": "4.60.0",
|
||||
"@rollup/rollup-openharmony-arm64": "4.60.0",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.60.0",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.60.0",
|
||||
"@rollup/rollup-win32-x64-gnu": "4.60.0",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.60.0",
|
||||
"@rollup/rollup-android-arm-eabi": "4.60.1",
|
||||
"@rollup/rollup-android-arm64": "4.60.1",
|
||||
"@rollup/rollup-darwin-arm64": "4.60.1",
|
||||
"@rollup/rollup-darwin-x64": "4.60.1",
|
||||
"@rollup/rollup-freebsd-arm64": "4.60.1",
|
||||
"@rollup/rollup-freebsd-x64": "4.60.1",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.60.1",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.60.1",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.60.1",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.60.1",
|
||||
"@rollup/rollup-linux-loong64-gnu": "4.60.1",
|
||||
"@rollup/rollup-linux-loong64-musl": "4.60.1",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.60.1",
|
||||
"@rollup/rollup-linux-ppc64-musl": "4.60.1",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.60.1",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.60.1",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.60.1",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.60.1",
|
||||
"@rollup/rollup-linux-x64-musl": "4.60.1",
|
||||
"@rollup/rollup-openbsd-x64": "4.60.1",
|
||||
"@rollup/rollup-openharmony-arm64": "4.60.1",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.60.1",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.60.1",
|
||||
"@rollup/rollup-win32-x64-gnu": "4.60.1",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.60.1",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
@ -10316,9 +10320,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/serialize-javascript": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.4.tgz",
|
||||
"integrity": "sha512-DuGdB+Po43Q5Jxwpzt1lhyFSYKryqoNjQSA9M92tyw0lyHIOur+XCalOUe0KTJpyqzT8+fQ5A0Jf7vCx/NKmIg==",
|
||||
"version": "7.0.5",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.5.tgz",
|
||||
"integrity": "sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
@ -11460,16 +11464,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.2.tgz",
|
||||
"integrity": "sha512-1gFhNi+bHhRE/qKZOJXACm6tX4bA3Isy9KuKF15AgSRuRazNBOJfdDemPBU16/mpMxApDPrWvZ08DcLPEoRnuA==",
|
||||
"version": "8.0.6",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.6.tgz",
|
||||
"integrity": "sha512-jeOXoY6N8rOfit/mZADMd0misLqjRdWBB3/S23ZQNuPcbVsfMBJutWD8b4ftdczMOsNyMBnKro0Z1Kt0HIqq5Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lightningcss": "^1.32.0",
|
||||
"picomatch": "^4.0.3",
|
||||
"picomatch": "^4.0.4",
|
||||
"postcss": "^8.5.8",
|
||||
"rolldown": "1.0.0-rc.11",
|
||||
"rolldown": "1.0.0-rc.13",
|
||||
"tinyglobby": "^0.2.15"
|
||||
},
|
||||
"bin": {
|
||||
@ -11487,7 +11491,7 @@
|
||||
"peerDependencies": {
|
||||
"@types/node": "^20.19.0 || >=22.12.0",
|
||||
"@vitejs/devtools": "^0.1.0",
|
||||
"esbuild": "^0.27.0",
|
||||
"esbuild": "^0.27.0 || ^0.28.0",
|
||||
"jiti": ">=1.21.0",
|
||||
"less": "^4.0.0",
|
||||
"sass": "^1.70.0",
|
||||
@ -11538,19 +11542,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vitest": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.1.tgz",
|
||||
"integrity": "sha512-yF+o4POL41rpAzj5KVILUxm1GCjKnELvaqmU9TLLUbMfDzuN0UpUR9uaDs+mCtjPe+uYPksXDRLQGGPvj1cTmA==",
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.2.tgz",
|
||||
"integrity": "sha512-xjR1dMTVHlFLh98JE3i/f/WePqJsah4A0FK9cc8Ehp9Udk0AZk6ccpIZhh1qJ/yxVWRZ+Q54ocnD8TXmkhspGg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/expect": "4.1.1",
|
||||
"@vitest/mocker": "4.1.1",
|
||||
"@vitest/pretty-format": "4.1.1",
|
||||
"@vitest/runner": "4.1.1",
|
||||
"@vitest/snapshot": "4.1.1",
|
||||
"@vitest/spy": "4.1.1",
|
||||
"@vitest/utils": "4.1.1",
|
||||
"@vitest/expect": "4.1.2",
|
||||
"@vitest/mocker": "4.1.2",
|
||||
"@vitest/pretty-format": "4.1.2",
|
||||
"@vitest/runner": "4.1.2",
|
||||
"@vitest/snapshot": "4.1.2",
|
||||
"@vitest/spy": "4.1.2",
|
||||
"@vitest/utils": "4.1.2",
|
||||
"es-module-lexer": "^2.0.0",
|
||||
"expect-type": "^1.3.0",
|
||||
"magic-string": "^0.30.21",
|
||||
@ -11561,7 +11565,7 @@
|
||||
"tinybench": "^2.9.0",
|
||||
"tinyexec": "^1.0.2",
|
||||
"tinyglobby": "^0.2.15",
|
||||
"tinyrainbow": "^3.0.3",
|
||||
"tinyrainbow": "^3.1.0",
|
||||
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0",
|
||||
"why-is-node-running": "^2.3.0"
|
||||
},
|
||||
@ -11578,10 +11582,10 @@
|
||||
"@edge-runtime/vm": "*",
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
|
||||
"@vitest/browser-playwright": "4.1.1",
|
||||
"@vitest/browser-preview": "4.1.1",
|
||||
"@vitest/browser-webdriverio": "4.1.1",
|
||||
"@vitest/ui": "4.1.1",
|
||||
"@vitest/browser-playwright": "4.1.2",
|
||||
"@vitest/browser-preview": "4.1.2",
|
||||
"@vitest/browser-webdriverio": "4.1.2",
|
||||
"@vitest/ui": "4.1.2",
|
||||
"happy-dom": "*",
|
||||
"jsdom": "*",
|
||||
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "axios",
|
||||
"version": "1.14.0",
|
||||
"version": "1.15.0",
|
||||
"description": "Promise based HTTP client for the browser and node.js",
|
||||
"main": "./dist/node/axios.cjs",
|
||||
"module": "./index.js",
|
||||
@ -109,8 +109,11 @@
|
||||
"test:vitest:watch": "vitest",
|
||||
"test:smoke:cjs:vitest": "npm --prefix tests/smoke/cjs run test:smoke:cjs:mocha",
|
||||
"test:smoke:esm:vitest": "npm --prefix tests/smoke/esm run test:smoke:esm:vitest",
|
||||
"test:smoke:deno": "deno task --cwd tests/smoke/deno test",
|
||||
"test:smoke:bun": "bun test --cwd tests/smoke/bun",
|
||||
"test:module:cjs": "npm --prefix tests/module/cjs run test:module:cjs",
|
||||
"test:module:esm": "npm --prefix tests/module/esm run test:module:esm",
|
||||
"docs:dev": "cd docs && npm run docs:dev",
|
||||
"start": "node ./sandbox/server.js",
|
||||
"examples": "node ./examples/server.js",
|
||||
"lint": "eslint lib/**/*.js",
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import fs from 'fs';
|
||||
import url from 'url';
|
||||
import path from 'path';
|
||||
import http from 'http';
|
||||
|
||||
@ -76,8 +75,8 @@ function handleApiRequest(req, res) {
|
||||
function requestHandler(req, res) {
|
||||
req.setEncoding('utf8');
|
||||
|
||||
const parsed = url.parse(req.url, true);
|
||||
let pathname = parsed.pathname;
|
||||
const parsed = new URL(req.url, 'http://localhost');
|
||||
const pathname = parsed.pathname;
|
||||
|
||||
console.log('[' + new Date() + ']', req.method, pathname);
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import axios from '../index.js';
|
||||
import { colorize } from './helpers/colorize.js';
|
||||
|
||||
const { GITHUB_TOKEN } = process.env;
|
||||
|
||||
@ -12,8 +11,9 @@ export default axios.create({
|
||||
defaultTransform[0],
|
||||
function (data) {
|
||||
console.log(
|
||||
colorize()`[${this.method.toUpperCase()}] Request [${new URL(axios.getUri(this)).pathname}]`
|
||||
`[${this.method.toUpperCase()}] Request [${new URL(axios.getUri(this)).pathname}]`
|
||||
);
|
||||
|
||||
return data;
|
||||
},
|
||||
],
|
||||
@ -1,7 +1,5 @@
|
||||
import fs from 'fs/promises';
|
||||
import _axios from '../index.js';
|
||||
import { exec } from './repo.js';
|
||||
import { colorize } from './helpers/colorize.js';
|
||||
|
||||
const axios = _axios.create({
|
||||
headers: {
|
||||
@ -27,6 +25,15 @@ const getWithRetry = (url, retries = 3) => {
|
||||
return doRequest();
|
||||
};
|
||||
|
||||
const setGithubOutput = async (key, value) => {
|
||||
if (!process.env.GITHUB_OUTPUT) {
|
||||
console.warn(`GITHUB_OUTPUT is not set; skipping output ${key}=${value}`);
|
||||
return;
|
||||
}
|
||||
|
||||
await fs.appendFile(process.env.GITHUB_OUTPUT, `${key}=${value}\n`);
|
||||
};
|
||||
|
||||
const updateReadmeSponsors = async (url, path, marker = '<!--<div>marker</div>-->') => {
|
||||
let fileContent = (await fs.readFile(path)).toString();
|
||||
|
||||
@ -41,14 +48,14 @@ const updateReadmeSponsors = async (url, path, marker = '<!--<div>marker</div>--
|
||||
const currentSponsorContent = fileContent.slice(0, index);
|
||||
|
||||
if (currentSponsorContent !== sponsorContent) {
|
||||
console.log(colorize()`Sponsor block in [${path}] is outdated`);
|
||||
console.log(`Sponsor block in [${path}] is outdated`);
|
||||
await fs.writeFile(path, sponsorContent + readmeContent);
|
||||
return sponsorContent;
|
||||
} else {
|
||||
console.log(colorize()`Sponsor block in [${path}] is up to date`);
|
||||
}
|
||||
|
||||
console.log(`Sponsor block in [${path}] is up to date`);
|
||||
} else {
|
||||
console.warn(colorize()`Can not find marker (${marker}) in ${path} to inject sponsor block`);
|
||||
console.warn(`Can not find marker (${marker}) in ${path} to inject sponsor block`);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -57,7 +64,7 @@ const updateReadmeSponsors = async (url, path, marker = '<!--<div>marker</div>--
|
||||
(async (url) => {
|
||||
const newContent = await updateReadmeSponsors(url, './README.md');
|
||||
|
||||
await exec(`echo "changed=${newContent ? 'true' : 'false'}" >> $GITHUB_OUTPUT`);
|
||||
await setGithubOutput('changed', newContent ? 'true' : 'false');
|
||||
if (newContent !== false) {
|
||||
await fs.mkdir('./temp').catch(() => {});
|
||||
await fs.writeFile('./temp/sponsors.md', newContent);
|
||||