1616 * @typedef Options
1717 * @property {string } [url] the URL to request
1818 * @property {'get'|'post'|'put'|'patch'|'delete'|'options'|'head'|'GET'|'POST'|'PUT'|'PATCH'|'DELETE'|'OPTIONS'|'HEAD' } [method="get"] HTTP method, case-insensitive
19- * @property {RequestHeaders } [headers] Request headers
19+ * @property {Headers } [headers] Request headers
2020 * @property {FormData|string|object } [body] a body, optionally encoded, to send
2121 * @property {'text'|'json'|'stream'|'blob'|'arrayBuffer'|'formData'|'stream' } [responseType="json"] An encoding to use for the response
2222 * @property {Record<string,any>|URLSearchParams } [params] querystring parameters
2626 * @property {string } [xsrfCookieName] Pass an Cross-site Request Forgery prevention cookie value as a header defined by `xsrfHeaderName`
2727 * @property {string } [xsrfHeaderName] The name of a header to use for passing XSRF cookies
2828 * @property {(status: number) => boolean } [validateStatus] Override status code handling (default: 200-399 is a success)
29- * @property {Array<(body: any, headers?: RequestHeaders ) => any?> } [transformRequest] An array of transformations to apply to the outgoing request
29+ * @property {Array<(body: any, headers: Headers ) => any?> } [transformRequest] An array of transformations to apply to the outgoing request
3030 * @property {string } [baseURL] a base URL from which to resolve all URLs
3131 * @property {typeof window.fetch } [fetch] Custom window.fetch implementation
32+ * @property {AbortSignal } [cancelToken] signal returned by AbortController
3233 * @property {any } [data]
3334 */
3435
3536/**
3637 * @public
37- * @typedef RequestHeaders
38- * @type {{[name: string]: string} | Headers }
38+ * @typedef Headers
39+ * @type {{[name: string]: string} }
3940 */
4041
4142/**
6566 */
6667
6768/**
68- * @public
69- * @param {Options } [defaults = {}]
70- * @returns {redaxios }
69+ * @typedef CancelToken
70+ * @type {{ (executor: Function): AbortSignal; source(): { token: AbortSignal; cancel: () => void; }; } }
7171 */
72- function create ( defaults ) {
72+
73+ /**
74+ * @typedef CancelTokenSourceMethod
75+ * @type {() => { token: AbortSignal, cancel: () => void } }
76+ */
77+
78+ /** */
79+ export default ( function create ( /** @type {Options } */ defaults ) {
7380 defaults = defaults || { } ;
7481
7582 /**
@@ -109,21 +116,25 @@ function create(defaults) {
109116 * @param {(...args: Args[]) => R } fn
110117 * @returns {(array: Args[]) => R }
111118 */
112- redaxios . spread = ( fn ) => /** @type {any } */ ( fn . apply . bind ( fn , fn ) ) ;
119+ redaxios . spread = function ( fn ) {
120+ return function ( results ) {
121+ return fn . apply ( this , results ) ;
122+ } ;
123+ } ;
124+ // 3b smaller:
125+ // redaxios.spread = (fn) => /** @type {any } */ (fn.apply.bind(fn, fn));
113126
114127 /**
115128 * @private
116- * @template T, U
117- * @param {T } opts
118- * @param {U } [overrides]
129+ * @param {Record<string,any> } opts
130+ * @param {Record<string,any> } [overrides]
119131 * @param {boolean } [lowerCase]
120- * @returns {{} & (T | U) }
132+ * @returns {Partial<opts> }
121133 */
122134 function deepMerge ( opts , overrides , lowerCase ) {
123- let out = /** @type { any } */ ( { } ) ,
135+ let out = { } ,
124136 i ;
125137 if ( Array . isArray ( opts ) ) {
126- // @ts -ignore
127138 return opts . concat ( overrides ) ;
128139 }
129140 for ( i in opts ) {
@@ -133,78 +144,113 @@ function create(defaults) {
133144 for ( i in overrides ) {
134145 const key = lowerCase ? i . toLowerCase ( ) : i ;
135146 const value = /** @type {any } */ ( overrides ) [ i ] ;
136- out [ key ] = key in out && typeof value == 'object' ? deepMerge ( out [ key ] , value , key == 'headers' ) : value ;
147+ out [ key ] = key in out && typeof value == 'object' ? deepMerge ( out [ key ] , value , key === 'headers' ) : value ;
137148 }
138149 return out ;
139150 }
140151
152+ /**
153+ * CancelToken
154+ * @private
155+ * @param {Function } executor
156+ * @returns {AbortSignal }
157+ */
158+ function CancelToken ( executor ) {
159+ if ( typeof executor !== 'function' ) {
160+ throw new TypeError ( 'executor must be a function.' ) ;
161+ }
162+
163+ const ac = new AbortController ( ) ;
164+
165+ executor ( ac . abort . bind ( ac ) ) ;
166+
167+ return ac . signal ;
168+ }
169+
170+ /**
171+ * @private
172+ * @type {CancelTokenSourceMethod }
173+ * @returns
174+ */
175+ CancelToken . source = ( ) => {
176+ const ac = new AbortController ( ) ;
177+
178+ return {
179+ token : ac . signal ,
180+ cancel : ac . abort . bind ( ac )
181+ } ;
182+ } ;
183+
141184 /**
142185 * Issues a request.
143186 * @public
144187 * @template T
145- * @param {string | Options } urlOrConfig
146- * @param {Options } [config = {}]
147- * @param {any } [_method] (internal)
148- * @param {any } [data] (internal)
149- * @param {never } [_undefined] (internal)
188+ * @param {string | Options } url
189+ * @param {Options } [config]
190+ * @param {any } [_method]
191+ * @param {any } [_data]
150192 * @returns {Promise<Response<T>> }
151193 */
152- function redaxios ( urlOrConfig , config , _method , data , _undefined ) {
153- let url = /** @type {string } */ ( typeof urlOrConfig != 'string' ? ( config = urlOrConfig ) . url : urlOrConfig ) ;
194+ function redaxios ( url , config , _method , _data ) {
195+ if ( typeof url !== 'string' ) {
196+ config = url ;
197+ url = config . url ;
198+ }
154199
155200 const response = /** @type {Response<any> } */ ( { config } ) ;
156201
157202 /** @type {Options } */
158203 const options = deepMerge ( defaults , config ) ;
159204
160- /** @type {RequestHeaders } */
205+ /** @type {Headers } */
161206 const customHeaders = { } ;
162207
163- data = data || options . data ;
208+ let data = _data || options . data ;
164209
165210 ( options . transformRequest || [ ] ) . map ( ( f ) => {
166211 data = f ( data , options . headers ) || data ;
167212 } ) ;
168213
169- if ( options . auth ) {
170- customHeaders . authorization = options . auth ;
171- }
172-
173- if ( data && typeof data === 'object' && typeof data . append !== 'function' && typeof data . text !== 'function' ) {
214+ if ( data && typeof data === 'object' && typeof data . append !== 'function' ) {
174215 data = JSON . stringify ( data ) ;
175216 customHeaders [ 'content-type' ] = 'application/json' ;
176217 }
177218
178- try {
179- // @ts -ignore providing the cookie name without header name is nonsensical anyway
180- customHeaders [ options . xsrfHeaderName ] = decodeURIComponent (
181- // @ts -ignore accessing match()[2] throws for no match, which is intentional
182- document . cookie . match ( RegExp ( '(^|; )' + options . xsrfCookieName + '=([^;]*)' ) ) [ 2 ]
183- ) ;
184- } catch ( e ) { }
219+ const m =
220+ typeof document !== 'undefined' && document . cookie . match ( RegExp ( '(^|; )' + options . xsrfCookieName + '=([^;]*)' ) ) ;
221+ if ( m ) customHeaders [ options . xsrfHeaderName ] = m [ 2 ] ;
222+
223+ if ( options . auth ) {
224+ customHeaders . authorization = options . auth ;
225+ }
185226
186227 if ( options . baseURL ) {
187- url = url . replace ( / ^ (? ! .* \/ \/ ) \/ ? / , options . baseURL + '/' ) ;
228+ url = url . replace ( / ^ (? ! .* \/ \/ ) \/ ? ( . * ) $ / , options . baseURL + '/$1 ' ) ;
188229 }
189230
190231 if ( options . params ) {
191- url +=
192- ( ~ url . indexOf ( '?' ) ? '&' : '?' ) +
193- ( options . paramsSerializer ? options . paramsSerializer ( options . params ) : new URLSearchParams ( options . params ) ) ;
232+ const divider = ~ url . indexOf ( '?' ) ? '&' : '?' ;
233+ const query = options . paramsSerializer
234+ ? options . paramsSerializer ( options . params )
235+ : new URLSearchParams ( options . params ) ;
236+ url += divider + query ;
194237 }
195238
196239 const fetchFunc = options . fetch || fetch ;
197240
198241 return fetchFunc ( url , {
199- method : ( _method || options . method || 'get' ) . toUpperCase ( ) ,
242+ method : _method || options . method ,
200243 body : data ,
201244 headers : deepMerge ( options . headers , customHeaders , true ) ,
202- credentials : options . withCredentials ? 'include' : _undefined
245+ credentials : options . withCredentials ? 'include' : 'same-origin' ,
246+ signal : options . cancelToken
203247 } ) . then ( ( res ) => {
204248 for ( const i in res ) {
205249 if ( typeof res [ i ] != 'function' ) response [ i ] = res [ i ] ;
206250 }
207251
252+ const ok = options . validateStatus ? options . validateStatus ( res . status ) : res . ok ;
253+
208254 if ( options . responseType == 'stream' ) {
209255 response . data = res . body ;
210256 return response ;
@@ -217,18 +263,22 @@ function create(defaults) {
217263 response . data = JSON . parse ( data ) ;
218264 } )
219265 . catch ( Object )
220- . then ( ( ) => {
221- const ok = options . validateStatus ? options . validateStatus ( res . status ) : res . ok ;
222- return ok ? response : Promise . reject ( response ) ;
223- } ) ;
266+ . then ( ( ) => ( ok ? response : Promise . reject ( response ) ) ) ;
224267 } ) ;
225268 }
226269
227270 /**
228271 * @public
229- * @type {AbortController }
272+ * @type {CancelToken }
273+ */
274+ redaxios . CancelToken = CancelToken ;
275+
276+ /**
277+ * @public
278+ * @param {DOMError } e
279+ * @returns {boolean }
230280 */
231- redaxios . CancelToken = /** @type { any } */ ( typeof AbortController == 'function' ? AbortController : Object ) ;
281+ redaxios . isCancel = ( e ) => e . name === 'AbortError' ;
232282
233283 /**
234284 * @public
@@ -242,6 +292,4 @@ function create(defaults) {
242292 redaxios . create = create ;
243293
244294 return redaxios ;
245- }
246-
247- export default create ( ) ;
295+ } ) ( ) ;
0 commit comments