lifecycleion 0.0.8 → 0.0.10

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 (48) hide show
  1. package/README.md +45 -36
  2. package/dist/lib/domain-utils/domain-utils.cjs +1154 -0
  3. package/dist/lib/domain-utils/domain-utils.cjs.map +1 -0
  4. package/dist/lib/domain-utils/domain-utils.d.cts +210 -0
  5. package/dist/lib/domain-utils/domain-utils.d.ts +210 -0
  6. package/dist/lib/domain-utils/domain-utils.js +1112 -0
  7. package/dist/lib/domain-utils/domain-utils.js.map +1 -0
  8. package/dist/lib/http-client/index.cjs +5254 -0
  9. package/dist/lib/http-client/index.cjs.map +1 -0
  10. package/dist/lib/http-client/index.d.cts +372 -0
  11. package/dist/lib/http-client/index.d.ts +372 -0
  12. package/dist/lib/http-client/index.js +5207 -0
  13. package/dist/lib/http-client/index.js.map +1 -0
  14. package/dist/lib/http-client-mock/index.cjs +525 -0
  15. package/dist/lib/http-client-mock/index.cjs.map +1 -0
  16. package/dist/lib/http-client-mock/index.d.cts +129 -0
  17. package/dist/lib/http-client-mock/index.d.ts +129 -0
  18. package/dist/lib/http-client-mock/index.js +488 -0
  19. package/dist/lib/http-client-mock/index.js.map +1 -0
  20. package/dist/lib/http-client-node/index.cjs +1112 -0
  21. package/dist/lib/http-client-node/index.cjs.map +1 -0
  22. package/dist/lib/http-client-node/index.d.cts +43 -0
  23. package/dist/lib/http-client-node/index.d.ts +43 -0
  24. package/dist/lib/http-client-node/index.js +1075 -0
  25. package/dist/lib/http-client-node/index.js.map +1 -0
  26. package/dist/lib/http-client-xhr/index.cjs +323 -0
  27. package/dist/lib/http-client-xhr/index.cjs.map +1 -0
  28. package/dist/lib/http-client-xhr/index.d.cts +23 -0
  29. package/dist/lib/http-client-xhr/index.d.ts +23 -0
  30. package/dist/lib/http-client-xhr/index.js +286 -0
  31. package/dist/lib/http-client-xhr/index.js.map +1 -0
  32. package/dist/lib/lifecycle-manager/index.cjs +118 -61
  33. package/dist/lib/lifecycle-manager/index.cjs.map +1 -1
  34. package/dist/lib/lifecycle-manager/index.js +118 -61
  35. package/dist/lib/lifecycle-manager/index.js.map +1 -1
  36. package/dist/lib/lru-cache/index.cjs +274 -0
  37. package/dist/lib/lru-cache/index.cjs.map +1 -0
  38. package/dist/lib/lru-cache/index.d.cts +84 -0
  39. package/dist/lib/lru-cache/index.d.ts +84 -0
  40. package/dist/lib/lru-cache/index.js +249 -0
  41. package/dist/lib/lru-cache/index.js.map +1 -0
  42. package/dist/lib/retry-utils/index.d.cts +3 -23
  43. package/dist/lib/retry-utils/index.d.ts +3 -23
  44. package/dist/types-CUPvmYQ8.d.cts +868 -0
  45. package/dist/types-D_MywcG0.d.cts +23 -0
  46. package/dist/types-D_MywcG0.d.ts +23 -0
  47. package/dist/types-Hw2PUTIT.d.ts +868 -0
  48. package/package.json +45 -3
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/lib/http-client/index.ts","../../../src/lib/id-helpers.ts","../../../src/lib/unix-time-helpers.ts","../../../src/lib/deep-clone.ts","../../../src/lib/strings.ts","../../../src/lib/retry-utils/lib/retry-utils-errors.ts","../../../src/lib/clamp.ts","../../../src/lib/retry-utils/lib/utils.ts","../../../src/lib/retry-utils/lib/retry-policy.ts","../../../src/lib/constants.ts","../../../src/lib/padding-utils.ts","../../../src/lib/ascii-tables/ascii-table-utils.ts","../../../src/lib/ascii-tables/multi-column-ascii-table.ts","../../../src/lib/ascii-tables/key-value-ascii-table.ts","../../../src/lib/error-to-string.ts","../../../src/lib/is-promise.ts","../../../src/lib/is-function.ts","../../../src/lib/safe-handle-callback.ts","../../../src/lib/http-client/utils.ts","../../../src/lib/domain-utils/domain-utils.ts","../../../src/lib/domain-utils/helpers.ts","../../../src/lib/http-client/consts.ts","../../../src/lib/http-client/adapters/fetch-adapter.ts","../../../src/lib/http-client/internal/header-utils.ts","../../../src/lib/http-client/request-tracker.ts","../../../src/lib/http-client/http-request-builder.ts","../../../src/lib/http-client/interceptors.ts","../../../src/lib/http-client/observers.ts","../../../src/lib/http-client/http-client.ts","../../../src/lib/http-client/cookie-jar.ts"],"sourcesContent":["export { HTTPClient } from './http-client';\nexport type { HTTPSubClient } from './http-client';\nexport { HTTPRequestBuilder } from './http-request-builder';\nexport { CookieJar } from './cookie-jar';\nexport { FetchAdapter } from './adapters/fetch-adapter';\n\nexport type {\n HTTPAdapter,\n AdapterType,\n AdapterRequest,\n AdapterResponse,\n HTTPMethod,\n ContentType,\n QueryValue,\n QueryObject,\n HTTPClientConfig,\n SubClientConfig,\n HTTPRequestOptions,\n HTTPResponse,\n ErrorCode,\n HTTPClientError,\n HTTPProgressEvent,\n AttemptStartEvent,\n AttemptEndEvent,\n RequestInterceptorFilter,\n ErrorObserverFilter,\n ResponseObserverFilter,\n RequestInterceptor,\n RequestInterceptorContext,\n InterceptorCancel,\n ResponseObserver,\n ErrorObserver,\n InterceptedRequest,\n AttemptRequest,\n RequestPhase,\n RequestPhaseName,\n InterceptorPhaseName,\n ResponseObserverPhaseName,\n ErrorObserverPhaseName,\n InterceptorPhase,\n ResponseObserverPhase,\n ErrorObserverPhase,\n RedirectHopInfo,\n RequestState,\n // Streaming types — needed to type a StreamResponseFactory function\n WritableLike,\n StreamResponseInfo,\n StreamResponseContext,\n StreamResponseCancel,\n StreamResponseFactory,\n} from './types';\n\nexport type { Cookie, CookieInput, CookieJarJSON } from './cookie-jar';\nexport type { RequestInfo } from './request-tracker';\n\nexport {\n RETRYABLE_STATUS_CODES,\n DEFAULT_TIMEOUT_MS,\n DEFAULT_REQUEST_ID_HEADER,\n DEFAULT_REQUEST_ATTEMPT_HEADER,\n DEFAULT_USER_AGENT,\n HTTP_METHODS,\n BROWSER_RESTRICTED_HEADERS,\n BROWSER_RESTRICTED_HEADER_PREFIXES,\n BROWSER_METHOD_OVERRIDE_HEADER_NAMES,\n BROWSER_FORBIDDEN_METHOD_OVERRIDE_VALUES,\n DEFAULT_MAX_REDIRECTS,\n REDIRECT_STATUS_CODES,\n} from './consts';\n","import ObjectID from 'bson-objectid';\nimport {\n v4 as UUIDv4,\n v7 as UUIDv7,\n validate as uuidValidate,\n version as uuidVersion,\n} from 'uuid';\nimport { ulid } from 'ulid';\nimport { convertMSToUnix } from './unix-time-helpers';\n\n/**\n * Supported identifier types:\n *\n * - **`objectID`**: MongoDB-style ObjectID\n * - Format: 24 hexadecimal characters\n * - Timestamp-based: Yes (sortable by creation time)\n * - Case-sensitive: No (accepts both uppercase and lowercase)\n * - Example: `\"507f1f77bcf86cd799439011\"`\n *\n * - **`uuid4`**: UUID version 4\n * - Format: 36 characters (32 hex + 4 dashes): `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`\n * - Timestamp-based: No (random)\n * - Case-sensitive: No (accepts both uppercase and lowercase)\n * - Example: `\"9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d\"`\n *\n * - **`uuid7`**: UUID version 7\n * - Format: 36 characters (32 hex + 4 dashes): `xxxxxxxx-xxxx-7xxx-yxxx-xxxxxxxxxxxx`\n * - Timestamp-based: Yes (sortable by creation time)\n * - Case-sensitive: No (accepts both uppercase and lowercase)\n * - Example: `\"018e8c6e-4f7e-7000-8000-0123456789ab\"`\n *\n * - **`ulid`**: Universally Unique Lexicographically Sortable Identifier\n * - Format: 26 characters using Crockford's base32 alphabet\n * - Timestamp-based: Yes (sortable by creation time)\n * - Case-sensitive: No (canonical form is uppercase, but accepts lowercase)\n * - Example: `\"01ARZ3NDEKTSV4RRFFQ69G5FAV\"`\n */\nexport type IdentifierType = 'objectID' | 'uuid4' | 'uuid7' | 'ulid';\n\n/**\n * Array of all supported identifier types.\n */\nexport const IDENTIFIER_TYPES = ['objectID', 'uuid4', 'uuid7', 'ulid'] as const;\n\nfunction assertIdentifierType(type: unknown): asserts type is IdentifierType {\n if (!IDENTIFIER_TYPES.includes(type as IdentifierType)) {\n throw new TypeError(\n `Invalid ID type given: \"${type as string}\". Expected one of: ${IDENTIFIER_TYPES.join(', ')}`,\n );\n }\n}\n\n/**\n * Generates a unique identifier of the specified type.\n *\n * @param type - The type of identifier to generate:\n * - `objectID`: MongoDB ObjectID (24 hex chars, timestamp-based)\n * - `uuid4`: UUID v4 (random, not sortable)\n * - `uuid7`: UUID v7 (timestamp-based, sortable)\n * - `ulid`: ULID (timestamp-based, sortable, case-insensitive)\n * @param seedTime - Optional timestamp in milliseconds to seed the ID with.\n * - Supported by: `objectID`, `uuid7`, `ulid`\n * - Ignored by: `uuid4` (always random)\n * - Use this for testing or when you need IDs to have a specific timestamp\n * @returns A unique identifier string\n * @throws {TypeError} If an invalid type is provided\n * @throws {TypeError} If `seedTime` is provided but is not a non-negative finite number\n *\n * @example\n * ```typescript\n * // Generate random IDs\n * const objId = generateID('objectID'); // \"507f1f77bcf86cd799439011\"\n * const uuid4 = generateID('uuid4'); // \"9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d\"\n * const uuid7 = generateID('uuid7'); // \"018e8c6e-4f7e-7000-8000-0123456789ab\"\n * const ulid = generateID('ulid'); // \"01ARZ3NDEKTSV4RRFFQ69G5FAV\"\n *\n * // Generate IDs with a specific timestamp\n * const timestamp = Date.now();\n * const seededId = generateID('uuid7', timestamp);\n * ```\n */\nexport function generateID(type: IdentifierType, seedTime?: number): string {\n assertIdentifierType(type);\n\n if (seedTime !== undefined && (!Number.isFinite(seedTime) || seedTime < 0)) {\n throw new TypeError(\n `seedTime must be a non-negative finite number (milliseconds), got: ${seedTime}`,\n );\n }\n\n if (type === 'objectID') {\n if (seedTime !== undefined) {\n // expects as unix time\n const unixTime = convertMSToUnix(seedTime);\n\n return new ObjectID(unixTime).toHexString();\n } else {\n return new ObjectID().toHexString();\n }\n } else if (type === 'uuid4') {\n return UUIDv4();\n } else if (type === 'uuid7') {\n if (seedTime !== undefined) {\n // expect in milliseconds\n return UUIDv7({ msecs: seedTime });\n } else {\n return UUIDv7();\n }\n } else if (type === 'ulid') {\n if (seedTime !== undefined) {\n // expect in milliseconds\n return ulid(seedTime);\n } else {\n return ulid();\n }\n } else {\n throw new TypeError(`Unhandled identifier type: \"${type as string}\"`);\n }\n}\n\n/**\n * Validates that a string is a valid identifier of the specified type.\n *\n * Performs strict validation:\n * - `objectID`: Must be 24 hexadecimal characters\n * - `uuid4`: Must be a valid UUID with version 4\n * - `uuid7`: Must be a valid UUID with version 7\n * - `ulid`: Must be 26 characters from the ULID character set\n *\n * Empty IDs (from `emptyID()`) are considered valid.\n * Non-string `id` values return `false`.\n *\n * @param type - The expected identifier type\n * @param id - The identifier string to validate\n * @returns `true` if the ID is valid for the specified type, `false` otherwise\n * @throws {TypeError} If an invalid type is provided\n *\n * @example\n * ```typescript\n * validateID('uuid4', '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'); // true\n * validateID('uuid4', '018e8c6e-4f7e-7000-8000-0123456789ab'); // false (this is uuid7)\n * validateID('objectID', '507f1f77bcf86cd799439011'); // true\n * validateID('objectID', 'invalid'); // false\n * ```\n */\nexport function validateID(type: IdentifierType, id: string): boolean {\n assertIdentifierType(type);\n\n if (typeof id !== 'string') {\n return false;\n }\n\n if (type === 'objectID') {\n if (id.match(/^[0-9a-fA-F]{24}$/)) {\n return true;\n } else {\n return false;\n }\n } else if (type === 'uuid4' || type === 'uuid7') {\n // Check if it's the empty ID first\n if (isEmptyID(type, id)) {\n return true;\n }\n\n const isValid = uuidValidate(id);\n if (!isValid) {\n return false;\n }\n\n // Check the specific UUID version\n const version = uuidVersion(id);\n if (type === 'uuid4' && version === 4) {\n return true;\n } else if (type === 'uuid7' && version === 7) {\n return true;\n } else {\n return false;\n }\n } else if (type === 'ulid') {\n if (id.match(/^[0-7][0-9A-HJKMNP-TV-Z]{25}$/i)) {\n return true;\n } else {\n return false;\n }\n } else {\n throw new TypeError(`Unhandled identifier type: \"${type as string}\"`);\n }\n}\n\n/**\n * Returns an empty/null identifier for the specified type.\n *\n * Empty IDs are valid IDs (pass `validateID()`) but represent a null/empty state.\n * Useful as default values or placeholders in databases.\n *\n * Empty ID formats:\n * - `objectID`: `\"000000000000000000000000\"` (24 zeros)\n * - `uuid4`: `\"00000000-0000-0000-0000-000000000000\"` (nil UUID)\n * - `uuid7`: `\"00000000-0000-0000-0000-000000000000\"` (nil UUID)\n * - `ulid`: `\"00000000000000000000000000\"` (26 zeros)\n *\n * @param type - The type of empty identifier to generate\n * @returns An empty identifier string\n * @throws {TypeError} If an invalid type is provided\n *\n * @example\n * ```typescript\n * const emptyUuid = emptyID('uuid4'); // \"00000000-0000-0000-0000-000000000000\"\n * validateID('uuid4', emptyUuid); // true\n * isEmptyID('uuid4', emptyUuid); // true\n * ```\n */\nexport function emptyID(type: IdentifierType): string {\n assertIdentifierType(type);\n\n if (type === 'objectID') {\n return '0'.repeat(24);\n } else if (type === 'uuid4' || type === 'uuid7') {\n return '00000000-0000-0000-0000-000000000000';\n } else if (type === 'ulid') {\n return '0'.repeat(26);\n } else {\n throw new TypeError(`Unhandled identifier type: \"${type as string}\"`);\n }\n}\n\n/**\n * Checks if an identifier is an empty/null ID.\n *\n * Compares the provided ID against the empty ID for the specified type.\n * This is useful for checking if an ID represents a null/empty state.\n *\n * @param type - The identifier type to check against\n * @param id - The identifier string to check\n * @returns `true` if the ID is empty for the specified type, `false` otherwise.\n * Non-string `id` values return `false`.\n * @throws {TypeError} If an invalid type is provided\n *\n * @example\n * ```typescript\n * const emptyUuid = emptyID('uuid4');\n * const realUuid = generateID('uuid4');\n *\n * isEmptyID('uuid4', emptyUuid); // true\n * isEmptyID('uuid4', realUuid); // false\n * ```\n */\nexport function isEmptyID(type: IdentifierType, id: string): boolean {\n assertIdentifierType(type);\n\n if (typeof id !== 'string') {\n return false;\n }\n\n return emptyID(type) === id;\n}\n\n/**\n * Helper class for working with identifiers of a specific type.\n *\n * This class provides a convenient way to work with IDs without repeatedly\n * specifying the type parameter. Initialize it with your preferred ID type,\n * then use its methods without passing the type each time.\n *\n * @example\n * ```typescript\n * // Create a helper for UUID v7 identifiers\n * const idHelper = new IDHelpers('uuid7');\n *\n * // Generate IDs without specifying type each time\n * const id1 = idHelper.generateID();\n * const id2 = idHelper.generateID(Date.now());\n *\n * // Validate IDs\n * if (idHelper.validateID(someId)) {\n * console.log('Valid uuid7');\n * }\n *\n * // Check for empty IDs\n * const empty = idHelper.emptyID();\n * console.log(idHelper.isEmptyID(empty)); // true\n * ```\n */\nexport class IDHelpers {\n private _type: IdentifierType;\n\n /**\n * Gets the identifier type this helper is configured for.\n */\n public get type(): IdentifierType {\n return this._type;\n }\n\n /**\n * Creates a new ID helper for the specified type.\n * @param type - The identifier type to use for all operations\n * @throws {TypeError} If an invalid type is provided\n */\n constructor(type: IdentifierType) {\n assertIdentifierType(type);\n this._type = type;\n }\n\n /**\n * Generates a new identifier using the configured type.\n * @param seedTime - Optional timestamp in milliseconds to seed the ID with\n * @returns A unique identifier string\n */\n public generateID(seedTime?: number): string {\n return generateID(this._type, seedTime);\n }\n\n /**\n * Validates an identifier against the configured type.\n * @param id - The identifier string to validate\n * @returns `true` if valid, `false` otherwise\n */\n public validateID(id: string): boolean {\n return validateID(this._type, id);\n }\n\n /**\n * Returns an empty identifier for the configured type.\n * @returns An empty identifier string\n */\n public emptyID(): string {\n return emptyID(this._type);\n }\n\n /**\n * Checks if an identifier is empty for the configured type.\n * @param id - The identifier string to check\n * @returns `true` if empty, `false` otherwise\n */\n public isEmptyID(id: string): boolean {\n return isEmptyID(this._type, id);\n }\n}\n","/**\n * Returns the current unix time in seconds\n *\n * ```typescript\n * const time = unix();\n * ```\n */\n\nexport function unix(): number {\n return Math.floor(Date.now() / 1000);\n}\n\n/**\n * Returns the current unix time in milliseconds\n *\n * ```typescript\n * const time = ms();\n * ```\n */\n\nexport function ms(): number {\n return Date.now();\n}\n\n/**\n * Returns a high resolution timestamp\n * Returns the time measured in milliseconds\n * This is aimed at performance monitoring\n *\n * ```typescript\n * const time = performance();\n * ```\n */\n\nexport function performance(): number {\n return globalThis.performance.now();\n}\n\n/**\n * Converts a Unix timestamp from milliseconds to seconds.\n * Useful for converting the millisecond-based timestamp from JavaScript's Date.now() into a Unix timestamp in seconds.\n *\n * @param {number} value - Unix timestamp in milliseconds.\n * @returns {number} - Unix timestamp converted to seconds.\n *\n * ```typescript\n * convertMSToUnix(1593189055006); // returns 1593189055\n * ```\n */\n\nexport function convertMSToUnix(value: number): number {\n return Math.floor(value / 1000);\n}\n\n/**\n * Converts a Unix timestamp from seconds to milliseconds.\n *\n * This function takes a Unix timestamp in seconds and converts it to milliseconds.\n * This is useful when dealing with JavaScript's Date object or other systems that\n * require time in milliseconds.\n *\n * @param {number} value - The Unix timestamp in seconds.\n * @returns {number} The Unix timestamp in milliseconds.\n *\n * Example:\n * ```typescript\n * convertUnix(1593189055); // returns 1593189055000\n * ```\n */\n\nexport function convertUnixToMS(value: number): number {\n return value * 1000;\n}\n","/**\n * Deep clone utility\n *\n * Creates a deep copy of a value, recursively cloning nested structures.\n * Handles most common data types including objects, arrays, dates, regexes,\n * Maps, Sets, and typed arrays.\n *\n * Note: Functions are returned by reference (not cloned). Circular references\n * are detected and handled to prevent infinite recursion.\n */\n\n/**\n * Deep clone an object or value\n *\n * @param obj - The value to clone\n * @returns A deep clone of the input value\n */\nexport function deepClone<T>(obj: T): T {\n return cloneInternal(obj, new WeakMap());\n}\n\nfunction cloneInternal<T>(obj: T, seen: WeakMap<object, unknown>): T {\n // Primitives and null/undefined return as-is\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n // Check for circular references\n if (seen.has(obj as object)) {\n return seen.get(obj as object) as T;\n }\n\n // Handle Date\n if (obj instanceof Date) {\n return new Date(obj) as T;\n }\n\n // Handle RegExp\n if (obj instanceof RegExp) {\n const flags = obj.flags;\n const cloned = new RegExp(obj.source, flags);\n cloned.lastIndex = obj.lastIndex;\n return cloned as T;\n }\n\n // Handle Map\n if (obj instanceof Map) {\n const cloned = new Map();\n seen.set(obj as object, cloned);\n\n for (const [key, value] of obj) {\n cloned.set(cloneInternal(key, seen), cloneInternal(value, seen));\n }\n\n return cloned as T;\n }\n\n // Handle Set\n if (obj instanceof Set) {\n const cloned = new Set();\n seen.set(obj as object, cloned);\n\n for (const value of obj) {\n cloned.add(cloneInternal(value, seen));\n }\n\n return cloned as T;\n }\n\n // Handle typed arrays\n if (ArrayBuffer.isView(obj) && !(obj instanceof DataView)) {\n const typedArray = obj as unknown as\n | Int8Array\n | Uint8Array\n | Uint8ClampedArray\n | Int16Array\n | Uint16Array\n | Int32Array\n | Uint32Array\n | Float32Array\n | Float64Array\n | BigInt64Array\n | BigUint64Array;\n const cloned = typedArray.slice();\n return cloned as T;\n }\n\n // Handle Array\n if (Array.isArray(obj)) {\n const cloned: unknown[] = [];\n seen.set(obj as object, cloned);\n\n for (const item of obj) {\n cloned.push(cloneInternal(item, seen));\n }\n\n return cloned as T;\n }\n\n // Handle plain objects\n const cloned: Record<string, unknown> = {};\n seen.set(obj as object, cloned);\n\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n cloned[key] = cloneInternal((obj as Record<string, unknown>)[key], seen);\n }\n }\n\n return cloned as T;\n}\n","import { removeEmptyStringsFromArray } from './arrays';\n\nexport function isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\n/**\n * Converts a string or an array of strings to Pascal Case.\n *\n * This function takes an input string or an array of strings, each potentially containing hyphens,\n * and converts them to Pascal Case. It removes any characters that are not letters or numbers,\n * capitalizes the first letter of each substring, and ensures the rest of the substring\n * is in lowercase. Finally, it concatenates all these substrings to produce a Pascal Case\n * output.\n *\n * @param {string | string[]} input - The input string or array of strings to be converted to Pascal Case.\n * @returns {string} The converted string in Pascal Case.\n *\n * Examples:\n * toPascalCase(\"hello-world-123!$\") will return \"HelloWorld123\"\n * toPascalCase([\"hello\", \"world-123!$\"]) will return \"HelloWorld123\"\n */\n\nexport function toPascalCase(input: string | string[]): string {\n // Ensure input is an array\n const inputArray = Array.isArray(input) ? input : [input];\n\n // Process each string in the array\n const parts: string[] = [];\n\n for (const item of inputArray) {\n // Clean the string, split by hyphen, and remove empty strings\n const cleanedItem = item.replace(/[^a-zA-Z0-9-]/g, '');\n parts.push(...removeEmptyStringsFromArray(cleanedItem.split('-')));\n }\n\n // Process and rejoin the input strings\n return parts\n .map(\n (subString) =>\n subString.charAt(0).toUpperCase() + subString.slice(1).toLowerCase(),\n )\n .join('');\n}\n\n/**\n * Converts a string or an array of strings to Camel Case.\n *\n * This function takes an input string or an array of strings, each potentially containing hyphens,\n * and converts them to Camel Case. It removes any characters that are not letters or numbers,\n * capitalizes the first letter of each substring after the first one, and ensures the rest of the substring\n * is in lowercase. For the first substring, it ensures the entire substring is in lowercase.\n * Finally, it concatenates all these substrings to produce a Camel Case output.\n *\n * @param {string | string[]} input - The input string or array of strings to be converted to Camel Case.\n * @returns {string} The converted string in Camel Case.\n *\n * Examples:\n * toCamelCase(\"hello-world-123!$\") will return \"helloWorld123\"\n * toCamelCase([\"hello\", \"world-123!$\"]) will return \"helloWorld123\"\n */\n\nexport function toCamelCase(input: string | string[]): string {\n // Ensure input is an array\n const inputArray = Array.isArray(input) ? input : [input];\n\n // Process each string in the array\n const parts: string[] = [];\n\n for (const item of inputArray) {\n // Clean the string, split by hyphen, and remove empty strings\n const cleanedItem = item.replace(/[^a-zA-Z0-9-]/g, '');\n parts.push(...removeEmptyStringsFromArray(cleanedItem.split('-')));\n }\n\n // Process and rejoin the input strings\n return parts\n .map((subString, index) =>\n index === 0\n ? subString.toLowerCase()\n : subString.charAt(0).toUpperCase() + subString.slice(1).toLowerCase(),\n )\n .join('');\n}\n\n/**\n * This method converts a string or an array of strings to camel case,\n * but if starting with a leading hyphen, it will convert to Pascal case.\n */\n\nexport function toCamelCaseWithPascalOverride(\n input: string | string[],\n): string {\n if (isString(input) && input.startsWith('-')) {\n return toPascalCase(input);\n } else if (\n Array.isArray(input) &&\n input.length > 0 &&\n input[0].startsWith('-')\n ) {\n return toPascalCase(input);\n } else {\n return toCamelCase(input);\n }\n}\n\n/**\n * Converts a string or an array of strings to constant case.\n *\n * The function takes a string or an array of strings, where each string can be separated by a '-',\n * and converts them into a constant case format (all uppercase with underscores between words).\n * It first cleans the input by removing non-alphanumeric characters (except for hyphens), splits the\n * string into parts on hyphens, and then joins these parts with underscores, converting the entire\n * result to uppercase.\n *\n * @param {string | string[]} input - The input string or array of strings to be converted.\n * @returns {string} The converted string in constant case.\n *\n * Example:\n * toConstantCase(\"hello-world\") will return \"HELLO_WORLD\"\n * toConstantCase([\"hello\", \"world\"]) will return \"HELLO_WORLD\"\n */\n\nexport function toConstantCase(input: string | string[]): string {\n // Ensure input is an array\n const inputArray = Array.isArray(input) ? input : [input];\n\n // Process each string in the array\n let parts: string[] = [];\n\n for (const item of inputArray) {\n // Clean the string and split by hyphen\n const cleanedItem = item.replace(/[^a-zA-Z0-9-]/g, '');\n parts.push(...cleanedItem.split('-'));\n }\n\n // Remove empty strings from the array\n parts = removeEmptyStringsFromArray(parts);\n\n // Join parts with underscore and convert to uppercase\n return parts.join('_').toUpperCase();\n}\n\nexport function splitGraphemes(text: string): string[] {\n const graphemes: string[] = [];\n let grapheme = '';\n let zwjSequence = '';\n\n for (let i = 0; i < text.length; i++) {\n const char = text[i];\n const nextChar = text[i + 1] || '';\n const code = char.charCodeAt(0);\n\n // Handling combining marks and zero width joiner\n if (\n (code >= 0x0300 && code <= 0x036f) || // Combining Diacritical Marks\n (code >= 0x1ab0 && code <= 0x1aff) || // Combining Diacritical Marks Extended\n (code >= 0x1dc0 && code <= 0x1dff) || // Combining Diacritical Marks Supplement\n (code >= 0xfe20 && code <= 0xfe2f) || // Combining Half Marks\n (code >= 0x0e31 && code <= 0x0e3a) || // Thai combining marks\n (code >= 0x0e47 && code <= 0x0e4e)\n ) {\n // Thai combining marks\n grapheme += char;\n } else if (char === '\\u200d') {\n // Zero Width Joiner (ZWJ)\n zwjSequence += grapheme + char;\n grapheme = '';\n } else {\n if (grapheme) {\n if (zwjSequence) {\n graphemes.push(zwjSequence + grapheme);\n zwjSequence = '';\n } else {\n graphemes.push(grapheme);\n }\n }\n grapheme = char;\n\n // Handle surrogate pairs (needed for certain characters including emojis)\n if (\n char >= '\\ud800' &&\n char <= '\\udbff' &&\n nextChar >= '\\udc00' &&\n nextChar <= '\\udfff'\n ) {\n grapheme += nextChar;\n i++;\n }\n }\n }\n\n if (grapheme) {\n if (zwjSequence) {\n graphemes.push(zwjSequence + grapheme);\n } else {\n graphemes.push(grapheme);\n }\n }\n\n return graphemes;\n}\n\nexport function skipTrailingNewLines(str: string): string {\n return str.replace(/\\n+$/, '');\n}\n\n/**\n * Filters a string to include only specified characters, optionally replacing disallowed characters.\n *\n * @param str - The input string to be filtered.\n * @param list - An array of allowed characters.\n * @param caseInsensitive - Optional. If true, the filtering is case-insensitive. Default is false.\n * @param replacementChar - Optional. Character to replace disallowed characters. If empty, disallowed characters are removed. Default is ''.\n * @returns A new string containing only the allowed characters from the input string, with disallowed characters optionally replaced.\n *\n * @example\n * // Case-sensitive usage, removing disallowed characters\n * characterAllowedOnly(\"Hello123!\", [\"H\", \"e\", \"l\", \"o\"]);\n * // Returns: \"Hello\"\n *\n * @example\n * // Case-insensitive usage, removing disallowed characters\n * characterAllowedOnly(\"Hello123!\", [\"h\", \"E\", \"L\", \"O\"], true);\n * // Returns: \"Hello\"\n *\n * @example\n * // Using replacement character\n * characterAllowedOnly(\"Hello123!\", [\"H\", \"e\", \"l\", \"o\"], false, \"-\");\n * // Returns: \"Hello---\"\n */\n\nexport function characterAllowedOnly(\n str: string,\n list: string[],\n // eslint-disable-next-line @typescript-eslint/naming-convention\n caseInsensitive = false,\n replacementChar = '',\n): string {\n let newStr = '';\n\n // Convert the allowed list to lowercase if case-insensitive\n if (caseInsensitive) {\n list = Array.from(new Set(list.map((item) => item.toLowerCase())));\n }\n\n // Convert the entire input string to lowercase if case-insensitive\n const processedStr = caseInsensitive ? str.toLowerCase() : str;\n\n for (const c of processedStr) {\n if (list.includes(c)) {\n newStr += c;\n } else if (replacementChar !== '') {\n newStr += replacementChar;\n }\n }\n\n return newStr;\n}\n\n// functions to chop characters from a string.\n\n/**\n * Will remove the matching first character from a string\n * @param str\n * @param char\n * @returns\n */\n\nexport function chopBeginningCharacter(str: string, char: string): string {\n if (str.startsWith(char)) {\n return str.slice(1);\n } else {\n return str;\n }\n}\n\n/**\n * Will remove the matching last character from the string\n * @param str\n * @param char\n * @returns\n */\nexport function chopEndingCharacter(str: string, char: string): string {\n if (str.endsWith(char)) {\n return str.slice(0, -1);\n } else {\n return str;\n }\n}\n\n/**\n * Will remove the matching character, from the beginning and/or end of the string if matching\n * @param str\n * @param char\n * @returns\n */\n\nexport function chopBothBeginningAndEndingCharacters(\n str: string,\n char: string,\n): string {\n return chopBeginningCharacter(chopEndingCharacter(str, char), char);\n}\n","/**\n * Simple error classes for retry-utils\n * Following the pattern from FileSinkError\n */\n\nexport class RetryUtilsErrPolicyConfigInvalidStrategy extends Error {\n constructor(\n public strategyProvided: string,\n public validStrategies: string[],\n ) {\n super('Invalid strategy provided.');\n this.name = 'RetryUtilsErrPolicyConfigInvalidStrategy';\n }\n}\n\nexport class RetryUtilsErrRunnerAlreadyCompleted extends Error {\n constructor(public invokedMethod: 'run' | 'resume' | 'forceTry') {\n super(\n 'The runner has already completed running the operation. Use the .reset() method, and .run() to run the operation again.',\n );\n this.name = 'RetryUtilsErrRunnerAlreadyCompleted';\n }\n}\n\nexport class RetryUtilsErrRunnerAlreadyRunning extends Error {\n constructor(public invokedMethod: 'run' | 'resume') {\n super('The operation is already running and cannot be started again.');\n this.name = 'RetryUtilsErrRunnerAlreadyRunning';\n }\n}\n\nexport class RetryUtilsErrRunnerForceTryRetryInProgress extends Error {\n constructor(public invokedMethod: 'forceTry') {\n super('Force try retry is already in progress.');\n this.name = 'RetryUtilsErrRunnerForceTryRetryInProgress';\n }\n}\n\nexport class RetryUtilsErrRunnerNotPaused extends Error {\n constructor(public invokedMethod: 'resume') {\n super(\n 'The runner is not in a paused state. resume() can only be called when the runner state is stopped.',\n );\n this.name = 'RetryUtilsErrRunnerNotPaused';\n }\n}\n\nexport class RetryUtilsErrRunnerCancelPending extends Error {\n constructor(public invokedMethod: 'run' | 'resume') {\n super(\n 'A cancel operation is pending. The operation cannot be started again.',\n );\n this.name = 'RetryUtilsErrRunnerCancelPending';\n }\n}\n\nexport class RetryUtilsErrRunnerRetryCanceled extends Error {\n constructor(public invokedMethod: 'run') {\n super(\n 'The operation was already canceled. Use either .resume(), .forceTry() or .reset() and .run() to run the operation again.',\n );\n this.name = 'RetryUtilsErrRunnerRetryCanceled';\n }\n}\n\nexport class RetryUtilsErrRunnerLastRetryFatallyFailed extends Error {\n constructor(public invokedMethod: 'run' | 'resume') {\n super(\n 'The last retry attempt failed fatally. The operation cannot be retried. Use either .reset() then .run() or .forceTry() to run the operation again.',\n );\n this.name = 'RetryUtilsErrRunnerLastRetryFatallyFailed';\n }\n}\n\nexport class RetryUtilsErrRunnerAttemptsExhausted extends Error {\n constructor(public invokedMethod: 'run' | 'resume') {\n super(\n 'All attempts were exhausted. The operation cannot be retried. Use either .reset() then .run() or .forceTry() to run the operation again.',\n );\n this.name = 'RetryUtilsErrRunnerAttemptsExhausted';\n }\n}\n\nexport class RetryUtilsErrRunnerLockAcquisitionError extends Error {\n constructor(public invokedMethod: 'run' | 'resume' | 'forceTry') {\n super(\n 'Failed to acquire operation lock. Cannot attempt to run the operation.',\n );\n this.name = 'RetryUtilsErrRunnerLockAcquisitionError';\n }\n}\n\nexport class RetryUtilsErrRunnerUnexpectedError extends Error {\n constructor(\n public invokedMethod: 'run' | 'resume' | 'forceTry',\n public originalError: Error,\n ) {\n super('An unexpected error occurred.');\n this.name = 'RetryUtilsErrRunnerUnexpectedError';\n }\n}\n\nexport class RetryUtilsErrRunnerUnknownState extends Error {\n constructor(\n public invokedMethod: 'waitForCompletion',\n public runnerState: string,\n ) {\n super('An unknown runner state was encountered.');\n this.name = 'RetryUtilsErrRunnerUnknownState';\n }\n}\n\nexport class RetryUtilsErrRunnerNotRunning extends Error {\n constructor(public invokedMethod: 'waitForCompletion') {\n super('The operation is not currently running.');\n this.name = 'RetryUtilsErrRunnerNotRunning';\n }\n}\n","export function clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(value, max));\n}\n\n/**\n * Clamps a value to a minimum, returning a default if the value is not finite or is undefined/null.\n *\n * Useful for config/settings validation where you want to:\n * - Enforce a minimum value\n * - Handle invalid inputs (Infinity, NaN, undefined, null) gracefully\n *\n * @param value - The value to clamp (can be undefined or null)\n * @param min - The minimum allowed value\n * @param defaultValue - The default to return if value is not finite or is undefined/null\n * @returns The clamped value, or defaultValue if value is not finite/undefined/null\n *\n * @example\n * ```typescript\n * finiteClampMin(5000, 1000, 3000) // 5000 (value > min)\n * finiteClampMin(500, 1000, 3000) // 1000 (enforces min)\n * finiteClampMin(Infinity, 1000, 3000) // 3000 (not finite, use default)\n * finiteClampMin(NaN, 1000, 3000) // 3000 (not finite, use default)\n * finiteClampMin(undefined, 1000, 3000) // 3000 (undefined, use default)\n * finiteClampMin(null, 1000, 3000) // 3000 (null, use default)\n * ```\n */\nexport function finiteClampMin(\n value: number | undefined | null,\n min: number,\n defaultValue: number,\n): number {\n if (value === null || value === undefined || !Number.isFinite(value)) {\n return defaultValue;\n }\n\n return Math.max(value, min);\n}\n","import { clamp } from '../../clamp';\n\ninterface ExponentialDelayParams {\n retryCount: number;\n minTimeoutMS: number;\n maxTimeoutMS: number;\n factor: number;\n dispersion: number;\n // Provide a function for randomness to make testing easier\n randomFn: () => number;\n}\n\nexport function calculateExponentialDelay({\n retryCount,\n minTimeoutMS,\n maxTimeoutMS,\n factor,\n dispersion,\n randomFn,\n}: ExponentialDelayParams): number {\n let delay = minTimeoutMS * Math.pow(factor, retryCount);\n\n if (dispersion > 0) {\n const dispersionAmount = delay * dispersion;\n // Apply dispersion jitter using the documented formula:\n // randomOffset = (Math.random() * 2 - 1) * (delay * dispersion)\n // Algebraically equivalent to: Math.random() * (dispersionAmount * 2) - dispersionAmount\n delay += randomFn() * (dispersionAmount * 2) - dispersionAmount;\n }\n\n // Use a clamp function to simplify bounds checking\n return clamp(delay, minTimeoutMS, maxTimeoutMS);\n}\n\n/**\n * Extracts a string message from an error value for grouping purposes.\n */\nfunction extractErrorMessage(error: unknown): string {\n // Check if it's an Error instance (most common case)\n if (error instanceof Error) {\n return error.message;\n }\n\n // Check if it's an object with a 'message' property\n if (\n error !== null &&\n error !== undefined &&\n typeof error === 'object' &&\n 'message' in error &&\n typeof (error as { message: unknown }).message === 'string'\n ) {\n return (error as { message: string }).message;\n }\n\n // Check if it's an object with an 'error' property (nested error)\n if (\n error !== null &&\n error !== undefined &&\n typeof error === 'object' &&\n 'error' in error\n ) {\n const nested = (error as { error: unknown }).error;\n\n if (nested instanceof Error) {\n return nested.message;\n } else if (\n nested !== null &&\n nested !== undefined &&\n typeof nested === 'object' &&\n 'message' in nested &&\n typeof (nested as { message: unknown }).message === 'string'\n ) {\n return (nested as { message: string }).message;\n } else {\n return String(nested);\n }\n }\n\n // Fall back to string conversion\n return String(error);\n}\n\nexport function getMostCommonError(errors: unknown[]): unknown {\n if (errors.length === 0) {\n return null;\n }\n\n // Strategy 1: Count by reference equality (===).\n // Handles reused error objects and guards against unstable message extraction.\n const refCounts = new Map<unknown, number>();\n\n for (const error of errors) {\n refCounts.set(error, (refCounts.get(error) ?? 0) + 1);\n }\n\n // Strategy 2: Count by extracted message string.\n // Groups distinct error objects that represent the same logical error.\n const messageCounts = new Map<string, { count: number; error: unknown }>();\n\n for (const error of errors) {\n const message = extractErrorMessage(error);\n const existing = messageCounts.get(message);\n\n if (existing) {\n existing.count += 1;\n } else {\n messageCounts.set(message, { count: 1, error });\n }\n }\n\n // Pick the winner across both strategies (highest count wins).\n let mostCommon: unknown = null;\n let maxCount = 0;\n\n for (const [error, count] of refCounts) {\n if (count > maxCount) {\n maxCount = count;\n mostCommon = error;\n }\n }\n\n for (const { count, error } of messageCounts.values()) {\n if (count > maxCount) {\n maxCount = count;\n mostCommon = error;\n }\n }\n\n return mostCommon;\n}\n","import { isString } from '../../strings';\nimport { RetryUtilsErrPolicyConfigInvalidStrategy } from './retry-utils-errors';\nimport type {\n RetryPolicyOptions,\n RetryPolicyValidated,\n RetryQueryResult,\n} from './types';\nimport { clamp } from '../../clamp';\nimport { calculateExponentialDelay, getMostCommonError } from './utils';\n\ninterface CurrentState {\n wasInitialAttemptTaken: boolean; // Represents if the initial attempt was taken or not since if errors is empty, it should return 1\n wasSuccessful: boolean;\n errors: unknown[];\n mostCommonErrorCached: {\n has: boolean;\n value: unknown;\n };\n}\n\nexport class RetryPolicy {\n private policy!: RetryPolicyValidated;\n private currentState: CurrentState = this.getEmptyCurrentState();\n\n /**\n * Gets the validated policy information for this retry policy instance.\n * @returns {RetryPolicyValidated} The current retry policy settings.\n */\n\n public get policyInfo(): RetryPolicyValidated {\n return this.policy;\n }\n\n /**\n * Gets the total number of attempts made, including the initial attempt and any retries.\n * @returns {number} The total number of attempts.\n */\n\n public get attempts(): number {\n if (this.currentState.wasSuccessful) {\n // When successful, include the initial attempt in the total.\n return this.currentState.errors.length + 1;\n } else {\n // When not successful, clamp to ensure at least 1 once the initial attempt was taken.\n return clamp(\n this.currentState.errors.length,\n this.wasInitialAttemptTaken ? 1 : 0,\n Infinity,\n );\n }\n }\n\n /**\n * Checks if the initial attempt has been taken.\n */\n\n public get wasInitialAttemptTaken(): boolean {\n return this.currentState.wasInitialAttemptTaken;\n }\n\n /**\n * Checks if the last operation attempt was successful. (used to calculate the number of attempts made)\n */\n\n public get wasSuccessful(): boolean {\n return this.currentState.wasSuccessful;\n }\n\n /**\n * Gets the maximum number of retry attempts allowed by the current policy.\n * @returns {number} The maximum number of retry attempts.\n */\n\n public get maxRetryAttempts(): number {\n return this.policy.maxRetryAttempts;\n }\n\n /**\n * Gets the number of retry attempts made, excluding the initial attempt.\n * @returns {number} The number of retries.\n */\n\n public get retryCount(): number {\n // Retry count is always attempts minus the initial attempt,\n // but only once the initial attempt has been taken.\n if (!this.wasInitialAttemptTaken) {\n return 0;\n }\n\n return Math.max(this.attempts - 1, 0);\n }\n\n /**\n * Checks if the retry attempts have been exhausted.\n * @returns {boolean} True if the number of retries has reached the maximum allowed attempts; otherwise, false.\n */\n\n public get areAttemptsExhausted(): boolean {\n return this.retryCount >= this.maxRetryAttempts;\n }\n\n /**\n * Gets a list of errors recorded from each retry attempt.\n * @returns {unknown[]} An array of errors encountered during retry attempts.\n */\n\n public get errors(): unknown[] {\n return [...this.currentState.errors];\n }\n\n /**\n * Gets the most common error encountered across all retry attempts.\n *\n * This method caches the most common error for performance. If the cache is invalidated due to a new error,\n * it recalculates the most common error.\n *\n * @returns {unknown} The most common error, or null if no errors have been encountered.\n */\n\n public get mostCommonError(): unknown {\n if (this.currentState.mostCommonErrorCached.has) {\n return this.currentState.mostCommonErrorCached.value;\n } else {\n const mostCommon = getMostCommonError(this.currentState.errors);\n\n this.currentState.mostCommonErrorCached.has = true;\n this.currentState.mostCommonErrorCached.value = mostCommon;\n\n return mostCommon;\n }\n }\n\n /**\n * Gets the last error encountered during the retry attempts.\n * @returns {unknown} The last error encountered, or null if no errors have been recorded.\n */\n\n public get lastError(): unknown {\n if (this.currentState.errors.length === 0) {\n return null;\n } else {\n return this.currentState.errors[this.currentState.errors.length - 1];\n }\n }\n\n /**\n * Constructs a RetryPolicy instance with specified options.\n *\n * @param {RetryPolicyOptions} policy The retry policy options, including strategy, maximum retry attempts,\n * and other parameters specific to the fixed or exponential strategy.\n *\n * Throws an error if an invalid retry strategy is provided.\n */\n\n constructor(policy: RetryPolicyOptions) {\n const DEFAULT_MAX_RETRY_ATTEMPTS = 10;\n const DEFAULT_FACTOR = 1.5;\n const DEFAULT_MIN_TIMEOUT_MS = 1000;\n const DEFAULT_MAX_TIMEOUT_MS = 30000;\n const DEFAULT_DISPERSION = 0.1;\n\n if (policy.strategy === 'fixed') {\n this.policy = {\n strategy: 'fixed',\n maxRetryAttempts: Math.floor(\n clamp(\n policy.maxRetryAttempts ?? DEFAULT_MAX_RETRY_ATTEMPTS,\n 1,\n Infinity,\n ),\n ),\n delayMS: clamp(policy.delayMS ?? DEFAULT_MIN_TIMEOUT_MS, 1, Infinity),\n };\n } else if (policy.strategy === 'exponential') {\n const minTimeoutMS = clamp(\n policy.minTimeoutMS ?? DEFAULT_MIN_TIMEOUT_MS,\n 1,\n Infinity,\n );\n const maxTimeoutMS = clamp(\n policy.maxTimeoutMS ?? DEFAULT_MAX_TIMEOUT_MS,\n 1,\n Infinity,\n );\n\n // Ensure maxTimeoutMS >= minTimeoutMS by swapping if needed\n const finalMin = Math.min(minTimeoutMS, maxTimeoutMS);\n const finalMax = Math.max(minTimeoutMS, maxTimeoutMS);\n\n this.policy = {\n strategy: 'exponential',\n maxRetryAttempts: Math.floor(\n clamp(\n policy.maxRetryAttempts ?? DEFAULT_MAX_RETRY_ATTEMPTS,\n 1,\n Infinity,\n ),\n ),\n factor: clamp(policy.factor ?? DEFAULT_FACTOR, 1, Infinity),\n minTimeoutMS: finalMin,\n maxTimeoutMS: finalMax,\n dispersion: clamp(policy.dispersion ?? DEFAULT_DISPERSION, 0, 1),\n };\n } else {\n throw new RetryUtilsErrPolicyConfigInvalidStrategy(\n isString(policy['strategy']) ? policy['strategy'] : 'unknown',\n ['fixed', 'exponential'],\n );\n }\n }\n\n /**\n * Resets the retry policy to its initial state.\n *\n * This method clears all recorded errors and marks the initial attempt as not taken,\n * effectively resetting the state of the retry policy for a new operation.\n */\n\n public reset(): void {\n this.currentState = this.getEmptyCurrentState();\n }\n\n /**\n * Determines if the initial operation attempt should proceed.\n *\n * This method checks if the initial attempt has already been taken and updates the state to reflect that\n * the initial attempt is now being made. This method is used to ensure that the retry logic only kicks in after\n * the first attempt has failed.\n *\n * Note that even upon success, you should call the reset method to clear the state for the next operation.\n *\n * @returns {boolean} True if the initial attempt has not been made yet; otherwise, false.\n */\n\n public shouldDoFirstTry(): boolean {\n if (this.currentState.wasInitialAttemptTaken) {\n return false;\n } else {\n this.currentState.wasInitialAttemptTaken = true; // Mark the initial attempt as taken.\n\n return true;\n }\n }\n\n /**\n * Marks the last operation attempt as successful.\n */\n\n public markAsSuccessful(): void {\n this.currentState.wasSuccessful = true;\n }\n\n /**\n * Records an error that occurred during the last operation attempt.\n *\n * Does not check if was successful or not, nor checks if should retry or not.\n */\n\n public reportError(error: unknown): void {\n this.currentState.errors.push(error);\n\n // Invalidate the mostCommonError cache\n this.currentState.mostCommonErrorCached.has = false;\n }\n\n /**\n * Determines if a retry should be made based on the current state and the provided error.\n *\n * When called, this method stores the provided error, checks if further retries are allowed based on the\n * maximum retry attempts, and calculates the delay for the next retry if applicable.\n *\n * It also invalidates the cached most common error since the error state has changed.\n *\n * @param {unknown} error The error that resulted from the last operation attempt. Can be omitted when `isQueryOnly` is `true`.\n * @param {boolean} isQueryOnly If true, the method only queries if a retry should be made without storing the error.\n * @returns {RetryQueryResult} An object indicating whether a retry should be attempted and the delay before the next attempt.\n */\n\n public shouldRetry(\n error?: unknown,\n isQueryOnly: boolean = false,\n ): RetryQueryResult {\n if (this.currentState.wasSuccessful) {\n if (!isQueryOnly) {\n // push the error into the errors array anyways if it was not a query only\n this.reportError(error);\n }\n\n // Once successful, retries are never allowed.\n return { shouldRetry: false, delayMS: 0 };\n }\n\n if (!isQueryOnly) {\n // push the error into the errors array\n this.reportError(error);\n }\n\n // Decide if we should retry - check if we've exhausted our retry attempts\n if (this.areAttemptsExhausted) {\n return { shouldRetry: false, delayMS: 0 };\n } else {\n // Calculate the delay for the next retry attempt\n const delayMS = this.calculateNextDelay();\n\n return { shouldRetry: true, delayMS };\n }\n }\n\n /**\n * Returning a fresh copy of the current state\n * to be immutable and not changed by the caller\n */\n\n private getEmptyCurrentState(): CurrentState {\n return {\n wasInitialAttemptTaken: false,\n wasSuccessful: false,\n errors: [],\n mostCommonErrorCached: {\n has: false,\n value: null,\n },\n };\n }\n\n /**\n * Calculates the delay before the next retry attempt based on the current retry policy.\n *\n * For a fixed strategy, it returns the specified delay. For an exponential strategy, it calculates the delay\n * based on the exponential backoff formula, considering the number of retry attempts, the base delay,\n * the exponential factor, and any specified dispersion to introduce randomness.\n *\n * @returns {number} The calculated delay in milliseconds before the next retry attempt.\n */\n\n private calculateNextDelay(): number {\n if (this.policy.strategy === 'fixed') {\n return this.policy.delayMS;\n } else if (this.policy.strategy === 'exponential') {\n return calculateExponentialDelay({\n retryCount: this.retryCount,\n minTimeoutMS: this.policy.minTimeoutMS,\n maxTimeoutMS: this.policy.maxTimeoutMS,\n factor: this.policy.factor,\n dispersion: this.policy.dispersion,\n randomFn: Math.random,\n });\n }\n\n return 1; // Should never reach here\n }\n}\n","// prettier-ignore\nexport const BLANK_SPACE = ' ';\n\nexport const EOL = '\\n';\nexport const DOUBLE_EOL = EOL + EOL;\nexport const INDENT = ' '.repeat(4);\nexport const DOUBLE_INDENT = INDENT + INDENT;\n\n// prettier-ignore\nexport const SINGLE_QUOTE = \"'\";\n\n// similar to Python string library\nexport const ASCII_LOWERCASE = 'abcdefghijklmnopqrstuvwxyz';\nexport const ASCII_UPPERCASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';\nexport const ASCII_LETTERS = ASCII_LOWERCASE + ASCII_UPPERCASE;\nexport const DIGITS = '0123456789';\nexport const HEX_DIGITS = DIGITS + 'abcdefABCDEF';\nexport const OCT_DIGITS = '01234567';\nexport const PUNCTUATION = '!\"#$%&\\'()*+,-./:;<=>?@[\\\\]^_`{|}~';\nexport const WHITESPACE = ' \\t\\n\\r\\v\\f';\nexport const PRINTABLE = DIGITS + ASCII_LETTERS + PUNCTUATION + WHITESPACE;\n","/**\n * Utilities to pad strings with another string up to a defined length.\n * Each function takes a string, length to pad and the string to be used for padding (but defaults to a blank space if not provided) and returns the modified string\n *\n * This only pads on the left side, so text is added to the front until the total string equals the given length.\n *\n * ```typescript\n * padLeft('Hey', 6, '*'); // returns ***Hey\n * ```\n * @category String Padding\n */\n\nimport { BLANK_SPACE } from './constants';\n\nexport function padLeft(\n str: string,\n length: number,\n padStr = BLANK_SPACE,\n): string {\n return str.padStart(length, padStr);\n}\n\n/**\n * This only pads on the right side, so text is added to the end until the total string equals the given length.\n *\n * ```typescript\n * padRight('Hey', 6, '*'); // returns Hey***\n * ```\n *\n * @category String Padding\n */\n\nexport function padRight(\n str: string,\n length: number,\n padStr = BLANK_SPACE,\n): string {\n return str.padEnd(length, padStr);\n}\n\n/**\n * Same as `padCenterPreferLeft` and `padCenterPreferRight` but you can pass in a string with `left` or `right` before the padStr to use more direct.\n *\n * Defaults to `left`\n *\n * @category String Padding\n */\n\nexport function padCenter(\n str: string,\n length: number,\n prefer: 'left' | 'right' = 'left',\n padStr = BLANK_SPACE,\n): string {\n const midStrLength = length - str.length;\n\n if (midStrLength > 0) {\n const padLeftAmount =\n prefer === 'left'\n ? Math.ceil(midStrLength / 2)\n : Math.floor(midStrLength / 2);\n\n const padRightAmount =\n prefer === 'left'\n ? Math.floor(midStrLength / 2)\n : Math.ceil(midStrLength / 2);\n\n return (\n padLeft('', padLeftAmount, padStr) +\n str +\n padRight('', padRightAmount, padStr)\n );\n } else {\n return str;\n }\n}\n\n/**\n * It tries to pad equally on both sides in an attempt to center your text. However if it can't the extra character will be added to the left side\n *\n * @category String Padding\n */\n\nexport function padCenterPreferLeft(\n str: string,\n length: number,\n padStr = BLANK_SPACE,\n): string {\n return padCenter(str, length, 'left', padStr);\n}\n\n/**\n * It tries to pad equally, but if it can't the extra character will be added to the right side\n *\n * @category String Padding\n */\n\nexport function padCenterPreferRight(\n str: string,\n length: number,\n padStr = BLANK_SPACE,\n): string {\n return padCenter(str, length, 'right', padStr);\n}\n","import { padCenterPreferRight, padRight } from '../padding-utils';\nimport stringWidth from 'string-width';\nimport { splitGraphemes } from '../strings';\n\nexport class ASCIITableUtils {\n public static centerText(text: string, width: number): string {\n return padCenterPreferRight(text, width, ' ');\n }\n\n public static createSeparator(\n columnWidths: number[],\n character: string = '=',\n ): string {\n const totalWidth =\n columnWidths.reduce((sum, width) => sum + width + 3, 0) - 1;\n\n return `+${padRight('', totalWidth, character)}+`;\n }\n\n public static wrapText(text: string, maxLength: number): string[] {\n const words = text.split(' ');\n const lines: string[] = [];\n let currentLine = '';\n\n for (const word of words) {\n if (stringWidth(currentLine) + stringWidth(word) + 1 <= maxLength) {\n currentLine += (currentLine ? ' ' : '') + word;\n } else {\n if (currentLine) {\n lines.push(currentLine);\n }\n\n if (stringWidth(word) <= maxLength) {\n currentLine = word;\n } else {\n const subWords = ASCIITableUtils.splitWord(word, maxLength);\n lines.push(...subWords.slice(0, -1));\n currentLine = subWords[subWords.length - 1];\n }\n }\n }\n\n if (currentLine) {\n lines.push(currentLine);\n }\n\n return lines;\n }\n\n public static splitWord(word: string, maxLength: number): string[] {\n const graphemes = splitGraphemes(word);\n const subWords: string[] = [];\n let currentSubWord = '';\n\n for (const grapheme of graphemes) {\n if (stringWidth(currentSubWord + grapheme) <= maxLength) {\n currentSubWord += grapheme;\n } else {\n subWords.push(currentSubWord);\n currentSubWord = grapheme;\n }\n }\n\n if (currentSubWord) {\n subWords.push(currentSubWord);\n }\n\n return subWords;\n }\n}\n","import { ASCIITableUtils } from './ascii-table-utils';\nimport stringWidth from 'string-width';\n\ninterface MultiColumnASCIITableOptions {\n tableWidth?: number;\n emptyMessage?: string;\n widthMode?: 'flex' | 'fixed';\n}\n\nexport class MultiColumnASCIITable {\n private headers: string[];\n private rows: string[][];\n private tableWidth: number;\n private emptyMessage: string;\n private widthMode: 'flex' | 'fixed';\n\n constructor(headers: string[], options: MultiColumnASCIITableOptions = {}) {\n this.headers = headers;\n this.rows = [];\n this.tableWidth = options.tableWidth || 80;\n this.emptyMessage = options.emptyMessage || '';\n this.widthMode = options.widthMode || 'flex';\n\n const minTableWidth = this.getMinimumWidth();\n\n if (this.tableWidth < minTableWidth) {\n throw new Error(\n `Table width must be at least ${minTableWidth} to accommodate the headers.`,\n );\n }\n }\n\n public getMinimumWidth(): number {\n return this.headers.length * 4 + 1;\n }\n\n public addRow(row: string[]): void {\n if (row.length !== this.headers.length) {\n throw new Error(\n `Number of values in the row (${row.length}) must match the number of headers (${this.headers.length}).`,\n );\n }\n\n this.rows.push(row);\n }\n\n public toString(options: MultiColumnASCIITableOptions = {}): string {\n const tableWidth = options.tableWidth || this.tableWidth;\n const emptyMessage = options.emptyMessage || this.emptyMessage;\n\n if (this.rows.length === 0) {\n const emptyTableWidth = Math.min(tableWidth, 40);\n\n const separator = '+' + '-'.repeat(emptyTableWidth - 2) + '+';\n const emptyMessageLines = ASCIITableUtils.wrapText(\n emptyMessage,\n emptyTableWidth - 4,\n );\n\n const emptyRows = emptyMessageLines.map((line) => {\n const paddingLeft = ' '.repeat(\n Math.floor((emptyTableWidth - stringWidth(line) - 4) / 2),\n );\n\n const paddingRight = ' '.repeat(\n Math.ceil((emptyTableWidth - stringWidth(line) - 4) / 2),\n );\n\n return `| ${paddingLeft}${line}${paddingRight} |`;\n });\n\n if (emptyRows.length === 0) {\n emptyRows.push(`| ${' '.repeat(emptyTableWidth - 4)} |`);\n }\n\n return [separator, ...emptyRows, separator].join('\\n');\n }\n\n const columnWidths = this.calculateColumnWidths(options);\n\n const headerSeparator = ASCIITableUtils.createSeparator(columnWidths);\n const rowSeparator = ASCIITableUtils.createSeparator(columnWidths, '-');\n let tableString = headerSeparator + '\\n';\n\n const header = this.renderRow(this.headers, columnWidths);\n tableString += header + '\\n' + rowSeparator + '\\n';\n\n const rows = this.rows.map((row) => {\n return this.renderRow(row, columnWidths);\n });\n\n tableString += rows.join('\\n' + rowSeparator + '\\n');\n tableString += '\\n' + headerSeparator;\n\n return tableString;\n }\n\n public calculateColumnWidths(\n options: MultiColumnASCIITableOptions = {},\n ): number[] {\n const tableWidth = options.tableWidth || this.tableWidth;\n const widthMode = options.widthMode || this.widthMode;\n\n const numColumns = this.headers.length;\n\n if (widthMode === 'fixed') {\n const availableWidth = tableWidth - (numColumns + 1) * 3 + 1;\n const columnWidth = Math.floor(availableWidth / numColumns);\n const extraWidth = availableWidth % numColumns;\n const columnWidths = new Array(numColumns).fill(columnWidth);\n\n // if there is any remaining width (extraWidth), we distribute it evenly among the columns starting from the first column.\n for (let i = 0; i < extraWidth; i++) {\n columnWidths[i] += 1;\n }\n\n return columnWidths as number[];\n }\n\n const availableWidth = tableWidth - (numColumns + 1) * 3 + 1;\n const maxColumnWidth = Math.floor(availableWidth / numColumns);\n const totalContentWidth = this.headers.reduce(\n (sum, header) => sum + stringWidth(header),\n 0,\n );\n\n if (availableWidth >= totalContentWidth) {\n const remainingWidth = availableWidth - totalContentWidth;\n const extraCharWidth = Math.floor(remainingWidth / numColumns);\n const extraCharRemainder = remainingWidth % numColumns;\n\n const columnWidths = this.headers.map((header, index) => {\n const extraWidth = index < extraCharRemainder ? 1 : 0;\n return stringWidth(header) + extraCharWidth + extraWidth;\n });\n\n return columnWidths;\n } else {\n const columnWidths = this.headers.map(() => maxColumnWidth);\n\n return columnWidths;\n }\n }\n\n private renderRow(row: string[], columnWidths: number[]): string {\n const wrappedCells = row.map((value, index) => {\n const wrappedLines = ASCIITableUtils.wrapText(value, columnWidths[index]);\n\n return wrappedLines\n .map((line) => line.padEnd(columnWidths[index]))\n .join('\\n');\n });\n\n const maxLines = Math.max(\n ...wrappedCells.map((cell) => cell.split('\\n').length),\n );\n\n const paddedRows = [];\n\n for (let i = 0; i < maxLines; i++) {\n const rowLine = wrappedCells.map((cell, index) => {\n const cellLines = cell.split('\\n');\n const cellLine = cellLines[i] || '';\n const padding = ' '.repeat(columnWidths[index] - stringWidth(cellLine));\n\n return ' ' + cellLine + padding + ' ';\n });\n\n paddedRows.push('|' + rowLine.join('|') + '|');\n }\n\n return paddedRows.join('\\n');\n }\n}\n","import { isString } from '../strings';\nimport { padRight } from '../padding-utils';\nimport { MultiColumnASCIITable } from './multi-column-ascii-table';\nimport { ASCIITableUtils } from './ascii-table-utils';\nimport stringWidth from 'string-width';\nimport { clamp } from '../clamp';\n\nexport type TableRowValue =\n | string\n | number\n | boolean\n | null\n | undefined\n | KeyValueASCIITable\n | MultiColumnASCIITable\n | NestedKeyValueEntry[];\n\ntype TableRow = TableRowRegular | TableRowOwn;\n\ninterface TableRowRegular {\n kind: 'regular';\n key: string;\n value: TableRowValue;\n}\n\ninterface TableRowOwn {\n kind: 'own';\n key: string;\n value: string | NestedKeyValueEntry[];\n}\n\nexport interface NestedKeyValueEntry {\n key: string;\n value: string | KeyValueASCIITable | NestedKeyValueEntry[];\n}\n\ninterface KeyValueASCIITableOptions {\n tableWidth?: number;\n autoAdjustWidthWhenPossible?: boolean;\n emptyMessage?: string;\n}\n\nexport class KeyValueASCIITable {\n public readonly tableWidth: number;\n private emptyMessage: string;\n private autoAdjustWidthWhenPossible: boolean = true;\n\n private rows: TableRow[] = [];\n\n constructor(options: KeyValueASCIITableOptions = {}) {\n const minTableWidth = this.getMinimumWidth();\n\n if (options.tableWidth && options.tableWidth < minTableWidth) {\n throw new Error(\n `Table width must be at least ${minTableWidth} to accommodate the table structure.`,\n );\n }\n\n this.tableWidth = options.tableWidth || 80;\n this.autoAdjustWidthWhenPossible =\n options.autoAdjustWidthWhenPossible ?? true;\n this.emptyMessage = options.emptyMessage || '';\n }\n\n public getMinimumWidth(): number {\n // The minimum width for the KeyValueASCIITable is 9 characters:\n // - 2 character for the '| ' at the start\n // - 1 character for the minimum key column width\n // - 3 character for the ' | ' separating the key and value columns\n // - 1 character for the minimum value column width\n // - 2 character for the ' |' at the end\n\n return 9;\n }\n\n /**\n * Adds key and value to the table but placing the value on its own row.\n *\n * @param key\n * @param value\n */\n\n public addValueOnSeparateRow(key: string, value: string): void {\n const row: TableRow = { kind: 'own', key, value };\n\n this.rows.push(row);\n }\n\n /**\n * Adds key and value to the table.\n *\n * If provided value is an instance of ASCIITable or MultiColumnASCIITable, it will be rendered as a nested table on its own row for readability.\n *\n * @param key\n * @param value\n */\n\n public addRow(key: string, value: TableRowValue): void {\n const row: TableRow = { kind: 'regular', key, value };\n\n this.rows.push(row);\n }\n\n public toString(options: KeyValueASCIITableOptions = {}): string {\n const tableWidth = options.tableWidth || this.tableWidth;\n const canAutoAdjustWidthWhenPossible =\n options.autoAdjustWidthWhenPossible ?? this.autoAdjustWidthWhenPossible;\n\n const emptyMessage = options.emptyMessage || this.emptyMessage;\n\n if (this.rows.length === 0) {\n const emptyTableWidth = Math.min(tableWidth, 40);\n\n const separator = '+' + '-'.repeat(emptyTableWidth - 2) + '+';\n const emptyMessageLines = ASCIITableUtils.wrapText(\n emptyMessage,\n emptyTableWidth - 4,\n );\n\n const emptyRows = emptyMessageLines.map((line) => {\n const paddingLeft = padRight(\n '',\n Math.floor((emptyTableWidth - stringWidth(line) - 4) / 2),\n ' ',\n );\n\n const paddingRight = padRight(\n '',\n Math.ceil((emptyTableWidth - stringWidth(line) - 4) / 2),\n ' ',\n );\n\n return `| ${paddingLeft}${line}${paddingRight} |`;\n });\n\n if (emptyRows.length === 0) {\n emptyRows.push(`| ${' '.repeat(emptyTableWidth - 4)} |`);\n }\n\n return [separator, ...emptyRows, separator].join('\\n');\n }\n\n const columnWidths = this.calculateColumnWidths(options);\n\n const headerSeparator = ASCIITableUtils.createSeparator(columnWidths);\n const rowSeparator = ASCIITableUtils.createSeparator(columnWidths, '-');\n\n let tableString = headerSeparator + '\\n';\n\n for (const [rowIndex, row] of this.rows.entries()) {\n const { kind, key, value } = row;\n\n if (\n kind === 'own' ||\n value instanceof KeyValueASCIITable ||\n value instanceof MultiColumnASCIITable ||\n Array.isArray(value)\n ) {\n const keyString = ASCIITableUtils.centerText(\n key,\n columnWidths[0] + columnWidths[1] + 3,\n );\n\n tableString += `| ${keyString} |\\n`;\n tableString += rowSeparator + '\\n';\n\n let valueString = '';\n\n if (value instanceof KeyValueASCIITable) {\n valueString = this.formatValue(\n value,\n tableWidth - 4,\n canAutoAdjustWidthWhenPossible,\n '',\n );\n } else if (value instanceof MultiColumnASCIITable) {\n valueString = this.formatValue(\n value,\n tableWidth - 4,\n canAutoAdjustWidthWhenPossible,\n '',\n );\n } else if (Array.isArray(value)) {\n valueString = this.formatValue(\n value,\n tableWidth - 4,\n canAutoAdjustWidthWhenPossible,\n '',\n );\n } else if (row.kind === 'own') {\n valueString = this.formatTableRowOnOwnRow(\n value as string,\n tableWidth - 4,\n tableWidth,\n );\n }\n\n const valueLines = valueString.split('\\n');\n const paddedValueLines = valueLines.map((line) => {\n const padding = padRight('', tableWidth - stringWidth(line) - 4, ' ');\n\n return `| ${line}${padding} |`;\n });\n\n tableString += paddedValueLines.join('\\n') + '\\n';\n tableString += headerSeparator + '\\n';\n } else {\n const keyLines = ASCIITableUtils.wrapText(key, columnWidths[0]);\n\n const valueLines = ASCIITableUtils.wrapText(\n this.formatValue(\n value,\n columnWidths[1],\n canAutoAdjustWidthWhenPossible,\n '',\n ),\n columnWidths[1],\n );\n\n const maxLines = Math.max(keyLines.length, valueLines.length);\n\n for (let i = 0; i < maxLines; i++) {\n const keyLine = keyLines[i] || '';\n const valueLine = valueLines[i] || '';\n\n const keyPadding = ' '.repeat(columnWidths[0] - stringWidth(keyLine));\n\n const valuePadding = ' '.repeat(\n columnWidths[1] - stringWidth(valueLine),\n );\n\n tableString += `| ${keyLine}${keyPadding} | ${valueLine}${valuePadding} |\\n`;\n\n if (i === maxLines - 1) {\n if (rowIndex === this.rows.length - 1) {\n tableString += headerSeparator + '\\n';\n } else {\n tableString += rowSeparator + '\\n';\n }\n }\n }\n }\n }\n\n return tableString.trim();\n }\n\n private calculateColumnWidths(\n options: KeyValueASCIITableOptions = {},\n ): number[] {\n const tableWidth = options.tableWidth || this.tableWidth;\n const canAutoAdjustWidthWhenPossible =\n options.autoAdjustWidthWhenPossible ?? this.autoAdjustWidthWhenPossible;\n\n const columnWidths: number[] = [0, 0];\n\n for (const row of this.rows) {\n const { key, value } = row;\n\n const keyWidth = stringWidth(key);\n const maxKeyWidth = Math.floor((tableWidth - 7) / 2);\n\n if (keyWidth > columnWidths[0]) {\n columnWidths[0] = Math.min(keyWidth, maxKeyWidth);\n columnWidths[1] = Math.max(0, tableWidth - columnWidths[0] - 7);\n }\n\n if (typeof value === 'string') {\n const valueWidth = Math.max(\n ...value.split('\\n').map((line) => stringWidth(line)),\n );\n\n if (valueWidth > columnWidths[1]) {\n columnWidths[1] = Math.min(\n valueWidth,\n tableWidth - columnWidths[0] - 7,\n );\n\n columnWidths[0] = Math.max(0, tableWidth - columnWidths[1] - 7);\n }\n } else if (row.kind === 'own') {\n let valueWidth = 0;\n\n if (isString(value)) {\n valueWidth = Math.max(\n ...value.split('\\n').map((line) => stringWidth(line)),\n );\n }\n\n if (valueWidth > columnWidths[1]) {\n columnWidths[1] = Math.min(\n valueWidth,\n tableWidth - columnWidths[0] - 7,\n );\n\n columnWidths[0] = Math.max(0, tableWidth - columnWidths[1] - 7);\n }\n } else if (value instanceof KeyValueASCIITable) {\n // Update column widths based on the nested table\n let nestedTableColumnWidths: number[] = [];\n\n if (canAutoAdjustWidthWhenPossible) {\n const minWidth = value.getMinimumWidth();\n\n const availableWidth = tableWidth - columnWidths[0] - 7;\n const adjustedWidth = clamp(availableWidth, minWidth, availableWidth);\n\n nestedTableColumnWidths = value.calculateColumnWidths({\n tableWidth: adjustedWidth,\n });\n } else {\n nestedTableColumnWidths = value.calculateColumnWidths();\n }\n\n const nestedTableWidth =\n nestedTableColumnWidths.reduce((sum, width) => sum + width, 0) +\n nestedTableColumnWidths.length * 3 -\n 1;\n\n const availableWidth = tableWidth - columnWidths[0] - 7;\n\n if (nestedTableWidth > availableWidth) {\n columnWidths[1] = availableWidth;\n } else {\n columnWidths[1] = Math.max(columnWidths[1], nestedTableWidth);\n }\n } else if (value instanceof MultiColumnASCIITable) {\n // Update column widths based on the nested multi-column table\n let nestedTableColumnWidths: number[] = [];\n\n if (canAutoAdjustWidthWhenPossible) {\n const minWidth = value.getMinimumWidth();\n\n const availableWidth = tableWidth - columnWidths[0] - 7;\n const adjustedWidth = clamp(availableWidth, minWidth, availableWidth);\n\n nestedTableColumnWidths = value.calculateColumnWidths({\n tableWidth: adjustedWidth,\n });\n } else {\n nestedTableColumnWidths = value.calculateColumnWidths();\n }\n\n const nestedTableWidth =\n nestedTableColumnWidths.reduce((sum, width) => sum + width, 0) +\n nestedTableColumnWidths.length * 3 -\n 1;\n\n const availableWidth = tableWidth - columnWidths[0] - 7;\n\n if (nestedTableWidth > availableWidth) {\n columnWidths[1] = availableWidth;\n } else {\n columnWidths[1] = Math.max(columnWidths[1], nestedTableWidth);\n }\n } else if (Array.isArray(value)) {\n for (const nestedCell of value) {\n const nestedKeyWidth = stringWidth(nestedCell.key);\n const maxNestedKeyWidth = Math.floor((tableWidth - 7) / 2);\n\n if (nestedKeyWidth > columnWidths[0]) {\n columnWidths[0] = Math.min(nestedKeyWidth, maxNestedKeyWidth);\n columnWidths[1] = Math.max(0, tableWidth - columnWidths[0] - 7);\n }\n\n if (typeof nestedCell.value === 'string') {\n const nestedValueWidth = Math.max(\n ...nestedCell.value.split('\\n').map((line) => stringWidth(line)),\n );\n\n if (nestedValueWidth > columnWidths[1]) {\n columnWidths[1] = Math.min(\n nestedValueWidth,\n tableWidth - columnWidths[0] - 7,\n );\n columnWidths[0] = Math.max(0, tableWidth - columnWidths[1] - 7);\n }\n }\n }\n }\n }\n\n return columnWidths;\n }\n\n private formatValue(\n value:\n | string\n | number\n | boolean\n | null\n | undefined\n | KeyValueASCIITable\n | MultiColumnASCIITable\n | NestedKeyValueEntry[],\n cellWidth: number,\n canAutoAdjustWidthWhenPossible: boolean,\n indent = '',\n ): string {\n if (typeof value === 'string') {\n return value;\n } else if (typeof value === 'number') {\n return String(value);\n } else if (typeof value === 'boolean') {\n return String(value);\n } else if (value === null) {\n return 'null';\n } else if (value === undefined) {\n return 'undefined';\n } else if (value instanceof KeyValueASCIITable) {\n let nestedTableLines: string[];\n\n if (canAutoAdjustWidthWhenPossible) {\n const minWidth = value.getMinimumWidth();\n\n const adjustedWidth = clamp(cellWidth, minWidth, cellWidth);\n\n nestedTableLines = value\n .toString({ tableWidth: adjustedWidth })\n .split('\\n');\n } else {\n nestedTableLines = value.toString().split('\\n');\n }\n\n const indentedLines = nestedTableLines.map((line) => `${indent}${line}`);\n\n return indentedLines.join('\\n');\n } else if (value instanceof MultiColumnASCIITable) {\n let nestedTableLines: string[];\n\n if (canAutoAdjustWidthWhenPossible) {\n const minWidth = value.getMinimumWidth();\n\n const adjustedWidth = clamp(cellWidth, minWidth, cellWidth);\n nestedTableLines = value\n .toString({ tableWidth: adjustedWidth })\n .split('\\n');\n } else {\n nestedTableLines = value.toString().split('\\n');\n }\n\n const indentedLines = nestedTableLines.map((line) => `${indent}${line}`);\n\n return indentedLines.join('\\n');\n } else if (Array.isArray(value)) {\n const nestedValueLines: string[] = [];\n\n for (const { key, value: nestedValue } of value) {\n const formattedKey = `${indent}${key}:`;\n const formattedValue = this.formatValue(\n nestedValue,\n cellWidth - indent.length - stringWidth(key) - 2,\n canAutoAdjustWidthWhenPossible,\n `${indent}`,\n );\n\n const wrappedSpacer = padRight('', 4, ' ');\n\n const wrappedValue = formattedValue\n .split('\\n')\n .map((line) => `${indent}${wrappedSpacer}${line}`);\n\n nestedValueLines.push(formattedKey);\n nestedValueLines.push(...wrappedValue);\n nestedValueLines.push('');\n }\n\n return nestedValueLines.slice(0, -1).join('\\n');\n } else {\n throw new TypeError('Invalid value type provided');\n }\n }\n\n private formatTableRowOnOwnRow(\n value: string,\n width: number,\n maxRowLength: number,\n ): string {\n const lines = value.split('\\n');\n\n const paddedLines = lines.map((line) => {\n const wrappedLines = ASCIITableUtils.wrapText(line, maxRowLength - 4);\n\n return wrappedLines\n .map((wrappedLine) => {\n const padding = padRight(\n '',\n width - stringWidth(wrappedLine) - 2,\n ' ',\n );\n\n return `${wrappedLine}${padding}`;\n })\n .join('\\n');\n });\n\n return paddedLines.join('\\n');\n }\n}\n","import type { NestedKeyValueEntry } from './ascii-tables/key-value-ascii-table';\nimport { KeyValueASCIITable } from './ascii-tables/key-value-ascii-table';\n\nfunction safeStringify(value: unknown): string {\n if (value === null || value === undefined) {\n return String(value);\n }\n\n switch (typeof value) {\n case 'string':\n return value;\n case 'number':\n case 'boolean':\n case 'bigint':\n return String(value);\n case 'object':\n return JSON.stringify(value);\n case 'function':\n return '[Function]';\n case 'symbol':\n return value.toString();\n default:\n // This should never happen, but satisfy the linter\n return String(value as string | number | boolean);\n }\n}\n\nexport function errorToString(error: unknown, maxRowLength = 80): string {\n const table = errorToASCIITable(error, maxRowLength);\n\n return table.toString();\n}\n\nfunction errorToASCIITable(\n error: unknown,\n maxRowLength: number,\n): KeyValueASCIITable {\n const table = new KeyValueASCIITable({\n tableWidth: maxRowLength,\n autoAdjustWidthWhenPossible: true,\n });\n\n if (error && typeof error === 'object') {\n const err = error as Record<string, unknown>;\n table.addRow('Key', 'Value');\n\n if (err['message']) {\n table.addRow('Message', safeStringify(err['message']));\n }\n\n if (err['name']) {\n table.addRow('Name', safeStringify(err['name']));\n }\n\n if (err['code']) {\n table.addRow('Code', safeStringify(err['code']));\n }\n\n if (err['errno']) {\n table.addRow('Errno', safeStringify(err['errno']));\n }\n\n // other conventional that might be used to enhance the error object\n if (err['errPrefix']) {\n table.addRow('Prefix', safeStringify(err['errPrefix']));\n }\n\n if (err['errType']) {\n table.addRow('errType', safeStringify(err['errType']));\n }\n\n if (err['errCode']) {\n table.addRow('errCode', safeStringify(err['errCode']));\n }\n\n if (err['additionalInfo']) {\n const additionalInfo = err['additionalInfo'] as Record<string, unknown>;\n const sensitiveFieldNames =\n (err['sensitiveFieldNames'] as string[]) || [];\n\n for (const key in additionalInfo) {\n if (sensitiveFieldNames.includes(key)) {\n table.addRow(`AdditionalInfo.${key}`, '***');\n } else {\n const value = additionalInfo[key];\n\n table.addRow(\n `AdditionalInfo.${key}`,\n stringifyValue(value, table, maxRowLength),\n );\n }\n }\n }\n\n if (err['stack']) {\n table.addValueOnSeparateRow('Stack', safeStringify(err['stack']));\n }\n }\n\n return table;\n}\n\nfunction stringifyValue(\n value: unknown,\n table: KeyValueASCIITable,\n maxRowLength: number,\n): string | KeyValueASCIITable | NestedKeyValueEntry[] {\n if (typeof value === 'string') {\n return value;\n } else if (Array.isArray(value)) {\n // Handle arrays differently\n return value\n .map((item) => {\n const result = stringifyValue(item, table, maxRowLength);\n // Convert complex types to strings for joining\n if (typeof result === 'string') {\n return result;\n } else if (result instanceof KeyValueASCIITable) {\n return result.toString();\n } else {\n return JSON.stringify(result);\n }\n })\n .join(', ');\n } else if (typeof value === 'object' && value !== null) {\n if (value instanceof Error) {\n return errorToASCIITable(value, maxRowLength - 4);\n } else {\n // Handle objects differently\n const entries: NestedKeyValueEntry[] = Object.entries(value).map(\n ([key, val]) => ({\n key,\n value: stringifyValue(val, table, maxRowLength - 4),\n }),\n );\n\n return entries;\n }\n } else {\n return String(value);\n }\n}\n","// Helper from https://github.com/then/is-promise/tree/master\n// For some reason the @types/is-promise package stopped being picked up on\n\nexport function isPromise(obj: unknown): obj is Promise<unknown> {\n return (\n !!obj &&\n (typeof obj === 'object' || typeof obj === 'function') &&\n // @ts-expect-error - obj is checked to be object/function, then property access works at runtime\n typeof obj['then'] === 'function'\n );\n}\n","export function isFunction(value: unknown): boolean {\n return typeof value === 'function' || value instanceof Function;\n}\n","import { errorToString } from './error-to-string';\nimport { isPromise } from './is-promise';\nimport { isFunction } from './is-function';\nimport { DOUBLE_EOL } from './constants';\n\n/**\n * Safely handles a callback function by catching any errors and reporting them\n * using the global `reportError` event (standard API available in Node.js 15+, Bun, Deno, and browsers).\n * This function can seamlessly handle both synchronous and asynchronous (Promise-based) callback functions.\n *\n * Errors are dispatched as ErrorEvent objects with type 'reportError' via `globalThis.dispatchEvent()`.\n * You can listen for these errors using `globalThis.addEventListener('reportError', handler)`.\n *\n * This function is a \"fire-and-forget\" type of function, meaning it doesn't wait\n * for the callback to complete and doesn't return any result or error. If you need\n * to handle the result or error of the callback, consider using the\n * `safeHandleCallbackAndWait` function instead.\n *\n * @param {string} callbackName - The name of the callback function, used for error reporting.\n * @param {unknown} callback - The callback function to be executed. It can be either a\n * synchronous function or a function that returns a Promise.\n * @param {...unknown[]} args - Additional arguments to pass to the callback function.\n */\n\nexport function safeHandleCallback(\n callbackName: string,\n callback: unknown,\n ...args: unknown[]\n): void {\n const handleError = (error: Error): void => {\n // Dispatch error using the standard reportError event API\n // Available in Node.js 15+, Bun, Deno, and browsers\n if (\n typeof (globalThis as Record<string, unknown>).dispatchEvent ===\n 'function'\n ) {\n (\n globalThis as unknown as {\n dispatchEvent: (event: Event) => void;\n }\n ).dispatchEvent(\n new ErrorEvent('reportError', {\n error: new Error(\n `Error in a callback ${callbackName}: ${DOUBLE_EOL}${errorToString(error)}`,\n ),\n }),\n );\n }\n };\n\n if (isFunction(callback)) {\n try {\n // We need to cast callback to the appropriate function type now\n const result = (callback as (...args: unknown[]) => unknown)(...args);\n\n if (isPromise(result)) {\n // Fire-and-forget async callback\n result.catch((error: unknown) => {\n handleError(error as Error);\n });\n }\n } catch (error) {\n handleError(error as Error);\n }\n } else {\n handleError(\n new Error(`Callback provided for ${callbackName} is not a function`),\n );\n }\n}\n\ninterface CallbackResult<T> {\n success: boolean;\n value?: T;\n error?: Error;\n}\n\n/**\n * Safely handles a callback function by catching any errors and reporting them\n * using the global `reportError` event (standard API available in Node.js 15+, Bun, Deno, and browsers).\n * This function can seamlessly handle both synchronous and asynchronous (Promise-based) callback\n * functions, and it waits for the callback to complete before returning the result or an error.\n *\n * Errors are dispatched as ErrorEvent objects with type 'reportError' via `globalThis.dispatchEvent()`.\n * You can listen for these errors using `globalThis.addEventListener('reportError', handler)`.\n *\n * @param {string} callbackName - The name of the callback function, used for error reporting.\n * @param {unknown} callback - The callback function to be executed. It can be either a\n * synchronous function or a function that returns a Promise.\n * @param {...unknown[]} args - Additional arguments to pass to the callback function.\n * @returns {Promise<CallbackResult<unknown>>} - A promise that resolves with an object containing\n * the success status, value (if any), and error (if any).\n */\n\nexport async function safeHandleCallbackAndWait<T>(\n callbackName: string,\n callback: unknown,\n ...args: unknown[]\n): Promise<CallbackResult<T>> {\n const handleError = (error: Error): CallbackResult<T> => {\n // Dispatch error using the standard reportError event API\n // Available in Node.js 15+, Bun, Deno, and browsers\n if (\n typeof (globalThis as Record<string, unknown>).dispatchEvent ===\n 'function'\n ) {\n (\n globalThis as unknown as {\n dispatchEvent: (event: Event) => void;\n }\n ).dispatchEvent(\n new ErrorEvent('reportError', {\n error: new Error(\n `Error in a callback ${callbackName}: ${DOUBLE_EOL}${errorToString(error)}`,\n ),\n }),\n );\n }\n\n return { success: false, error };\n };\n\n if (isFunction(callback)) {\n try {\n // We need to cast callback to the appropriate function type now\n const result = (callback as (...args: unknown[]) => unknown)(...args);\n\n if (isPromise(result)) {\n // Wait for the async callback to complete\n const value = await (result as Promise<T>);\n\n return { success: true, value };\n } else {\n return { success: true, value: result as T };\n }\n } catch (error) {\n return handleError(error as Error);\n }\n } else {\n return handleError(\n new Error(`Callback provided for ${callbackName} is not a function`),\n );\n }\n}\n","import qs from 'qs';\nimport {\n matchesWildcardDomain,\n normalizeDomain,\n} from '../domain-utils/domain-utils';\nimport type {\n ContentType,\n RequestPhaseName,\n HTTPClientConfig,\n AdapterType,\n} from './types';\n\n/**\n * If `path` is an absolute HTTP(S) URL, returns its canonical `href` (normalized\n * scheme/host casing). Otherwise `null`. Protocol-relative `//host` is handled\n * separately in `buildURL`.\n *\n * Rules differ from `resolveAbsoluteURL` (which accepts any absolute scheme).\n * One parse here per request is negligible next to network I/O.\n */\nfunction tryAbsoluteWebHref(path: string): string | null {\n if (!path || path.startsWith('//')) {\n return null;\n }\n\n try {\n const u = new URL(path);\n if (u.protocol === 'http:' || u.protocol === 'https:') {\n return u.href;\n }\n } catch {\n // not parseable as absolute\n }\n\n return null;\n}\n\n/**\n * Builds a request URL string from `baseURL`, `path`, and optional query params\n * (`qs` — nested objects and arrays supported).\n *\n * **Relative paths (usual case)** — When `baseURL` is set and `path` is not\n * absolute, `path` is joined to `baseURL` (leading slash normalized). Example:\n * `baseURL: https://api.test`, `path: /v1/users` → `https://api.test/v1/users`.\n *\n * **Absolute / protocol-relative `path` (escape hatch)** — If `path` is a full\n * `http:` or `https:` URL, it is **not** prefixed with `baseURL` (after\n * normalization via `URL#href`). The same applies to protocol-relative URLs\n * (`//cdn.example/x`): they are left for {@link resolveAbsoluteURL} to resolve\n * using the client `baseURL`’s scheme. Use this for one-off cross-origin calls,\n * CDN assets, or URLs returned by APIs; for strict per-origin clients, prefer\n * relative paths and a dedicated client or `HTTPClient.createSubClient()` per\n * origin.\n */\nexport function buildURL(\n baseURL: string | undefined,\n path: string,\n params?: Record<string, unknown>,\n): string {\n let url: string;\n\n const absoluteHref = tryAbsoluteWebHref(path);\n\n if (baseURL && absoluteHref === null && !path.startsWith('//')) {\n // Avoid double slashes when joining base + path\n const base = baseURL.endsWith('/') ? baseURL.slice(0, -1) : baseURL;\n const p = path.startsWith('/') ? path : `/${path}`;\n url = `${base}${p}`;\n } else if (absoluteHref !== null) {\n url = absoluteHref;\n } else {\n url = path;\n }\n\n if (params && Object.keys(params).length > 0) {\n const [urlWithoutHash, hash = ''] = url.split('#', 2);\n const queryStartIndex = urlWithoutHash.indexOf('?');\n\n if (queryStartIndex === -1) {\n const queryString = qs.stringify(params, { addQueryPrefix: true });\n url = `${urlWithoutHash}${queryString}${hash ? `#${hash}` : ''}`;\n } else {\n const basePath = urlWithoutHash.slice(0, queryStartIndex);\n const existingQuery = urlWithoutHash.slice(queryStartIndex + 1);\n // Fragments are preserved only as part of the caller's URL string.\n // They are not transmitted in HTTP requests, but keeping them intact\n // makes buildURL safer as a general-purpose URL composition helper.\n const mergedParams = {\n ...qs.parse(existingQuery),\n ...params,\n };\n\n const queryString = qs.stringify(mergedParams, { addQueryPrefix: true });\n url = `${basePath}${queryString}${hash ? `#${hash}` : ''}`;\n }\n }\n\n return url;\n}\n\n/**\n * Best-effort absolute URL for logging, redirects, and hop metadata.\n *\n * - If `url` parses as an absolute URL (has a scheme), returns normalized `href`.\n * - Otherwise, when `baseURL` is set, resolves `url` against it (path-relative,\n * same-host relative, protocol-relative `//host`, query-only, etc.).\n * - If neither works, returns `url` unchanged (callers without `baseURL` may still\n * see path-only strings).\n */\nexport function resolveAbsoluteURL(url: string, baseURL?: string): string {\n if (!url) {\n return url;\n }\n\n try {\n return new URL(url).href;\n } catch {\n // Not a standalone absolute URL\n }\n\n if (baseURL) {\n try {\n const base = baseURL.endsWith('/') ? baseURL : `${baseURL}/`;\n return new URL(url, base).href;\n } catch {\n // fall through\n }\n }\n\n return url;\n}\n\n/**\n * Browser-aware absolute URL resolution used by HTTPClient before interceptors\n * and adapter dispatch. Starts with normal baseURL resolution, then falls back\n * to the current page/worker location when running in a browser-like runtime.\n */\nexport function resolveAbsoluteURLForRuntime(\n url: string,\n baseURL: string | undefined,\n isBrowserRuntime: boolean,\n): string {\n const resolved = resolveAbsoluteURL(url, baseURL);\n\n if (\n !isBrowserRuntime ||\n resolved.startsWith('http://') ||\n resolved.startsWith('https://')\n ) {\n return resolved;\n }\n\n const browserBase = getBrowserResolutionBase();\n\n if (!browserBase) {\n return resolved;\n }\n\n return resolveAbsoluteURL(resolved, browserBase);\n}\n\nfunction getBrowserResolutionBase(): string | undefined {\n if (\n typeof document !== 'undefined' &&\n typeof document.baseURI === 'string' &&\n document.baseURI\n ) {\n return document.baseURI;\n }\n\n if (\n typeof window !== 'undefined' &&\n window.location &&\n typeof window.location.href === 'string' &&\n window.location.href\n ) {\n return window.location.href;\n }\n\n const globalLocation = (globalThis as { location?: { href?: unknown } })\n .location;\n\n if (\n globalLocation &&\n typeof globalLocation.href === 'string' &&\n globalLocation.href\n ) {\n return globalLocation.href;\n }\n\n const selfLocation = (\n globalThis as { self?: { location?: { href?: unknown } } }\n ).self?.location;\n\n if (\n selfLocation &&\n typeof selfLocation.href === 'string' &&\n selfLocation.href\n ) {\n return selfLocation.href;\n }\n\n return undefined;\n}\n\n/**\n * Normalizes header keys to lowercase.\n */\nexport function normalizeHeaders(\n headers: Record<string, string>,\n): Record<string, string> {\n const result: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(headers)) {\n result[key.toLowerCase()] = value;\n }\n\n return result;\n}\n\n/**\n * Merges multiple request-header objects, normalizing keys to lowercase.\n * Later objects win on conflict. Array values replace earlier scalars/arrays\n * wholesale, and single-item arrays are collapsed back to a plain string.\n */\nexport function mergeHeaders(\n ...headerSets: Array<Record<string, string | string[]> | undefined>\n): Record<string, string | string[]> {\n const result: Record<string, string | string[]> = {};\n for (const headers of headerSets) {\n if (!headers) {\n continue;\n }\n\n for (const [key, value] of Object.entries(headers)) {\n result[key.toLowerCase()] = Array.isArray(value)\n ? normalizeMergedHeaderArray(value)\n : String(value);\n }\n }\n\n return result;\n}\n\nfunction normalizeMergedHeaderArray(value: string[]): string | string[] {\n const normalized = value.map((item) => String(item));\n return normalized.length === 1 ? normalized[0] : normalized;\n}\n\nexport function mergeObservedHeaders(\n ...headerSets: Array<Record<string, string | string[]> | undefined>\n): Record<string, string | string[]> {\n const result: Record<string, string | string[]> = {};\n\n for (const headers of headerSets) {\n if (!headers) {\n continue;\n }\n\n for (const [key, value] of Object.entries(headers)) {\n result[key.toLowerCase()] = Array.isArray(value)\n ? value.map((item) => String(item))\n : String(value);\n }\n }\n\n return result;\n}\n\n/**\n * Parses the Content-Type header into a ContentType enum value.\n */\nexport function parseContentType(\n contentTypeHeader: string | undefined,\n): ContentType {\n if (!contentTypeHeader) {\n return 'binary';\n } else {\n const lower = contentTypeHeader.trim().toLowerCase();\n\n if (lower.includes('application/json') || lower.includes('+json')) {\n return 'json';\n } else if (lower.startsWith('text/')) {\n return 'text';\n } else if (lower.includes('application/x-www-form-urlencoded')) {\n return 'text';\n } else {\n return 'binary';\n }\n }\n}\n\n/**\n * Validates adapter/runtime combinations and redirect config before a client\n * is constructed, so unsupported browser-only/server-only options fail fast\n * with clear errors instead of surfacing later during request dispatch.\n */\nexport function assertSupportedAdapterRuntimeAndConfig(\n config: HTTPClientConfig,\n adapterType: AdapterType,\n isBrowserRuntime: boolean,\n): void {\n if (\n config.baseURL !== undefined &&\n requiresAbsoluteBaseURL(adapterType, isBrowserRuntime)\n ) {\n assertValidBaseURL(config.baseURL);\n }\n\n if (config.maxRedirects !== undefined && config.followRedirects !== true) {\n throw new Error('HTTPClient maxRedirects requires followRedirects: true.');\n }\n\n if (\n config.followRedirects === true &&\n config.maxRedirects !== undefined &&\n config.maxRedirects < 1\n ) {\n throw new Error(\n 'HTTPClient maxRedirects must be greater than or equal to 1 when followRedirects is true.',\n );\n }\n\n if (adapterType === 'xhr' && config.followRedirects === true) {\n throw new Error(\n 'HTTPClient redirect handling is not supported with XHR adapter. Set followRedirects: false or use a different adapter/runtime.',\n );\n }\n\n if (adapterType === 'xhr' && !hasXMLHttpRequestGlobal()) {\n throw new Error(\n 'HTTPClient XHR adapter is not supported when XMLHttpRequest is unavailable. Use a browser runtime, install a test shim, or switch to the FetchAdapter/NodeAdapter.',\n );\n }\n\n if (!isBrowserRuntime) {\n return;\n }\n\n if (adapterType === 'node') {\n throw new Error(\n 'HTTPClient Node adapter is not supported in browser environments.',\n );\n }\n\n // MockAdapter is intentionally allowed in browser runtimes: it is an\n // in-memory test adapter, so cookie jars and redirect following are local\n // simulation features rather than forbidden browser networking controls.\n if ((adapterType === 'fetch' || adapterType === 'xhr') && config.cookieJar) {\n throw new Error(\n `HTTPClient cookieJar is not supported with ${adapterType === 'fetch' ? 'FetchAdapter' : 'XHR adapter'} in browser environments. Browsers manage cookies automatically.`,\n );\n }\n\n if ((adapterType === 'fetch' || adapterType === 'xhr') && config.userAgent) {\n throw new Error(\n `HTTPClient userAgent is not supported with ${adapterType === 'fetch' ? 'FetchAdapter' : 'XHR adapter'} in browser environments. Browsers do not allow overriding the User-Agent header.`,\n );\n }\n\n if (adapterType === 'fetch' && config.followRedirects === true) {\n throw new Error(\n 'HTTPClient redirect handling is not supported with FetchAdapter in browser environments. Set followRedirects: false or use a server runtime.',\n );\n }\n}\n\nfunction requiresAbsoluteBaseURL(\n adapterType: AdapterType,\n isBrowserRuntime: boolean,\n): boolean {\n if (adapterType === 'node' || adapterType === 'mock') {\n return true;\n }\n\n if (adapterType === 'fetch' && !isBrowserRuntime) {\n return true;\n }\n\n return false;\n}\n\nfunction hasXMLHttpRequestGlobal(): boolean {\n return (\n typeof globalThis !== 'undefined' &&\n typeof (globalThis as { XMLHttpRequest?: unknown }).XMLHttpRequest ===\n 'function'\n );\n}\n\n/**\n * Converts a Headers object (from fetch) into AdapterResponse headers.\n * `set-cookie` is extracted as `string[]` via `getSetCookie()` — the Fetch API\n * would otherwise incorrectly comma-join multiple Set-Cookie values.\n * All other headers are extracted as plain strings.\n */\nexport function extractFetchHeaders(\n headers: Headers,\n): Record<string, string | string[]> {\n const result: Record<string, string | string[]> = {};\n\n for (const [key, value] of headers.entries()) {\n const lower = key.toLowerCase();\n\n if (lower !== 'set-cookie') {\n result[lower] = value;\n }\n }\n\n // Use getSetCookie() when available (Bun, Node 18.14+, modern browsers)\n if (typeof headers.getSetCookie === 'function') {\n const setCookies = headers.getSetCookie();\n\n if (setCookies.length > 0) {\n result['set-cookie'] = setCookies;\n }\n } else {\n // Fallback: headers.get() comma-joins — split on ', ' is unreliable for\n // cookies but better than nothing on older runtimes\n const raw = headers.get('set-cookie');\n\n if (raw) {\n result['set-cookie'] = [raw];\n }\n }\n\n return result;\n}\n\n/**\n * Lowercases all keys on adapter/response header objects. `HTTPClient` runs\n * this on each adapter response before {@link CookieJar.processResponseHeaders}.\n * The jar also normalizes so the same shapes work when feeding headers directly.\n *\n * - Non–`set-cookie` values: if an array appears (unexpected), the first\n * element is kept when read via {@link scalarHeader}.\n * - `set-cookie`: stored as `string[]` — each array entry is one full\n * `Set-Cookie` header line (one cookie). A single string value becomes a\n * one-element array. If the same header appears under keys that differ only\n * by case, those lines are appended in the order they appear on the input\n * object.\n */\nexport function normalizeAdapterResponseHeaders(\n headers: Record<string, string | string[]>,\n): Record<string, string | string[]> {\n const result: Record<string, string | string[]> = {};\n\n for (const [key, value] of Object.entries(headers)) {\n const lower = key.toLowerCase();\n\n if (lower === 'set-cookie') {\n const chunk = Array.isArray(value) ? value : [value];\n const existing = result[lower];\n\n if (existing === undefined) {\n result[lower] = chunk;\n } else {\n const existingLines = Array.isArray(existing) ? existing : [existing];\n result[lower] = [...existingLines, ...chunk];\n }\n } else {\n result[lower] = Array.isArray(value) ? (value[0] ?? '') : value;\n }\n }\n\n return result;\n}\n\n/**\n * Reads a single-valued header when keys are already lowercase (e.g. after\n * {@link mergeHeaders} on requests or {@link normalizeAdapterResponseHeaders}\n * on responses). If the stored value is `string[]`, returns the first entry.\n */\nexport function scalarHeader(\n headers: Record<string, string | string[]>,\n lowercaseName: string,\n): string | undefined {\n const v = headers[lowercaseName];\n\n if (v === undefined) {\n return undefined;\n }\n\n return Array.isArray(v) ? v[0] : v;\n}\n\n/**\n * Resolves a redirect target from response headers when the adapter can\n * observe a redirect response but the client may not follow it itself.\n */\nexport function resolveDetectedRedirectURL(\n requestURL: string,\n status: number,\n headers: Record<string, string | string[]>,\n baseURL?: string,\n): string | undefined {\n if (![301, 302, 303, 307, 308].includes(status)) {\n return undefined;\n }\n\n const location = scalarHeader(headers, 'location');\n\n if (!location) {\n return undefined;\n }\n\n try {\n const absoluteRequestURL = resolveAbsoluteURL(requestURL, baseURL);\n return new URL(location, absoluteRequestURL).toString();\n } catch {\n return location;\n }\n}\n\nexport function assertValidBaseURL(\n baseURL: string,\n fieldName = 'baseURL',\n): void {\n try {\n const url = new URL(baseURL);\n\n if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n throw new Error('unsupported protocol');\n }\n } catch {\n throw new Error(\n `HTTPClient ${fieldName} must be an absolute http(s) URL (for example \"https://api.example.com\").`,\n );\n }\n}\n\n/**\n * Detects whether the current runtime looks like a browser environment.\n */\nexport function isBrowserEnvironment(): boolean {\n if (typeof globalThis === 'undefined') {\n return false;\n }\n\n if ('window' in globalThis && 'document' in globalThis) {\n return true;\n }\n\n const workerGlobalScope = (\n globalThis as {\n WorkerGlobalScope?: abstract new (...args: never[]) => unknown;\n }\n ).WorkerGlobalScope;\n\n if (\n typeof workerGlobalScope === 'function' &&\n (globalThis as { self?: unknown }).self instanceof workerGlobalScope\n ) {\n return true;\n }\n\n const constructorName = globalThis.constructor?.name;\n\n return (\n !('window' in globalThis) &&\n !('document' in globalThis) &&\n typeof constructorName === 'string' &&\n constructorName.endsWith('WorkerGlobalScope')\n );\n}\n\n/**\n * Serializes the request body and returns the body + inferred content-type.\n * If `formData` is provided, it takes precedence over `body`.\n */\nexport function serializeBody(body: unknown): {\n body: string | Uint8Array | FormData | null;\n contentType: string | null;\n} {\n assertSupportedRequestBody(body);\n\n if (body instanceof FormData) {\n return { body, contentType: null }; // browser/runtime sets multipart boundary automatically\n } else if (body === undefined || body === null) {\n return { body: null, contentType: null };\n } else if (typeof body === 'string') {\n return { body, contentType: 'text/plain; charset=utf-8' };\n } else if (body instanceof Uint8Array) {\n return { body, contentType: 'application/octet-stream' };\n } else if (Array.isArray(body) || isPlainJSONBodyObject(body)) {\n return {\n body: JSON.stringify(body),\n contentType: 'application/json; charset=utf-8',\n };\n } else {\n throw new Error(\n 'Unsupported request body type. Supported types: string, Uint8Array, FormData, plain object, array, null, and undefined.',\n );\n }\n}\n\nexport function assertSupportedRequestBody(body: unknown): void {\n if (\n body === undefined ||\n body === null ||\n typeof body === 'string' ||\n body instanceof Uint8Array ||\n body instanceof FormData ||\n Array.isArray(body) ||\n isPlainJSONBodyObject(body)\n ) {\n return;\n }\n\n throw new Error(\n 'Unsupported request body type. Supported types: string, Uint8Array, FormData, plain object, array, null, and undefined.',\n );\n}\n\nexport function isPlainJSONBodyObject(\n value: unknown,\n): value is Record<string, unknown> {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n return false;\n }\n\n const prototype = Reflect.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n\n/**\n * Extracts the hostname from a URL string. Returns empty string on failure.\n */\nexport function extractHostname(url: string): string {\n try {\n return new URL(url).hostname;\n } catch {\n return '';\n }\n}\n\n/**\n * Wildcard hostname matching backed by {@link matchesWildcardDomain}.\n *\n * - `*` — global wildcard, matches any valid hostname including apex domains\n * - `*.example.com` — matches exactly one subdomain label (`api.example.com`) but not deeper levels or the apex\n * - `**.example.com` — matches one or more subdomain labels (`api.example.com`, `a.b.example.com`) but not the apex\n * - Exact patterns (no `*`) — normalized comparison, case-insensitive\n * - PSL tail guard active: `*.com`, `**.co.uk`, etc. never match\n * - Pseudo-TLD suffix wildcards are rejected just like PSL tails (`*.localhost`, `*.local`, etc.)\n */\nexport function matchesHostPattern(hostname: string, pattern: string): boolean {\n if (pattern.includes('*')) {\n return matchesWildcardDomain(hostname, pattern);\n }\n\n const normalizedHostname = normalizeDomain(hostname);\n const normalizedPattern = normalizeDomain(pattern);\n return normalizedHostname !== '' && normalizedHostname === normalizedPattern;\n}\n\n/**\n * Checks whether a dot-path key exists in a nested object.\n * Arrays are not traversed — only plain objects at each segment.\n */\nfunction hasNestedKey(obj: Record<string, unknown>, path: string): boolean {\n const parts = path.split('.');\n let current: unknown = obj;\n\n for (const part of parts) {\n if (!current || typeof current !== 'object' || Array.isArray(current)) {\n return false;\n }\n\n if (!(part in (current as Record<string, unknown>))) {\n return false;\n }\n\n current = (current as Record<string, unknown>)[part];\n }\n\n return true;\n}\n\nfunction normalizeMimeType(value: string): string {\n return value.split(';', 1)[0].trim().toLowerCase();\n}\n\nfunction matchesContentTypePattern(\n actualHeader: string,\n pattern: string,\n): boolean {\n const actual = normalizeMimeType(actualHeader);\n const expected = normalizeMimeType(pattern);\n\n if (!actual || !expected) {\n return false;\n }\n\n if (expected.endsWith('/*')) {\n const expectedType = expected.slice(0, -2);\n const slashIndex = actual.indexOf('/');\n\n if (slashIndex === -1) {\n return false;\n }\n\n return actual.slice(0, slashIndex) === expectedType;\n }\n\n return actual === expected;\n}\n\n/**\n * Tests whether a request context matches an interceptor/observer filter.\n *\n * Each filter field is optional — omitting it skips that check entirely.\n * All specified fields must match for the function to return true.\n * Within each field, values are matched with OR logic (any one match is sufficient).\n *\n * - `phases`: **OR** allowlist on `phaseType` ({@link RequestPhaseName}). Skipped when\n * `filter.phases` is omitted or empty.\n * - `statusCodes`: skipped if `context.status` is absent.\n * - `methods`: skipped if `context.method` is absent.\n * - `hosts`: supports exact hostnames and wildcard patterns. `*.example.com` matches\n * exactly one subdomain label; `**.example.com` matches any depth. Neither matches the\n * apex — list it explicitly. PSL tail guard prevents `*.com`-style patterns. `*` is a\n * global wildcard that matches any valid hostname. Skipped if `context.requestURL` is absent.\n * - `schemes`: `'http'` or `'https'`. `requestURL` is absolute whenever the\n * request could be resolved before dispatch. For `MockAdapter`, path-only\n * requests without a client `baseURL` are materialized as `http://localhost/...`;\n * browser adapters fall back to `window.location`, and the Node adapter requires\n * absolute URLs. Skipped only when `requestURL` is absent.\n * - `bodyContainsKeys`: supports dot paths (e.g. `data.results`). Each segment in\n * the path must resolve to a plain object for traversal to continue — the final\n * value can be anything (array, string, null, etc). Array indexing is not supported.\n * Skipped when `kind` is `'error'`.\n */\nexport function matchesFilter(\n filter: {\n statusCodes?: number[];\n methods?: string[];\n bodyContainsKeys?: string[];\n hosts?: string[];\n schemes?: ('http' | 'https')[];\n phases?: RequestPhaseName[];\n contentTypes?: ContentType[];\n contentTypeHeaders?: string[];\n },\n context: {\n status?: number;\n method?: string;\n body?: unknown;\n requestURL?: string;\n contentType?: ContentType;\n contentTypeHeader?: string;\n },\n phaseType: RequestPhaseName,\n kind: 'request' | 'response' | 'error',\n): boolean {\n if (\n filter.phases &&\n filter.phases.length > 0 &&\n !filter.phases.includes(phaseType)\n ) {\n return false;\n }\n\n if (filter.statusCodes && context.status !== undefined) {\n if (!filter.statusCodes.includes(context.status)) {\n return false;\n }\n }\n\n if (filter.methods && context.method) {\n if (!filter.methods.includes(context.method)) {\n return false;\n }\n }\n\n if (filter.contentTypes && filter.contentTypes.length > 0) {\n if (\n !context.contentType ||\n !filter.contentTypes.includes(context.contentType)\n ) {\n return false;\n }\n }\n\n if (filter.contentTypeHeaders && filter.contentTypeHeaders.length > 0) {\n if (\n !context.contentTypeHeader ||\n !filter.contentTypeHeaders.some((pattern) =>\n matchesContentTypePattern(context.contentTypeHeader as string, pattern),\n )\n ) {\n return false;\n }\n }\n\n if (\n kind !== 'error' &&\n filter.bodyContainsKeys &&\n filter.bodyContainsKeys.length > 0\n ) {\n if (\n !context.body ||\n typeof context.body !== 'object' ||\n Array.isArray(context.body)\n ) {\n return false;\n }\n\n const body = context.body as Record<string, unknown>;\n\n if (!filter.bodyContainsKeys.some((k) => hasNestedKey(body, k))) {\n return false;\n }\n }\n\n if (filter.hosts && context.requestURL) {\n const hostname = extractHostname(context.requestURL);\n\n if (\n !filter.hosts.some((pattern: string) =>\n matchesHostPattern(hostname, pattern),\n )\n ) {\n return false;\n }\n }\n\n if (filter.schemes && filter.schemes.length > 0 && context.requestURL) {\n let scheme: 'http' | 'https' | null = null;\n\n try {\n const parsedScheme = new URL(context.requestURL).protocol.replace(\n ':',\n '',\n );\n\n if (parsedScheme === 'http' || parsedScheme === 'https') {\n scheme = parsedScheme;\n }\n } catch {\n scheme = null;\n }\n\n if (!scheme || !filter.schemes.includes(scheme)) {\n return false;\n }\n }\n\n return true;\n}\n","import { getDomain, getSubdomain, getPublicSuffix } from 'tldts';\nimport {\n isAllWildcards,\n hasPartialLabelWildcard,\n checkDNSLength,\n normalizeDomain,\n isIPv6,\n toAsciiDots,\n canonicalizeBracketedIPv6Content,\n matchesMultiLabelPattern,\n extractFixedTailAfterLastWildcard,\n isIPAddress,\n normalizeWildcardPattern,\n INTERNAL_PSEUDO_TLDS,\n INVALID_DOMAIN_CHARS,\n MAX_LABELS,\n} from './helpers';\n\nexport function safeParseURL(input: string): URL | null {\n try {\n return new URL(input);\n } catch {\n return null;\n }\n}\n\nfunction hasValidWildcardOriginHost(url: URL): boolean {\n return normalizeDomain(url.hostname) !== '';\n}\n\nfunction extractAuthority(input: string, schemeIdx: number): string {\n const afterScheme = input.slice(schemeIdx + 3);\n const cut = Math.min(\n ...[\n afterScheme.indexOf('/'),\n afterScheme.indexOf('?'),\n afterScheme.indexOf('#'),\n ].filter((i) => i !== -1),\n );\n\n return cut === Infinity ? afterScheme : afterScheme.slice(0, cut);\n}\n\nfunction hasDanglingPortInAuthority(input: string): boolean {\n const schemeIdx = input.indexOf('://');\n if (schemeIdx === -1) {\n return false;\n }\n\n const authority = extractAuthority(input, schemeIdx);\n const at = authority.lastIndexOf('@');\n const hostPort = at === -1 ? authority : authority.slice(at + 1);\n\n return hostPort.endsWith(':');\n}\n\n/**\n * Normalize a bare origin for consistent comparison.\n * Returns the canonical origin form with a normalized hostname,\n * lowercase scheme, no trailing slash, and default ports removed\n * (80 for http, 443 for https).\n */\nexport function normalizeOrigin(origin: string): string {\n // Preserve literal \"null\" origin exactly; treat all other invalids as empty sentinel\n if (origin === 'null') {\n return 'null';\n }\n\n // Normalize Unicode dots before URL parsing for browser compatibility\n // Chrome allows URLs like https://127。0。0。1\n const normalizedOrigin = toAsciiDots(origin);\n if (hasDanglingPortInAuthority(normalizedOrigin)) {\n return '';\n }\n\n const url = safeParseURL(normalizedOrigin);\n if (url) {\n // Only normalize bare origins. Allow a single trailing slash so callers\n // can pass values like \"https://example.com/\" without broadening real paths.\n if (\n url.username ||\n url.password ||\n (url.pathname && url.pathname !== '/') ||\n url.search ||\n url.hash\n ) {\n return '';\n }\n\n // Normalize hostname with punycode\n const normalizedHostname = normalizeDomain(url.hostname);\n\n // If hostname normalization fails (pathological IDN), return original origin\n // to avoid emitting values like \"https://\" with an empty host.\n if (normalizedHostname === '') {\n return '';\n }\n\n // Preserve brackets for IPv6 hosts; avoid double-bracketing if already present\n let host: string;\n // Extract the raw bracketed host (if present) from the authority portion only\n // to prevent matching brackets in path/query/fragment portions of full URLs.\n const schemeSep = normalizedOrigin.indexOf('://');\n const authority = extractAuthority(normalizedOrigin, schemeSep);\n const bracketMatch = authority.match(/\\[([^\\]]+)\\]/);\n const rawBracketContent = bracketMatch ? bracketMatch[1] : null;\n\n // Decode only for IPv6 detection, not for output\n const hostnameForIpv6Check = (\n rawBracketContent ? rawBracketContent : normalizedHostname\n )\n .replace(/%25/g, '%')\n .toLowerCase();\n\n if (isIPv6(hostnameForIpv6Check)) {\n // Canonicalize bracket content using shared helper (do not decode %25)\n const raw = rawBracketContent\n ? rawBracketContent\n : normalizedHostname.replace(/^\\[|\\]$/g, '');\n\n const canon = canonicalizeBracketedIPv6Content(raw);\n\n host = `[${canon}]`;\n } else {\n host = normalizedHostname;\n }\n\n // Normalize default ports for http/https\n let port = '';\n const protocolLower = url.protocol.toLowerCase();\n const defaultPort =\n protocolLower === 'https:'\n ? '443'\n : protocolLower === 'http:'\n ? '80'\n : '';\n\n if (url.port) {\n // Remove default ports for known protocols\n port = url.port === defaultPort ? '' : `:${url.port}`;\n } else {\n // Fallback: some URL implementations with exotic hosts might not populate url.port\n // even if an explicit port exists in the original string. Detect and normalize manually.\n // Handle potential userinfo (user:pass@) prefix for future compatibility\n\n // Try IPv6 bracketed format first\n let portMatch = authority.match(/^(?:[^@]*@)?\\[[^\\]]+\\]:(\\d+)$/);\n\n if (portMatch) {\n const explicit = portMatch[1];\n port = explicit === defaultPort ? '' : `:${explicit}`;\n } else {\n // Fallback for non-IPv6 authorities: detect :port after host\n portMatch = authority.match(/^(?:[^@]*@)?([^:]+):(\\d+)$/);\n if (portMatch) {\n const explicit = portMatch[2];\n port = explicit === defaultPort ? '' : `:${explicit}`;\n }\n }\n }\n\n // Explicitly use lowercase protocol for consistency\n return `${protocolLower}//${host}${port}`;\n }\n\n // If URL parsing fails, return empty sentinel (handles invalid URLs).\n // Literal \"null\" is handled above.\n return '';\n}\n\n/**\n * Smart wildcard matching for domains (apex must be explicit)\n *\n * Special case: a single \"*\" matches any host (domains and IPs).\n * For non-global patterns, apex domains must be listed explicitly.\n *\n * Pattern matching rules:\n * - \"*.example.com\" matches DIRECT subdomains only:\n * - \"api.example.com\" ✅ (direct subdomain)\n * - \"app.api.example.com\" ❌ (nested subdomain - use ** for this)\n * - \"**.example.com\" matches ALL subdomains (including nested):\n * - \"api.example.com\" ✅ (direct subdomain)\n * - \"app.api.example.com\" ✅ (nested subdomain)\n * - \"v2.app.api.example.com\" ✅ (deep nesting)\n * - \"*.*.example.com\" matches exactly TWO subdomain levels:\n * - \"a.b.example.com\" ✅ (two levels)\n * - \"api.example.com\" ❌ (one level)\n * - \"x.y.z.example.com\" ❌ (three levels)\n */\nexport function matchesWildcardDomain(\n domain: string,\n pattern: string,\n): boolean {\n const normalizedDomain = normalizeDomain(domain);\n\n if (normalizedDomain === '') {\n return false; // invalid domain cannot match\n }\n\n // Normalize pattern preserving wildcard labels and trailing dot handling\n const normalizedPattern = normalizeWildcardPattern(pattern);\n if (!normalizedPattern) {\n return false; // invalid pattern\n }\n\n // Check if pattern contains wildcards\n if (!normalizedPattern.includes('*')) {\n return false;\n }\n\n // Allow single \"*\" as global wildcard - matches both domains and IP addresses\n if (normalizedPattern === '*') {\n return true;\n }\n\n // Do not wildcard-match IP addresses with non-global patterns; only exact IP matches are supported elsewhere\n if (isIPAddress(normalizedDomain)) {\n return false;\n }\n\n // Reject other all-wildcards patterns (e.g., \"*.*\", \"**.*\")\n if (isAllWildcards(normalizedPattern)) {\n return false;\n }\n\n // PSL/IP tail guard: ensure the fixed tail is neither a PSL, a pseudo-TLD, nor an IP.\n // This prevents patterns like \"*.com\" or \"**.co.uk\" from matching\n\n const labels = normalizedPattern.split('.');\n const { fixedTail: fixedTailLabels } =\n extractFixedTailAfterLastWildcard(labels);\n if (fixedTailLabels.length === 0) {\n return false; // require a concrete tail\n }\n\n const tail = fixedTailLabels.join('.');\n\n if (isIPAddress(tail)) {\n return false; // no wildcarding around IPs\n }\n\n const ps = getPublicSuffix(tail);\n\n if (INTERNAL_PSEUDO_TLDS.has(tail) || (ps && ps === tail)) {\n return false; // no wildcarding around suffix-like tails\n }\n\n // \"**.\" requires at least one label before the remainder, so a domain that\n // exactly equals the remainder can never match (e.g., \"**.example.com\" ≠ \"example.com\").\n if (normalizedPattern.startsWith('**.')) {\n if (normalizedDomain === normalizeDomain(normalizedPattern.slice(3))) {\n return false;\n }\n }\n\n return matchesMultiLabelPattern(normalizedDomain, normalizedPattern);\n}\n\n/**\n * Smart origin wildcard matching for CORS with URL parsing\n * Supports protocol-specific wildcards and domain wildcards:\n * - * - matches any valid HTTP(S) origin (global wildcard)\n * - https://* or http://* - matches any domain with specific protocol\n * - *.example.com - matches direct subdomains with any protocol (ignores port)\n * - **.example.com - matches all subdomains including nested with any protocol\n * - https://*.example.com or http://*.example.com - matches direct subdomains with specific protocol\n * - https://**.example.com or http://**.example.com - matches all subdomains including nested with specific protocol\n *\n * Protocol support:\n * - For CORS, only http/https are supported; non-HTTP(S) origins never match\n * - Invalid or non-HTTP(S) schemes are rejected early for security\n *\n * Special cases:\n * - \"null\" origins: Cannot be matched by wildcard patterns, only by exact string inclusion in arrays\n * (Security note: sandboxed/file/data contexts can emit literal \"null\". Treat as lower trust; do not\n * allow via \"*\" or host wildcards. Include the literal \"null\" explicitly if you want to allow it.)\n * - Apex domains (example.com) must be listed explicitly, wildcards ignore port numbers\n * - Invalid URLs that fail parsing are treated as literal strings (no wildcard matching)\n */\nexport function matchesWildcardOrigin(\n origin: string,\n pattern: string,\n): boolean {\n // Normalize Unicode dots before URL parsing for consistency\n const normalizedOrigin = toAsciiDots(origin);\n const normalizedPattern = toAsciiDots(pattern);\n\n if (hasDanglingPortInAuthority(normalizedOrigin)) {\n return false;\n }\n\n // Parse once and reuse\n const originURL = safeParseURL(normalizedOrigin);\n\n // For CORS, only http/https are relevant; reject other schemes early when parsed.\n if (originURL) {\n const scheme = originURL.protocol.toLowerCase();\n if (scheme !== 'http:' && scheme !== 'https:') {\n return false;\n }\n\n if (\n originURL.username ||\n originURL.password ||\n (originURL.pathname && originURL.pathname !== '/') ||\n originURL.search ||\n originURL.hash\n ) {\n return false;\n }\n }\n\n // Global wildcard: single \"*\" matches any valid HTTP(S) origin\n if (normalizedPattern === '*') {\n return originURL !== null && hasValidWildcardOriginHost(originURL);\n }\n\n // Protocol-only wildcards: require valid URL parsing for security\n const patternLower = normalizedPattern.toLowerCase();\n\n if (patternLower === 'https://*' || patternLower === 'http://*') {\n if (!originURL) {\n return false; // must be a valid URL\n }\n\n const want = patternLower === 'https://*' ? 'https:' : 'http:';\n return (\n originURL.protocol.toLowerCase() === want &&\n hasValidWildcardOriginHost(originURL)\n );\n }\n\n // Remaining logic requires a parsed URL\n if (!originURL) {\n return false;\n }\n\n const normalizedHostname = normalizeDomain(originURL.hostname);\n\n if (normalizedHostname === '') {\n return false;\n }\n\n const originProtocol = originURL.protocol.slice(0, -1).toLowerCase(); // Remove trailing \":\" and lowercase\n\n // Handle protocol-specific domain wildcards: https://*.example.com\n if (normalizedPattern.includes('://')) {\n const [patternProtocol, ...rest] = normalizedPattern.split('://');\n const domainPattern = rest.join('://');\n\n // Reject non-domain characters in the domain pattern portion\n if (INVALID_DOMAIN_CHARS.test(domainPattern)) {\n return false;\n }\n\n // Protocol must match exactly\n if (originProtocol !== patternProtocol.toLowerCase()) {\n return false;\n }\n\n // Fast reject: domain pattern must contain at least one wildcard and not be all-wildcards\n if (!domainPattern.includes('*') || isAllWildcards(domainPattern)) {\n return false;\n }\n\n // Check domain pattern using direct domain matching\n return matchesWildcardDomain(normalizedHostname, domainPattern);\n }\n\n // Handle domain wildcard patterns (including multi-label patterns)\n if (normalizedPattern.includes('*')) {\n // Fast reject for invalid all-wildcards patterns (e.g., \"*.*\", \"**.*\")\n // Note: single \"*\" is handled above as global wildcard\n if (normalizedPattern !== '*' && isAllWildcards(normalizedPattern)) {\n return false;\n }\n\n return matchesWildcardDomain(normalizedHostname, normalizedPattern);\n }\n\n return false;\n}\n\n/**\n * Check if a domain matches any pattern in a list\n * Supports exact matches, wildcards, and normalization\n *\n * Validation:\n * - Origin-style patterns (e.g., \"https://*.example.com\") are NOT allowed in domain lists.\n * If any entry contains \"://\", an error will be thrown to surface misconfiguration early.\n * - Empty or whitespace-only entries are ignored.\n * Use `matchesOriginList` for origin-style patterns.\n */\nexport function matchesDomainList(\n domain: string,\n allowedDomains: string[],\n): boolean {\n const normalizedDomain = normalizeDomain(domain);\n\n // Early exit: invalid input cannot match any allowed domain\n if (normalizedDomain === '') {\n return false;\n }\n\n // Trim and filter out empty entries first\n const cleaned = allowedDomains\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n\n // Validate: throw if any origin-style patterns are present\n const ORIGIN_LIKE = /^[a-z][a-z0-9+\\-.]*:\\/\\//i;\n const originLike = cleaned.filter((s) => ORIGIN_LIKE.test(s));\n\n if (originLike.length > 0) {\n throw new Error(\n `matchesDomainList: origin-style patterns are not allowed in domain lists: ${originLike.join(', ')}`,\n );\n }\n\n for (const allowed of cleaned) {\n if (allowed.includes('*')) {\n if (matchesWildcardDomain(domain, allowed)) {\n return true;\n }\n continue;\n }\n\n const normalizedAllowed = normalizeDomain(allowed);\n if (\n isAllowedExactHostname(normalizedAllowed) &&\n normalizedDomain === normalizedAllowed\n ) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction isAllowedExactHostname(normalizedHostname: string): boolean {\n if (!normalizedHostname) {\n return false;\n }\n\n // The literal string \"null\" is origin-only and must never match in domain context.\n // Guard explicitly rather than relying on PSL classification of unknown single-label TLDs.\n if (normalizedHostname === 'null') {\n return false;\n }\n\n if (\n isIPAddress(normalizedHostname) ||\n INTERNAL_PSEUDO_TLDS.has(normalizedHostname)\n ) {\n return true;\n }\n\n const publicSuffix = getPublicSuffix(normalizedHostname);\n return !(publicSuffix && publicSuffix === normalizedHostname);\n}\n\n/**\n * Validate a configuration entry for either domain or origin contexts.\n * Non-throwing: returns { valid, info? } where info can carry non-fatal hints.\n *\n * - Domain context: accepts exact domains and domain wildcard patterns.\n * - Origin context: accepts\n * - exact origins,\n * - protocol-only wildcards like \"https://*\",\n * - protocol + domain wildcard like \"https://*.example.com\",\n * - bare domains (treated like domain context).\n *\n * Common rules:\n * - Only full-label wildcards are allowed (\"*\" or \"**\"); partial label wildcards are invalid.\n * - All-wildcards domain patterns (e.g., \"*.*\") are invalid. The global \"*\" may be allowed\n * in origin context when explicitly enabled via options.\n * - Wildcards cannot target IP tails.\n * - PSL tail guard also rejects pseudo-TLD suffix wildcards like `*.localhost`.\n */\nexport type WildcardKind = 'none' | 'global' | 'protocol' | 'subdomain';\n\nexport type ValidationResult = {\n valid: boolean;\n info?: string;\n wildcardKind: WildcardKind;\n};\n\nfunction isValidPortString(port: string): boolean {\n if (!/^\\d+$/.test(port)) {\n return false;\n }\n\n const portNumber = Number(port);\n return Number.isInteger(portNumber) && portNumber >= 0 && portNumber <= 65535;\n}\n\nexport function validateConfigEntry(\n entry: string,\n context: 'domain' | 'origin',\n options?: { allowGlobalWildcard?: boolean; allowProtocolWildcard?: boolean },\n): ValidationResult {\n const raw = (entry ?? '').trim();\n const SCHEME_RE = /^[a-z][a-z0-9+\\-.]*$/i;\n if (!raw) {\n return { valid: false, info: 'empty entry', wildcardKind: 'none' };\n }\n\n // Normalize options with secure defaults\n const opts = {\n allowGlobalWildcard: false,\n allowProtocolWildcard: true,\n ...(options ?? {}),\n } as Required<NonNullable<typeof options>> & {\n allowGlobalWildcard: boolean;\n allowProtocolWildcard: boolean;\n };\n\n // Helper: validate non-wildcard labels (punycode + DNS limits)\n function validateConcreteLabels(pattern: string): boolean {\n const labels = pattern.split('.');\n const concrete: string[] = [];\n\n for (const lbl of labels) {\n if (lbl === '*' || lbl === '**') {\n continue;\n }\n\n if (lbl.length > 63) {\n return false;\n }\n\n const nd = normalizeDomain(lbl);\n\n if (nd === '') {\n return false;\n }\n\n concrete.push(nd);\n }\n\n if (concrete.length > 0) {\n if (!checkDNSLength(concrete.join('.'))) {\n return false;\n }\n }\n\n return true;\n }\n\n // Helper: PSL tail guard and IP-tail rejection for wildcard patterns\n function wildcardTailIsInvalid(pattern: string): boolean {\n const normalized = normalizeWildcardPattern(pattern);\n\n const labels = normalized.split('.');\n\n // Extract the fixed tail after the last wildcard\n const { fixedTail: fixedTailLabels } =\n extractFixedTailAfterLastWildcard(labels);\n if (fixedTailLabels.length === 0) {\n return true; // require a concrete tail\n }\n\n const tail = fixedTailLabels.join('.');\n if (isIPAddress(tail)) {\n return true; // no wildcarding around IPs\n }\n const ps = getPublicSuffix(tail);\n if (INTERNAL_PSEUDO_TLDS.has(tail) || (ps && ps === tail)) {\n return true;\n }\n return false;\n }\n\n // Helper: domain-wildcard structural checks (no URL chars, full labels, etc.)\n function validateDomainWildcard(pattern: string): ValidationResult {\n // Normalize Unicode dots and trim\n const trimmed = pattern\n .trim()\n .normalize('NFC')\n .replace(/[.。。]/g, '.'); // normalize Unicode dot variants to ASCII\n\n if (INVALID_DOMAIN_CHARS.test(trimmed)) {\n return {\n valid: false,\n info: 'invalid characters in domain pattern',\n wildcardKind: 'none',\n };\n }\n\n if (hasPartialLabelWildcard(trimmed)) {\n return {\n valid: false,\n info: 'partial-label wildcards are not allowed',\n wildcardKind: 'none',\n };\n }\n\n const normalized = normalizeWildcardPattern(trimmed);\n\n if (!normalized) {\n return {\n valid: false,\n info: 'invalid domain labels',\n wildcardKind: 'none',\n };\n }\n\n if (normalized.split('.').length > MAX_LABELS) {\n return {\n valid: false,\n info: 'wildcard pattern exceeds label limit',\n wildcardKind: 'none',\n };\n }\n\n if (isAllWildcards(normalized)) {\n return {\n valid: false,\n info: 'all-wildcards pattern is not allowed',\n wildcardKind: 'none',\n };\n }\n\n if (!validateConcreteLabels(normalized)) {\n return {\n valid: false,\n info: 'invalid domain labels',\n wildcardKind: 'none',\n };\n }\n\n if (wildcardTailIsInvalid(normalized)) {\n return {\n valid: false,\n info: 'wildcard tail targets public suffix or IP (disallowed)',\n wildcardKind: 'none',\n };\n }\n\n return { valid: true, wildcardKind: 'subdomain' };\n }\n\n // Helper: exact domain check (no protocols). Reject apex public suffixes.\n function validateExactDomain(s: string): ValidationResult {\n // The literal string \"null\" is origin-only; reject it explicitly\n // rather than relying on PSL classification of unknown single-label TLDs.\n if (s.toLowerCase() === 'null') {\n return {\n valid: false,\n info: '\"null\" is not a valid domain entry',\n wildcardKind: 'none',\n };\n }\n\n // Check if it's an IP address first - if so, allow it (consistent with matchesDomainList)\n // Normalize Unicode dots for consistent IP detection\n const sDots = toAsciiDots(s);\n if (isIPAddress(sDots)) {\n return { valid: true, wildcardKind: 'none' };\n }\n\n // For non-IP addresses, reject URL-like characters\n if (INVALID_DOMAIN_CHARS.test(s)) {\n return {\n valid: false,\n info: 'invalid characters in domain',\n wildcardKind: 'none',\n };\n }\n\n const nd = normalizeDomain(s);\n\n if (nd === '') {\n return { valid: false, info: 'invalid domain', wildcardKind: 'none' };\n }\n\n const ps = getPublicSuffix(nd);\n\n if (ps && ps === nd && !INTERNAL_PSEUDO_TLDS.has(nd)) {\n return {\n valid: false,\n info: 'entry equals a public suffix (not registrable)',\n wildcardKind: 'none',\n };\n }\n return { valid: true, wildcardKind: 'none' };\n }\n\n // Domain context path\n if (context === 'domain') {\n // Reject any origin-style entries (with protocols) upfront\n if (/^[a-z][a-z0-9+\\-.]*:\\/\\//i.test(raw)) {\n return {\n valid: false,\n info: 'protocols are not allowed in domain context',\n wildcardKind: 'none',\n };\n }\n\n // Special-case: global wildcard in domain context (config-time validation)\n if (raw === '*') {\n return opts.allowGlobalWildcard\n ? { valid: true, wildcardKind: 'global' }\n : {\n valid: false,\n info: \"global wildcard '*' not allowed in this context\",\n wildcardKind: 'none',\n };\n }\n\n if (raw.includes('*')) {\n return validateDomainWildcard(raw);\n }\n return validateExactDomain(raw);\n }\n\n // Origin context\n // Special-case: literal \"null\" origin is allowed by exact inclusion\n if (raw === 'null') {\n return { valid: true, wildcardKind: 'none' };\n }\n\n // Special-case: global wildcard in origin context (config-time validation)\n if (raw === '*') {\n return opts.allowGlobalWildcard\n ? { valid: true, wildcardKind: 'global' }\n : {\n valid: false,\n info: \"global wildcard '*' not allowed in this context\",\n wildcardKind: 'none',\n };\n }\n\n const schemeIdx = raw.indexOf('://');\n if (schemeIdx === -1) {\n // Bare domain/or domain pattern allowed in origin lists; reuse domain rules\n if (raw.includes('*')) {\n return validateDomainWildcard(raw);\n }\n return validateExactDomain(raw);\n }\n\n const scheme = raw.slice(0, schemeIdx).toLowerCase();\n const rest = raw.slice(schemeIdx + 3);\n\n if (!SCHEME_RE.test(scheme)) {\n return {\n valid: false,\n info: 'invalid scheme in origin',\n wildcardKind: 'none',\n };\n }\n\n let normalizedRest = rest;\n\n // Disallow query/fragment in origin entries. Allow a single trailing slash\n // for exact origins so copied values like \"https://example.com/\" validate\n // the same way the runtime matchers normalize them.\n if (normalizedRest.includes('#') || normalizedRest.includes('?')) {\n return {\n valid: false,\n info: 'origin must not contain path, query, or fragment',\n wildcardKind: 'none',\n };\n }\n\n const slashIdx = normalizedRest.indexOf('/');\n if (slashIdx !== -1) {\n const authority = normalizedRest.slice(0, slashIdx);\n const suffix = normalizedRest.slice(slashIdx);\n\n if (suffix !== '/' || authority.includes('*')) {\n return {\n valid: false,\n info: 'origin must not contain path, query, or fragment',\n wildcardKind: 'none',\n };\n }\n\n normalizedRest = authority;\n }\n\n if (!normalizedRest) {\n return {\n valid: false,\n info: 'missing host in origin',\n wildcardKind: 'none',\n };\n }\n\n // Reject userinfo in origin entries for security and clarity\n if (normalizedRest.includes('@')) {\n return {\n valid: false,\n info: 'origin must not include userinfo',\n wildcardKind: 'none',\n };\n }\n\n // Protocol-only wildcard: scheme://*\n if (normalizedRest === '*') {\n if (scheme !== 'http' && scheme !== 'https') {\n return {\n valid: false,\n info: 'wildcard origins require http or https scheme',\n wildcardKind: 'none',\n };\n }\n\n if (!opts.allowProtocolWildcard) {\n return {\n valid: false,\n info: 'protocol wildcard not allowed',\n wildcardKind: 'none',\n };\n }\n\n const info =\n scheme === 'http' || scheme === 'https'\n ? undefined\n : 'non-http(s) scheme; CORS may not match';\n return { valid: true, info, wildcardKind: 'protocol' };\n }\n\n // Extract host (and optional port) while respecting IPv6 brackets\n let host = normalizedRest;\n let hasPort = false;\n\n if (normalizedRest.startsWith('[')) {\n const end = normalizedRest.indexOf(']');\n if (end === -1) {\n return {\n valid: false,\n info: 'unclosed IPv6 bracket',\n wildcardKind: 'none',\n };\n }\n host = normalizedRest.slice(0, end + 1);\n const after = normalizedRest.slice(end + 1);\n if (after.startsWith(':')) {\n const port = after.slice(1);\n\n if (!isValidPortString(port)) {\n return {\n valid: false,\n info: 'invalid port in origin',\n wildcardKind: 'none',\n };\n }\n\n // port present -> allowed for exact origins, but reject with wildcard hosts below\n // leave host as bracketed literal\n hasPort = true;\n } else if (after.length > 0) {\n return {\n valid: false,\n info: 'unexpected characters after IPv6 host',\n wildcardKind: 'none',\n };\n }\n } else {\n // strip port if present\n const colon = normalizedRest.indexOf(':');\n if (colon !== -1) {\n host = normalizedRest.slice(0, colon);\n const port = normalizedRest.slice(colon + 1);\n\n if (!isValidPortString(port)) {\n return {\n valid: false,\n info: 'invalid port in origin',\n wildcardKind: 'none',\n };\n }\n\n // optional port part is fine for exact origins\n hasPort = true;\n }\n }\n\n // If wildcard present in origin authority, treat as protocol+domain wildcard\n if (host.includes('*')) {\n if (scheme !== 'http' && scheme !== 'https') {\n return {\n valid: false,\n info: 'wildcard origins require http or https scheme',\n wildcardKind: 'none',\n };\n }\n\n // Forbid ports/brackets with wildcard hosts\n if (host.includes('[') || host.includes(']')) {\n return {\n valid: false,\n info: 'wildcard host cannot be an IP literal',\n wildcardKind: 'none',\n };\n }\n\n if (hasPort) {\n return {\n valid: false,\n info: 'ports are not allowed in wildcard origins',\n wildcardKind: 'none',\n };\n }\n\n // Validate as domain wildcard\n const verdict = validateDomainWildcard(host);\n if (!verdict.valid) {\n return verdict;\n }\n\n const info =\n scheme === 'http' || scheme === 'https'\n ? undefined\n : 'non-http(s) scheme; CORS may not match';\n return { valid: true, info, wildcardKind: 'subdomain' };\n }\n\n // Exact origin: allow any scheme; validate host as domain or IP\n if (host.startsWith('[')) {\n const bracketContent = host.slice(1, -1);\n\n if (!isIPv6(bracketContent)) {\n return {\n valid: false,\n info: 'invalid IPv6 literal in origin',\n wildcardKind: 'none',\n };\n }\n\n const info =\n scheme === 'http' || scheme === 'https'\n ? undefined\n : 'non-http(s) scheme; CORS may not match';\n\n return { valid: true, info, wildcardKind: 'none' };\n }\n\n const hostDots = toAsciiDots(host);\n if (isIPAddress(hostDots)) {\n const info =\n scheme === 'http' || scheme === 'https'\n ? undefined\n : 'non-http(s) scheme; CORS may not match';\n return { valid: true, info, wildcardKind: 'none' };\n }\n\n // Domain host\n const nd = normalizeDomain(host);\n\n if (nd === '') {\n return {\n valid: false,\n info: 'invalid domain in origin',\n wildcardKind: 'none',\n };\n }\n const ps = getPublicSuffix(nd);\n if (ps && ps === nd && !INTERNAL_PSEUDO_TLDS.has(nd)) {\n return {\n valid: false,\n info: 'origin host equals a public suffix (not registrable)',\n wildcardKind: 'none',\n };\n }\n const info =\n scheme === 'http' || scheme === 'https'\n ? undefined\n : 'non-http(s) scheme; CORS may not match';\n return { valid: true, info, wildcardKind: 'none' };\n}\n\n/**\n * Parse an exact origin for list matching.\n * Rejects userinfo, non-empty paths, queries, and fragments so malformed inputs\n * are not silently normalized into broader origins.\n */\nfunction parseExactOriginForMatching(entry: string): {\n normalizedOrigin: string;\n normalizedHostname: string;\n} | null {\n if (entry === 'null') {\n return { normalizedOrigin: 'null', normalizedHostname: '' };\n }\n\n const normalized = toAsciiDots(entry);\n const schemeIdx = normalized.indexOf('://');\n\n if (schemeIdx !== -1) {\n const authority = extractAuthority(normalized, schemeIdx);\n const at = authority.lastIndexOf('@');\n const hostPort = at === -1 ? authority : authority.slice(at + 1);\n\n if (hostPort.endsWith(':')) {\n return null;\n }\n }\n\n const url = safeParseURL(normalized);\n if (!url) {\n return null;\n }\n\n if (url.username || url.password) {\n return null;\n }\n\n if (url.pathname && url.pathname !== '/') {\n return null;\n }\n\n if (url.search || url.hash) {\n return null;\n }\n\n const normalizedOrigin = normalizeOrigin(entry);\n if (normalizedOrigin === '') {\n return null;\n }\n\n return {\n normalizedOrigin,\n normalizedHostname: normalizeDomain(url.hostname),\n };\n}\n\nfunction isCredentialsSafeWildcardOriginPattern(pattern: string): boolean {\n const trimmed = pattern\n .trim()\n .normalize('NFC')\n .replace(/[.。。]/g, '.');\n\n function isValidCredentialWildcardHost(hostPattern: string): boolean {\n if (isAllWildcards(hostPattern)) {\n return false;\n }\n\n if (INVALID_DOMAIN_CHARS.test(hostPattern)) {\n return false;\n }\n\n if (hasPartialLabelWildcard(hostPattern)) {\n return false;\n }\n\n const labels = hostPattern.split('.');\n const concrete: string[] = [];\n\n for (const lbl of labels) {\n if (lbl === '*' || lbl === '**') {\n continue;\n }\n\n if (lbl.length > 63) {\n return false;\n }\n\n const nd = normalizeDomain(lbl);\n if (nd === '') {\n return false;\n }\n\n concrete.push(nd);\n }\n\n if (concrete.length > 0 && !checkDNSLength(concrete.join('.'))) {\n return false;\n }\n\n const normalized = normalizeWildcardPattern(hostPattern);\n const { fixedTail } = extractFixedTailAfterLastWildcard(\n (normalized || hostPattern).split('.'),\n );\n if (!normalized || fixedTail.length === 0) {\n return false;\n }\n\n const tail = fixedTail.join('.');\n if (isIPAddress(tail)) {\n return false;\n }\n\n const ps = getPublicSuffix(tail);\n return !INTERNAL_PSEUDO_TLDS.has(tail) && !(ps && ps === tail);\n }\n\n if (!trimmed.includes('*')) {\n return false;\n }\n\n const schemeIdx = trimmed.indexOf('://');\n if (schemeIdx === -1) {\n return isValidCredentialWildcardHost(trimmed);\n }\n\n const scheme = trimmed.slice(0, schemeIdx).toLowerCase();\n const host = trimmed.slice(schemeIdx + 3);\n\n if ((scheme !== 'http' && scheme !== 'https') || host === '*') {\n return false;\n }\n\n return isValidCredentialWildcardHost(host);\n}\n\n/**\n * Helper function to check origin list with wildcard support.\n * Supports exact matches, wildcard matches, and normalization.\n *\n * Exact origins may use non-HTTP(S) schemes and are compared exactly.\n * Wildcard matching remains HTTP(S)-only.\n * Blank allowlist entries are ignored after trimming.\n * Special case: single \"*\" matches any valid HTTP(S) origin.\n *\n * @param origin - The origin to check (undefined for requests without Origin header)\n * @param allowedOrigins - Array of allowed origin patterns\n * @param opts - Options for handling edge cases\n * @param opts.treatNoOriginAsAllowed - If true, allows requests without Origin header when \"*\" is in the allowed list\n */\nexport function matchesOriginList(\n origin: string | undefined,\n allowedOrigins: string[],\n opts: { treatNoOriginAsAllowed?: boolean } = {},\n): boolean {\n const cleaned = allowedOrigins.map((s) => s.trim()).filter(Boolean);\n\n if (!origin) {\n // Only allow requests without Origin header if explicitly opted in AND \"*\" is in the list\n return !!opts.treatNoOriginAsAllowed && cleaned.includes('*');\n }\n\n const parsedOrigin = parseExactOriginForMatching(origin);\n if (!parsedOrigin) {\n return false;\n }\n\n return cleaned.some((allowed) => {\n // Global wildcard: single \"*\" matches any origin - delegate to matchesWildcardOrigin for proper validation\n if (allowed === '*') {\n return matchesWildcardOrigin(origin, '*');\n }\n\n if (allowed.includes('*')) {\n // Avoid double-normalizing/parsing; wildcard matcher handles parsing + normalization itself\n // We pass the raw origin/pattern here (vs normalized in the non-wildcard path) because\n // the wildcard matcher needs to parse the origin as a URL for protocol/host extraction\n return matchesWildcardOrigin(origin, allowed);\n }\n\n if (allowed === 'null') {\n return parsedOrigin.normalizedOrigin === 'null';\n }\n\n if (!allowed.includes('://')) {\n const normalizedAllowedDomain = normalizeDomain(allowed);\n\n return (\n isAllowedExactHostname(normalizedAllowedDomain) &&\n parsedOrigin.normalizedHostname !== '' &&\n parsedOrigin.normalizedHostname === normalizedAllowedDomain\n );\n }\n\n const parsedAllowed = parseExactOriginForMatching(allowed);\n if (!parsedAllowed) {\n return false;\n }\n\n if (!isAllowedExactHostname(parsedAllowed.normalizedHostname)) {\n return false;\n }\n\n return parsedOrigin.normalizedOrigin === parsedAllowed.normalizedOrigin;\n });\n}\n\n/**\n * Helper function to check if origin matches any pattern in a list (credentials-safe).\n *\n * Exact origins may use non-HTTP(S) schemes and are compared exactly.\n * When `allowWildcardSubdomains` is enabled, only host subdomain wildcard\n * patterns are honored. Global \"*\" and protocol-only wildcards such as\n * \"https://*\" are intentionally not honored in credentials mode.\n * Blank allowlist entries are ignored after trimming.\n */\nexport function matchesCORSCredentialsList(\n origin: string | undefined,\n allowedOrigins: string[],\n options: { allowWildcardSubdomains?: boolean } = {},\n): boolean {\n if (!origin) {\n return false;\n }\n\n const parsedOrigin = parseExactOriginForMatching(origin);\n if (!parsedOrigin) {\n return false;\n }\n\n const cleaned = allowedOrigins.map((s) => s.trim()).filter(Boolean);\n\n const allowWildcard = !!options.allowWildcardSubdomains;\n\n for (const allowed of cleaned) {\n // Optional wildcard support for credentials lists (subdomain patterns only)\n if (allowWildcard && allowed.includes('*')) {\n if (\n isCredentialsSafeWildcardOriginPattern(allowed) &&\n matchesWildcardOrigin(origin, allowed)\n ) {\n return true;\n }\n continue;\n }\n\n if (allowed === 'null') {\n if (parsedOrigin.normalizedOrigin === 'null') {\n return true;\n }\n\n continue;\n }\n\n if (!allowed.includes('://')) {\n const normalizedAllowedDomain = normalizeDomain(allowed);\n\n if (\n isAllowedExactHostname(normalizedAllowedDomain) &&\n parsedOrigin.normalizedHostname !== '' &&\n parsedOrigin.normalizedHostname === normalizedAllowedDomain\n ) {\n return true;\n }\n\n continue;\n }\n\n const parsedAllowed = parseExactOriginForMatching(allowed);\n if (!parsedAllowed) {\n continue;\n }\n\n if (!isAllowedExactHostname(parsedAllowed.normalizedHostname)) {\n continue;\n }\n\n if (parsedOrigin.normalizedOrigin === parsedAllowed.normalizedOrigin) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Result of parsing a Host header\n */\nexport interface ParsedHost {\n /** Domain/hostname with brackets stripped (e.g., \"[::1]\" → \"::1\") */\n domain: string;\n /** Port number as string, or empty string if no port specified */\n port: string;\n}\n\n/**\n * Parse Host header into domain and port components\n * Supports IPv6 brackets and handles port extraction with strict validation\n *\n * This function is commonly used to parse the HTTP Host header,\n * which may contain:\n * - Regular hostnames: \"example.com\" or \"example.com:8080\"\n * - IPv6 addresses: \"[::1]\" or \"[::1]:8080\"\n * - IPv4 addresses: \"127.0.0.1\" or \"127.0.0.1:8080\"\n *\n * The returned domain has brackets stripped for normalization\n * (e.g., \"[::1]\" → \"::1\"), while port is returned separately.\n *\n * **Strict validation:** For bracketed IPv6 addresses, after the closing bracket `]`,\n * only the following are valid:\n * - Nothing (end of string): `[::1]` → valid\n * - Port with colon: `[::1]:8080` → valid\n * - Any other characters: `[::1]garbage`, `[::1][::2]` → returns empty (malformed)\n *\n * @param host - Host header value (hostname[:port] or [ipv6][:port])\n * @returns Object with domain (without brackets) and port (empty string if no port).\n * Returns `{ domain: '', port: '' }` for malformed input.\n *\n * @example\n * parseHostHeader('example.com:8080')\n * // => { domain: 'example.com', port: '8080' }\n *\n * parseHostHeader('[::1]:8080')\n * // => { domain: '::1', port: '8080' }\n *\n * parseHostHeader('[2001:db8::1]')\n * // => { domain: '2001:db8::1', port: '' }\n *\n * parseHostHeader('localhost')\n * // => { domain: 'localhost', port: '' }\n *\n * parseHostHeader('[::1][::2]') // malformed\n * // => { domain: '', port: '' }\n */\nexport function parseHostHeader(host: string): ParsedHost {\n const trimmedHost = host.trim();\n\n if (!trimmedHost) {\n return { domain: '', port: '' };\n }\n\n function parsePortOrFail(port: string): ParsedHost | null {\n if (!isValidPortString(port)) {\n return { domain: '', port: '' };\n }\n\n return null;\n }\n\n // Handle IPv6 brackets\n if (trimmedHost.startsWith('[')) {\n const end = trimmedHost.indexOf(']');\n\n if (end !== -1) {\n const domain = trimmedHost.slice(1, end); // Remove brackets for normalization\n const rest = trimmedHost.slice(end + 1);\n\n if (!isIPv6(domain)) {\n return { domain: '', port: '' };\n }\n\n // Strict validation: after closing bracket, only allow empty or :port\n if (rest === '') {\n return { domain, port: '' };\n }\n\n if (rest.startsWith(':')) {\n const invalid = parsePortOrFail(rest.slice(1));\n if (invalid) {\n return invalid;\n }\n\n return { domain, port: rest.slice(1) };\n }\n\n // Malformed: has junk after closing bracket (e.g., \"[::1]garbage\" or \"[::1][::2]\")\n return { domain: '', port: '' };\n }\n\n // Malformed bracket - missing closing bracket\n return { domain: '', port: '' };\n }\n\n // Regular hostname:port parsing\n const idx = trimmedHost.indexOf(':');\n\n if (idx === -1) {\n return { domain: trimmedHost, port: '' };\n }\n\n if (idx === 0) {\n return { domain: '', port: '' };\n }\n\n const invalid = parsePortOrFail(trimmedHost.slice(idx + 1));\n if (invalid) {\n return invalid;\n }\n\n return {\n domain: trimmedHost.slice(0, idx),\n port: trimmedHost.slice(idx + 1),\n };\n}\n\n/**\n * Helper function to check if domain is apex (no subdomain)\n * Uses tldts to properly handle multi-part TLDs like .co.uk\n */\nexport function isApexDomain(domain: string): boolean {\n const normalizedDomain = normalizeDomain(domain);\n\n if (!normalizedDomain || isIPAddress(normalizedDomain)) {\n return false;\n }\n\n // Handle pseudo-TLD domains before tldts, which doesn't know about them.\n const labels = normalizedDomain.split('.');\n const lastLabel = labels[labels.length - 1];\n if (INTERNAL_PSEUDO_TLDS.has(lastLabel)) {\n if (normalizedDomain === lastLabel) {\n return true; // bare pseudo-TLD hostname (e.g. localhost, local) → apex\n }\n if (lastLabel === 'localhost') {\n return false; // localhost is a hostname, not a TLD; sub.localhost is not apex\n }\n return labels.length === 2; // foo.local → apex; bar.foo.local → not\n }\n\n // Use tldts to properly detect apex domains vs subdomains\n // This correctly handles multi-part TLDs like .co.uk, .com.au, etc.\n const parsedDomain = getDomain(normalizedDomain);\n const subdomain = getSubdomain(normalizedDomain);\n\n // Guard against null returns from tldts for invalid hosts\n if (!parsedDomain) {\n return false;\n }\n\n // Domain is apex if it matches the parsed domain and has no subdomain\n return parsedDomain === normalizedDomain && !subdomain;\n}\n\nexport {\n normalizeDomain,\n isIPAddress,\n isIPv4,\n isIPv6,\n checkDNSLength,\n canonicalizeBracketedIPv6Content,\n} from './helpers';\n\nexport { getDomain, getSubdomain } from 'tldts';\n","import { toASCII } from 'tr46';\n\n// Defense-in-depth: cap label processing to avoid pathological patterns\nexport const MAX_LABELS = 32;\n// Extra safety: cap recursive matching steps to avoid exponential blow-ups\nconst STEP_LIMIT = 10_000;\n\n// Invalid domain characters: ports, paths, fragments, brackets, userinfo, backslashes\nexport const INVALID_DOMAIN_CHARS = /[/?#:[\\]@\\\\]/;\n\n// Internal / special-use TLDs that we explicitly treat as non-PSL for wildcard-tail checks.\n// Keep this list explicit—do not guess.\n// Currently: 'localhost', 'local', 'test' (IANA special-use), and 'internal' (common in k8s/corporate).\n// If you want to allow other names (e.g., 'lan'), add them here deliberately.\nexport const INTERNAL_PSEUDO_TLDS = Object.freeze(\n new Set<string>(['localhost', 'local', 'test', 'internal']),\n);\n\n// Helper functions for wildcard pattern validation\nexport function isAllWildcards(s: string): boolean {\n return s.split('.').every((l) => l === '*' || l === '**');\n}\n\nexport function hasPartialLabelWildcard(s: string): boolean {\n return s.split('.').some((l) => l.includes('*') && l !== '*' && l !== '**');\n}\n\n/**\n * Check DNS length constraints for hostnames (non-throwing):\n * - each label <= 63 octets\n * - total FQDN <= 255 octets\n * - max 127 labels (theoretical DNS limit)\n * Assumes ASCII input (post-TR46 processing).\n */\nexport function checkDNSLength(host: string): boolean {\n const labels = host.split('.');\n\n // Label count cap for domains (127 is theoretical DNS limit)\n if (labels.length === 0 || labels.length > 127) {\n return false;\n }\n\n let total = 0;\n let i = 0;\n\n for (const lbl of labels) {\n const isLast = i++ === labels.length - 1;\n\n if (lbl.length === 0) {\n // Allow only a *trailing* empty label (for FQDN with a dot)\n if (!isLast) {\n return false;\n }\n continue;\n }\n\n if (lbl.length > 63) {\n return false;\n }\n\n total += lbl.length + 1; // account for dot\n }\n\n return total > 0 ? total - 1 <= 255 : false;\n}\n\n// IPv6 regex pattern hoisted to module scope for performance\nconst IPV6_BASE_REGEX =\n /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/;\n\n/**\n * Check if a string is an IPv4 address\n */\nexport function isIPv4(str: string): boolean {\n const ipv4Regex =\n /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;\n return ipv4Regex.test(str);\n}\n\n/**\n * Check if a string is an IPv6 address\n */\nexport function isIPv6(str: string): boolean {\n // Zone identifiers are intentionally rejected to keep behavior portable across\n // Node, Bun, and browser-facing URL handling.\n const cleaned = str.replace(/^\\[|\\]$/g, '');\n if (cleaned.includes('%')) {\n return false;\n }\n\n return IPV6_BASE_REGEX.test(cleaned);\n}\n\n/**\n * Check if a string is an IP address (IPv4 or IPv6)\n */\nexport function isIPAddress(str: string): boolean {\n return isIPv4(str) || isIPv6(str);\n}\n\nfunction canonicalizeIPAddressLiteral(host: string): string | null {\n const isIPAddressLike =\n host.includes('.') ||\n host.includes(':') ||\n (host.startsWith('[') && host.endsWith(']'));\n\n if (!isIPAddressLike) {\n return null;\n }\n\n if (isIPv6(host)) {\n return canonicalizeBracketedIPv6Content(host.replace(/^\\[|\\]$/g, ''));\n }\n\n try {\n const url = new URL(`http://${host}/`);\n const canonicalHostname = url.hostname.toLowerCase();\n\n if (isIPv4(canonicalHostname)) {\n return canonicalHostname;\n }\n\n if (isIPv6(canonicalHostname)) {\n return canonicalHostname.replace(/^\\[|\\]$/g, '');\n }\n } catch {\n // Fall through to regular domain normalization.\n }\n\n return null;\n}\n\n/**\n * Canonicalize IPv6 literal content for deterministic origin comparison.\n * Uses the platform URL parser so the result matches WHATWG URL origin semantics.\n */\nexport function canonicalizeBracketedIPv6Content(content: string): string {\n try {\n const url = new URL(`http://[${content}]/`);\n return url.hostname.replace(/^\\[|\\]$/g, '');\n } catch {\n // Callers normally validate before canonicalizing; keep this helper\n // non-throwing as a defensive fallback.\n return content.toLowerCase();\n }\n}\n\n/**\n * Extract the fixed tail (non-wildcard labels) after the last wildcard in a pattern.\n * Returns the labels that come after the rightmost wildcard in the pattern.\n *\n * @param patternLabels - Array of pattern labels (e.g., [\"*\", \"api\", \"example\", \"com\"])\n * @returns Object with fixedTailStart index and fixedTail labels array\n */\nexport function extractFixedTailAfterLastWildcard(patternLabels: string[]): {\n fixedTailStart: number;\n fixedTail: string[];\n} {\n // Find the rightmost wildcard\n let lastWildcardIdx = -1;\n for (let i = patternLabels.length - 1; i >= 0; i--) {\n const lbl = patternLabels[i];\n if (lbl === '*' || lbl === '**') {\n lastWildcardIdx = i;\n break;\n }\n }\n\n const fixedTailStart = lastWildcardIdx + 1;\n const fixedTail = patternLabels.slice(fixedTailStart);\n\n return { fixedTailStart, fixedTail };\n}\n\n/**\n * Internal recursive helper for wildcard label matching\n */\nfunction matchesWildcardLabelsInternal(\n domainLabels: string[],\n patternLabels: string[],\n domainIndex: number,\n patternIndex: number,\n counter: { count: number },\n): boolean {\n if (++counter.count > STEP_LIMIT) {\n return false;\n }\n\n while (patternIndex < patternLabels.length) {\n const patternLabel = patternLabels[patternIndex];\n\n if (patternLabel === '**') {\n const isLeftmost = patternIndex === 0;\n\n // ** at index 0 means \"1+ labels\" while interior ** is \"0+\"\n // If leftmost, require at least one domain label\n if (isLeftmost) {\n for (let i = domainIndex + 1; i <= domainLabels.length; i++) {\n if (\n matchesWildcardLabelsInternal(\n domainLabels,\n patternLabels,\n i,\n patternIndex + 1,\n counter,\n )\n ) {\n return true;\n }\n }\n return false;\n }\n\n // Interior **: zero-or-more\n if (\n matchesWildcardLabelsInternal(\n domainLabels,\n patternLabels,\n domainIndex,\n patternIndex + 1,\n counter,\n )\n ) {\n return true;\n }\n\n // Try matching one or more labels\n for (let i = domainIndex + 1; i <= domainLabels.length; i++) {\n if (\n matchesWildcardLabelsInternal(\n domainLabels,\n patternLabels,\n i,\n patternIndex + 1,\n counter,\n )\n ) {\n return true;\n }\n }\n return false;\n } else if (patternLabel === '*') {\n // * matches exactly one label\n if (domainIndex >= domainLabels.length) {\n return false; // Not enough domain labels\n }\n domainIndex++;\n patternIndex++;\n } else {\n // Exact label match\n if (\n domainIndex >= domainLabels.length ||\n domainLabels[domainIndex] !== patternLabel\n ) {\n return false;\n }\n domainIndex++;\n patternIndex++;\n }\n }\n\n // All pattern labels matched, check if all domain labels are consumed\n return domainIndex === domainLabels.length;\n}\n\n/**\n * Match domain labels against wildcard pattern labels\n */\nexport function matchesWildcardLabels(\n domainLabels: string[],\n patternLabels: string[],\n): boolean {\n const counter = { count: 0 };\n return matchesWildcardLabelsInternal(\n domainLabels,\n patternLabels,\n 0,\n 0,\n counter,\n );\n}\n\n/**\n * Helper function for label-wise wildcard matching\n * Supports patterns like *.example.com, **.example.com, *.*.example.com, etc.\n */\nexport function matchesMultiLabelPattern(\n domain: string,\n pattern: string,\n): boolean {\n const domainLabels = domain.split('.');\n const patternLabels = pattern.split('.');\n\n // Guard against pathological label counts\n if (domainLabels.length > MAX_LABELS || patternLabels.length > MAX_LABELS) {\n return false;\n }\n\n // Pattern must have at least one non-wildcard label (the base domain)\n if (\n patternLabels.length === 0 ||\n patternLabels.every((label) => label === '*' || label === '**')\n ) {\n return false;\n }\n\n // Extract the fixed tail after the last wildcard\n const { fixedTailStart, fixedTail } =\n extractFixedTailAfterLastWildcard(patternLabels);\n\n // Domain must be at least as long as the fixed tail\n if (domainLabels.length < fixedTail.length) {\n return false;\n }\n\n // Match fixed tail exactly (right-aligned)\n for (let i = 0; i < fixedTail.length; i++) {\n const domainLabel =\n domainLabels[domainLabels.length - fixedTail.length + i];\n const patternLabel = fixedTail[i];\n if (patternLabel !== domainLabel) {\n return false;\n }\n }\n\n // Now match the left side (which may include wildcards and fixed labels)\n const remainingDomainLabels = domainLabels.slice(\n 0,\n domainLabels.length - fixedTail.length,\n );\n const leftPatternLabels = patternLabels.slice(0, fixedTailStart);\n\n if (leftPatternLabels.length === 0) {\n // No left pattern, so only the fixed tail is required\n return remainingDomainLabels.length === 0;\n }\n\n return matchesWildcardLabels(remainingDomainLabels, leftPatternLabels);\n}\n\n/**\n * Normalize Unicode dot variants to ASCII dots for consistent IP and domain handling\n * @param s - String that may contain Unicode dot variants\n * @returns String with Unicode dots normalized to ASCII dots\n */\nexport function toAsciiDots(s: string): string {\n return s.replace(/[.。。]/g, '.'); // fullwidth/japanese/halfwidth\n}\n\n/**\n * Normalize a domain name for consistent comparison\n * Handles trim, lowercase, a single trailing-dot FQDN form, NFC normalization,\n * and punycode conversion for IDN safety. Returns the canonical host form\n * without a trailing dot. Repeated trailing dots are rejected as invalid.\n * IP literals are canonicalized to a stable WHATWG URL-compatible form.\n */\nexport function normalizeDomain(domain: string): string {\n let trimmed = domain.trim();\n\n // Normalize Unicode dots BEFORE checking IP for consistent behavior\n trimmed = toAsciiDots(trimmed);\n\n // Allow a single trailing dot for FQDNs, but reject repeated trailing dots\n if (/\\.\\.+$/.test(trimmed)) {\n return '';\n }\n\n if (trimmed.endsWith('.')) {\n trimmed = trimmed.slice(0, -1);\n }\n\n // Canonicalize IP literals up front so exact host checks line up with WHATWG URL parsing.\n const canonicalIPAddress = canonicalizeIPAddressLiteral(trimmed);\n if (canonicalIPAddress !== null) {\n return canonicalIPAddress;\n }\n\n // Apply NFC normalization for Unicode domains\n const normalized = trimmed.normalize('NFC').toLowerCase();\n\n try {\n // Use TR46/IDNA processing for robust Unicode domain handling that mirrors browser behavior\n const ascii = toASCII(normalized, {\n useSTD3ASCIIRules: true,\n checkHyphens: true,\n checkBidi: true,\n checkJoiners: true,\n transitionalProcessing: false, // matches modern browser behavior (non-transitional)\n verifyDNSLength: false, // we already do our own length checks\n });\n if (!ascii) {\n throw new Error('TR46 processing failed');\n }\n // Enforce DNS length constraints post-TR46\n return checkDNSLength(ascii) ? ascii : ''; // return sentinel on invalid DNS lengths\n } catch {\n // On TR46 failure, return sentinel empty-string to signal invalid hostname\n return '';\n }\n}\n\n/**\n * Normalize a wildcard domain pattern by preserving wildcard labels\n * and punycode only non-wildcard labels. Also trims and removes\n * a trailing dot if present.\n */\nexport function normalizeWildcardPattern(pattern: string): string {\n let trimmed = pattern\n .trim()\n .normalize('NFC')\n .replace(/[.。。]/g, '.'); // normalize Unicode dot variants to ASCII\n\n // Refuse non-domain characters (ports, paths, fragments, brackets, userinfo, backslashes)\n if (INVALID_DOMAIN_CHARS.test(trimmed)) {\n return ''; // sentinel for invalid pattern\n }\n\n if (trimmed.endsWith('.')) {\n trimmed = trimmed.slice(0, -1);\n }\n\n const labels = trimmed.split('.');\n\n // Reject empty labels post-split early (e.g., *..example.com)\n // This avoids double dots slipping to punycode\n for (const lbl of labels) {\n if (lbl.length === 0) {\n return ''; // sentinel for invalid pattern (no empty labels)\n }\n }\n\n const normalizedLabels = [];\n for (const lbl of labels) {\n if (lbl === '*' || lbl === '**') {\n normalizedLabels.push(lbl);\n continue;\n }\n\n // Pre-punycode check for obviously invalid labels\n if (lbl.length > 63) {\n return ''; // sentinel for invalid pattern\n }\n\n const nd = normalizeDomain(lbl);\n\n if (nd === '') {\n // Invalid label after normalization\n return ''; // sentinel for invalid pattern\n }\n\n normalizedLabels.push(nd);\n }\n\n // Extract concrete (non-wildcard) labels and validate final ASCII length\n const concreteLabels = normalizedLabels.filter(\n (lbl) => lbl !== '*' && lbl !== '**',\n );\n if (concreteLabels.length > 0) {\n const concretePattern = concreteLabels.join('.');\n // Validate the ASCII length of the concrete parts to prevent pathological long IDNs\n if (!checkDNSLength(concretePattern)) {\n return ''; // sentinel for invalid pattern\n }\n }\n\n return normalizedLabels.join('.');\n}\n","import type { HTTPMethod } from './types';\n\n/**\n * HTTP responses that are plausibly transient and worth retrying when a retry\n * policy is explicitly enabled.\n *\n * `status === 0` is included on purpose because browser/XHR-style adapters can\n * surface \"no real HTTP response\" that way when the network is unavailable or\n * the request otherwise fails before a normal status code is received.\n */\nexport const RETRYABLE_STATUS_CODES: ReadonlySet<number> = new Set([\n // 0: Browser/XHR-style \"no response\" status.\n 0,\n\n // 408 Request Timeout\n 408,\n // 429 Too Many Requests\n 429,\n\n // 500 Internal Server Error\n 500,\n // 502 Bad Gateway\n 502,\n // 503 Service Unavailable\n 503,\n // 504 Gateway Timeout\n 504,\n\n // 507 Insufficient Storage\n 507,\n // 509 Bandwidth Limit Exceeded (non-standard)\n 509,\n // 520 Unknown Error (Cloudflare)\n 520,\n // 521 Web Server Is Down (Cloudflare)\n 521,\n // 522 Connection Timed Out (Cloudflare)\n 522,\n // 523 Origin Is Unreachable (Cloudflare)\n 523,\n // 524 A Timeout Occurred (Cloudflare)\n 524,\n // 598 Network Read Timeout Error (non-standard)\n 598,\n // 599 Network Connect Timeout Error (non-standard)\n 599,\n]);\n\nexport const DEFAULT_TIMEOUT_MS = 30_000;\n\nexport const DEFAULT_REQUEST_ID_HEADER = 'x-local-client-request-id';\n\nexport const DEFAULT_REQUEST_ATTEMPT_HEADER = 'x-local-client-request-attempt';\n\nexport const DEFAULT_USER_AGENT = 'lifecycleion-http-client';\n\nexport const NON_RETRYABLE_HTTP_CLIENT_CALLBACK_ERROR_FLAG =\n '_lifecycleion_non_retryable_http_client_callback_error';\n\nexport const STREAM_FACTORY_ERROR_FLAG = '_lifecycleion_stream_factory_error';\n\n/**\n * Attached to the AbortError thrown when a StreamResponseFactory returns null\n * or `{ cancel: true, reason? }`. The value is the reason string if provided,\n * or `true` if the factory cancelled without a reason. Lets HTTPClient surface\n * the reason on HTTPClientError.cancelReason.\n */\nexport const STREAM_FACTORY_CANCEL_KEY =\n '_lifecycleion_stream_factory_cancel_reason';\n\nexport const RESPONSE_STREAM_ABORT_FLAG = '_lifecycleion_response_stream_abort';\n\n/**\n * Set on the AbortError thrown by XHRAdapter's defensive `timeout` event\n * listener. Lets HTTPClient classify the error as a timeout (retryable) rather\n * than an unexpected abort (non-retryable cancel).\n */\nexport const XHR_BROWSER_TIMEOUT_FLAG = '_lifecycleion_xhr_browser_timeout';\n\nexport const HTTP_METHODS: ReadonlyArray<HTTPMethod> = [\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'HEAD',\n];\n\n/**\n * Exact-match request headers that browsers either forbid outright or do not\n * let this client set reliably via plain Fetch/XHR headers.\n *\n * Prefix-based rules like `proxy-*` and `sec-*` are handled in `header-utils.ts`.\n */\nexport const BROWSER_RESTRICTED_HEADERS: ReadonlySet<string> = new Set([\n // Encoding / CORS negotiation headers controlled by the browser.\n 'accept-charset',\n 'accept-encoding',\n 'access-control-request-headers',\n 'access-control-request-method',\n 'access-control-request-private-network',\n\n // Connection-level transport headers.\n 'connection',\n 'content-length',\n 'date',\n 'expect',\n 'host',\n 'keep-alive',\n 'te',\n 'trailer',\n 'transfer-encoding',\n 'upgrade',\n 'via',\n\n // Browser-managed request context / privacy headers.\n 'cookie',\n 'dnt',\n 'origin',\n 'referer',\n 'set-cookie',\n 'user-agent',\n]);\n\nexport const BROWSER_RESTRICTED_HEADER_PREFIXES: ReadonlyArray<string> = [\n 'proxy-',\n 'sec-',\n];\n\n/**\n * Headers that can tunnel the real method through POST. Browsers block these\n * when they try to smuggle forbidden transport methods.\n */\nexport const BROWSER_METHOD_OVERRIDE_HEADER_NAMES: ReadonlySet<string> =\n new Set(['x-http-method', 'x-http-method-override', 'x-method-override']);\n\n/**\n * Methods that browsers do not allow request headers to tunnel via the\n * override headers above.\n */\nexport const BROWSER_FORBIDDEN_METHOD_OVERRIDE_VALUES: ReadonlySet<string> =\n new Set(['connect', 'trace', 'track']);\n\nexport const DEFAULT_MAX_REDIRECTS = 5;\n\n/**\n * Redirect responses that carry a follow-up `Location` hop. `300` and `304`\n * are excluded because they do not represent an automatic redirect here.\n */\nexport const REDIRECT_STATUS_CODES: ReadonlySet<number> = new Set([\n // 301 Moved Permanently\n 301,\n // 302 Found\n 302,\n\n // 303 See Other\n 303,\n\n // 307 Temporary Redirect\n 307,\n // 308 Permanent Redirect\n 308,\n]);\n","import { extractFetchHeaders, resolveDetectedRedirectURL } from '../utils';\nimport { REDIRECT_STATUS_CODES } from '../consts';\nimport type {\n HTTPAdapter,\n AdapterRequest,\n AdapterResponse,\n AdapterType,\n} from '../types';\n\nexport class FetchAdapter implements HTTPAdapter {\n public getType(): AdapterType {\n return 'fetch';\n }\n\n public async send(request: AdapterRequest): Promise<AdapterResponse> {\n const { requestURL, method, headers, body, signal } = request;\n\n // Fire 0% upload progress\n request.onUploadProgress?.({ loaded: 0, total: 0, progress: 0 });\n\n let response: Response;\n\n try {\n response = await fetch(requestURL, {\n method,\n headers: materializeFetchHeaders(headers),\n body: body as BodyInit | null,\n signal: signal ?? null,\n redirect: 'manual',\n });\n } catch (error) {\n // Re-throw AbortErrors and any error thrown when the signal is already\n // aborted. When abort(string) is called, fetch rejects with the string\n // itself (not an AbortError), so checking signal.aborted covers that case.\n if (isAbortError(error) || signal?.aborted) {\n throw error; // preserve cancellation / timeout classification\n }\n\n return {\n status: 0,\n isTransportError: true,\n headers: {},\n body: null,\n errorCause: error instanceof Error ? error : new Error(String(error)),\n };\n }\n\n // Browser-only: `redirect: 'manual'` in a browser context yields an opaque\n // redirect response (status 0, no accessible Location header) due to CORS\n // security constraints. In server runtimes (Bun, Node) `redirect: 'manual'`\n // returns the real 3xx with a Location header, so this branch is never hit\n // there — the real status falls through to the normal return path below and\n // HTTPClient's redirect loop handles it as usual.\n if (response.type === 'opaqueredirect') {\n // Even though the client will classify this as redirect_disabled, the\n // browser completed the fetch operation. Emit terminal progress so the\n // browser adapters match the server/mock adapters' completion semantics.\n request.onUploadProgress?.({ loaded: 1, total: 1, progress: 1 });\n request.onDownloadProgress?.({ loaded: 0, total: 0, progress: 1 });\n\n return {\n status: 0,\n wasRedirectDetected: true,\n headers: {},\n body: null,\n };\n }\n\n // Fire 100% upload + download progress (fetch has no real per-chunk progress)\n request.onUploadProgress?.({ loaded: 1, total: 1, progress: 1 });\n\n const rawBody = await readResponseBody(method, response);\n\n request.onDownloadProgress?.({\n loaded: rawBody?.length ?? 0,\n total: rawBody?.length ?? 0,\n progress: 1,\n });\n\n const responseHeaders = extractFetchHeaders(response.headers);\n const detectedRedirectURL = resolveDetectedRedirectURL(\n requestURL,\n response.status,\n responseHeaders,\n );\n\n return {\n status: response.status,\n // Server/runtime manual redirects reach this path as real 3xx responses.\n // Browser opaque redirects returned above never reach this branch.\n wasRedirectDetected:\n detectedRedirectURL !== undefined ||\n REDIRECT_STATUS_CODES.has(response.status),\n ...(detectedRedirectURL ? { detectedRedirectURL } : {}),\n headers: responseHeaders,\n body: rawBody,\n };\n }\n}\n\nasync function readResponseBody(\n method: string,\n response: Response,\n): Promise<Uint8Array | null> {\n if (method === 'HEAD' || response.status === 204 || response.status === 304) {\n return null;\n }\n\n const buffer = await response.arrayBuffer();\n return new Uint8Array(buffer);\n}\n\nfunction isAbortError(error: unknown): boolean {\n return error instanceof Error && error.name === 'AbortError';\n}\n\nfunction materializeFetchHeaders(\n headers: Record<string, string | string[]>,\n): HeadersInit {\n let shouldUseHeadersObject = false;\n\n for (const value of Object.values(headers)) {\n if (Array.isArray(value)) {\n shouldUseHeadersObject = true;\n break;\n }\n }\n\n if (!shouldUseHeadersObject) {\n return headers as Record<string, string>;\n }\n\n const materialized = new Headers();\n\n for (const [key, value] of Object.entries(headers)) {\n if (Array.isArray(value)) {\n if (key.toLowerCase() === 'cookie') {\n materialized.set(key, value.join('; '));\n } else {\n for (const item of value) {\n materialized.append(key, item);\n }\n }\n } else {\n materialized.append(key, value);\n }\n }\n\n return materialized;\n}\n","import {\n BROWSER_FORBIDDEN_METHOD_OVERRIDE_VALUES,\n BROWSER_METHOD_OVERRIDE_HEADER_NAMES,\n BROWSER_RESTRICTED_HEADERS,\n BROWSER_RESTRICTED_HEADER_PREFIXES,\n} from '../consts';\n\nexport function isBrowserRestrictedHeader(\n key: string,\n value: string | undefined,\n): boolean {\n const lowerKey = key.toLowerCase();\n\n // Straight denylist: browsers block these header names outright.\n if (BROWSER_RESTRICTED_HEADERS.has(lowerKey)) {\n return true;\n }\n\n // Prefix-based denylist for browser-owned header namespaces like `sec-*`.\n if (\n BROWSER_RESTRICTED_HEADER_PREFIXES.some((prefix) =>\n lowerKey.startsWith(prefix),\n )\n ) {\n return true;\n }\n\n // Method-override headers are only restricted when they try to tunnel a\n // forbidden method such as TRACE/CONNECT/TRACK through an allowed verb.\n if (BROWSER_METHOD_OVERRIDE_HEADER_NAMES.has(lowerKey) && value) {\n return value\n .split(',')\n .some((method) =>\n BROWSER_FORBIDDEN_METHOD_OVERRIDE_VALUES.has(\n method.trim().toLowerCase(),\n ),\n );\n }\n\n return false;\n}\n\n/**\n * Throws if any of the given headers are browser-restricted.\n * Used by Fetch and XHR adapters to fail fast during development.\n */\nexport function assertNoBrowserRestrictedHeaders(\n headers: Record<string, string | string[]>,\n adapterName: string,\n): void {\n for (const [key, value] of Object.entries(headers)) {\n if (\n isBrowserRestrictedHeader(\n key,\n Array.isArray(value) ? value.join(', ') : value,\n )\n ) {\n throw new Error(\n `[${adapterName}] Cannot set browser-restricted header \"${key}\". ` +\n `Browsers silently ignore this header — remove it to avoid subtle bugs.`,\n );\n }\n }\n}\n\n/**\n * Returns true if the content-type indicates a JSON body.\n */\nexport function isJSONContentType(contentType: string | undefined): boolean {\n if (!contentType) {\n return false;\n }\n\n const lower = contentType.toLowerCase();\n return lower.includes('application/json') || lower.includes('+json');\n}\n","import type { RequestState } from './types';\n\nexport interface TrackedRequest {\n requestID: string;\n clientID: string;\n label?: string;\n state: RequestState;\n abortController: AbortController;\n}\n\n/**\n * Shared in-flight request map. One instance is shared between a root HTTPClient and\n * all its sub-clients so that cancelAll() cancels across all of them.\n */\nexport class RequestTracker {\n private requests: Map<string, TrackedRequest> = new Map();\n\n public add(entry: TrackedRequest): void {\n this.requests.set(entry.requestID, entry);\n }\n\n public remove(requestID: string): void {\n this.requests.delete(requestID);\n }\n\n public get(requestID: string): TrackedRequest | undefined {\n return this.requests.get(requestID);\n }\n\n public updateState(requestID: string, state: RequestState): void {\n const entry = this.requests.get(requestID);\n\n if (entry) {\n entry.state = state;\n }\n }\n\n /**\n * Cancels a single request by ID. Returns 1 if cancelled, 0 if not found.\n */\n public cancel(requestID: string, reason?: string): number {\n const entry = this.requests.get(requestID);\n\n if (entry) {\n entry.state = 'cancelled';\n entry.abortController.abort(reason);\n return 1;\n }\n\n return 0;\n }\n\n /**\n * Cancels ALL in-flight requests across the shared tracker (all clients).\n * Returns the number of requests cancelled.\n */\n public cancelAll(reason?: string): number {\n let count = 0;\n\n for (const entry of this.requests.values()) {\n entry.state = 'cancelled';\n entry.abortController.abort(reason);\n count++;\n }\n\n return count;\n }\n\n /**\n * Cancels all requests owned by a specific client.\n * Returns the number of requests cancelled.\n */\n public cancelOwn(clientID: string, reason?: string): number {\n let count = 0;\n\n for (const entry of this.requests.values()) {\n if (entry.clientID === clientID) {\n entry.state = 'cancelled';\n entry.abortController.abort(reason);\n count++;\n }\n }\n\n return count;\n }\n\n /**\n * Cancels all requests that have the given label (across all clients in the shared tracker).\n * Returns the number of requests cancelled.\n */\n public cancelAllWithLabel(label: string, reason?: string): number {\n let count = 0;\n\n for (const entry of this.requests.values()) {\n if (entry.label === label) {\n entry.state = 'cancelled';\n entry.abortController.abort(reason);\n count++;\n }\n }\n\n return count;\n }\n\n /**\n * Cancels requests owned by a specific client that also have the given label.\n * Returns the number of requests cancelled.\n */\n public cancelOwnWithLabel(\n clientID: string,\n label: string,\n reason?: string,\n ): number {\n let count = 0;\n\n for (const entry of this.requests.values()) {\n if (entry.clientID === clientID && entry.label === label) {\n entry.state = 'cancelled';\n entry.abortController.abort(reason);\n count++;\n }\n }\n\n return count;\n }\n\n /**\n * Returns a read-only view of tracked requests.\n *\n * Intentionally omits abortController,\n * callers cancel via cancel()/cancelAll()/etc. so that\n * the tracker remains the sole owner of state mutations.\n */\n public list(filter?: { clientID?: string; label?: string }): {\n count: number;\n requests: RequestInfo[];\n } {\n const requests: RequestInfo[] = [];\n\n for (const entry of this.requests.values()) {\n if (filter?.clientID && entry.clientID !== filter.clientID) {\n continue;\n }\n\n if (filter?.label && entry.label !== filter.label) {\n continue;\n }\n\n requests.push({\n requestID: entry.requestID,\n clientID: entry.clientID,\n label: entry.label,\n state: entry.state,\n });\n }\n\n return { count: requests.length, requests };\n }\n}\n\nexport interface RequestInfo {\n requestID: string;\n clientID: string;\n label?: string;\n state: RequestState;\n}\n","import { generateID } from '../id-helpers';\nimport type {\n HTTPMethod,\n HTTPResponse,\n HTTPRequestOptions,\n HTTPProgressEvent,\n AttemptStartEvent,\n AttemptEndEvent,\n RequestState,\n HTTPClientError,\n StreamResponseFactory,\n} from './types';\nimport type { RetryPolicyOptions } from '../retry-utils';\n\nexport interface BuilderCallbacks<T> {\n setState: (state: RequestState) => void;\n setResponse: (response: HTTPResponse<T>) => void;\n setError: (error: HTTPClientError) => void;\n setAttemptCount: (count: number) => void;\n setNextRetryDelayMS: (delayMS: number | null) => void;\n setNextRetryAt: (timestampMS: number | null) => void;\n setStartedAt: (timestampMS: number) => void;\n setCancelFn: (fn: (reason?: string) => void) => void;\n}\n\nexport interface BuilderSendContext<T = unknown> {\n method: HTTPMethod;\n path: string;\n requestID: string;\n options: ResolvedBuilderOptions;\n callbacks: BuilderCallbacks<T>;\n}\n\nexport interface ResolvedBuilderOptions extends HTTPRequestOptions {\n headers: Record<string, string | string[]>;\n}\n\ntype SendFn<T> = (context: BuilderSendContext<T>) => Promise<HTTPResponse<T>>;\n\n/**\n * Fluent, single-use request builder. Returned by HTTPClient methods.\n * Call .send() to execute the request.\n */\nexport class HTTPRequestBuilder<T = unknown> {\n private _method: HTTPMethod;\n private _path: string;\n private _headers: Record<string, string | string[]> = {};\n private _params?: Record<string, unknown>;\n private _body?: unknown;\n private _timeout?: number;\n private _signal?: AbortSignal;\n private _retryPolicy?: RetryPolicyOptions | null;\n private _label?: string;\n private _onUploadProgress?: (event: HTTPProgressEvent) => void;\n private _onDownloadProgress?: (event: HTTPProgressEvent) => void;\n private _onAttemptStart?: (event: AttemptStartEvent) => void;\n private _onAttemptEnd?: (event: AttemptEndEvent) => void;\n private _streamResponse?: StreamResponseFactory;\n\n private _sendFn: SendFn<T>;\n private _sent = false;\n\n // Post-send state (public read-only after send)\n private _requestID: string = generateID('ulid');\n private _state: RequestState = 'pending';\n private _response: HTTPResponse<T> | null = null;\n private _error: HTTPClientError | null = null;\n private _attemptCount: number | null = null;\n private _nextRetryDelayMS: number | null = null;\n private _nextRetryAt: number | null = null;\n private _startedAt: number | null = null;\n private _completedAt: number | null = null;\n private _cancelFn: ((reason?: string) => void) | null = null;\n private _preSendCancelReason: string | undefined = undefined;\n\n constructor(\n method: HTTPMethod,\n path: string,\n sendFn: SendFn<T>,\n options?: HTTPRequestOptions,\n ) {\n this._method = method;\n this._path = path;\n this._sendFn = sendFn;\n\n if (options) {\n this._applyOptions(options);\n }\n }\n\n // --- Fluent builder methods ---\n\n public headers(headers: Record<string, string | string[]>): this {\n this._assertNotSent('headers');\n Object.assign(this._headers, headers);\n return this;\n }\n\n public params(params: Record<string, unknown>): this {\n this._assertNotSent('params');\n this._params = params;\n return this;\n }\n\n public json(data: unknown): this {\n this._assertNotSent('json');\n this._body = data;\n return this;\n }\n\n public formData(data: FormData): this {\n this._assertNotSent('formData');\n this._body = data;\n return this;\n }\n\n public text(data: string): this {\n this._assertNotSent('text');\n this._body = data;\n return this;\n }\n\n public body(data: unknown): this {\n this._assertNotSent('body');\n this._body = data;\n return this;\n }\n\n public timeout(ms: number): this {\n this._assertNotSent('timeout');\n this._timeout = ms;\n return this;\n }\n\n public signal(abortSignal: AbortSignal): this {\n this._assertNotSent('signal');\n this._signal = abortSignal;\n return this;\n }\n\n public label(label: string): this {\n this._assertNotSent('label');\n\n if (label.trim().length === 0) {\n throw new Error(\n 'HTTPRequestBuilder.label() requires a non-empty, non-whitespace label.',\n );\n }\n\n this._label = label;\n return this;\n }\n\n public retryPolicy(options: RetryPolicyOptions | null): this {\n this._assertNotSent('retryPolicy');\n this._retryPolicy = options;\n return this;\n }\n\n public onUploadProgress(fn: (event: HTTPProgressEvent) => void): this {\n this._assertNotSent('onUploadProgress');\n this._onUploadProgress = fn;\n return this;\n }\n\n public onDownloadProgress(fn: (event: HTTPProgressEvent) => void): this {\n this._assertNotSent('onDownloadProgress');\n this._onDownloadProgress = fn;\n return this;\n }\n\n public onAttemptStart(fn: (event: AttemptStartEvent) => void): this {\n this._assertNotSent('onAttemptStart');\n this._onAttemptStart = fn;\n return this;\n }\n\n public onAttemptEnd(fn: (event: AttemptEndEvent) => void): this {\n this._assertNotSent('onAttemptEnd');\n this._onAttemptEnd = fn;\n return this;\n }\n\n /**\n * NodeAdapter only. Called after response headers arrive on a 200 response,\n * before any body bytes are read. Return a WritableLike to pipe the body into\n * it, or null to cancel the request entirely.\n *\n * The context provides an attempt-scoped AbortSignal that fires on cancel,\n * timeout, or stream write failure — useful for co-locating cleanup with setup:\n *\n * .streamResponse((_info, { signal }) => {\n * const stream = createWriteStream('/tmp/file.bin');\n *\n * signal.addEventListener('abort', () => {\n * stream.destroy();\n * fs.unlinkSync('/tmp/file.bin'); // clean up partial file\n * });\n * return stream;\n * })\n *\n * HTTPClient rejects non-node adapters before dispatch if this is set.\n */\n public streamResponse(fn: StreamResponseFactory): this {\n this._assertNotSent('streamResponse');\n this._streamResponse = fn;\n return this;\n }\n\n // --- Post-send accessors ---\n\n public get requestID(): string {\n return this._requestID;\n }\n\n public get state(): RequestState {\n return this._state;\n }\n\n public get response(): HTTPResponse<T> | null {\n return this._response;\n }\n\n public get error(): HTTPClientError | null {\n return this._error;\n }\n\n public get attemptCount(): number | null {\n return this._attemptCount;\n }\n\n public get nextRetryDelayMS(): number | null {\n return this._nextRetryDelayMS;\n }\n\n public get nextRetryAt(): number | null {\n return this._nextRetryAt;\n }\n\n /** Epoch ms when the first attempt was dispatched. null before send(). */\n public get startedAt(): number | null {\n return this._startedAt;\n }\n\n /** Total wall-clock ms since the first attempt, including retry waits. null before send().\n * Freezes once the request completes.\n */\n public get elapsedMS(): number | null {\n if (this._startedAt === null) {\n return null;\n }\n\n const end = this._completedAt ?? Date.now();\n return end - this._startedAt;\n }\n\n /**\n * Cancels the request. Returns true if the cancel was applied, false if it\n * was a no-op (already completed, cancelled, or failed).\n *\n * Calling cancel() before send() marks the builder as cancelled so that\n * send() throws instead of dispatching the request.\n */\n public cancel(reason?: string): boolean {\n if (\n this._state === 'completed' ||\n this._state === 'cancelled' ||\n this._state === 'failed'\n ) {\n return false;\n }\n\n // Pre-send cancel: mark as cancelled so send() is blocked\n if (!this._sent) {\n this._state = 'cancelled';\n this._preSendCancelReason = reason;\n return true;\n }\n\n if (this._cancelFn) {\n this._cancelFn(reason);\n return true;\n }\n\n return false;\n }\n\n // --- Execute ---\n\n public async send<U = T>(): Promise<HTTPResponse<U>> {\n if (this._state === 'cancelled') {\n const reasonSuffix =\n this._preSendCancelReason !== undefined\n ? ` (reason: '${this._preSendCancelReason}')`\n : '';\n throw new Error(\n `HTTPRequestBuilder.send() cannot be called after cancel() has been called.${reasonSuffix}`,\n );\n }\n\n if (this._sent) {\n throw new Error(\n 'HTTPRequestBuilder.send() can only be called once per builder instance.',\n );\n }\n\n this._sent = true;\n\n const response = await this._sendFn({\n method: this._method,\n path: this._path,\n requestID: this._requestID,\n options: {\n headers: this._headers,\n params: this._params,\n body: this._body,\n timeout: this._timeout,\n signal: this._signal,\n retryPolicy: this._retryPolicy,\n label: this._label,\n onUploadProgress: this._onUploadProgress,\n onDownloadProgress: this._onDownloadProgress,\n onAttemptStart: this._onAttemptStart,\n onAttemptEnd: this._onAttemptEnd,\n streamResponse: this._streamResponse,\n },\n callbacks: {\n setState: (state) => {\n this._state = state;\n\n if (\n state === 'completed' ||\n state === 'cancelled' ||\n state === 'failed'\n ) {\n this._completedAt = Date.now();\n }\n },\n setResponse: (res) => {\n this._response = res;\n },\n setError: (err) => {\n this._error = err;\n },\n setAttemptCount: (count) => {\n this._attemptCount = count;\n },\n setNextRetryDelayMS: (delayMS) => {\n this._nextRetryDelayMS = delayMS;\n },\n setNextRetryAt: (timestampMS) => {\n this._nextRetryAt = timestampMS;\n },\n setStartedAt: (timestampMS) => {\n this._startedAt = timestampMS;\n },\n setCancelFn: (fn) => {\n this._cancelFn = fn;\n },\n },\n });\n\n return response as unknown as HTTPResponse<U>;\n }\n\n // --- Private helpers ---\n\n private _applyOptions(opts: HTTPRequestOptions): void {\n // Request headers merged on top of any defaults\n if (opts.headers) {\n this.headers(opts.headers);\n }\n\n // URL query params\n if (opts.params) {\n this.params(opts.params);\n }\n\n // Body — type determines serialization (FormData → multipart, string → text/plain, object → JSON).\n // A custom content-type header overrides the auto-detected one.\n if (opts.body !== undefined) {\n this.body(opts.body);\n }\n\n // Request-level timeout in ms\n if (opts.timeout !== undefined) {\n this.timeout(opts.timeout);\n }\n\n // External abort signal — merged with the internal one so both can cancel\n if (opts.signal) {\n this.signal(opts.signal);\n }\n\n // Retry behavior — null explicitly disables retrying\n if (opts.retryPolicy !== undefined) {\n this.retryPolicy(opts.retryPolicy);\n }\n\n // Tracking label for cancel/list filtering\n if (opts.label !== undefined) {\n this.label(opts.label);\n }\n\n // Progress callbacks - upload\n if (opts.onUploadProgress) {\n this.onUploadProgress(opts.onUploadProgress);\n }\n\n // Progress callbacks - download\n if (opts.onDownloadProgress) {\n this.onDownloadProgress(opts.onDownloadProgress);\n }\n\n // Called before each attempt (including retries)\n if (opts.onAttemptStart) {\n this.onAttemptStart(opts.onAttemptStart);\n }\n\n // Called after each attempt (including retries)\n if (opts.onAttemptEnd) {\n this.onAttemptEnd(opts.onAttemptEnd);\n }\n\n // NodeAdapter response streaming factory\n if (opts.streamResponse) {\n this.streamResponse(opts.streamResponse);\n }\n }\n\n private _assertNotSent(method: string): void {\n if (this._sent) {\n throw new Error(\n `Cannot call .${method}() after .send() has been called. Builders are single-use.`,\n );\n }\n }\n}\n","import { matchesFilter } from './utils';\nimport type {\n RequestInterceptorFilter,\n RequestInterceptor,\n RequestInterceptorContext,\n InterceptedRequest,\n InterceptorCancel,\n InterceptorPhase,\n} from './types';\n\ninterface RegisteredInterceptor<T> {\n fn: T;\n filter?: RequestInterceptorFilter;\n}\n\ntype RemoveFn = () => void;\nconst DEFAULT_INTERCEPTOR_PHASES: RequestInterceptorFilter['phases'] = [\n 'initial',\n];\n\nexport class RequestInterceptorManager {\n private interceptors: RegisteredInterceptor<RequestInterceptor>[] = [];\n\n public add(\n fn: RequestInterceptor,\n filter?: RequestInterceptorFilter,\n ): RemoveFn {\n const entry: RegisteredInterceptor<RequestInterceptor> = {\n fn,\n filter: {\n ...filter,\n phases: filter?.phases ?? DEFAULT_INTERCEPTOR_PHASES,\n },\n };\n this.interceptors.push(entry);\n\n return () => {\n const idx = this.interceptors.indexOf(entry);\n\n if (idx !== -1) {\n this.interceptors.splice(idx, 1);\n }\n };\n }\n\n public async run(\n request: InterceptedRequest,\n phase: InterceptorPhase,\n context: RequestInterceptorContext,\n ): Promise<InterceptedRequest | InterceptorCancel> {\n let current = request;\n\n for (const { fn, filter } of this.interceptors) {\n if (\n !matchesFilter(\n filter ?? {},\n {\n method: current.method,\n requestURL: current.requestURL,\n body: current.body,\n },\n phase.type,\n 'request',\n )\n ) {\n continue;\n }\n\n const result = await fn(current, phase, context);\n\n // null is shorthand for { cancel: true } with no reason\n if (result === null) {\n return { cancel: true };\n }\n\n // Interceptor signalled cancellation with optional reason\n if (result && 'cancel' in result && result.cancel === true) {\n return result;\n }\n\n current = result as InterceptedRequest;\n }\n\n return current;\n }\n}\n","import { safeHandleCallbackAndWait } from '../safe-handle-callback';\nimport { matchesFilter, scalarHeader } from './utils';\nimport type {\n ResponseObserverFilter,\n ErrorObserverFilter,\n ResponseObserver,\n ErrorObserver,\n AttemptRequest,\n HTTPResponse,\n HTTPClientError,\n ResponseObserverPhase,\n ErrorObserverPhase,\n} from './types';\n\ntype RemoveFn = () => void;\nconst DEFAULT_OBSERVER_PHASES: ResponseObserverFilter['phases'] = ['final'];\nconst DEFAULT_ERROR_OBSERVER_PHASES: ErrorObserverFilter['phases'] = ['final'];\n\nexport class ResponseObserverManager {\n private observers: Array<{\n fn: ResponseObserver;\n filter?: ResponseObserverFilter;\n }> = [];\n\n public add(fn: ResponseObserver, filter?: ResponseObserverFilter): RemoveFn {\n const entry = {\n fn,\n filter: {\n ...filter,\n phases: filter?.phases ?? DEFAULT_OBSERVER_PHASES,\n },\n };\n this.observers.push(entry);\n\n return () => {\n const idx = this.observers.indexOf(entry);\n\n if (idx !== -1) {\n this.observers.splice(idx, 1);\n }\n };\n }\n\n public async run(\n response: HTTPResponse,\n request: AttemptRequest,\n phase: ResponseObserverPhase,\n ): Promise<void> {\n for (const { fn, filter } of this.observers) {\n if (\n !matchesFilter(\n filter ?? {},\n {\n status: response.status,\n method: request.method,\n requestURL: request.requestURL,\n body: response.body,\n contentType: response.contentType,\n contentTypeHeader: scalarHeader(response.headers, 'content-type'),\n },\n phase.type,\n 'response',\n )\n ) {\n continue;\n }\n\n await safeHandleCallbackAndWait(\n 'ResponseObserver',\n fn,\n response,\n request,\n phase,\n );\n }\n }\n}\n\nexport class ErrorObserverManager {\n private observers: Array<{\n fn: ErrorObserver;\n filter?: ErrorObserverFilter;\n }> = [];\n\n public add(fn: ErrorObserver, filter?: ErrorObserverFilter): RemoveFn {\n const entry = {\n fn,\n filter: {\n ...filter,\n phases: filter?.phases ?? DEFAULT_ERROR_OBSERVER_PHASES,\n },\n };\n this.observers.push(entry);\n\n return () => {\n const idx = this.observers.indexOf(entry);\n\n if (idx !== -1) {\n this.observers.splice(idx, 1);\n }\n };\n }\n\n public async run(\n error: HTTPClientError,\n request: AttemptRequest,\n phase: ErrorObserverPhase,\n ): Promise<void> {\n for (const { fn, filter } of this.observers) {\n if (\n !matchesFilter(\n filter ?? {},\n {\n method: request.method,\n requestURL: request.requestURL,\n },\n phase.type,\n 'error',\n )\n ) {\n continue;\n }\n\n await safeHandleCallbackAndWait(\n 'ErrorObserver',\n fn,\n error,\n request,\n phase,\n );\n }\n }\n}\n","import { generateID } from '../id-helpers';\nimport { deepClone } from '../deep-clone';\nimport { RetryPolicy } from '../retry-utils';\nimport { FetchAdapter } from './adapters/fetch-adapter';\nimport { assertNoBrowserRestrictedHeaders } from './internal/header-utils';\nimport { RequestTracker } from './request-tracker';\nimport type { RequestInfo } from './request-tracker';\nimport { HTTPRequestBuilder } from './http-request-builder';\nimport { RequestInterceptorManager } from './interceptors';\nimport { ResponseObserverManager, ErrorObserverManager } from './observers';\nimport {\n assertSupportedAdapterRuntimeAndConfig,\n assertSupportedRequestBody,\n buildURL,\n isBrowserEnvironment,\n mergeObservedHeaders,\n mergeHeaders,\n normalizeAdapterResponseHeaders,\n parseContentType,\n resolveAbsoluteURL,\n resolveAbsoluteURLForRuntime,\n scalarHeader,\n serializeBody,\n} from './utils';\nimport {\n DEFAULT_TIMEOUT_MS,\n DEFAULT_REQUEST_ID_HEADER,\n DEFAULT_REQUEST_ATTEMPT_HEADER,\n DEFAULT_USER_AGENT,\n NON_RETRYABLE_HTTP_CLIENT_CALLBACK_ERROR_FLAG,\n RESPONSE_STREAM_ABORT_FLAG,\n STREAM_FACTORY_CANCEL_KEY,\n STREAM_FACTORY_ERROR_FLAG,\n XHR_BROWSER_TIMEOUT_FLAG,\n RETRYABLE_STATUS_CODES,\n REDIRECT_STATUS_CODES,\n DEFAULT_MAX_REDIRECTS,\n} from './consts';\nimport type {\n HTTPClientConfig,\n HTTPMethod,\n HTTPResponse,\n HTTPClientError,\n InterceptedRequest,\n AttemptRequest,\n RequestInterceptorFilter,\n RequestInterceptor,\n ResponseObserver,\n ResponseObserverFilter,\n ErrorObserver,\n ErrorObserverFilter,\n AdapterType,\n AdapterResponse,\n HTTPRequestOptions,\n RedirectHopInfo,\n InterceptorCancel,\n RequestInterceptorContext,\n SubClientConfig,\n InterceptorPhase,\n ResponseObserverPhase,\n ErrorObserverPhase,\n} from './types';\nimport type {\n BuilderCallbacks,\n ResolvedBuilderOptions,\n BuilderSendContext,\n} from './http-request-builder';\nimport type { RetryPolicyOptions } from '../retry-utils';\nimport type { CookieJar } from './cookie-jar';\n\ntype RemoveFn = () => void;\n\ninterface InternalClientState {\n tracker?: RequestTracker;\n parentClient?: BaseHTTPClient | null;\n}\n\nexport class BaseHTTPClient {\n protected _clientID: string;\n protected _config: Required<\n Pick<\n HTTPClientConfig,\n | 'timeout'\n | 'includeRequestID'\n | 'includeAttemptHeader'\n | 'followRedirects'\n | 'maxRedirects'\n >\n > &\n HTTPClientConfig;\n\n protected _adapter: NonNullable<HTTPClientConfig['adapter']>;\n protected _tracker: RequestTracker;\n protected _parentClient: BaseHTTPClient | null;\n protected _isBrowserRuntime: boolean;\n\n private _requestInterceptors: RequestInterceptorManager;\n private _responseObservers: ResponseObserverManager;\n private _errorObservers: ErrorObserverManager;\n\n private _disabled = false;\n\n constructor(\n config: HTTPClientConfig = {},\n internal: InternalClientState = {},\n ) {\n this._clientID = generateID('ulid');\n this._adapter = config.adapter ?? new FetchAdapter();\n this._isBrowserRuntime = isBrowserEnvironment();\n assertSupportedAdapterRuntimeAndConfig(\n config,\n this._adapter.getType(),\n this._isBrowserRuntime,\n );\n this._tracker = internal.tracker ?? new RequestTracker();\n this._parentClient = internal.parentClient ?? null;\n\n this._config = {\n adapter: this._adapter,\n baseURL: config.baseURL,\n defaultHeaders: config.defaultHeaders ?? {},\n timeout: config.timeout ?? DEFAULT_TIMEOUT_MS,\n cookieJar: config.cookieJar,\n retryPolicy: config.retryPolicy,\n includeRequestID: config.includeRequestID ?? false,\n includeAttemptHeader: config.includeAttemptHeader ?? false,\n userAgent: config.userAgent,\n followRedirects: config.followRedirects ?? false,\n maxRedirects: config.maxRedirects ?? DEFAULT_MAX_REDIRECTS,\n };\n\n this._requestInterceptors = new RequestInterceptorManager();\n this._responseObservers = new ResponseObserverManager();\n this._errorObservers = new ErrorObserverManager();\n }\n\n // --- Client metadata ---\n\n public get clientID(): string {\n return this._clientID;\n }\n\n public get adapterType(): AdapterType {\n return this._adapter.getType();\n }\n\n // --- Interceptors ---\n\n public addRequestInterceptor(\n fn: RequestInterceptor,\n filter?: RequestInterceptorFilter,\n ): RemoveFn {\n return this._requestInterceptors.add(fn, filter);\n }\n\n public addResponseObserver(\n fn: ResponseObserver,\n filter?: ResponseObserverFilter,\n ): RemoveFn {\n return this._responseObservers.add(fn, filter);\n }\n\n public addErrorObserver(\n fn: ErrorObserver,\n filter?: ErrorObserverFilter,\n ): RemoveFn {\n return this._errorObservers.add(fn, filter);\n }\n\n // --- Request methods ---\n\n /**\n * Start a request. `path` is usually **relative** to {@link HTTPClientConfig.baseURL}\n * when `baseURL` is set (e.g. `/v1/users`, `v1/users`).\n *\n * You may also pass a full **`http:` / `https:`** URL or a **protocol-relative**\n * `//host/...` string; those are **not** concatenated onto `baseURL`, so one\n * client can occasionally target another origin without a sub-client. The\n * final string is still run through `resolveAbsoluteURL` with `baseURL` so\n * `//…` picks up the right scheme. See `buildURL` in `./utils`.\n */\n public request<T = unknown>(\n method: HTTPMethod,\n path: string,\n options?: HTTPRequestOptions,\n ): HTTPRequestBuilder<T> {\n return new HTTPRequestBuilder<T>(\n method,\n path,\n (ctx) => this._execute(ctx),\n options,\n );\n }\n\n public get<T = unknown>(\n path: string,\n options?: HTTPRequestOptions,\n ): HTTPRequestBuilder<T> {\n return this.request<T>('GET', path, options);\n }\n\n public post<T = unknown>(\n path: string,\n options?: HTTPRequestOptions,\n ): HTTPRequestBuilder<T> {\n return this.request<T>('POST', path, options);\n }\n\n public put<T = unknown>(\n path: string,\n options?: HTTPRequestOptions,\n ): HTTPRequestBuilder<T> {\n return this.request<T>('PUT', path, options);\n }\n\n public patch<T = unknown>(\n path: string,\n options?: HTTPRequestOptions,\n ): HTTPRequestBuilder<T> {\n return this.request<T>('PATCH', path, options);\n }\n\n public delete<T = unknown>(\n path: string,\n options?: HTTPRequestOptions,\n ): HTTPRequestBuilder<T> {\n return this.request<T>('DELETE', path, options);\n }\n\n public head<T = unknown>(\n path: string,\n options?: HTTPRequestOptions,\n ): HTTPRequestBuilder<T> {\n return this.request<T>('HEAD', path, options);\n }\n\n // --- Cancellation ---\n\n public cancel(requestID: string, reason?: string): void {\n this._tracker.cancel(requestID, reason);\n }\n\n public cancelAll(reason?: string): void {\n this._tracker.cancelAll(reason);\n }\n\n public cancelOwn(reason?: string): void {\n this._tracker.cancelOwn(this._clientID, reason);\n }\n\n public cancelAllWithLabel(label: string, reason?: string): void {\n this._tracker.cancelAllWithLabel(label, reason);\n }\n\n public cancelOwnWithLabel(label: string, reason?: string): void {\n this._tracker.cancelOwnWithLabel(this._clientID, label, reason);\n }\n\n // --- Request inspection ---\n\n public listRequests(filter?: { scope?: 'own' | 'all'; label?: string }): {\n count: number;\n requests: RequestInfo[];\n } {\n const scope = filter?.scope ?? 'own';\n\n return this._tracker.list({\n clientID: scope === 'own' ? this._clientID : undefined,\n label: filter?.label,\n });\n }\n\n // --- Enable/disable ---\n\n public disable(): void {\n this._disabled = true;\n }\n\n public enable(): void {\n this._disabled = false;\n }\n\n public get isDisabled(): boolean {\n if (this._disabled) {\n return true;\n } else if (this._parentClient?.isDisabled) {\n return true;\n }\n\n return false;\n }\n\n // --- Sub-client configuration ---\n\n protected _buildSubClientConfig(\n overrides: SubClientConfig = {},\n ): HTTPClientConfig {\n const shouldFollowRedirects =\n overrides.followRedirects ?? this._config.followRedirects;\n const defaultHeaders =\n overrides.defaultHeadersStrategy === 'merge'\n ? mergeHeaders(this._config.defaultHeaders, overrides.defaultHeaders)\n : (overrides.defaultHeaders ?? this._config.defaultHeaders);\n\n const config: HTTPClientConfig = {\n ...this._config,\n ...overrides,\n defaultHeaders,\n followRedirects: shouldFollowRedirects,\n adapter: overrides.adapter ?? this._adapter,\n cookieJar:\n overrides.cookieJar !== undefined\n ? overrides.cookieJar\n : this._config.cookieJar,\n };\n\n if (\n shouldFollowRedirects === false &&\n overrides.maxRedirects === undefined\n ) {\n delete config.maxRedirects;\n }\n\n return config;\n }\n\n // --- Core execution ---\n\n private async _execute<T>(\n ctx: BuilderSendContext<T>,\n ): Promise<HTTPResponse<T>> {\n // Main request orchestration:\n // 1. Build URL, merge headers, apply user-agent\n // 2. Check pre-aborted signal → early cancel\n // 3. Create AbortController + wire builder.cancel()\n // 4. Run request interceptor chain\n // 5. Apply cookie jar\n // 6. Serialize body\n // 7. Create shared RetryPolicy instance\n // 8. _dispatchRequestAttempts → retry loop (sends via adapter)\n // 9. If redirect status → follow redirect (iterative loop, shares retry budget)\n // 10. Build final response, run observers, freeze timing\n if (this.isDisabled) {\n throw new Error(\n 'HTTPClient is disabled. Call .enable() before sending requests.',\n );\n }\n\n const { method, path, requestID, options, callbacks } = ctx;\n\n // Wire up builder state\n callbacks.setState('sending');\n\n // buildURL: relative path + baseURL, OR absolute http(s) / //host path unchanged.\n // For MockAdapter only, synthesize a deterministic absolute base URL when\n // no baseURL is configured so interceptors and observers do not depend on\n // ambient browser location state:\n // - true path-only inputs -> http://localhost/...\n // - protocol-relative //host/... inputs -> http://host/...\n // Other non-HTTP absolute-like inputs still fail validation later.\n const effectiveBaseURL =\n this._config.baseURL ??\n (this._adapter.getType() === 'mock'\n ? !/^[a-z][a-z0-9+\\-.]*:/i.test(path)\n ? 'http://localhost'\n : undefined\n : undefined);\n\n const url = resolveAbsoluteURLForRuntime(\n buildURL(effectiveBaseURL, path, options.params),\n effectiveBaseURL,\n this._isBrowserRuntime,\n );\n const timeout = options.timeout ?? this._config.timeout;\n\n // Merge headers\n const baseHeaders = mergeHeaders(\n this._config.defaultHeaders,\n options.headers,\n );\n\n if (this._config.includeRequestID) {\n baseHeaders[DEFAULT_REQUEST_ID_HEADER] = requestID;\n }\n\n const adapterType = this._adapter.getType();\n\n if (\n this._config.userAgent &&\n (adapterType === 'node' ||\n adapterType === 'fetch' ||\n adapterType === 'mock')\n ) {\n baseHeaders['user-agent'] = this._config.userAgent;\n } else if (\n adapterType === 'node' ||\n adapterType === 'mock' ||\n (adapterType === 'fetch' && !this._isBrowserRuntime)\n ) {\n baseHeaders['user-agent'] = DEFAULT_USER_AGENT;\n }\n\n // Build intercepted request context\n const interceptedRequest: InterceptedRequest = {\n requestURL: url,\n method,\n headers: baseHeaders,\n body: options.body,\n };\n\n // Short-circuit already-aborted external signals so we do not run\n // interceptors, tracking, retries, or adapter dispatch at all.\n if (options.signal?.aborted) {\n callbacks.setAttemptCount(0);\n callbacks.setNextRetryDelayMS(null);\n callbacks.setNextRetryAt(null);\n\n const response = this._buildResponse<T>({\n adapterResponse: null,\n requestID,\n wasCancelled: true,\n wasTimeout: false,\n adapterType: this._adapter.getType(),\n initialURL: interceptedRequest.requestURL,\n requestURL: interceptedRequest.requestURL,\n redirectHistory: [],\n });\n\n const error = this._makeError(\n response,\n requestID,\n false,\n undefined,\n undefined,\n options.signal ? getSignalCancelReason(options.signal) : undefined,\n );\n callbacks.setError(error);\n callbacks.setState('cancelled');\n await this._runErrorObservers(\n error,\n this._bestEffortAttemptRequestFromPending(\n interceptedRequest,\n timeout,\n requestID,\n ),\n {\n type: 'final',\n },\n );\n callbacks.setResponse(response);\n return response;\n }\n\n // Setup AbortController + tracker\n const abortController = new AbortController();\n this._tracker.add({\n requestID,\n clientID: this._clientID,\n label: options.label,\n state: 'sending',\n abortController,\n });\n\n const trackedCallbacks: BuilderCallbacks<T> = {\n ...callbacks,\n setState: (state) => {\n callbacks.setState(state);\n this._tracker.updateState(requestID, state);\n },\n };\n\n // Wire builder.cancel() to our abort controller\n trackedCallbacks.setCancelFn((reason?: string) => {\n abortController.abort(reason);\n });\n\n // Compose user signal with our internal abort controller\n let cancelSignal: AbortSignal = abortController.signal;\n\n if (options.signal) {\n cancelSignal = this._composeSignals(\n options.signal,\n abortController.signal,\n );\n }\n\n try {\n let finalRequest = interceptedRequest;\n let response: HTTPResponse<T>;\n let observerRequest = this._bestEffortAttemptRequestFromPending(\n interceptedRequest,\n timeout,\n requestID,\n );\n let errorCode: HTTPClientError['code'] | undefined;\n let adapterCause: Error | undefined;\n let cancelReason: string | undefined;\n let isRetriesExhausted = false;\n let completedAttemptCount = 0;\n\n try {\n // streamResponse is NodeAdapter-only. Validate it inside the normal\n // request setup flow so builder/error observer state is updated the same\n // way as every other request_setup_error.\n if (options.streamResponse && this._adapter.getType() !== 'node') {\n throw new Error(\n `[HTTPClient] .streamResponse() requires NodeAdapter. Current adapter: ${this._adapter.getType()}`,\n );\n }\n\n // Validate the resolved URL is a proper http(s) URL. Protocol-relative\n // //host paths without a baseURL to supply the scheme stay unresolved and\n // must fail here as a request_setup_error rather than reaching the adapter.\n if (!this._isSupportedRequestURL(url)) {\n throw new Error(\n `[HTTPClient] Request URL could not be resolved to an absolute http(s) URL: \"${url}\". ` +\n `Set a baseURL with an http(s) scheme or pass an absolute URL.`,\n );\n }\n\n this._assertRequestIsSupported(interceptedRequest);\n\n // Run interceptors (initial phase)\n const initialPhase: InterceptorPhase = { type: 'initial' };\n let interceptResult: InterceptedRequest | InterceptorCancel;\n let initialRequestCandidate: InterceptedRequest = finalRequest;\n\n try {\n interceptResult = await this._runInterceptors(\n finalRequest,\n initialPhase,\n {\n initialURL: url,\n redirectHistory: [],\n requestID,\n attemptNumber: 1,\n },\n );\n\n if (!('cancel' in interceptResult)) {\n initialRequestCandidate = interceptResult;\n this._assertRequestIsSupported(interceptResult);\n this._assertInterceptorResolvedURL(interceptResult.requestURL);\n }\n } catch (error) {\n const response = this._buildResponse<T>({\n adapterResponse: null,\n requestID,\n wasCancelled: false,\n wasTimeout: false,\n adapterType: this._adapter.getType(),\n initialURL: url,\n requestURL: initialRequestCandidate.requestURL,\n redirectHistory: [],\n isNetworkErrorOverride: false,\n });\n\n const normalizedError = this._makeError(\n response,\n requestID,\n false,\n 'interceptor_error',\n error instanceof Error ? error : new Error(String(error)),\n );\n\n callbacks.setError(normalizedError);\n trackedCallbacks.setState('failed');\n callbacks.setResponse(response);\n\n await this._runErrorObservers(\n normalizedError,\n this._bestEffortAttemptRequestFromPending(\n initialRequestCandidate,\n timeout,\n requestID,\n ),\n {\n type: 'final',\n },\n );\n\n return response;\n }\n\n if ('cancel' in interceptResult) {\n const cancelledResponse = this._buildResponse<T>({\n adapterResponse: null,\n requestID,\n wasCancelled: true,\n wasTimeout: false,\n adapterType: this._adapter.getType(),\n initialURL: url,\n requestURL: url,\n redirectHistory: [],\n });\n\n const error = this._makeError(\n cancelledResponse,\n requestID,\n false,\n undefined,\n undefined,\n interceptResult.reason,\n );\n callbacks.setError(error);\n trackedCallbacks.setState('cancelled');\n\n await this._runErrorObservers(\n error,\n this._bestEffortAttemptRequestFromPending(\n finalRequest,\n timeout,\n requestID,\n ),\n {\n type: 'final',\n },\n );\n\n callbacks.setResponse(cancelledResponse);\n return cancelledResponse;\n }\n\n finalRequest = interceptResult;\n\n // Cookie header is not merged here: _dispatchRequestAttempts applies the jar on\n // every adapter attempt (first try and retries) after internal + interceptor headers.\n const jar = this._config.cookieJar;\n\n // Determine effective retry policy — one shared instance used by both\n // the main dispatch loop AND any redirect hops (shared budget).\n const retryPolicyOptions: RetryPolicyOptions | undefined | null =\n options.retryPolicy !== undefined\n ? options.retryPolicy\n : this._config.retryPolicy;\n const retryPolicy = retryPolicyOptions\n ? new RetryPolicy(retryPolicyOptions)\n : null;\n\n // --- Main request + redirect loop ---\n //\n // Redirect following is handled here as an iterative loop rather than\n // in a separate recursive method. Each iteration either sends the\n // initial request or follows a redirect hop. Retries within each hop\n // are handled by _dispatchRequestAttempts, which shares the same\n // RetryPolicy instance across all hops so retries on redirect targets\n // eat into the same budget as retries on the initial request.\n //\n // On a redirect response (301, 302, 303, 307, 308), the loop:\n // 1. Resolves the Location header into an absolute URL\n // 2. Rewrites the method per HTTP spec (303 → GET; 301/302 + POST → GET)\n // 3. Strips non-safelisted headers on cross-origin redirects\n // 4. Seeds Cookie from the jar for the redirect URL (dispatch re-merges from the jar\n // on each attempt of that hop, so this stays in sync with Set-Cookie from prior responses)\n // 5. Runs redirect-phase interceptors and observers\n // 6. Continues the loop with the updated request state\n let currentInterceptedRequest: InterceptedRequest = finalRequest;\n let redirectHistory: string[] = [];\n let hopCount = 0;\n // Tracks the last global attempt number across all hops and retries,\n // so the next hop's attempts continue the sequence (e.g. 1,2,3 on\n // initial request → 4,5 on first redirect hop → 6 on second hop).\n let lastAttemptNumber = 0;\n let currentHopInfo: RedirectHopInfo | undefined;\n\n while (true) {\n // Send request through the adapter with retry support. Each hop gets\n // its own call; the shared retryPolicy tracks budget across all hops.\n const attemptResult = await this._dispatchRequestAttempts({\n request: currentInterceptedRequest,\n timeout,\n cancelSignal,\n retryPolicy,\n requestID,\n options,\n callbacks: trackedCallbacks,\n initialURL: finalRequest.requestURL,\n startAttemptNumber: lastAttemptNumber + 1,\n redirectHistory,\n hopContext: currentHopInfo\n ? { hopNumber: hopCount, redirect: currentHopInfo }\n : undefined,\n cookieJar: jar ?? undefined,\n });\n\n const { adapterResponse, wasCancelled, wasTimeout } = attemptResult;\n lastAttemptNumber = attemptResult.attemptCount;\n isRetriesExhausted = attemptResult.isRetriesExhausted;\n completedAttemptCount = attemptResult.attemptCount;\n\n // If adapter threw, capture the error code and cause\n if (attemptResult.errorCode) {\n errorCode = attemptResult.errorCode;\n }\n\n if (attemptResult.adapterCause) {\n adapterCause = attemptResult.adapterCause;\n }\n\n if (attemptResult.cancelReason !== undefined) {\n cancelReason = attemptResult.cancelReason;\n }\n\n callbacks.setAttemptCount(attemptResult.attemptCount);\n observerRequest = attemptResult.sentRequest;\n\n if (\n !this._config.followRedirects &&\n adapterResponse &&\n REDIRECT_STATUS_CODES.has(adapterResponse.status)\n ) {\n response = this._buildResponse<T>({\n // Pass a synthetic status-0 response so wasRedirectDetected is\n // preserved — null would lose the flag since _buildResponse\n // computes it as `adapterResponse?.wasRedirectDetected ?? false`.\n adapterResponse: {\n status: 0,\n wasRedirectDetected: true,\n detectedRedirectURL: adapterResponse.detectedRedirectURL,\n headers: {},\n body: null,\n },\n requestID,\n wasCancelled: false,\n wasTimeout: false,\n adapterType: this._adapter.getType(),\n initialURL: finalRequest.requestURL,\n requestURL: attemptResult.sentRequest.requestURL,\n redirectHistory,\n isNetworkErrorOverride: false,\n });\n errorCode = 'redirect_disabled';\n break;\n }\n\n // --- Follow redirects (301, 302, 303, 307, 308) ---\n if (\n this._config.followRedirects &&\n adapterResponse &&\n REDIRECT_STATUS_CODES.has(adapterResponse.status)\n ) {\n hopCount++;\n\n // Guard against infinite redirect chains\n if (hopCount > this._config.maxRedirects) {\n response = this._buildResponse<T>({\n adapterResponse: null,\n requestID,\n wasCancelled: false,\n wasTimeout: false,\n adapterType: this._adapter.getType(),\n initialURL: finalRequest.requestURL,\n requestURL: attemptResult.sentRequest.requestURL,\n redirectHistory,\n });\n errorCode = 'redirect_loop';\n break;\n }\n\n // Resolve the Location header into an absolute URL.\n // Relative paths (e.g. \"/new-path\") resolve against the current request URL.\n const location = scalarHeader(adapterResponse.headers, 'location');\n\n if (!location) {\n // Redirect status but no Location header — treat as final response\n response = this._buildResponse<T>({\n adapterResponse,\n requestID,\n wasCancelled: false,\n wasTimeout: false,\n adapterType: this._adapter.getType(),\n initialURL: finalRequest.requestURL,\n requestURL: attemptResult.sentRequest.requestURL,\n redirectHistory,\n });\n\n break;\n }\n\n let redirectURL: string;\n\n try {\n redirectURL = new URL(\n location,\n attemptResult.sentRequest.requestURL,\n ).toString();\n } catch {\n redirectURL = location;\n }\n\n redirectURL = resolveAbsoluteURL(redirectURL, this._config.baseURL);\n\n // Method rewriting per HTTP spec (matches browser/fetch behavior):\n // - 303 (See Other) always becomes GET\n // - 301 (Moved Permanently) / 302 (Found) rewrite POST to GET\n // - 307 (Temporary Redirect) / 308 (Permanent Redirect) preserve method/body\n let redirectMethod: HTTPMethod = currentInterceptedRequest.method;\n\n if (\n adapterResponse.status === 303 ||\n ((adapterResponse.status === 301 ||\n adapterResponse.status === 302) &&\n currentInterceptedRequest.method === 'POST')\n ) {\n redirectMethod = 'GET';\n }\n\n const hopInfo: RedirectHopInfo = {\n hop: hopCount,\n from: attemptResult.sentRequest.requestURL,\n to: redirectURL,\n statusCode: adapterResponse.status,\n };\n\n // Notify redirect-phase response observers (after Set-Cookie from\n // this response is applied). Same hop/from/to/statusCode as the\n // redirect-phase request interceptors that run below.\n await this._runResponseObservers(\n this._buildResponse({\n adapterResponse,\n requestID,\n wasCancelled: false,\n wasTimeout: false,\n adapterType: this._adapter.getType(),\n initialURL: finalRequest.requestURL,\n requestURL: attemptResult.sentRequest.requestURL,\n redirectHistory,\n }),\n attemptResult.sentRequest,\n { type: 'redirect', ...hopInfo },\n );\n\n // Cross-origin safety: strip ALL headers except CORS-safelisted ones\n // when the redirect crosses origins (scheme + host + port). Matches\n // Chromium/fetch behavior — Authorization, X-API-Key, etc. must not\n // leak to a different host. Cookies and internal headers (request ID)\n // are re-attached below as needed.\n const nextRedirectHistory = [...redirectHistory, redirectURL];\n\n const redirectRequest = this._sanitizeRedirectRequest(\n {\n ...currentInterceptedRequest,\n requestURL: redirectURL,\n method: redirectMethod,\n body:\n redirectMethod === 'GET'\n ? undefined\n : currentInterceptedRequest.body,\n },\n {\n fromURL: attemptResult.sentRequest.requestURL,\n cookieJar: jar ?? undefined,\n },\n );\n\n // Run redirect-phase request interceptors so they can update headers\n // for the new target (e.g. refresh auth tokens). Retry-phase\n // interceptors run inside _dispatchRequestAttempts if the hop itself\n // needs retrying.\n let redirectIntercept: InterceptedRequest | InterceptorCancel;\n let failedRedirectRequest: InterceptedRequest = redirectRequest;\n\n try {\n redirectIntercept = await this._runInterceptors(\n redirectRequest,\n { type: 'redirect', ...hopInfo },\n {\n initialURL: finalRequest.requestURL,\n redirectHistory: nextRedirectHistory,\n requestID,\n attemptNumber: lastAttemptNumber + 1,\n },\n );\n if (!('cancel' in redirectIntercept)) {\n failedRedirectRequest = redirectIntercept;\n this._assertRequestIsSupported(redirectIntercept);\n this._assertInterceptorResolvedURL(\n redirectIntercept.requestURL,\n );\n }\n } catch (error) {\n observerRequest = this._bestEffortAttemptRequestFromPending(\n failedRedirectRequest,\n timeout,\n requestID,\n );\n response = this._buildResponse<T>({\n adapterResponse: null,\n requestID,\n wasCancelled: false,\n wasTimeout: false,\n adapterType: this._adapter.getType(),\n initialURL: finalRequest.requestURL,\n requestURL: failedRedirectRequest.requestURL,\n redirectHistory: nextRedirectHistory,\n isNetworkErrorOverride: false,\n });\n\n errorCode = 'interceptor_error';\n adapterCause =\n error instanceof Error ? error : new Error(String(error));\n\n break;\n }\n\n if ('cancel' in redirectIntercept) {\n const cancelledRequestURL = redirectRequest.requestURL;\n observerRequest = this._bestEffortAttemptRequestFromPending(\n redirectRequest,\n timeout,\n requestID,\n );\n if (redirectIntercept.reason !== undefined) {\n cancelReason = redirectIntercept.reason;\n }\n\n response = this._buildResponse<T>({\n adapterResponse: null,\n requestID,\n wasCancelled: true,\n wasTimeout: false,\n adapterType: this._adapter.getType(),\n initialURL: finalRequest.requestURL,\n requestURL: cancelledRequestURL,\n redirectHistory: [...redirectHistory, cancelledRequestURL],\n });\n\n break;\n }\n\n const sanitizedRedirectRequest = this._sanitizeRedirectRequest(\n redirectIntercept,\n {\n // fromURL is the redirect target URL (what the interceptor received).\n // This sanitize only strips headers if the interceptor rewrote the\n // URL to a third host — in that case from=redirectTarget, to=thirdHost\n // is cross-origin and the strip fires correctly.\n\n // If the interceptor kept the URL (normal case), from and to are the\n // same origin and nothing is stripped, preserving any headers the\n // interceptor added (e.g. Authorization for the redirect target).\n fromURL: redirectRequest.requestURL,\n cookieJar: jar ?? undefined,\n },\n );\n\n const redirectedRequestURL = sanitizedRedirectRequest.requestURL;\n\n // Update loop state for the next redirect hop\n currentInterceptedRequest = sanitizedRedirectRequest;\n redirectHistory = [...redirectHistory, redirectedRequestURL];\n currentHopInfo = {\n ...hopInfo,\n to: redirectedRequestURL,\n };\n\n continue;\n }\n\n // Non-redirect: build final HTTPResponse\n response = this._buildResponse<T>({\n adapterResponse,\n requestID,\n wasCancelled,\n wasTimeout,\n adapterType: this._adapter.getType(),\n initialURL: finalRequest.requestURL,\n requestURL: attemptResult.sentRequest.requestURL,\n redirectHistory,\n ...(attemptResult.errorCode === 'interceptor_error' ||\n attemptResult.errorCode === 'stream_setup_error' ||\n attemptResult.errorCode === 'redirect_disabled'\n ? { isNetworkErrorOverride: false }\n : {}),\n });\n\n break;\n }\n } catch (error) {\n response = this._buildResponse<T>({\n adapterResponse: null,\n requestID,\n wasCancelled: false,\n wasTimeout: false,\n adapterType: this._adapter.getType(),\n initialURL: interceptedRequest.requestURL,\n requestURL: interceptedRequest.requestURL,\n redirectHistory: [],\n isNetworkErrorOverride: false,\n });\n\n const normalizedError = this._makeError(\n response,\n requestID,\n false,\n 'request_setup_error',\n error instanceof Error ? error : new Error(String(error)),\n );\n\n callbacks.setAttemptCount(completedAttemptCount);\n callbacks.setNextRetryDelayMS(null);\n callbacks.setNextRetryAt(null);\n callbacks.setError(normalizedError);\n trackedCallbacks.setState('failed');\n callbacks.setResponse(response);\n await this._runErrorObservers(\n normalizedError,\n this._bestEffortAttemptRequestFromPending(\n interceptedRequest,\n timeout,\n requestID,\n ),\n {\n type: 'final',\n },\n );\n return response;\n }\n\n // Run response or error observers. Phase `final` means this `send()` has finished.\n // Observers with `phases: ['retry']` already ran inside _dispatchRequestAttempts\n // for each retryable outcome before the retry delay; `redirect` phase response\n // observers ran inside the redirect loop for each redirect response. Network and\n // retryable HTTP failures may have been retried before we get here; interceptor\n // throw/cancel never retries and reaches this block immediately.\n const finalResponse = response;\n\n if (response.isFailed) {\n const error = this._makeError(\n response,\n requestID,\n isRetriesExhausted,\n // Set for adapter_error, interceptor_error, redirect_loop, etc.; otherwise network_error.\n // Streamed-body failures after headers also terminate here, but preserve\n // their real HTTP status on the response object.\n errorCode ??\n (response.isStreamError ? 'stream_write_error' : undefined),\n adapterCause,\n cancelReason,\n );\n\n callbacks.setError(error);\n callbacks.setNextRetryDelayMS(null);\n callbacks.setNextRetryAt(null);\n trackedCallbacks.setState(\n response.isCancelled ? 'cancelled' : 'failed',\n );\n await this._runErrorObservers(error, observerRequest, {\n type: 'final',\n });\n } else {\n callbacks.setNextRetryDelayMS(null);\n callbacks.setNextRetryAt(null);\n trackedCallbacks.setState('completed');\n await this._runResponseObservers(response, observerRequest, {\n type: 'final',\n });\n }\n\n callbacks.setResponse(finalResponse);\n return finalResponse;\n } finally {\n this._tracker.remove(requestID);\n }\n }\n\n private _sanitizeRedirectRequest(\n request: InterceptedRequest,\n params: {\n fromURL: string;\n cookieJar?: CookieJar | null;\n },\n ): InterceptedRequest {\n const { fromURL, cookieJar } = params;\n const isCrossOrigin = this._isCrossOriginRedirect(\n fromURL,\n request.requestURL,\n );\n\n let headers: Record<string, string | string[]>;\n\n if (isCrossOrigin) {\n const safeHeaders: Record<string, string | string[]> = {};\n // Cross-origin safety: strip ALL headers except CORS-safelisted ones\n // when the redirect crosses origins (scheme + host + port). Matches\n // Chromium/fetch behavior — Authorization, X-API-Key, etc. must not\n // leak to a different host. Cookies and internal headers are re-attached\n // later as needed.\n const safelisted = new Set([\n 'accept',\n 'accept-language',\n 'content-language',\n 'content-type',\n 'user-agent',\n ]);\n\n for (const [key, value] of Object.entries(request.headers)) {\n const lower = key.toLowerCase();\n\n if (safelisted.has(lower)) {\n safeHeaders[lower] = value;\n }\n }\n\n headers = safeHeaders;\n } else {\n // Same-origin: keep the headers from the request that just ran.\n // If a cookie jar is configured, the next attempt rebuilds `Cookie`\n // from the jar during request materialization, making the jar authoritative.\n headers = { ...request.headers };\n }\n\n if (request.method === 'GET') {\n // Drop body-related headers when method was rewritten to GET.\n delete headers['content-type'];\n delete headers['content-length'];\n }\n\n if (cookieJar) {\n // Cookie for the new URL before the next hop is dispatched; each send on\n // this hop still refreshes from the jar inside _dispatchRequestAttempts.\n const cookieStr = cookieJar.getCookieHeaderString(request.requestURL);\n\n if (cookieStr) {\n headers.cookie = cookieStr;\n } else {\n delete headers.cookie;\n }\n } else if (isCrossOrigin) {\n // Without a jar, never let a caller-supplied Cookie header survive a\n // cross-origin redirect or redirect-interceptor rewrite.\n delete headers.cookie;\n }\n\n return {\n ...request,\n headers,\n };\n }\n\n private _isCrossOriginRedirect(fromURL: string, toURL: string): boolean {\n try {\n const from = new URL(fromURL);\n const to = new URL(toURL);\n return from.origin !== to.origin;\n } catch {\n return true;\n }\n }\n\n /**\n * Core retry loop — sends the request through the adapter and retries on\n * retryable status codes (503, 429, etc.) or network errors, up to the\n * policy's max attempts. Each attempt gets its own independent timeout.\n *\n * Cancellation (via cancelSignal) is checked after every retry delay so\n * the caller doesn't have to wait for the full delay to finish.\n *\n * The same RetryPolicy instance is shared across the redirect loop in\n * _execute, so retries during redirect hops eat into the same budget.\n */\n private async _dispatchRequestAttempts<T>(params: {\n request: InterceptedRequest;\n /** Per-attempt timeout in ms. Each attempt gets its own independent timer — NOT a total deadline across all retries. */\n timeout: number;\n /** Cancellation signal from user cancel / cancelAll / external AbortSignal — NOT timeout. Also used to abort retry delays. */\n cancelSignal: AbortSignal;\n retryPolicy: RetryPolicy | null;\n requestID: string;\n options: ResolvedBuilderOptions;\n callbacks: BuilderCallbacks<T>;\n /** The original URL before any redirects — used in callbacks so consumers can correlate attempts across hops. */\n initialURL: string;\n /** First attempt number for this dispatch (continues from previous hops). Defaults to 1. */\n startAttemptNumber?: number;\n /** Accumulated redirect history — passed to interceptor context. */\n redirectHistory?: string[];\n /** When dispatching a redirect hop, carries the hop number and redirect info for callbacks and observer phases. */\n hopContext?: { hopNumber: number; redirect: RedirectHopInfo };\n /**\n * If set: each adapter response updates the jar from `Set-Cookie` before retry/backoff,\n * and each outbound attempt rebuilds the `Cookie` header from the jar for `attemptTarget`.\n */\n cookieJar?: CookieJar | null;\n }): Promise<{\n adapterResponse: AdapterResponse | null;\n sentRequest: AttemptRequest;\n attemptCount: number;\n wasCancelled: boolean;\n wasTimeout: boolean;\n isRetriesExhausted: boolean;\n errorCode?: HTTPClientError['code'];\n adapterCause?: Error;\n cancelReason?: string;\n }> {\n const {\n request: baseRequest,\n timeout,\n cancelSignal,\n retryPolicy: policy,\n requestID,\n options,\n callbacks,\n initialURL,\n hopContext,\n } = params;\n const startAttempt = params.startAttemptNumber ?? 1;\n const redirectHistory = params.redirectHistory ?? [];\n const cookieJar = params.cookieJar ?? null;\n let attemptNumber = startAttempt - 1;\n let isRetriesExhausted = false;\n\n while (true) {\n attemptNumber++;\n const isRetry = attemptNumber > startAttempt;\n\n // Only set the start timestamp on the very first attempt of the entire\n // request (attempt 1). Redirect hops reuse the original start time.\n if (attemptNumber === 1) {\n callbacks.setStartedAt(Date.now());\n } else {\n callbacks.setState('sending');\n }\n\n callbacks.setAttemptCount(attemptNumber);\n callbacks.setNextRetryDelayMS(null);\n callbacks.setNextRetryAt(null);\n options.onAttemptStart?.({\n attemptNumber,\n isRetry,\n requestID,\n initialURL,\n ...(hopContext\n ? { hopNumber: hopContext.hopNumber, redirect: hopContext.redirect }\n : {}),\n });\n\n // RetryPolicy only tracks exhaustion after the initial try is registered (retry-utils).\n if (attemptNumber === 1 && policy) {\n policy.shouldDoFirstTry();\n }\n\n // Per-attempt wall-clock timeout — separate from the cancel signal.\n // This covers the full attempt lifetime, including response body\n // streaming, and is NOT reset by upload/download progress or chunk\n // activity. Set timeout <= 0 to disable the per-attempt timer.\n const timeoutController = new AbortController();\n let isTimedOut = false;\n let timeoutID: ReturnType<typeof setTimeout> | undefined;\n\n if (timeout > 0) {\n timeoutID = setTimeout(() => {\n isTimedOut = true;\n timeoutController.abort();\n }, timeout);\n }\n\n // Final signal: cancel OR timeout\n const attemptSignal = this._composeSignals(\n cancelSignal,\n timeoutController.signal,\n );\n\n // Set internal headers unconditionally on every attempt — this is\n // simpler than relying on them surviving cross-origin header stripping\n // during redirects. Both are always re-applied here so the redirect\n // loop doesn't need to worry about re-attaching them.\n let attemptRequest: InterceptedRequest = baseRequest;\n\n // Run retry-phase interceptors before each reattempt so they can refresh\n // headers or rewrite the request. On redirect hops, the phase includes\n // redirect context so interceptors know which hop is being retried.\n if (isRetry) {\n const retryPhase: InterceptorPhase = {\n type: 'retry',\n attempt: attemptNumber,\n maxAttempts: policy ? policy.maxRetryAttempts + 1 : attemptNumber,\n ...(hopContext?.redirect ? { redirect: hopContext.redirect } : {}),\n };\n let retryIntercept: InterceptedRequest | InterceptorCancel;\n let failedRetryRequest: InterceptedRequest = baseRequest;\n\n try {\n retryIntercept = await this._runInterceptors(\n {\n ...baseRequest,\n headers: this._withInternalRequestHeaders(\n baseRequest.headers,\n requestID,\n attemptNumber,\n ),\n },\n retryPhase,\n { initialURL, redirectHistory, requestID, attemptNumber },\n );\n if (!('cancel' in retryIntercept)) {\n failedRetryRequest = retryIntercept;\n this._assertRequestIsSupported(retryIntercept);\n this._assertInterceptorResolvedURL(retryIntercept.requestURL);\n }\n } catch (error) {\n clearTimeout(timeoutID);\n\n options.onAttemptEnd?.({\n attemptNumber,\n isRetry,\n willRetry: false,\n nextRetryDelayMS: undefined,\n nextRetryAt: undefined,\n status: 0,\n requestID,\n initialURL,\n ...(hopContext\n ? {\n hopNumber: hopContext.hopNumber,\n redirect: hopContext.redirect,\n }\n : {}),\n });\n\n // Terminal failure — no further attempts. _execute notifies error observers\n // with phase `final` (same as all settled errors), not `retry`.\n return {\n adapterResponse: null,\n sentRequest: this._bestEffortAttemptRequestFromPending(\n failedRetryRequest,\n timeout,\n requestID,\n ),\n attemptCount: attemptNumber,\n wasCancelled: false,\n wasTimeout: false,\n isRetriesExhausted: false,\n errorCode: 'interceptor_error',\n adapterCause:\n error instanceof Error ? error : new Error(String(error)),\n };\n }\n\n if ('cancel' in retryIntercept) {\n clearTimeout(timeoutID);\n\n options.onAttemptEnd?.({\n attemptNumber,\n isRetry,\n willRetry: false,\n nextRetryDelayMS: undefined,\n nextRetryAt: undefined,\n status: 0,\n requestID,\n initialURL,\n ...(hopContext\n ? {\n hopNumber: hopContext.hopNumber,\n redirect: hopContext.redirect,\n }\n : {}),\n });\n\n return {\n adapterResponse: null,\n sentRequest: this._bestEffortAttemptRequestFromPending(\n baseRequest,\n timeout,\n requestID,\n ),\n attemptCount: attemptNumber,\n wasCancelled: true,\n wasTimeout: false,\n isRetriesExhausted: false,\n ...(retryIntercept.reason !== undefined\n ? { cancelReason: retryIntercept.reason }\n : {}),\n };\n }\n\n attemptRequest = retryIntercept;\n }\n\n const sentRequest = this._buildAttemptRequest(attemptRequest, {\n requestID,\n timeout,\n attemptNumber,\n cookieJar,\n });\n\n const onUploadProgress = options.onUploadProgress;\n const onDownloadProgress = options.onDownloadProgress;\n\n let observedSentRequest: AttemptRequest = sentRequest;\n\n try {\n const rawAdapterResponse = await this._adapter.send({\n requestURL: sentRequest.requestURL,\n method: sentRequest.method,\n headers: { ...sentRequest.headers },\n body: sentRequest.body ?? null,\n signal: attemptSignal,\n // Forward the builder's streaming factory to each adapter attempt.\n // NodeAdapter invokes it only for a 200 response, letting the caller\n // create attempt-local writable state when a retry happens.\n streamResponse: options.streamResponse,\n // attemptNumber and requestID are passed so NodeAdapter can populate\n // StreamResponseInfo without the adapter needing to track attempt state\n // itself.\n attemptNumber,\n requestID: requestID,\n onUploadProgress: onUploadProgress\n ? (e) =>\n onUploadProgress({\n ...e,\n attemptNumber,\n ...(hopContext ? { hopNumber: hopContext.hopNumber } : {}),\n })\n : undefined,\n onDownloadProgress: onDownloadProgress\n ? (e) =>\n onDownloadProgress({\n ...e,\n attemptNumber,\n ...(hopContext ? { hopNumber: hopContext.hopNumber } : {}),\n })\n : undefined,\n });\n\n const adapterResponse: AdapterResponse = {\n ...rawAdapterResponse,\n headers: normalizeAdapterResponseHeaders(rawAdapterResponse.headers),\n };\n\n observedSentRequest = rawAdapterResponse.effectiveRequestHeaders\n ? {\n ...sentRequest,\n headers: mergeObservedHeaders(\n sentRequest.headers,\n rawAdapterResponse.effectiveRequestHeaders,\n ),\n }\n : sentRequest;\n\n clearTimeout(timeoutID);\n\n // Store Set-Cookie before retry/backoff so the next attempt matches browsers\n // and curl (cookies from error responses apply to follow-up requests).\n if (cookieJar) {\n cookieJar.processResponseHeaders(\n adapterResponse.headers,\n sentRequest.requestURL,\n );\n }\n\n // Browser-only path: adapter returned status 0 but flagged a redirect\n // (FetchAdapter opaque redirect or XHR auto-follow).\n //\n // Status 0 means no Location header is available, so the normal\n // REDIRECT_STATUS_CODES check in the outer loop can't handle it.\n //\n // When redirects are disabled this is redirect_disabled.\n // When enabled, the status-0 response falls\n // through to the transport error path (nowhere to redirect to).\n //\n // Real 3xx responses (NodeAdapter, MockAdapter) do NOT reach this path\n // because their status != 0. They fall through to onAttemptEnd with\n // the correct status, and the outer redirect loop handles follow/disable.\n if (\n adapterResponse.wasRedirectDetected &&\n adapterResponse.status === 0 &&\n !this._config.followRedirects\n ) {\n options.onAttemptEnd?.({\n attemptNumber,\n isRetry,\n willRetry: false,\n nextRetryDelayMS: undefined,\n nextRetryAt: undefined,\n status: 0,\n requestID,\n initialURL,\n ...(hopContext\n ? {\n hopNumber: hopContext.hopNumber,\n redirect: hopContext.redirect,\n }\n : {}),\n });\n\n return {\n adapterResponse,\n sentRequest: observedSentRequest,\n attemptCount: attemptNumber,\n wasCancelled: false,\n wasTimeout: false,\n isRetriesExhausted: false,\n errorCode: 'redirect_disabled',\n };\n }\n\n // Check if should retry based on status code.\n // Stream failures are terminal even when status is retryable (e.g. 0).\n if (\n policy &&\n adapterResponse.isRetryable !== false &&\n !adapterResponse.isStreamError &&\n RETRYABLE_STATUS_CODES.has(adapterResponse.status) &&\n !cancelSignal.aborted\n ) {\n const { shouldRetry, delayMS } = policy.shouldRetry(\n new Error(`HTTP ${adapterResponse.status}`),\n );\n const nextRetryAt = shouldRetry ? Date.now() + delayMS : undefined;\n\n if (shouldRetry) {\n callbacks.setNextRetryDelayMS(delayMS);\n callbacks.setNextRetryAt(nextRetryAt ?? null);\n callbacks.setState('waiting_for_retry');\n }\n\n options.onAttemptEnd?.({\n attemptNumber,\n isRetry,\n willRetry: shouldRetry,\n nextRetryDelayMS: shouldRetry ? delayMS : undefined,\n nextRetryAt,\n status: adapterResponse.status,\n requestID,\n initialURL,\n ...(hopContext\n ? {\n hopNumber: hopContext.hopNumber,\n redirect: hopContext.redirect,\n }\n : {}),\n });\n\n if (shouldRetry) {\n const retryHTTPResponse = this._buildResponse({\n adapterResponse,\n requestID,\n wasCancelled: false,\n wasTimeout: false,\n adapterType: this._adapter.getType(),\n initialURL,\n requestURL: sentRequest.requestURL,\n redirectHistory,\n });\n\n await this._runResponseObservers(\n retryHTTPResponse,\n observedSentRequest,\n this._retryOutcomePhase(\n policy,\n attemptNumber,\n hopContext?.redirect,\n ),\n );\n\n await this._cancellableDelay(delayMS, cancelSignal);\n\n if (cancelSignal.aborted) {\n const signalReason = getSignalCancelReason(cancelSignal);\n return {\n adapterResponse: null,\n sentRequest: observedSentRequest,\n attemptCount: attemptNumber,\n wasCancelled: true,\n wasTimeout: false,\n isRetriesExhausted: false,\n ...(signalReason !== undefined\n ? { cancelReason: signalReason }\n : {}),\n };\n }\n\n continue;\n }\n\n isRetriesExhausted = true;\n } else {\n options.onAttemptEnd?.({\n attemptNumber,\n isRetry,\n willRetry: false,\n nextRetryDelayMS: undefined,\n nextRetryAt: undefined,\n status: adapterResponse.status,\n requestID,\n initialURL,\n ...(hopContext\n ? {\n hopNumber: hopContext.hopNumber,\n redirect: hopContext.redirect,\n }\n : {}),\n });\n }\n\n const responseCause: Error | undefined =\n adapterResponse.errorCause instanceof Error\n ? adapterResponse.errorCause\n : undefined;\n\n const streamErrorCode = adapterResponse.isStreamError\n ? (adapterResponse.streamErrorCode ?? 'stream_write_error')\n : undefined;\n\n return {\n adapterResponse,\n sentRequest: observedSentRequest,\n attemptCount: attemptNumber,\n wasCancelled: false,\n wasTimeout: false,\n isRetriesExhausted,\n errorCode: streamErrorCode,\n adapterCause: responseCause,\n };\n } catch (error) {\n clearTimeout(timeoutID);\n\n // When abort(string) is called, fetch() rejects with the string itself (per Fetch spec),\n // not an AbortError. Check cancelSignal.aborted first so string-reason cancels are caught.\n if (cancelSignal.aborted && !isAbortError(error)) {\n options.onAttemptEnd?.({\n attemptNumber,\n isRetry,\n willRetry: false,\n nextRetryDelayMS: undefined,\n nextRetryAt: undefined,\n status: 0,\n requestID,\n initialURL,\n ...(hopContext\n ? {\n hopNumber: hopContext.hopNumber,\n redirect: hopContext.redirect,\n }\n : {}),\n });\n\n const signalReason = getSignalCancelReason(cancelSignal);\n\n return {\n adapterResponse: null,\n sentRequest,\n attemptCount: attemptNumber,\n wasCancelled: true,\n wasTimeout: isTimedOut,\n isRetriesExhausted: false,\n ...(signalReason !== undefined\n ? { cancelReason: signalReason }\n : {}),\n };\n }\n\n if (isAbortError(error) && isResponseStreamAbortError(error)) {\n if (cancelSignal.aborted) {\n options.onAttemptEnd?.({\n attemptNumber,\n isRetry,\n willRetry: false,\n nextRetryDelayMS: undefined,\n nextRetryAt: undefined,\n status: 0,\n requestID,\n initialURL,\n ...(hopContext\n ? {\n hopNumber: hopContext.hopNumber,\n redirect: hopContext.redirect,\n }\n : {}),\n });\n\n const signalReason = getSignalCancelReason(cancelSignal);\n return {\n adapterResponse: null,\n sentRequest: sentRequestForObservedAdapterError(\n sentRequest,\n error,\n observedSentRequest,\n ),\n attemptCount: attemptNumber,\n wasCancelled: true,\n wasTimeout: isTimedOut,\n isRetriesExhausted: false,\n ...(signalReason !== undefined\n ? { cancelReason: signalReason }\n : {}),\n };\n }\n\n const streamedAbort = getResponseStreamAbortInfo(error);\n\n if (isTimedOut && streamedAbort) {\n options.onAttemptEnd?.({\n attemptNumber,\n isRetry,\n willRetry: false,\n nextRetryDelayMS: undefined,\n nextRetryAt: undefined,\n status: streamedAbort.status,\n requestID,\n initialURL,\n ...(hopContext\n ? {\n hopNumber: hopContext.hopNumber,\n redirect: hopContext.redirect,\n }\n : {}),\n });\n\n return {\n adapterResponse: {\n status: streamedAbort.status,\n headers: streamedAbort.headers,\n body: null,\n isStreamError: true,\n streamErrorCode: 'stream_response_error',\n errorCause: error,\n effectiveRequestHeaders:\n getEffectiveRequestHeadersFromError(error),\n },\n sentRequest: sentRequestForObservedAdapterError(\n sentRequest,\n error,\n observedSentRequest,\n ),\n attemptCount: attemptNumber,\n wasCancelled: false,\n wasTimeout: true,\n isRetriesExhausted: false,\n errorCode: 'stream_response_error',\n adapterCause: error,\n };\n }\n\n options.onAttemptEnd?.({\n attemptNumber,\n isRetry,\n willRetry: false,\n nextRetryDelayMS: undefined,\n nextRetryAt: undefined,\n status: streamedAbort?.status ?? 0,\n requestID,\n initialURL,\n ...(hopContext\n ? {\n hopNumber: hopContext.hopNumber,\n redirect: hopContext.redirect,\n }\n : {}),\n });\n\n return {\n adapterResponse: {\n status: streamedAbort?.status ?? 0,\n headers: streamedAbort?.headers ?? {},\n body: null,\n isStreamError: true,\n streamErrorCode: 'stream_response_error',\n errorCause: error,\n effectiveRequestHeaders:\n getEffectiveRequestHeadersFromError(error),\n },\n sentRequest: sentRequestForObservedAdapterError(\n sentRequest,\n error,\n observedSentRequest,\n ),\n attemptCount: attemptNumber,\n wasCancelled: false,\n wasTimeout: isTimedOut,\n isRetriesExhausted: false,\n errorCode: 'stream_response_error',\n adapterCause: error,\n };\n }\n\n if (isAbortError(error)) {\n // User/parent cancellation — never retry (even if a timeout fired in the same window).\n if (cancelSignal.aborted) {\n options.onAttemptEnd?.({\n attemptNumber,\n isRetry,\n willRetry: false,\n nextRetryDelayMS: undefined,\n nextRetryAt: undefined,\n status: 0,\n requestID,\n initialURL,\n ...(hopContext\n ? {\n hopNumber: hopContext.hopNumber,\n redirect: hopContext.redirect,\n }\n : {}),\n });\n\n const signalReason = getSignalCancelReason(cancelSignal);\n return {\n adapterResponse: null,\n sentRequest,\n attemptCount: attemptNumber,\n wasCancelled: true,\n wasTimeout: isTimedOut,\n isRetriesExhausted: false,\n ...(signalReason !== undefined\n ? { cancelReason: signalReason }\n : {}),\n };\n }\n\n // Per-attempt timeout — fall through and reuse the same retry path as network errors.\n if (!isTimedOut) {\n // Check for a browser-fired XHR timeout (xhr.timeout = 0 but the browser\n // has its own hard limit). Treat it the same as our own timeout so it gets\n // retried and classified as isTimeout rather than isCancelled.\n if (isXHRBrowserTimeout(error)) {\n isTimedOut = true;\n // Fall through to the normal timeout retry path below.\n } else {\n // AbortError without our timeout flag — treat as non-retryable cancel.\n // This path includes StreamResponseFactory returning null / { cancel: true }.\n const factoryCancelValue =\n error !== null &&\n typeof error === 'object' &&\n STREAM_FACTORY_CANCEL_KEY in error\n ? (error as Record<string, unknown>)[\n STREAM_FACTORY_CANCEL_KEY\n ]\n : undefined;\n const factoryCancelReason =\n typeof factoryCancelValue === 'string'\n ? factoryCancelValue\n : undefined;\n\n options.onAttemptEnd?.({\n attemptNumber,\n isRetry,\n willRetry: false,\n nextRetryDelayMS: undefined,\n nextRetryAt: undefined,\n status: 0,\n requestID,\n initialURL,\n ...(hopContext\n ? {\n hopNumber: hopContext.hopNumber,\n redirect: hopContext.redirect,\n }\n : {}),\n });\n\n return {\n adapterResponse: null,\n sentRequest,\n attemptCount: attemptNumber,\n wasCancelled: true,\n wasTimeout: false,\n isRetriesExhausted: false,\n ...(factoryCancelReason !== undefined\n ? { cancelReason: factoryCancelReason }\n : {}),\n };\n }\n }\n }\n\n const didTimeoutThisAttempt = isAbortError(error) && isTimedOut;\n const isNonRetryableClientCallbackFailure =\n isNonRetryableClientCallbackError(error);\n\n if (isNonRetryableClientCallbackFailure) {\n options.onAttemptEnd?.({\n attemptNumber,\n isRetry,\n willRetry: false,\n nextRetryDelayMS: undefined,\n nextRetryAt: undefined,\n status: 0,\n requestID,\n initialURL,\n ...(hopContext\n ? {\n hopNumber: hopContext.hopNumber,\n redirect: hopContext.redirect,\n }\n : {}),\n });\n\n const isStreamFactoryError =\n isStreamFactoryClientCallbackError(error);\n\n return {\n adapterResponse: null,\n sentRequest: sentRequestForNonRetryableAdapterCallbackError(\n sentRequest,\n error,\n observedSentRequest,\n ),\n attemptCount: attemptNumber,\n wasCancelled: false,\n wasTimeout: didTimeoutThisAttempt,\n isRetriesExhausted: false,\n errorCode: isStreamFactoryError\n ? 'stream_setup_error'\n : 'interceptor_error',\n adapterCause:\n error instanceof Error ? error : new Error(String(error)),\n };\n }\n\n // Network / adapter / per-attempt timeout — retry if policy allows\n if (policy && !cancelSignal.aborted) {\n const { shouldRetry, delayMS } = policy.shouldRetry(\n error instanceof Error ? error : new Error(String(error)),\n );\n const nextRetryAt = shouldRetry ? Date.now() + delayMS : undefined;\n\n if (shouldRetry) {\n callbacks.setNextRetryDelayMS(delayMS);\n callbacks.setNextRetryAt(nextRetryAt ?? null);\n callbacks.setState('waiting_for_retry');\n }\n\n options.onAttemptEnd?.({\n attemptNumber,\n isRetry,\n willRetry: shouldRetry,\n nextRetryDelayMS: shouldRetry ? delayMS : undefined,\n nextRetryAt,\n status: 0,\n requestID,\n initialURL,\n ...(hopContext\n ? {\n hopNumber: hopContext.hopNumber,\n redirect: hopContext.redirect,\n }\n : {}),\n });\n\n if (shouldRetry) {\n const failedAttemptResponse = this._buildResponse({\n adapterResponse: null,\n requestID,\n wasCancelled: false,\n wasTimeout: didTimeoutThisAttempt,\n adapterType: this._adapter.getType(),\n initialURL,\n requestURL: sentRequest.requestURL,\n redirectHistory,\n isNetworkErrorOverride: false,\n });\n\n const retryError = this._makeError(\n failedAttemptResponse,\n requestID,\n false,\n 'adapter_error',\n error instanceof Error ? error : new Error(String(error)),\n );\n\n await this._runErrorObservers(\n retryError,\n sentRequest,\n this._retryOutcomePhase(\n policy,\n attemptNumber,\n hopContext?.redirect,\n ),\n );\n\n await this._cancellableDelay(delayMS, cancelSignal);\n\n if (cancelSignal.aborted) {\n const signalReason = getSignalCancelReason(cancelSignal);\n return {\n adapterResponse: null,\n sentRequest,\n attemptCount: attemptNumber,\n wasCancelled: true,\n wasTimeout: false,\n isRetriesExhausted: false,\n ...(signalReason !== undefined\n ? { cancelReason: signalReason }\n : {}),\n };\n }\n\n continue;\n }\n\n isRetriesExhausted = true;\n } else {\n options.onAttemptEnd?.({\n attemptNumber,\n isRetry,\n willRetry: false,\n nextRetryDelayMS: undefined,\n nextRetryAt: undefined,\n status: 0,\n requestID,\n initialURL,\n ...(hopContext\n ? {\n hopNumber: hopContext.hopNumber,\n redirect: hopContext.redirect,\n }\n : {}),\n });\n }\n\n return {\n adapterResponse: null,\n sentRequest,\n attemptCount: attemptNumber,\n wasCancelled: false,\n wasTimeout: didTimeoutThisAttempt,\n isRetriesExhausted,\n errorCode: 'adapter_error',\n adapterCause:\n error instanceof Error ? error : new Error(String(error)),\n };\n }\n }\n }\n\n /**\n * Delay that resolves early when the cancel signal fires.\n * Only wired to cancelSignal (user cancel / cancelAll) — the per-attempt\n * timeout does NOT cancel retry delays.\n * Cleans up both the timer and the abort listener to avoid leaks.\n */\n private _cancellableDelay(ms: number, signal: AbortSignal): Promise<void> {\n if (signal.aborted) {\n return Promise.resolve();\n }\n\n return new Promise<void>((resolve) => {\n const onAbort = () => {\n clearTimeout(id);\n resolve();\n };\n\n const id = setTimeout(() => {\n signal.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n\n signal.addEventListener('abort', onAbort, { once: true });\n });\n }\n\n private _buildResponse<T>(params: {\n adapterResponse: AdapterResponse | null;\n requestID: string;\n wasCancelled: boolean;\n wasTimeout: boolean;\n adapterType: AdapterType;\n initialURL: string;\n requestURL: string;\n redirectHistory: string[];\n isNetworkErrorOverride?: boolean;\n }): HTTPResponse<T> {\n const {\n adapterResponse,\n requestID,\n wasCancelled,\n wasTimeout,\n adapterType,\n initialURL,\n requestURL,\n redirectHistory,\n isNetworkErrorOverride,\n } = params;\n\n const wasRedirectFollowed = redirectHistory.length > 0;\n const wasRedirectDetected =\n wasRedirectFollowed || (adapterResponse?.wasRedirectDetected ?? false);\n const detectedRedirectURL = adapterResponse?.detectedRedirectURL;\n\n if (!adapterResponse) {\n return {\n status: 0,\n headers: {},\n body: null as unknown as T,\n contentType: 'binary',\n isJSON: false,\n isText: false,\n isCancelled: wasCancelled,\n isTimeout: wasTimeout,\n isNetworkError:\n isNetworkErrorOverride ?? (!wasCancelled && !wasTimeout),\n isFailed: true,\n isParseError: false,\n isStreamed: false,\n isStreamError: false,\n initialURL,\n requestURL,\n wasRedirectDetected,\n wasRedirectFollowed,\n detectedRedirectURL,\n redirectHistory,\n requestID,\n adapterType,\n };\n }\n\n if (\n (adapterResponse.isTransportError || adapterResponse.status === 0) &&\n !adapterResponse.isStreamError\n ) {\n return {\n status: adapterResponse.status,\n headers: adapterResponse.headers,\n body: null as unknown as T,\n contentType: 'binary',\n isJSON: false,\n isText: false,\n isCancelled: false,\n isTimeout: false,\n isNetworkError: isNetworkErrorOverride ?? true,\n isFailed: true,\n isParseError: false,\n isStreamed: false,\n isStreamError: false,\n initialURL,\n requestURL,\n wasRedirectDetected,\n wasRedirectFollowed,\n detectedRedirectURL,\n redirectHistory,\n requestID,\n adapterType,\n };\n }\n\n // Response-body failure after headers: the server returned a real HTTP\n // response, so we\n // preserve its status and headers on HTTPResponse, but the request must\n // still follow the failed/error path because the body could not be fully\n // delivered to the caller's sink. Callers should treat isStreamError /\n // builder.error as authoritative for success, not the preserved status.\n if (adapterResponse.isStreamError) {\n return {\n status: adapterResponse.status,\n headers: adapterResponse.headers,\n body: null as unknown as T,\n contentType: 'binary',\n isJSON: false,\n isText: false,\n isCancelled: false,\n isTimeout: wasTimeout,\n isNetworkError: false,\n isFailed: true,\n isParseError: false,\n isStreamed: false,\n isStreamError: true,\n initialURL,\n requestURL,\n wasRedirectDetected,\n wasRedirectFollowed,\n detectedRedirectURL,\n redirectHistory,\n requestID,\n adapterType,\n };\n }\n\n // Successful stream: body was piped to the caller's writable. Nothing to\n // parse — body is null. Status and headers are still fully populated.\n // `contentType` stays `binary` intentionally here: in this client it tracks\n // how the response body was materialized for callers, and streamed bodies\n // are never decoded into text/JSON at this layer.\n if (adapterResponse.isStreamed) {\n return {\n status: adapterResponse.status,\n headers: adapterResponse.headers,\n body: null as unknown as T,\n contentType: 'binary',\n isJSON: false,\n isText: false,\n isCancelled: false,\n isTimeout: false,\n isNetworkError: false,\n isFailed: false,\n isParseError: false,\n isStreamed: true,\n isStreamError: false,\n initialURL,\n requestURL,\n wasRedirectDetected,\n wasRedirectFollowed,\n detectedRedirectURL,\n redirectHistory,\n requestID,\n adapterType,\n };\n }\n\n const contentTypeHeader = scalarHeader(\n adapterResponse.headers,\n 'content-type',\n );\n const contentType = parseContentType(contentTypeHeader);\n\n let body: unknown = adapterResponse.body;\n let isJSON = false;\n let isText = false;\n let isParseError = false;\n let decodedTextBody: string | null = null;\n\n if (\n (contentType === 'json' || contentType === 'text') &&\n adapterResponse.body\n ) {\n decodedTextBody = new TextDecoder().decode(adapterResponse.body);\n }\n\n if (contentType === 'json' && decodedTextBody !== null) {\n try {\n body = JSON.parse(decodedTextBody);\n isJSON = true;\n } catch {\n isParseError = true;\n body = decodedTextBody;\n }\n } else if (contentType === 'text') {\n isText = true;\n body = decodedTextBody;\n }\n\n return {\n status: adapterResponse.status,\n headers: adapterResponse.headers,\n body: body as T,\n contentType,\n isJSON,\n isText,\n isCancelled: false,\n isTimeout: false,\n isNetworkError: false,\n isFailed: false,\n isParseError,\n isStreamed: false,\n isStreamError: false,\n initialURL,\n requestURL,\n wasRedirectDetected,\n wasRedirectFollowed,\n detectedRedirectURL,\n redirectHistory,\n requestID,\n adapterType,\n };\n }\n\n /**\n * Build an HTTPClientError from a failed response.\n *\n * Error code priority:\n * 1. Explicit codeOverride (redirect_disabled, redirect_loop, request_setup_error, adapter_error, stream_write_error, stream_response_error, stream_setup_error)\n * 2. Response flags (isCancelled → cancelled, isTimeout → timeout),\n * except streamed-body failures preserve their specific stream_* code while\n * still surfacing `isTimeout: true`\n * 3. Default fallback → network_error\n *\n * Key distinction:\n * - `adapter_error`: Adapter threw an exception (DNS failure, connection refused, etc.)\n * The adapter failed to handle the error gracefully.\n * - `network_error`: Adapter reported a transport-level failure cleanly via\n * `isTransportError`, or returned `status: 0` to indicate a transport\n * failure.\n *\n * Well-behaved adapters should catch their own transport failures and return\n * an AdapterResponse instead of throwing. Prefer `isTransportError: true`\n * when reporting adapter-originated transport failures. If an adapter\n * throws, that's an adapter implementation problem.\n */\n private _makeError(\n response: HTTPResponse,\n requestID: string,\n isRetriesExhausted: boolean,\n codeOverride?: HTTPClientError['code'],\n cause?: Error,\n cancelReason?: string,\n ): HTTPClientError {\n let code: HTTPClientError['code'] = codeOverride ?? 'network_error';\n let message = 'Network error';\n\n const isSpecificStreamCodePreserved =\n code === 'stream_write_error' ||\n code === 'stream_response_error' ||\n code === 'stream_setup_error';\n\n if (response.isCancelled) {\n code = 'cancelled';\n message = 'Request was cancelled';\n } else if (response.isTimeout && !isSpecificStreamCodePreserved) {\n code = 'timeout';\n message = 'Request timed out';\n } else if (code === 'redirect_disabled') {\n message = 'Redirect encountered while redirects are disabled';\n } else if (code === 'redirect_loop') {\n message = 'Redirect limit exceeded';\n } else if (code === 'request_setup_error') {\n message = 'Request setup failed';\n } else if (code === 'adapter_error') {\n message = 'Adapter error';\n } else if (code === 'interceptor_error') {\n message = 'Interceptor error';\n } else if (code === 'stream_write_error') {\n message = 'Response stream write failed';\n } else if (code === 'stream_response_error') {\n message = 'Response download stream failed';\n } else if (code === 'stream_setup_error') {\n message = 'Stream response setup failed';\n }\n\n return {\n code,\n message,\n cause,\n initialURL: response.initialURL,\n requestURL: response.requestURL,\n wasRedirectDetected: response.wasRedirectDetected,\n wasRedirectFollowed: response.wasRedirectFollowed,\n detectedRedirectURL: response.detectedRedirectURL,\n redirectHistory: response.redirectHistory,\n requestID,\n isTimeout: response.isTimeout,\n isRetriesExhausted,\n ...(cancelReason !== undefined ? { cancelReason } : {}),\n };\n }\n\n /**\n * Runs parent + own interceptor chains in order.\n * Returns the (possibly modified) request, or an InterceptorCancel signal.\n */\n private async _runInterceptors(\n request: InterceptedRequest,\n phase: InterceptorPhase,\n context: RequestInterceptorContext,\n ): Promise<InterceptedRequest | InterceptorCancel> {\n let current: InterceptedRequest | InterceptorCancel = request;\n\n if (this._parentClient) {\n current = await this._parentClient._requestInterceptors.run(\n request,\n phase,\n context,\n );\n\n if ('cancel' in current) {\n return current;\n }\n }\n\n return this._requestInterceptors.run(current, phase, context);\n }\n\n /**\n * Phase for an attempt outcome that will be retried (before the retry delay).\n * `attempt` matches `onAttemptEnd.attemptNumber` for that outcome.\n */\n private _retryOutcomePhase(\n policy: RetryPolicy | null,\n completedAttemptNumber: number,\n redirect?: RedirectHopInfo,\n ): Extract<ResponseObserverPhase, { type: 'retry' }> {\n const maxAttempts = policy\n ? policy.maxRetryAttempts + 1\n : completedAttemptNumber;\n\n return redirect !== undefined\n ? {\n type: 'retry',\n attempt: completedAttemptNumber,\n maxAttempts,\n redirect,\n }\n : {\n type: 'retry',\n attempt: completedAttemptNumber,\n maxAttempts,\n };\n }\n\n private _withInternalRequestHeaders(\n headers: Record<string, string | string[]>,\n requestID: string,\n attemptNumber?: number,\n ): Record<string, string | string[]> {\n const nextHeaders = mergeHeaders(headers);\n\n if (this._config.includeRequestID) {\n nextHeaders[DEFAULT_REQUEST_ID_HEADER] = requestID;\n }\n\n if (attemptNumber !== undefined && this._config.includeAttemptHeader) {\n nextHeaders[DEFAULT_REQUEST_ATTEMPT_HEADER] = String(attemptNumber);\n }\n\n return nextHeaders;\n }\n\n private _buildAttemptRequest(\n request: InterceptedRequest,\n params: {\n requestID: string;\n timeout: number;\n attemptNumber?: number;\n cookieJar?: CookieJar | null;\n },\n ): AttemptRequest {\n const { requestID, timeout, attemptNumber, cookieJar } = params;\n\n // Build the finalized attempt snapshot before adapter-specific transport\n // materialization. Header names are normalized to lowercase here, and adapters\n // may further materialize repeated header values at send time.\n const observedBodies = buildObservedAttemptBodies(request.body);\n const { contentType } = observedBodies;\n const headers = this._withInternalRequestHeaders(\n request.headers,\n requestID,\n attemptNumber,\n );\n\n // Preserve an explicit content-type from interceptors/callers; otherwise\n // infer one from the serialized body shape.\n if (contentType && headers['content-type'] === undefined) {\n headers['content-type'] = contentType;\n }\n\n // When a jar is present it is authoritative for outbound cookies on every\n // attempt, including redirects and retries.\n if (cookieJar) {\n const cookieStr = cookieJar.getCookieHeaderString(request.requestURL);\n\n if (cookieStr) {\n headers.cookie = cookieStr;\n } else {\n delete headers.cookie;\n }\n }\n\n return {\n requestURL: request.requestURL,\n method: request.method,\n headers,\n body: observedBodies.body,\n rawBody: observedBodies.rawBody,\n timeout,\n attemptNumber,\n requestID,\n };\n }\n\n private _bestEffortAttemptRequestFromPending(\n request: InterceptedRequest,\n timeout: number,\n requestID: string,\n ): AttemptRequest {\n // Best-effort snapshot for observers when a request fails before any adapter\n // attempt is dispatched (interceptor throw, pre-send cancel, setup error, etc.).\n // Jar cookies and internal headers (x-local-client-request-id, x-local-client-request-attempt) are omitted\n // intentionally — they are applied at dispatch time, and since no attempt ever\n // went out, including them would be misleading. Unsupported body types are caught\n // and swallowed here; the real error is reported via request_setup_error instead.\n const headers = mergeHeaders(request.headers);\n let clonedBodies: Pick<AttemptRequest, 'body' | 'rawBody'>;\n\n try {\n clonedBodies = buildObservedAttemptBodies(request.body);\n } catch {\n clonedBodies = {\n body: null,\n rawBody: request.body,\n };\n }\n\n return {\n requestURL: request.requestURL,\n method: request.method,\n headers,\n body: clonedBodies.body,\n rawBody: clonedBodies.rawBody,\n timeout,\n requestID,\n };\n }\n\n private async _runResponseObservers(\n response: HTTPResponse,\n request: AttemptRequest,\n phase: ResponseObserverPhase,\n ): Promise<void> {\n if (this._parentClient) {\n await this._parentClient._responseObservers.run(response, request, phase);\n }\n\n await this._responseObservers.run(response, request, phase);\n }\n\n private async _runErrorObservers(\n error: HTTPClientError,\n request: AttemptRequest,\n phase: ErrorObserverPhase,\n ): Promise<void> {\n if (this._parentClient) {\n await this._parentClient._errorObservers.run(error, request, phase);\n }\n\n await this._errorObservers.run(error, request, phase);\n }\n\n private _composeSignals(a: AbortSignal, b: AbortSignal): AbortSignal {\n if (typeof AbortSignal.any === 'function') {\n return AbortSignal.any([a, b]);\n }\n\n const controller = new AbortController();\n const abort = (signal: AbortSignal) => controller.abort(signal.reason);\n\n if (a.aborted) {\n abort(a);\n } else if (b.aborted) {\n abort(b);\n } else {\n a.addEventListener('abort', () => abort(a), { once: true });\n b.addEventListener('abort', () => abort(b), { once: true });\n }\n\n return controller.signal;\n }\n\n private _assertRequestIsSupported(request: InterceptedRequest): void {\n assertSupportedRequestBody(request.body);\n\n if (\n this._isBrowserRuntime &&\n (this._adapter.getType() === 'fetch' || this._adapter.getType() === 'xhr')\n ) {\n assertNoBrowserRestrictedHeaders(\n request.headers,\n this._adapter.getType() === 'fetch' ? 'FetchAdapter' : 'XHR adapter',\n );\n }\n }\n\n private _assertInterceptorResolvedURL(requestURL: string): void {\n if (this._isSupportedRequestURL(requestURL)) {\n return;\n }\n\n throw new Error(\n `[HTTPClient] Interceptor rewrote requestURL to a value that could not be resolved to an absolute http(s) URL: \"${requestURL}\".`,\n );\n }\n\n private _isSupportedRequestURL(requestURL: string): boolean {\n try {\n const url = new URL(requestURL);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n return false;\n }\n }\n}\n\nexport class HTTPClient extends BaseHTTPClient {\n constructor(config: HTTPClientConfig = {}) {\n super(config);\n }\n\n /**\n * Creates a sub-client that inherits this client's config, request tracker,\n * and interceptor/observer chain integration.\n *\n * `defaultHeaders` use `'replace'` behavior by default. Set\n * `defaultHeadersStrategy: 'merge'` to preserve inherited defaults and\n * layer new headers on top.\n *\n * If no new `defaultHeaders` are provided, `'merge'` keeps the inherited defaults as-is,\n * which is useful for sub-clients that only swap adapters or other non-header config.\n */\n public createSubClient(overrides: SubClientConfig = {}): HTTPSubClient {\n return new BaseHTTPClient(this._buildSubClientConfig(overrides), {\n tracker: this._tracker,\n parentClient: this,\n });\n }\n}\n\n/**\n * Public type for sub-clients returned by {@link HTTPClient.createSubClient}.\n *\n * Identical to {@link HTTPClient} except `createSubClient` is not available —\n * sub-clients share the parent's tracker and observer chain but cannot spawn\n * further sub-clients.\n */\nexport type HTTPSubClient = Omit<HTTPClient, 'createSubClient'>;\n\nfunction buildObservedAttemptBodies(\n rawBody: unknown,\n): Pick<AttemptRequest, 'body' | 'rawBody'> & { contentType: string | null } {\n // Validate before cloning so unsupported object-like values (URLSearchParams,\n // Blob, etc.) fail explicitly instead of being deep-cloned into `{}`.\n assertSupportedRequestBody(rawBody);\n const rawBodySnapshot = cloneBodyValue(rawBody);\n const { body, contentType } = serializeBody(rawBodySnapshot);\n\n return {\n body,\n rawBody: rawBodySnapshot,\n contentType,\n };\n}\n\nfunction cloneBodyValue(body: unknown): unknown {\n if (body instanceof FormData) {\n const cloned = new FormData();\n\n for (const [key, value] of body.entries()) {\n cloned.append(key, value);\n }\n\n return cloned;\n } else if (body instanceof Uint8Array) {\n return new Uint8Array(body);\n } else if (\n Array.isArray(body) ||\n (body !== null &&\n typeof body === 'object' &&\n (Object.getPrototypeOf(body) === Object.prototype ||\n Object.getPrototypeOf(body) === null))\n ) {\n return deepClone(body);\n }\n\n return body;\n}\n\nfunction isAbortError(err: unknown): err is Error {\n return err instanceof Error && err.name === 'AbortError';\n}\n\n/**\n * When `adapter.send()` rejects before resolving (e.g. stream factory throw),\n * adapters may still attach `effectiveRequestHeaders` on the error so observers\n * see the same merged headers as on a successful `AdapterResponse`.\n */\nfunction sentRequestForNonRetryableAdapterCallbackError(\n sentRequest: AttemptRequest,\n error: unknown,\n observedAfterAdapterResolve: AttemptRequest,\n): AttemptRequest {\n return sentRequestForObservedAdapterError(\n sentRequest,\n error,\n observedAfterAdapterResolve,\n );\n}\n\nfunction isNonRetryableClientCallbackError(err: unknown): boolean {\n return Boolean(\n err &&\n typeof err === 'object' &&\n NON_RETRYABLE_HTTP_CLIENT_CALLBACK_ERROR_FLAG in err &&\n (\n err as Record<\n typeof NON_RETRYABLE_HTTP_CLIENT_CALLBACK_ERROR_FLAG,\n boolean | undefined\n >\n )[NON_RETRYABLE_HTTP_CLIENT_CALLBACK_ERROR_FLAG] === true,\n );\n}\n\nfunction isStreamFactoryClientCallbackError(err: unknown): boolean {\n return (\n err !== null && typeof err === 'object' && STREAM_FACTORY_ERROR_FLAG in err\n );\n}\n\nfunction sentRequestForObservedAdapterError(\n sentRequest: AttemptRequest,\n error: unknown,\n observedAfterAdapterResolve: AttemptRequest,\n): AttemptRequest {\n const eff = getEffectiveRequestHeadersFromError(error);\n\n if (!eff) {\n return observedAfterAdapterResolve;\n }\n\n return {\n ...sentRequest,\n headers: mergeObservedHeaders(sentRequest.headers, eff),\n };\n}\n\nfunction getEffectiveRequestHeadersFromError(\n error: unknown,\n): Record<string, string | string[]> | undefined {\n if (\n error &&\n typeof error === 'object' &&\n 'effectiveRequestHeaders' in error &&\n (error as { effectiveRequestHeaders?: unknown }).effectiveRequestHeaders\n ) {\n return (\n error as {\n effectiveRequestHeaders: Record<string, string | string[]>;\n }\n ).effectiveRequestHeaders;\n }\n\n return undefined;\n}\n\nfunction isResponseStreamAbortError(err: unknown): boolean {\n return (\n err !== null && typeof err === 'object' && RESPONSE_STREAM_ABORT_FLAG in err\n );\n}\n\nfunction isXHRBrowserTimeout(err: unknown): boolean {\n return (\n err !== null && typeof err === 'object' && XHR_BROWSER_TIMEOUT_FLAG in err\n );\n}\n\nfunction getResponseStreamAbortInfo(\n err: unknown,\n): { status: number; headers: Record<string, string | string[]> } | undefined {\n if (\n !err ||\n typeof err !== 'object' ||\n !('streamAbortStatus' in err) ||\n !('streamAbortHeaders' in err)\n ) {\n return undefined;\n }\n\n const status = (err as { streamAbortStatus?: unknown }).streamAbortStatus;\n const headers = (err as { streamAbortHeaders?: unknown }).streamAbortHeaders;\n\n if (typeof status !== 'number' || !headers || typeof headers !== 'object') {\n return undefined;\n }\n\n return {\n status,\n headers: headers as Record<string, string | string[]>,\n };\n}\n\n/**\n * Returns the AbortSignal's reason as a string if the caller explicitly passed\n * one (e.g. `controller.abort('my reason')`). Returns undefined for the default\n * AbortError reason set by the runtime when no explicit reason is provided.\n */\nfunction getSignalCancelReason(signal: AbortSignal): string | undefined {\n return typeof signal.reason === 'string' ? signal.reason : undefined;\n}\n","import { parse } from 'tldts';\nimport { normalizeAdapterResponseHeaders } from './utils';\n\n// Matches bare hostnames like 'localhost', 'myapp', 'my-app' that tldts\n// won't assign a registered domain to but are still valid cookie domains.\nconst HOSTNAME_PATTERN =\n /^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*$/;\n\ninterface ParsedCookie {\n name: string;\n value: string;\n domain?: string;\n path?: string;\n expires?: Date;\n maxAge?: number;\n secure?: boolean;\n httpOnly?: boolean;\n sameSite?: 'Strict' | 'Lax' | 'None';\n}\n\nexport interface Cookie {\n name: string;\n value: string;\n domain?: string;\n /** True when the cookie came from a Set-Cookie without Domain= and must not match subdomains. */\n hostOnly?: boolean;\n path?: string;\n expires?: Date;\n /** Seconds from {@link createdAt}; no synthetic `expires` when only Max-Age was sent (RFC 6265). */\n maxAge?: number;\n secure?: boolean;\n httpOnly?: boolean;\n sameSite?: 'Strict' | 'Lax' | 'None';\n /** Epoch ms when the cookie was stored. Used with {@link maxAge} to compute expiry. */\n createdAt: number;\n}\n\n/**\n * Input shape for {@link CookieJar.setCookie}. Identical to {@link Cookie} except\n * `createdAt` is optional — the jar injects `Date.now()` when omitted.\n */\nexport type CookieInput = Omit<Cookie, 'createdAt'> & { createdAt?: number };\n\nexport interface CookieJarJSON {\n cookies: Cookie[];\n}\n\n/**\n * Shareable, standalone cookie jar.\n *\n * Cookies are bucketed by apex domain (via tldts Public Suffix List) for efficient\n * URL lookup — only the relevant bucket is scanned instead of all stored cookies.\n *\n * Validation applied when storing from Set-Cookie headers:\n * - Rejects Domain= values that are recognized public suffixes (e.g. co.uk, com)\n * - Rejects Domain= values that are not a suffix of the request host\n * - Strips leading dots from Domain= per RFC 6265\n *\n * IPs and local hostnames like localhost are never treated as public suffixes.\n */\nexport class CookieJar {\n // Outer key: apex domain from tldts (e.g. 'example.co.uk'), or the hostname\n // itself for IPs and localhost\n // Inner key: composite 'name@domain/path' for deduplication\n private buckets: Map<string, Map<string, Cookie>> = new Map();\n\n /**\n * Stores or updates a cookie. Returns false if the domain is missing or\n * not a valid hostname/IP (e.g. empty string, spaces, garbage input).\n *\n * Valid domains include: hostnames (example.com, localhost, myapp.test),\n * IPv4 (127.0.0.1), and IPv6 ([::1]).\n *\n * For server responses use parseSetCookieHeader — it also enforces PSL\n * validation and domain-suffix checks on top of the syntax check here.\n */\n public setCookie(cookie: CookieInput): boolean {\n const domain = cookie.domain ?? '';\n\n if (!this.isSyntaxValidDomain(domain)) {\n return false;\n }\n\n const normalizedDomain = this.normalizeStoredDomain(domain);\n const path = cookie.path ?? '/';\n const createdAt = cookie.createdAt ?? Date.now();\n const bucket = this.getOrCreateBucket(this.apexFor(normalizedDomain));\n\n bucket.set(this.cookieKey(cookie.name, normalizedDomain, path), {\n ...cookie,\n createdAt,\n domain: normalizedDomain,\n path,\n });\n\n return true;\n }\n\n /**\n * Returns all stored cookies (including possibly expired ones — call\n * clearExpiredCookies first if needed).\n */\n public getAllCookies(): Cookie[] {\n const result: Cookie[] = [];\n\n for (const bucket of this.buckets.values()) {\n result.push(...bucket.values());\n }\n\n return result;\n }\n\n /**\n * Returns the named cookie applicable for the given URL (domain + path\n * matching, unexpired), or undefined.\n *\n * Applies the same rules as getCookiesFor — domain, path, and expiry are all checked.\n */\n public getCookieFor(name: string, url: string): Cookie | undefined {\n return this.getCookiesFor(url).find((c) => c.name === name);\n }\n\n /**\n * Returns all domains that have cookies stored, with a count per domain.\n * Domains are stored in canonical form (lowercase hostnames; normalized IP literals).\n */\n public getStoredDomains(): Array<{ domain: string; count: number }> {\n const counts = new Map<string, number>();\n\n for (const bucket of this.buckets.values()) {\n for (const cookie of bucket.values()) {\n const domain = cookie.domain ?? '';\n counts.set(domain, (counts.get(domain) ?? 0) + 1);\n }\n }\n\n return Array.from(counts.entries()).map(([domain, count]) => ({\n domain,\n count,\n }));\n }\n\n /**\n * Parses a Set-Cookie header string and stores the resulting cookie.\n * The request URL is used to infer and validate the domain (PSL + suffix checks).\n */\n public parseSetCookieHeader(header: string, url: string): void {\n const parsed = this.parseCookieString(header);\n\n if (!parsed) {\n return;\n }\n\n this.storeParsed(parsed, url);\n }\n\n /**\n * Processes all Set-Cookie headers from a response headers object.\n *\n * Uses the same normalization as `HTTPClient` ({@link normalizeAdapterResponseHeaders}):\n * lowercase keys and merged `set-cookie` lines, so mixed-case adapter output\n * matches `FetchAdapter` / normalized responses.\n */\n public processResponseHeaders(\n headers: Record<string, string | string[]>,\n url: string,\n ): void {\n const normalized = normalizeAdapterResponseHeaders(headers);\n const raw = normalized['set-cookie'];\n\n if (raw === undefined || raw === '') {\n return;\n }\n\n const lines: string[] = Array.isArray(raw) ? raw : [raw];\n\n if (lines.length === 0) {\n return;\n }\n\n for (const line of lines) {\n this.parseSetCookieHeader(line, url);\n }\n }\n\n /**\n * Returns cookies applicable for the given URL (domain + path matching, unexpired).\n * Cookies with the Secure attribute are omitted unless the URL uses the `https:` scheme\n * (RFC 6265 §5.4).\n *\n * Only scans the apex-domain bucket for the URL — O(cookies in that domain)\n * instead of O(all cookies).\n */\n public getCookiesFor(url: string): Cookie[] {\n let hostname: string;\n let pathname: string;\n\n let requestScheme: string;\n\n try {\n const parsed = new URL(url);\n hostname = parsed.hostname;\n pathname = parsed.pathname;\n // RFC 6265 §5.4 — Secure cookies must not be sent on non-HTTPS requests.\n requestScheme = parsed.protocol;\n } catch {\n return [];\n }\n\n const now = Date.now();\n const result: Cookie[] = [];\n const apex = this.apexFor(hostname);\n\n const apexBucket = this.buckets.get(apex);\n\n if (apexBucket) {\n for (const cookie of apexBucket.values()) {\n if (this.isExpired(cookie, now)) {\n continue;\n }\n\n const isDomainMatch = cookie.hostOnly\n ? this.hostOnlyDomainMatches(hostname, cookie.domain ?? '')\n : this.domainMatches(hostname, cookie.domain ?? '');\n\n if (!isDomainMatch) {\n continue;\n }\n\n if (!this.pathMatches(pathname, cookie.path ?? '/')) {\n continue;\n }\n\n if (cookie.secure && requestScheme !== 'https:') {\n continue;\n }\n\n result.push(cookie);\n }\n }\n\n result.sort((a, b) => {\n const pathLengthDelta = (b.path ?? '/').length - (a.path ?? '/').length;\n\n if (pathLengthDelta !== 0) {\n return pathLengthDelta;\n }\n\n return a.createdAt - b.createdAt;\n });\n\n return result;\n }\n\n /**\n * Returns a `Cookie: name=value; name2=value2` string for the given URL.\n * Uses `getCookiesFor`, so expired cookies are never included (same as RFC\n * behavior on the wire).\n */\n public getCookieHeaderString(url: string): string {\n return this.getCookiesFor(url)\n .map((c) => `${c.name}=${c.value}`)\n .join('; ');\n }\n\n /**\n * Removes expired cookies from the jar. Returns the number of cookies removed.\n */\n public clearExpiredCookies(): number {\n const now = Date.now();\n let count = 0;\n\n for (const [apex, bucket] of this.buckets.entries()) {\n for (const [key, cookie] of bucket.entries()) {\n if (this.isExpired(cookie, now)) {\n bucket.delete(key);\n count++;\n\n if (bucket.size === 0) {\n this.buckets.delete(apex);\n }\n }\n }\n }\n\n return count;\n }\n\n /**\n * Removes cookies from the jar.\n *\n * - `clear()` — removes everything\n * - `clear(host, 'hostname')` — removes cookies stored for exactly that hostname,\n * leaving other subdomains untouched. e.g. `clear('api.example.com', 'hostname')`\n * does not touch cookies stored for `example.com`.\n * - `clear(host, 'domain')` — removes all cookies for the entire domain family\n * (apex + all subdomains). e.g. `clear('api.example.com', 'domain')` clears\n * everything in the `example.com` apex bucket.\n */\n public clear(): number;\n public clear(host: string, scope: 'hostname' | 'domain'): number;\n public clear(host?: string, scope?: 'hostname' | 'domain'): number {\n if (host === undefined) {\n const count = this.getAllCookies().length;\n this.buckets.clear();\n return count;\n } else if (scope === 'domain') {\n const count = this.buckets.get(this.apexFor(host))?.size ?? 0;\n this.buckets.delete(this.apexFor(host));\n return count;\n } else {\n const apex = this.apexFor(host);\n const bucket = this.buckets.get(apex);\n\n if (!bucket) {\n return 0;\n }\n\n const normalizedHost = this.normalizeStoredDomain(host);\n let count = 0;\n\n for (const [key, cookie] of bucket.entries()) {\n if (cookie.domain === normalizedHost) {\n bucket.delete(key);\n count++;\n }\n }\n\n this.pruneEmptyBucket(apex);\n return count;\n }\n }\n\n /**\n * Serializes the jar to JSON.\n */\n public toJSON(): CookieJarJSON {\n return { cookies: this.getAllCookies() };\n }\n\n /**\n * Restores a jar from serialized JSON.\n */\n public fromJSON(data: CookieJarJSON): void {\n this.buckets.clear();\n\n for (const cookie of data.cookies) {\n if (cookie.expires && !(cookie.expires instanceof Date)) {\n cookie.expires = new Date(cookie.expires as unknown as string);\n }\n\n this.setCookie(cookie);\n }\n }\n\n // --- Private helpers ---\n\n private cookieKey(name: string, domain: string, path: string): string {\n return `${name}@${domain}${path}`;\n }\n\n /** Canonical form for stored cookie domains: lowercase DNS names; canonical IP literals. */\n private normalizeStoredDomain(domain: string): string {\n const ip = this.tryCanonicalIPLiteral(domain);\n\n if (ip !== null) {\n return ip;\n }\n\n return this.unbracketHost(domain).toLowerCase();\n }\n\n private parseCookieString(header: string): ParsedCookie | null {\n const parts = header.split(';').map((p) => p.trim());\n const nameValuePart = parts[0];\n const eqIndex = nameValuePart.indexOf('=');\n\n if (eqIndex === -1) {\n return null;\n }\n\n const name = nameValuePart.slice(0, eqIndex).trim();\n const value = nameValuePart.slice(eqIndex + 1).trim();\n\n if (!name) {\n return null;\n }\n\n const cookie: ParsedCookie = { name, value };\n\n for (let i = 1; i < parts.length; i++) {\n const part = parts[i];\n const lowerPart = part.toLowerCase();\n\n if (lowerPart === 'secure') {\n cookie.secure = true;\n } else if (lowerPart === 'httponly') {\n cookie.httpOnly = true;\n } else {\n const eqIdx = part.indexOf('=');\n if (eqIdx === -1) {\n continue;\n }\n\n const attrName = part.slice(0, eqIdx).trim().toLowerCase();\n const attrValue = part.slice(eqIdx + 1).trim();\n\n switch (attrName) {\n case 'domain': {\n cookie.domain = attrValue.startsWith('.')\n ? attrValue.slice(1)\n : attrValue;\n break;\n }\n case 'path': {\n // RFC 6265 §5.2 — empty Path attribute is ignored (default-path applies).\n if (attrValue !== '') {\n cookie.path = attrValue;\n }\n break;\n }\n case 'expires': {\n const date = new Date(attrValue);\n if (!isNaN(date.getTime())) {\n cookie.expires = date;\n }\n break;\n }\n case 'max-age': {\n const maxAge = parseInt(attrValue, 10);\n if (!isNaN(maxAge)) {\n cookie.maxAge = maxAge;\n }\n break;\n }\n case 'samesite': {\n const lower = attrValue.toLowerCase();\n if (lower === 'strict') {\n cookie.sameSite = 'Strict';\n } else if (lower === 'lax') {\n cookie.sameSite = 'Lax';\n } else if (lower === 'none') {\n cookie.sameSite = 'None';\n }\n break;\n }\n }\n }\n }\n\n return cookie;\n }\n\n private pruneEmptyBucket(apex: string): void {\n if (this.buckets.get(apex)?.size === 0) {\n this.buckets.delete(apex);\n }\n }\n\n private deleteCookieByIdentity(\n name: string,\n domain: string,\n path: string,\n ): void {\n const apex = this.apexFor(domain);\n this.buckets.get(apex)?.delete(this.cookieKey(name, domain, path));\n this.pruneEmptyBucket(apex);\n }\n\n /**\n * RFC 6265 §5.1.4 — default-path from the path portion of the request-uri.\n * E.g. `/admin/settings` → `/admin`; `/admin` or `/` → `/`.\n */\n private defaultCookiePathFromPathname(pathname: string): string {\n if (pathname === '' || pathname.charCodeAt(0) !== 47 /* / */) {\n return '/';\n }\n\n let slashCount = 0;\n\n for (let i = 0; i < pathname.length; i++) {\n if (pathname.charCodeAt(i) === 47) {\n slashCount++;\n }\n }\n\n if (slashCount <= 1) {\n return '/';\n }\n\n return pathname.slice(0, pathname.lastIndexOf('/'));\n }\n\n /** Path from Set-Cookie when present and non-empty; otherwise §5.1.4 default-path. */\n private resolvedCookiePath(\n parsed: ParsedCookie,\n requestPathname: string,\n ): string {\n if (parsed.path !== undefined && parsed.path !== '') {\n return parsed.path;\n }\n\n return this.defaultCookiePathFromPathname(requestPathname);\n }\n\n /** Returns the apex (registered) domain for bucketing.\n * Falls back to hostname for IPs and local hostnames like localhost. */\n private apexFor(hostname: string): string {\n const ip = this.tryCanonicalIPLiteral(hostname);\n\n if (ip !== null) {\n return ip;\n }\n\n const result = parse(hostname);\n return result.domain ?? hostname;\n }\n\n private getOrCreateBucket(apex: string): Map<string, Cookie> {\n let bucket = this.buckets.get(apex);\n\n if (!bucket) {\n bucket = new Map();\n this.buckets.set(apex, bucket);\n }\n\n return bucket;\n }\n\n private storeParsed(parsed: ParsedCookie, url: string): void {\n let address: URL;\n\n try {\n address = new URL(url);\n } catch {\n return;\n }\n\n const requestHostname = address.hostname;\n\n let domain: string;\n\n if (parsed.domain) {\n // RFC 6265 §5.2.3: strip leading dot\n const raw = parsed.domain.startsWith('.')\n ? parsed.domain.slice(1)\n : parsed.domain;\n\n // RFC 6265 5.1.3: domain matching is case-insensitive; URL.host is lowercased but Domain= is not.\n const normalizedDomain = this.normalizeStoredDomain(raw);\n\n // Reject public suffixes — prevents Domain=co.uk style attacks\n if (this.isPublicSuffix(normalizedDomain)) {\n return;\n }\n\n // Reject cross-domain — server can only set cookies for its own domain\n if (!this.domainMatches(requestHostname, normalizedDomain)) {\n return;\n }\n\n domain = normalizedDomain;\n } else {\n domain = requestHostname;\n }\n\n const path = this.resolvedCookiePath(parsed, address.pathname);\n\n // Max-Age=0 or negative → delete the cookie\n if (parsed.maxAge !== undefined && parsed.maxAge <= 0) {\n this.deleteCookieByIdentity(parsed.name, domain, path);\n return;\n }\n\n // Expires in the past (or now) with no Max-Age: discard / remove — same effect as\n // Max-Age=0 for cookie identity. If Max-Age is present and positive, it overrides\n // Expires per RFC 6265 and the cookie may still be valid.\n if (\n parsed.expires !== undefined &&\n parsed.expires.getTime() <= Date.now() &&\n parsed.maxAge === undefined\n ) {\n this.deleteCookieByIdentity(parsed.name, domain, path);\n return;\n }\n\n const cookie: Cookie = {\n name: parsed.name,\n value: parsed.value,\n domain,\n // Align with `if (parsed.domain)` above: empty `Domain=` / `Domain=.` parses to\n // `''` and must be host-only like a missing Domain attribute.\n hostOnly: !parsed.domain,\n path,\n createdAt: Date.now(),\n };\n\n if (parsed.expires) {\n cookie.expires = parsed.expires;\n }\n\n if (parsed.maxAge !== undefined) {\n cookie.maxAge = parsed.maxAge;\n }\n\n if (parsed.secure) {\n cookie.secure = true;\n }\n\n if (parsed.httpOnly) {\n cookie.httpOnly = true;\n }\n\n if (parsed.sameSite) {\n cookie.sameSite = parsed.sameSite;\n }\n\n this.setCookie(cookie);\n }\n\n /**\n * Returns a canonical lowercase IP literal for bucketing and matching, or null if\n * `host` is not syntactically a valid IPv4 or IPv6 host string (bracketed or not).\n *\n * Uses the URL parser for IPv6 literals so validation does not depend on tldts\n * `isIp`, which is unreliable for bracketed IPv6 and false for unbracketed `::1`\n * in some releases (see tldts#2288).\n */\n private tryCanonicalIPLiteral(host: string): string | null {\n if (!host) {\n return null;\n }\n\n if (host.startsWith('[') && host.endsWith(']')) {\n const inner = host.slice(1, -1);\n\n if (!inner) {\n return null;\n }\n\n try {\n new URL(`http://[${inner}]/`);\n return inner.toLowerCase();\n } catch {\n return null;\n }\n }\n\n if (host.includes(':')) {\n try {\n new URL(`http://[${host}]/`);\n return host.toLowerCase();\n } catch {\n return null;\n }\n }\n\n if (/^\\d{1,3}(\\.\\d{1,3}){3}$/.test(host)) {\n try {\n const { hostname } = new URL(`http://${host}/`);\n if (hostname !== host) {\n return null;\n }\n return host;\n } catch {\n return null;\n }\n }\n\n return null;\n }\n\n private unbracketHost(host: string): string {\n if (host.length >= 2 && host[0] === '[' && host[host.length - 1] === ']') {\n return host.slice(1, -1);\n }\n return host;\n }\n\n /** Validates domain syntax for setCookie. Accepts hostnames (example.com,\n * localhost, myapp.test), IPv4, and bracketed IPv6 ([::1]). Rejects empty\n * strings, spaces, and other garbage. Does NOT enforce PSL — use\n * parseSetCookieHeader for server responses. */\n private isSyntaxValidDomain(domain: string): boolean {\n if (!domain) {\n return false;\n }\n\n if (this.tryCanonicalIPLiteral(domain) !== null) {\n return true;\n }\n\n const result = parse(domain);\n\n if (result.isIp) {\n return true;\n } else if (result.domain !== null) {\n return true;\n } else {\n // Bare hostnames like 'localhost' — tldts domain is null but valid\n return result.isIcann !== true && HOSTNAME_PATTERN.test(domain);\n }\n }\n\n /** Returns true if the domain is a recognized public suffix (e.g. co.uk, com).\n * IPs and local hostnames like localhost are not rejected. */\n private isPublicSuffix(domain: string): boolean {\n if (this.tryCanonicalIPLiteral(domain) !== null) {\n return false;\n }\n\n const result = parse(domain);\n return !result.isIp && result.domain === null && result.isIcann === true;\n }\n\n private isExpired(cookie: Cookie, now: number): boolean {\n if (cookie.maxAge !== undefined) {\n return now > cookie.createdAt + cookie.maxAge * 1000;\n }\n\n if (cookie.expires) {\n return now > cookie.expires.getTime();\n }\n\n return false;\n }\n\n private domainMatches(requestHost: string, cookieDomain: string): boolean {\n if (!cookieDomain) {\n return true;\n }\n\n const canonicalRequestHost = this.tryCanonicalIPLiteral(requestHost);\n const canonicalCookieDomain = this.tryCanonicalIPLiteral(cookieDomain);\n\n if (canonicalRequestHost !== null && canonicalCookieDomain !== null) {\n return canonicalRequestHost === canonicalCookieDomain;\n }\n\n const req = this.unbracketHost(requestHost).toLowerCase();\n const cook = this.unbracketHost(cookieDomain).toLowerCase();\n\n if (req === cook) {\n return true;\n }\n\n // Subdomain suffix rules apply to DNS names only, not IP literals.\n if (req.includes(':') || cook.includes(':')) {\n return false;\n }\n\n return req.endsWith('.' + cook);\n }\n\n private hostOnlyDomainMatches(\n requestHost: string,\n cookieDomain: string,\n ): boolean {\n const canonicalRequestHost = this.tryCanonicalIPLiteral(requestHost);\n const canonicalCookieDomain = this.tryCanonicalIPLiteral(cookieDomain);\n\n if (canonicalRequestHost !== null && canonicalCookieDomain !== null) {\n return canonicalRequestHost === canonicalCookieDomain;\n }\n\n return (\n this.unbracketHost(requestHost).toLowerCase() ===\n this.unbracketHost(cookieDomain).toLowerCase()\n );\n }\n\n /**\n * RFC 6265 §5.1.4 — request-path path-matches cookie-path when:\n * (1) identical, (2) cookie-path is a prefix and ends with `/`, or\n * (3) cookie-path is a prefix and the next request-path character is `/`.\n *\n * A single `startsWith(cookiePath + '/')` only covers (1)+(3) and breaks (2):\n * e.g. cookie `/api/` must match `/api/users` without requiring `/api//`.\n */\n private pathMatches(requestPath: string, cookiePath: string): boolean {\n if (cookiePath === '/') {\n return true;\n } else if (requestPath === cookiePath) {\n return true;\n } else if (!requestPath.startsWith(cookiePath)) {\n return false;\n } else if (cookiePath.endsWith('/')) {\n return true;\n } else {\n return (\n requestPath.length > cookiePath.length &&\n requestPath.charAt(cookiePath.length) === '/'\n );\n }\n }\n}\n"],"mappings":"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","names":["ObjectID","UUIDv4","UUIDv7","cloned","stringWidth","import_string_width","stringWidth","availableWidth","import_string_width","stringWidth","availableWidth","import_tldts","qs","response","isAbortError","import_tldts"]}