mirror of
https://github.com/axios/axios.git
synced 2026-04-11 14:21:59 +08:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c7a76ddbf2 | ||
|
|
914bc2605a | ||
|
|
0912bde937 | ||
|
|
8b68491d04 | ||
|
|
62f6281660 | ||
|
|
c44f4d728b | ||
|
|
34d137cbae | ||
|
|
9f992a8eb9 | ||
|
|
9df2cd3df7 | ||
|
|
f53ebf2198 |
@ -1,5 +1,5 @@
|
||||
<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"> </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>
|
||||
|
||||
41
index.d.cts
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
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,
|
||||
|
||||
@ -875,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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
|
||||
27
test/unit/helpers/progressEventReducer.js
Normal file
27
test/unit/helpers/progressEventReducer.js
Normal file
@ -0,0 +1,27 @@
|
||||
import assert from 'assert';
|
||||
import { progressEventReducer } from '../../../lib/helpers/progressEventReducer.js';
|
||||
|
||||
describe('helpers::progressEventReducer', () => {
|
||||
it('should clamp loaded/progress and avoid negative bytes for out-of-order events', () => {
|
||||
const events = [];
|
||||
const [onProgress, flush] = progressEventReducer((data) => {
|
||||
events.push(data);
|
||||
}, false, Number.POSITIVE_INFINITY);
|
||||
|
||||
onProgress({ lengthComputable: true, loaded: 80, total: 100 });
|
||||
onProgress({ lengthComputable: true, loaded: 60, total: 100 });
|
||||
onProgress({ lengthComputable: true, loaded: 180, total: 100 });
|
||||
flush();
|
||||
|
||||
assert.strictEqual(events.length, 3);
|
||||
assert.strictEqual(events[0].bytes, 80);
|
||||
assert.strictEqual(events[1].bytes, 0);
|
||||
|
||||
const last = events[events.length - 1];
|
||||
assert.strictEqual(last.loaded, 100);
|
||||
assert.strictEqual(last.total, 100);
|
||||
assert.strictEqual(last.progress, 1);
|
||||
assert.strictEqual(last.upload, true);
|
||||
assert.strictEqual(last.bytes, 20);
|
||||
});
|
||||
});
|
||||
@ -550,6 +550,54 @@ describe.runIf(typeof fetch === 'function')('supports fetch with nodejs', () =>
|
||||
await stopHTTPServer(server);
|
||||
}
|
||||
});
|
||||
|
||||
it('should remove manually set Content-Type without boundary for FormData', async () => {
|
||||
const form = new FormData();
|
||||
form.append('foo', 'bar');
|
||||
|
||||
const server = await startHTTPServer(
|
||||
(req, res) => {
|
||||
const contentType = req.headers['content-type'];
|
||||
assert.match(contentType, /^multipart\/form-data; boundary=/i);
|
||||
res.end('OK');
|
||||
},
|
||||
{ port: SERVER_PORT }
|
||||
);
|
||||
|
||||
try {
|
||||
await fetchAxios.post(`http://localhost:${server.address().port}/form`, form, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
});
|
||||
} finally {
|
||||
await stopHTTPServer(server);
|
||||
}
|
||||
});
|
||||
|
||||
it('should preserve Content-Type if it already has boundary', async () => {
|
||||
const form = new FormData();
|
||||
form.append('foo', 'bar');
|
||||
|
||||
const customBoundary = '----CustomBoundary123';
|
||||
|
||||
const server = await startHTTPServer(
|
||||
(req, res) => {
|
||||
const contentType = req.headers['content-type'];
|
||||
assert.ok(contentType.includes(customBoundary));
|
||||
res.end('OK');
|
||||
},
|
||||
{ port: SERVER_PORT }
|
||||
);
|
||||
|
||||
try {
|
||||
await fetchAxios.post(`http://localhost:${server.address().port}/form`, form, {
|
||||
headers: {
|
||||
'Content-Type': `multipart/form-data; boundary=${customBoundary}`,
|
||||
},
|
||||
});
|
||||
} finally {
|
||||
await stopHTTPServer(server);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('env config', () => {
|
||||
|
||||
@ -29,6 +29,7 @@ import getStream from 'get-stream';
|
||||
import bodyParser from 'body-parser';
|
||||
import { AbortController } from 'abortcontroller-polyfill/dist/cjs-ponyfill.js';
|
||||
import { lookup } from 'dns';
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
const OPEN_WEB_PORT = 80;
|
||||
const SERVER_PORT = 8020;
|
||||
@ -3817,6 +3818,60 @@ describe('supports http with nodejs', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('should reject when only the request socket emits an error', async () => {
|
||||
const noop = () => {};
|
||||
const socket = new EventEmitter();
|
||||
socket.setKeepAlive = noop;
|
||||
socket.on('error', noop);
|
||||
|
||||
const transport = {
|
||||
request() {
|
||||
return new (class MockRequest extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
this.destroyed = false;
|
||||
}
|
||||
|
||||
setTimeout() {}
|
||||
|
||||
write() {}
|
||||
|
||||
end() {
|
||||
this.emit('socket', socket);
|
||||
|
||||
setImmediate(() => {
|
||||
socket.emit('error', Object.assign(new Error('write EPIPE'), { code: 'EPIPE' }));
|
||||
});
|
||||
}
|
||||
|
||||
destroy(err) {
|
||||
if (this.destroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.destroyed = true;
|
||||
err && this.emit('error', err);
|
||||
this.emit('close');
|
||||
}
|
||||
})();
|
||||
},
|
||||
};
|
||||
|
||||
const error = await Promise.race([
|
||||
axios.post('http://example.com/', 'test', {
|
||||
transport,
|
||||
maxRedirects: 0,
|
||||
}),
|
||||
setTimeoutAsync(200).then(() => {
|
||||
throw new Error('socket error did not reject the request');
|
||||
}),
|
||||
]).catch((err) => err);
|
||||
|
||||
assert.ok(error instanceof AxiosError);
|
||||
assert.strictEqual(error.code, 'EPIPE');
|
||||
assert.strictEqual(error.message, 'write EPIPE');
|
||||
});
|
||||
|
||||
describe('keep-alive', () => {
|
||||
it('should not fail with "socket hang up" when using timeouts', async () => {
|
||||
const server = await startHTTPServer(
|
||||
@ -3838,5 +3893,66 @@ describe('supports http with nodejs', () => {
|
||||
await stopHTTPServer(server);
|
||||
}
|
||||
}, 15000);
|
||||
|
||||
it('should remove request socket error listeners after keep-alive requests close', async () => {
|
||||
const noop = () => {};
|
||||
const socket = new EventEmitter();
|
||||
socket.setKeepAlive = noop;
|
||||
socket.on('error', noop);
|
||||
|
||||
const baseErrorListenerCount = socket.listenerCount('error');
|
||||
|
||||
const transport = {
|
||||
request(_, cb) {
|
||||
return new (class MockRequest extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
this.destroyed = false;
|
||||
}
|
||||
|
||||
setTimeout() {}
|
||||
|
||||
write() {}
|
||||
|
||||
end() {
|
||||
this.emit('socket', socket);
|
||||
|
||||
setImmediate(() => {
|
||||
const response = stream.Readable.from(['ok']);
|
||||
response.statusCode = 200;
|
||||
response.headers = {};
|
||||
|
||||
cb(response);
|
||||
this.emit('close');
|
||||
});
|
||||
}
|
||||
|
||||
destroy(err) {
|
||||
if (this.destroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.destroyed = true;
|
||||
err && this.emit('error', err);
|
||||
this.emit('close');
|
||||
}
|
||||
})();
|
||||
},
|
||||
};
|
||||
|
||||
await axios.get('http://example.com/first', {
|
||||
transport,
|
||||
maxRedirects: 0,
|
||||
});
|
||||
await setTimeoutAsync(0);
|
||||
assert.strictEqual(socket.listenerCount('error'), baseErrorListenerCount);
|
||||
|
||||
await axios.get('http://example.com/second', {
|
||||
transport,
|
||||
maxRedirects: 0,
|
||||
});
|
||||
await setTimeoutAsync(0);
|
||||
assert.strictEqual(socket.listenerCount('error'), baseErrorListenerCount);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -27,6 +27,32 @@ describe('formDataToJSON', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should keep repeatable values flat for 3+ entries', () => {
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append('select3', '301');
|
||||
formData.append('select3', '302');
|
||||
formData.append('select3', '303');
|
||||
|
||||
expect(formDataToJSON(formData)).toEqual({
|
||||
select3: ['301', '302', '303'],
|
||||
});
|
||||
});
|
||||
|
||||
it('should keep nested repeatable values flat for 3+ entries', () => {
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append('foo[bar]', '1');
|
||||
formData.append('foo[bar]', '2');
|
||||
formData.append('foo[bar]', '3');
|
||||
|
||||
expect(formDataToJSON(formData)).toEqual({
|
||||
foo: {
|
||||
bar: ['1', '2', '3'],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert props with empty brackets to arrays', () => {
|
||||
const formData = new FormData();
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user