lifecycleion 0.0.19 → 0.0.21

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 (74) hide show
  1. package/README.md +39 -36
  2. package/dist/lib/event-emitter.cjs +195 -9
  3. package/dist/lib/event-emitter.cjs.map +1 -1
  4. package/dist/lib/event-emitter.js +195 -9
  5. package/dist/lib/event-emitter.js.map +1 -1
  6. package/dist/lib/global-event-target.cjs +217 -0
  7. package/dist/lib/global-event-target.cjs.map +1 -0
  8. package/dist/lib/global-event-target.d.cts +70 -0
  9. package/dist/lib/global-event-target.d.ts +70 -0
  10. package/dist/lib/global-event-target.js +189 -0
  11. package/dist/lib/global-event-target.js.map +1 -0
  12. package/dist/lib/http-client/index.cjs +554 -193
  13. package/dist/lib/http-client/index.cjs.map +1 -1
  14. package/dist/lib/http-client/index.d.cts +9 -3
  15. package/dist/lib/http-client/index.d.ts +9 -3
  16. package/dist/lib/http-client/index.js +554 -193
  17. package/dist/lib/http-client/index.js.map +1 -1
  18. package/dist/lib/http-client-mock/index.cjs +71 -24
  19. package/dist/lib/http-client-mock/index.cjs.map +1 -1
  20. package/dist/lib/http-client-mock/index.d.cts +50 -2
  21. package/dist/lib/http-client-mock/index.d.ts +50 -2
  22. package/dist/lib/http-client-mock/index.js +71 -24
  23. package/dist/lib/http-client-mock/index.js.map +1 -1
  24. package/dist/lib/http-client-node/index.cjs +135 -33
  25. package/dist/lib/http-client-node/index.cjs.map +1 -1
  26. package/dist/lib/http-client-node/index.d.cts +33 -2
  27. package/dist/lib/http-client-node/index.d.ts +33 -2
  28. package/dist/lib/http-client-node/index.js +135 -33
  29. package/dist/lib/http-client-node/index.js.map +1 -1
  30. package/dist/lib/http-client-xhr/index.cjs +0 -14
  31. package/dist/lib/http-client-xhr/index.cjs.map +1 -1
  32. package/dist/lib/http-client-xhr/index.d.cts +3 -2
  33. package/dist/lib/http-client-xhr/index.d.ts +3 -2
  34. package/dist/lib/http-client-xhr/index.js +0 -14
  35. package/dist/lib/http-client-xhr/index.js.map +1 -1
  36. package/dist/lib/lifecycle-manager/index.cjs +199 -13
  37. package/dist/lib/lifecycle-manager/index.cjs.map +1 -1
  38. package/dist/lib/lifecycle-manager/index.js +199 -13
  39. package/dist/lib/lifecycle-manager/index.js.map +1 -1
  40. package/dist/lib/logger/index.cjs +203 -21
  41. package/dist/lib/logger/index.cjs.map +1 -1
  42. package/dist/lib/logger/index.d.cts +5 -1
  43. package/dist/lib/logger/index.d.ts +5 -1
  44. package/dist/lib/logger/index.js +203 -21
  45. package/dist/lib/logger/index.js.map +1 -1
  46. package/dist/lib/lru-cache/index.cjs +195 -9
  47. package/dist/lib/lru-cache/index.cjs.map +1 -1
  48. package/dist/lib/lru-cache/index.js +195 -9
  49. package/dist/lib/lru-cache/index.js.map +1 -1
  50. package/dist/lib/process-signal-manager.cjs +199 -13
  51. package/dist/lib/process-signal-manager.cjs.map +1 -1
  52. package/dist/lib/process-signal-manager.js +199 -13
  53. package/dist/lib/process-signal-manager.js.map +1 -1
  54. package/dist/lib/promise-protected-resolver.cjs +195 -9
  55. package/dist/lib/promise-protected-resolver.cjs.map +1 -1
  56. package/dist/lib/promise-protected-resolver.js +195 -9
  57. package/dist/lib/promise-protected-resolver.js.map +1 -1
  58. package/dist/lib/retry-utils/index.cjs +195 -9
  59. package/dist/lib/retry-utils/index.cjs.map +1 -1
  60. package/dist/lib/retry-utils/index.js +195 -9
  61. package/dist/lib/retry-utils/index.js.map +1 -1
  62. package/dist/lib/safe-handle-callback.cjs +196 -18
  63. package/dist/lib/safe-handle-callback.cjs.map +1 -1
  64. package/dist/lib/safe-handle-callback.d.cts +14 -4
  65. package/dist/lib/safe-handle-callback.d.ts +14 -4
  66. package/dist/lib/safe-handle-callback.js +196 -18
  67. package/dist/lib/safe-handle-callback.js.map +1 -1
  68. package/dist/lib/single-event-observer.cjs +195 -9
  69. package/dist/lib/single-event-observer.cjs.map +1 -1
  70. package/dist/lib/single-event-observer.js +195 -9
  71. package/dist/lib/single-event-observer.js.map +1 -1
  72. package/dist/{types-CWw885iO.d.cts → types-BFvpJPMt.d.cts} +72 -11
  73. package/dist/{types-Mso0dYOS.d.ts → types-BONtIhQ5.d.ts} +72 -11
  74. package/package.json +31 -12
@@ -1181,18 +1181,204 @@ function isFunction(value) {
1181
1181
  return typeof value === "function" || value instanceof Function;
1182
1182
  }
1183
1183
 
1184
+ // src/lib/global-event-target.ts
1185
+ var GLOBAL_KEY = "__lifecycleion_global_event_target__";
1186
+ var METHOD_NAMES = [
1187
+ "addEventListener",
1188
+ "removeEventListener",
1189
+ "dispatchEvent"
1190
+ ];
1191
+ var g = globalThis;
1192
+ function getState() {
1193
+ const value = readGlobal(GLOBAL_KEY);
1194
+ return value === UNREADABLE ? void 0 : asUsableState(value);
1195
+ }
1196
+ function asUsableState(value) {
1197
+ if (typeof value !== "object" || value === null) {
1198
+ return void 0;
1199
+ }
1200
+ return asUsableTarget(readMember(value, "target")) === null ? void 0 : value;
1201
+ }
1202
+ function asUsableTarget(value) {
1203
+ if (typeof value !== "object" || value === null) {
1204
+ return null;
1205
+ }
1206
+ for (const name of METHOD_NAMES) {
1207
+ if (typeof readMember(value, name) !== "function") {
1208
+ return null;
1209
+ }
1210
+ }
1211
+ return value;
1212
+ }
1213
+ function bindTargetMethods(target) {
1214
+ const bound = {};
1215
+ for (const name of METHOD_NAMES) {
1216
+ const method = readMember(target, name);
1217
+ if (typeof method !== "function") {
1218
+ return null;
1219
+ }
1220
+ let boundMethod;
1221
+ try {
1222
+ boundMethod = method.bind(target);
1223
+ } catch {
1224
+ return null;
1225
+ }
1226
+ if (typeof boundMethod !== "function") {
1227
+ return null;
1228
+ }
1229
+ bound[name] = boundMethod;
1230
+ }
1231
+ return bound;
1232
+ }
1233
+ function isStateInstalled(state) {
1234
+ return state !== void 0 && readMember(state, "isInstalled") === true;
1235
+ }
1236
+ function readStateTarget(state) {
1237
+ if (state === void 0) {
1238
+ return null;
1239
+ }
1240
+ return asUsableTarget(readMember(state, "target"));
1241
+ }
1242
+ var UNREADABLE = /* @__PURE__ */ Symbol("lifecycleion.unreadable");
1243
+ function readGlobal(name) {
1244
+ try {
1245
+ return g[name];
1246
+ } catch {
1247
+ return UNREADABLE;
1248
+ }
1249
+ }
1250
+ function readMember(source, key) {
1251
+ try {
1252
+ return source[key];
1253
+ } catch {
1254
+ return UNREADABLE;
1255
+ }
1256
+ }
1257
+ function probeMember(name) {
1258
+ const value = readGlobal(name);
1259
+ if (value === UNREADABLE) {
1260
+ return "hostile";
1261
+ }
1262
+ if (typeof value === "function") {
1263
+ return "usable";
1264
+ }
1265
+ return value === void 0 ? "absent" : "occupied";
1266
+ }
1267
+ function canDefineProperty(key) {
1268
+ const descriptor = Object.getOwnPropertyDescriptor(g, key);
1269
+ if (descriptor === void 0) {
1270
+ return Object.isExtensible(g);
1271
+ }
1272
+ return descriptor.configurable === true;
1273
+ }
1274
+ function installGlobalEventTarget() {
1275
+ const members = METHOD_NAMES.map((name) => probeMember(name));
1276
+ if (members.every((member) => member === "usable")) {
1277
+ return isStateInstalled(getState()) ? "already-installed" : "native";
1278
+ }
1279
+ if (members.some((member) => member !== "absent")) {
1280
+ return "partial";
1281
+ }
1282
+ const eventTargetConstructor = readGlobal("EventTarget");
1283
+ if (typeof eventTargetConstructor !== "function") {
1284
+ return "unsupported";
1285
+ }
1286
+ const isDefinable = [...METHOD_NAMES, GLOBAL_KEY].every(
1287
+ (key) => canDefineProperty(key)
1288
+ );
1289
+ if (!isDefinable) {
1290
+ return "blocked";
1291
+ }
1292
+ const existingState = getState();
1293
+ const defined = [];
1294
+ const priorStateDescriptor = Object.getOwnPropertyDescriptor(g, GLOBAL_KEY);
1295
+ const rollback = () => {
1296
+ for (const key of defined) {
1297
+ if (key === GLOBAL_KEY && priorStateDescriptor !== void 0) {
1298
+ try {
1299
+ Object.defineProperty(g, GLOBAL_KEY, priorStateDescriptor);
1300
+ } catch {
1301
+ }
1302
+ continue;
1303
+ }
1304
+ try {
1305
+ Reflect.deleteProperty(g, key);
1306
+ } catch {
1307
+ }
1308
+ }
1309
+ };
1310
+ const reusableTarget = readStateTarget(existingState);
1311
+ const reusableMethods = reusableTarget === null ? null : bindTargetMethods(reusableTarget);
1312
+ let state;
1313
+ let methods;
1314
+ try {
1315
+ if (existingState === void 0 || reusableMethods === null) {
1316
+ let target;
1317
+ try {
1318
+ target = new eventTargetConstructor();
1319
+ } catch {
1320
+ return "unsupported";
1321
+ }
1322
+ const freshMethods = bindTargetMethods(target);
1323
+ if (freshMethods === null) {
1324
+ return "unsupported";
1325
+ }
1326
+ state = { target, isInstalled: false };
1327
+ methods = freshMethods;
1328
+ Object.defineProperty(g, GLOBAL_KEY, {
1329
+ value: state,
1330
+ enumerable: false,
1331
+ writable: false,
1332
+ configurable: true
1333
+ });
1334
+ defined.push(GLOBAL_KEY);
1335
+ } else {
1336
+ state = existingState;
1337
+ methods = reusableMethods;
1338
+ }
1339
+ for (const name of METHOD_NAMES) {
1340
+ Object.defineProperty(g, name, {
1341
+ value: methods[name],
1342
+ enumerable: false,
1343
+ writable: true,
1344
+ configurable: true
1345
+ });
1346
+ defined.push(name);
1347
+ }
1348
+ if (readMember(state, "isInstalled") !== true) {
1349
+ state.isInstalled = true;
1350
+ }
1351
+ } catch {
1352
+ rollback();
1353
+ return "blocked";
1354
+ }
1355
+ return "installed";
1356
+ }
1357
+ function isGlobalEventTargetAvailable() {
1358
+ return METHOD_NAMES.every((name) => probeMember(name) === "usable") && probeMember("ErrorEvent") === "usable";
1359
+ }
1360
+
1184
1361
  // src/lib/safe-handle-callback.ts
1362
+ installGlobalEventTarget();
1363
+ function reportCallbackError(callbackName, error) {
1364
+ installGlobalEventTarget();
1365
+ if (!isGlobalEventTargetAvailable()) {
1366
+ return;
1367
+ }
1368
+ try {
1369
+ globalThis.dispatchEvent(
1370
+ new ErrorEvent("reportError", {
1371
+ error: new Error(
1372
+ `Error in a callback ${callbackName}: ${DOUBLE_EOL}${errorToString(error)}`
1373
+ )
1374
+ })
1375
+ );
1376
+ } catch {
1377
+ }
1378
+ }
1185
1379
  async function safeHandleCallbackAndWait(callbackName, callback, ...args) {
1186
1380
  const handleError = (error) => {
1187
- if (typeof globalThis.dispatchEvent === "function") {
1188
- globalThis.dispatchEvent(
1189
- new ErrorEvent("reportError", {
1190
- error: new Error(
1191
- `Error in a callback ${callbackName}: ${DOUBLE_EOL}${errorToString(error)}`
1192
- )
1193
- })
1194
- );
1195
- }
1381
+ reportCallbackError(callbackName, error);
1196
1382
  return { success: false, error };
1197
1383
  };
1198
1384
  if (isFunction(callback)) {
@@ -1957,6 +2143,74 @@ function matchesFilter(filter, context, phaseType, kind) {
1957
2143
  return true;
1958
2144
  }
1959
2145
 
2146
+ // src/lib/http-client/internal/tls-error-utils.ts
2147
+ var CERT_ERROR_CODES = /* @__PURE__ */ new Set([
2148
+ "UNABLE_TO_VERIFY_LEAF_SIGNATURE",
2149
+ "CERT_HAS_EXPIRED",
2150
+ "DEPTH_ZERO_SELF_SIGNED_CERT",
2151
+ "ERR_TLS_CERT_ALTNAME_INVALID",
2152
+ "ERR_SSL_TLSV13_ALERT_CERTIFICATE_REQUIRED",
2153
+ "ERR_SSL_PEER_DID_NOT_RETURN_A_CERTIFICATE",
2154
+ "SELF_SIGNED_CERT_IN_CHAIN",
2155
+ "UNABLE_TO_GET_ISSUER_CERT_LOCALLY",
2156
+ "CERT_REVOKED"
2157
+ ]);
2158
+ var CRL_CODE_PATTERN = /(?:^|_)CRLS?(?:_|$)/;
2159
+ var TRANSPORT_ERROR_CODES = /* @__PURE__ */ new Set([
2160
+ "ENOTFOUND",
2161
+ "EAI_AGAIN",
2162
+ "ECONNREFUSED",
2163
+ "ECONNRESET",
2164
+ "ECONNABORTED",
2165
+ "ETIMEDOUT",
2166
+ "EPIPE",
2167
+ "EHOSTUNREACH",
2168
+ "EHOSTDOWN",
2169
+ "ENETUNREACH",
2170
+ "ENETDOWN",
2171
+ "EADDRNOTAVAIL"
2172
+ ]);
2173
+ var UNDICI_TRANSPORT_ERROR_PREFIX = "UND_ERR_";
2174
+ function isTLSCertificateError(error) {
2175
+ if (isTLSCertificateErrorSelf(error)) {
2176
+ return true;
2177
+ }
2178
+ const cause = readMember2(error, "cause");
2179
+ return isErrorValue(cause) ? isTLSCertificateErrorSelf(cause) : false;
2180
+ }
2181
+ function isErrorValue(value) {
2182
+ try {
2183
+ return value instanceof Error;
2184
+ } catch {
2185
+ return false;
2186
+ }
2187
+ }
2188
+ function isTLSCertificateErrorSelf(error) {
2189
+ const rawCode = readMember2(error, "code");
2190
+ const code = typeof rawCode === "string" ? rawCode : "";
2191
+ if (CERT_ERROR_CODES.has(code)) {
2192
+ return true;
2193
+ }
2194
+ if (CRL_CODE_PATTERN.test(code)) {
2195
+ return true;
2196
+ }
2197
+ if ((code.startsWith("ERR_TLS_") || code.startsWith("ERR_SSL_")) && code.includes("CERT")) {
2198
+ return true;
2199
+ }
2200
+ if (TRANSPORT_ERROR_CODES.has(code) || code.startsWith(UNDICI_TRANSPORT_ERROR_PREFIX)) {
2201
+ return false;
2202
+ }
2203
+ const message = readMember2(error, "message");
2204
+ return typeof message === "string" ? /certificate|self signed|unable to verify|altname/i.test(message) : false;
2205
+ }
2206
+ function readMember2(error, key) {
2207
+ try {
2208
+ return error[key];
2209
+ } catch {
2210
+ return void 0;
2211
+ }
2212
+ }
2213
+
1960
2214
  // src/lib/http-client/consts.ts
1961
2215
  var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([
1962
2216
  // 0: Browser/XHR-style "no response" status.
@@ -1992,6 +2246,7 @@ var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([
1992
2246
  // 599 Network Connect Timeout Error (non-standard)
1993
2247
  599
1994
2248
  ]);
2249
+ var NON_IDEMPOTENT_METHODS = /* @__PURE__ */ new Set(["POST", "PATCH"]);
1995
2250
  var DEFAULT_TIMEOUT_MS = 3e4;
1996
2251
  var DEFAULT_REQUEST_ID_HEADER = "x-local-client-request-id";
1997
2252
  var DEFAULT_REQUEST_ATTEMPT_HEADER = "x-local-client-request-attempt";
@@ -2077,12 +2332,23 @@ var FetchAdapter = class {
2077
2332
  if (isAbortError(error) || signal?.aborted) {
2078
2333
  throw error;
2079
2334
  }
2335
+ const normalizedError = normalizeError(error);
2336
+ if (isTLSCertificateError(normalizedError)) {
2337
+ return {
2338
+ status: 495,
2339
+ isTransportError: true,
2340
+ isRetryable: false,
2341
+ headers: {},
2342
+ body: null,
2343
+ errorCause: normalizedError
2344
+ };
2345
+ }
2080
2346
  return {
2081
2347
  status: 0,
2082
2348
  isTransportError: true,
2083
2349
  headers: {},
2084
2350
  body: null,
2085
- errorCause: error instanceof Error ? error : new Error(String(error))
2351
+ errorCause: normalizedError
2086
2352
  };
2087
2353
  }
2088
2354
  if (response.type === "opaqueredirect") {
@@ -2096,13 +2362,43 @@ var FetchAdapter = class {
2096
2362
  };
2097
2363
  }
2098
2364
  request.onUploadProgress?.({ loaded: 1, total: 1, progress: 1 });
2099
- const rawBody = await readResponseBody(method, response);
2365
+ const responseHeadersForBody = extractFetchHeaders(response.headers);
2366
+ let rawBody;
2367
+ try {
2368
+ rawBody = await readResponseBody(method, response);
2369
+ } catch (error) {
2370
+ if (isAbortError(error) || signal?.aborted) {
2371
+ throw markResponseStreamAbort(
2372
+ error,
2373
+ response.status,
2374
+ responseHeadersForBody
2375
+ );
2376
+ }
2377
+ const detectedRedirectURL2 = resolveDetectedRedirectURL(
2378
+ requestURL,
2379
+ response.status,
2380
+ responseHeadersForBody
2381
+ );
2382
+ return {
2383
+ status: response.status,
2384
+ wasRedirectDetected: detectedRedirectURL2 !== void 0 || REDIRECT_STATUS_CODES.has(response.status),
2385
+ ...detectedRedirectURL2 ? { detectedRedirectURL: detectedRedirectURL2 } : {},
2386
+ headers: responseHeadersForBody,
2387
+ body: null,
2388
+ isStreamError: true,
2389
+ // fetch buffers the body for us, so there is no per-chunk delivery to
2390
+ // distinguish a local write failure from an upstream stream failure.
2391
+ // Everything reaching here is an upstream/transfer failure.
2392
+ streamErrorCode: "stream_response_error",
2393
+ errorCause: normalizeError(error)
2394
+ };
2395
+ }
2100
2396
  request.onDownloadProgress?.({
2101
2397
  loaded: rawBody?.length ?? 0,
2102
2398
  total: rawBody?.length ?? 0,
2103
2399
  progress: 1
2104
2400
  });
2105
- const responseHeaders = extractFetchHeaders(response.headers);
2401
+ const responseHeaders = responseHeadersForBody;
2106
2402
  const detectedRedirectURL = resolveDetectedRedirectURL(
2107
2403
  requestURL,
2108
2404
  response.status,
@@ -2127,7 +2423,33 @@ async function readResponseBody(method, response) {
2127
2423
  return new Uint8Array(buffer);
2128
2424
  }
2129
2425
  function isAbortError(error) {
2130
- return error instanceof Error && error.name === "AbortError";
2426
+ const normalized = asError(error);
2427
+ return normalized !== void 0 && readObjectMember(normalized, "name") === "AbortError";
2428
+ }
2429
+ function asError(value) {
2430
+ try {
2431
+ return value instanceof Error ? value : void 0;
2432
+ } catch {
2433
+ return void 0;
2434
+ }
2435
+ }
2436
+ function normalizeError(value) {
2437
+ const existing = asError(value);
2438
+ if (existing !== void 0) {
2439
+ return existing;
2440
+ }
2441
+ try {
2442
+ return new Error(String(value));
2443
+ } catch {
2444
+ return new Error("Unknown error");
2445
+ }
2446
+ }
2447
+ function readObjectMember(source, key) {
2448
+ try {
2449
+ return source[key];
2450
+ } catch {
2451
+ return void 0;
2452
+ }
2131
2453
  }
2132
2454
  function materializeFetchHeaders(headers) {
2133
2455
  let shouldUseHeadersObject = false;
@@ -2156,6 +2478,22 @@ function materializeFetchHeaders(headers) {
2156
2478
  }
2157
2479
  return materialized;
2158
2480
  }
2481
+ function markResponseStreamAbort(error, status, headers) {
2482
+ const original = asError(error);
2483
+ const originalMessage = original === void 0 ? void 0 : readObjectMember(original, "message");
2484
+ const originalName = original === void 0 ? void 0 : readObjectMember(original, "name");
2485
+ const tagged = new Error(
2486
+ typeof originalMessage === "string" ? originalMessage : "Request aborted"
2487
+ );
2488
+ tagged.name = typeof originalName === "string" ? originalName : "AbortError";
2489
+ Object.assign(tagged, {
2490
+ [RESPONSE_STREAM_ABORT_FLAG]: true,
2491
+ streamAbortStatus: status,
2492
+ streamAbortHeaders: headers,
2493
+ cause: error
2494
+ });
2495
+ return tagged;
2496
+ }
2159
2497
 
2160
2498
  // src/lib/http-client/internal/header-utils.ts
2161
2499
  function isBrowserRestrictedHeader(key, value) {
@@ -2315,6 +2653,7 @@ var HTTPRequestBuilder = class {
2315
2653
  _timeout;
2316
2654
  _signal;
2317
2655
  _retryPolicy;
2656
+ _retryNonIdempotentMethods;
2318
2657
  _label;
2319
2658
  _onUploadProgress;
2320
2659
  _onDownloadProgress;
@@ -2399,6 +2738,15 @@ var HTTPRequestBuilder = class {
2399
2738
  this._retryPolicy = options;
2400
2739
  return this;
2401
2740
  }
2741
+ /**
2742
+ * Allow or forbid retrying this request when its method is not idempotent
2743
+ * (`POST`, `PATCH`). Overrides the client config for this request only.
2744
+ */
2745
+ retryNonIdempotentMethods(allow) {
2746
+ this._assertNotSent("retryNonIdempotentMethods");
2747
+ this._retryNonIdempotentMethods = allow;
2748
+ return this;
2749
+ }
2402
2750
  onUploadProgress(fn) {
2403
2751
  this._assertNotSent("onUploadProgress");
2404
2752
  this._onUploadProgress = fn;
@@ -2527,6 +2875,7 @@ var HTTPRequestBuilder = class {
2527
2875
  timeout: this._timeout,
2528
2876
  signal: this._signal,
2529
2877
  retryPolicy: this._retryPolicy,
2878
+ retryNonIdempotentMethods: this._retryNonIdempotentMethods,
2530
2879
  label: this._label,
2531
2880
  onUploadProgress: this._onUploadProgress,
2532
2881
  onDownloadProgress: this._onDownloadProgress,
@@ -2586,6 +2935,9 @@ var HTTPRequestBuilder = class {
2586
2935
  if (opts.retryPolicy !== void 0) {
2587
2936
  this.retryPolicy(opts.retryPolicy);
2588
2937
  }
2938
+ if (opts.retryNonIdempotentMethods !== void 0) {
2939
+ this.retryNonIdempotentMethods(opts.retryNonIdempotentMethods);
2940
+ }
2589
2941
  if (opts.label !== void 0) {
2590
2942
  this.label(opts.label);
2591
2943
  }
@@ -2784,6 +3136,7 @@ var BaseHTTPClient = class {
2784
3136
  timeout: config.timeout ?? DEFAULT_TIMEOUT_MS,
2785
3137
  cookieJar: config.cookieJar,
2786
3138
  retryPolicy: config.retryPolicy,
3139
+ retryNonIdempotentMethods: config.retryNonIdempotentMethods ?? false,
2787
3140
  includeRequestID: config.includeRequestID ?? false,
2788
3141
  includeAttemptHeader: config.includeAttemptHeader ?? false,
2789
3142
  userAgent: config.userAgent,
@@ -3063,7 +3416,7 @@ var BaseHTTPClient = class {
3063
3416
  requestID,
3064
3417
  false,
3065
3418
  "interceptor_error",
3066
- error instanceof Error ? error : new Error(String(error))
3419
+ normalizeError2(error)
3067
3420
  );
3068
3421
  callbacks.setError(normalizedError);
3069
3422
  trackedCallbacks.setState("failed");
@@ -3168,7 +3521,14 @@ var BaseHTTPClient = class {
3168
3521
  body: null
3169
3522
  },
3170
3523
  requestID,
3524
+ // Provably false: a cancel settles with no adapter response, and
3525
+ // this branch is guarded on having one.
3171
3526
  wasCancelled: false,
3527
+ // Hardcoded even when a per-attempt timeout struck mid-body. The
3528
+ // request ends at the redirect either way, so `redirect_disabled`
3529
+ // is the outcome the caller acts on; surfacing the timeout would
3530
+ // reclassify the error code on whether the body happened to
3531
+ // finish. See docs/http-client.md.
3172
3532
  wasTimeout: false,
3173
3533
  adapterType: this._adapter.getType(),
3174
3534
  initialURL: finalRequest.requestURL,
@@ -3179,7 +3539,7 @@ var BaseHTTPClient = class {
3179
3539
  errorCode = "redirect_disabled";
3180
3540
  break;
3181
3541
  }
3182
- if (this._config.followRedirects && adapterResponse && REDIRECT_STATUS_CODES.has(adapterResponse.status)) {
3542
+ if (this._config.followRedirects && adapterResponse && !adapterResponse.isStreamError && REDIRECT_STATUS_CODES.has(adapterResponse.status)) {
3183
3543
  hopCount++;
3184
3544
  if (hopCount > this._config.maxRedirects) {
3185
3545
  response = this._buildResponse({
@@ -3294,7 +3654,7 @@ var BaseHTTPClient = class {
3294
3654
  isNetworkErrorOverride: false
3295
3655
  });
3296
3656
  errorCode = "interceptor_error";
3297
- adapterCause = error instanceof Error ? error : new Error(String(error));
3657
+ adapterCause = normalizeError2(error);
3298
3658
  break;
3299
3659
  }
3300
3660
  if ("cancel" in redirectIntercept) {
@@ -3372,7 +3732,7 @@ var BaseHTTPClient = class {
3372
3732
  requestID,
3373
3733
  false,
3374
3734
  "request_setup_error",
3375
- error instanceof Error ? error : new Error(String(error))
3735
+ normalizeError2(error)
3376
3736
  );
3377
3737
  callbacks.setAttemptCount(completedAttemptCount);
3378
3738
  callbacks.setNextRetryDelayMS(null);
@@ -3509,11 +3869,28 @@ var BaseHTTPClient = class {
3509
3869
  const startAttempt = params.startAttemptNumber ?? 1;
3510
3870
  const redirectHistory = params.redirectHistory ?? [];
3511
3871
  const cookieJar = params.cookieJar ?? null;
3872
+ const isRetryAvailable = () => policy !== null && policy.errors.length < policy.maxRetryAttempts;
3873
+ const allowNonIdempotentRetry = options.retryNonIdempotentMethods ?? this._config.retryNonIdempotentMethods;
3512
3874
  let attemptNumber = startAttempt - 1;
3513
3875
  let isRetriesExhausted = false;
3514
3876
  while (true) {
3515
3877
  attemptNumber++;
3516
3878
  const isRetry = attemptNumber > startAttempt;
3879
+ const emitAttemptEnd = (outcome) => {
3880
+ options.onAttemptEnd?.({
3881
+ attemptNumber,
3882
+ isRetry,
3883
+ nextRetryDelayMS: void 0,
3884
+ nextRetryAt: void 0,
3885
+ ...outcome,
3886
+ requestID,
3887
+ initialURL,
3888
+ ...hopContext ? {
3889
+ hopNumber: hopContext.hopNumber,
3890
+ redirect: hopContext.redirect
3891
+ } : {}
3892
+ });
3893
+ };
3517
3894
  if (attemptNumber === 1) {
3518
3895
  callbacks.setStartedAt(Date.now());
3519
3896
  } else {
@@ -3575,19 +3952,11 @@ var BaseHTTPClient = class {
3575
3952
  }
3576
3953
  } catch (error) {
3577
3954
  clearTimeout(timeoutID);
3578
- options.onAttemptEnd?.({
3579
- attemptNumber,
3580
- isRetry,
3955
+ emitAttemptEnd({
3581
3956
  willRetry: false,
3582
3957
  nextRetryDelayMS: void 0,
3583
3958
  nextRetryAt: void 0,
3584
- status: 0,
3585
- requestID,
3586
- initialURL,
3587
- ...hopContext ? {
3588
- hopNumber: hopContext.hopNumber,
3589
- redirect: hopContext.redirect
3590
- } : {}
3959
+ status: 0
3591
3960
  });
3592
3961
  return {
3593
3962
  adapterResponse: null,
@@ -3601,24 +3970,16 @@ var BaseHTTPClient = class {
3601
3970
  wasTimeout: false,
3602
3971
  isRetriesExhausted: false,
3603
3972
  errorCode: "interceptor_error",
3604
- adapterCause: error instanceof Error ? error : new Error(String(error))
3973
+ adapterCause: normalizeError2(error)
3605
3974
  };
3606
3975
  }
3607
3976
  if ("cancel" in retryIntercept) {
3608
3977
  clearTimeout(timeoutID);
3609
- options.onAttemptEnd?.({
3610
- attemptNumber,
3611
- isRetry,
3978
+ emitAttemptEnd({
3612
3979
  willRetry: false,
3613
3980
  nextRetryDelayMS: void 0,
3614
3981
  nextRetryAt: void 0,
3615
- status: 0,
3616
- requestID,
3617
- initialURL,
3618
- ...hopContext ? {
3619
- hopNumber: hopContext.hopNumber,
3620
- redirect: hopContext.redirect
3621
- } : {}
3982
+ status: 0
3622
3983
  });
3623
3984
  return {
3624
3985
  adapterResponse: null,
@@ -3691,19 +4052,11 @@ var BaseHTTPClient = class {
3691
4052
  );
3692
4053
  }
3693
4054
  if (adapterResponse.wasRedirectDetected && adapterResponse.status === 0 && !this._config.followRedirects) {
3694
- options.onAttemptEnd?.({
3695
- attemptNumber,
3696
- isRetry,
4055
+ emitAttemptEnd({
3697
4056
  willRetry: false,
3698
4057
  nextRetryDelayMS: void 0,
3699
4058
  nextRetryAt: void 0,
3700
- status: 0,
3701
- requestID,
3702
- initialURL,
3703
- ...hopContext ? {
3704
- hopNumber: hopContext.hopNumber,
3705
- redirect: hopContext.redirect
3706
- } : {}
4059
+ status: 0
3707
4060
  });
3708
4061
  return {
3709
4062
  adapterResponse,
@@ -3715,7 +4068,10 @@ var BaseHTTPClient = class {
3715
4068
  errorCode: "redirect_disabled"
3716
4069
  };
3717
4070
  }
3718
- if (policy && adapterResponse.isRetryable !== false && !adapterResponse.isStreamError && RETRYABLE_STATUS_CODES.has(adapterResponse.status) && !cancelSignal.aborted) {
4071
+ const isTransportOutcome = adapterResponse.isTransportError === true;
4072
+ const isMethodReplayable = allowNonIdempotentRetry || !NON_IDEMPOTENT_METHODS.has(sentRequest.method) || isTransportOutcome && adapterResponse.wasDefinitelyNotSent === true;
4073
+ const retrySuppressedReason = isRetryAvailable() && RETRYABLE_STATUS_CODES.has(adapterResponse.status) && !cancelSignal.aborted ? adapterResponse.isRetryable === false ? "adapter_veto" : adapterResponse.isStreamError ? "stream_error" : !isMethodReplayable ? "non_idempotent_method" : void 0 : void 0;
4074
+ if (policy && adapterResponse.isRetryable !== false && !adapterResponse.isStreamError && isMethodReplayable && RETRYABLE_STATUS_CODES.has(adapterResponse.status) && !cancelSignal.aborted) {
3719
4075
  const { shouldRetry, delayMS } = policy.shouldRetry(
3720
4076
  new Error(`HTTP ${adapterResponse.status}`)
3721
4077
  );
@@ -3725,19 +4081,11 @@ var BaseHTTPClient = class {
3725
4081
  callbacks.setNextRetryAt(nextRetryAt ?? null);
3726
4082
  callbacks.setState("waiting_for_retry");
3727
4083
  }
3728
- options.onAttemptEnd?.({
3729
- attemptNumber,
3730
- isRetry,
4084
+ emitAttemptEnd({
3731
4085
  willRetry: shouldRetry,
3732
4086
  nextRetryDelayMS: shouldRetry ? delayMS : void 0,
3733
4087
  nextRetryAt,
3734
- status: adapterResponse.status,
3735
- requestID,
3736
- initialURL,
3737
- ...hopContext ? {
3738
- hopNumber: hopContext.hopNumber,
3739
- redirect: hopContext.redirect
3740
- } : {}
4088
+ status: adapterResponse.status
3741
4089
  });
3742
4090
  if (shouldRetry) {
3743
4091
  const retryHTTPResponse = this._buildResponse({
@@ -3776,22 +4124,18 @@ var BaseHTTPClient = class {
3776
4124
  }
3777
4125
  isRetriesExhausted = true;
3778
4126
  } else {
3779
- options.onAttemptEnd?.({
3780
- attemptNumber,
3781
- isRetry,
4127
+ emitAttemptEnd({
3782
4128
  willRetry: false,
4129
+ ...retrySuppressedReason ? { retrySuppressedReason } : {},
3783
4130
  nextRetryDelayMS: void 0,
3784
4131
  nextRetryAt: void 0,
3785
- status: adapterResponse.status,
3786
- requestID,
3787
- initialURL,
3788
- ...hopContext ? {
3789
- hopNumber: hopContext.hopNumber,
3790
- redirect: hopContext.redirect
3791
- } : {}
4132
+ status: adapterResponse.status
3792
4133
  });
3793
4134
  }
3794
- const responseCause = adapterResponse.errorCause instanceof Error ? adapterResponse.errorCause : void 0;
4135
+ const responseCauseValue = adapterResponse.errorCause;
4136
+ const responseCause = asErrorValue(
4137
+ responseCauseValue
4138
+ ) ? responseCauseValue : void 0;
3795
4139
  const streamErrorCode = adapterResponse.isStreamError ? adapterResponse.streamErrorCode ?? "stream_write_error" : void 0;
3796
4140
  return {
3797
4141
  adapterResponse,
@@ -3805,20 +4149,19 @@ var BaseHTTPClient = class {
3805
4149
  };
3806
4150
  } catch (error) {
3807
4151
  clearTimeout(timeoutID);
4152
+ const abortedResponse = isResponseStreamAbortError(error) ? getResponseStreamAbortInfo(error) : void 0;
4153
+ if (cookieJar && abortedResponse) {
4154
+ cookieJar.processResponseHeaders(
4155
+ abortedResponse.headers,
4156
+ sentRequest.requestURL
4157
+ );
4158
+ }
3808
4159
  if (cancelSignal.aborted && !isAbortError2(error)) {
3809
- options.onAttemptEnd?.({
3810
- attemptNumber,
3811
- isRetry,
4160
+ emitAttemptEnd({
3812
4161
  willRetry: false,
3813
4162
  nextRetryDelayMS: void 0,
3814
4163
  nextRetryAt: void 0,
3815
- status: 0,
3816
- requestID,
3817
- initialURL,
3818
- ...hopContext ? {
3819
- hopNumber: hopContext.hopNumber,
3820
- redirect: hopContext.redirect
3821
- } : {}
4164
+ status: 0
3822
4165
  });
3823
4166
  const signalReason = getSignalCancelReason(cancelSignal);
3824
4167
  return {
@@ -3831,21 +4174,26 @@ var BaseHTTPClient = class {
3831
4174
  ...signalReason !== void 0 ? { cancelReason: signalReason } : {}
3832
4175
  };
3833
4176
  }
3834
- if (isAbortError2(error) && isResponseStreamAbortError(error)) {
4177
+ if (isResponseStreamAbortError(error)) {
4178
+ const streamCause = normalizeError2(error);
4179
+ const streamSuppressionReason = (status) => isRetryAvailable() && RETRYABLE_STATUS_CODES.has(status) && !cancelSignal.aborted ? "stream_error" : void 0;
4180
+ const redirectFieldsFor = (status, headers) => {
4181
+ const detectedRedirectURL = resolveDetectedRedirectURL(
4182
+ sentRequest.requestURL,
4183
+ status,
4184
+ headers
4185
+ );
4186
+ return {
4187
+ wasRedirectDetected: detectedRedirectURL !== void 0 || REDIRECT_STATUS_CODES.has(status),
4188
+ ...detectedRedirectURL ? { detectedRedirectURL } : {}
4189
+ };
4190
+ };
3835
4191
  if (cancelSignal.aborted) {
3836
- options.onAttemptEnd?.({
3837
- attemptNumber,
3838
- isRetry,
4192
+ emitAttemptEnd({
3839
4193
  willRetry: false,
3840
4194
  nextRetryDelayMS: void 0,
3841
4195
  nextRetryAt: void 0,
3842
- status: 0,
3843
- requestID,
3844
- initialURL,
3845
- ...hopContext ? {
3846
- hopNumber: hopContext.hopNumber,
3847
- redirect: hopContext.redirect
3848
- } : {}
4196
+ status: 0
3849
4197
  });
3850
4198
  const signalReason = getSignalCancelReason(cancelSignal);
3851
4199
  return {
@@ -3862,30 +4210,29 @@ var BaseHTTPClient = class {
3862
4210
  ...signalReason !== void 0 ? { cancelReason: signalReason } : {}
3863
4211
  };
3864
4212
  }
3865
- const streamedAbort = getResponseStreamAbortInfo(error);
3866
- if (isTimedOut && streamedAbort) {
3867
- options.onAttemptEnd?.({
3868
- attemptNumber,
3869
- isRetry,
4213
+ if (isTimedOut && abortedResponse) {
4214
+ const suppressedReason = streamSuppressionReason(
4215
+ abortedResponse.status
4216
+ );
4217
+ emitAttemptEnd({
3870
4218
  willRetry: false,
4219
+ ...suppressedReason ? { retrySuppressedReason: suppressedReason } : {},
3871
4220
  nextRetryDelayMS: void 0,
3872
4221
  nextRetryAt: void 0,
3873
- status: streamedAbort.status,
3874
- requestID,
3875
- initialURL,
3876
- ...hopContext ? {
3877
- hopNumber: hopContext.hopNumber,
3878
- redirect: hopContext.redirect
3879
- } : {}
4222
+ status: abortedResponse.status
3880
4223
  });
3881
4224
  return {
3882
4225
  adapterResponse: {
3883
- status: streamedAbort.status,
3884
- headers: streamedAbort.headers,
4226
+ status: abortedResponse.status,
4227
+ ...redirectFieldsFor(
4228
+ abortedResponse.status,
4229
+ abortedResponse.headers
4230
+ ),
4231
+ headers: abortedResponse.headers,
3885
4232
  body: null,
3886
4233
  isStreamError: true,
3887
4234
  streamErrorCode: "stream_response_error",
3888
- errorCause: error,
4235
+ errorCause: streamCause,
3889
4236
  effectiveRequestHeaders: getEffectiveRequestHeadersFromError(error)
3890
4237
  },
3891
4238
  sentRequest: sentRequestForObservedAdapterError(
@@ -3898,31 +4245,30 @@ var BaseHTTPClient = class {
3898
4245
  wasTimeout: true,
3899
4246
  isRetriesExhausted: false,
3900
4247
  errorCode: "stream_response_error",
3901
- adapterCause: error
4248
+ adapterCause: streamCause
3902
4249
  };
3903
4250
  }
3904
- options.onAttemptEnd?.({
3905
- attemptNumber,
3906
- isRetry,
4251
+ const fallbackSuppressedReason = streamSuppressionReason(
4252
+ abortedResponse?.status ?? 0
4253
+ );
4254
+ emitAttemptEnd({
3907
4255
  willRetry: false,
4256
+ ...fallbackSuppressedReason ? { retrySuppressedReason: fallbackSuppressedReason } : {},
3908
4257
  nextRetryDelayMS: void 0,
3909
4258
  nextRetryAt: void 0,
3910
- status: streamedAbort?.status ?? 0,
3911
- requestID,
3912
- initialURL,
3913
- ...hopContext ? {
3914
- hopNumber: hopContext.hopNumber,
3915
- redirect: hopContext.redirect
3916
- } : {}
4259
+ status: abortedResponse?.status ?? 0
3917
4260
  });
4261
+ const fallbackStatus = abortedResponse?.status ?? 0;
4262
+ const fallbackHeaders = abortedResponse?.headers ?? {};
3918
4263
  return {
3919
4264
  adapterResponse: {
3920
- status: streamedAbort?.status ?? 0,
3921
- headers: streamedAbort?.headers ?? {},
4265
+ status: fallbackStatus,
4266
+ ...redirectFieldsFor(fallbackStatus, fallbackHeaders),
4267
+ headers: fallbackHeaders,
3922
4268
  body: null,
3923
4269
  isStreamError: true,
3924
4270
  streamErrorCode: "stream_response_error",
3925
- errorCause: error,
4271
+ errorCause: streamCause,
3926
4272
  effectiveRequestHeaders: getEffectiveRequestHeadersFromError(error)
3927
4273
  },
3928
4274
  sentRequest: sentRequestForObservedAdapterError(
@@ -3935,24 +4281,16 @@ var BaseHTTPClient = class {
3935
4281
  wasTimeout: isTimedOut,
3936
4282
  isRetriesExhausted: false,
3937
4283
  errorCode: "stream_response_error",
3938
- adapterCause: error
4284
+ adapterCause: streamCause
3939
4285
  };
3940
4286
  }
3941
4287
  if (isAbortError2(error)) {
3942
4288
  if (cancelSignal.aborted) {
3943
- options.onAttemptEnd?.({
3944
- attemptNumber,
3945
- isRetry,
4289
+ emitAttemptEnd({
3946
4290
  willRetry: false,
3947
4291
  nextRetryDelayMS: void 0,
3948
4292
  nextRetryAt: void 0,
3949
- status: 0,
3950
- requestID,
3951
- initialURL,
3952
- ...hopContext ? {
3953
- hopNumber: hopContext.hopNumber,
3954
- redirect: hopContext.redirect
3955
- } : {}
4293
+ status: 0
3956
4294
  });
3957
4295
  const signalReason = getSignalCancelReason(cancelSignal);
3958
4296
  return {
@@ -3969,21 +4307,16 @@ var BaseHTTPClient = class {
3969
4307
  if (isXHRBrowserTimeout(error)) {
3970
4308
  isTimedOut = true;
3971
4309
  } else {
3972
- const factoryCancelValue = error !== null && typeof error === "object" && STREAM_FACTORY_CANCEL_KEY in error ? error[STREAM_FACTORY_CANCEL_KEY] : void 0;
4310
+ const factoryCancelValue = readObjectMember2(
4311
+ error,
4312
+ STREAM_FACTORY_CANCEL_KEY
4313
+ );
3973
4314
  const factoryCancelReason = typeof factoryCancelValue === "string" ? factoryCancelValue : void 0;
3974
- options.onAttemptEnd?.({
3975
- attemptNumber,
3976
- isRetry,
4315
+ emitAttemptEnd({
3977
4316
  willRetry: false,
3978
4317
  nextRetryDelayMS: void 0,
3979
4318
  nextRetryAt: void 0,
3980
- status: 0,
3981
- requestID,
3982
- initialURL,
3983
- ...hopContext ? {
3984
- hopNumber: hopContext.hopNumber,
3985
- redirect: hopContext.redirect
3986
- } : {}
4319
+ status: 0
3987
4320
  });
3988
4321
  return {
3989
4322
  adapterResponse: null,
@@ -4000,19 +4333,11 @@ var BaseHTTPClient = class {
4000
4333
  const didTimeoutThisAttempt = isAbortError2(error) && isTimedOut;
4001
4334
  const isNonRetryableClientCallbackFailure = isNonRetryableClientCallbackError(error);
4002
4335
  if (isNonRetryableClientCallbackFailure) {
4003
- options.onAttemptEnd?.({
4004
- attemptNumber,
4005
- isRetry,
4336
+ emitAttemptEnd({
4006
4337
  willRetry: false,
4007
4338
  nextRetryDelayMS: void 0,
4008
4339
  nextRetryAt: void 0,
4009
- status: 0,
4010
- requestID,
4011
- initialURL,
4012
- ...hopContext ? {
4013
- hopNumber: hopContext.hopNumber,
4014
- redirect: hopContext.redirect
4015
- } : {}
4340
+ status: 0
4016
4341
  });
4017
4342
  const isStreamFactoryError = isStreamFactoryClientCallbackError(error);
4018
4343
  return {
@@ -4027,12 +4352,12 @@ var BaseHTTPClient = class {
4027
4352
  wasTimeout: didTimeoutThisAttempt,
4028
4353
  isRetriesExhausted: false,
4029
4354
  errorCode: isStreamFactoryError ? "stream_setup_error" : "interceptor_error",
4030
- adapterCause: error instanceof Error ? error : new Error(String(error))
4355
+ adapterCause: normalizeError2(error)
4031
4356
  };
4032
4357
  }
4033
- if (policy && !cancelSignal.aborted) {
4358
+ if (policy && !cancelSignal.aborted && (allowNonIdempotentRetry || !NON_IDEMPOTENT_METHODS.has(sentRequest.method))) {
4034
4359
  const { shouldRetry, delayMS } = policy.shouldRetry(
4035
- error instanceof Error ? error : new Error(String(error))
4360
+ normalizeError2(error)
4036
4361
  );
4037
4362
  const nextRetryAt = shouldRetry ? Date.now() + delayMS : void 0;
4038
4363
  if (shouldRetry) {
@@ -4040,19 +4365,11 @@ var BaseHTTPClient = class {
4040
4365
  callbacks.setNextRetryAt(nextRetryAt ?? null);
4041
4366
  callbacks.setState("waiting_for_retry");
4042
4367
  }
4043
- options.onAttemptEnd?.({
4044
- attemptNumber,
4045
- isRetry,
4368
+ emitAttemptEnd({
4046
4369
  willRetry: shouldRetry,
4047
4370
  nextRetryDelayMS: shouldRetry ? delayMS : void 0,
4048
4371
  nextRetryAt,
4049
- status: 0,
4050
- requestID,
4051
- initialURL,
4052
- ...hopContext ? {
4053
- hopNumber: hopContext.hopNumber,
4054
- redirect: hopContext.redirect
4055
- } : {}
4372
+ status: 0
4056
4373
  });
4057
4374
  if (shouldRetry) {
4058
4375
  const failedAttemptResponse = this._buildResponse({
@@ -4071,7 +4388,7 @@ var BaseHTTPClient = class {
4071
4388
  requestID,
4072
4389
  false,
4073
4390
  "adapter_error",
4074
- error instanceof Error ? error : new Error(String(error))
4391
+ normalizeError2(error)
4075
4392
  );
4076
4393
  await this._runErrorObservers(
4077
4394
  retryError,
@@ -4099,19 +4416,13 @@ var BaseHTTPClient = class {
4099
4416
  }
4100
4417
  isRetriesExhausted = true;
4101
4418
  } else {
4102
- options.onAttemptEnd?.({
4103
- attemptNumber,
4104
- isRetry,
4419
+ const isSuppressedByMethod = isRetryAvailable() && !cancelSignal.aborted && !allowNonIdempotentRetry && NON_IDEMPOTENT_METHODS.has(sentRequest.method);
4420
+ emitAttemptEnd({
4105
4421
  willRetry: false,
4422
+ ...isSuppressedByMethod ? { retrySuppressedReason: "non_idempotent_method" } : {},
4106
4423
  nextRetryDelayMS: void 0,
4107
4424
  nextRetryAt: void 0,
4108
- status: 0,
4109
- requestID,
4110
- initialURL,
4111
- ...hopContext ? {
4112
- hopNumber: hopContext.hopNumber,
4113
- redirect: hopContext.redirect
4114
- } : {}
4425
+ status: 0
4115
4426
  });
4116
4427
  }
4117
4428
  return {
@@ -4122,7 +4433,7 @@ var BaseHTTPClient = class {
4122
4433
  wasTimeout: didTimeoutThisAttempt,
4123
4434
  isRetriesExhausted,
4124
4435
  errorCode: "adapter_error",
4125
- adapterCause: error instanceof Error ? error : new Error(String(error))
4436
+ adapterCause: normalizeError2(error)
4126
4437
  };
4127
4438
  }
4128
4439
  }
@@ -4492,7 +4803,7 @@ var BaseHTTPClient = class {
4492
4803
  return AbortSignal.any([a, b]);
4493
4804
  }
4494
4805
  const controller = new AbortController();
4495
- const abort = (signal) => controller.abort(signal.reason);
4806
+ const abort = (signal) => controller.abort(readObjectMember2(signal, "reason"));
4496
4807
  if (a.aborted) {
4497
4808
  abort(a);
4498
4809
  } else if (b.aborted) {
@@ -4576,7 +4887,24 @@ function cloneBodyValue(body) {
4576
4887
  return body;
4577
4888
  }
4578
4889
  function isAbortError2(err) {
4579
- return err instanceof Error && err.name === "AbortError";
4890
+ return asErrorValue(err) && readObjectMember2(err, "name") === "AbortError";
4891
+ }
4892
+ function asErrorValue(value) {
4893
+ try {
4894
+ return value instanceof Error;
4895
+ } catch {
4896
+ return false;
4897
+ }
4898
+ }
4899
+ function normalizeError2(value) {
4900
+ if (asErrorValue(value)) {
4901
+ return value;
4902
+ }
4903
+ try {
4904
+ return new Error(String(value));
4905
+ } catch {
4906
+ return new Error("Unknown error");
4907
+ }
4580
4908
  }
4581
4909
  function sentRequestForNonRetryableAdapterCallbackError(sentRequest, error, observedAfterAdapterResolve) {
4582
4910
  return sentRequestForObservedAdapterError(
@@ -4586,12 +4914,10 @@ function sentRequestForNonRetryableAdapterCallbackError(sentRequest, error, obse
4586
4914
  );
4587
4915
  }
4588
4916
  function isNonRetryableClientCallbackError(err) {
4589
- return Boolean(
4590
- err && typeof err === "object" && NON_RETRYABLE_HTTP_CLIENT_CALLBACK_ERROR_FLAG in err && err[NON_RETRYABLE_HTTP_CLIENT_CALLBACK_ERROR_FLAG] === true
4591
- );
4917
+ return readObjectMember2(err, NON_RETRYABLE_HTTP_CLIENT_CALLBACK_ERROR_FLAG) === true;
4592
4918
  }
4593
4919
  function isStreamFactoryClientCallbackError(err) {
4594
- return err !== null && typeof err === "object" && STREAM_FACTORY_ERROR_FLAG in err;
4920
+ return readObjectMember2(err, STREAM_FACTORY_ERROR_FLAG) === true;
4595
4921
  }
4596
4922
  function sentRequestForObservedAdapterError(sentRequest, error, observedAfterAdapterResolve) {
4597
4923
  const eff = getEffectiveRequestHeadersFromError(error);
@@ -4604,24 +4930,58 @@ function sentRequestForObservedAdapterError(sentRequest, error, observedAfterAda
4604
4930
  };
4605
4931
  }
4606
4932
  function getEffectiveRequestHeadersFromError(error) {
4607
- if (error && typeof error === "object" && "effectiveRequestHeaders" in error && error.effectiveRequestHeaders) {
4608
- return error.effectiveRequestHeaders;
4933
+ return snapshotHeaderRecord(
4934
+ readObjectMember2(error, "effectiveRequestHeaders")
4935
+ );
4936
+ }
4937
+ function readObjectMember2(source, key) {
4938
+ if (typeof source !== "object" && typeof source !== "function" || source === null) {
4939
+ return void 0;
4940
+ }
4941
+ try {
4942
+ return source[key];
4943
+ } catch {
4944
+ return void 0;
4609
4945
  }
4610
- return void 0;
4946
+ }
4947
+ function snapshotHeaderRecord(value) {
4948
+ if (typeof value !== "object" || value === null) {
4949
+ return void 0;
4950
+ }
4951
+ try {
4952
+ const snapshot = {};
4953
+ for (const [name, headerValue] of Object.entries(value)) {
4954
+ if (typeof headerValue === "string") {
4955
+ snapshot[name] = headerValue;
4956
+ } else if (Array.isArray(headerValue) && headerValue.every((item) => typeof item === "string")) {
4957
+ snapshot[name] = [...headerValue];
4958
+ } else {
4959
+ return void 0;
4960
+ }
4961
+ }
4962
+ return snapshot;
4963
+ } catch {
4964
+ return void 0;
4965
+ }
4966
+ }
4967
+ function hasAdapterMarker(err, flag) {
4968
+ return readObjectMember2(err, flag) === true;
4611
4969
  }
4612
4970
  function isResponseStreamAbortError(err) {
4613
- return err !== null && typeof err === "object" && RESPONSE_STREAM_ABORT_FLAG in err;
4971
+ return hasAdapterMarker(err, RESPONSE_STREAM_ABORT_FLAG);
4614
4972
  }
4615
4973
  function isXHRBrowserTimeout(err) {
4616
- return err !== null && typeof err === "object" && XHR_BROWSER_TIMEOUT_FLAG in err;
4974
+ return hasAdapterMarker(err, XHR_BROWSER_TIMEOUT_FLAG);
4617
4975
  }
4618
4976
  function getResponseStreamAbortInfo(err) {
4619
- if (!err || typeof err !== "object" || !("streamAbortStatus" in err) || !("streamAbortHeaders" in err)) {
4977
+ const status = readObjectMember2(err, "streamAbortStatus");
4978
+ if (typeof status !== "number") {
4620
4979
  return void 0;
4621
4980
  }
4622
- const status = err.streamAbortStatus;
4623
- const headers = err.streamAbortHeaders;
4624
- if (typeof status !== "number" || !headers || typeof headers !== "object") {
4981
+ const headers = snapshotHeaderRecord(
4982
+ readObjectMember2(err, "streamAbortHeaders")
4983
+ );
4984
+ if (headers === void 0) {
4625
4985
  return void 0;
4626
4986
  }
4627
4987
  return {
@@ -4630,7 +4990,8 @@ function getResponseStreamAbortInfo(err) {
4630
4990
  };
4631
4991
  }
4632
4992
  function getSignalCancelReason(signal) {
4633
- return typeof signal.reason === "string" ? signal.reason : void 0;
4993
+ const reason = readObjectMember2(signal, "reason");
4994
+ return typeof reason === "string" ? reason : void 0;
4634
4995
  }
4635
4996
 
4636
4997
  // src/lib/http-client/cookie-jar.ts