@marianmeres/http-utils 1.12.0 → 1.13.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.d.ts CHANGED
@@ -90,4 +90,5 @@ export declare const HTTP_ERROR: {
90
90
  ServiceUnavailable: typeof ServiceUnavailable;
91
91
  };
92
92
  export declare const createHttpError: (code: number | string, message?: string | null, body?: string | null, cause?: any) => BadRequest | Unauthorized | Forbidden | NotFound | MethodNotAllowed | RequestTimeout | Conflict | Gone | UnprocessableContent | ImATeapot | InternalServerError | NotImplemented | BadGateway | ServiceUnavailable;
93
+ export declare const getErrorMessage: (e: any, stripErrorPrefix?: boolean) => string;
93
94
  export {};
package/dist/index.cjs CHANGED
@@ -241,6 +241,15 @@ const _wellKnownCtorMap = {
241
241
  '502': BadGateway,
242
242
  '503': ServiceUnavailable,
243
243
  };
244
+ const _maybeJsonParse = (v) => {
245
+ if (typeof v === 'string') {
246
+ try {
247
+ v = JSON.parse(v);
248
+ }
249
+ catch (e) { }
250
+ }
251
+ return v;
252
+ };
244
253
  const createHttpError = (code, message,
245
254
  // arbitrary content, typically http response body which threw this error
246
255
  // (will be JSON.parse-d if the content is a valid json string)
@@ -253,21 +262,9 @@ cause) => {
253
262
  if (isNaN(code) || !(code >= 400 && code < 600))
254
263
  code = fallback.CODE;
255
264
  // opinionated convention
256
- if (typeof body === 'string') {
257
- // prettier-ignore
258
- try {
259
- body = JSON.parse(body);
260
- }
261
- catch (e) { }
262
- }
265
+ body = _maybeJsonParse(body);
263
266
  // opinionated convention
264
- if (typeof cause === 'string') {
265
- // prettier-ignore
266
- try {
267
- cause = JSON.parse(cause);
268
- }
269
- catch (e) { }
270
- }
267
+ cause = _maybeJsonParse(cause);
271
268
  // try to find the well known one, otherwise fallback to generic
272
269
  const ctor = _wellKnownCtorMap[`${code}`] ?? HttpError;
273
270
  //
@@ -280,6 +277,40 @@ cause) => {
280
277
  e.body = body;
281
278
  return e;
282
279
  };
280
+ const getErrorMessage = (e, stripErrorPrefix = true) => {
281
+ if (!e)
282
+ return '';
283
+ // PROBLEM is that error may bubble from various sources which are not always under control
284
+ // and even if they were it still may not be trivial to keep similar structure on each error boundary...
285
+ // So, we'll just do what we can, it will not be perfect, but should handle most cases most of the time.
286
+ // Also, I'm relying on some of my own opinionated conventions as well...
287
+ const cause = _maybeJsonParse(e?.cause);
288
+ const body = _maybeJsonParse(e?.body);
289
+ let msg =
290
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause
291
+ // e.cause is the standard prop for error details, so should be considered as
292
+ // the most authoritative (if available)
293
+ // "code" and "message" are my own conventions
294
+ cause?.code ||
295
+ cause?.message ||
296
+ (typeof cause === 'string' ? cause : null) ||
297
+ // non-standard "body" is this package's HttpError prop
298
+ body?.error?.message ||
299
+ body?.message ||
300
+ (typeof body === 'string' ? body : null) ||
301
+ // the common message from Error ctor (e.g. "Foo" if new TypeError("Foo"))
302
+ e?.message ||
303
+ // the Error class name (e.g. TypeError)
304
+ e?.name ||
305
+ // this should handle (almost) everything else (mainly if e is not the Error instance)
306
+ e?.toString() ||
307
+ // very last fallback if `toString()` was not available (or returned empty)
308
+ 'Unknown Error';
309
+ if (stripErrorPrefix) {
310
+ msg = msg.replace(/^[^:]*Error: /, '');
311
+ }
312
+ return msg;
313
+ };
283
314
 
284
315
  const _fetchRaw = async ({ method, path, data = null, token = null, headers = null, signal = null, credentials, }) => {
285
316
  headers = Object.entries(headers || {}).reduce((m, [k, v]) => ({ ...m, [k.toLowerCase()]: v }), {});
@@ -405,3 +436,4 @@ exports.HTTP_ERROR = HTTP_ERROR;
405
436
  exports.HTTP_STATUS = HTTP_STATUS;
406
437
  exports.createHttpApi = createHttpApi;
407
438
  exports.createHttpError = createHttpError;
439
+ exports.getErrorMessage = getErrorMessage;
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export { HTTP_STATUS } from './status.js';
2
- export { HTTP_ERROR, createHttpError } from './error.js';
2
+ export { HTTP_ERROR, createHttpError, getErrorMessage } from './error.js';
3
3
  export { createHttpApi } from './api.js';
package/dist/index.js CHANGED
@@ -239,6 +239,15 @@ const _wellKnownCtorMap = {
239
239
  '502': BadGateway,
240
240
  '503': ServiceUnavailable,
241
241
  };
242
+ const _maybeJsonParse = (v) => {
243
+ if (typeof v === 'string') {
244
+ try {
245
+ v = JSON.parse(v);
246
+ }
247
+ catch (e) { }
248
+ }
249
+ return v;
250
+ };
242
251
  const createHttpError = (code, message,
243
252
  // arbitrary content, typically http response body which threw this error
244
253
  // (will be JSON.parse-d if the content is a valid json string)
@@ -251,21 +260,9 @@ cause) => {
251
260
  if (isNaN(code) || !(code >= 400 && code < 600))
252
261
  code = fallback.CODE;
253
262
  // opinionated convention
254
- if (typeof body === 'string') {
255
- // prettier-ignore
256
- try {
257
- body = JSON.parse(body);
258
- }
259
- catch (e) { }
260
- }
263
+ body = _maybeJsonParse(body);
261
264
  // opinionated convention
262
- if (typeof cause === 'string') {
263
- // prettier-ignore
264
- try {
265
- cause = JSON.parse(cause);
266
- }
267
- catch (e) { }
268
- }
265
+ cause = _maybeJsonParse(cause);
269
266
  // try to find the well known one, otherwise fallback to generic
270
267
  const ctor = _wellKnownCtorMap[`${code}`] ?? HttpError;
271
268
  //
@@ -278,6 +275,40 @@ cause) => {
278
275
  e.body = body;
279
276
  return e;
280
277
  };
278
+ const getErrorMessage = (e, stripErrorPrefix = true) => {
279
+ if (!e)
280
+ return '';
281
+ // PROBLEM is that error may bubble from various sources which are not always under control
282
+ // and even if they were it still may not be trivial to keep similar structure on each error boundary...
283
+ // So, we'll just do what we can, it will not be perfect, but should handle most cases most of the time.
284
+ // Also, I'm relying on some of my own opinionated conventions as well...
285
+ const cause = _maybeJsonParse(e?.cause);
286
+ const body = _maybeJsonParse(e?.body);
287
+ let msg =
288
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause
289
+ // e.cause is the standard prop for error details, so should be considered as
290
+ // the most authoritative (if available)
291
+ // "code" and "message" are my own conventions
292
+ cause?.code ||
293
+ cause?.message ||
294
+ (typeof cause === 'string' ? cause : null) ||
295
+ // non-standard "body" is this package's HttpError prop
296
+ body?.error?.message ||
297
+ body?.message ||
298
+ (typeof body === 'string' ? body : null) ||
299
+ // the common message from Error ctor (e.g. "Foo" if new TypeError("Foo"))
300
+ e?.message ||
301
+ // the Error class name (e.g. TypeError)
302
+ e?.name ||
303
+ // this should handle (almost) everything else (mainly if e is not the Error instance)
304
+ e?.toString() ||
305
+ // very last fallback if `toString()` was not available (or returned empty)
306
+ 'Unknown Error';
307
+ if (stripErrorPrefix) {
308
+ msg = msg.replace(/^[^:]*Error: /, '');
309
+ }
310
+ return msg;
311
+ };
281
312
 
282
313
  const _fetchRaw = async ({ method, path, data = null, token = null, headers = null, signal = null, credentials, }) => {
283
314
  headers = Object.entries(headers || {}).reduce((m, [k, v]) => ({ ...m, [k.toLowerCase()]: v }), {});
@@ -399,4 +430,4 @@ function createHttpApi(base, defaults, factoryErrorMessageExtractor) {
399
430
  }
400
431
  createHttpApi.defaultErrorMessageExtractor = null;
401
432
 
402
- export { HTTP_ERROR, HTTP_STATUS, createHttpApi, createHttpError };
433
+ export { HTTP_ERROR, HTTP_STATUS, createHttpApi, createHttpError, getErrorMessage };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marianmeres/http-utils",
3
- "version": "1.12.0",
3
+ "version": "1.13.0",
4
4
  "description": "Misc DRY http fetch related helpers",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",