@marianmeres/http-utils 2.9.0 → 2.10.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/AGENTS.md CHANGED
@@ -162,7 +162,8 @@ function getErrorMessage(e: unknown, stripErrorPrefix?: boolean): string;
162
162
  // AbortError/TimeoutError pass through untouched. Used internally by HttpApi.
163
163
  // 3rd arg is a label string OR FetchOrThrowOptions { what?, onRequest?, onError? } (pure observers; a string normalizes to { what }).
164
164
  // onRequest fires before dispatch (throw => request not sent). onError fires on every failure
165
- // with kind: "abort" | "timeout" | "network" (throw => swallowed, real error preserved).
165
+ // with { error, url, what?, kind: "abort"|"timeout"|"network", reason } (reason via getErrorMessage;
166
+ // throw => swallowed, real error preserved).
166
167
  // Global defaults (overridable per call; resolution: per-call ?? global; instruments HttpApi too):
167
168
  // fetchOrThrow.global.onRequest / fetchOrThrow.global.onError
168
169
  function fetchOrThrow(
package/API.md CHANGED
@@ -746,6 +746,8 @@ interface FetchOrThrowOptions {
746
746
  url: string;
747
747
  what?: string;
748
748
  kind: "abort" | "timeout" | "network";
749
+ /** Human-readable reason (via `getErrorMessage`); always a string. */
750
+ reason: string;
749
751
  }) => void;
750
752
  }
751
753
 
@@ -773,8 +775,8 @@ Set defaults once on `fetchOrThrow.global`; per-call options win (resolution is
773
775
  ```ts
774
776
  // app-wide defaults (also fire for every HttpApi request)
775
777
  fetchOrThrow.global.onRequest = ({ method, url }) => console.debug(`→ ${method} ${url}`);
776
- fetchOrThrow.global.onError = ({ url, kind }) =>
777
- kind !== "abort" && console.error(`✗ ${url}`);
778
+ fetchOrThrow.global.onError = ({ url, kind, reason }) =>
779
+ kind !== "abort" && console.error(`✗ ${url}: ${reason}`);
778
780
 
779
781
  // per-call object form (overrides the global onRequest for this call only)
780
782
  await fetchOrThrow(url, init, { what: "Token issuer", onRequest: () => {} });
package/README.md CHANGED
@@ -240,8 +240,8 @@ where neither a response nor an error ever arrives. Set defaults once on
240
240
  ```ts
241
241
  // app-wide defaults (also fire for every HttpApi request)
242
242
  fetchOrThrow.global.onRequest = ({ method, url }) => console.debug(`→ ${method} ${url}`);
243
- fetchOrThrow.global.onError = ({ url, kind }) =>
244
- kind !== "abort" && console.error(`✗ ${url}`); // kind: "abort" | "timeout" | "network"
243
+ fetchOrThrow.global.onError = ({ url, kind, reason }) =>
244
+ kind !== "abort" && console.error(`✗ ${url}: ${reason}`); // kind: "abort" | "timeout" | "network"
245
245
 
246
246
  // per-call override (here: silence the global tracer for one call)
247
247
  await fetchOrThrow(url, init, { what: "Token issuer", onRequest: () => {} });
package/dist/api.d.ts CHANGED
@@ -151,6 +151,14 @@ export interface FetchOrThrowOptions {
151
151
  url: string;
152
152
  what?: string;
153
153
  kind: "abort" | "timeout" | "network";
154
+ /**
155
+ * Human-readable failure reason, extracted via `getErrorMessage`. For a
156
+ * `network` failure this is the resolved transport reason embedded in the
157
+ * `NetworkError` message (e.g. `"ENOTFOUND"`); for `abort`/`timeout` it is
158
+ * the message of the original error. Always a string — handy for structured
159
+ * logging without re-parsing `error` yourself.
160
+ */
161
+ reason: string;
154
162
  }) => void;
155
163
  }
156
164
  /**
@@ -200,8 +208,8 @@ export type FetchOrThrowGlobalOptions = Pick<FetchOrThrowOptions, "onRequest" |
200
208
  *
201
209
  * // Configure tracing once, app-wide (also instruments the HttpApi client):
202
210
  * fetchOrThrow.global.onRequest = ({ method, url }) => console.debug(`→ ${method} ${url}`);
203
- * fetchOrThrow.global.onError = ({ url, kind }) =>
204
- * kind !== "abort" && console.error(`✗ ${url}`);
211
+ * fetchOrThrow.global.onError = ({ url, kind, reason }) =>
212
+ * kind !== "abort" && console.error(`✗ ${url}: ${reason}`);
205
213
  *
206
214
  * try {
207
215
  * const res = await fetchOrThrow("https://issuer.example.com/jwks", undefined, "Token issuer");
package/dist/api.js CHANGED
@@ -228,15 +228,22 @@ const _FOT_GLOBAL =
228
228
  onError: undefined,
229
229
  });
230
230
  /**
231
- * Invoke an `onError` observer defensively: `url` is only computed when a hook
232
- * is present, and a throwing hook is swallowed so it can never replace the real
233
- * error that is about to propagate.
231
+ * Invoke an `onError` observer defensively: `url` and `reason` are only computed
232
+ * when a hook is present (the network path passes its already-resolved `reason`
233
+ * to avoid a second extraction), and a throwing hook is swallowed so it can never
234
+ * replace the real error that is about to propagate.
234
235
  */
235
- function _notifyFetchError(hook, error, describe, input, what, kind) {
236
+ function _notifyFetchError(hook, error, describe, input, what, kind, reason) {
236
237
  if (!hook)
237
238
  return;
238
239
  try {
239
- hook({ error, url: describe(input), what, kind });
240
+ hook({
241
+ error,
242
+ url: describe(input),
243
+ what,
244
+ kind,
245
+ reason: reason ?? getErrorMessage(error),
246
+ });
240
247
  }
241
248
  catch {
242
249
  /* observer hooks must not alter control flow */
@@ -283,8 +290,8 @@ function _notifyFetchError(hook, error, describe, input, what, kind) {
283
290
  *
284
291
  * // Configure tracing once, app-wide (also instruments the HttpApi client):
285
292
  * fetchOrThrow.global.onRequest = ({ method, url }) => console.debug(`→ ${method} ${url}`);
286
- * fetchOrThrow.global.onError = ({ url, kind }) =>
287
- * kind !== "abort" && console.error(`✗ ${url}`);
293
+ * fetchOrThrow.global.onError = ({ url, kind, reason }) =>
294
+ * kind !== "abort" && console.error(`✗ ${url}: ${reason}`);
288
295
  *
289
296
  * try {
290
297
  * const res = await fetchOrThrow("https://issuer.example.com/jwks", undefined, "Token issuer");
@@ -332,7 +339,7 @@ export async function fetchOrThrow(input, init, what) {
332
339
  ? `${label} unreachable (${url}): ${reason}`
333
340
  : `Network request to ${url} failed: ${reason}`;
334
341
  const networkError = new NetworkError(message, { cause: underlying });
335
- _notifyFetchError(onError, networkError, () => url, input, label, kind);
342
+ _notifyFetchError(onError, networkError, () => url, input, label, kind, reason);
336
343
  throw networkError;
337
344
  }
338
345
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marianmeres/http-utils",
3
- "version": "2.9.0",
3
+ "version": "2.10.0",
4
4
  "type": "module",
5
5
  "main": "dist/mod.js",
6
6
  "types": "dist/mod.d.ts",