@naturalcycles/js-lib 14.150.0 → 14.151.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/error/error.model.d.ts +11 -0
- package/dist/error/error.util.d.ts +3 -2
- package/dist/error/error.util.js +16 -10
- package/dist/http/fetcher.js +6 -4
- package/dist/http/fetcher.model.d.ts +4 -2
- package/dist/string/stringifyAny.js +2 -2
- package/dist-esm/error/error.util.js +13 -8
- package/dist-esm/http/fetcher.js +7 -6
- package/dist-esm/string/stringifyAny.js +3 -3
- package/package.json +1 -1
- package/src/error/error.model.ts +11 -7
- package/src/error/error.util.ts +13 -8
- package/src/http/fetcher.model.ts +4 -2
- package/src/http/fetcher.ts +7 -5
- package/src/string/stringifyAny.ts +3 -3
|
@@ -87,6 +87,17 @@ export interface HttpRequestErrorData extends ErrorData {
|
|
|
87
87
|
*/
|
|
88
88
|
responseStatusCode: HttpStatusCode;
|
|
89
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Sometimes there are cases when Errors come from unexpected places,
|
|
92
|
+
* where err is not instanceof Error, but still looks like Error.
|
|
93
|
+
*/
|
|
94
|
+
export interface ErrorLike {
|
|
95
|
+
name: string;
|
|
96
|
+
message: string;
|
|
97
|
+
stack?: string;
|
|
98
|
+
data?: any;
|
|
99
|
+
cause?: any;
|
|
100
|
+
}
|
|
90
101
|
/**
|
|
91
102
|
* Portable object that represents Error.
|
|
92
103
|
* Has extendable generic `data` property.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ErrorData, ErrorObject, BackendErrorResponseObject, Class, HttpRequestErrorData } from '..';
|
|
1
|
+
import type { ErrorData, ErrorObject, BackendErrorResponseObject, Class, HttpRequestErrorData, ErrorLike } from '..';
|
|
2
2
|
import { AppError } from '..';
|
|
3
3
|
/**
|
|
4
4
|
* Useful to ensure that error in `catch (err) { ... }`
|
|
@@ -16,7 +16,7 @@ export declare function _anyToError<ERROR_TYPE extends Error = Error>(o: any, er
|
|
|
16
16
|
* Objects (not Errors) get converted to prettified JSON string (via `_stringifyAny`).
|
|
17
17
|
*/
|
|
18
18
|
export declare function _anyToErrorObject<DATA_TYPE extends ErrorData = ErrorData>(o: any, errorData?: Partial<DATA_TYPE>): ErrorObject<DATA_TYPE>;
|
|
19
|
-
export declare function
|
|
19
|
+
export declare function _errorLikeToErrorObject<DATA_TYPE extends ErrorData = ErrorData>(e: AppError<DATA_TYPE> | Error | ErrorLike): ErrorObject<DATA_TYPE>;
|
|
20
20
|
export declare function _errorObjectToError<DATA_TYPE extends ErrorData, ERROR_TYPE extends Error>(o: ErrorObject<DATA_TYPE>, errorClass?: Class<ERROR_TYPE>): ERROR_TYPE;
|
|
21
21
|
export declare function _isBackendErrorResponseObject(o: any): o is BackendErrorResponseObject;
|
|
22
22
|
export declare function _isHttpRequestErrorObject(o: any): o is ErrorObject<HttpRequestErrorData>;
|
|
@@ -24,6 +24,7 @@ export declare function _isHttpRequestErrorObject(o: any): o is ErrorObject<Http
|
|
|
24
24
|
* Note: any instance of AppError is also automatically an ErrorObject
|
|
25
25
|
*/
|
|
26
26
|
export declare function _isErrorObject<DATA_TYPE extends ErrorData = ErrorData>(o: any): o is ErrorObject<DATA_TYPE>;
|
|
27
|
+
export declare function _isErrorLike(o: any): o is ErrorLike;
|
|
27
28
|
/**
|
|
28
29
|
* Convenience function to safely add properties to Error's `data` object
|
|
29
30
|
* (even if it wasn't previously existing)
|
package/dist/error/error.util.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports._errorDataAppend = exports._isErrorObject = exports._isHttpRequestErrorObject = exports._isBackendErrorResponseObject = exports._errorObjectToError = exports.
|
|
3
|
+
exports._errorDataAppend = exports._isErrorLike = exports._isErrorObject = exports._isHttpRequestErrorObject = exports._isBackendErrorResponseObject = exports._errorObjectToError = exports._errorLikeToErrorObject = exports._anyToErrorObject = exports._anyToError = void 0;
|
|
4
4
|
const __1 = require("..");
|
|
5
5
|
/**
|
|
6
6
|
* Useful to ensure that error in `catch (err) { ... }`
|
|
@@ -38,8 +38,9 @@ exports._anyToError = _anyToError;
|
|
|
38
38
|
*/
|
|
39
39
|
function _anyToErrorObject(o, errorData) {
|
|
40
40
|
let eo;
|
|
41
|
-
if (o instanceof Error) {
|
|
42
|
-
|
|
41
|
+
// if (o instanceof Error) {
|
|
42
|
+
if (_isErrorLike(o)) {
|
|
43
|
+
eo = _errorLikeToErrorObject(o);
|
|
43
44
|
}
|
|
44
45
|
else {
|
|
45
46
|
o = (0, __1._jsonParseIfPossible)(o);
|
|
@@ -49,6 +50,9 @@ function _anyToErrorObject(o, errorData) {
|
|
|
49
50
|
else if (_isErrorObject(o)) {
|
|
50
51
|
eo = o;
|
|
51
52
|
}
|
|
53
|
+
else if (_isErrorLike(o)) {
|
|
54
|
+
eo = _errorLikeToErrorObject(o);
|
|
55
|
+
}
|
|
52
56
|
else {
|
|
53
57
|
// Here we are sure it has no `data` property,
|
|
54
58
|
// so, fair to return `data: {}` in the end
|
|
@@ -66,19 +70,20 @@ function _anyToErrorObject(o, errorData) {
|
|
|
66
70
|
return eo;
|
|
67
71
|
}
|
|
68
72
|
exports._anyToErrorObject = _anyToErrorObject;
|
|
69
|
-
function
|
|
73
|
+
function _errorLikeToErrorObject(e) {
|
|
70
74
|
const obj = {
|
|
71
75
|
name: e.name,
|
|
72
76
|
message: e.message,
|
|
73
|
-
data: { ...e.data },
|
|
74
|
-
stack: e.stack,
|
|
77
|
+
data: { ...e.data }, // empty by default
|
|
75
78
|
};
|
|
79
|
+
if (e.stack)
|
|
80
|
+
obj.stack = e.stack;
|
|
76
81
|
if (e.cause) {
|
|
77
82
|
obj.cause = _anyToErrorObject(e.cause);
|
|
78
83
|
}
|
|
79
84
|
return obj;
|
|
80
85
|
}
|
|
81
|
-
exports.
|
|
86
|
+
exports._errorLikeToErrorObject = _errorLikeToErrorObject;
|
|
82
87
|
function _errorObjectToError(o, errorClass = Error) {
|
|
83
88
|
if (o instanceof errorClass)
|
|
84
89
|
return o;
|
|
@@ -136,9 +141,10 @@ function _isErrorObject(o) {
|
|
|
136
141
|
typeof o.data === 'object');
|
|
137
142
|
}
|
|
138
143
|
exports._isErrorObject = _isErrorObject;
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
144
|
+
function _isErrorLike(o) {
|
|
145
|
+
return !!o && typeof o === 'object' && typeof o.name === 'string' && typeof o.message === 'string';
|
|
146
|
+
}
|
|
147
|
+
exports._isErrorLike = _isErrorLike;
|
|
142
148
|
/**
|
|
143
149
|
* Convenience function to safely add properties to Error's `data` object
|
|
144
150
|
* (even if it wasn't previously existing)
|
package/dist/http/fetcher.js
CHANGED
|
@@ -156,7 +156,8 @@ class Fetcher {
|
|
|
156
156
|
}
|
|
157
157
|
catch (err) {
|
|
158
158
|
// For example, CORS error would result in "TypeError: failed to fetch" here
|
|
159
|
-
|
|
159
|
+
// or, `fetch failed` with the cause of `unexpected redirect`
|
|
160
|
+
res.err = (0, error_util_1._anyToError)(err);
|
|
160
161
|
res.ok = false;
|
|
161
162
|
// important to set it to undefined, otherwise it can keep the previous value (from previous try)
|
|
162
163
|
res.fetchResponse = undefined;
|
|
@@ -259,9 +260,10 @@ class Fetcher {
|
|
|
259
260
|
clearTimeout(timeout);
|
|
260
261
|
let cause;
|
|
261
262
|
if (res.err) {
|
|
262
|
-
// This is only possible on JSON.parse error
|
|
263
|
+
// This is only possible on JSON.parse error, or CORS error,
|
|
264
|
+
// or `unexpected redirect`
|
|
263
265
|
// This check should go first, to avoid calling .text() twice (which will fail)
|
|
264
|
-
cause = (0, error_util_1.
|
|
266
|
+
cause = (0, error_util_1._errorLikeToErrorObject)(res.err);
|
|
265
267
|
}
|
|
266
268
|
else if (res.fetchResponse) {
|
|
267
269
|
const body = (0, json_util_1._jsonParseIfPossible)(await res.fetchResponse.text());
|
|
@@ -467,7 +469,7 @@ class Fetcher {
|
|
|
467
469
|
...this.cfg.init,
|
|
468
470
|
method: opt.method || this.cfg.init.method,
|
|
469
471
|
credentials: opt.credentials || this.cfg.init.credentials,
|
|
470
|
-
redirect: opt.
|
|
472
|
+
redirect: opt.redirect || 'follow',
|
|
471
473
|
}, {
|
|
472
474
|
headers: (0, object_util_1._mapKeys)(opt.headers || {}, k => k.toLowerCase()),
|
|
473
475
|
}),
|
|
@@ -123,9 +123,11 @@ export interface FetcherOptions {
|
|
|
123
123
|
body?: Blob | BufferSource | FormData | URLSearchParams | string;
|
|
124
124
|
credentials?: RequestCredentials;
|
|
125
125
|
/**
|
|
126
|
-
* Default to
|
|
126
|
+
* Default to 'follow'.
|
|
127
|
+
* 'error' would throw on redirect.
|
|
128
|
+
* 'manual' will not throw, but return !ok response with 3xx status.
|
|
127
129
|
*/
|
|
128
|
-
|
|
130
|
+
redirect?: RequestRedirect;
|
|
129
131
|
headers?: Record<string, any>;
|
|
130
132
|
mode?: FetcherMode;
|
|
131
133
|
searchParams?: Record<string, any>;
|
|
@@ -59,10 +59,10 @@ function _stringifyAny(obj, opt = {}) {
|
|
|
59
59
|
if ((0, error_util_1._isBackendErrorResponseObject)(obj)) {
|
|
60
60
|
return _stringifyAny(obj.error, opt);
|
|
61
61
|
}
|
|
62
|
-
if (obj instanceof Error || (0, error_util_1.
|
|
62
|
+
if (obj instanceof Error || (0, error_util_1._isErrorLike)(obj)) {
|
|
63
63
|
const { includeErrorCause = true } = opt;
|
|
64
64
|
//
|
|
65
|
-
// Error or
|
|
65
|
+
// Error or ErrorLike
|
|
66
66
|
//
|
|
67
67
|
// Omit "default" error name as non-informative
|
|
68
68
|
// UPD: no, it's still important to understand that we're dealing with Error and not just some string
|
|
@@ -31,8 +31,9 @@ export function _anyToError(o, errorClass = Error, errorData) {
|
|
|
31
31
|
*/
|
|
32
32
|
export function _anyToErrorObject(o, errorData) {
|
|
33
33
|
let eo;
|
|
34
|
-
if (o instanceof Error) {
|
|
35
|
-
|
|
34
|
+
// if (o instanceof Error) {
|
|
35
|
+
if (_isErrorLike(o)) {
|
|
36
|
+
eo = _errorLikeToErrorObject(o);
|
|
36
37
|
}
|
|
37
38
|
else {
|
|
38
39
|
o = _jsonParseIfPossible(o);
|
|
@@ -42,6 +43,9 @@ export function _anyToErrorObject(o, errorData) {
|
|
|
42
43
|
else if (_isErrorObject(o)) {
|
|
43
44
|
eo = o;
|
|
44
45
|
}
|
|
46
|
+
else if (_isErrorLike(o)) {
|
|
47
|
+
eo = _errorLikeToErrorObject(o);
|
|
48
|
+
}
|
|
45
49
|
else {
|
|
46
50
|
// Here we are sure it has no `data` property,
|
|
47
51
|
// so, fair to return `data: {}` in the end
|
|
@@ -58,13 +62,14 @@ export function _anyToErrorObject(o, errorData) {
|
|
|
58
62
|
Object.assign(eo.data, errorData);
|
|
59
63
|
return eo;
|
|
60
64
|
}
|
|
61
|
-
export function
|
|
65
|
+
export function _errorLikeToErrorObject(e) {
|
|
62
66
|
const obj = {
|
|
63
67
|
name: e.name,
|
|
64
68
|
message: e.message,
|
|
65
|
-
data: Object.assign({}, e.data),
|
|
66
|
-
stack: e.stack,
|
|
69
|
+
data: Object.assign({}, e.data), // empty by default
|
|
67
70
|
};
|
|
71
|
+
if (e.stack)
|
|
72
|
+
obj.stack = e.stack;
|
|
68
73
|
if (e.cause) {
|
|
69
74
|
obj.cause = _anyToErrorObject(e.cause);
|
|
70
75
|
}
|
|
@@ -124,9 +129,9 @@ export function _isErrorObject(o) {
|
|
|
124
129
|
typeof o.message === 'string' &&
|
|
125
130
|
typeof o.data === 'object');
|
|
126
131
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
132
|
+
export function _isErrorLike(o) {
|
|
133
|
+
return !!o && typeof o === 'object' && typeof o.name === 'string' && typeof o.message === 'string';
|
|
134
|
+
}
|
|
130
135
|
/**
|
|
131
136
|
* Convenience function to safely add properties to Error's `data` object
|
|
132
137
|
* (even if it wasn't previously existing)
|
package/dist-esm/http/fetcher.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference lib="dom"/>
|
|
2
2
|
import { isServerSide } from '../env';
|
|
3
|
-
import { _anyToError, _anyToErrorObject,
|
|
3
|
+
import { _anyToError, _anyToErrorObject, _errorLikeToErrorObject } from '../error/error.util';
|
|
4
4
|
import { HttpRequestError } from '../error/httpRequestError';
|
|
5
5
|
import { _clamp } from '../number/number.util';
|
|
6
6
|
import { _filterNullishValues, _filterUndefinedValues, _mapKeys, _merge, _omit, _pick, } from '../object/object.util';
|
|
@@ -141,7 +141,8 @@ export class Fetcher {
|
|
|
141
141
|
}
|
|
142
142
|
catch (err) {
|
|
143
143
|
// For example, CORS error would result in "TypeError: failed to fetch" here
|
|
144
|
-
|
|
144
|
+
// or, `fetch failed` with the cause of `unexpected redirect`
|
|
145
|
+
res.err = _anyToError(err);
|
|
145
146
|
res.ok = false;
|
|
146
147
|
// important to set it to undefined, otherwise it can keep the previous value (from previous try)
|
|
147
148
|
res.fetchResponse = undefined;
|
|
@@ -245,9 +246,10 @@ export class Fetcher {
|
|
|
245
246
|
clearTimeout(timeout);
|
|
246
247
|
let cause;
|
|
247
248
|
if (res.err) {
|
|
248
|
-
// This is only possible on JSON.parse error
|
|
249
|
+
// This is only possible on JSON.parse error, or CORS error,
|
|
250
|
+
// or `unexpected redirect`
|
|
249
251
|
// This check should go first, to avoid calling .text() twice (which will fail)
|
|
250
|
-
cause =
|
|
252
|
+
cause = _errorLikeToErrorObject(res.err);
|
|
251
253
|
}
|
|
252
254
|
else if (res.fetchResponse) {
|
|
253
255
|
const body = _jsonParseIfPossible(await res.fetchResponse.text());
|
|
@@ -431,7 +433,6 @@ export class Fetcher {
|
|
|
431
433
|
return norm;
|
|
432
434
|
}
|
|
433
435
|
normalizeOptions(opt) {
|
|
434
|
-
var _a, _b;
|
|
435
436
|
const req = Object.assign(Object.assign(Object.assign(Object.assign({}, _pick(this.cfg, [
|
|
436
437
|
'timeoutSeconds',
|
|
437
438
|
'throwHttpErrors',
|
|
@@ -444,7 +445,7 @@ export class Fetcher {
|
|
|
444
445
|
'logRequestBody',
|
|
445
446
|
'logResponse',
|
|
446
447
|
'logResponseBody',
|
|
447
|
-
])), { started: Date.now() }), _omit(opt, ['method', 'headers', 'credentials'])), { inputUrl: opt.url || '', fullUrl: opt.url || '', retry: Object.assign(Object.assign({}, this.cfg.retry), _filterUndefinedValues(opt.retry || {})), init: _merge(Object.assign(Object.assign({}, this.cfg.init), { method: opt.method || this.cfg.init.method, credentials: opt.credentials || this.cfg.init.credentials, redirect:
|
|
448
|
+
])), { started: Date.now() }), _omit(opt, ['method', 'headers', 'credentials'])), { inputUrl: opt.url || '', fullUrl: opt.url || '', retry: Object.assign(Object.assign({}, this.cfg.retry), _filterUndefinedValues(opt.retry || {})), init: _merge(Object.assign(Object.assign({}, this.cfg.init), { method: opt.method || this.cfg.init.method, credentials: opt.credentials || this.cfg.init.credentials, redirect: opt.redirect || 'follow' }), {
|
|
448
449
|
headers: _mapKeys(opt.headers || {}, k => k.toLowerCase()),
|
|
449
450
|
}) });
|
|
450
451
|
// setup url
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _isBackendErrorResponseObject, _isErrorLike } from '../error/error.util';
|
|
2
2
|
import { _jsonParseIfPossible } from './json.util';
|
|
3
3
|
import { _safeJsonStringify } from './safeJsonStringify';
|
|
4
4
|
const supportsAggregateError = typeof globalThis.AggregateError === 'function';
|
|
@@ -55,10 +55,10 @@ export function _stringifyAny(obj, opt = {}) {
|
|
|
55
55
|
if (_isBackendErrorResponseObject(obj)) {
|
|
56
56
|
return _stringifyAny(obj.error, opt);
|
|
57
57
|
}
|
|
58
|
-
if (obj instanceof Error ||
|
|
58
|
+
if (obj instanceof Error || _isErrorLike(obj)) {
|
|
59
59
|
const { includeErrorCause = true } = opt;
|
|
60
60
|
//
|
|
61
|
-
// Error or
|
|
61
|
+
// Error or ErrorLike
|
|
62
62
|
//
|
|
63
63
|
// Omit "default" error name as non-informative
|
|
64
64
|
// UPD: no, it's still important to understand that we're dealing with Error and not just some string
|
package/package.json
CHANGED
package/src/error/error.model.ts
CHANGED
|
@@ -104,13 +104,17 @@ export interface HttpRequestErrorData extends ErrorData {
|
|
|
104
104
|
responseStatusCode: HttpStatusCode
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
107
|
+
/**
|
|
108
|
+
* Sometimes there are cases when Errors come from unexpected places,
|
|
109
|
+
* where err is not instanceof Error, but still looks like Error.
|
|
110
|
+
*/
|
|
111
|
+
export interface ErrorLike {
|
|
112
|
+
name: string
|
|
113
|
+
message: string
|
|
114
|
+
stack?: string
|
|
115
|
+
data?: any
|
|
116
|
+
cause?: any
|
|
117
|
+
}
|
|
114
118
|
|
|
115
119
|
/**
|
|
116
120
|
* Portable object that represents Error.
|
package/src/error/error.util.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
BackendErrorResponseObject,
|
|
5
5
|
Class,
|
|
6
6
|
HttpRequestErrorData,
|
|
7
|
+
ErrorLike,
|
|
7
8
|
} from '..'
|
|
8
9
|
import { AppError, _jsonParseIfPossible, _stringifyAny } from '..'
|
|
9
10
|
|
|
@@ -53,8 +54,9 @@ export function _anyToErrorObject<DATA_TYPE extends ErrorData = ErrorData>(
|
|
|
53
54
|
): ErrorObject<DATA_TYPE> {
|
|
54
55
|
let eo: ErrorObject<DATA_TYPE>
|
|
55
56
|
|
|
56
|
-
if (o instanceof Error) {
|
|
57
|
-
|
|
57
|
+
// if (o instanceof Error) {
|
|
58
|
+
if (_isErrorLike(o)) {
|
|
59
|
+
eo = _errorLikeToErrorObject(o)
|
|
58
60
|
} else {
|
|
59
61
|
o = _jsonParseIfPossible(o)
|
|
60
62
|
|
|
@@ -62,6 +64,8 @@ export function _anyToErrorObject<DATA_TYPE extends ErrorData = ErrorData>(
|
|
|
62
64
|
eo = o.error as ErrorObject<DATA_TYPE>
|
|
63
65
|
} else if (_isErrorObject(o)) {
|
|
64
66
|
eo = o as ErrorObject<DATA_TYPE>
|
|
67
|
+
} else if (_isErrorLike(o)) {
|
|
68
|
+
eo = _errorLikeToErrorObject(o)
|
|
65
69
|
} else {
|
|
66
70
|
// Here we are sure it has no `data` property,
|
|
67
71
|
// so, fair to return `data: {}` in the end
|
|
@@ -81,16 +85,17 @@ export function _anyToErrorObject<DATA_TYPE extends ErrorData = ErrorData>(
|
|
|
81
85
|
return eo
|
|
82
86
|
}
|
|
83
87
|
|
|
84
|
-
export function
|
|
85
|
-
e: AppError<DATA_TYPE> | Error,
|
|
88
|
+
export function _errorLikeToErrorObject<DATA_TYPE extends ErrorData = ErrorData>(
|
|
89
|
+
e: AppError<DATA_TYPE> | Error | ErrorLike,
|
|
86
90
|
): ErrorObject<DATA_TYPE> {
|
|
87
91
|
const obj: ErrorObject<DATA_TYPE> = {
|
|
88
92
|
name: e.name,
|
|
89
93
|
message: e.message,
|
|
90
94
|
data: { ...(e as any).data }, // empty by default
|
|
91
|
-
stack: e.stack,
|
|
92
95
|
}
|
|
93
96
|
|
|
97
|
+
if (e.stack) obj.stack = e.stack
|
|
98
|
+
|
|
94
99
|
if (e.cause) {
|
|
95
100
|
obj.cause = _anyToErrorObject(e.cause)
|
|
96
101
|
}
|
|
@@ -168,9 +173,9 @@ export function _isErrorObject<DATA_TYPE extends ErrorData = ErrorData>(
|
|
|
168
173
|
)
|
|
169
174
|
}
|
|
170
175
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
176
|
+
export function _isErrorLike(o: any): o is ErrorLike {
|
|
177
|
+
return !!o && typeof o === 'object' && typeof o.name === 'string' && typeof o.message === 'string'
|
|
178
|
+
}
|
|
174
179
|
|
|
175
180
|
/**
|
|
176
181
|
* Convenience function to safely add properties to Error's `data` object
|
|
@@ -150,9 +150,11 @@ export interface FetcherOptions {
|
|
|
150
150
|
|
|
151
151
|
credentials?: RequestCredentials
|
|
152
152
|
/**
|
|
153
|
-
* Default to
|
|
153
|
+
* Default to 'follow'.
|
|
154
|
+
* 'error' would throw on redirect.
|
|
155
|
+
* 'manual' will not throw, but return !ok response with 3xx status.
|
|
154
156
|
*/
|
|
155
|
-
|
|
157
|
+
redirect?: RequestRedirect
|
|
156
158
|
|
|
157
159
|
// Removing RequestInit from options to simplify FetcherOptions interface.
|
|
158
160
|
// Will instead only add hand-picked useful options, such as `credentials`.
|
package/src/http/fetcher.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { isServerSide } from '../env'
|
|
4
4
|
import { ErrorObject } from '../error/error.model'
|
|
5
|
-
import { _anyToError, _anyToErrorObject,
|
|
5
|
+
import { _anyToError, _anyToErrorObject, _errorLikeToErrorObject } from '../error/error.util'
|
|
6
6
|
import { HttpRequestError } from '../error/httpRequestError'
|
|
7
7
|
import { _clamp } from '../number/number.util'
|
|
8
8
|
import {
|
|
@@ -221,7 +221,8 @@ export class Fetcher {
|
|
|
221
221
|
res.err = undefined
|
|
222
222
|
} catch (err) {
|
|
223
223
|
// For example, CORS error would result in "TypeError: failed to fetch" here
|
|
224
|
-
|
|
224
|
+
// or, `fetch failed` with the cause of `unexpected redirect`
|
|
225
|
+
res.err = _anyToError(err)
|
|
225
226
|
res.ok = false
|
|
226
227
|
// important to set it to undefined, otherwise it can keep the previous value (from previous try)
|
|
227
228
|
res.fetchResponse = undefined
|
|
@@ -336,9 +337,10 @@ export class Fetcher {
|
|
|
336
337
|
let cause: ErrorObject | undefined
|
|
337
338
|
|
|
338
339
|
if (res.err) {
|
|
339
|
-
// This is only possible on JSON.parse error
|
|
340
|
+
// This is only possible on JSON.parse error, or CORS error,
|
|
341
|
+
// or `unexpected redirect`
|
|
340
342
|
// This check should go first, to avoid calling .text() twice (which will fail)
|
|
341
|
-
cause =
|
|
343
|
+
cause = _errorLikeToErrorObject(res.err)
|
|
342
344
|
} else if (res.fetchResponse) {
|
|
343
345
|
const body = _jsonParseIfPossible(await res.fetchResponse.text())
|
|
344
346
|
if (body) {
|
|
@@ -574,7 +576,7 @@ export class Fetcher {
|
|
|
574
576
|
...this.cfg.init,
|
|
575
577
|
method: opt.method || this.cfg.init.method,
|
|
576
578
|
credentials: opt.credentials || this.cfg.init.credentials,
|
|
577
|
-
redirect: opt.
|
|
579
|
+
redirect: opt.redirect || 'follow',
|
|
578
580
|
},
|
|
579
581
|
{
|
|
580
582
|
headers: _mapKeys(opt.headers || {}, k => k.toLowerCase()),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _isBackendErrorResponseObject, _isErrorLike } from '../error/error.util'
|
|
2
2
|
import type { Reviver } from '../types'
|
|
3
3
|
import { _jsonParseIfPossible } from './json.util'
|
|
4
4
|
import { _safeJsonStringify } from './safeJsonStringify'
|
|
@@ -92,10 +92,10 @@ export function _stringifyAny(obj: any, opt: StringifyAnyOptions = {}): string {
|
|
|
92
92
|
return _stringifyAny(obj.error, opt)
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
if (obj instanceof Error ||
|
|
95
|
+
if (obj instanceof Error || _isErrorLike(obj)) {
|
|
96
96
|
const { includeErrorCause = true } = opt
|
|
97
97
|
//
|
|
98
|
-
// Error or
|
|
98
|
+
// Error or ErrorLike
|
|
99
99
|
//
|
|
100
100
|
|
|
101
101
|
// Omit "default" error name as non-informative
|