forked from daren.hsu/line_push
update
This commit is contained in:
+366
-4
@@ -1,5 +1,368 @@
|
||||
# Changelog
|
||||
|
||||
### 0.21.4 (September 6, 2021)
|
||||
|
||||
Fixes and Functionality:
|
||||
- Fixing JSON transform when data is stringified. Providing backward compatibility and complying to the JSON RFC standard ([#4020](https://github.com/axios/axios/pull/4020))
|
||||
|
||||
Huge thanks to everyone who contributed to this release via code (authors listed below) or via reviews and triaging on GitHub:
|
||||
|
||||
- [Jay](mailto:jasonsaayman@gmail.com)
|
||||
- [Guillaume Fortaine](https://github.com/gfortaine)
|
||||
- [Yusuke Kawasaki](https://github.com/kawanet)
|
||||
- [Dmitriy Mozgovoy](https://github.com/DigitalBrainJS)
|
||||
|
||||
### 0.21.3 (September 4, 2021)
|
||||
|
||||
Fixes and Functionality:
|
||||
- Fixing response interceptor not being called when request interceptor is attached ([#4013](https://github.com/axios/axios/pull/4013))
|
||||
|
||||
Huge thanks to everyone who contributed to this release via code (authors listed below) or via reviews and triaging on GitHub:
|
||||
|
||||
- [Jay](mailto:jasonsaayman@gmail.com)
|
||||
- [Julian Hollmann](https://github.com/nerdbeere)
|
||||
|
||||
### 0.21.2 (September 4, 2021)
|
||||
|
||||
Fixes and Functionality:
|
||||
|
||||
- Updating axios requests to be delayed by pre-emptive promise creation ([#2702](https://github.com/axios/axios/pull/2702))
|
||||
- Adding "synchronous" and "runWhen" options to interceptors api ([#2702](https://github.com/axios/axios/pull/2702))
|
||||
- Updating of transformResponse ([#3377](https://github.com/axios/axios/pull/3377))
|
||||
- Adding ability to omit User-Agent header ([#3703](https://github.com/axios/axios/pull/3703))
|
||||
- Adding multiple JSON improvements ([#3688](https://github.com/axios/axios/pull/3688), [#3763](https://github.com/axios/axios/pull/3763))
|
||||
- Fixing quadratic runtime and extra memory usage when setting a maxContentLength ([#3738](https://github.com/axios/axios/pull/3738))
|
||||
- Adding parseInt to config.timeout ([#3781](https://github.com/axios/axios/pull/3781))
|
||||
- Adding custom return type support to interceptor ([#3783](https://github.com/axios/axios/pull/3783))
|
||||
- Adding security fix for ReDoS vulnerability ([#3980](https://github.com/axios/axios/pull/3980))
|
||||
|
||||
Internal and Tests:
|
||||
|
||||
- Updating build dev dependancies ([#3401](https://github.com/axios/axios/pull/3401))
|
||||
- Fixing builds running on Travis CI ([#3538](https://github.com/axios/axios/pull/3538))
|
||||
- Updating follow rediect version ([#3694](https://github.com/axios/axios/pull/3694), [#3771](https://github.com/axios/axios/pull/3771))
|
||||
- Updating karma sauce launcher to fix failing sauce tests ([#3712](https://github.com/axios/axios/pull/3712), [#3717](https://github.com/axios/axios/pull/3717))
|
||||
- Updating content-type header for application/json to not contain charset field, according do RFC 8259 ([#2154](https://github.com/axios/axios/pull/2154))
|
||||
- Fixing tests by bumping karma-sauce-launcher version ([#3813](https://github.com/axios/axios/pull/3813))
|
||||
- Changing testing process from Travis CI to GitHub Actions ([#3938](https://github.com/axios/axios/pull/3938))
|
||||
|
||||
Documentation:
|
||||
|
||||
- Updating documentation around the use of `AUTH_TOKEN` with multiple domain endpoints ([#3539](https://github.com/axios/axios/pull/3539))
|
||||
- Remove duplication of item in changelog ([#3523](https://github.com/axios/axios/pull/3523))
|
||||
- Fixing gramatical errors ([#2642](https://github.com/axios/axios/pull/2642))
|
||||
- Fixing spelling error ([#3567](https://github.com/axios/axios/pull/3567))
|
||||
- Moving gitpod metion ([#2637](https://github.com/axios/axios/pull/2637))
|
||||
- Adding new axios documentation website link ([#3681](https://github.com/axios/axios/pull/3681), [#3707](https://github.com/axios/axios/pull/3707))
|
||||
- Updating documentation around dispatching requests ([#3772](https://github.com/axios/axios/pull/3772))
|
||||
- Adding documentation for the type guard isAxiosError ([#3767](https://github.com/axios/axios/pull/3767))
|
||||
- Adding explanation of cancel token ([#3803](https://github.com/axios/axios/pull/3803))
|
||||
- Updating CI status badge ([#3953](https://github.com/axios/axios/pull/3953))
|
||||
- Fixing errors with JSON documentation ([#3936](https://github.com/axios/axios/pull/3936))
|
||||
- Fixing README typo under Request Config ([#3825](https://github.com/axios/axios/pull/3825))
|
||||
- Adding axios-multi-api to the ecosystem file ([#3817](https://github.com/axios/axios/pull/3817))
|
||||
- Adding SECURITY.md to properly disclose security vulnerabilities ([#3981](https://github.com/axios/axios/pull/3981))
|
||||
|
||||
Huge thanks to everyone who contributed to this release via code (authors listed below) or via reviews and triaging on GitHub:
|
||||
|
||||
- [Jay](mailto:jasonsaayman@gmail.com)
|
||||
- [Sasha Korotkov](https://github.com/SashaKoro)
|
||||
- [Daniel Lopretto](https://github.com/timemachine3030)
|
||||
- [Mike Bishop](https://github.com/MikeBishop)
|
||||
- [Dmitriy Mozgovoy](https://github.com/DigitalBrainJS)
|
||||
- [Mark](https://github.com/bimbiltu)
|
||||
- [Philipe Gouveia Paixão](https://github.com/piiih)
|
||||
- [hippo](https://github.com/hippo2cat)
|
||||
- [ready-research](https://github.com/ready-research)
|
||||
- [Xianming Zhong](https://github.com/chinesedfan)
|
||||
- [Christopher Chrapka](https://github.com/OJezu)
|
||||
- [Brian Anglin](https://github.com/anglinb)
|
||||
- [Kohta Ito](https://github.com/koh110)
|
||||
- [Ali Clark](https://github.com/aliclark)
|
||||
- [caikan](https://github.com/caikan)
|
||||
- [Elina Gorshkova](https://github.com/elinagorshkova)
|
||||
- [Ryota Ikezawa](https://github.com/paveg)
|
||||
- [Nisar Hassan Naqvi](https://github.com/nisarhassan12)
|
||||
- [Jake](https://github.com/codemaster138)
|
||||
- [TagawaHirotaka](https://github.com/wafuwafu13)
|
||||
- [Johannes Jarbratt](https://github.com/johachi)
|
||||
- [Mo Sattler](https://github.com/MoSattler)
|
||||
- [Sam Carlton](https://github.com/ThatGuySam)
|
||||
- [Matt Czapliński](https://github.com/MattCCC)
|
||||
- [Ziding Zhang](https://github.com/zidingz)
|
||||
|
||||
### 0.21.1 (December 21, 2020)
|
||||
|
||||
Fixes and Functionality:
|
||||
|
||||
- Hotfix: Prevent SSRF ([#3410](https://github.com/axios/axios/pull/3410))
|
||||
- Protocol not parsed when setting proxy config from env vars ([#3070](https://github.com/axios/axios/pull/3070))
|
||||
- Updating axios in types to be lower case ([#2797](https://github.com/axios/axios/pull/2797))
|
||||
- Adding a type guard for `AxiosError` ([#2949](https://github.com/axios/axios/pull/2949))
|
||||
|
||||
Internal and Tests:
|
||||
|
||||
- Remove the skipping of the `socket` http test ([#3364](https://github.com/axios/axios/pull/3364))
|
||||
- Use different socket for Win32 test ([#3375](https://github.com/axios/axios/pull/3375))
|
||||
|
||||
Huge thanks to everyone who contributed to this release via code (authors listed below) or via reviews and triaging on GitHub:
|
||||
|
||||
- Daniel Lopretto <timemachine3030@users.noreply.github.com>
|
||||
- Jason Kwok <JasonHK@users.noreply.github.com>
|
||||
- Jay <jasonsaayman@gmail.com>
|
||||
- Jonathan Foster <jonathan@jonathanfoster.io>
|
||||
- Remco Haszing <remcohaszing@gmail.com>
|
||||
- Xianming Zhong <chinesedfan@qq.com>
|
||||
|
||||
### 0.21.0 (October 23, 2020)
|
||||
|
||||
Fixes and Functionality:
|
||||
|
||||
- Fixing requestHeaders.Authorization ([#3287](https://github.com/axios/axios/pull/3287))
|
||||
- Fixing node types ([#3237](https://github.com/axios/axios/pull/3237))
|
||||
- Fixing axios.delete ignores config.data ([#3282](https://github.com/axios/axios/pull/3282))
|
||||
- Revert "Fixing overwrite Blob/File type as Content-Type in browser. (#1773)" ([#3289](https://github.com/axios/axios/pull/3289))
|
||||
- Fixing an issue that type 'null' and 'undefined' is not assignable to validateStatus when typescript strict option is enabled ([#3200](https://github.com/axios/axios/pull/3200))
|
||||
|
||||
Internal and Tests:
|
||||
|
||||
- Lock travis to not use node v15 ([#3361](https://github.com/axios/axios/pull/3361))
|
||||
|
||||
Documentation:
|
||||
|
||||
- Fixing simple typo, existant -> existent ([#3252](https://github.com/axios/axios/pull/3252))
|
||||
- Fixing typos ([#3309](https://github.com/axios/axios/pull/3309))
|
||||
|
||||
Huge thanks to everyone who contributed to this release via code (authors listed below) or via reviews and triaging on GitHub:
|
||||
|
||||
- Allan Cruz <57270969+Allanbcruz@users.noreply.github.com>
|
||||
- George Cheng <Gerhut@GMail.com>
|
||||
- Jay <jasonsaayman@gmail.com>
|
||||
- Kevin Kirsche <Kev.Kirsche+GitHub@gmail.com>
|
||||
- Remco Haszing <remcohaszing@gmail.com>
|
||||
- Taemin Shin <cprayer13@gmail.com>
|
||||
- Tim Gates <tim.gates@iress.com>
|
||||
- Xianming Zhong <chinesedfan@qq.com>
|
||||
|
||||
### 0.20.0 (August 20, 2020)
|
||||
|
||||
Release of 0.20.0-pre as a full release with no other changes.
|
||||
|
||||
### 0.20.0-pre (July 15, 2020)
|
||||
|
||||
Fixes and Functionality:
|
||||
|
||||
- Fixing response with utf-8 BOM can not parse to json ([#2419](https://github.com/axios/axios/pull/2419))
|
||||
- fix: remove byte order marker (UTF-8 BOM) when transform response
|
||||
- fix: remove BOM only utf-8
|
||||
- test: utf-8 BOM
|
||||
- fix: incorrect param name
|
||||
- Refactor mergeConfig without utils.deepMerge ([#2844](https://github.com/axios/axios/pull/2844))
|
||||
- Adding failing test
|
||||
- Fixing #2587 default custom config persisting
|
||||
- Adding Concat keys and filter duplicates
|
||||
- Fixed value from CPE
|
||||
- update for review feedbacks
|
||||
- no deepMerge
|
||||
- only merge between plain objects
|
||||
- fix rename
|
||||
- always merge config by mergeConfig
|
||||
- extract function mergeDeepProperties
|
||||
- refactor mergeConfig with all keys, and add special logic for validateStatus
|
||||
- add test for resetting headers
|
||||
- add lots of tests and fix a bug
|
||||
- should not inherit `data`
|
||||
- use simple toString
|
||||
- Fixing overwrite Blob/File type as Content-Type in browser. ([#1773](https://github.com/axios/axios/pull/1773))
|
||||
- Fixing an issue that type 'null' is not assignable to validateStatus ([#2773](https://github.com/axios/axios/pull/2773))
|
||||
- Fixing special char encoding ([#1671](https://github.com/axios/axios/pull/1671))
|
||||
- removing @ character from replacement list since it is a reserved character
|
||||
- Updating buildURL test to not include the @ character
|
||||
- Removing console logs
|
||||
- Fixing password encoding with special characters in basic authentication ([#1492](https://github.com/axios/axios/pull/1492))
|
||||
- Fixing password encoding with special characters in basic authentication
|
||||
- Adding test to check if password with non-Latin1 characters pass
|
||||
- Fixing 'Network Error' in react native android ([#1487](https://github.com/axios/axios/pull/1487))
|
||||
There is a bug in react native Android platform when using get method. It will trigger a 'Network Error' when passing the requestData which is an empty string to request.send function. So if the requestData is an empty string we can set it to null as well to fix the bug.
|
||||
- Fixing Cookie Helper with Async Components ([#1105](https://github.com/axios/axios/pull/1105)) ([#1107](https://github.com/axios/axios/pull/1107))
|
||||
- Fixing 'progressEvent' type ([#2851](https://github.com/axios/axios/pull/2851))
|
||||
- Fix 'progressEvent' type
|
||||
- Update axios.ts
|
||||
- Fixing getting local files (file://) failed ([#2470](https://github.com/axios/axios/pull/2470))
|
||||
- fix issue #2416, #2396
|
||||
- fix Eslint warn
|
||||
- Modify judgment conditions
|
||||
- add unit test
|
||||
- update unit test
|
||||
- update unit test
|
||||
- Allow PURGE method in typings ([#2191](https://github.com/axios/axios/pull/2191))
|
||||
- Adding option to disable automatic decompression ([#2661](https://github.com/axios/axios/pull/2661))
|
||||
- Adding ability to disable auto decompression
|
||||
- Updating decompress documentation in README
|
||||
- Fixing test\unit\adapters\http.js lint errors
|
||||
- Adding test for disabling auto decompression
|
||||
- Removing changes that fixed lint errors in tests
|
||||
- Removing formatting change to unit test
|
||||
- Add independent `maxBodyLength` option ([#2781](https://github.com/axios/axios/pull/2781))
|
||||
- Add independent option to set the maximum size of the request body
|
||||
- Remove maxBodyLength check
|
||||
- Update README
|
||||
- Assert for error code and message
|
||||
- Adding responseEncoding to mergeConfig ([#1745](https://github.com/axios/axios/pull/1745))
|
||||
- Compatible with follow-redirect aborts the request ([#2689](https://github.com/axios/axios/pull/2689))
|
||||
- Compatible with follow-redirect aborts the request
|
||||
- Use the error code
|
||||
- Fix merging of params ([#2656](https://github.com/axios/axios/pull/2656))
|
||||
- Name function to avoid ESLint func-names warning
|
||||
- Switch params config to merge list and update tests
|
||||
- Restore testing of both false and null
|
||||
- Restore test cases for keys without defaults
|
||||
- Include test for non-object values that aren't false-y.
|
||||
- Revert `finally` as `then` ([#2683](https://github.com/axios/axios/pull/2683))
|
||||
|
||||
Internal and Tests:
|
||||
|
||||
- Fix stale bot config ([#3049](https://github.com/axios/axios/pull/3049))
|
||||
- fix stale bot config
|
||||
- fix multiple lines
|
||||
- Add days and change name to work ([#3035](https://github.com/axios/axios/pull/3035))
|
||||
- Update close-issues.yml ([#3031](https://github.com/axios/axios/pull/3031))
|
||||
- Update close-issues.yml
|
||||
Update close message to read better 😄
|
||||
- Fix use of quotations
|
||||
Use single quotes as per other .yml files
|
||||
- Remove user name form message
|
||||
- Add GitHub actions to close stale issues/prs ([#3029](https://github.com/axios/axios/pull/3029))
|
||||
- prepare stale actions
|
||||
- update messages
|
||||
- Add exempt labels and lighten up comments
|
||||
- Add GitHub actions to close invalid issues ([#3022](https://github.com/axios/axios/pull/3022))
|
||||
- add close actions
|
||||
- fix with checkout
|
||||
- update issue templates
|
||||
- add reminder
|
||||
- update close message
|
||||
- Add test with Node.js 12 ([#2860](https://github.com/axios/axios/pull/2860))
|
||||
- test with Node.js 12
|
||||
- test with latest
|
||||
- Adding console log on sandbox server startup ([#2210](https://github.com/axios/axios/pull/2210))
|
||||
- Adding console log on sandbox server startup
|
||||
- Update server.js
|
||||
Add server error handling
|
||||
- Update server.js
|
||||
Better error message, remove retry.
|
||||
- Adding tests for method `options` type definitions ([#1996](https://github.com/axios/axios/pull/1996))
|
||||
Update tests.
|
||||
- Add test for redirecting with too large response ([#2695](https://github.com/axios/axios/pull/2695))
|
||||
- Fixing unit test failure in Windows OS ([#2601](https://github.com/axios/axios/pull/2601))
|
||||
- Fixing issue for HEAD method and gzipped response ([#2666](https://github.com/axios/axios/pull/2666))
|
||||
- Fix tests in browsers ([#2748](https://github.com/axios/axios/pull/2748))
|
||||
- chore: add `jsdelivr` and `unpkg` support ([#2443](https://github.com/axios/axios/pull/2443))
|
||||
|
||||
Documentation:
|
||||
|
||||
- Adding support for URLSearchParams in node ([#1900](https://github.com/axios/axios/pull/1900))
|
||||
- Adding support for URLSearchParams in node
|
||||
- Remove un-needed code
|
||||
- Update utils.js
|
||||
- Make changes as suggested
|
||||
- Adding table of content (preview) ([#3050](https://github.com/axios/axios/pull/3050))
|
||||
- add toc (preview)
|
||||
- remove toc in toc
|
||||
Signed-off-by: Moni <usmoni@gmail.com>
|
||||
- fix sublinks
|
||||
- fix indentation
|
||||
- remove redundant table links
|
||||
- update caps and indent
|
||||
- remove axios
|
||||
- Replace 'blacklist' with 'blocklist' ([#3006](https://github.com/axios/axios/pull/3006))
|
||||
- docs(): Detailed config options environment. ([#2088](https://github.com/axios/axios/pull/2088))
|
||||
- docs(): Detailed config options environment.
|
||||
- Update README.md
|
||||
- Include axios-data-unpacker in ECOSYSTEM.md ([#2080](https://github.com/axios/axios/pull/2080))
|
||||
- Allow opening examples in Gitpod ([#1958](https://github.com/axios/axios/pull/1958))
|
||||
- Remove axios.all() and axios.spread() from Readme.md ([#2727](https://github.com/axios/axios/pull/2727))
|
||||
- remove axios.all(), axios.spread()
|
||||
- replace example
|
||||
- axios.all() -> Promise.all()
|
||||
- axios.spread(function (acct, perms)) -> function (acct, perms)
|
||||
- add deprecated mark
|
||||
- Update README.md ([#2887](https://github.com/axios/axios/pull/2887))
|
||||
Small change to the data attribute doc of the config. A request body can also be set for DELETE methods but this wasn't mentioned in the documentation (it only mentioned POST, PUT and PATCH). Took my some 10-20 minutes until I realized that I don't need to manipulate the request body with transformRequest in the case of DELETE.
|
||||
- Include swagger-taxos-codegen in ECOSYSTEM.md ([#2162](https://github.com/axios/axios/pull/2162))
|
||||
- Add CDNJS version badge in README.md ([#878](https://github.com/axios/axios/pull/878))
|
||||
This badge will show the version on CDNJS!
|
||||
- Documentation update to clear up ambiguity in code examples ([#2928](https://github.com/axios/axios/pull/2928))
|
||||
- Made an adjustment to the documentation to clear up any ambiguity around the use of "fs". This should help clear up that the code examples with "fs" cannot be used on the client side.
|
||||
- Update README.md about validateStatus ([#2912](https://github.com/axios/axios/pull/2912))
|
||||
Rewrote the comment from "Reject only if the status code is greater than or equal to 500" to "Resolve only if the status code is less than 500"
|
||||
- Updating documentation for usage form-data ([#2805](https://github.com/axios/axios/pull/2805))
|
||||
Closes #2049
|
||||
- Fixing CHANGELOG.md issue link ([#2784](https://github.com/axios/axios/pull/2784))
|
||||
- Include axios-hooks in ECOSYSTEM.md ([#2003](https://github.com/axios/axios/pull/2003))
|
||||
- Added Response header access instructions ([#1901](https://github.com/axios/axios/pull/1901))
|
||||
- Added Response header access instructions
|
||||
- Added note about using bracket notation
|
||||
- Add `onUploadProgress` and `onDownloadProgress` are browser only ([#2763](https://github.com/axios/axios/pull/2763))
|
||||
Saw in #928 and #1966 that `onUploadProgress` and `onDownloadProgress` only work in the browser and was missing that from the README.
|
||||
- Update ' sign to ` in proxy spec ([#2778](https://github.com/axios/axios/pull/2778))
|
||||
- Adding jsDelivr link in README ([#1110](https://github.com/axios/axios/pull/1110))
|
||||
- Adding jsDelivr link
|
||||
- Add SRI
|
||||
- Remove SRI
|
||||
|
||||
Huge thanks to everyone who contributed to this release via code (authors listed
|
||||
below) or via reviews and triaging on GitHub:
|
||||
|
||||
- Alan Wang <wp_scut@163.com>
|
||||
- Alexandru Ungureanu <khakcarot@gmail.com>
|
||||
- Anubhav Srivastava <anubhav.srivastava00@gmail.com>
|
||||
- Benny Neugebauer <bn@bennyn.de>
|
||||
- Cr <631807682@qq.com>
|
||||
- David <cygnidavid@gmail.com>
|
||||
- David Ko <david.ko@pvtmethod.com>
|
||||
- David Tanner <david.tanner@lifeomic.com>
|
||||
- Emily Morehouse <emilyemorehouse@gmail.com>
|
||||
- Felipe Martins <felipewmartins@gmail.com>
|
||||
- Fonger <5862369+Fonger@users.noreply.github.com>
|
||||
- Frostack <soulburn007@gmail.com>
|
||||
- George Cheng <Gerhut@GMail.com>
|
||||
- grumblerchester <grumblerchester@users.noreply.github.com>
|
||||
- Gustavo López <gualopezb@gmail.com>
|
||||
- hexaez <45806662+hexaez@users.noreply.github.com>
|
||||
- huangzuizui <huangzuizui@gmail.com>
|
||||
- Ian Wijma <ian@wij.ma>
|
||||
- Jay <jasonsaayman@gmail.com>
|
||||
- jeffjing <zgayjjf@qq.com>
|
||||
- jennynju <46782518+jennynju@users.noreply.github.com>
|
||||
- Jimmy Liao <52391190+jimmy-liao-gogoro@users.noreply.github.com>
|
||||
- Jonathan Sharpe <j.r.sharpe@gmail.com>
|
||||
- JounQin <admin@1stg.me>
|
||||
- Justin Beckwith <justin.beckwith@gmail.com>
|
||||
- Kamil Posiadała <3dcreator.pl@gmail.com>
|
||||
- Lukas Drgon <lukas.drgon@gmail.com>
|
||||
- marcinx <mail@marcinx.com>
|
||||
- Martti Laine <martti@codeclown.net>
|
||||
- Michał Zarach <michal.m.zarach@gmail.com>
|
||||
- Moni <usmoni@gmail.com>
|
||||
- Motonori Iwata <121048+iwata@users.noreply.github.com>
|
||||
- Nikita Galkin <nikita@galk.in>
|
||||
- Petr Mares <petr@mares.tw>
|
||||
- Philippe Recto <precto1285@gmal.com>
|
||||
- Remco Haszing <remcohaszing@gmail.com>
|
||||
- rockcs1992 <chengshi1219@gmail.com>
|
||||
- Ryan Bown <rbown@niftee.com.au>
|
||||
- Samina Fu <sufuf3@gmail.com>
|
||||
- Simone Busoli <simone.busoli@gmail.com>
|
||||
- Spencer von der Ohe <s.vonderohe40@gmail.com>
|
||||
- Sven Efftinge <sven.efftinge@typefox.io>
|
||||
- Taegyeoung Oh <otk1090@naver.com>
|
||||
- Taemin Shin <cprayer13@gmail.com>
|
||||
- Thibault Ehrhart <1208424+ehrhart@users.noreply.github.com>
|
||||
- Xianming Zhong <chinesedfan@qq.com>
|
||||
- Yasu Flores <carlosyasu91@gmail.com>
|
||||
- Zac Delventhal <delventhalz@gmail.com>
|
||||
|
||||
### 0.19.2 (Jan 20, 2020)
|
||||
|
||||
- Remove unnecessary XSS check ([#2679](https://github.com/axios/axios/pull/2679)) (see ([#2646](https://github.com/axios/axios/issues/2646)) for discussion)
|
||||
@@ -25,7 +388,7 @@ Fixes and Functionality:
|
||||
- Add error toJSON example ([#2466](https://github.com/axios/axios/pull/2466))
|
||||
- Fixing Vulnerability A Fortify Scan finds a critical Cross-Site Scrip… ([#2451](https://github.com/axios/axios/pull/2451))
|
||||
- Fixing subdomain handling on no_proxy ([#2442](https://github.com/axios/axios/pull/2442))
|
||||
- Make redirection from HTTP to HTTPS work ([#2426](https://github.com/axios/axios/pull/2426] and ([#2547](https://github.com/axios/axios/pull/2547))
|
||||
- Make redirection from HTTP to HTTPS work ([#2426](https://github.com/axios/axios/pull/2426)) and ([#2547](https://github.com/axios/axios/pull/2547))
|
||||
- Add toJSON property to AxiosError type ([#2427](https://github.com/axios/axios/pull/2427))
|
||||
- Fixing socket hang up error on node side for slow response. ([#1752](https://github.com/axios/axios/pull/1752))
|
||||
- Alternative syntax to send data into the body ([#2317](https://github.com/axios/axios/pull/2317))
|
||||
@@ -33,7 +396,6 @@ Fixes and Functionality:
|
||||
- Fixing set `config.method` after mergeConfig for Axios.prototype.request ([#2383](https://github.com/axios/axios/pull/2383))
|
||||
- Axios create url bug ([#2290](https://github.com/axios/axios/pull/2290))
|
||||
- Do not modify config.url when using a relative baseURL (resolves [#1628](https://github.com/axios/axios/issues/1098)) ([#2391](https://github.com/axios/axios/pull/2391))
|
||||
- Add typescript HTTP method definition for LINK and UNLINK ([#2444](https://github.com/axios/axios/pull/2444))
|
||||
|
||||
Internal:
|
||||
|
||||
@@ -57,7 +419,7 @@ Documentation:
|
||||
- Update response interceptor docs ([#2399](https://github.com/axios/axios/pull/2399))
|
||||
- Update README.md ([#2504](https://github.com/axios/axios/pull/2504))
|
||||
- Fix word 'sintaxe' to 'syntax' in README.md ([#2432](https://github.com/axios/axios/pull/2432))
|
||||
- upadating README: notes on CommonJS autocomplete ([#2256](https://github.com/axios/axios/pull/2256))
|
||||
- updating README: notes on CommonJS autocomplete ([#2256](https://github.com/axios/axios/pull/2256))
|
||||
- Fix grammar in README.md ([#2271](https://github.com/axios/axios/pull/2271))
|
||||
- Doc fixes, minor examples cleanup ([#2198](https://github.com/axios/axios/pull/2198))
|
||||
|
||||
@@ -110,7 +472,7 @@ New Functionality:
|
||||
|
||||
- Add getUri method ([#1712](https://github.com/axios/axios/issues/1712))
|
||||
- Add support for no_proxy env variable ([#1693](https://github.com/axios/axios/issues/1693))
|
||||
- Add toJSON to decorated Axios errors to faciliate serialization ([#1625](https://github.com/axios/axios/issues/1625))
|
||||
- Add toJSON to decorated Axios errors to facilitate serialization ([#1625](https://github.com/axios/axios/issues/1625))
|
||||
- Add second then on axios call ([#1623](https://github.com/axios/axios/issues/1623))
|
||||
- Typings: allow custom return types
|
||||
- Add option to specify character set in responses (with http adapter)
|
||||
|
||||
+182
-23
@@ -1,7 +1,9 @@
|
||||
# axios
|
||||
|
||||
[](https://www.npmjs.org/package/axios)
|
||||
[](https://travis-ci.org/axios/axios)
|
||||
[](https://cdnjs.com/libraries/axios)
|
||||

|
||||
[](https://gitpod.io/#https://github.com/axios/axios)
|
||||
[](https://coveralls.io/r/mzabriskie/axios)
|
||||
[](https://packagephobia.now.sh/result?p=axios)
|
||||
[](http://npm-stat.com/charts.html?package=axios)
|
||||
@@ -10,6 +12,40 @@
|
||||
|
||||
Promise based HTTP client for the browser and node.js
|
||||
|
||||
> New axios docs website: [click here](https://axios-http.com/)
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Features](#features)
|
||||
- [Browser Support](#browser-support)
|
||||
- [Installing](#installing)
|
||||
- [Example](#example)
|
||||
- [Axios API](#axios-api)
|
||||
- [Request method aliases](#request-method-aliases)
|
||||
- [Concurrency (Deprecated)](#concurrency-deprecated)
|
||||
- [Creating an instance](#creating-an-instance)
|
||||
- [Instance methods](#instance-methods)
|
||||
- [Request Config](#request-config)
|
||||
- [Response Schema](#response-schema)
|
||||
- [Config Defaults](#config-defaults)
|
||||
- [Global axios defaults](#global-axios-defaults)
|
||||
- [Custom instance defaults](#custom-instance-defaults)
|
||||
- [Config order of precedence](#config-order-of-precedence)
|
||||
- [Interceptors](#interceptors)
|
||||
- [Handling Errors](#handling-errors)
|
||||
- [Cancellation](#cancellation)
|
||||
- [Using application/x-www-form-urlencoded format](#using-applicationx-www-form-urlencoded-format)
|
||||
- [Browser](#browser)
|
||||
- [Node.js](#nodejs)
|
||||
- [Query string](#query-string)
|
||||
- [Form data](#form-data)
|
||||
- [Semver](#semver)
|
||||
- [Promises](#promises)
|
||||
- [TypeScript](#typescript)
|
||||
- [Resources](#resources)
|
||||
- [Credits](#credits)
|
||||
- [License](#license)
|
||||
|
||||
## Features
|
||||
|
||||
- Make [XMLHttpRequests](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) from the browser
|
||||
@@ -49,7 +85,13 @@ Using yarn:
|
||||
$ yarn add axios
|
||||
```
|
||||
|
||||
Using cdn:
|
||||
Using jsDelivr CDN:
|
||||
|
||||
```html
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
```
|
||||
|
||||
Using unpkg CDN:
|
||||
|
||||
```html
|
||||
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
|
||||
@@ -81,7 +123,7 @@ axios.get('/user?ID=12345')
|
||||
// handle error
|
||||
console.log(error);
|
||||
})
|
||||
.finally(function () {
|
||||
.then(function () {
|
||||
// always executed
|
||||
});
|
||||
|
||||
@@ -97,7 +139,7 @@ axios.get('/user', {
|
||||
.catch(function (error) {
|
||||
console.log(error);
|
||||
})
|
||||
.finally(function () {
|
||||
.then(function () {
|
||||
// always executed
|
||||
});
|
||||
|
||||
@@ -141,10 +183,11 @@ function getUserPermissions() {
|
||||
return axios.get('/user/12345/permissions');
|
||||
}
|
||||
|
||||
axios.all([getUserAccount(), getUserPermissions()])
|
||||
.then(axios.spread(function (acct, perms) {
|
||||
// Both requests are now complete
|
||||
}));
|
||||
Promise.all([getUserAccount(), getUserPermissions()])
|
||||
.then(function (results) {
|
||||
const acct = results[0];
|
||||
const perm = results[1];
|
||||
});
|
||||
```
|
||||
|
||||
## axios API
|
||||
@@ -166,7 +209,7 @@ axios({
|
||||
```
|
||||
|
||||
```js
|
||||
// GET request for remote image
|
||||
// GET request for remote image in node.js
|
||||
axios({
|
||||
method: 'get',
|
||||
url: 'http://bit.ly/2mTM3nY',
|
||||
@@ -200,12 +243,13 @@ For convenience aliases have been provided for all supported request methods.
|
||||
###### NOTE
|
||||
When using the alias methods `url`, `method`, and `data` properties don't need to be specified in config.
|
||||
|
||||
### Concurrency
|
||||
### Concurrency (Deprecated)
|
||||
Please use `Promise.all` to replace the below functions.
|
||||
|
||||
Helper functions for dealing with concurrent requests.
|
||||
|
||||
##### axios.all(iterable)
|
||||
##### axios.spread(callback)
|
||||
axios.all(iterable)
|
||||
axios.spread(callback)
|
||||
|
||||
### Creating an instance
|
||||
|
||||
@@ -287,7 +331,7 @@ These are the available config options for making requests. Only the `url` is re
|
||||
},
|
||||
|
||||
// `data` is the data to be sent as the request body
|
||||
// Only applicable for request methods 'PUT', 'POST', and 'PATCH'
|
||||
// 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
|
||||
@@ -330,7 +374,7 @@ These are the available config options for making requests. Only the `url` is re
|
||||
// browser only: 'blob'
|
||||
responseType: 'json', // default
|
||||
|
||||
// `responseEncoding` indicates encoding to use for decoding responses
|
||||
// `responseEncoding` indicates encoding to use for decoding responses (Node.js only)
|
||||
// Note: Ignored for `responseType` of 'stream' or client-side requests
|
||||
responseEncoding: 'utf8', // default
|
||||
|
||||
@@ -341,18 +385,23 @@ These are the available config options for making requests. Only the `url` is re
|
||||
xsrfHeaderName: 'X-XSRF-TOKEN', // default
|
||||
|
||||
// `onUploadProgress` allows handling of progress events for uploads
|
||||
// browser only
|
||||
onUploadProgress: function (progressEvent) {
|
||||
// Do whatever you want with the native progress event
|
||||
},
|
||||
|
||||
// `onDownloadProgress` allows handling of progress events for downloads
|
||||
// browser only
|
||||
onDownloadProgress: function (progressEvent) {
|
||||
// Do whatever you want with the native progress event
|
||||
},
|
||||
|
||||
// `maxContentLength` defines the max size of the http response content in bytes allowed
|
||||
// `maxContentLength` defines the max size of the http response content in bytes allowed in node.js
|
||||
maxContentLength: 2000,
|
||||
|
||||
// `maxBodyLength` (Node only option) defines the max size of the http request content in bytes allowed
|
||||
maxBodyLength: 2000,
|
||||
|
||||
// `validateStatus` defines whether to resolve or reject the promise for a given
|
||||
// HTTP response status code. If `validateStatus` returns `true` (or is set to `null`
|
||||
// or `undefined`), the promise will be resolved; otherwise, the promise will be
|
||||
@@ -377,7 +426,7 @@ These are the available config options for making requests. Only the `url` is re
|
||||
httpAgent: new http.Agent({ keepAlive: true }),
|
||||
httpsAgent: new https.Agent({ keepAlive: true }),
|
||||
|
||||
// 'proxy' defines the hostname and port of the proxy server.
|
||||
// `proxy` defines the hostname, port, and protocol of the proxy server.
|
||||
// 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
|
||||
@@ -387,7 +436,9 @@ These are the available config options for making requests. Only the `url` is re
|
||||
// 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`.
|
||||
proxy: {
|
||||
protocol: 'https',
|
||||
host: '127.0.0.1',
|
||||
port: 9000,
|
||||
auth: {
|
||||
@@ -399,7 +450,27 @@ These are the available config options for making requests. Only the `url` is re
|
||||
// `cancelToken` specifies a cancel token that can be used to cancel the request
|
||||
// (see Cancellation section below for details)
|
||||
cancelToken: new CancelToken(function (cancel) {
|
||||
})
|
||||
}),
|
||||
|
||||
// `decompress` indicates whether or not the response body should be decompressed
|
||||
// automatically. If set to `true` will also remove the 'content-encoding' header
|
||||
// from the responses objects of all decompressed responses
|
||||
// - Node only (XHR cannot turn off decompression)
|
||||
decompress: true, // default
|
||||
|
||||
// transitional options for backward compatibility that may be removed in the newer versions
|
||||
transitional: {
|
||||
// silent JSON parsing mode
|
||||
// `true` - ignore JSON parsing errors and set response.data to null if parsing failed (old behaviour)
|
||||
// `false` - throw SyntaxError if JSON parsing failed (Note: responseType must be set to 'json')
|
||||
silentJSONParsing: true, // default value for the current Axios version
|
||||
|
||||
// try to parse the response string as JSON even if `responseType` is not 'json'
|
||||
forcedJSONParsing: true,
|
||||
|
||||
// throw ETIMEDOUT error instead of generic ECONNABORTED on request timeouts
|
||||
clarifyTimeoutError: false,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -418,8 +489,9 @@ The response for a request contains the following information.
|
||||
// `statusText` is the HTTP status message from the server response
|
||||
statusText: 'OK',
|
||||
|
||||
// `headers` the headers that the server responded with
|
||||
// All header names are lower cased
|
||||
// `headers` the HTTP headers that the server responded with
|
||||
// All header names are lower cased and can be accessed using the bracket notation.
|
||||
// Example: `response.headers['content-type']`
|
||||
headers: {},
|
||||
|
||||
// `config` is the config that was provided to `axios` for the request
|
||||
@@ -455,7 +527,11 @@ You can specify config defaults that will be applied to every request.
|
||||
|
||||
```js
|
||||
axios.defaults.baseURL = 'https://api.example.com';
|
||||
|
||||
// Important: If axios is used with multiple domains, the AUTH_TOKEN will be sent to all of them.
|
||||
// See below for an example using Custom instance defaults instead.
|
||||
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
|
||||
|
||||
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||
```
|
||||
|
||||
@@ -530,6 +606,34 @@ const instance = axios.create();
|
||||
instance.interceptors.request.use(function () {/*...*/});
|
||||
```
|
||||
|
||||
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 });
|
||||
```
|
||||
|
||||
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 });
|
||||
```
|
||||
|
||||
## Handling Errors
|
||||
|
||||
```js
|
||||
@@ -559,7 +663,7 @@ Using the `validateStatus` config option, you can define HTTP code(s) that shoul
|
||||
```js
|
||||
axios.get('/user/12345', {
|
||||
validateStatus: function (status) {
|
||||
return status < 500; // Reject only if the status code is greater than or equal to 500
|
||||
return status < 500; // Resolve only if the status code is less than 500
|
||||
}
|
||||
})
|
||||
```
|
||||
@@ -623,6 +727,7 @@ cancel();
|
||||
```
|
||||
|
||||
> Note: you can cancel several requests with the same cancel token.
|
||||
> 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 real request.
|
||||
|
||||
## Using application/x-www-form-urlencoded format
|
||||
|
||||
@@ -664,6 +769,8 @@ axios(options);
|
||||
|
||||
### Node.js
|
||||
|
||||
#### Query string
|
||||
|
||||
In node.js, you can use the [`querystring`](https://nodejs.org/api/querystring.html) module as follows:
|
||||
|
||||
```js
|
||||
@@ -671,11 +778,45 @@ const querystring = require('querystring');
|
||||
axios.post('http://something.com/', querystring.stringify({ foo: 'bar' }));
|
||||
```
|
||||
|
||||
or ['URLSearchParams'](https://nodejs.org/api/url.html#url_class_urlsearchparams) from ['url module'](https://nodejs.org/api/url.html) as follows:
|
||||
|
||||
```js
|
||||
const url = require('url');
|
||||
const params = new url.URLSearchParams({ foo: 'bar' });
|
||||
axios.post('http://something.com/', params.toString());
|
||||
```
|
||||
|
||||
You can also use the [`qs`](https://github.com/ljharb/qs) library.
|
||||
|
||||
###### NOTE
|
||||
The `qs` library is preferable if you need to stringify nested objects, as the `querystring` method has known issues with that use case (https://github.com/nodejs/node-v0.x-archive/issues/1665).
|
||||
|
||||
#### Form data
|
||||
|
||||
In node.js, you can use the [`form-data`](https://github.com/form-data/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', new Buffer(10));
|
||||
form.append('my_file', fs.createReadStream('/foo/bar.jpg'));
|
||||
|
||||
axios.post('https://example.com', form, { headers: form.getHeaders() })
|
||||
```
|
||||
|
||||
Alternatively, use an interceptor:
|
||||
|
||||
```js
|
||||
axios.interceptors.request.use(config => {
|
||||
if (config.data instanceof FormData) {
|
||||
Object.assign(config.headers, config.data.getHeaders());
|
||||
}
|
||||
return config;
|
||||
});
|
||||
```
|
||||
|
||||
## Semver
|
||||
|
||||
Until axios reaches a `1.0` release, breaking changes will be released with a new minor version. For example `0.5.1`, and `0.5.4` will have the same API, but `0.6.0` will have breaking changes.
|
||||
@@ -686,12 +827,30 @@ axios depends on a native ES6 Promise implementation to be [supported](http://ca
|
||||
If your environment doesn't support ES6 Promises, you can [polyfill](https://github.com/jakearchibald/es6-promise).
|
||||
|
||||
## TypeScript
|
||||
axios includes [TypeScript](http://typescriptlang.org) definitions.
|
||||
|
||||
axios includes [TypeScript](http://typescriptlang.org) definitions and a type guard for axios errors.
|
||||
|
||||
```typescript
|
||||
import axios from 'axios';
|
||||
axios.get('/user?ID=12345');
|
||||
let user: User = null;
|
||||
try {
|
||||
const { data } = await axios.get('/user?ID=12345');
|
||||
user = data.userDetails;
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
handleAxiosError(error);
|
||||
} else {
|
||||
handleUnexpectedError(error);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Online one-click setup
|
||||
|
||||
You can use Gitpod an online IDE(which is free for Open Source) for contributing or running the examples online.
|
||||
|
||||
[](https://gitpod.io/#https://github.com/axios/axios/blob/master/examples/server.js)
|
||||
|
||||
|
||||
## Resources
|
||||
|
||||
* [Changelog](https://github.com/axios/axios/blob/master/CHANGELOG.md)
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please report security issues to jasonsaayman@gmail.com
|
||||
+1
-1
@@ -135,7 +135,7 @@ This will polyfill the global environment, and only needs to be done once.
|
||||
|
||||
#### `axios.success`/`axios.error`
|
||||
|
||||
The `success`, and `error` aliases were deprectated in [0.4.0](https://github.com/axios/axios/blob/master/CHANGELOG.md#040-oct-03-2014). As of this release they have been removed entirely. Instead please use `axios.then`, and `axios.catch` respectively.
|
||||
The `success`, and `error` aliases were deprecated in [0.4.0](https://github.com/axios/axios/blob/master/CHANGELOG.md#040-oct-03-2014). As of this release they have been removed entirely. Instead please use `axios.then`, and `axios.catch` respectively.
|
||||
|
||||
```js
|
||||
axios.get('some/url')
|
||||
|
||||
+2044
-1566
File diff suppressed because it is too large
Load Diff
+1
-1
File diff suppressed because one or more lines are too long
+2
-2
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+21
-10
@@ -29,17 +29,24 @@ export type Method =
|
||||
| 'post' | 'POST'
|
||||
| 'put' | 'PUT'
|
||||
| 'patch' | 'PATCH'
|
||||
| 'purge' | 'PURGE'
|
||||
| 'link' | 'LINK'
|
||||
| 'unlink' | 'UNLINK'
|
||||
|
||||
export type ResponseType =
|
||||
| 'arraybuffer'
|
||||
| 'blob'
|
||||
| 'document'
|
||||
| 'json'
|
||||
| 'text'
|
||||
export type ResponseType =
|
||||
| 'arraybuffer'
|
||||
| 'blob'
|
||||
| 'document'
|
||||
| 'json'
|
||||
| 'text'
|
||||
| 'stream'
|
||||
|
||||
export interface TransitionalOptions{
|
||||
silentJSONParsing: boolean;
|
||||
forcedJSONParsing: boolean;
|
||||
clarifyTimeoutError: boolean;
|
||||
}
|
||||
|
||||
export interface AxiosRequestConfig {
|
||||
url?: string;
|
||||
method?: Method;
|
||||
@@ -61,13 +68,16 @@ export interface AxiosRequestConfig {
|
||||
onUploadProgress?: (progressEvent: any) => void;
|
||||
onDownloadProgress?: (progressEvent: any) => void;
|
||||
maxContentLength?: number;
|
||||
validateStatus?: (status: number) => boolean;
|
||||
validateStatus?: ((status: number) => boolean) | null;
|
||||
maxBodyLength?: number;
|
||||
maxRedirects?: number;
|
||||
socketPath?: string | null;
|
||||
httpAgent?: any;
|
||||
httpsAgent?: any;
|
||||
proxy?: AxiosProxyConfig | false;
|
||||
cancelToken?: CancelToken;
|
||||
decompress?: boolean;
|
||||
transitional?: TransitionalOptions
|
||||
}
|
||||
|
||||
export interface AxiosResponse<T = any> {
|
||||
@@ -120,7 +130,7 @@ export interface CancelTokenSource {
|
||||
}
|
||||
|
||||
export interface AxiosInterceptorManager<V> {
|
||||
use(onFulfilled?: (value: V) => V | Promise<V>, onRejected?: (error: any) => any): number;
|
||||
use<T = V>(onFulfilled?: (value: V) => T | Promise<T>, onRejected?: (error: any) => any): number;
|
||||
eject(id: number): void;
|
||||
}
|
||||
|
||||
@@ -150,8 +160,9 @@ export interface AxiosStatic extends AxiosInstance {
|
||||
isCancel(value: any): boolean;
|
||||
all<T>(values: (T | Promise<T>)[]): Promise<T[]>;
|
||||
spread<T, R>(callback: (...args: T[]) => R): (array: T[]) => R;
|
||||
isAxiosError(payload: any): payload is AxiosError;
|
||||
}
|
||||
|
||||
declare const Axios: AxiosStatic;
|
||||
declare const axios: AxiosStatic;
|
||||
|
||||
export default Axios;
|
||||
export default axios;
|
||||
|
||||
+84
-32
@@ -16,6 +16,31 @@ var enhanceError = require('../core/enhanceError');
|
||||
|
||||
var isHttps = /https:?/;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {http.ClientRequestArgs} options
|
||||
* @param {AxiosProxyConfig} proxy
|
||||
* @param {string} location
|
||||
*/
|
||||
function setProxy(options, proxy, location) {
|
||||
options.hostname = proxy.host;
|
||||
options.host = proxy.host;
|
||||
options.port = proxy.port;
|
||||
options.path = location;
|
||||
|
||||
// Basic proxy authorization
|
||||
if (proxy.auth) {
|
||||
var base64 = Buffer.from(proxy.auth.username + ':' + proxy.auth.password, 'utf8').toString('base64');
|
||||
options.headers['Proxy-Authorization'] = 'Basic ' + base64;
|
||||
}
|
||||
|
||||
// If a proxy is used, any redirects must also pass through the proxy
|
||||
options.beforeRedirect = function beforeRedirect(redirection) {
|
||||
redirection.headers.host = redirection.host;
|
||||
setProxy(redirection, proxy, redirection.href);
|
||||
};
|
||||
}
|
||||
|
||||
/*eslint consistent-return:0*/
|
||||
module.exports = function httpAdapter(config) {
|
||||
return new Promise(function dispatchHttpRequest(resolvePromise, rejectPromise) {
|
||||
@@ -29,9 +54,16 @@ module.exports = function httpAdapter(config) {
|
||||
var headers = config.headers;
|
||||
|
||||
// Set User-Agent (required by some servers)
|
||||
// Only set header if it hasn't been set in config
|
||||
// See https://github.com/axios/axios/issues/69
|
||||
if (!headers['User-Agent'] && !headers['user-agent']) {
|
||||
if ('User-Agent' in headers || 'user-agent' in headers) {
|
||||
// User-Agent is specified; handle case where no UA header is desired
|
||||
if (!headers['User-Agent'] && !headers['user-agent']) {
|
||||
delete headers['User-Agent'];
|
||||
delete headers['user-agent'];
|
||||
}
|
||||
// Otherwise, use specified value
|
||||
} else {
|
||||
// Only set header if it hasn't been set in config
|
||||
headers['User-Agent'] = 'axios/' + pkg.version;
|
||||
}
|
||||
|
||||
@@ -126,11 +158,11 @@ module.exports = function httpAdapter(config) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (shouldProxy) {
|
||||
proxy = {
|
||||
host: parsedProxyUrl.hostname,
|
||||
port: parsedProxyUrl.port
|
||||
port: parsedProxyUrl.port,
|
||||
protocol: parsedProxyUrl.protocol
|
||||
};
|
||||
|
||||
if (parsedProxyUrl.auth) {
|
||||
@@ -145,17 +177,8 @@ module.exports = function httpAdapter(config) {
|
||||
}
|
||||
|
||||
if (proxy) {
|
||||
options.hostname = proxy.host;
|
||||
options.host = proxy.host;
|
||||
options.headers.host = parsed.hostname + (parsed.port ? ':' + parsed.port : '');
|
||||
options.port = proxy.port;
|
||||
options.path = protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path;
|
||||
|
||||
// Basic proxy authorization
|
||||
if (proxy.auth) {
|
||||
var base64 = Buffer.from(proxy.auth.username + ':' + proxy.auth.password, 'utf8').toString('base64');
|
||||
options.headers['Proxy-Authorization'] = 'Basic ' + base64;
|
||||
}
|
||||
setProxy(options, proxy, protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path);
|
||||
}
|
||||
|
||||
var transport;
|
||||
@@ -171,8 +194,8 @@ module.exports = function httpAdapter(config) {
|
||||
transport = isHttpsProxy ? httpsFollow : httpFollow;
|
||||
}
|
||||
|
||||
if (config.maxContentLength && config.maxContentLength > -1) {
|
||||
options.maxBodyLength = config.maxContentLength;
|
||||
if (config.maxBodyLength > -1) {
|
||||
options.maxBodyLength = config.maxBodyLength;
|
||||
}
|
||||
|
||||
// Create the request
|
||||
@@ -181,22 +204,27 @@ module.exports = function httpAdapter(config) {
|
||||
|
||||
// uncompress the response body transparently if required
|
||||
var stream = res;
|
||||
switch (res.headers['content-encoding']) {
|
||||
/*eslint default-case:0*/
|
||||
case 'gzip':
|
||||
case 'compress':
|
||||
case 'deflate':
|
||||
// add the unzipper to the body stream processing pipeline
|
||||
stream = (res.statusCode === 204) ? stream : stream.pipe(zlib.createUnzip());
|
||||
|
||||
// remove the content-encoding in order to not confuse downstream operations
|
||||
delete res.headers['content-encoding'];
|
||||
break;
|
||||
}
|
||||
|
||||
// return the last request in case of redirects
|
||||
var lastRequest = res.req || req;
|
||||
|
||||
|
||||
// if no content, is HEAD request or decompress disabled we should not decompress
|
||||
if (res.statusCode !== 204 && lastRequest.method !== 'HEAD' && config.decompress !== false) {
|
||||
switch (res.headers['content-encoding']) {
|
||||
/*eslint default-case:0*/
|
||||
case 'gzip':
|
||||
case 'compress':
|
||||
case 'deflate':
|
||||
// add the unzipper to the body stream processing pipeline
|
||||
stream = stream.pipe(zlib.createUnzip());
|
||||
|
||||
// remove the content-encoding in order to not confuse downstream operations
|
||||
delete res.headers['content-encoding'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var response = {
|
||||
status: res.statusCode,
|
||||
statusText: res.statusMessage,
|
||||
@@ -210,11 +238,13 @@ module.exports = function httpAdapter(config) {
|
||||
settle(resolve, reject, response);
|
||||
} else {
|
||||
var responseBuffer = [];
|
||||
var totalResponseBytes = 0;
|
||||
stream.on('data', function handleStreamData(chunk) {
|
||||
responseBuffer.push(chunk);
|
||||
totalResponseBytes += chunk.length;
|
||||
|
||||
// make sure the content length is not over the maxContentLength if specified
|
||||
if (config.maxContentLength > -1 && Buffer.concat(responseBuffer).length > config.maxContentLength) {
|
||||
if (config.maxContentLength > -1 && totalResponseBytes > config.maxContentLength) {
|
||||
stream.destroy();
|
||||
reject(createError('maxContentLength size of ' + config.maxContentLength + ' exceeded',
|
||||
config, null, lastRequest));
|
||||
@@ -230,6 +260,9 @@ module.exports = function httpAdapter(config) {
|
||||
var responseData = Buffer.concat(responseBuffer);
|
||||
if (config.responseType !== 'arraybuffer') {
|
||||
responseData = responseData.toString(config.responseEncoding);
|
||||
if (!config.responseEncoding || config.responseEncoding === 'utf8') {
|
||||
responseData = utils.stripBOM(responseData);
|
||||
}
|
||||
}
|
||||
|
||||
response.data = responseData;
|
||||
@@ -240,20 +273,39 @@ module.exports = function httpAdapter(config) {
|
||||
|
||||
// Handle errors
|
||||
req.on('error', function handleRequestError(err) {
|
||||
if (req.aborted) return;
|
||||
if (req.aborted && err.code !== 'ERR_FR_TOO_MANY_REDIRECTS') return;
|
||||
reject(enhanceError(err, config, null, req));
|
||||
});
|
||||
|
||||
// Handle request timeout
|
||||
if (config.timeout) {
|
||||
// This is forcing a int timeout to avoid problems if the `req` interface doesn't handle other types.
|
||||
var timeout = parseInt(config.timeout, 10);
|
||||
|
||||
if (isNaN(timeout)) {
|
||||
reject(createError(
|
||||
'error trying to parse `config.timeout` to int',
|
||||
config,
|
||||
'ERR_PARSE_TIMEOUT',
|
||||
req
|
||||
));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Sometime, the response will be very slow, and does not respond, the connect event will be block by event loop system.
|
||||
// And timer callback will be fired, and abort() will be invoked before connection, then get "socket hang up" and code ECONNRESET.
|
||||
// At this time, if we have a large number of request, nodejs will hang up some socket on background. and the number will up and up.
|
||||
// And then these socket which be hang up will devoring CPU little by little.
|
||||
// ClientRequest.setTimeout will be fired on the specify milliseconds, and can make sure that abort() will be fired after connect.
|
||||
req.setTimeout(config.timeout, function handleRequestTimeout() {
|
||||
req.setTimeout(timeout, function handleRequestTimeout() {
|
||||
req.abort();
|
||||
reject(createError('timeout of ' + config.timeout + 'ms exceeded', config, 'ECONNABORTED', req));
|
||||
reject(createError(
|
||||
'timeout of ' + timeout + 'ms exceeded',
|
||||
config,
|
||||
config.transitional && config.transitional.clarifyTimeoutError ? 'ETIMEDOUT' : 'ECONNABORTED',
|
||||
req
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+38
-29
@@ -2,6 +2,7 @@
|
||||
|
||||
var utils = require('./../utils');
|
||||
var settle = require('./../core/settle');
|
||||
var cookies = require('./../helpers/cookies');
|
||||
var buildURL = require('./../helpers/buildURL');
|
||||
var buildFullPath = require('../core/buildFullPath');
|
||||
var parseHeaders = require('./../helpers/parseHeaders');
|
||||
@@ -12,6 +13,7 @@ module.exports = function xhrAdapter(config) {
|
||||
return new Promise(function dispatchXhrRequest(resolve, reject) {
|
||||
var requestData = config.data;
|
||||
var requestHeaders = config.headers;
|
||||
var responseType = config.responseType;
|
||||
|
||||
if (utils.isFormData(requestData)) {
|
||||
delete requestHeaders['Content-Type']; // Let the browser set it
|
||||
@@ -22,7 +24,7 @@ module.exports = function xhrAdapter(config) {
|
||||
// HTTP basic authentication
|
||||
if (config.auth) {
|
||||
var username = config.auth.username || '';
|
||||
var password = config.auth.password || '';
|
||||
var password = config.auth.password ? unescape(encodeURIComponent(config.auth.password)) : '';
|
||||
requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password);
|
||||
}
|
||||
|
||||
@@ -32,23 +34,14 @@ module.exports = function xhrAdapter(config) {
|
||||
// Set the request timeout in MS
|
||||
request.timeout = config.timeout;
|
||||
|
||||
// Listen for ready state
|
||||
request.onreadystatechange = function handleLoad() {
|
||||
if (!request || request.readyState !== 4) {
|
||||
function onloadend() {
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The request errored out and we didn't get a response, this will be
|
||||
// handled by onerror instead
|
||||
// With one exception: request that using file: protocol, most browsers
|
||||
// will return status as 0 even though it's a successful request
|
||||
if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare the response
|
||||
var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null;
|
||||
var responseData = !config.responseType || config.responseType === 'text' ? request.responseText : request.response;
|
||||
var responseData = !responseType || responseType === 'text' || responseType === 'json' ?
|
||||
request.responseText : request.response;
|
||||
var response = {
|
||||
data: responseData,
|
||||
status: request.status,
|
||||
@@ -62,7 +55,30 @@ module.exports = function xhrAdapter(config) {
|
||||
|
||||
// Clean up request
|
||||
request = null;
|
||||
};
|
||||
}
|
||||
|
||||
if ('onloadend' in request) {
|
||||
// Use onloadend if available
|
||||
request.onloadend = onloadend;
|
||||
} else {
|
||||
// Listen for ready state to emulate onloadend
|
||||
request.onreadystatechange = function handleLoad() {
|
||||
if (!request || request.readyState !== 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The request errored out and we didn't get a response, this will be
|
||||
// handled by onerror instead
|
||||
// With one exception: request that using file: protocol, most browsers
|
||||
// will return status as 0 even though it's a successful request
|
||||
if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {
|
||||
return;
|
||||
}
|
||||
// readystate handler is calling before onerror or ontimeout handlers,
|
||||
// so we should call onloadend on the next 'tick'
|
||||
setTimeout(onloadend);
|
||||
};
|
||||
}
|
||||
|
||||
// Handle browser request cancellation (as opposed to a manual cancellation)
|
||||
request.onabort = function handleAbort() {
|
||||
@@ -92,7 +108,10 @@ module.exports = function xhrAdapter(config) {
|
||||
if (config.timeoutErrorMessage) {
|
||||
timeoutErrorMessage = config.timeoutErrorMessage;
|
||||
}
|
||||
reject(createError(timeoutErrorMessage, config, 'ECONNABORTED',
|
||||
reject(createError(
|
||||
timeoutErrorMessage,
|
||||
config,
|
||||
config.transitional && config.transitional.clarifyTimeoutError ? 'ETIMEDOUT' : 'ECONNABORTED',
|
||||
request));
|
||||
|
||||
// Clean up request
|
||||
@@ -103,8 +122,6 @@ module.exports = function xhrAdapter(config) {
|
||||
// This is only done if running in a standard browser environment.
|
||||
// Specifically not if we're in a web worker, or react-native.
|
||||
if (utils.isStandardBrowserEnv()) {
|
||||
var cookies = require('./../helpers/cookies');
|
||||
|
||||
// Add xsrf header
|
||||
var xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) && config.xsrfCookieName ?
|
||||
cookies.read(config.xsrfCookieName) :
|
||||
@@ -134,16 +151,8 @@ module.exports = function xhrAdapter(config) {
|
||||
}
|
||||
|
||||
// Add responseType to request if needed
|
||||
if (config.responseType) {
|
||||
try {
|
||||
request.responseType = config.responseType;
|
||||
} catch (e) {
|
||||
// Expected DOMException thrown by browsers not compatible XMLHttpRequest Level 2.
|
||||
// But, this can be suppressed for 'json' type as it can be parsed by default 'transformResponse' function.
|
||||
if (config.responseType !== 'json') {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
if (responseType && responseType !== 'json') {
|
||||
request.responseType = config.responseType;
|
||||
}
|
||||
|
||||
// Handle progress if needed
|
||||
@@ -170,7 +179,7 @@ module.exports = function xhrAdapter(config) {
|
||||
});
|
||||
}
|
||||
|
||||
if (requestData === undefined) {
|
||||
if (!requestData) {
|
||||
requestData = null;
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -47,6 +47,9 @@ axios.all = function all(promises) {
|
||||
};
|
||||
axios.spread = require('./helpers/spread');
|
||||
|
||||
// Expose isAxiosError
|
||||
axios.isAxiosError = require('./helpers/isAxiosError');
|
||||
|
||||
module.exports = axios;
|
||||
|
||||
// Allow use of default import syntax in TypeScript
|
||||
|
||||
+64
-10
@@ -5,7 +5,9 @@ var buildURL = require('../helpers/buildURL');
|
||||
var InterceptorManager = require('./InterceptorManager');
|
||||
var dispatchRequest = require('./dispatchRequest');
|
||||
var mergeConfig = require('./mergeConfig');
|
||||
var validator = require('../helpers/validator');
|
||||
|
||||
var validators = validator.validators;
|
||||
/**
|
||||
* Create a new instance of Axios
|
||||
*
|
||||
@@ -45,20 +47,71 @@ Axios.prototype.request = function request(config) {
|
||||
config.method = 'get';
|
||||
}
|
||||
|
||||
// Hook up interceptors middleware
|
||||
var chain = [dispatchRequest, undefined];
|
||||
var promise = Promise.resolve(config);
|
||||
var transitional = config.transitional;
|
||||
|
||||
if (transitional !== undefined) {
|
||||
validator.assertOptions(transitional, {
|
||||
silentJSONParsing: validators.transitional(validators.boolean, '1.0.0'),
|
||||
forcedJSONParsing: validators.transitional(validators.boolean, '1.0.0'),
|
||||
clarifyTimeoutError: validators.transitional(validators.boolean, '1.0.0')
|
||||
}, false);
|
||||
}
|
||||
|
||||
// filter out skipped interceptors
|
||||
var requestInterceptorChain = [];
|
||||
var synchronousRequestInterceptors = true;
|
||||
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
|
||||
chain.unshift(interceptor.fulfilled, interceptor.rejected);
|
||||
if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;
|
||||
|
||||
requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
|
||||
});
|
||||
|
||||
var responseInterceptorChain = [];
|
||||
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
|
||||
chain.push(interceptor.fulfilled, interceptor.rejected);
|
||||
responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
|
||||
});
|
||||
|
||||
while (chain.length) {
|
||||
promise = promise.then(chain.shift(), chain.shift());
|
||||
var promise;
|
||||
|
||||
if (!synchronousRequestInterceptors) {
|
||||
var chain = [dispatchRequest, undefined];
|
||||
|
||||
Array.prototype.unshift.apply(chain, requestInterceptorChain);
|
||||
chain = chain.concat(responseInterceptorChain);
|
||||
|
||||
promise = Promise.resolve(config);
|
||||
while (chain.length) {
|
||||
promise = promise.then(chain.shift(), chain.shift());
|
||||
}
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
|
||||
var newConfig = config;
|
||||
while (requestInterceptorChain.length) {
|
||||
var onFulfilled = requestInterceptorChain.shift();
|
||||
var onRejected = requestInterceptorChain.shift();
|
||||
try {
|
||||
newConfig = onFulfilled(newConfig);
|
||||
} catch (error) {
|
||||
onRejected(error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
promise = dispatchRequest(newConfig);
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
while (responseInterceptorChain.length) {
|
||||
promise = promise.then(responseInterceptorChain.shift(), responseInterceptorChain.shift());
|
||||
}
|
||||
|
||||
return promise;
|
||||
@@ -73,9 +126,10 @@ Axios.prototype.getUri = function getUri(config) {
|
||||
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
|
||||
/*eslint func-names:0*/
|
||||
Axios.prototype[method] = function(url, config) {
|
||||
return this.request(utils.merge(config || {}, {
|
||||
return this.request(mergeConfig(config || {}, {
|
||||
method: method,
|
||||
url: url
|
||||
url: url,
|
||||
data: (config || {}).data
|
||||
}));
|
||||
};
|
||||
});
|
||||
@@ -83,7 +137,7 @@ utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData
|
||||
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
|
||||
/*eslint func-names:0*/
|
||||
Axios.prototype[method] = function(url, data, config) {
|
||||
return this.request(utils.merge(config || {}, {
|
||||
return this.request(mergeConfig(config || {}, {
|
||||
method: method,
|
||||
url: url,
|
||||
data: data
|
||||
|
||||
+4
-2
@@ -14,10 +14,12 @@ function InterceptorManager() {
|
||||
*
|
||||
* @return {Number} An ID used to remove interceptor later
|
||||
*/
|
||||
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
|
||||
InterceptorManager.prototype.use = function use(fulfilled, rejected, options) {
|
||||
this.handlers.push({
|
||||
fulfilled: fulfilled,
|
||||
rejected: rejected
|
||||
rejected: rejected,
|
||||
synchronous: options ? options.synchronous : false,
|
||||
runWhen: options ? options.runWhen : null
|
||||
});
|
||||
return this.handlers.length - 1;
|
||||
};
|
||||
|
||||
+1
@@ -3,5 +3,6 @@
|
||||
The modules found in `core/` should be modules that are specific to the domain logic of axios. These modules would most likely not make sense to be consumed outside of the axios module, as their logic is too specific. Some examples of core modules are:
|
||||
|
||||
- Dispatching requests
|
||||
- Requests sent via `adapters/` (see lib/adapters/README.md)
|
||||
- Managing interceptors
|
||||
- Handling config
|
||||
|
||||
+6
-3
@@ -27,7 +27,8 @@ module.exports = function dispatchRequest(config) {
|
||||
config.headers = config.headers || {};
|
||||
|
||||
// Transform request data
|
||||
config.data = transformData(
|
||||
config.data = transformData.call(
|
||||
config,
|
||||
config.data,
|
||||
config.headers,
|
||||
config.transformRequest
|
||||
@@ -53,7 +54,8 @@ module.exports = function dispatchRequest(config) {
|
||||
throwIfCancellationRequested(config);
|
||||
|
||||
// Transform response data
|
||||
response.data = transformData(
|
||||
response.data = transformData.call(
|
||||
config,
|
||||
response.data,
|
||||
response.headers,
|
||||
config.transformResponse
|
||||
@@ -66,7 +68,8 @@ module.exports = function dispatchRequest(config) {
|
||||
|
||||
// Transform response data
|
||||
if (reason && reason.response) {
|
||||
reason.response.data = transformData(
|
||||
reason.response.data = transformData.call(
|
||||
config,
|
||||
reason.response.data,
|
||||
reason.response.headers,
|
||||
config.transformResponse
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ module.exports = function enhanceError(error, config, code, request, response) {
|
||||
error.response = response;
|
||||
error.isAxiosError = true;
|
||||
|
||||
error.toJSON = function() {
|
||||
error.toJSON = function toJSON() {
|
||||
return {
|
||||
// Standard
|
||||
message: this.message,
|
||||
|
||||
+47
-33
@@ -15,59 +15,73 @@ module.exports = function mergeConfig(config1, config2) {
|
||||
config2 = config2 || {};
|
||||
var config = {};
|
||||
|
||||
var valueFromConfig2Keys = ['url', 'method', 'params', 'data'];
|
||||
var mergeDeepPropertiesKeys = ['headers', 'auth', 'proxy'];
|
||||
var valueFromConfig2Keys = ['url', 'method', 'data'];
|
||||
var mergeDeepPropertiesKeys = ['headers', 'auth', 'proxy', 'params'];
|
||||
var defaultToConfig2Keys = [
|
||||
'baseURL', 'url', 'transformRequest', 'transformResponse', 'paramsSerializer',
|
||||
'timeout', 'withCredentials', 'adapter', 'responseType', 'xsrfCookieName',
|
||||
'xsrfHeaderName', 'onUploadProgress', 'onDownloadProgress',
|
||||
'maxContentLength', 'validateStatus', 'maxRedirects', 'httpAgent',
|
||||
'httpsAgent', 'cancelToken', 'socketPath'
|
||||
'baseURL', 'transformRequest', 'transformResponse', 'paramsSerializer',
|
||||
'timeout', 'timeoutMessage', 'withCredentials', 'adapter', 'responseType', 'xsrfCookieName',
|
||||
'xsrfHeaderName', 'onUploadProgress', 'onDownloadProgress', 'decompress',
|
||||
'maxContentLength', 'maxBodyLength', 'maxRedirects', 'transport', 'httpAgent',
|
||||
'httpsAgent', 'cancelToken', 'socketPath', 'responseEncoding'
|
||||
];
|
||||
var directMergeKeys = ['validateStatus'];
|
||||
|
||||
function getMergedValue(target, source) {
|
||||
if (utils.isPlainObject(target) && utils.isPlainObject(source)) {
|
||||
return utils.merge(target, source);
|
||||
} else if (utils.isPlainObject(source)) {
|
||||
return utils.merge({}, source);
|
||||
} else if (utils.isArray(source)) {
|
||||
return source.slice();
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
function mergeDeepProperties(prop) {
|
||||
if (!utils.isUndefined(config2[prop])) {
|
||||
config[prop] = getMergedValue(config1[prop], config2[prop]);
|
||||
} else if (!utils.isUndefined(config1[prop])) {
|
||||
config[prop] = getMergedValue(undefined, config1[prop]);
|
||||
}
|
||||
}
|
||||
|
||||
utils.forEach(valueFromConfig2Keys, function valueFromConfig2(prop) {
|
||||
if (typeof config2[prop] !== 'undefined') {
|
||||
config[prop] = config2[prop];
|
||||
if (!utils.isUndefined(config2[prop])) {
|
||||
config[prop] = getMergedValue(undefined, config2[prop]);
|
||||
}
|
||||
});
|
||||
|
||||
utils.forEach(mergeDeepPropertiesKeys, function mergeDeepProperties(prop) {
|
||||
if (utils.isObject(config2[prop])) {
|
||||
config[prop] = utils.deepMerge(config1[prop], config2[prop]);
|
||||
} else if (typeof config2[prop] !== 'undefined') {
|
||||
config[prop] = config2[prop];
|
||||
} else if (utils.isObject(config1[prop])) {
|
||||
config[prop] = utils.deepMerge(config1[prop]);
|
||||
} else if (typeof config1[prop] !== 'undefined') {
|
||||
config[prop] = config1[prop];
|
||||
}
|
||||
});
|
||||
utils.forEach(mergeDeepPropertiesKeys, mergeDeepProperties);
|
||||
|
||||
utils.forEach(defaultToConfig2Keys, function defaultToConfig2(prop) {
|
||||
if (typeof config2[prop] !== 'undefined') {
|
||||
config[prop] = config2[prop];
|
||||
} else if (typeof config1[prop] !== 'undefined') {
|
||||
config[prop] = config1[prop];
|
||||
if (!utils.isUndefined(config2[prop])) {
|
||||
config[prop] = getMergedValue(undefined, config2[prop]);
|
||||
} else if (!utils.isUndefined(config1[prop])) {
|
||||
config[prop] = getMergedValue(undefined, config1[prop]);
|
||||
}
|
||||
});
|
||||
|
||||
utils.forEach(directMergeKeys, function merge(prop) {
|
||||
if (prop in config2) {
|
||||
config[prop] = getMergedValue(config1[prop], config2[prop]);
|
||||
} else if (prop in config1) {
|
||||
config[prop] = getMergedValue(undefined, config1[prop]);
|
||||
}
|
||||
});
|
||||
|
||||
var axiosKeys = valueFromConfig2Keys
|
||||
.concat(mergeDeepPropertiesKeys)
|
||||
.concat(defaultToConfig2Keys);
|
||||
.concat(defaultToConfig2Keys)
|
||||
.concat(directMergeKeys);
|
||||
|
||||
var otherKeys = Object
|
||||
.keys(config2)
|
||||
.keys(config1)
|
||||
.concat(Object.keys(config2))
|
||||
.filter(function filterAxiosKeys(key) {
|
||||
return axiosKeys.indexOf(key) === -1;
|
||||
});
|
||||
|
||||
utils.forEach(otherKeys, function otherKeysDefaultToConfig2(prop) {
|
||||
if (typeof config2[prop] !== 'undefined') {
|
||||
config[prop] = config2[prop];
|
||||
} else if (typeof config1[prop] !== 'undefined') {
|
||||
config[prop] = config1[prop];
|
||||
}
|
||||
});
|
||||
utils.forEach(otherKeys, mergeDeepProperties);
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ var createError = require('./createError');
|
||||
*/
|
||||
module.exports = function settle(resolve, reject, response) {
|
||||
var validateStatus = response.config.validateStatus;
|
||||
if (!validateStatus || validateStatus(response.status)) {
|
||||
if (!response.status || !validateStatus || validateStatus(response.status)) {
|
||||
resolve(response);
|
||||
} else {
|
||||
reject(createError(
|
||||
|
||||
+3
-1
@@ -1,6 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var utils = require('./../utils');
|
||||
var defaults = require('./../defaults');
|
||||
|
||||
/**
|
||||
* Transform the data for a request or a response
|
||||
@@ -11,9 +12,10 @@ var utils = require('./../utils');
|
||||
* @returns {*} The resulting transformed data
|
||||
*/
|
||||
module.exports = function transformData(data, headers, fns) {
|
||||
var context = this || defaults;
|
||||
/*eslint no-param-reassign:0*/
|
||||
utils.forEach(fns, function transform(fn) {
|
||||
data = fn(data, headers);
|
||||
data = fn.call(context, data, headers);
|
||||
});
|
||||
|
||||
return data;
|
||||
|
||||
+44
-7
@@ -2,6 +2,7 @@
|
||||
|
||||
var utils = require('./utils');
|
||||
var normalizeHeaderName = require('./helpers/normalizeHeaderName');
|
||||
var enhanceError = require('./core/enhanceError');
|
||||
|
||||
var DEFAULT_CONTENT_TYPE = {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
@@ -25,12 +26,35 @@ function getDefaultAdapter() {
|
||||
return adapter;
|
||||
}
|
||||
|
||||
function stringifySafely(rawValue, parser, encoder) {
|
||||
if (utils.isString(rawValue)) {
|
||||
try {
|
||||
(parser || JSON.parse)(rawValue);
|
||||
return utils.trim(rawValue);
|
||||
} catch (e) {
|
||||
if (e.name !== 'SyntaxError') {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (encoder || JSON.stringify)(rawValue);
|
||||
}
|
||||
|
||||
var defaults = {
|
||||
|
||||
transitional: {
|
||||
silentJSONParsing: true,
|
||||
forcedJSONParsing: true,
|
||||
clarifyTimeoutError: false
|
||||
},
|
||||
|
||||
adapter: getDefaultAdapter(),
|
||||
|
||||
transformRequest: [function transformRequest(data, headers) {
|
||||
normalizeHeaderName(headers, 'Accept');
|
||||
normalizeHeaderName(headers, 'Content-Type');
|
||||
|
||||
if (utils.isFormData(data) ||
|
||||
utils.isArrayBuffer(data) ||
|
||||
utils.isBuffer(data) ||
|
||||
@@ -47,20 +71,32 @@ var defaults = {
|
||||
setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8');
|
||||
return data.toString();
|
||||
}
|
||||
if (utils.isObject(data)) {
|
||||
setContentTypeIfUnset(headers, 'application/json;charset=utf-8');
|
||||
return JSON.stringify(data);
|
||||
if (utils.isObject(data) || (headers && headers['Content-Type'] === 'application/json')) {
|
||||
setContentTypeIfUnset(headers, 'application/json');
|
||||
return stringifySafely(data);
|
||||
}
|
||||
return data;
|
||||
}],
|
||||
|
||||
transformResponse: [function transformResponse(data) {
|
||||
/*eslint no-param-reassign:0*/
|
||||
if (typeof data === 'string') {
|
||||
var transitional = this.transitional;
|
||||
var silentJSONParsing = transitional && transitional.silentJSONParsing;
|
||||
var forcedJSONParsing = transitional && transitional.forcedJSONParsing;
|
||||
var strictJSONParsing = !silentJSONParsing && this.responseType === 'json';
|
||||
|
||||
if (strictJSONParsing || (forcedJSONParsing && utils.isString(data) && data.length)) {
|
||||
try {
|
||||
data = JSON.parse(data);
|
||||
} catch (e) { /* Ignore */ }
|
||||
return JSON.parse(data);
|
||||
} catch (e) {
|
||||
if (strictJSONParsing) {
|
||||
if (e.name === 'SyntaxError') {
|
||||
throw enhanceError(e, this, 'E_JSON_PARSE');
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}],
|
||||
|
||||
@@ -74,6 +110,7 @@ var defaults = {
|
||||
xsrfHeaderName: 'X-XSRF-TOKEN',
|
||||
|
||||
maxContentLength: -1,
|
||||
maxBodyLength: -1,
|
||||
|
||||
validateStatus: function validateStatus(status) {
|
||||
return status >= 200 && status < 300;
|
||||
|
||||
-1
@@ -4,7 +4,6 @@ var utils = require('./../utils');
|
||||
|
||||
function encode(val) {
|
||||
return encodeURIComponent(val).
|
||||
replace(/%40/gi, '@').
|
||||
replace(/%3A/gi, ':').
|
||||
replace(/%24/g, '$').
|
||||
replace(/%2C/gi, ',').
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Determines whether the payload is an error thrown by Axios
|
||||
*
|
||||
* @param {*} payload The value to test
|
||||
* @returns {boolean} True if the payload is an error thrown by Axios, otherwise false
|
||||
*/
|
||||
module.exports = function isAxiosError(payload) {
|
||||
return (typeof payload === 'object') && (payload.isAxiosError === true);
|
||||
};
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
'use strict';
|
||||
|
||||
var pkg = require('./../../package.json');
|
||||
|
||||
var validators = {};
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
['object', 'boolean', 'number', 'function', 'string', 'symbol'].forEach(function(type, i) {
|
||||
validators[type] = function validator(thing) {
|
||||
return typeof thing === type || 'a' + (i < 1 ? 'n ' : ' ') + type;
|
||||
};
|
||||
});
|
||||
|
||||
var deprecatedWarnings = {};
|
||||
var currentVerArr = pkg.version.split('.');
|
||||
|
||||
/**
|
||||
* Compare package versions
|
||||
* @param {string} version
|
||||
* @param {string?} thanVersion
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isOlderVersion(version, thanVersion) {
|
||||
var pkgVersionArr = thanVersion ? thanVersion.split('.') : currentVerArr;
|
||||
var destVer = version.split('.');
|
||||
for (var i = 0; i < 3; i++) {
|
||||
if (pkgVersionArr[i] > destVer[i]) {
|
||||
return true;
|
||||
} else if (pkgVersionArr[i] < destVer[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transitional option validator
|
||||
* @param {function|boolean?} validator
|
||||
* @param {string?} version
|
||||
* @param {string} message
|
||||
* @returns {function}
|
||||
*/
|
||||
validators.transitional = function transitional(validator, version, message) {
|
||||
var isDeprecated = version && isOlderVersion(version);
|
||||
|
||||
function formatMessage(opt, desc) {
|
||||
return '[Axios v' + pkg.version + '] Transitional option \'' + opt + '\'' + desc + (message ? '. ' + message : '');
|
||||
}
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
return function(value, opt, opts) {
|
||||
if (validator === false) {
|
||||
throw new Error(formatMessage(opt, ' has been removed in ' + version));
|
||||
}
|
||||
|
||||
if (isDeprecated && !deprecatedWarnings[opt]) {
|
||||
deprecatedWarnings[opt] = true;
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
formatMessage(
|
||||
opt,
|
||||
' has been deprecated since v' + version + ' and will be removed in the near future'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return validator ? validator(value, opt, opts) : true;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Assert object's properties type
|
||||
* @param {object} options
|
||||
* @param {object} schema
|
||||
* @param {boolean?} allowUnknown
|
||||
*/
|
||||
|
||||
function assertOptions(options, schema, allowUnknown) {
|
||||
if (typeof options !== 'object') {
|
||||
throw new TypeError('options must be an object');
|
||||
}
|
||||
var keys = Object.keys(options);
|
||||
var i = keys.length;
|
||||
while (i-- > 0) {
|
||||
var opt = keys[i];
|
||||
var validator = schema[opt];
|
||||
if (validator) {
|
||||
var value = options[opt];
|
||||
var result = value === undefined || validator(value, opt, options);
|
||||
if (result !== true) {
|
||||
throw new TypeError('option ' + opt + ' must be ' + result);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (allowUnknown !== true) {
|
||||
throw Error('Unknown option ' + opt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isOlderVersion: isOlderVersion,
|
||||
assertOptions: assertOptions,
|
||||
validators: validators
|
||||
};
|
||||
+37
-32
@@ -2,8 +2,6 @@
|
||||
|
||||
var bind = require('./helpers/bind');
|
||||
|
||||
/*global toString:true*/
|
||||
|
||||
// utils is a library of generic helper functions non-specific to axios
|
||||
|
||||
var toString = Object.prototype.toString;
|
||||
@@ -105,6 +103,21 @@ function isObject(val) {
|
||||
return val !== null && typeof val === 'object';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a value is a plain Object
|
||||
*
|
||||
* @param {Object} val The value to test
|
||||
* @return {boolean} True if value is a plain Object, otherwise false
|
||||
*/
|
||||
function isPlainObject(val) {
|
||||
if (toString.call(val) !== '[object Object]') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var prototype = Object.getPrototypeOf(val);
|
||||
return prototype === null || prototype === Object.prototype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a value is a Date
|
||||
*
|
||||
@@ -172,7 +185,7 @@ function isURLSearchParams(val) {
|
||||
* @returns {String} The String freed of excess whitespace
|
||||
*/
|
||||
function trim(str) {
|
||||
return str.replace(/^\s*/, '').replace(/\s*$/, '');
|
||||
return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -261,34 +274,12 @@ function forEach(obj, fn) {
|
||||
function merge(/* obj1, obj2, obj3, ... */) {
|
||||
var result = {};
|
||||
function assignValue(val, key) {
|
||||
if (typeof result[key] === 'object' && typeof val === 'object') {
|
||||
if (isPlainObject(result[key]) && isPlainObject(val)) {
|
||||
result[key] = merge(result[key], val);
|
||||
} else {
|
||||
result[key] = val;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0, l = arguments.length; i < l; i++) {
|
||||
forEach(arguments[i], assignValue);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function equal to merge with the difference being that no reference
|
||||
* to original objects is kept.
|
||||
*
|
||||
* @see merge
|
||||
* @param {Object} obj1 Object to merge
|
||||
* @returns {Object} Result of all merge properties
|
||||
*/
|
||||
function deepMerge(/* obj1, obj2, obj3, ... */) {
|
||||
var result = {};
|
||||
function assignValue(val, key) {
|
||||
if (typeof result[key] === 'object' && typeof val === 'object') {
|
||||
result[key] = deepMerge(result[key], val);
|
||||
} else if (typeof val === 'object') {
|
||||
result[key] = deepMerge({}, val);
|
||||
} else if (isPlainObject(val)) {
|
||||
result[key] = merge({}, val);
|
||||
} else if (isArray(val)) {
|
||||
result[key] = val.slice();
|
||||
} else {
|
||||
result[key] = val;
|
||||
}
|
||||
@@ -319,6 +310,19 @@ function extend(a, b, thisArg) {
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
|
||||
*
|
||||
* @param {string} content with BOM
|
||||
* @return {string} content value without BOM
|
||||
*/
|
||||
function stripBOM(content) {
|
||||
if (content.charCodeAt(0) === 0xFEFF) {
|
||||
content = content.slice(1);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isArray: isArray,
|
||||
isArrayBuffer: isArrayBuffer,
|
||||
@@ -328,6 +332,7 @@ module.exports = {
|
||||
isString: isString,
|
||||
isNumber: isNumber,
|
||||
isObject: isObject,
|
||||
isPlainObject: isPlainObject,
|
||||
isUndefined: isUndefined,
|
||||
isDate: isDate,
|
||||
isFile: isFile,
|
||||
@@ -338,7 +343,7 @@ module.exports = {
|
||||
isStandardBrowserEnv: isStandardBrowserEnv,
|
||||
forEach: forEach,
|
||||
merge: merge,
|
||||
deepMerge: deepMerge,
|
||||
extend: extend,
|
||||
trim: trim
|
||||
trim: trim,
|
||||
stripBOM: stripBOM
|
||||
};
|
||||
|
||||
+33
-35
@@ -1,35 +1,33 @@
|
||||
{
|
||||
"_args": [
|
||||
[
|
||||
"axios@0.19.2",
|
||||
"/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series"
|
||||
"axios@0.21.4",
|
||||
"/home/node/nuxt"
|
||||
]
|
||||
],
|
||||
"_from": "axios@0.19.2",
|
||||
"_id": "axios@0.19.2",
|
||||
"_from": "axios@0.21.4",
|
||||
"_id": "axios@0.21.4",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
|
||||
"_integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
|
||||
"_location": "/axios",
|
||||
"_phantomChildren": {
|
||||
"debug": "3.1.0"
|
||||
},
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "axios@0.19.2",
|
||||
"raw": "axios@0.21.4",
|
||||
"name": "axios",
|
||||
"escapedName": "axios",
|
||||
"rawSpec": "0.19.2",
|
||||
"rawSpec": "0.21.4",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "0.19.2"
|
||||
"fetchSpec": "0.21.4"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/@line/bot-sdk",
|
||||
"/@nuxtjs/axios"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
|
||||
"_spec": "0.19.2",
|
||||
"_where": "/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series",
|
||||
"_resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
|
||||
"_spec": "0.21.4",
|
||||
"_where": "/home/node/nuxt",
|
||||
"author": {
|
||||
"name": "Matt Zabriskie"
|
||||
},
|
||||
@@ -46,47 +44,46 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"follow-redirects": "1.5.10"
|
||||
"follow-redirects": "^1.14.0"
|
||||
},
|
||||
"description": "Promise based HTTP client for the browser and node.js",
|
||||
"devDependencies": {
|
||||
"bundlesize": "^0.17.0",
|
||||
"coveralls": "^3.0.0",
|
||||
"es6-promise": "^4.2.4",
|
||||
"grunt": "^1.0.2",
|
||||
"grunt": "^1.3.0",
|
||||
"grunt-banner": "^0.6.0",
|
||||
"grunt-cli": "^1.2.0",
|
||||
"grunt-contrib-clean": "^1.1.0",
|
||||
"grunt-contrib-watch": "^1.0.0",
|
||||
"grunt-eslint": "^20.1.0",
|
||||
"grunt-karma": "^2.0.0",
|
||||
"grunt-eslint": "^23.0.0",
|
||||
"grunt-karma": "^4.0.0",
|
||||
"grunt-mocha-test": "^0.13.3",
|
||||
"grunt-ts": "^6.0.0-beta.19",
|
||||
"grunt-webpack": "^1.0.18",
|
||||
"grunt-webpack": "^4.0.2",
|
||||
"istanbul-instrumenter-loader": "^1.0.0",
|
||||
"jasmine-core": "^2.4.1",
|
||||
"karma": "^1.3.0",
|
||||
"karma-chrome-launcher": "^2.2.0",
|
||||
"karma-coverage": "^1.1.1",
|
||||
"karma-firefox-launcher": "^1.1.0",
|
||||
"karma": "^6.3.2",
|
||||
"karma-chrome-launcher": "^3.1.0",
|
||||
"karma-firefox-launcher": "^2.1.0",
|
||||
"karma-jasmine": "^1.1.1",
|
||||
"karma-jasmine-ajax": "^0.1.13",
|
||||
"karma-opera-launcher": "^1.0.0",
|
||||
"karma-safari-launcher": "^1.0.0",
|
||||
"karma-sauce-launcher": "^1.2.0",
|
||||
"karma-sauce-launcher": "^4.3.6",
|
||||
"karma-sinon": "^1.0.5",
|
||||
"karma-sourcemap-loader": "^0.3.7",
|
||||
"karma-webpack": "^1.7.0",
|
||||
"karma-sourcemap-loader": "^0.3.8",
|
||||
"karma-webpack": "^4.0.2",
|
||||
"load-grunt-tasks": "^3.5.2",
|
||||
"minimist": "^1.2.0",
|
||||
"mocha": "^5.2.0",
|
||||
"mocha": "^8.2.1",
|
||||
"sinon": "^4.5.0",
|
||||
"typescript": "^2.8.1",
|
||||
"terser-webpack-plugin": "^4.2.3",
|
||||
"typescript": "^4.0.5",
|
||||
"url-search-params": "^0.10.0",
|
||||
"webpack": "^1.13.1",
|
||||
"webpack-dev-server": "^1.14.1"
|
||||
"webpack": "^4.44.2",
|
||||
"webpack-dev-server": "^3.11.0"
|
||||
},
|
||||
"homepage": "https://github.com/axios/axios",
|
||||
"homepage": "https://axios-http.com",
|
||||
"jsdelivr": "dist/axios.min.js",
|
||||
"keywords": [
|
||||
"xhr",
|
||||
"http",
|
||||
@@ -109,9 +106,10 @@
|
||||
"postversion": "git push && git push --tags",
|
||||
"preversion": "npm test",
|
||||
"start": "node ./sandbox/server.js",
|
||||
"test": "grunt test && bundlesize",
|
||||
"test": "grunt test",
|
||||
"version": "npm run build && grunt version && git add -A dist && git add CHANGELOG.md bower.json package.json"
|
||||
},
|
||||
"typings": "./index.d.ts",
|
||||
"version": "0.19.2"
|
||||
"unpkg": "dist/axios.min.js",
|
||||
"version": "0.21.4"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user