@naturalcycles/js-lib 14.141.0 → 14.143.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/app.error.d.ts +4 -4
- package/dist/error/app.error.js +3 -3
- package/dist/error/assert.d.ts +5 -3
- package/dist/error/assert.js +18 -6
- package/dist/error/error.model.d.ts +44 -21
- package/dist/error/error.util.d.ts +4 -4
- package/dist/error/error.util.js +8 -11
- package/dist/error/httpRequestError.d.ts +22 -0
- package/dist/error/httpRequestError.js +27 -0
- package/dist/error/jsonParseError.d.ts +11 -0
- package/dist/error/jsonParseError.js +11 -0
- package/dist/error/try.js +1 -1
- package/dist/http/fetcher.js +34 -31
- package/dist/http/http.model.d.ts +4 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/promise/pTimeout.d.ts +2 -2
- package/dist/promise/pTimeout.js +2 -2
- package/dist/string/json.util.d.ts +9 -1
- package/dist/string/json.util.js +19 -1
- package/dist/string/stringifyAny.js +6 -6
- package/dist/types.d.ts +8 -0
- package/dist-esm/error/app.error.js +3 -3
- package/dist-esm/error/assert.js +17 -6
- package/dist-esm/error/error.util.js +5 -8
- package/dist-esm/error/httpRequestError.js +23 -0
- package/dist-esm/error/jsonParseError.js +7 -0
- package/dist-esm/error/try.js +1 -1
- package/dist-esm/http/fetcher.js +36 -28
- package/dist-esm/index.js +2 -1
- package/dist-esm/promise/pTimeout.js +2 -2
- package/dist-esm/string/json.util.js +17 -0
- package/dist-esm/string/stringifyAny.js +7 -7
- package/package.json +1 -1
- package/src/error/app.error.ts +6 -6
- package/src/error/assert.ts +22 -9
- package/src/error/error.model.ts +48 -23
- package/src/error/error.util.ts +15 -12
- package/src/error/httpRequestError.ts +25 -0
- package/src/error/jsonParseError.ts +21 -0
- package/src/error/try.ts +1 -1
- package/src/http/fetcher.ts +42 -32
- package/src/http/http.model.ts +5 -0
- package/src/index.ts +2 -1
- package/src/promise/pTimeout.ts +3 -3
- package/src/string/json.util.ts +20 -4
- package/src/string/stringifyAny.ts +7 -7
- package/src/types.ts +11 -0
- package/dist/error/http.error.d.ts +0 -8
- package/dist/error/http.error.js +0 -13
- package/dist-esm/error/http.error.js +0 -9
- package/src/error/http.error.ts +0 -13
package/src/http/fetcher.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { isServerSide } from '../env'
|
|
4
4
|
import { ErrorObject } from '../error/error.model'
|
|
5
5
|
import { _anyToError, _anyToErrorObject, _errorToErrorObject } from '../error/error.util'
|
|
6
|
-
import {
|
|
6
|
+
import { HttpRequestError } from '../error/httpRequestError'
|
|
7
7
|
import { _clamp } from '../number/number.util'
|
|
8
8
|
import {
|
|
9
9
|
_filterNullishValues,
|
|
@@ -13,8 +13,9 @@ import {
|
|
|
13
13
|
_omit,
|
|
14
14
|
} from '../object/object.util'
|
|
15
15
|
import { pDelay } from '../promise/pDelay'
|
|
16
|
-
import { _jsonParseIfPossible } from '../string/json.util'
|
|
16
|
+
import { _jsonParse, _jsonParseIfPossible } from '../string/json.util'
|
|
17
17
|
import { _since } from '../time/time.util'
|
|
18
|
+
import { UnixTimestampNumber } from '../types'
|
|
18
19
|
import type {
|
|
19
20
|
FetcherAfterResponseHook,
|
|
20
21
|
FetcherBeforeRequestHook,
|
|
@@ -218,7 +219,7 @@ export class Fetcher {
|
|
|
218
219
|
)
|
|
219
220
|
} else {
|
|
220
221
|
// !res.ok
|
|
221
|
-
await this.onNotOkResponse(res, timeout)
|
|
222
|
+
await this.onNotOkResponse(res, started, timeout)
|
|
222
223
|
}
|
|
223
224
|
}
|
|
224
225
|
|
|
@@ -231,7 +232,7 @@ export class Fetcher {
|
|
|
231
232
|
|
|
232
233
|
private async onOkResponse(
|
|
233
234
|
res: FetcherResponse<any> & { fetchResponse: Response },
|
|
234
|
-
started:
|
|
235
|
+
started: UnixTimestampNumber,
|
|
235
236
|
timeout?: number,
|
|
236
237
|
): Promise<void> {
|
|
237
238
|
const { req } = res
|
|
@@ -244,14 +245,21 @@ export class Fetcher {
|
|
|
244
245
|
if (text) {
|
|
245
246
|
try {
|
|
246
247
|
res.body = text
|
|
247
|
-
res.body =
|
|
248
|
+
res.body = _jsonParse(text, req.jsonReviver)
|
|
248
249
|
} catch (err) {
|
|
249
|
-
|
|
250
|
-
res.err =
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
250
|
+
// Error while parsing json
|
|
251
|
+
// res.err = _anyToError(err, HttpRequestError, {
|
|
252
|
+
// requestUrl: res.req.url,
|
|
253
|
+
// requestBaseUrl: this.cfg.baseUrl,
|
|
254
|
+
// requestMethod: res.req.init.method,
|
|
255
|
+
// requestSignature: res.signature,
|
|
256
|
+
// requestDuration: Date.now() - started,
|
|
257
|
+
// responseStatusCode: res.fetchResponse.status,
|
|
258
|
+
// } satisfies HttpRequestErrorData)
|
|
259
|
+
res.err = _anyToError(err)
|
|
254
260
|
res.ok = false
|
|
261
|
+
|
|
262
|
+
return await this.onNotOkResponse(res, started, timeout)
|
|
255
263
|
}
|
|
256
264
|
} else {
|
|
257
265
|
// Body had a '' (empty string)
|
|
@@ -302,42 +310,44 @@ export class Fetcher {
|
|
|
302
310
|
return await globalThis.fetch(url, init)
|
|
303
311
|
}
|
|
304
312
|
|
|
305
|
-
private async onNotOkResponse(
|
|
313
|
+
private async onNotOkResponse(
|
|
314
|
+
res: FetcherResponse,
|
|
315
|
+
started: UnixTimestampNumber,
|
|
316
|
+
timeout?: number,
|
|
317
|
+
): Promise<void> {
|
|
306
318
|
clearTimeout(timeout)
|
|
307
319
|
|
|
308
|
-
let
|
|
320
|
+
let cause: ErrorObject | undefined
|
|
309
321
|
|
|
310
|
-
if (res.
|
|
322
|
+
if (res.err) {
|
|
323
|
+
// This is only possible on JSON.parse error (or CORS error!)
|
|
324
|
+
// This check should go first, to avoid calling .text() twice (which will fail)
|
|
325
|
+
cause = _errorToErrorObject(res.err)
|
|
326
|
+
} else if (res.fetchResponse) {
|
|
311
327
|
const body = _jsonParseIfPossible(await res.fetchResponse.text())
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
} else {
|
|
316
|
-
errObj = {} as ErrorObject
|
|
328
|
+
if (body) {
|
|
329
|
+
cause = _anyToErrorObject(body)
|
|
330
|
+
}
|
|
317
331
|
}
|
|
318
332
|
|
|
319
|
-
const
|
|
320
|
-
errObj.message = [
|
|
321
|
-
[res.fetchResponse?.status, res.signature].filter(Boolean).join(' '),
|
|
322
|
-
originalMessage,
|
|
323
|
-
]
|
|
324
|
-
.filter(Boolean)
|
|
325
|
-
.join('\n')
|
|
326
|
-
|
|
327
|
-
res.err = new HttpError(
|
|
328
|
-
errObj.message,
|
|
333
|
+
const message = [res.fetchResponse?.status, res.signature].filter(Boolean).join(' ')
|
|
329
334
|
|
|
335
|
+
res.err = new HttpRequestError(
|
|
336
|
+
message,
|
|
330
337
|
_filterNullishValues({
|
|
331
|
-
|
|
332
|
-
originalMessage,
|
|
333
|
-
httpStatusCode: res.fetchResponse?.status || 0,
|
|
338
|
+
responseStatusCode: res.fetchResponse?.status || 0,
|
|
334
339
|
// These properties are provided to be used in e.g custom Sentry error grouping
|
|
335
340
|
// Actually, disabled now, to avoid unnecessary error printing when both msg and data are printed
|
|
336
341
|
// Enabled, cause `data` is not printed by default when error is HttpError
|
|
337
342
|
// method: req.method,
|
|
338
|
-
url: res.req.url,
|
|
339
343
|
// tryCount: req.tryCount,
|
|
344
|
+
requestUrl: res.req.url,
|
|
345
|
+
requestBaseUrl: this.cfg.baseUrl || (null as any),
|
|
346
|
+
requestMethod: res.req.init.method,
|
|
347
|
+
requestSignature: res.signature,
|
|
348
|
+
requestDuration: Date.now() - started,
|
|
340
349
|
}),
|
|
350
|
+
cause,
|
|
341
351
|
)
|
|
342
352
|
|
|
343
353
|
await this.processRetry(res)
|
package/src/http/http.model.ts
CHANGED
|
@@ -3,4 +3,9 @@ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD'
|
|
|
3
3
|
|
|
4
4
|
export type HttpStatusFamily = 5 | 4 | 3 | 2 | 1
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Number, representing a valid Http status code (e.g 401, 500, etc)
|
|
8
|
+
*/
|
|
9
|
+
export type HttpStatusCode = number
|
|
10
|
+
|
|
6
11
|
export const HTTP_METHODS: HttpMethod[] = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD']
|
package/src/index.ts
CHANGED
|
@@ -20,9 +20,10 @@ export * from './enum.util'
|
|
|
20
20
|
export * from './error/error.model'
|
|
21
21
|
export * from './error/error.util'
|
|
22
22
|
export * from './error/errorMode'
|
|
23
|
-
export * from './error/
|
|
23
|
+
export * from './error/httpRequestError'
|
|
24
24
|
export * from './error/try'
|
|
25
25
|
export * from './error/tryCatch'
|
|
26
|
+
export * from './error/jsonParseError'
|
|
26
27
|
export * from './json-schema/from-data/generateJsonSchemaFromData'
|
|
27
28
|
export * from './json-schema/jsonSchema.cnst'
|
|
28
29
|
export * from './json-schema/jsonSchema.model'
|
package/src/promise/pTimeout.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { AppError } from '../error/app.error'
|
|
2
|
-
import type { ErrorData } from '../error/error.model'
|
|
2
|
+
import type { ErrorData, ErrorObject } from '../error/error.model'
|
|
3
3
|
import { _errorDataAppend } from '../error/error.util'
|
|
4
4
|
import type { AnyAsyncFunction } from '../types'
|
|
5
5
|
|
|
6
6
|
export class TimeoutError extends AppError {
|
|
7
|
-
constructor(message: string, data = {},
|
|
8
|
-
super(message, data,
|
|
7
|
+
constructor(message: string, data = {}, cause?: ErrorObject) {
|
|
8
|
+
super(message, data, cause, 'TimeoutError')
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
|
package/src/string/json.util.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { JsonParseError } from '../error/jsonParseError'
|
|
2
|
+
import { Reviver } from '../types'
|
|
3
|
+
|
|
1
4
|
// const possibleJsonStartTokens = ['{', '[', '"']
|
|
2
5
|
const DETECT_JSON = /^\s*[{["\-\d]/
|
|
3
6
|
|
|
@@ -5,10 +8,7 @@ const DETECT_JSON = /^\s*[{["\-\d]/
|
|
|
5
8
|
* Attempts to parse object as JSON.
|
|
6
9
|
* Returns original object if JSON parse failed (silently).
|
|
7
10
|
*/
|
|
8
|
-
export function _jsonParseIfPossible(
|
|
9
|
-
obj: any,
|
|
10
|
-
reviver?: (this: any, key: string, value: any) => any,
|
|
11
|
-
): any {
|
|
11
|
+
export function _jsonParseIfPossible(obj: any, reviver?: Reviver): any {
|
|
12
12
|
// Optimization: only try to parse if it looks like JSON: starts with a json possible character
|
|
13
13
|
if (typeof obj === 'string' && obj && DETECT_JSON.test(obj)) {
|
|
14
14
|
try {
|
|
@@ -18,3 +18,19 @@ export function _jsonParseIfPossible(
|
|
|
18
18
|
|
|
19
19
|
return obj
|
|
20
20
|
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Same as JSON.parse, but throws JsonParseError:
|
|
24
|
+
*
|
|
25
|
+
* 1. It's message includes a piece of source text (truncated)
|
|
26
|
+
* 2. It's data.text contains full source text
|
|
27
|
+
*/
|
|
28
|
+
export function _jsonParse(s: string, reviver?: Reviver): unknown {
|
|
29
|
+
try {
|
|
30
|
+
return JSON.parse(s, reviver)
|
|
31
|
+
} catch {
|
|
32
|
+
throw new JsonParseError({
|
|
33
|
+
text: s,
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _isErrorObject,
|
|
1
|
+
import { _isErrorObject, _isBackendErrorResponseObject } from '../error/error.util'
|
|
2
2
|
import type { Reviver } from '../types'
|
|
3
3
|
import { _jsonParseIfPossible } from './json.util'
|
|
4
4
|
import { _safeJsonStringify } from './safeJsonStringify'
|
|
@@ -88,7 +88,7 @@ export function _stringifyAny(obj: any, opt: StringifyAnyOptions = {}): string {
|
|
|
88
88
|
//
|
|
89
89
|
// HttpErrorResponse
|
|
90
90
|
//
|
|
91
|
-
if (
|
|
91
|
+
if (_isBackendErrorResponseObject(obj)) {
|
|
92
92
|
return _stringifyAny(obj.error, opt)
|
|
93
93
|
}
|
|
94
94
|
|
|
@@ -103,12 +103,12 @@ export function _stringifyAny(obj: any, opt: StringifyAnyOptions = {}): string {
|
|
|
103
103
|
// if (obj?.name === 'Error') {
|
|
104
104
|
// s = obj.message
|
|
105
105
|
// }
|
|
106
|
-
if (_isErrorObject(obj) && _isHttpErrorObject(obj)) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
106
|
+
// if (_isErrorObject(obj) && _isHttpErrorObject(obj)) {
|
|
107
|
+
// // Printing (0) to avoid ambiguity
|
|
108
|
+
// s = `${obj.name}(${obj.data.httpStatusCode}): ${obj.message}`
|
|
109
|
+
// }
|
|
110
110
|
|
|
111
|
-
s
|
|
111
|
+
s = [obj.name, obj.message].filter(Boolean).join(': ')
|
|
112
112
|
|
|
113
113
|
if (typeof (obj as any).code === 'string') {
|
|
114
114
|
// Error that has no `data`, but has `code` property
|
package/src/types.ts
CHANGED
|
@@ -222,15 +222,26 @@ export type UnixTimestampMillisNumber = number
|
|
|
222
222
|
*/
|
|
223
223
|
export type UnixTimestamp = number
|
|
224
224
|
|
|
225
|
+
export type NumberOfSeconds = number
|
|
226
|
+
export type NumberOfMilliseconds = number
|
|
227
|
+
|
|
225
228
|
/**
|
|
226
229
|
* Same as `number`, but with semantic meaning that it's an Integer.
|
|
227
230
|
*/
|
|
228
231
|
export type Integer = number
|
|
229
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Used as a compact representation of truthy value.
|
|
235
|
+
* undefined ('' or other short falsy value) should be used as falsy value.
|
|
236
|
+
*/
|
|
237
|
+
export type ShortBoolean = '1'
|
|
238
|
+
|
|
230
239
|
export type Base64String = string
|
|
231
240
|
export type Base64UrlString = string
|
|
232
241
|
export type JWTString = string
|
|
233
242
|
|
|
243
|
+
export type SemVerString = string
|
|
244
|
+
|
|
234
245
|
/**
|
|
235
246
|
* Named type for JSON.parse / JSON.stringify second argument
|
|
236
247
|
*/
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { AppError } from './app.error';
|
|
2
|
-
import type { HttpErrorData } from './error.model';
|
|
3
|
-
/**
|
|
4
|
-
* Base class for HTTP errors - errors that define HTTP error code.
|
|
5
|
-
*/
|
|
6
|
-
export declare class HttpError<DATA_TYPE extends HttpErrorData = HttpErrorData> extends AppError<DATA_TYPE> {
|
|
7
|
-
constructor(message: string, data: DATA_TYPE, opt?: ErrorOptions);
|
|
8
|
-
}
|
package/dist/error/http.error.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.HttpError = void 0;
|
|
4
|
-
const app_error_1 = require("./app.error");
|
|
5
|
-
/**
|
|
6
|
-
* Base class for HTTP errors - errors that define HTTP error code.
|
|
7
|
-
*/
|
|
8
|
-
class HttpError extends app_error_1.AppError {
|
|
9
|
-
constructor(message, data, opt) {
|
|
10
|
-
super(message, data, opt, 'HttpError');
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
exports.HttpError = HttpError;
|
package/src/error/http.error.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { AppError } from './app.error'
|
|
2
|
-
import type { HttpErrorData } from './error.model'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Base class for HTTP errors - errors that define HTTP error code.
|
|
6
|
-
*/
|
|
7
|
-
export class HttpError<
|
|
8
|
-
DATA_TYPE extends HttpErrorData = HttpErrorData,
|
|
9
|
-
> extends AppError<DATA_TYPE> {
|
|
10
|
-
constructor(message: string, data: DATA_TYPE, opt?: ErrorOptions) {
|
|
11
|
-
super(message, data, opt, 'HttpError')
|
|
12
|
-
}
|
|
13
|
-
}
|