@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.
Files changed (52) hide show
  1. package/dist/error/app.error.d.ts +4 -4
  2. package/dist/error/app.error.js +3 -3
  3. package/dist/error/assert.d.ts +5 -3
  4. package/dist/error/assert.js +18 -6
  5. package/dist/error/error.model.d.ts +44 -21
  6. package/dist/error/error.util.d.ts +4 -4
  7. package/dist/error/error.util.js +8 -11
  8. package/dist/error/httpRequestError.d.ts +22 -0
  9. package/dist/error/httpRequestError.js +27 -0
  10. package/dist/error/jsonParseError.d.ts +11 -0
  11. package/dist/error/jsonParseError.js +11 -0
  12. package/dist/error/try.js +1 -1
  13. package/dist/http/fetcher.js +34 -31
  14. package/dist/http/http.model.d.ts +4 -0
  15. package/dist/index.d.ts +2 -1
  16. package/dist/index.js +2 -1
  17. package/dist/promise/pTimeout.d.ts +2 -2
  18. package/dist/promise/pTimeout.js +2 -2
  19. package/dist/string/json.util.d.ts +9 -1
  20. package/dist/string/json.util.js +19 -1
  21. package/dist/string/stringifyAny.js +6 -6
  22. package/dist/types.d.ts +8 -0
  23. package/dist-esm/error/app.error.js +3 -3
  24. package/dist-esm/error/assert.js +17 -6
  25. package/dist-esm/error/error.util.js +5 -8
  26. package/dist-esm/error/httpRequestError.js +23 -0
  27. package/dist-esm/error/jsonParseError.js +7 -0
  28. package/dist-esm/error/try.js +1 -1
  29. package/dist-esm/http/fetcher.js +36 -28
  30. package/dist-esm/index.js +2 -1
  31. package/dist-esm/promise/pTimeout.js +2 -2
  32. package/dist-esm/string/json.util.js +17 -0
  33. package/dist-esm/string/stringifyAny.js +7 -7
  34. package/package.json +1 -1
  35. package/src/error/app.error.ts +6 -6
  36. package/src/error/assert.ts +22 -9
  37. package/src/error/error.model.ts +48 -23
  38. package/src/error/error.util.ts +15 -12
  39. package/src/error/httpRequestError.ts +25 -0
  40. package/src/error/jsonParseError.ts +21 -0
  41. package/src/error/try.ts +1 -1
  42. package/src/http/fetcher.ts +42 -32
  43. package/src/http/http.model.ts +5 -0
  44. package/src/index.ts +2 -1
  45. package/src/promise/pTimeout.ts +3 -3
  46. package/src/string/json.util.ts +20 -4
  47. package/src/string/stringifyAny.ts +7 -7
  48. package/src/types.ts +11 -0
  49. package/dist/error/http.error.d.ts +0 -8
  50. package/dist/error/http.error.js +0 -13
  51. package/dist-esm/error/http.error.js +0 -9
  52. package/src/error/http.error.ts +0 -13
@@ -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 { HttpError } from '../error/http.error'
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: number,
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 = JSON.parse(text, req.jsonReviver)
248
+ res.body = _jsonParse(text, req.jsonReviver)
248
249
  } catch (err) {
249
- const { message } = _anyToError(err)
250
- res.err = new HttpError([res.signature, message].join('\n'), {
251
- httpStatusCode: 0,
252
- url: req.url,
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(res: FetcherResponse, timeout?: number): Promise<void> {
313
+ private async onNotOkResponse(
314
+ res: FetcherResponse,
315
+ started: UnixTimestampNumber,
316
+ timeout?: number,
317
+ ): Promise<void> {
306
318
  clearTimeout(timeout)
307
319
 
308
- let errObj: ErrorObject
320
+ let cause: ErrorObject | undefined
309
321
 
310
- if (res.fetchResponse) {
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
- errObj = _anyToErrorObject(body)
313
- } else if (res.err) {
314
- errObj = _errorToErrorObject(res.err)
315
- } else {
316
- errObj = {} as ErrorObject
328
+ if (body) {
329
+ cause = _anyToErrorObject(body)
330
+ }
317
331
  }
318
332
 
319
- const originalMessage = errObj.message
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
- ...errObj.data,
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)
@@ -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/http.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'
@@ -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 = {}, opt?: ErrorOptions) {
8
- super(message, data, opt, 'TimeoutError')
7
+ constructor(message: string, data = {}, cause?: ErrorObject) {
8
+ super(message, data, cause, 'TimeoutError')
9
9
  }
10
10
  }
11
11
 
@@ -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, _isHttpErrorObject, _isHttpErrorResponse } from '../error/error.util'
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 (_isHttpErrorResponse(obj)) {
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
- // Printing (0) to avoid ambiguity
108
- s = `${obj.name}(${obj.data.httpStatusCode}): ${obj.message}`
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 ||= [obj.name, obj.message].filter(Boolean).join(': ')
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
- }
@@ -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;
@@ -1,9 +0,0 @@
1
- import { AppError } from './app.error';
2
- /**
3
- * Base class for HTTP errors - errors that define HTTP error code.
4
- */
5
- export class HttpError extends AppError {
6
- constructor(message, data, opt) {
7
- super(message, data, opt, 'HttpError');
8
- }
9
- }
@@ -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
- }