@naturalcycles/js-lib 14.176.0 → 14.177.1

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.
@@ -246,7 +246,9 @@ class AppError extends Error {
246
246
  }
247
247
  constructor(message, data = {}, opt = {}) {
248
248
  super(message);
249
- const { name = 'AppError', cause } = opt;
249
+ // Here we default to `this.constructor.name` on Node, but to 'AppError' on the Frontend
250
+ // because Frontend tends to minify class names, so `constructor.name` is not reliable
251
+ const { name = (0, __1.isServerSide)() ? this.constructor.name : 'AppError', cause } = opt;
250
252
  Object.defineProperties(this, {
251
253
  name: {
252
254
  value: name,
@@ -15,7 +15,7 @@ export declare class Fetcher {
15
15
  *
16
16
  * Version is to be incremented every time a difference in behaviour (or a bugfix) is done.
17
17
  */
18
- static readonly VERSION = 1;
18
+ static readonly VERSION = 2;
19
19
  static readonly userAgent: string | undefined;
20
20
  private constructor();
21
21
  /**
@@ -40,7 +40,7 @@ class Fetcher {
40
40
  *
41
41
  * Version is to be incremented every time a difference in behaviour (or a bugfix) is done.
42
42
  */
43
- static { this.VERSION = 1; }
43
+ static { this.VERSION = 2; }
44
44
  static { this.userAgent = (0, env_1.isServerSide)() ? `fetcher${this.VERSION}` : undefined; }
45
45
  constructor(cfg = {}) {
46
46
  if (typeof globalThis.fetch !== 'function') {
@@ -224,7 +224,7 @@ class Fetcher {
224
224
  }
225
225
  res.statusFamily = this.getStatusFamily(res);
226
226
  res.statusCode = res.fetchResponse?.status;
227
- if (res.fetchResponse?.ok) {
227
+ if (res.fetchResponse?.ok || !req.throwHttpErrors) {
228
228
  try {
229
229
  // We are applying a separate Timeout (as long as original Timeout for now) to "download and parse the body"
230
230
  await (0, pTimeout_1.pTimeout)(async () => await this.onOkResponse(res), {
@@ -293,7 +293,7 @@ class Fetcher {
293
293
  }
294
294
  res.retryStatus.retryStopped = true;
295
295
  // res.err can happen on `failed to fetch` type of error, e.g JSON.parse, CORS, unexpected redirect
296
- if (!res.err && this.cfg.logResponse) {
296
+ if ((!res.err || !req.throwHttpErrors) && this.cfg.logResponse) {
297
297
  const { retryAttempt } = res.retryStatus;
298
298
  const { logger } = this.cfg;
299
299
  logger.log([
@@ -531,6 +531,7 @@ class Fetcher {
531
531
  redirect: cfg.redirect,
532
532
  },
533
533
  hooks: {},
534
+ throwHttpErrors: true,
534
535
  }, (0, object_util_1._omit)(cfg, ['method', 'credentials', 'headers', 'redirect', 'logger']));
535
536
  norm.init.headers = (0, object_util_1._mapKeys)(norm.init.headers, k => k.toLowerCase());
536
537
  return norm;
@@ -549,6 +550,7 @@ class Fetcher {
549
550
  'logResponse',
550
551
  'logResponseBody',
551
552
  'debug',
553
+ 'throwHttpErrors',
552
554
  ]),
553
555
  started: Date.now(),
554
556
  ...(0, object_util_1._omit)(opt, ['method', 'headers', 'credentials']),
@@ -4,7 +4,7 @@ import type { CommonLogger } from '../log/commonLogger';
4
4
  import type { Promisable } from '../typeFest';
5
5
  import type { AnyObject, NumberOfMilliseconds, Reviver, UnixTimestampMillisNumber } from '../types';
6
6
  import type { HttpMethod, HttpStatusFamily } from './http.model';
7
- export interface FetcherNormalizedCfg extends Required<FetcherCfg>, Omit<FetcherRequest, 'started' | 'fullUrl' | 'logRequest' | 'logRequestBody' | 'logResponse' | 'logResponseBody' | 'debug' | 'redirect' | 'credentials'> {
7
+ export interface FetcherNormalizedCfg extends Required<FetcherCfg>, Omit<FetcherRequest, 'started' | 'fullUrl' | 'logRequest' | 'logRequestBody' | 'logResponse' | 'logResponseBody' | 'debug' | 'redirect' | 'credentials' | 'throwHttpErrors'> {
8
8
  logger: CommonLogger;
9
9
  searchParams: Record<string, any>;
10
10
  }
@@ -67,6 +67,7 @@ export interface FetcherCfg {
67
67
  * Defaults to `console`.
68
68
  */
69
69
  logger?: CommonLogger;
70
+ throwHttpErrors?: boolean;
70
71
  }
71
72
  export interface FetcherRetryStatus {
72
73
  retryAttempt: number;
@@ -182,6 +183,11 @@ export interface FetcherOptions {
182
183
  * If provided - will be used instead of static `Fetcher.callNativeFetch`.
183
184
  */
184
185
  fetchFn?: FetchFunction;
186
+ /**
187
+ * Default to true.
188
+ * Set to false to not throw on `!Response.ok`, but simply return `Response.body` as-is (json parsed, etc).
189
+ */
190
+ throwHttpErrors?: boolean;
185
191
  }
186
192
  export type RequestInitNormalized = Omit<RequestInit, 'method' | 'headers'> & {
187
193
  method: HttpMethod;
@@ -1,4 +1,4 @@
1
- import { _jsonParseIfPossible, _stringifyAny, _truncate, _truncateMiddle } from '..';
1
+ import { _jsonParseIfPossible, _stringifyAny, _truncate, _truncateMiddle, isServerSide } from '..';
2
2
  /**
3
3
  * Useful to ensure that error in `catch (err) { ... }`
4
4
  * is indeed an Error (and not e.g `string` or `undefined`).
@@ -228,7 +228,9 @@ export class AppError extends Error {
228
228
  }
229
229
  constructor(message, data = {}, opt = {}) {
230
230
  super(message);
231
- const { name = 'AppError', cause } = opt;
231
+ // Here we default to `this.constructor.name` on Node, but to 'AppError' on the Frontend
232
+ // because Frontend tends to minify class names, so `constructor.name` is not reliable
233
+ const { name = isServerSide() ? this.constructor.name : 'AppError', cause } = opt;
232
234
  Object.defineProperties(this, {
233
235
  name: {
234
236
  value: name,
@@ -202,7 +202,7 @@ export class Fetcher {
202
202
  }
203
203
  res.statusFamily = this.getStatusFamily(res);
204
204
  res.statusCode = (_b = res.fetchResponse) === null || _b === void 0 ? void 0 : _b.status;
205
- if ((_c = res.fetchResponse) === null || _c === void 0 ? void 0 : _c.ok) {
205
+ if (((_c = res.fetchResponse) === null || _c === void 0 ? void 0 : _c.ok) || !req.throwHttpErrors) {
206
206
  try {
207
207
  // We are applying a separate Timeout (as long as original Timeout for now) to "download and parse the body"
208
208
  await pTimeout(async () => await this.onOkResponse(res), {
@@ -271,7 +271,7 @@ export class Fetcher {
271
271
  }
272
272
  res.retryStatus.retryStopped = true;
273
273
  // res.err can happen on `failed to fetch` type of error, e.g JSON.parse, CORS, unexpected redirect
274
- if (!res.err && this.cfg.logResponse) {
274
+ if ((!res.err || !req.throwHttpErrors) && this.cfg.logResponse) {
275
275
  const { retryAttempt } = res.retryStatus;
276
276
  const { logger } = this.cfg;
277
277
  logger.log([
@@ -511,6 +511,7 @@ export class Fetcher {
511
511
  redirect: cfg.redirect,
512
512
  },
513
513
  hooks: {},
514
+ throwHttpErrors: true,
514
515
  }, _omit(cfg, ['method', 'credentials', 'headers', 'redirect', 'logger']));
515
516
  norm.init.headers = _mapKeys(norm.init.headers, k => k.toLowerCase());
516
517
  return norm;
@@ -529,6 +530,7 @@ export class Fetcher {
529
530
  'logResponse',
530
531
  'logResponseBody',
531
532
  'debug',
533
+ 'throwHttpErrors',
532
534
  ])), { 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), { headers: Object.assign({}, this.cfg.init.headers), method: opt.method || this.cfg.init.method, credentials: opt.credentials || this.cfg.init.credentials, redirect: opt.redirect || this.cfg.init.redirect || 'follow' }), {
533
535
  headers: _mapKeys(opt.headers || {}, k => k.toLowerCase()),
534
536
  }) });
@@ -582,7 +584,7 @@ _a = Fetcher;
582
584
  *
583
585
  * Version is to be incremented every time a difference in behaviour (or a bugfix) is done.
584
586
  */
585
- Fetcher.VERSION = 1;
587
+ Fetcher.VERSION = 2;
586
588
  Fetcher.userAgent = isServerSide() ? `fetcher${_a.VERSION}` : undefined;
587
589
  export function getFetcher(cfg = {}) {
588
590
  return Fetcher.create(cfg);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/js-lib",
3
- "version": "14.176.0",
3
+ "version": "14.177.1",
4
4
  "scripts": {
5
5
  "prepare": "husky install",
6
6
  "build-prod": "build-prod-esm-cjs",
@@ -6,7 +6,7 @@ import type {
6
6
  HttpRequestErrorData,
7
7
  ErrorLike,
8
8
  } from '..'
9
- import { _jsonParseIfPossible, _stringifyAny, _truncate, _truncateMiddle } from '..'
9
+ import { _jsonParseIfPossible, _stringifyAny, _truncate, _truncateMiddle, isServerSide } from '..'
10
10
 
11
11
  /**
12
12
  * Useful to ensure that error in `catch (err) { ... }`
@@ -325,7 +325,9 @@ export class AppError<DATA_TYPE extends ErrorData = ErrorData> extends Error {
325
325
 
326
326
  constructor(message: string, data = {} as DATA_TYPE, opt: AppErrorOptions = {}) {
327
327
  super(message)
328
- const { name = 'AppError', cause } = opt
328
+ // Here we default to `this.constructor.name` on Node, but to 'AppError' on the Frontend
329
+ // because Frontend tends to minify class names, so `constructor.name` is not reliable
330
+ const { name = isServerSide() ? this.constructor.name : 'AppError', cause } = opt
329
331
 
330
332
  Object.defineProperties(this, {
331
333
  name: {
@@ -19,6 +19,7 @@ export interface FetcherNormalizedCfg
19
19
  | 'debug'
20
20
  | 'redirect'
21
21
  | 'credentials'
22
+ | 'throwHttpErrors'
22
23
  > {
23
24
  logger: CommonLogger
24
25
  searchParams: Record<string, any>
@@ -93,6 +94,8 @@ export interface FetcherCfg {
93
94
  * Defaults to `console`.
94
95
  */
95
96
  logger?: CommonLogger
97
+
98
+ throwHttpErrors?: boolean
96
99
  }
97
100
 
98
101
  export interface FetcherRetryStatus {
@@ -232,6 +235,12 @@ export interface FetcherOptions {
232
235
  * If provided - will be used instead of static `Fetcher.callNativeFetch`.
233
236
  */
234
237
  fetchFn?: FetchFunction
238
+
239
+ /**
240
+ * Default to true.
241
+ * Set to false to not throw on `!Response.ok`, but simply return `Response.body` as-is (json parsed, etc).
242
+ */
243
+ throwHttpErrors?: boolean
235
244
  }
236
245
 
237
246
  export type RequestInitNormalized = Omit<RequestInit, 'method' | 'headers'> & {
@@ -71,7 +71,7 @@ export class Fetcher {
71
71
  *
72
72
  * Version is to be incremented every time a difference in behaviour (or a bugfix) is done.
73
73
  */
74
- static readonly VERSION = 1
74
+ static readonly VERSION = 2
75
75
  static readonly userAgent = isServerSide() ? `fetcher${this.VERSION}` : undefined
76
76
 
77
77
  private constructor(cfg: FetcherCfg & FetcherOptions = {}) {
@@ -308,7 +308,7 @@ export class Fetcher {
308
308
  res.statusFamily = this.getStatusFamily(res)
309
309
  res.statusCode = res.fetchResponse?.status
310
310
 
311
- if (res.fetchResponse?.ok) {
311
+ if (res.fetchResponse?.ok || !req.throwHttpErrors) {
312
312
  try {
313
313
  // We are applying a separate Timeout (as long as original Timeout for now) to "download and parse the body"
314
314
  await pTimeout(
@@ -384,7 +384,7 @@ export class Fetcher {
384
384
  res.retryStatus.retryStopped = true
385
385
 
386
386
  // res.err can happen on `failed to fetch` type of error, e.g JSON.parse, CORS, unexpected redirect
387
- if (!res.err && this.cfg.logResponse) {
387
+ if ((!res.err || !req.throwHttpErrors) && this.cfg.logResponse) {
388
388
  const { retryAttempt } = res.retryStatus
389
389
  const { logger } = this.cfg
390
390
  logger.log(
@@ -654,6 +654,7 @@ export class Fetcher {
654
654
  redirect: cfg.redirect,
655
655
  },
656
656
  hooks: {},
657
+ throwHttpErrors: true,
657
658
  },
658
659
  _omit(cfg, ['method', 'credentials', 'headers', 'redirect', 'logger']),
659
660
  )
@@ -677,6 +678,7 @@ export class Fetcher {
677
678
  'logResponse',
678
679
  'logResponseBody',
679
680
  'debug',
681
+ 'throwHttpErrors',
680
682
  ]),
681
683
  started: Date.now(),
682
684
  ..._omit(opt, ['method', 'headers', 'credentials']),