diff --git a/.github/actions/acceptance/action.yml b/.github/actions/acceptance/action.yml index ff629ec..4168d34 100644 --- a/.github/actions/acceptance/action.yml +++ b/.github/actions/acceptance/action.yml @@ -1,4 +1,4 @@ -# Copyright IBM Corp. 2022, 2025 +# Copyright IBM Corp. 2022, 2026 # SPDX-License-Identifier: MPL-2.0 --- diff --git a/.github/workflows/tagrelease.yml b/.github/workflows/tagrelease.yml index 0372a1f..4670cfc 100644 --- a/.github/workflows/tagrelease.yml +++ b/.github/workflows/tagrelease.yml @@ -15,7 +15,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - name: Checkout - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: ref: ${{ github.head_ref }} # checkout the correct branch name fetch-depth: 0 # fetch the whole repo history diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3061b13..67b8218 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,8 +10,8 @@ jobs: ci: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 24 - run: npm install @@ -28,8 +28,8 @@ jobs: unauthenticated: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 24 - name: Run action-setup-enos @@ -39,8 +39,8 @@ jobs: with-github-token-input: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 24 - name: Run action-setup-enos @@ -52,8 +52,8 @@ jobs: with-GITHUB_TOKEN-env-var: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 24 - name: Run action-setup-enos diff --git a/action.yml b/action.yml index 9012d95..e3e7c77 100644 --- a/action.yml +++ b/action.yml @@ -1,4 +1,4 @@ -# Copyright IBM Corp. 2022, 2025 +# Copyright IBM Corp. 2022, 2026 # SPDX-License-Identifier: MPL-2.0 name: setup-enos diff --git a/dist/index.js b/dist/index.js index 7286f39..2d72285 100644 --- a/dist/index.js +++ b/dist/index.js @@ -41353,6 +41353,7 @@ function isPrimitiveTypeName(name) { return primitiveTypeNames.includes(name); } const assertionTypeDescriptions = [ + 'bound Function', 'positive number', 'negative number', 'Class', @@ -41387,7 +41388,13 @@ const assertionTypeDescriptions = [ 'non-empty map', 'PropertyKey', 'even integer', + 'finite number', + 'negative integer', + 'non-negative integer', + 'non-negative number', 'odd integer', + 'positive integer', + 'safe integer', 'T', 'in range', 'predicate returns truthy for any value', @@ -41400,7 +41407,7 @@ const assertionTypeDescriptions = [ ]; const getObjectType = (value) => { const objectTypeName = Object.prototype.toString.call(value).slice(8, -1); - if (/HTML\w+Element/.test(objectTypeName) && isHtmlElement(value)) { + if (/HTML\w+Element/v.test(objectTypeName) && isHtmlElement(value)) { return 'HTMLElement'; } if (isObjectTypeName(objectTypeName)) { @@ -41412,6 +41419,7 @@ function detect(value) { if (value === null) { return 'null'; } + // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check switch (typeof value) { case 'undefined': { return 'undefined'; @@ -41446,13 +41454,13 @@ function detect(value) { return 'Buffer'; } const tagType = getObjectType(value); - if (tagType && tagType !== 'Object') { + if (tagType !== undefined && tagType !== 'Object') { return tagType; } if (hasPromiseApi(value)) { return 'Promise'; } - if (value instanceof String || value instanceof Boolean || value instanceof Number) { + if (isBoxedPrimitiveObject(value)) { throw new TypeError('Please don\'t use object wrappers for primitive types'); } return 'Object'; @@ -41460,12 +41468,29 @@ function detect(value) { function hasPromiseApi(value) { return isFunction(value?.then) && isFunction(value?.catch); } +function hasBoxedPrimitiveBrand(value, valueOf) { + try { + // `Object.prototype.toString` can be spoofed via `Symbol.toStringTag`, but the + // boxed primitive `valueOf` methods still enforce the real internal brand. + Reflect.apply(valueOf, value, []); + return true; + } + catch { + return false; + } +} +function isBoxedPrimitiveObject(value) { + return hasBoxedPrimitiveBrand(value, String.prototype.valueOf) + || hasBoxedPrimitiveBrand(value, Boolean.prototype.valueOf) + || hasBoxedPrimitiveBrand(value, Number.prototype.valueOf); +} const is = Object.assign(detect, { all: isAll, any: isAny, array: isArray, arrayBuffer: isArrayBuffer, arrayLike: isArrayLike, + arrayOf: isArrayOf, asyncFunction: isAsyncFunction, asyncGenerator: isAsyncGenerator, asyncGeneratorFunction: isAsyncGeneratorFunction, @@ -41492,6 +41517,7 @@ const is = Object.assign(detect, { error: isError, evenInteger: isEvenInteger, falsy: isFalsy, + finiteNumber: isFiniteNumber, float32Array: isFloat32Array, float64Array: isFloat64Array, formData: isFormData, @@ -41509,6 +41535,7 @@ const is = Object.assign(detect, { map: isMap, nan: isNan, nativePromise: isNativePromise, + negativeInteger: isNegativeInteger, negativeNumber: isNegativeNumber, nodeStream: isNodeStream, nonEmptyArray: isNonEmptyArray, @@ -41517,6 +41544,8 @@ const is = Object.assign(detect, { nonEmptySet: isNonEmptySet, nonEmptyString: isNonEmptyString, nonEmptyStringAndNotWhitespace: isNonEmptyStringAndNotWhitespace, + nonNegativeInteger: isNonNegativeInteger, + nonNegativeNumber: isNonNegativeNumber, null: isNull, nullOrUndefined: isNullOrUndefined, number: isNumber, @@ -41524,7 +41553,9 @@ const is = Object.assign(detect, { object: isObject, observable: isObservable, oddInteger: isOddInteger, + oneOf: isOneOf, plainObject: distribution_isPlainObject, + positiveInteger: isPositiveInteger, positiveNumber: isPositiveNumber, primitive: isPrimitive, promise: isPromise, @@ -41569,9 +41600,12 @@ function validatePredicateArray(predicateArray, allowEmpty) { return; } for (const predicate of predicateArray) { - if (!isFunction(predicate)) { - throw new TypeError(`Invalid predicate: ${JSON.stringify(predicate)}`); - } + validatePredicate(predicate); + } +} +function validatePredicate(predicate) { + if (!isFunction(predicate)) { + throw new TypeError(`Invalid predicate: ${JSON.stringify(predicate)}`); } } function isAll(predicate, ...values) { @@ -41617,6 +41651,9 @@ function isArrayBuffer(value) { function isArrayLike(value) { return !isNullOrUndefined(value) && !isFunction(value) && isValidLength(value.length); } +function isArrayOf(predicate) { + return (value) => isArray(value) && value.every(element => predicate(element)); +} function isAsyncFunction(value) { return getObjectType(value) === 'AsyncFunction'; } @@ -41644,7 +41681,7 @@ function isBlob(value) { function isBoolean(value) { return value === true || value === false; } -// eslint-disable-next-line @typescript-eslint/ban-types +// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type function isBoundFunction(value) { return isFunction(value) && !Object.hasOwn(value, 'prototype'); } @@ -41652,11 +41689,11 @@ function isBoundFunction(value) { Note: [Prefer using `Uint8Array` instead of `Buffer`.](https://sindresorhus.com/blog/goodbye-nodejs-buffer) */ function isBuffer(value) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call + // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access return value?.constructor?.isBuffer?.(value) ?? false; } function isClass(value) { - return isFunction(value) && /^class(\s+|{)/.test(value.toString()); + return isFunction(value) && /^class(?:\s+|\{)/v.test(value.toString()); } function isDataView(value) { return getObjectType(value) === 'DataView'; @@ -41677,7 +41714,7 @@ function isEmptyMap(value) { return isMap(value) && value.size === 0; } function isEmptyObject(value) { - return isObject(value) && !isMap(value) && !isSet(value) && Object.keys(value).length === 0; + return isObject(value) && !isFunction(value) && !isArray(value) && !isMap(value) && !isSet(value) && Object.keys(value).length === 0; } function isEmptySet(value) { return isSet(value) && value.size === 0; @@ -41689,11 +41726,21 @@ function isEmptyStringOrWhitespace(value) { return isEmptyString(value) || isWhitespaceString(value); } function isEnumCase(value, targetEnum) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - return Object.values(targetEnum).includes(value); + // Numeric enums have reverse mappings (e.g. `Direction[0] = "Up"`), so their runtime object contains both `{ Up: 0 }` and `{ "0": "Up" }`. Filtering out entries that round-trip like a canonical number and point back to an own property leaves only actual enum member values. + const enumObject = targetEnum; + return Object.entries(enumObject).some(([key, enumValue]) => { + if (!isString(enumValue)) { + return enumValue === value; + } + const numericKey = Number(key); + if (Number.isNaN(numericKey) || String(numericKey) !== key) { + return enumValue === value; + } + return enumValue === value && !(Object.hasOwn(enumObject, enumValue) && enumObject[enumValue] === numericKey); + }); } function isError(value) { - // TODO: Use `Error.isError` when targeting Node.js 24.` + // TODO: Use `Error.isError` when targeting Node.js 24. return getObjectType(value) === 'Error'; } function isEvenInteger(value) { @@ -41703,6 +41750,9 @@ function isEvenInteger(value) { function isFalsy(value) { return !value; } +function isFiniteNumber(value) { + return Number.isFinite(value); +} // TODO: Support detecting Float16Array when targeting Node.js 24. function isFloat32Array(value) { return getObjectType(value) === 'Float32Array'; @@ -41713,7 +41763,7 @@ function isFloat64Array(value) { function isFormData(value) { return getObjectType(value) === 'FormData'; } -// eslint-disable-next-line @typescript-eslint/ban-types +// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type function isFunction(value) { return typeof value === 'function'; } @@ -41723,9 +41773,7 @@ function isGenerator(value) { function isGeneratorFunction(value) { return getObjectType(value) === 'GeneratorFunction'; } -// eslint-disable-next-line @typescript-eslint/naming-convention -const NODE_TYPE_ELEMENT = 1; -// eslint-disable-next-line @typescript-eslint/naming-convention +const NODE_TYPE_ELEMENT = 1; // eslint-disable-line @typescript-eslint/naming-convention const DOM_PROPERTIES_TO_CHECK = [ 'innerHTML', 'ownerDocument', @@ -41748,6 +41796,9 @@ function isInRange(value, range) { return value >= Math.min(0, range) && value <= Math.max(range, 0); } if (isArray(range) && range.length === 2) { + if (Number.isNaN(range[0]) || Number.isNaN(range[1])) { + throw new TypeError(`Invalid range: ${JSON.stringify(range)}`); + } return value >= Math.min(...range) && value <= Math.max(...range); } throw new TypeError(`Invalid range: ${JSON.stringify(range)}`); @@ -41776,6 +41827,9 @@ function isNan(value) { function isNativePromise(value) { return getObjectType(value) === 'Promise'; } +function isNegativeInteger(value) { + return isInteger(value) && value < 0; +} function isNegativeNumber(value) { return isNumber(value) && value < 0; } @@ -41791,7 +41845,7 @@ function isNonEmptyMap(value) { // TODO: Use `not` operator here to remove `Map` and `Set` from type guard: // - https://github.com/Microsoft/TypeScript/pull/29317 function isNonEmptyObject(value) { - return isObject(value) && !isMap(value) && !isSet(value) && Object.keys(value).length > 0; + return isObject(value) && !isFunction(value) && !isArray(value) && !isMap(value) && !isSet(value) && Object.keys(value).length > 0; } function isNonEmptySet(value) { return isSet(value) && value.size > 0; @@ -41804,11 +41858,17 @@ function isNonEmptyString(value) { function isNonEmptyStringAndNotWhitespace(value) { return isString(value) && !isEmptyStringOrWhitespace(value); } -// eslint-disable-next-line @typescript-eslint/ban-types +function isNonNegativeInteger(value) { + return isInteger(value) && value >= 0; +} +function isNonNegativeNumber(value) { + return isNumber(value) && value >= 0; +} +// eslint-disable-next-line @typescript-eslint/no-restricted-types function isNull(value) { return value === null; } -// eslint-disable-next-line @typescript-eslint/ban-types +// eslint-disable-next-line @typescript-eslint/no-restricted-types function isNullOrUndefined(value) { return isNull(value) || isUndefined(value); } @@ -41816,9 +41876,9 @@ function isNumber(value) { return typeof value === 'number' && !Number.isNaN(value); } function isNumericString(value) { - return isString(value) && !isEmptyStringOrWhitespace(value) && !Number.isNaN(Number(value)); + return isString(value) && !isEmptyStringOrWhitespace(value) && value === value.trim() && !Number.isNaN(Number(value)); } -// eslint-disable-next-line @typescript-eslint/ban-types +// eslint-disable-next-line @typescript-eslint/no-restricted-types function isObject(value) { return !isNull(value) && (typeof value === 'object' || isFunction(value)); } @@ -41826,11 +41886,11 @@ function isObservable(value) { if (!value) { return false; } - // eslint-disable-next-line no-use-extend-native/no-use-extend-native, @typescript-eslint/no-unsafe-call + // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access if (Symbol.observable !== undefined && value === value[Symbol.observable]?.()) { return true; } - // eslint-disable-next-line @typescript-eslint/no-unsafe-call + // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access if (value === value['@@observable']?.()) { return true; } @@ -41839,6 +41899,9 @@ function isObservable(value) { function isOddInteger(value) { return isAbsoluteModule2(1)(value); } +function isOneOf(values) { + return (value) => values.includes(value); +} function distribution_isPlainObject(value) { // From: https://github.com/sindresorhus/is-plain-obj/blob/main/index.js if (typeof value !== 'object' || value === null) { @@ -41848,6 +41911,9 @@ function distribution_isPlainObject(value) { const prototype = Object.getPrototypeOf(value); return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in value) && !(Symbol.iterator in value); } +function isPositiveInteger(value) { + return isInteger(value) && value > 0; +} function isPositiveNumber(value) { return isNumber(value) && value > 0; } @@ -41857,7 +41923,7 @@ function isPrimitive(value) { function isPromise(value) { return isNativePromise(value) || hasPromiseApi(value); } -// `PropertyKey` is any value that can be used as an object key (string, number, or symbol) +// `PropertyKey` is any value that can be used as an object key (string, number, or symbol). Note: NaN is technically `typeof 'number'` and thus fits TypeScript's `PropertyKey`, but we intentionally exclude it here because using NaN as a property key is almost always a mistake. function isPropertyKey(value) { return isAny([isString, isNumber, isSymbol], value); } @@ -41933,25 +41999,23 @@ function isValidDate(value) { function isValidLength(value) { return isSafeInteger(value) && value >= 0; } -// eslint-disable-next-line @typescript-eslint/ban-types +// eslint-disable-next-line @typescript-eslint/no-restricted-types function isWeakMap(value) { return getObjectType(value) === 'WeakMap'; } -// eslint-disable-next-line @typescript-eslint/ban-types, unicorn/prevent-abbreviations +// eslint-disable-next-line @typescript-eslint/no-restricted-types function isWeakRef(value) { return getObjectType(value) === 'WeakRef'; } -// eslint-disable-next-line @typescript-eslint/ban-types +// eslint-disable-next-line @typescript-eslint/no-restricted-types function isWeakSet(value) { return getObjectType(value) === 'WeakSet'; } function isWhitespaceString(value) { - return isString(value) && /^\s+$/.test(value); + return isString(value) && /^\s+$/v.test(value); } function predicateOnArray(method, predicate, values) { - if (!isFunction(predicate)) { - throw new TypeError(`Invalid predicate: ${JSON.stringify(predicate)}`); - } + validatePredicate(predicate); if (values.length === 0) { throw new TypeError('Invalid number of values'); } @@ -41960,6 +42024,9 @@ function predicateOnArray(method, predicate, values) { function typeErrorMessage(description, value) { return `Expected value which is \`${description}\`, received value of type \`${is(value)}\`.`; } +function typeErrorMessageNot(description, value) { + return `Expected value which is not \`${description}\`, received value of type \`${is(value)}\`.`; +} function unique(values) { // eslint-disable-next-line unicorn/prefer-spread return Array.from(new Set(values)); @@ -41971,9 +42038,41 @@ function typeErrorMessageMultipleValues(expectedType, values) { const uniqueValueTypes = unique(values.map(value => `\`${is(value)}\``)); return `Expected values which are ${orFormatter.format(uniqueExpectedTypes)}. Received values of type${uniqueValueTypes.length > 1 ? 's' : ''} ${andFormatter.format(uniqueValueTypes)}.`; } +// Negative assertions are limited to types where the assertion rejects every TypeScript value assignable to the forbidden type. Structural object types such as `Map`, `Set`, `Date`, and `Array` are excluded because TypeScript accepts shape-compatible mocks while the runtime checks use object brands, so `Exclude` would narrow values that can pass the negative assertion. +function createAssertNot(predicate, description) { + return (value, message) => { + if (predicate(value)) { + throw new TypeError(message ?? typeErrorMessageNot(description, value)); + } + }; +} +const assertNotUndefined = createAssertNot(isUndefined, 'undefined'); +// eslint-disable-next-line @typescript-eslint/no-restricted-types +const assertNotNull = createAssertNot(isNull, 'null'); +// eslint-disable-next-line @typescript-eslint/no-restricted-types +const assertNotNullOrUndefined +// eslint-disable-next-line @typescript-eslint/no-restricted-types += createAssertNot(isNullOrUndefined, 'null or undefined'); +const assertNotString = createAssertNot(isString, 'string'); +const assertNotBoolean = createAssertNot(isBoolean, 'boolean'); +const assertNotSymbol = createAssertNot(isSymbol, 'symbol'); +const assertNotBigint = createAssertNot(isBigint, 'bigint'); +const assertNotPrimitive = createAssertNot(isPrimitive, 'primitive'); // eslint-disable-line @typescript-eslint/no-restricted-types +// We intentionally do not support `assert.not(is.undefined, value)`. TypeScript cannot derive safe complement types from arbitrary predicates, and many predicates here are refinements (for example, `is.number` rejects `NaN`). Explicit methods keep runtime checks and type narrowing aligned. +const notAssertions = { + bigint: assertNotBigint, + boolean: assertNotBoolean, + null: assertNotNull, + nullOrUndefined: assertNotNullOrUndefined, + primitive: assertNotPrimitive, + string: assertNotString, + symbol: assertNotSymbol, + undefined: assertNotUndefined, +}; const assert = { all: assertAll, any: assertAny, + not: notAssertions, optional: assertOptional, array: assertArray, arrayBuffer: assertArrayBuffer, @@ -42003,6 +42102,7 @@ const assert = { error: assertError, evenInteger: assertEvenInteger, falsy: assertFalsy, + finiteNumber: assertFiniteNumber, float32Array: assertFloat32Array, float64Array: assertFloat64Array, formData: assertFormData, @@ -42020,6 +42120,7 @@ const assert = { map: assertMap, nan: assertNan, nativePromise: assertNativePromise, + negativeInteger: assertNegativeInteger, negativeNumber: assertNegativeNumber, nodeStream: assertNodeStream, nonEmptyArray: assertNonEmptyArray, @@ -42028,6 +42129,8 @@ const assert = { nonEmptySet: assertNonEmptySet, nonEmptyString: assertNonEmptyString, nonEmptyStringAndNotWhitespace: assertNonEmptyStringAndNotWhitespace, + nonNegativeInteger: assertNonNegativeInteger, + nonNegativeNumber: assertNonNegativeNumber, null: assertNull, nullOrUndefined: assertNullOrUndefined, number: assertNumber, @@ -42036,6 +42139,7 @@ const assert = { observable: assertObservable, oddInteger: assertOddInteger, plainObject: assertPlainObject, + positiveInteger: assertPositiveInteger, positiveNumber: assertPositiveNumber, primitive: assertPrimitive, promise: assertPromise, @@ -42077,7 +42181,7 @@ const methodTypeMap = { isBigUint64Array: 'BigUint64Array', isBlob: 'Blob', isBoolean: 'boolean', - isBoundFunction: 'Function', + isBoundFunction: 'bound Function', isBuffer: 'Buffer', isClass: 'Class', isDataView: 'DataView', @@ -42093,6 +42197,7 @@ const methodTypeMap = { isError: 'Error', isEvenInteger: 'even integer', isFalsy: 'falsy', + isFiniteNumber: 'finite number', isFloat32Array: 'Float32Array', isFloat64Array: 'Float64Array', isFormData: 'FormData', @@ -42110,6 +42215,7 @@ const methodTypeMap = { isMap: 'Map', isNan: 'NaN', isNativePromise: 'native Promise', + isNegativeInteger: 'negative integer', isNegativeNumber: 'negative number', isNodeStream: 'Node.js Stream', isNonEmptyArray: 'non-empty array', @@ -42118,6 +42224,8 @@ const methodTypeMap = { isNonEmptySet: 'non-empty set', isNonEmptyString: 'non-empty string', isNonEmptyStringAndNotWhitespace: 'non-empty string and not whitespace', + isNonNegativeInteger: 'non-negative integer', + isNonNegativeNumber: 'non-negative number', isNull: 'null', isNullOrUndefined: 'null or undefined', isNumber: 'number', @@ -42126,12 +42234,13 @@ const methodTypeMap = { isObservable: 'Observable', isOddInteger: 'odd integer', isPlainObject: 'plain object', + isPositiveInteger: 'positive integer', isPositiveNumber: 'positive number', isPrimitive: 'primitive', isPromise: 'Promise', isPropertyKey: 'PropertyKey', isRegExp: 'RegExp', - isSafeInteger: 'integer', + isSafeInteger: 'safe integer', isSet: 'Set', isSharedArrayBuffer: 'SharedArrayBuffer', isString: 'string', @@ -42204,7 +42313,7 @@ function assertArrayLike(value, message) { throw new TypeError(message ?? typeErrorMessage('array-like', value)); } } -// eslint-disable-next-line @typescript-eslint/ban-types +// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type function assertAsyncFunction(value, message) { if (!isAsyncFunction(value)) { throw new TypeError(message ?? typeErrorMessage('AsyncFunction', value)); @@ -42250,10 +42359,10 @@ function assertBoolean(value, message) { throw new TypeError(message ?? typeErrorMessage('boolean', value)); } } -// eslint-disable-next-line @typescript-eslint/ban-types +// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type function assertBoundFunction(value, message) { if (!isBoundFunction(value)) { - throw new TypeError(message ?? typeErrorMessage('Function', value)); + throw new TypeError(message ?? typeErrorMessage('bound Function', value)); } } /** @@ -42334,6 +42443,11 @@ function assertFalsy(value, message) { throw new TypeError(message ?? typeErrorMessage('falsy', value)); } } +function assertFiniteNumber(value, message) { + if (!isFiniteNumber(value)) { + throw new TypeError(message ?? typeErrorMessage('finite number', value)); + } +} function assertFloat32Array(value, message) { if (!isFloat32Array(value)) { throw new TypeError(message ?? typeErrorMessage('Float32Array', value)); @@ -42349,7 +42463,7 @@ function assertFormData(value, message) { throw new TypeError(message ?? typeErrorMessage('FormData', value)); } } -// eslint-disable-next-line @typescript-eslint/ban-types +// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type function assertFunction(value, message) { if (!isFunction(value)) { throw new TypeError(message ?? typeErrorMessage('Function', value)); @@ -42420,6 +42534,11 @@ function assertNativePromise(value, message) { throw new TypeError(message ?? typeErrorMessage('native Promise', value)); } } +function assertNegativeInteger(value, message) { + if (!isNegativeInteger(value)) { + throw new TypeError(message ?? typeErrorMessage('negative integer', value)); + } +} function assertNegativeNumber(value, message) { if (!isNegativeNumber(value)) { throw new TypeError(message ?? typeErrorMessage('negative number', value)); @@ -42460,13 +42579,23 @@ function assertNonEmptyStringAndNotWhitespace(value, message) { throw new TypeError(message ?? typeErrorMessage('non-empty string and not whitespace', value)); } } -// eslint-disable-next-line @typescript-eslint/ban-types +function assertNonNegativeInteger(value, message) { + if (!isNonNegativeInteger(value)) { + throw new TypeError(message ?? typeErrorMessage('non-negative integer', value)); + } +} +function assertNonNegativeNumber(value, message) { + if (!isNonNegativeNumber(value)) { + throw new TypeError(message ?? typeErrorMessage('non-negative number', value)); + } +} +// eslint-disable-next-line @typescript-eslint/no-restricted-types function assertNull(value, message) { if (!isNull(value)) { throw new TypeError(message ?? typeErrorMessage('null', value)); } } -// eslint-disable-next-line @typescript-eslint/ban-types +// eslint-disable-next-line @typescript-eslint/no-restricted-types function assertNullOrUndefined(value, message) { if (!isNullOrUndefined(value)) { throw new TypeError(message ?? typeErrorMessage('null or undefined', value)); @@ -42482,7 +42611,7 @@ function assertNumericString(value, message) { throw new TypeError(message ?? typeErrorMessage('string with a number', value)); } } -// eslint-disable-next-line @typescript-eslint/ban-types +// eslint-disable-next-line @typescript-eslint/no-restricted-types function assertObject(value, message) { if (!isObject(value)) { throw new TypeError(message ?? typeErrorMessage('Object', value)); @@ -42503,6 +42632,11 @@ function assertPlainObject(value, message) { throw new TypeError(message ?? typeErrorMessage('plain object', value)); } } +function assertPositiveInteger(value, message) { + if (!isPositiveInteger(value)) { + throw new TypeError(message ?? typeErrorMessage('positive integer', value)); + } +} function assertPositiveNumber(value, message) { if (!isPositiveNumber(value)) { throw new TypeError(message ?? typeErrorMessage('positive number', value)); @@ -42530,7 +42664,7 @@ function assertRegExp(value, message) { } function assertSafeInteger(value, message) { if (!isSafeInteger(value)) { - throw new TypeError(message ?? typeErrorMessage('integer', value)); + throw new TypeError(message ?? typeErrorMessage('safe integer', value)); } } function assertSet(value, message) { @@ -42619,19 +42753,19 @@ function assertValidLength(value, message) { throw new TypeError(message ?? typeErrorMessage('valid length', value)); } } -// eslint-disable-next-line @typescript-eslint/ban-types +// eslint-disable-next-line @typescript-eslint/no-restricted-types function assertWeakMap(value, message) { if (!isWeakMap(value)) { throw new TypeError(message ?? typeErrorMessage('WeakMap', value)); } } -// eslint-disable-next-line @typescript-eslint/ban-types, unicorn/prevent-abbreviations +// eslint-disable-next-line @typescript-eslint/no-restricted-types function assertWeakRef(value, message) { if (!isWeakRef(value)) { throw new TypeError(message ?? typeErrorMessage('WeakRef', value)); } } -// eslint-disable-next-line @typescript-eslint/ban-types +// eslint-disable-next-line @typescript-eslint/no-restricted-types function assertWeakSet(value, message) { if (!isWeakSet(value)) { throw new TypeError(message ?? typeErrorMessage('WeakSet', value)); @@ -42646,129 +42780,20 @@ function assertWhitespaceString(value, message) { // EXTERNAL MODULE: external "node:events" var external_node_events_ = __nccwpck_require__(8474); -;// CONCATENATED MODULE: ./node_modules/p-cancelable/index.js -class CancelError extends Error { - constructor(reason) { - super(reason || 'Promise was canceled'); - this.name = 'CancelError'; - } - - get isCanceled() { - return true; - } -} - -const promiseState = Object.freeze({ - pending: Symbol('pending'), - canceled: Symbol('canceled'), - resolved: Symbol('resolved'), - rejected: Symbol('rejected'), -}); - -class PCancelable { - static fn(userFunction) { - return (...arguments_) => new PCancelable((resolve, reject, onCancel) => { - arguments_.push(onCancel); - userFunction(...arguments_).then(resolve, reject); - }); - } - - #cancelHandlers = []; - #rejectOnCancel = true; - #state = promiseState.pending; - #promise; - #reject; - - constructor(executor) { - this.#promise = new Promise((resolve, reject) => { - this.#reject = reject; - - const onResolve = value => { - if (this.#state !== promiseState.canceled || !onCancel.shouldReject) { - resolve(value); - this.#setState(promiseState.resolved); - } - }; - - const onReject = error => { - if (this.#state !== promiseState.canceled || !onCancel.shouldReject) { - reject(error); - this.#setState(promiseState.rejected); - } - }; - - const onCancel = handler => { - if (this.#state !== promiseState.pending) { - throw new Error(`The \`onCancel\` handler was attached after the promise ${this.#state.description}.`); - } - - this.#cancelHandlers.push(handler); - }; - - Object.defineProperties(onCancel, { - shouldReject: { - get: () => this.#rejectOnCancel, - set: boolean => { - this.#rejectOnCancel = boolean; - }, - }, - }); - - executor(onResolve, onReject, onCancel); - }); - } - - // eslint-disable-next-line unicorn/no-thenable - then(onFulfilled, onRejected) { - return this.#promise.then(onFulfilled, onRejected); - } - - catch(onRejected) { - return this.#promise.catch(onRejected); - } - - finally(onFinally) { - return this.#promise.finally(onFinally); - } - - cancel(reason) { - if (this.#state !== promiseState.pending) { - return; - } - - this.#setState(promiseState.canceled); - - if (this.#cancelHandlers.length > 0) { - try { - for (const handler of this.#cancelHandlers) { - handler(); - } - } catch (error) { - this.#reject(error); - return; - } - } - - if (this.#rejectOnCancel) { - this.#reject(new CancelError(reason)); - } - } - - get isCanceled() { - return this.#state === promiseState.canceled; - } - - #setState(state) { - if (this.#state === promiseState.pending) { - this.#state = state; - } - } +;// CONCATENATED MODULE: ./node_modules/got/dist/source/core/utils/strip-url-auth.js +/* +Returns the URL as a string with `username` and `password` stripped. +*/ +function stripUrlAuth(url) { + const sanitized = new URL(url); + sanitized.username = ''; + sanitized.password = ''; + return sanitized.toString(); } -Object.setPrototypeOf(PCancelable.prototype, Promise.prototype); - ;// CONCATENATED MODULE: ./node_modules/got/dist/source/core/errors.js + // A hacky check to prevent circular references. function isRequest(x) { return distribution.object(x) && '_onResponse' in x; @@ -42810,13 +42835,13 @@ class errors_RequestError extends Error { // Recover the original stacktrace if (distribution.string(error.stack) && distribution.string(this.stack)) { const indexOfMessage = this.stack.indexOf(this.message) + this.message.length; - const thisStackTrace = this.stack.slice(indexOfMessage).split('\n').reverse(); - const errorStackTrace = error.stack.slice(error.stack.indexOf(error.message) + error.message.length).split('\n').reverse(); + const thisStackTrace = this.stack.slice(indexOfMessage).split('\n').toReversed(); + const errorStackTrace = error.stack.slice(error.stack.indexOf(error.message) + error.message.length).split('\n').toReversed(); // Remove duplicated traces while (errorStackTrace.length > 0 && errorStackTrace[0] === thisStackTrace[0]) { thisStackTrace.shift(); } - this.stack = `${this.stack.slice(0, indexOfMessage)}${thisStackTrace.reverse().join('\n')}${errorStackTrace.reverse().join('\n')}`; + this.stack = `${this.stack.slice(0, indexOfMessage)}${thisStackTrace.toReversed().join('\n')}${errorStackTrace.toReversed().join('\n')}`; } } } @@ -42835,13 +42860,12 @@ class MaxRedirectsError extends errors_RequestError { An error to be thrown when the server response code is not 2xx nor 3xx if `options.followRedirect` is `true`, but always except for 304. Includes a `response` property. */ -// TODO: Change `HTTPError` to `HTTPError` in the next major version to enforce type usage. // eslint-disable-next-line @typescript-eslint/naming-convention class errors_HTTPError extends errors_RequestError { name = 'HTTPError'; code = 'ERR_NON_2XX_3XX_RESPONSE'; constructor(response) { - super(`Request failed with status code ${response.statusCode} (${response.statusMessage}): ${response.request.options.method} ${response.request.options.url.toString()}`, {}, response.request); + super(`Request failed with status code ${response.statusCode} (${response.statusMessage}): ${response.request.options.method} ${stripUrlAuth(response.request.options.url)}`, {}, response.request); } } /** @@ -42852,9 +42876,7 @@ class CacheError extends errors_RequestError { name = 'CacheError'; constructor(error, request) { super(error.message, error, request); - if (this.code === 'ERR_GOT_REQUEST_ERROR') { - this.code = 'ERR_CACHE_ACCESS'; - } + this.code = 'ERR_CACHE_ACCESS'; } } /** @@ -42864,9 +42886,7 @@ class UploadError extends errors_RequestError { name = 'UploadError'; constructor(error, request) { super(error.message, error, request); - if (this.code === 'ERR_GOT_REQUEST_ERROR') { - this.code = 'ERR_UPLOAD'; - } + this.code = 'ERR_UPLOAD'; } } /** @@ -42888,10 +42908,11 @@ An error to be thrown when reading from response stream fails. */ class ReadError extends errors_RequestError { name = 'ReadError'; + code = 'ERR_READING_RESPONSE_STREAM'; constructor(error, request) { super(error.message, error, request); - if (this.code === 'ERR_GOT_REQUEST_ERROR') { - this.code = 'ERR_READING_RESPONSE_STREAM'; + if (error.code === 'ECONNRESET' || error.code === 'ERR_HTTP_CONTENT_LENGTH_MISMATCH') { + this.code = error.code; } } } @@ -42939,162 +42960,635 @@ function byteLength(data) { return 0; } -// EXTERNAL MODULE: external "node:crypto" -var external_node_crypto_ = __nccwpck_require__(7598); -// EXTERNAL MODULE: external "node:url" -var external_node_url_ = __nccwpck_require__(3136); -;// CONCATENATED MODULE: ./node_modules/is-stream/index.js -function isStream(stream, {checkOpen = true} = {}) { - return stream !== null - && typeof stream === 'object' - && (stream.writable || stream.readable || !checkOpen || (stream.writable === undefined && stream.readable === undefined)) - && typeof stream.pipe === 'function'; -} +;// CONCATENATED MODULE: ./node_modules/chunk-data/index.js +const toUint8Array = data => (data instanceof Uint8Array + ? data + : new Uint8Array(data.buffer, data.byteOffset, data.byteLength)); -function isWritableStream(stream, {checkOpen = true} = {}) { - return isStream(stream, {checkOpen}) - && (stream.writable || !checkOpen) - && typeof stream.write === 'function' - && typeof stream.end === 'function' - && typeof stream.writable === 'boolean' - && typeof stream.writableObjectMode === 'boolean' - && typeof stream.destroy === 'function' - && typeof stream.destroyed === 'boolean'; -} +function * chunk(data, chunkSize) { + if (!ArrayBuffer.isView(data)) { + throw new TypeError('Expected data to be ArrayBufferView'); + } -function isReadableStream(stream, {checkOpen = true} = {}) { - return isStream(stream, {checkOpen}) - && (stream.readable || !checkOpen) - && typeof stream.read === 'function' - && typeof stream.readable === 'boolean' - && typeof stream.readableObjectMode === 'boolean' - && typeof stream.destroy === 'function' - && typeof stream.destroyed === 'boolean'; -} + if (!Number.isSafeInteger(chunkSize) || chunkSize <= 0) { + throw new TypeError('Expected chunkSize to be a positive integer'); + } -function isDuplexStream(stream, options) { - return isWritableStream(stream, options) - && isReadableStream(stream, options); -} + const uint8Array = toUint8Array(data); -function isTransformStream(stream, options) { - return isDuplexStream(stream, options) - && typeof stream._transform === 'function'; + for (let offset = 0; offset < uint8Array.length; offset += chunkSize) { + yield uint8Array.subarray(offset, offset + chunkSize); + } } -;// CONCATENATED MODULE: ./node_modules/@sec-ant/readable-stream/dist/ponyfill/asyncIterator.js -const a = Object.getPrototypeOf( - Object.getPrototypeOf( - /* istanbul ignore next */ - async function* () { - } - ).prototype -); -class c { - #t; - #n; - #r = !1; - #e = void 0; - constructor(e, t) { - this.#t = e, this.#n = t; - } - next() { - const e = () => this.#s(); - return this.#e = this.#e ? this.#e.then(e, e) : e(), this.#e; - } - return(e) { - const t = () => this.#i(e); - return this.#e ? this.#e.then(t, t) : t(); - } - async #s() { - if (this.#r) - return { - done: !0, - value: void 0 - }; - let e; - try { - e = await this.#t.read(); - } catch (t) { - throw this.#e = void 0, this.#r = !0, this.#t.releaseLock(), t; - } - return e.done && (this.#e = void 0, this.#r = !0, this.#t.releaseLock()), e; - } - async #i(e) { - if (this.#r) - return { - done: !0, - value: e - }; - if (this.#r = !0, !this.#n) { - const t = this.#t.cancel(e); - return this.#t.releaseLock(), await t, { - done: !0, - value: e - }; - } - return this.#t.releaseLock(), { - done: !0, - value: e - }; - } -} -const n = Symbol(); -function i() { - return this[n].next(); -} -Object.defineProperty(i, "name", { value: "next" }); -function o(r) { - return this[n].return(r); -} -Object.defineProperty(o, "name", { value: "return" }); -const u = Object.create(a, { - next: { - enumerable: !0, - configurable: !0, - writable: !0, - value: i - }, - return: { - enumerable: !0, - configurable: !0, - writable: !0, - value: o - } -}); -function h({ preventCancel: r = !1 } = {}) { - const e = this.getReader(), t = new c( - e, - r - ), s = Object.create(u); - return s[n] = t, s; -} +function * chunkFrom(iterable, chunkSize) { + if (typeof iterable?.[Symbol.iterator] !== 'function' || typeof iterable === 'string') { + throw new TypeError('Expected iterable to be an Iterable'); + } + if (!Number.isSafeInteger(chunkSize) || chunkSize <= 0) { + throw new TypeError('Expected chunkSize to be a positive integer'); + } -;// CONCATENATED MODULE: ./node_modules/@sec-ant/readable-stream/dist/ponyfill/index.js + let carryBuffer; + let carryLength = 0; + for (const part of iterable) { + if (!ArrayBuffer.isView(part)) { + throw new TypeError('Expected iterable chunks to be Uint8Array or ArrayBufferView'); + } + const buffer = toUint8Array(part); + // Skip empty buffers + if (buffer.length === 0) { + continue; + } -;// CONCATENATED MODULE: ./node_modules/get-stream/source/stream.js + let offset = 0; + + // Fill carry buffer to a full chunk if present + if (carryLength > 0) { + const needed = chunkSize - carryLength; + if (buffer.length >= needed) { + // Complete the chunk: merge carry + needed bytes from buffer + const out = new Uint8Array(chunkSize); + out.set(carryBuffer.subarray(0, carryLength), 0); + out.set(buffer.subarray(0, needed), carryLength); + yield out; + carryLength = 0; + offset = needed; + } else { + // Accumulate into fixed carry buffer (avoids O(n²) from repeated reallocations) + // Safe: buffer.length < needed implies carryLength + buffer.length < chunkSize + carryBuffer.set(buffer, carryLength); + carryLength += buffer.length; + continue; + } + } + // Emit direct slices from current buffer + for (; offset + chunkSize <= buffer.length; offset += chunkSize) { + yield buffer.subarray(offset, offset + chunkSize); + } + // Save remainder in carry buffer + if (offset < buffer.length) { + carryBuffer ||= new Uint8Array(chunkSize); -const getAsyncIterable = stream => { - if (isReadableStream(stream, {checkOpen: false}) && nodeImports.on !== undefined) { - return getStreamIterable(stream); + const remainder = buffer.length - offset; + carryBuffer.set(buffer.subarray(offset), 0); + carryLength = remainder; + } } - if (typeof stream?.[Symbol.asyncIterator] === 'function') { - return stream; + if (carryLength > 0) { + yield carryBuffer.subarray(0, carryLength); } +} - // `ReadableStream[Symbol.asyncIterator]` support is missing in multiple browsers, so we ponyfill it - if (stream_toString.call(stream) === '[object ReadableStream]') { - return h.call(stream); +async function * chunkFromAsync(iterable, chunkSize) { + if (typeof iterable?.[Symbol.asyncIterator] !== 'function' && typeof iterable?.[Symbol.iterator] !== 'function') { + throw new TypeError('Expected iterable to be an async iterable or iterable'); } - throw new TypeError('The first argument must be a Readable, a ReadableStream, or an async iterable.'); + if (!Number.isSafeInteger(chunkSize) || chunkSize <= 0) { + throw new TypeError('Expected chunkSize to be a positive integer'); + } + + let carryBuffer; + let carryLength = 0; + + for await (const part of iterable) { + if (!ArrayBuffer.isView(part)) { + throw new TypeError('Expected iterable chunks to be Uint8Array or ArrayBufferView'); + } + + const buffer = toUint8Array(part); + + // Skip empty buffers + if (buffer.length === 0) { + continue; + } + + let offset = 0; + + // Fill carry buffer to a full chunk if present + if (carryLength > 0) { + const needed = chunkSize - carryLength; + if (buffer.length >= needed) { + // Complete the chunk: merge carry + needed bytes from buffer + const out = new Uint8Array(chunkSize); + out.set(carryBuffer.subarray(0, carryLength), 0); + out.set(buffer.subarray(0, needed), carryLength); + yield out; + carryLength = 0; + offset = needed; + } else { + // Accumulate into fixed carry buffer (avoids O(n²) from repeated reallocations) + // Safe: buffer.length < needed implies carryLength + buffer.length < chunkSize + carryBuffer.set(buffer, carryLength); + carryLength += buffer.length; + continue; + } + } + + // Emit direct slices from current buffer + for (; offset + chunkSize <= buffer.length; offset += chunkSize) { + yield buffer.subarray(offset, offset + chunkSize); + } + + // Save remainder in carry buffer + if (offset < buffer.length) { + carryBuffer ||= new Uint8Array(chunkSize); + + const remainder = buffer.length - offset; + carryBuffer.set(buffer.subarray(offset), 0); + carryLength = remainder; + } + } + + if (carryLength > 0) { + yield carryBuffer.subarray(0, carryLength); + } +} + +;// CONCATENATED MODULE: ./node_modules/uint8array-extras/index.js +const objectToString = Object.prototype.toString; +const uint8ArrayStringified = '[object Uint8Array]'; +const arrayBufferStringified = '[object ArrayBuffer]'; + +function isType(value, typeConstructor, typeStringified) { + if (!value) { + return false; + } + + if (value.constructor === typeConstructor) { + return true; + } + + return objectToString.call(value) === typeStringified; +} + +function uint8array_extras_isUint8Array(value) { + return isType(value, Uint8Array, uint8ArrayStringified); +} + +function uint8array_extras_isArrayBuffer(value) { + return isType(value, ArrayBuffer, arrayBufferStringified); +} + +function isUint8ArrayOrArrayBuffer(value) { + return uint8array_extras_isUint8Array(value) || uint8array_extras_isArrayBuffer(value); +} + +function uint8array_extras_assertUint8Array(value) { + if (!uint8array_extras_isUint8Array(value)) { + throw new TypeError(`Expected \`Uint8Array\`, got \`${typeof value}\``); + } +} + +function assertUint8ArrayOrArrayBuffer(value) { + if (!isUint8ArrayOrArrayBuffer(value)) { + throw new TypeError(`Expected \`Uint8Array\` or \`ArrayBuffer\`, got \`${typeof value}\``); + } +} + +function uint8array_extras_toUint8Array(value) { + if (value instanceof ArrayBuffer) { + return new Uint8Array(value); + } + + if (ArrayBuffer.isView(value)) { + return new Uint8Array(value.buffer, value.byteOffset, value.byteLength); + } + + throw new TypeError(`Unsupported value, got \`${typeof value}\`.`); +} + +function concatUint8Arrays(arrays, totalLength) { + if (arrays.length === 0) { + return new Uint8Array(0); + } + + totalLength ??= arrays.reduce((accumulator, currentValue) => accumulator + currentValue.length, 0); + + const returnValue = new Uint8Array(totalLength); + + let offset = 0; + for (const array of arrays) { + uint8array_extras_assertUint8Array(array); + returnValue.set(array, offset); + offset += array.length; + } + + return returnValue; +} + +function areUint8ArraysEqual(a, b) { + uint8array_extras_assertUint8Array(a); + uint8array_extras_assertUint8Array(b); + + if (a === b) { + return true; + } + + if (a.length !== b.length) { + return false; + } + + // eslint-disable-next-line unicorn/no-for-loop + for (let index = 0; index < a.length; index++) { + if (a[index] !== b[index]) { + return false; + } + } + + return true; +} + +function compareUint8Arrays(a, b) { + uint8array_extras_assertUint8Array(a); + uint8array_extras_assertUint8Array(b); + + const length = Math.min(a.length, b.length); + + for (let index = 0; index < length; index++) { + const diff = a[index] - b[index]; + if (diff !== 0) { + return Math.sign(diff); + } + } + + // At this point, all the compared elements are equal. + // The shorter array should come first if the arrays are of different lengths. + return Math.sign(a.length - b.length); +} + +const cachedDecoders = { + utf8: new globalThis.TextDecoder('utf8'), +}; + +function uint8ArrayToString(array, encoding = 'utf8') { + assertUint8ArrayOrArrayBuffer(array); + cachedDecoders[encoding] ??= new globalThis.TextDecoder(encoding); + return cachedDecoders[encoding].decode(array); +} + +function uint8array_extras_assertString(value) { + if (typeof value !== 'string') { + throw new TypeError(`Expected \`string\`, got \`${typeof value}\``); + } +} + +const cachedEncoder = new globalThis.TextEncoder(); + +function stringToUint8Array(string) { + uint8array_extras_assertString(string); + return cachedEncoder.encode(string); +} + +function base64ToBase64Url(base64) { + return base64.replaceAll('+', '-').replaceAll('/', '_').replace(/=+$/, ''); +} + +function base64UrlToBase64(base64url) { + const base64 = base64url.replaceAll('-', '+').replaceAll('_', '/'); + const padding = (4 - (base64.length % 4)) % 4; + return base64 + '='.repeat(padding); +} + +// Reference: https://phuoc.ng/collection/this-vs-that/concat-vs-push/ +// Important: Keep this value divisible by 3 so intermediate chunks produce no Base64 padding. +const MAX_BLOCK_SIZE = 65_535; + +function uint8ArrayToBase64(array, {urlSafe = false} = {}) { + uint8array_extras_assertUint8Array(array); + + let base64 = ''; + + for (let index = 0; index < array.length; index += MAX_BLOCK_SIZE) { + const chunk = array.subarray(index, index + MAX_BLOCK_SIZE); + // Required as `btoa` and `atob` don't properly support Unicode: https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem + base64 += globalThis.btoa(String.fromCodePoint.apply(undefined, chunk)); + } + + return urlSafe ? base64ToBase64Url(base64) : base64; +} + +function base64ToUint8Array(base64String) { + uint8array_extras_assertString(base64String); + return Uint8Array.from(globalThis.atob(base64UrlToBase64(base64String)), x => x.codePointAt(0)); +} + +function stringToBase64(string, {urlSafe = false} = {}) { + uint8array_extras_assertString(string); + return uint8ArrayToBase64(stringToUint8Array(string), {urlSafe}); +} + +function base64ToString(base64String) { + uint8array_extras_assertString(base64String); + return uint8ArrayToString(base64ToUint8Array(base64String)); +} + +const byteToHexLookupTable = Array.from({length: 256}, (_, index) => index.toString(16).padStart(2, '0')); + +function uint8ArrayToHex(array) { + uint8array_extras_assertUint8Array(array); + + // Concatenating a string is faster than using an array. + let hexString = ''; + + // eslint-disable-next-line unicorn/no-for-loop -- Max performance is critical. + for (let index = 0; index < array.length; index++) { + hexString += byteToHexLookupTable[array[index]]; + } + + return hexString; +} + +const hexToDecimalLookupTable = { + 0: 0, + 1: 1, + 2: 2, + 3: 3, + 4: 4, + 5: 5, + 6: 6, + 7: 7, + 8: 8, + 9: 9, + a: 10, + b: 11, + c: 12, + d: 13, + e: 14, + f: 15, + A: 10, + B: 11, + C: 12, + D: 13, + E: 14, + F: 15, +}; + +function hexToUint8Array(hexString) { + uint8array_extras_assertString(hexString); + + if (hexString.length % 2 !== 0) { + throw new Error('Invalid Hex string length.'); + } + + const resultLength = hexString.length / 2; + const bytes = new Uint8Array(resultLength); + + for (let index = 0; index < resultLength; index++) { + const highNibble = hexToDecimalLookupTable[hexString[index * 2]]; + const lowNibble = hexToDecimalLookupTable[hexString[(index * 2) + 1]]; + + if (highNibble === undefined || lowNibble === undefined) { + throw new Error(`Invalid Hex character encountered at position ${index * 2}`); + } + + bytes[index] = (highNibble << 4) | lowNibble; // eslint-disable-line no-bitwise + } + + return bytes; +} + +/** +@param {DataView} view +@returns {number} +*/ +function getUintBE(view) { + const {byteLength} = view; + + if (byteLength === 6) { + return (view.getUint16(0) * (2 ** 32)) + view.getUint32(2); + } + + if (byteLength === 5) { + return (view.getUint8(0) * (2 ** 32)) + view.getUint32(1); + } + + if (byteLength === 4) { + return view.getUint32(0); + } + + if (byteLength === 3) { + return (view.getUint8(0) * (2 ** 16)) + view.getUint16(1); + } + + if (byteLength === 2) { + return view.getUint16(0); + } + + if (byteLength === 1) { + return view.getUint8(0); + } +} + +/** +@param {Uint8Array} array +@param {Uint8Array} value +@returns {number} +*/ +function indexOf(array, value) { + const arrayLength = array.length; + const valueLength = value.length; + + if (valueLength === 0) { + return -1; + } + + if (valueLength > arrayLength) { + return -1; + } + + const validOffsetLength = arrayLength - valueLength; + + for (let index = 0; index <= validOffsetLength; index++) { + let isMatch = true; + for (let index2 = 0; index2 < valueLength; index2++) { + if (array[index + index2] !== value[index2]) { + isMatch = false; + break; + } + } + + if (isMatch) { + return index; + } + } + + return -1; +} + +/** +@param {Uint8Array} array +@param {Uint8Array} value +@returns {boolean} +*/ +function includes(array, value) { + return indexOf(array, value) !== -1; +} + +// EXTERNAL MODULE: external "node:crypto" +var external_node_crypto_ = __nccwpck_require__(7598); +// EXTERNAL MODULE: external "node:url" +var external_node_url_ = __nccwpck_require__(3136); +;// CONCATENATED MODULE: ./node_modules/is-stream/index.js +function isStream(stream, {checkOpen = true} = {}) { + return stream !== null + && typeof stream === 'object' + && (stream.writable || stream.readable || !checkOpen || (stream.writable === undefined && stream.readable === undefined)) + && typeof stream.pipe === 'function'; +} + +function isWritableStream(stream, {checkOpen = true} = {}) { + return isStream(stream, {checkOpen}) + && (stream.writable || !checkOpen) + && typeof stream.write === 'function' + && typeof stream.end === 'function' + && typeof stream.writable === 'boolean' + && typeof stream.writableObjectMode === 'boolean' + && typeof stream.destroy === 'function' + && typeof stream.destroyed === 'boolean'; +} + +function isReadableStream(stream, {checkOpen = true} = {}) { + return isStream(stream, {checkOpen}) + && (stream.readable || !checkOpen) + && typeof stream.read === 'function' + && typeof stream.readable === 'boolean' + && typeof stream.readableObjectMode === 'boolean' + && typeof stream.destroy === 'function' + && typeof stream.destroyed === 'boolean'; +} + +function isDuplexStream(stream, options) { + return isWritableStream(stream, options) + && isReadableStream(stream, options); +} + +function isTransformStream(stream, options) { + return isDuplexStream(stream, options) + && typeof stream._transform === 'function'; +} + +;// CONCATENATED MODULE: ./node_modules/@sec-ant/readable-stream/dist/ponyfill/asyncIterator.js +const a = Object.getPrototypeOf( + Object.getPrototypeOf( + /* istanbul ignore next */ + async function* () { + } + ).prototype +); +class c { + #t; + #n; + #r = !1; + #e = void 0; + constructor(e, t) { + this.#t = e, this.#n = t; + } + next() { + const e = () => this.#s(); + return this.#e = this.#e ? this.#e.then(e, e) : e(), this.#e; + } + return(e) { + const t = () => this.#i(e); + return this.#e ? this.#e.then(t, t) : t(); + } + async #s() { + if (this.#r) + return { + done: !0, + value: void 0 + }; + let e; + try { + e = await this.#t.read(); + } catch (t) { + throw this.#e = void 0, this.#r = !0, this.#t.releaseLock(), t; + } + return e.done && (this.#e = void 0, this.#r = !0, this.#t.releaseLock()), e; + } + async #i(e) { + if (this.#r) + return { + done: !0, + value: e + }; + if (this.#r = !0, !this.#n) { + const t = this.#t.cancel(e); + return this.#t.releaseLock(), await t, { + done: !0, + value: e + }; + } + return this.#t.releaseLock(), { + done: !0, + value: e + }; + } +} +const n = Symbol(); +function i() { + return this[n].next(); +} +Object.defineProperty(i, "name", { value: "next" }); +function o(r) { + return this[n].return(r); +} +Object.defineProperty(o, "name", { value: "return" }); +const u = Object.create(a, { + next: { + enumerable: !0, + configurable: !0, + writable: !0, + value: i + }, + return: { + enumerable: !0, + configurable: !0, + writable: !0, + value: o + } +}); +function h({ preventCancel: r = !1 } = {}) { + const e = this.getReader(), t = new c( + e, + r + ), s = Object.create(u); + return s[n] = t, s; +} + + +;// CONCATENATED MODULE: ./node_modules/@sec-ant/readable-stream/dist/ponyfill/index.js + + + + +;// CONCATENATED MODULE: ./node_modules/get-stream/source/stream.js + + + +const getAsyncIterable = stream => { + if (isReadableStream(stream, {checkOpen: false}) && nodeImports.on !== undefined) { + return getStreamIterable(stream); + } + + if (typeof stream?.[Symbol.asyncIterator] === 'function') { + return stream; + } + + // `ReadableStream[Symbol.asyncIterator]` support is missing in multiple browsers, so we ponyfill it + if (stream_toString.call(stream) === '[object ReadableStream]') { + return h.call(stream); + } + + throw new TypeError('The first argument must be a Readable, a ReadableStream, or an async iterable.'); }; const {toString: stream_toString} = Object.prototype; @@ -43235,7 +43729,7 @@ const getChunkType = chunk => { return 'buffer'; } - const prototypeName = objectToString.call(chunk); + const prototypeName = contents_objectToString.call(chunk); if (prototypeName === '[object ArrayBuffer]') { return 'arrayBuffer'; @@ -43248,7 +43742,7 @@ const getChunkType = chunk => { if ( Number.isInteger(chunk.byteLength) && Number.isInteger(chunk.byteOffset) - && objectToString.call(chunk.buffer) === '[object ArrayBuffer]' + && contents_objectToString.call(chunk.buffer) === '[object ArrayBuffer]' ) { return 'typedArray'; } @@ -43256,7 +43750,7 @@ const getChunkType = chunk => { return 'others'; }; -const {toString: objectToString} = Object.prototype; +const {toString: contents_objectToString} = Object.prototype; class MaxBufferError extends Error { name = 'MaxBufferError'; @@ -44802,7 +45296,7 @@ function lowercase_keys_lowercaseKeys(object) { -class Response extends external_node_stream_.Readable { +class responselike_Response extends external_node_stream_.Readable { statusCode; headers; body; @@ -44989,7 +45483,7 @@ class CacheableRequest { headers[headerName] = originalHeaders[headerName]; } } - response = new Response({ + response = new responselike_Response({ statusCode: revalidate.statusCode, headers, body: revalidate.body, @@ -45089,7 +45583,7 @@ class CacheableRequest { const headers = convertHeaders(policy.responseHeaders()); const bodyBuffer = cacheEntry.body; const body = Buffer.from(bodyBuffer); - const response = new Response({ + const response = new responselike_Response({ statusCode: cacheEntry.statusCode, headers, body, @@ -45315,351 +45809,6 @@ function decompressResponse(response) { return finalStream; } -;// CONCATENATED MODULE: ./node_modules/form-data-encoder/lib/index.js -var __typeError = (msg) => { - throw TypeError(msg); -}; -var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg); -var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj)); -var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value); -var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value); -var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method); - -// src/util/chunk.ts -var MAX_CHUNK_SIZE = 65536; -function* chunk(value) { - if (value.byteLength <= MAX_CHUNK_SIZE) { - yield value; - return; - } - let offset = 0; - while (offset < value.byteLength) { - const size = Math.min(value.byteLength - offset, MAX_CHUNK_SIZE); - const buffer = value.buffer.slice(offset, offset + size); - offset += buffer.byteLength; - yield new Uint8Array(buffer); - } -} - -// src/util/createBoundary.ts -var alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; -function createBoundary() { - let size = 16; - let res = ""; - while (size--) { - res += alphabet[Math.random() * alphabet.length << 0]; - } - return res; -} - -// src/util/escapeName.ts -var escapeName = (name) => String(name).replace(/\r/g, "%0D").replace(/\n/g, "%0A").replace(/"/g, "%22"); - -// src/util/isFunction.ts -var lib_isFunction = (value) => typeof value === "function"; - -// src/util/isReadableStreamFallback.ts -var isReadableStreamFallback = (value) => !!value && typeof value === "object" && !Array.isArray(value) && lib_isFunction(value.getReader); - -// src/util/isAsyncIterable.ts -var lib_isAsyncIterable = (value) => lib_isFunction(value[Symbol.asyncIterator]); - -// src/util/getStreamIterator.ts -async function* readStream(readable) { - const reader = readable.getReader(); - while (true) { - const { done, value } = await reader.read(); - if (done) { - break; - } - yield value; - } -} -async function* chunkStream(stream) { - for await (const value of stream) { - yield* chunk(value); - } -} -var getStreamIterator = (source) => { - if (lib_isAsyncIterable(source)) { - return chunkStream(source); - } - if (isReadableStreamFallback(source)) { - return chunkStream(readStream(source)); - } - throw new TypeError( - "Unsupported data source: Expected either ReadableStream or async iterable." - ); -}; - -// src/util/isFile.ts -var isFile = (value) => Boolean( - value && typeof value === "object" && lib_isFunction(value.constructor) && value[Symbol.toStringTag] === "File" && lib_isFunction(value.stream) && value.name != null -); - -// src/util/isFormData.ts -var lib_isFormData = (value) => Boolean( - value && lib_isFunction(value.constructor) && value[Symbol.toStringTag] === "FormData" && lib_isFunction(value.append) && lib_isFunction(value.getAll) && lib_isFunction(value.entries) && lib_isFunction(value[Symbol.iterator]) -); - -// src/util/isPlainObject.ts -var getType = (value) => Object.prototype.toString.call(value).slice(8, -1).toLowerCase(); -function lib_isPlainObject(value) { - if (getType(value) !== "object") { - return false; - } - const pp = Object.getPrototypeOf(value); - if (pp === null || pp === void 0) { - return true; - } - return pp.constructor?.toString?.() === Object.toString(); -} - -// src/util/normalizeValue.ts -var normalizeValue = (value) => String(value).replace(/\r|\n/g, (match, i, str) => { - if (match === "\r" && str[i + 1] !== "\n" || match === "\n" && str[i - 1] !== "\r") { - return "\r\n"; - } - return match; -}); - -// src/util/proxyHeaders.ts -function getProperty(target, prop) { - if (typeof prop === "string") { - for (const [name, value] of Object.entries(target)) { - if (prop.toLowerCase() === name.toLowerCase()) { - return value; - } - } - } - return void 0; -} -var proxyHeaders = (object) => new Proxy( - object, - { - get: (target, prop) => getProperty(target, prop), - has: (target, prop) => getProperty(target, prop) !== void 0 - } -); - -// src/FormDataEncoder.ts -var defaultOptions = { - enableAdditionalHeaders: false -}; -var readonlyProp = { writable: false, configurable: false }; -var _CRLF, _CRLF_BYTES, _CRLF_BYTES_LENGTH, _DASHES, _encoder, _footer, _form, _options, _FormDataEncoder_instances, getFieldHeader_fn, getContentLength_fn; -var FormDataEncoder = class { - constructor(form, boundaryOrOptions, options) { - __privateAdd(this, _FormDataEncoder_instances); - __privateAdd(this, _CRLF, "\r\n"); - __privateAdd(this, _CRLF_BYTES); - __privateAdd(this, _CRLF_BYTES_LENGTH); - __privateAdd(this, _DASHES, "-".repeat(2)); - /** - * TextEncoder instance - */ - __privateAdd(this, _encoder, new TextEncoder()); - /** - * Returns form-data footer bytes - */ - __privateAdd(this, _footer); - /** - * FormData instance - */ - __privateAdd(this, _form); - /** - * Instance options - */ - __privateAdd(this, _options); - if (!lib_isFormData(form)) { - throw new TypeError("Expected first argument to be a FormData instance."); - } - let boundary; - if (lib_isPlainObject(boundaryOrOptions)) { - options = boundaryOrOptions; - } else { - boundary = boundaryOrOptions; - } - if (!boundary) { - boundary = `form-data-encoder-${createBoundary()}`; - } - if (typeof boundary !== "string") { - throw new TypeError("Expected boundary argument to be a string."); - } - if (options && !lib_isPlainObject(options)) { - throw new TypeError("Expected options argument to be an object."); - } - __privateSet(this, _form, Array.from(form.entries())); - __privateSet(this, _options, { ...defaultOptions, ...options }); - __privateSet(this, _CRLF_BYTES, __privateGet(this, _encoder).encode(__privateGet(this, _CRLF))); - __privateSet(this, _CRLF_BYTES_LENGTH, __privateGet(this, _CRLF_BYTES).byteLength); - this.boundary = boundary; - this.contentType = `multipart/form-data; boundary=${this.boundary}`; - __privateSet(this, _footer, __privateGet(this, _encoder).encode( - `${__privateGet(this, _DASHES)}${this.boundary}${__privateGet(this, _DASHES)}${__privateGet(this, _CRLF).repeat(2)}` - )); - const headers = { - "Content-Type": this.contentType - }; - const contentLength = __privateMethod(this, _FormDataEncoder_instances, getContentLength_fn).call(this); - if (contentLength) { - this.contentLength = contentLength; - headers["Content-Length"] = contentLength; - } - this.headers = proxyHeaders(Object.freeze(headers)); - Object.defineProperties(this, { - boundary: readonlyProp, - contentType: readonlyProp, - contentLength: readonlyProp, - headers: readonlyProp - }); - } - /** - * Creates an iterator allowing to go through form-data parts (with metadata). - * This method **will not** read the files and **will not** split values big into smaller chunks. - * - * Using this method, you can convert form-data content into Blob: - * - * @example - * - * ```ts - * import {Readable} from "stream" - * - * import {FormDataEncoder} from "form-data-encoder" - * - * import {FormData} from "formdata-polyfill/esm-min.js" - * import {fileFrom} from "fetch-blob/form.js" - * import {File} from "fetch-blob/file.js" - * import {Blob} from "fetch-blob" - * - * import fetch from "node-fetch" - * - * const form = new FormData() - * - * form.set("field", "Just a random string") - * form.set("file", new File(["Using files is class amazing"])) - * form.set("fileFromPath", await fileFrom("path/to/a/file.txt")) - * - * const encoder = new FormDataEncoder(form) - * - * const options = { - * method: "post", - * body: new Blob(encoder, {type: encoder.contentType}) - * } - * - * const response = await fetch("https://httpbin.org/post", options) - * - * console.log(await response.json()) - * ``` - */ - *values() { - for (const [name, raw] of __privateGet(this, _form)) { - const value = isFile(raw) ? raw : __privateGet(this, _encoder).encode(normalizeValue(raw)); - yield __privateMethod(this, _FormDataEncoder_instances, getFieldHeader_fn).call(this, name, value); - yield value; - yield __privateGet(this, _CRLF_BYTES); - } - yield __privateGet(this, _footer); - } - /** - * Creates an async iterator allowing to perform the encoding by portions. - * This method reads through files and splits big values into smaller pieces (65536 bytes per each). - * - * @example - * - * ```ts - * import {Readable} from "stream" - * - * import {FormData, File, fileFromPath} from "formdata-node" - * import {FormDataEncoder} from "form-data-encoder" - * - * import fetch from "node-fetch" - * - * const form = new FormData() - * - * form.set("field", "Just a random string") - * form.set("file", new File(["Using files is class amazing"], "file.txt")) - * form.set("fileFromPath", await fileFromPath("path/to/a/file.txt")) - * - * const encoder = new FormDataEncoder(form) - * - * const options = { - * method: "post", - * headers: encoder.headers, - * body: Readable.from(encoder.encode()) // or Readable.from(encoder) - * } - * - * const response = await fetch("https://httpbin.org/post", options) - * - * console.log(await response.json()) - * ``` - */ - async *encode() { - for (const part of this.values()) { - if (isFile(part)) { - yield* getStreamIterator(part.stream()); - } else { - yield* chunk(part); - } - } - } - /** - * Creates an iterator allowing to read through the encoder data using for...of loops - */ - [Symbol.iterator]() { - return this.values(); - } - /** - * Creates an **async** iterator allowing to read through the encoder data using for-await...of loops - */ - [Symbol.asyncIterator]() { - return this.encode(); - } -}; -_CRLF = new WeakMap(); -_CRLF_BYTES = new WeakMap(); -_CRLF_BYTES_LENGTH = new WeakMap(); -_DASHES = new WeakMap(); -_encoder = new WeakMap(); -_footer = new WeakMap(); -_form = new WeakMap(); -_options = new WeakMap(); -_FormDataEncoder_instances = new WeakSet(); -getFieldHeader_fn = function(name, value) { - let header = ""; - header += `${__privateGet(this, _DASHES)}${this.boundary}${__privateGet(this, _CRLF)}`; - header += `Content-Disposition: form-data; name="${escapeName(name)}"`; - if (isFile(value)) { - header += `; filename="${escapeName(value.name)}"${__privateGet(this, _CRLF)}`; - header += `Content-Type: ${value.type || "application/octet-stream"}`; - } - if (__privateGet(this, _options).enableAdditionalHeaders === true) { - const size = isFile(value) ? value.size : value.byteLength; - if (size != null && !isNaN(size)) { - header += `${__privateGet(this, _CRLF)}Content-Length: ${size}`; - } - } - return __privateGet(this, _encoder).encode(`${header}${__privateGet(this, _CRLF).repeat(2)}`); -}; -/** - * Returns form-data content length - */ -getContentLength_fn = function() { - let length = 0; - for (const [name, raw] of __privateGet(this, _form)) { - const value = isFile(raw) ? raw : __privateGet(this, _encoder).encode(normalizeValue(raw)); - const size = isFile(value) ? value.size : value.byteLength; - if (size == null || isNaN(size)) { - return void 0; - } - length += __privateMethod(this, _FormDataEncoder_instances, getFieldHeader_fn).call(this, name, value).byteLength; - length += size; - length += __privateGet(this, _CRLF_BYTES_LENGTH); - } - return String(length + __privateGet(this, _footer).byteLength); -}; - - // EXTERNAL MODULE: external "node:util" var external_node_util_ = __nccwpck_require__(7975); ;// CONCATENATED MODULE: ./node_modules/got/dist/source/core/utils/defer-to-connect.js @@ -45667,22 +45816,10 @@ function isTlsSocket(socket) { return 'encrypted' in socket; } const deferToConnect = (socket, fn) => { - let listeners; - if (typeof fn === 'function') { - const connect = fn; - listeners = { connect }; - } - else { - listeners = fn; - } - const hasConnectListener = typeof listeners.connect === 'function'; - const hasSecureConnectListener = typeof listeners.secureConnect === 'function'; - const hasCloseListener = typeof listeners.close === 'function'; + const listeners = typeof fn === 'function' ? { connect: fn } : fn; const onConnect = () => { - if (hasConnectListener) { - listeners.connect(); - } - if (isTlsSocket(socket) && hasSecureConnectListener) { + listeners.connect?.(); + if (isTlsSocket(socket) && listeners.secureConnect) { if (socket.authorized) { listeners.secureConnect(); } @@ -45691,7 +45828,7 @@ const deferToConnect = (socket, fn) => { socket.once('secureConnect', listeners.secureConnect); } } - if (hasCloseListener) { + if (listeners.close) { socket.once('close', listeners.close); } }; @@ -45701,7 +45838,7 @@ const deferToConnect = (socket, fn) => { else if (socket.connecting) { socket.once('connect', onConnect); } - else if (socket.destroyed && hasCloseListener) { + else if (socket.destroyed && listeners.close) { const hadError = '_hadError' in socket ? Boolean(socket._hadError) : false; listeners.close(hadError); } @@ -45712,6 +45849,10 @@ const deferToConnect = (socket, fn) => { +const getInitialConnectionTimings = (socket) => Reflect.get(socket, '__initial_connection_timings__'); +const setInitialConnectionTimings = (socket, timings) => { + Reflect.set(socket, '__initial_connection_timings__', timings); +}; const timer = (request) => { if (request.timings) { return request.timings; @@ -45769,11 +45910,12 @@ const timer = (request) => { // original connection so they're not lost. timings.lookup = timings.socket; timings.connect = timings.socket; - if (socket.__initial_connection_timings__) { + const initialConnectionTimings = getInitialConnectionTimings(socket); + if (initialConnectionTimings) { // Restore the phase timings from the initial connection - timings.phases.dns = socket.__initial_connection_timings__.dnsPhase; - timings.phases.tcp = socket.__initial_connection_timings__.tcpPhase; - timings.phases.tls = socket.__initial_connection_timings__.tlsPhase; + timings.phases.dns = initialConnectionTimings.dnsPhase; + timings.phases.tcp = initialConnectionTimings.tcpPhase; + timings.phases.tls = initialConnectionTimings.tlsPhase; // Set secureConnect timestamp if there was TLS if (timings.phases.tls !== undefined) { timings.secureConnect = timings.socket; @@ -45811,20 +45953,21 @@ const timer = (request) => { timings.phases.dns = 0; } // Store connection phase timings on socket for potential reuse - if (!socket.__initial_connection_timings__) { - socket.__initial_connection_timings__ = { + if (!getInitialConnectionTimings(socket)) { + setInitialConnectionTimings(socket, { dnsPhase: timings.phases.dns, // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- TypeScript can't prove this is defined due to callback structure tcpPhase: timings.phases.tcp, - }; + }); } }, secureConnect() { timings.secureConnect = Date.now(); timings.phases.tls = timings.secureConnect - timings.connect; // Update stored timings with TLS phase timing - if (socket.__initial_connection_timings__) { - socket.__initial_connection_timings__.tlsPhase = timings.phases.tls; + const initialConnectionTimings = getInitialConnectionTimings(socket); + if (initialConnectionTimings) { + initialConnectionTimings.tlsPhase = timings.phases.tls; } }, }); @@ -45872,17 +46015,10 @@ const timer = (request) => { }; /* harmony default export */ const utils_timer = (timer); -;// CONCATENATED MODULE: ./node_modules/got/dist/source/core/utils/is-form-data.js - -function is_form_data_isFormData(body) { - return distribution.nodeStream(body) && distribution.function(body.getBoundary); -} - ;// CONCATENATED MODULE: ./node_modules/got/dist/source/core/utils/get-body-size.js - -async function getBodySize(body, headers) { +function getBodySize(body, headers) { if (headers && 'content-length' in headers) { return Number(headers['content-length']); } @@ -45890,7 +46026,7 @@ async function getBodySize(body, headers) { return 0; } if (distribution.string(body)) { - return new TextEncoder().encode(body).byteLength; + return stringToUint8Array(body).byteLength; } if (distribution.buffer(body)) { return body.length; @@ -45898,37 +46034,21 @@ async function getBodySize(body, headers) { if (distribution.typedArray(body)) { return body.byteLength; } - if (is_form_data_isFormData(body)) { - try { - return await (0,external_node_util_.promisify)(body.getLength.bind(body))(); - } - catch (error) { - const typedError = error; - throw new Error('Cannot determine content-length for form-data with stream(s) of unknown length. ' - + 'This is a limitation of the `form-data` package. ' - + 'To fix this, either:\n' - + '1. Use the `knownLength` option when appending streams:\n' - + ' form.append(\'file\', stream, {knownLength: 12345});\n' - + '2. Switch to spec-compliant FormData (formdata-node package)\n' - + 'See: https://github.com/form-data/form-data#alternative-submission-methods\n' - + `Original error: ${typedError.message}`); - } - } return undefined; } ;// CONCATENATED MODULE: ./node_modules/got/dist/source/core/utils/proxy-events.js function proxyEvents(from, to, events) { - const eventFunctions = {}; + const eventFunctions = new Map(); for (const event of events) { const eventFunction = (...arguments_) => { to.emit(event, ...arguments_); }; - eventFunctions[event] = eventFunction; + eventFunctions.set(event, eventFunction); from.on(event, eventFunction); } return () => { - for (const [event, eventFunction] of Object.entries(eventFunctions)) { + for (const [event, eventFunction] of eventFunctions) { from.off(event, eventFunction); } }; @@ -45949,8 +46069,7 @@ function unhandle() { handlers.push({ origin, event, fn: function_ }); }, unhandleAll() { - for (const handler of handlers) { - const { origin, event, fn } = handler; + for (const { origin, event, fn } of handlers) { origin.removeListener(event, fn); } handlers.length = 0; @@ -45964,9 +46083,9 @@ function unhandle() { const reentry = Symbol('reentry'); const timed_out_noop = () => { }; class timed_out_TimeoutError extends Error { - event; name = 'TimeoutError'; code = 'ETIMEDOUT'; + event; constructor(threshold, event) { super(`Timeout awaiting '${event}' for ${threshold}ms`); this.event = event; @@ -45979,12 +46098,12 @@ function timedOut(request, delays, options) { request[reentry] = true; const cancelers = []; const { once, unhandleAll } = unhandle(); - const handled = new Map(); + const handled = new Set(); const addTimeout = (delay, callback, event) => { const timeout = setTimeout(callback, delay, delay, event); timeout.unref?.(); const cancel = () => { - handled.set(event, true); + handled.add(event); clearTimeout(timeout); }; cancelers.push(cancel); @@ -46042,7 +46161,7 @@ function timedOut(request, delays, options) { const { socketPath } = request; /* istanbul ignore next: hard to test */ if (socket.connecting) { - const hasPath = Boolean(socketPath ?? external_node_net_.isIP(hostname ?? host ?? '') !== 0); + const hasPath = Boolean(socketPath ?? (external_node_net_.isIP(hostname ?? host ?? '') !== 0)); if (hasLookup && !hasPath && socket.address().address === undefined) { const cancelTimeout = addTimeout(delays.lookup, timeoutHandler, 'lookup'); once(socket, 'lookup', cancelTimeout); @@ -46096,30 +46215,6 @@ function timedOut(request, delays, options) { return cancelTimeouts; } -;// CONCATENATED MODULE: ./node_modules/got/dist/source/core/utils/url-to-options.js - -function urlToOptions(url) { - // Cast to URL - url = url; - const options = { - protocol: url.protocol, - hostname: distribution.string(url.hostname) && url.hostname.startsWith('[') ? url.hostname.slice(1, -1) : url.hostname, - host: url.host, - hash: url.hash, - search: url.search, - pathname: url.pathname, - href: url.href, - path: `${url.pathname || ''}${url.search || ''}`, - }; - if (distribution.string(url.port) && url.port.length > 0) { - options.port = Number(url.port); - } - if (url.username || url.password) { - options.auth = `${url.username || ''}:${url.password || ''}`; - } - return options; -} - ;// CONCATENATED MODULE: ./node_modules/got/dist/source/core/utils/weakable-map.js class WeakableMap { weakMap = new WeakMap(); @@ -46163,10 +46258,7 @@ const calculateRetryDelay = ({ attemptCount, retryOptions, error, retryAfter, co if (error.response) { if (retryAfter) { // In this case `computedValue` is `options.request.timeout` - if (retryAfter > computedValue) { - return 0; - } - return retryAfter; + return retryAfter > computedValue ? 0 : retryAfter; } if (error.response.statusCode === 413) { return 0; @@ -46181,6 +46273,34 @@ const calculateRetryDelay = ({ attemptCount, retryOptions, error, retryAfter, co var external_node_tls_ = __nccwpck_require__(1692); ;// CONCATENATED MODULE: external "node:https" const external_node_https_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("node:https"); +;// CONCATENATED MODULE: ./node_modules/got/node_modules/lowercase-keys/index.js +function node_modules_lowercase_keys_lowercaseKeys(object, {onConflict} = {}) { + if (typeof object !== 'object' || object === null) { + throw new TypeError(`Expected an object, got ${object === null ? 'null' : typeof object}`); + } + + const result = {}; + + for (const [key, value] of Object.entries(object)) { + const lowercasedKey = key.toLowerCase(); + const hasExistingKey = Object.hasOwn(result, lowercasedKey); + const existingValue = hasExistingKey ? result[lowercasedKey] : undefined; + + const resolvedValue = onConflict && hasExistingKey + ? onConflict({key: lowercasedKey, newValue: value, existingValue}) + : value; + + Object.defineProperty(result, lowercasedKey, { + value: resolvedValue, + writable: true, + enumerable: true, + configurable: true, + }); + } + + return result; +} + // EXTERNAL MODULE: external "node:dns" var external_node_dns_ = __nccwpck_require__(610); ;// CONCATENATED MODULE: external "node:os" @@ -46636,12 +46756,59 @@ class CacheableLookup { // EXTERNAL MODULE: ./node_modules/http2-wrapper/source/index.js var source = __nccwpck_require__(4956); ;// CONCATENATED MODULE: ./node_modules/got/dist/source/core/parse-link-header.js +const splitHeaderValue = (value, separator) => { + const values = []; + let current = ''; + let inQuotes = false; + let inReference = false; + let isEscaped = false; + for (const character of value) { + if (inQuotes && isEscaped) { + current += character; + isEscaped = false; + continue; + } + if (inQuotes && character === '\\') { + current += character; + isEscaped = true; + continue; + } + if (character === '"') { + inQuotes = !inQuotes; + current += character; + continue; + } + if (!inQuotes && character === '<') { + inReference = true; + current += character; + continue; + } + if (!inQuotes && character === '>') { + inReference = false; + current += character; + continue; + } + // Link headers use both quoted strings and values, so raw + // splitting on `,` / `;` would break valid values containing those characters. + if (!inQuotes && !inReference && character === separator) { + values.push(current); + current = ''; + continue; + } + current += character; + } + if (inQuotes || isEscaped) { + throw new Error(`Failed to parse Link header: ${value}`); + } + values.push(current); + return values; +}; function parseLinkHeader(link) { const parsed = []; - const items = link.split(','); + const items = splitHeaderValue(link, ','); for (const item of items) { // https://tools.ietf.org/html/rfc5988#section-5 - const [rawUriReference, ...rawLinkParameters] = item.split(';'); + const [rawUriReference, ...rawLinkParameters] = splitHeaderValue(item, ';'); const trimmedUriReference = rawUriReference.trim(); // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with if (trimmedUriReference[0] !== '<' || trimmedUriReference.at(-1) !== '>') { @@ -46649,6 +46816,9 @@ function parseLinkHeader(link) { } const reference = trimmedUriReference.slice(1, -1); const parameters = {}; + if (reference.includes('<') || reference.includes('>')) { + throw new Error(`Invalid format of the Link header reference: ${trimmedUriReference}`); + } if (rawLinkParameters.length === 0) { throw new Error(`Unexpected end of Link header parameters: ${rawLinkParameters.join(';')}`); } @@ -46670,6 +46840,32 @@ function parseLinkHeader(link) { return parsed; } +;// CONCATENATED MODULE: ./node_modules/got/dist/source/core/utils/is-unix-socket-url.js +function isUnixSocketUrl(url) { + return url.protocol === 'unix:' || url.hostname === 'unix'; +} +/** +Extract the socket path from a UNIX socket URL. + +@example +``` +getUnixSocketPath(new URL('http://unix/foo:/path')); +//=> '/foo' + +getUnixSocketPath(new URL('unix:/foo:/path')); +//=> '/foo' + +getUnixSocketPath(new URL('http://example.com')); +//=> undefined +``` +*/ +function getUnixSocketPath(url) { + if (!isUnixSocketUrl(url)) { + return undefined; + } + return /^(?[^:]+):/v.exec(`${url.pathname}${url.search}`)?.groups?.socketPath; +} + ;// CONCATENATED MODULE: ./node_modules/got/dist/source/core/options.js @@ -46708,17 +46904,77 @@ function options_assertAny(optionName, validators, value) { }); } /** -Helper function that wraps assert.plainObject() to provide better error messages. -When assertion fails, it includes the option name in the error message. +Helper function that wraps assert.plainObject() to provide better error messages. +When assertion fails, it includes the option name in the error message. +*/ +function options_assertPlainObject(optionName, value) { + wrapAssertionWithContext(optionName, () => { + assert.plainObject(value); + }); +} +function isSameOrigin(previousUrl, nextUrl) { + return previousUrl.origin === nextUrl.origin + && getUnixSocketPath(previousUrl) === getUnixSocketPath(nextUrl); +} +const crossOriginStripHeaders = ['host', 'cookie', 'cookie2', 'authorization', 'proxy-authorization']; +const bodyHeaderNames = ['content-length', 'content-encoding', 'content-language', 'content-location', 'content-type', 'transfer-encoding']; +function usesUnixSocket(url) { + return url.protocol === 'unix:' || getUnixSocketPath(url) !== undefined; +} +function hasCredentialInUrl(url, credential) { + if (url instanceof URL) { + return url[credential] !== ''; + } + if (!distribution.string(url)) { + return false; + } + try { + return new URL(url)[credential] !== ''; + } + catch { + return false; + } +} +const hasExplicitCredentialInUrlChange = (changedState, url, credential) => (changedState.has(credential) + || (changedState.has('url') && url?.[credential] !== '')); +const hasProtocolSlashes = (value) => /^[a-z][\d+\-.a-z]*:\/\//iv.test(value); +const hasHttpProtocolWithoutSlashes = (value) => /^https?:(?!\/\/)/iv.test(value); +function applyUrlOverride(options, url, { username, password } = {}) { + if (distribution.string(url) && options.url) { + url = new URL(url, options.url).toString(); + } + options.prefixUrl = ''; + options.url = url; + if (username !== undefined) { + options.username = username; + } + if (password !== undefined) { + options.password = password; + } + return options.url; +} +function assertValidHeaderName(name) { + if (name.startsWith(':')) { + throw new TypeError(`HTTP/2 pseudo-headers are not supported in \`options.headers\`: ${name}`); + } +} +/** +Safely assign own properties from source to target, skipping `__proto__` to prevent prototype pollution from JSON.parse'd input. */ -function options_assertPlainObject(optionName, value) { - wrapAssertionWithContext(optionName, () => { - assert.plainObject(value); - }); +function safeObjectAssign(target, source) { + for (const [key, value] of Object.entries(source)) { + if (key === '__proto__') { + continue; + } + Reflect.set(target, key, value); + } } +const isToughCookieJar = (cookieJar) => cookieJar.setCookie.length === 4 && cookieJar.getCookieString.length === 0; function validateSearchParameters(searchParameters) { - // eslint-disable-next-line guard-for-in - for (const key in searchParameters) { + for (const key of Object.keys(searchParameters)) { + if (key === '__proto__') { + continue; + } const value = searchParameters[key]; options_assertAny(`searchParams.${key}`, [distribution.string, distribution.number, distribution.boolean, distribution.null, distribution.undefined], value); } @@ -46811,7 +47067,7 @@ const defaultInternals = { password: '', http2: false, allowGetBody: false, - copyPipedHeaders: true, + copyPipedHeaders: false, headers: { 'user-agent': 'got (https://github.com/sindresorhus/got)', }, @@ -46855,8 +47111,7 @@ const defaultInternals = { calculateDelay: ({ computedValue }) => computedValue, backoffLimit: Number.POSITIVE_INFINITY, noise: 100, - // TODO: Change default to `true` in the next major version to fix https://github.com/sindresorhus/got/issues/2243 - enforceRetryRules: false, + enforceRetryRules: true, }, localAddress: undefined, method: 'GET', @@ -46908,8 +47163,9 @@ const defaultInternals = { const parsed = parseLinkHeader(rawLinkHeader); const next = parsed.find(entry => entry.parameters.rel === 'next' || entry.parameters.rel === '"next"'); if (next) { + const baseUrl = response.request.options.url ?? response.url; return { - url: new URL(next.reference, response.url), + url: new URL(next.reference, baseUrl), }; } return false; @@ -46925,7 +47181,7 @@ const defaultInternals = { maxHeaderSize: undefined, signal: undefined, enableUnixSockets: false, - strictContentLength: false, + strictContentLength: true, }; const cloneInternals = (internals) => { const { hooks, retry } = internals; @@ -46958,27 +47214,24 @@ const cloneInternals = (internals) => { return result; }; const cloneRaw = (raw) => { - const { hooks, retry } = raw; const result = { ...raw }; - if (distribution.object(raw.context)) { + if (Object.hasOwn(raw, 'context') && distribution.object(raw.context)) { result.context = { ...raw.context }; } - if (distribution.object(raw.cacheOptions)) { + if (Object.hasOwn(raw, 'cacheOptions') && distribution.object(raw.cacheOptions)) { result.cacheOptions = { ...raw.cacheOptions }; } - if (distribution.object(raw.https)) { + if (Object.hasOwn(raw, 'https') && distribution.object(raw.https)) { result.https = { ...raw.https }; } - if (distribution.object(raw.cacheOptions)) { - result.cacheOptions = { ...result.cacheOptions }; - } - if (distribution.object(raw.agent)) { + if (Object.hasOwn(raw, 'agent') && distribution.object(raw.agent)) { result.agent = { ...raw.agent }; } - if (distribution.object(raw.headers)) { + if (Object.hasOwn(raw, 'headers') && distribution.object(raw.headers)) { result.headers = { ...raw.headers }; } - if (distribution.object(retry)) { + if (Object.hasOwn(raw, 'retry') && distribution.object(raw.retry)) { + const { retry } = raw; result.retry = { ...retry }; if (distribution.array(retry.errorCodes)) { result.retry.errorCodes = [...retry.errorCodes]; @@ -46990,10 +47243,11 @@ const cloneRaw = (raw) => { result.retry.statusCodes = [...retry.statusCodes]; } } - if (distribution.object(raw.timeout)) { + if (Object.hasOwn(raw, 'timeout') && distribution.object(raw.timeout)) { result.timeout = { ...raw.timeout }; } - if (distribution.object(hooks)) { + if (Object.hasOwn(raw, 'hooks') && distribution.object(raw.hooks)) { + const { hooks } = raw; result.hooks = { ...hooks, }; @@ -47019,7 +47273,7 @@ const cloneRaw = (raw) => { result.hooks.afterResponse = [...hooks.afterResponse]; } } - if (raw.searchParams) { + if (Object.hasOwn(raw, 'searchParams') && raw.searchParams) { if (distribution.string(raw.searchParams)) { result.searchParams = raw.searchParams; } @@ -47030,17 +47284,34 @@ const cloneRaw = (raw) => { result.searchParams = { ...raw.searchParams }; } } - if (distribution.object(raw.pagination)) { + if (Object.hasOwn(raw, 'pagination') && distribution.object(raw.pagination)) { result.pagination = { ...raw.pagination }; } return result; }; const getHttp2TimeoutOption = (internals) => { const delays = [internals.timeout.socket, internals.timeout.connect, internals.timeout.lookup, internals.timeout.request, internals.timeout.secureConnect].filter(delay => typeof delay === 'number'); - if (delays.length > 0) { - return Math.min(...delays); + return delays.length > 0 ? Math.min(...delays) : undefined; +}; +const trackStateMutation = (trackedStateMutations, name) => { + trackedStateMutations?.add(name); +}; +const addExplicitHeader = (explicitHeaders, name) => { + explicitHeaders.add(name); +}; +const markHeaderAsExplicit = (explicitHeaders, trackedStateMutations, name) => { + addExplicitHeader(explicitHeaders, name); + trackStateMutation(trackedStateMutations, name); +}; +const trackReplacedHeaderMutations = (trackedStateMutations, previousHeaders, nextHeaders) => { + if (!trackedStateMutations) { + return; + } + for (const header of new Set([...Object.keys(previousHeaders), ...Object.keys(nextHeaders)])) { + if (previousHeaders[header] !== nextHeaders[header]) { + trackStateMutation(trackedStateMutations, header); + } } - return undefined; }; const init = (options, withOptions, self) => { const initHooks = options.hooks?.init; @@ -47050,11 +47321,15 @@ const init = (options, withOptions, self) => { } } }; +// Keys never merged: got.extend() internals, url (passed as first arg), control flags, security +const nonMergeableKeys = new Set(['mutableDefaults', 'handlers', 'url', 'preserveHooks', 'isStream', '__proto__']); class Options { - _unixOptions; - _internals; - _merging = false; - _init; + #internals; + #headersProxy; + #merging = false; + #init; + #explicitHeaders; + #trackedStateMutations; constructor(input, options, defaults) { options_assertAny('input', [distribution.string, distribution.urlInstance, distribution.object, distribution.undefined], input); options_assertAny('options', [distribution.object, distribution.undefined], options); @@ -47062,8 +47337,17 @@ class Options { if (input instanceof Options || options instanceof Options) { throw new TypeError('The defaults must be passed as the third argument'); } - this._internals = cloneInternals(defaults?._internals ?? defaults ?? defaultInternals); - this._init = [...(defaults?._init ?? [])]; + if (defaults) { + this.#internals = cloneInternals(defaults.#internals); + this.#init = [...defaults.#init]; + this.#explicitHeaders = new Set(defaults.#explicitHeaders); + } + else { + this.#internals = cloneInternals(defaultInternals); + this.#init = []; + this.#explicitHeaders = new Set(); + } + this.#headersProxy = this.#createHeadersProxy(); // This rule allows `finally` to be considered more important. // Meaning no matter the error thrown in the `try` block, // if `finally` throws then the `finally` error will be thrown. @@ -47072,7 +47356,7 @@ class Options { // would get merged. Instead we set the `searchParams` first, then // `url.searchParams` is overwritten as expected. // - /* eslint-disable no-unsafe-finally */ + /* eslint-disable no-unsafe-finally -- `finally` is used intentionally here to ensure `url` is always set last, overwriting any merged searchParams */ try { if (distribution.plainObject(input)) { try { @@ -47113,9 +47397,9 @@ class Options { return; } if (options instanceof Options) { - // Create a copy of the _init array to avoid infinite loop + // Create a copy of the #init array to avoid infinite loop // when merging an Options instance with itself - const initArray = [...options._init]; + const initArray = [...options.#init]; for (const init of initArray) { this.merge(init); } @@ -47124,24 +47408,11 @@ class Options { options = cloneRaw(options); init(this, options, this); init(options, options, this); - this._merging = true; - // Always merge `isStream` first - if ('isStream' in options) { - this.isStream = options.isStream; - } + this.#merging = true; try { let push = false; - for (const key in options) { - // `got.extend()` options - if (key === 'mutableDefaults' || key === 'handlers') { - continue; - } - // Never merge `url` - if (key === 'url') { - continue; - } - // Never merge `preserveHooks` - it's a control flag, not a persistent option - if (key === 'preserveHooks') { + for (const key of Object.keys(options)) { + if (nonMergeableKeys.has(key)) { continue; } if (!(key in this)) { @@ -47157,11 +47428,11 @@ class Options { push = true; } if (push) { - this._init.push(options); + this.#init.push(options); } } finally { - this._merging = false; + this.#merging = false; } } /** @@ -47171,11 +47442,11 @@ class Options { @default http.request | https.request */ get request() { - return this._internals.request; + return this.#internals.request; } set request(value) { options_assertAny('request', [distribution.function, distribution.undefined], value); - this._internals.request = value; + this.#internals.request = value; } /** An object representing `http`, `https` and `http2` keys for [`http.Agent`](https://nodejs.org/api/http.html#http_class_http_agent), [`https.Agent`](https://nodejs.org/api/https.html#https_class_https_agent) and [`http2wrapper.Agent`](https://github.com/szmarczak/http2-wrapper#new-http2agentoptions) instance. @@ -47200,47 +47471,49 @@ class Options { ``` */ get agent() { - return this._internals.agent; + return this.#internals.agent; } set agent(value) { options_assertPlainObject('agent', value); - // eslint-disable-next-line guard-for-in - for (const key in value) { - if (!(key in this._internals.agent)) { + for (const key of Object.keys(value)) { + if (key === '__proto__') { + continue; + } + if (!(key in this.#internals.agent)) { throw new TypeError(`Unexpected agent option: ${key}`); } // @ts-expect-error - No idea why `value[key]` doesn't work here. options_assertAny(`agent.${key}`, [distribution.object, distribution.undefined, (v) => v === false], value[key]); } - if (this._merging) { - Object.assign(this._internals.agent, value); + if (this.#merging) { + safeObjectAssign(this.#internals.agent, value); } else { - this._internals.agent = { ...value }; + this.#internals.agent = { ...value }; } } get h2session() { - return this._internals.h2session; + return this.#internals.h2session; } set h2session(value) { - this._internals.h2session = value; + this.#internals.h2session = value; } /** Decompress the response automatically. This will set the `accept-encoding` header to `gzip, deflate, br` unless you set it yourself. - If this is disabled, a compressed response is returned as a `Buffer`. + If this is disabled, a compressed response is returned as a `Uint8Array`. This may be useful if you want to handle decompression yourself or stream the raw compressed data. @default true */ get decompress() { - return this._internals.decompress; + return this.#internals.decompress; } set decompress(value) { assert.boolean(value); - this._internals.decompress = value; + this.#internals.decompress = value; } /** Milliseconds to wait for the server to end the response before aborting the request with `got.TimeoutError` error (a.k.a. `request` property). @@ -47260,23 +47533,25 @@ class Options { get timeout() { // We always return `Delays` here. // It has to be `Delays | number`, otherwise TypeScript will error because the getter and the setter have incompatible types. - return this._internals.timeout; + return this.#internals.timeout; } set timeout(value) { options_assertPlainObject('timeout', value); - // eslint-disable-next-line guard-for-in - for (const key in value) { - if (!(key in this._internals.timeout)) { + for (const key of Object.keys(value)) { + if (key === '__proto__') { + continue; + } + if (!(key in this.#internals.timeout)) { throw new Error(`Unexpected timeout option: ${key}`); } // @ts-expect-error - No idea why `value[key]` doesn't work here. options_assertAny(`timeout.${key}`, [distribution.number, distribution.undefined], value[key]); } - if (this._merging) { - Object.assign(this._internals.timeout, value); + if (this.#merging) { + safeObjectAssign(this.#internals.timeout, value); } else { - this._internals.timeout = { ...value }; + this.#internals.timeout = { ...value }; } } /** @@ -47321,23 +47596,23 @@ class Options { get prefixUrl() { // We always return `string` here. // It has to be `string | URL`, otherwise TypeScript will error because the getter and the setter have incompatible types. - return this._internals.prefixUrl; + return this.#internals.prefixUrl; } set prefixUrl(value) { options_assertAny('prefixUrl', [distribution.string, distribution.urlInstance], value); if (value === '') { - this._internals.prefixUrl = ''; + this.#internals.prefixUrl = ''; return; } value = value.toString(); if (!value.endsWith('/')) { value += '/'; } - if (this._internals.prefixUrl && this._internals.url) { - const { href } = this._internals.url; - this._internals.url.href = value + href.slice(this._internals.prefixUrl.length); + if (this.#internals.prefixUrl && this.#internals.url) { + const { href } = this.#internals.url; + this.#internals.url.href = value + href.slice(this.#internals.prefixUrl.length); } - this._internals.prefixUrl = value; + this.#internals.prefixUrl = value; } /** __Note #1__: The `body` option cannot be used with the `json` or `form` option. @@ -47348,7 +47623,7 @@ class Options { __Note #4__: This option is not enumerable and will not be merged with the instance defaults. - The `content-length` header will be automatically set if `body` is a `string` / `Buffer` / typed array ([`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array), etc.) / [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) / [`form-data` instance](https://github.com/form-data/form-data), and `content-length` and `transfer-encoding` are not manually set in `options.headers`. + The `content-length` header will be automatically set if `body` is a `string` / `Uint8Array` / typed array, and `content-length` and `transfer-encoding` are not manually set in `options.headers`. Since Got 12, the `content-length` is not automatically set when `body` is a `fs.createReadStream`. @@ -47370,18 +47645,19 @@ class Options { ``` */ get body() { - return this._internals.body; + return this.#internals.body; } set body(value) { - options_assertAny('body', [distribution.string, distribution.buffer, distribution.nodeStream, distribution.generator, distribution.asyncGenerator, distribution.iterable, distribution.asyncIterable, lib_isFormData, distribution.typedArray, distribution.undefined], value); + options_assertAny('body', [distribution.string, distribution.buffer, distribution.nodeStream, distribution.generator, distribution.asyncGenerator, distribution.iterable, distribution.asyncIterable, distribution.typedArray, distribution.undefined], value); if (distribution.nodeStream(value)) { assert.truthy(value.readable); } if (value !== undefined) { - assert.undefined(this._internals.form); - assert.undefined(this._internals.json); + assert.undefined(this.#internals.form); + assert.undefined(this.#internals.json); } - this._internals.body = value; + this.#internals.body = value; + trackStateMutation(this.#trackedStateMutations, 'body'); } /** The form body is converted to a query string using [`(new URLSearchParams(object)).toString()`](https://nodejs.org/api/url.html#url_constructor_new_urlsearchparams_obj). @@ -47393,15 +47669,16 @@ class Options { __Note #2__: This option is not enumerable and will not be merged with the instance defaults. */ get form() { - return this._internals.form; + return this.#internals.form; } set form(value) { options_assertAny('form', [distribution.plainObject, distribution.undefined], value); if (value !== undefined) { - assert.undefined(this._internals.body); - assert.undefined(this._internals.json); + assert.undefined(this.#internals.body); + assert.undefined(this.#internals.json); } - this._internals.form = value; + this.#internals.form = value; + trackStateMutation(this.#trackedStateMutations, 'form'); } /** JSON request body. If the `content-type` header is not set, it will be set to `application/json`. @@ -47413,14 +47690,15 @@ class Options { __Note #2__: This option is not enumerable and will not be merged with the instance defaults. */ get json() { - return this._internals.json; + return this.#internals.json; } set json(value) { if (value !== undefined) { - assert.undefined(this._internals.body); - assert.undefined(this._internals.form); + assert.undefined(this.#internals.body); + assert.undefined(this.#internals.form); } - this._internals.json = value; + this.#internals.json = value; + trackStateMutation(this.#trackedStateMutations, 'json'); } /** The URL to request, as a string, a [`https.request` options object](https://nodejs.org/api/https.html#https_https_request_options_callback), or a [WHATWG `URL`](https://nodejs.org/api/url.html#url_class_url). @@ -47441,24 +47719,34 @@ class Options { ``` */ get url() { - return this._internals.url; + return this.#internals.url; } set url(value) { options_assertAny('url', [distribution.string, distribution.urlInstance, distribution.undefined], value); if (value === undefined) { - this._internals.url = undefined; + this.#internals.url = undefined; + trackStateMutation(this.#trackedStateMutations, 'url'); return; } if (distribution.string(value) && value.startsWith('/')) { throw new Error('`url` must not start with a slash'); } - // Detect if URL is already absolute (has a protocol/scheme) const valueString = value.toString(); - const isAbsolute = distribution.urlInstance(value) || /^[a-z][a-z\d+.-]*:\/\//i.test(valueString); + if (distribution.string(value) + && !this.prefixUrl + && hasHttpProtocolWithoutSlashes(valueString)) { + throw new Error('`url` protocol must be followed by `//`'); + } + // Detect if URL is already absolute (has a protocol/scheme) + const isAbsolute = distribution.urlInstance(value) || hasProtocolSlashes(valueString); // Only concatenate prefixUrl if the URL is relative const urlString = isAbsolute ? valueString : `${this.prefixUrl}${valueString}`; const url = new URL(urlString); - this._internals.url = url; + this.#internals.url = url; + trackStateMutation(this.#trackedStateMutations, 'url'); + if (usesUnixSocket(url) && !this.#internals.enableUnixSockets) { + throw new Error('Using UNIX domain sockets but option `enableUnixSockets` is not enabled'); + } if (url.protocol === 'unix:') { url.href = `http://unix${url.pathname}${url.search}`; } @@ -47467,37 +47755,18 @@ class Options { error.code = 'ERR_UNSUPPORTED_PROTOCOL'; throw error; } - if (this._internals.username) { - url.username = this._internals.username; - this._internals.username = ''; - } - if (this._internals.password) { - url.password = this._internals.password; - this._internals.password = ''; - } - if (this._internals.searchParams) { - url.search = this._internals.searchParams.toString(); - this._internals.searchParams = undefined; - } - if (url.hostname === 'unix') { - if (!this._internals.enableUnixSockets) { - throw new Error('Using UNIX domain sockets but option `enableUnixSockets` is not enabled'); - } - const matches = /(?.+?):(?.+)/.exec(`${url.pathname}${url.search}`); - if (matches?.groups) { - const { socketPath, path } = matches.groups; - this._unixOptions = { - socketPath, - path, - host: '', - }; - } - else { - this._unixOptions = undefined; - } - return; + if (this.#internals.username) { + url.username = this.#internals.username; + this.#internals.username = ''; + } + if (this.#internals.password) { + url.password = this.#internals.password; + this.#internals.password = ''; + } + if (this.#internals.searchParams) { + url.search = this.#internals.searchParams.toString(); + this.#internals.searchParams = undefined; } - this._unixOptions = undefined; } /** Cookie support. You don't have to care about parsing or how to store them. @@ -47505,28 +47774,26 @@ class Options { __Note__: If you provide this option, `options.headers.cookie` will be overridden. */ get cookieJar() { - return this._internals.cookieJar; + return this.#internals.cookieJar; } set cookieJar(value) { options_assertAny('cookieJar', [distribution.object, distribution.undefined], value); if (value === undefined) { - this._internals.cookieJar = undefined; + this.#internals.cookieJar = undefined; return; } - let { setCookie, getCookieString } = value; + const { setCookie, getCookieString } = value; assert.function(setCookie); assert.function(getCookieString); /* istanbul ignore next: Horrible `tough-cookie` v3 check */ - if (setCookie.length === 4 && getCookieString.length === 0) { - setCookie = (0,external_node_util_.promisify)(setCookie.bind(value)); - getCookieString = (0,external_node_util_.promisify)(getCookieString.bind(value)); - this._internals.cookieJar = { - setCookie, - getCookieString: getCookieString, + if (isToughCookieJar(value)) { + this.#internals.cookieJar = { + setCookie: (0,external_node_util_.promisify)(value.setCookie.bind(value)), + getCookieString: (0,external_node_util_.promisify)(value.getCookieString.bind(value)), }; } else { - this._internals.cookieJar = value; + this.#internals.cookieJar = value; } } /** @@ -47548,11 +47815,11 @@ class Options { ``` */ get signal() { - return this._internals.signal; + return this.#internals.signal; } set signal(value) { - assert.object(value); - this._internals.signal = value; + options_assertAny('signal', [distribution.object, distribution.undefined], value); + this.#internals.signal = value; } /** Ignore invalid cookies instead of throwing an error. @@ -47561,11 +47828,11 @@ class Options { @default false */ get ignoreInvalidCookies() { - return this._internals.ignoreInvalidCookies; + return this.#internals.ignoreInvalidCookies; } set ignoreInvalidCookies(value) { assert.boolean(value); - this._internals.ignoreInvalidCookies = value; + this.#internals.ignoreInvalidCookies = value; } /** Query string that will be added to the request URL. @@ -47586,19 +47853,17 @@ class Options { ``` */ get searchParams() { - if (this._internals.url) { - return this._internals.url.searchParams; + if (this.#internals.url) { + return this.#internals.url.searchParams; } - if (this._internals.searchParams === undefined) { - this._internals.searchParams = new URLSearchParams(); - } - return this._internals.searchParams; + this.#internals.searchParams ??= new URLSearchParams(); + return this.#internals.searchParams; } set searchParams(value) { options_assertAny('searchParams', [distribution.string, distribution.object, distribution.undefined], value); - const url = this._internals.url; + const url = this.#internals.url; if (value === undefined) { - this._internals.searchParams = undefined; + this.#internals.searchParams = undefined; if (url) { url.search = ''; } @@ -47615,8 +47880,10 @@ class Options { else { validateSearchParameters(value); updated = new URLSearchParams(); - // eslint-disable-next-line guard-for-in - for (const key in value) { + for (const key of Object.keys(value)) { + if (key === '__proto__') { + continue; + } const entry = value[key]; if (entry === null) { updated.append(key, ''); @@ -47629,7 +47896,7 @@ class Options { } } } - if (this._merging) { + if (this.#merging) { // These keys will be replaced for (const key of updated.keys()) { searchParameters.delete(key); @@ -47642,7 +47909,7 @@ class Options { url.search = searchParameters.toString(); } else { - this._internals.searchParams = searchParameters; + this.#internals.searchParams = searchParameters; } } get searchParameters() { @@ -47652,11 +47919,11 @@ class Options { throw new Error('The `searchParameters` option does not exist. Use `searchParams` instead.'); } get dnsLookup() { - return this._internals.dnsLookup; + return this.#internals.dnsLookup; } set dnsLookup(value) { options_assertAny('dnsLookup', [distribution.function, distribution.undefined], value); - this._internals.dnsLookup = value; + this.#internals.dnsLookup = value; } /** An instance of [`CacheableLookup`](https://github.com/szmarczak/cacheable-lookup) used for making DNS lookups. @@ -47669,18 +47936,18 @@ class Options { @default false */ get dnsCache() { - return this._internals.dnsCache; + return this.#internals.dnsCache; } set dnsCache(value) { options_assertAny('dnsCache', [distribution.object, distribution.boolean, distribution.undefined], value); if (value === true) { - this._internals.dnsCache = getGlobalDnsCache(); + this.#internals.dnsCache = getGlobalDnsCache(); } else if (value === false) { - this._internals.dnsCache = undefined; + this.#internals.dnsCache = undefined; } else { - this._internals.dnsCache = value; + this.#internals.dnsCache = value; } } /** @@ -47715,15 +47982,15 @@ class Options { ``` */ get context() { - return this._internals.context; + return this.#internals.context; } set context(value) { assert.object(value); - if (this._merging) { - Object.assign(this._internals.context, value); + if (this.#merging) { + safeObjectAssign(this.#internals.context, value); } else { - this._internals.context = { ...value }; + this.#internals.context = { ...value }; } } /** @@ -47731,13 +47998,15 @@ class Options { Hook functions may be async and are run serially. */ get hooks() { - return this._internals.hooks; + return this.#internals.hooks; } set hooks(value) { assert.object(value); - // eslint-disable-next-line guard-for-in - for (const knownHookEvent in value) { - if (!(knownHookEvent in this._internals.hooks)) { + for (const knownHookEvent of Object.keys(value)) { + if (knownHookEvent === '__proto__') { + continue; + } + if (!(knownHookEvent in this.#internals.hooks)) { throw new Error(`Unexpected hook event: ${knownHookEvent}`); } const typedKnownHookEvent = knownHookEvent; @@ -47748,10 +48017,10 @@ class Options { assert.function(hook); } } - if (this._merging) { + if (this.#merging) { if (hooks) { // @ts-expect-error FIXME - this._internals.hooks[typedKnownHookEvent].push(...hooks); + this.#internals.hooks[typedKnownHookEvent].push(...hooks); } } else { @@ -47759,7 +48028,7 @@ class Options { throw new Error(`Missing hook event: ${knownHookEvent}`); } // @ts-expect-error FIXME - this._internals.hooks[knownHookEvent] = [...hooks]; + this.#internals.hooks[knownHookEvent] = [...hooks]; } } } @@ -47770,15 +48039,16 @@ class Options { Note that if a `303` is sent by the server in response to any request type (`POST`, `DELETE`, etc.), Got will automatically request the resource pointed to in the location header via `GET`. This is in accordance with [the spec](https://tools.ietf.org/html/rfc7231#section-6.4.4). You can optionally turn on this behavior also for other redirect codes - see `methodRewriting`. + On cross-origin redirects, Got strips `host`, `cookie`, `cookie2`, `authorization`, and `proxy-authorization`. When a redirect rewrites the request to `GET`, Got also strips request body headers. Use `hooks.beforeRedirect` for app-specific sensitive headers. @default true */ get followRedirect() { - return this._internals.followRedirect; + return this.#internals.followRedirect; } set followRedirect(value) { options_assertAny('followRedirect', [distribution.boolean, distribution.function], value); - this._internals.followRedirect = value; + this.#internals.followRedirect = value; } get followRedirects() { throw new TypeError('The `followRedirects` option does not exist. Use `followRedirect` instead.'); @@ -47792,11 +48062,11 @@ class Options { @default 10 */ get maxRedirects() { - return this._internals.maxRedirects; + return this.#internals.maxRedirects; } set maxRedirects(value) { assert.number(value); - this._internals.maxRedirects = value; + this.#internals.maxRedirects = value; } /** A cache adapter instance for storing cached response data. @@ -47804,18 +48074,18 @@ class Options { @default false */ get cache() { - return this._internals.cache; + return this.#internals.cache; } set cache(value) { options_assertAny('cache', [distribution.object, distribution.string, distribution.boolean, distribution.undefined], value); if (value === true) { - this._internals.cache = globalCache; + this.#internals.cache = globalCache; } else if (value === false) { - this._internals.cache = undefined; + this.#internals.cache = undefined; } else { - this._internals.cache = wrapQuickLruIfNeeded(value); + this.#internals.cache = wrapQuickLruIfNeeded(value); } } /** @@ -47827,43 +48097,45 @@ class Options { @default true */ get throwHttpErrors() { - return this._internals.throwHttpErrors; + return this.#internals.throwHttpErrors; } set throwHttpErrors(value) { assert.boolean(value); - this._internals.throwHttpErrors = value; + this.#internals.throwHttpErrors = value; } get username() { - const url = this._internals.url; - const value = url ? url.username : this._internals.username; + const url = this.#internals.url; + const value = url ? url.username : this.#internals.username; return decodeURIComponent(value); } set username(value) { assert.string(value); - const url = this._internals.url; + const url = this.#internals.url; const fixedValue = encodeURIComponent(value); if (url) { url.username = fixedValue; } else { - this._internals.username = fixedValue; + this.#internals.username = fixedValue; } + trackStateMutation(this.#trackedStateMutations, 'username'); } get password() { - const url = this._internals.url; - const value = url ? url.password : this._internals.password; + const url = this.#internals.url; + const value = url ? url.password : this.#internals.password; return decodeURIComponent(value); } set password(value) { assert.string(value); - const url = this._internals.url; + const url = this.#internals.url; const fixedValue = encodeURIComponent(value); if (url) { url.password = fixedValue; } else { - this._internals.password = fixedValue; + this.#internals.password = fixedValue; } + trackStateMutation(this.#trackedStateMutations, 'password'); } /** If set to `true`, Got will additionally accept HTTP2 requests. @@ -47887,11 +48159,11 @@ class Options { ``` */ get http2() { - return this._internals.http2; + return this.#internals.http2; } set http2(value) { assert.boolean(value); - this._internals.http2 = value; + this.#internals.http2 = value; } /** Set this to `true` to allow sending body for the `GET` method. @@ -47903,36 +48175,35 @@ class Options { @default false */ get allowGetBody() { - return this._internals.allowGetBody; + return this.#internals.allowGetBody; } set allowGetBody(value) { assert.boolean(value); - this._internals.allowGetBody = value; + this.#internals.allowGetBody = value; } /** Automatically copy headers from piped streams. When piping a request into a Got stream (e.g., `request.pipe(got.stream(url))`), this controls whether headers from the source stream are automatically merged into the Got request headers. - Note: Piped headers overwrite any explicitly set headers with the same name. To override this, either set `copyPipedHeaders` to `false` and manually copy safe headers, or use a `beforeRequest` hook to force specific header values after piping. + Note: Explicitly set headers take precedence over piped headers. Piped headers are only copied when a header is not already explicitly set. - Useful for proxy scenarios, but you may want to disable this to filter out headers like `Host`, `Connection`, `Authorization`, etc. + Useful for proxy scenarios when explicitly enabled, but you may still want to filter out headers like `Host`, `Connection`, `Authorization`, etc. - @default true + @default false @example ``` import got from 'got'; import {pipeline} from 'node:stream/promises'; - // Disable automatic header copying and manually copy only safe headers + // Opt in to automatic header copying for proxy scenarios server.get('/proxy', async (request, response) => { const gotStream = got.stream('https://example.com', { - copyPipedHeaders: false, + copyPipedHeaders: true, + // Explicit headers win over piped headers headers: { - 'user-agent': request.headers['user-agent'], - 'accept': request.headers['accept'], - // Explicitly NOT copying host, connection, authorization, etc. + host: 'example.com', } }); @@ -47943,27 +48214,143 @@ class Options { @example ``` import got from 'got'; + import {pipeline} from 'node:stream/promises'; - // Override piped headers using beforeRequest hook - const gotStream = got.stream('https://example.com', { - hooks: { - beforeRequest: [ - options => { - // Force specific header values after piping - options.headers.host = 'example.com'; - delete options.headers.authorization; - } - ] - } + // Keep it disabled and manually copy only safe headers + server.get('/proxy', async (request, response) => { + const gotStream = got.stream('https://example.com', { + headers: { + 'user-agent': request.headers['user-agent'], + 'accept': request.headers['accept'], + // Explicitly NOT copying host, connection, authorization, etc. + } + }); + + await pipeline(request, gotStream, response); }); ``` */ get copyPipedHeaders() { - return this._internals.copyPipedHeaders; + return this.#internals.copyPipedHeaders; } set copyPipedHeaders(value) { assert.boolean(value); - this._internals.copyPipedHeaders = value; + this.#internals.copyPipedHeaders = value; + } + isHeaderExplicitlySet(name) { + return this.#explicitHeaders.has(name.toLowerCase()); + } + shouldCopyPipedHeader(name) { + return !this.isHeaderExplicitlySet(name); + } + setPipedHeader(name, value) { + assertValidHeaderName(name); + this.#internals.headers[name.toLowerCase()] = value; + } + getInternalHeaders() { + return this.#internals.headers; + } + setInternalHeader(name, value) { + assertValidHeaderName(name); + this.#internals.headers[name.toLowerCase()] = value; + } + deleteInternalHeader(name) { + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete this.#internals.headers[name.toLowerCase()]; + } + async trackStateMutations(operation) { + const changedState = new Set(); + this.#trackedStateMutations = changedState; + try { + return await operation(changedState); + } + finally { + this.#trackedStateMutations = undefined; + } + } + clearBody() { + this.body = undefined; + this.json = undefined; + this.form = undefined; + for (const header of bodyHeaderNames) { + this.deleteInternalHeader(header); + } + } + clearUnchangedCookieHeader(previousState, changedState) { + if (previousState?.hadCookieJar + && this.cookieJar === undefined + && !this.isHeaderExplicitlySet('cookie') + && !changedState?.has('cookie') + && this.headers.cookie === previousState.headers.cookie) { + this.deleteInternalHeader('cookie'); + } + } + restoreCookieHeader(previousState, headers) { + if (!previousState) { + return; + } + if (Object.hasOwn(headers ?? {}, 'cookie')) { + return; + } + if (previousState.cookieWasExplicitlySet) { + this.headers.cookie = previousState.headers.cookie; + return; + } + delete this.headers.cookie; + if (previousState.headers.cookie !== undefined) { + this.setInternalHeader('cookie', previousState.headers.cookie); + } + } + syncCookieHeaderAfterMerge(previousState, headers) { + this.restoreCookieHeader(previousState, headers); + this.clearUnchangedCookieHeader(previousState); + } + stripUnchangedCrossOriginState(previousState, changedState, { clearBody = true } = {}) { + const headers = this.getInternalHeaders(); + const url = this.#internals.url; + for (const header of crossOriginStripHeaders) { + if (!changedState.has(header) && headers[header] === previousState.headers[header]) { + this.deleteInternalHeader(header); + } + } + if (!hasExplicitCredentialInUrlChange(changedState, url, 'username')) { + this.username = ''; + } + if (!hasExplicitCredentialInUrlChange(changedState, url, 'password')) { + this.password = ''; + } + if (clearBody && !changedState.has('body') && !changedState.has('json') && !changedState.has('form') && isBodyUnchanged(this, previousState)) { + this.clearBody(); + } + } + /** + Strip sensitive headers and credentials when navigating to a different origin. + Headers and credentials explicitly provided in `userOptions` are preserved. + */ + stripSensitiveHeaders(previousUrl, nextUrl, userOptions) { + if (isSameOrigin(previousUrl, nextUrl)) { + return; + } + const headers = node_modules_lowercase_keys_lowercaseKeys(userOptions.headers ?? {}); + for (const header of crossOriginStripHeaders) { + if (headers[header] === undefined) { + this.deleteInternalHeader(header); + } + } + const explicitUsername = Object.hasOwn(userOptions, 'username') ? userOptions.username : undefined; + const explicitPassword = Object.hasOwn(userOptions, 'password') ? userOptions.password : undefined; + const hasExplicitUsername = explicitUsername !== undefined + || hasCredentialInUrl(userOptions.url, 'username') + || isCrossOriginCredentialChanged(previousUrl, nextUrl, 'username'); + const hasExplicitPassword = explicitPassword !== undefined + || hasCredentialInUrl(userOptions.url, 'password') + || isCrossOriginCredentialChanged(previousUrl, nextUrl, 'password'); + if (!hasExplicitUsername && this.username) { + this.username = ''; + } + if (!hasExplicitPassword && this.password) { + this.password = ''; + } } /** Request headers. @@ -47973,33 +48360,49 @@ class Options { @default {} */ get headers() { - return this._internals.headers; + return this.#headersProxy; } set headers(value) { options_assertPlainObject('headers', value); - if (this._merging) { - Object.assign(this._internals.headers, lowercase_keys_lowercaseKeys(value)); + const normalizedHeaders = node_modules_lowercase_keys_lowercaseKeys(value); + for (const header of Object.keys(normalizedHeaders)) { + assertValidHeaderName(header); + } + if (this.#merging) { + safeObjectAssign(this.#internals.headers, normalizedHeaders); } else { - this._internals.headers = lowercase_keys_lowercaseKeys(value); + const previousHeaders = this.#internals.headers; + this.#internals.headers = normalizedHeaders; + this.#headersProxy = this.#createHeadersProxy(); + this.#explicitHeaders.clear(); + trackReplacedHeaderMutations(this.#trackedStateMutations, previousHeaders, normalizedHeaders); + } + for (const header of Object.keys(normalizedHeaders)) { + if (this.#merging) { + markHeaderAsExplicit(this.#explicitHeaders, this.#trackedStateMutations, header); + } + else { + addExplicitHeader(this.#explicitHeaders, header); + } } } /** Specifies if the HTTP request method should be [rewritten as `GET`](https://tools.ietf.org/html/rfc7231#section-6.4) on redirects. - As the [specification](https://tools.ietf.org/html/rfc7231#section-6.4) prefers to rewrite the HTTP method only on `303` responses, this is Got's default behavior. - Setting `methodRewriting` to `true` will also rewrite `301` and `302` responses, as allowed by the spec. This is the behavior followed by `curl` and browsers. + As the [specification](https://tools.ietf.org/html/rfc7231#section-6.4) prefers to rewrite the HTTP method only on `303` responses, this is Got's default behavior. Cross-origin `301` and `302` redirects also rewrite `POST` requests to `GET` by default to avoid forwarding request bodies to another origin. + Setting `methodRewriting` to `true` will also rewrite same-origin `301` and `302` responses, as allowed by the spec. This is the behavior followed by `curl` and browsers. __Note__: Got never performs method rewriting on `307` and `308` responses, as this is [explicitly prohibited by the specification](https://www.rfc-editor.org/rfc/rfc7231#section-6.4.7). @default false */ get methodRewriting() { - return this._internals.methodRewriting; + return this.#internals.methodRewriting; } set methodRewriting(value) { assert.boolean(value); - this._internals.methodRewriting = value; + this.#internals.methodRewriting = value; } /** Indicates which DNS record family to use. @@ -48012,13 +48415,13 @@ class Options { @default undefined */ get dnsLookupIpVersion() { - return this._internals.dnsLookupIpVersion; + return this.#internals.dnsLookupIpVersion; } set dnsLookupIpVersion(value) { if (value !== undefined && value !== 4 && value !== 6) { throw new TypeError(`Invalid DNS lookup IP version: ${value}`); } - this._internals.dnsLookupIpVersion = value; + this.#internals.dnsLookupIpVersion = value; } /** A function used to parse JSON responses. @@ -48036,11 +48439,11 @@ class Options { ``` */ get parseJson() { - return this._internals.parseJson; + return this.#internals.parseJson; } set parseJson(value) { assert.function(value); - this._internals.parseJson = value; + this.#internals.parseJson = value; } /** A function used to stringify the body of JSON requests. @@ -48084,11 +48487,11 @@ class Options { ``` */ get stringifyJson() { - return this._internals.stringifyJson; + return this.#internals.stringifyJson; } set stringifyJson(value) { assert.function(value); - this._internals.stringifyJson = value; + this.#internals.stringifyJson = value; } /** An object representing `limit`, `calculateDelay`, `methods`, `statusCodes`, `maxRetryAfter` and `errorCodes` fields for maximum retry count, retry handler, allowed methods, allowed status codes, maximum [`Retry-After`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After) time and allowed error codes. @@ -48098,9 +48501,9 @@ class Options { The `calculateDelay` property is a `function` that receives an object with `attemptCount`, `retryOptions`, `error` and `computedValue` properties for current retry count, the retry options, error and default computed value. The function must return a delay in milliseconds (or a Promise resolving with it) (`0` return value cancels retry). - The `enforceRetryRules` property is a `boolean` that, when set to `true`, enforces the `limit`, `methods`, `statusCodes`, and `errorCodes` options before calling `calculateDelay`. Your `calculateDelay` function is only invoked when a retry is allowed based on these criteria. When `false` (default), `calculateDelay` receives the computed value but can override all retry logic. + The `enforceRetryRules` property is a `boolean` that, when set to `true` (default), enforces the `limit`, `methods`, `statusCodes`, and `errorCodes` options before calling `calculateDelay`. Your `calculateDelay` function is only invoked when a retry is allowed based on these criteria. When `false`, `calculateDelay` receives the computed value but can override all retry logic. - __Note:__ When `enforceRetryRules` is `false`, you must check `computedValue` in your `calculateDelay` function to respect the default retry logic. When `true`, the retry rules are enforced automatically. + __Note:__ When `enforceRetryRules` is `false`, you must check `computedValue` in your `calculateDelay` function to respect retry rules. When `true` (default), the retry rules are enforced automatically. By default, it retries *only* on the specified methods, status codes, and on these network errors: @@ -48117,7 +48520,7 @@ class Options { __Note__: If [`Retry-After`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After) header is greater than `maxRetryAfter`, it will cancel the request. */ get retry() { - return this._internals.retry; + return this.#internals.retry; } set retry(value) { options_assertPlainObject('retry', value); @@ -48132,18 +48535,21 @@ class Options { if (value.noise && Math.abs(value.noise) > 100) { throw new Error(`The maximum acceptable retry noise is +/- 100ms, got ${value.noise}`); } - for (const key in value) { - if (!(key in this._internals.retry)) { + for (const key of Object.keys(value)) { + if (key === '__proto__') { + continue; + } + if (!(key in this.#internals.retry)) { throw new Error(`Unexpected retry option: ${key}`); } } - if (this._merging) { - Object.assign(this._internals.retry, value); + if (this.#merging) { + safeObjectAssign(this.#internals.retry, value); } else { - this._internals.retry = { ...value }; + this.#internals.retry = { ...value }; } - const { retry } = this._internals; + const { retry } = this.#internals; retry.methods = [...new Set(retry.methods.map(method => method.toUpperCase()))]; retry.statusCodes = [...new Set(retry.statusCodes)]; retry.errorCodes = [...new Set(retry.errorCodes)]; @@ -48154,11 +48560,11 @@ class Options { The IP address used to send the request from. */ get localAddress() { - return this._internals.localAddress; + return this.#internals.localAddress; } set localAddress(value) { options_assertAny('localAddress', [distribution.string, distribution.undefined], value); - this._internals.localAddress = value; + this.#internals.localAddress = value; } /** The HTTP method used to make the request. @@ -48166,18 +48572,18 @@ class Options { @default 'GET' */ get method() { - return this._internals.method; + return this.#internals.method; } set method(value) { assert.string(value); - this._internals.method = value.toUpperCase(); + this.#internals.method = value.toUpperCase(); } get createConnection() { - return this._internals.createConnection; + return this.#internals.createConnection; } set createConnection(value) { options_assertAny('createConnection', [distribution.function, distribution.undefined], value); - this._internals.createConnection = value; + this.#internals.createConnection = value; } /** From `http-cache-semantics` @@ -48185,7 +48591,7 @@ class Options { @default {} */ get cacheOptions() { - return this._internals.cacheOptions; + return this.#internals.cacheOptions; } set cacheOptions(value) { options_assertPlainObject('cacheOptions', value); @@ -48193,23 +48599,26 @@ class Options { options_assertAny('cacheOptions.cacheHeuristic', [distribution.number, distribution.undefined], value.cacheHeuristic); options_assertAny('cacheOptions.immutableMinTimeToLive', [distribution.number, distribution.undefined], value.immutableMinTimeToLive); options_assertAny('cacheOptions.ignoreCargoCult', [distribution.boolean, distribution.undefined], value.ignoreCargoCult); - for (const key in value) { - if (!(key in this._internals.cacheOptions)) { + for (const key of Object.keys(value)) { + if (key === '__proto__') { + continue; + } + if (!(key in this.#internals.cacheOptions)) { throw new Error(`Cache option \`${key}\` does not exist`); } } - if (this._merging) { - Object.assign(this._internals.cacheOptions, value); + if (this.#merging) { + safeObjectAssign(this.#internals.cacheOptions, value); } else { - this._internals.cacheOptions = { ...value }; + this.#internals.cacheOptions = { ...value }; } } /** Options for the advanced HTTPS API. */ get https() { - return this._internals.https; + return this.#internals.https; } set https(value) { options_assertPlainObject('https', value); @@ -48232,22 +48641,25 @@ class Options { options_assertAny('https.ecdhCurve', [distribution.string, distribution.undefined], value.ecdhCurve); options_assertAny('https.certificateRevocationLists', [distribution.string, distribution.buffer, distribution.array, distribution.undefined], value.certificateRevocationLists); options_assertAny('https.secureOptions', [distribution.number, distribution.undefined], value.secureOptions); - for (const key in value) { - if (!(key in this._internals.https)) { + for (const key of Object.keys(value)) { + if (key === '__proto__') { + continue; + } + if (!(key in this.#internals.https)) { throw new Error(`HTTPS option \`${key}\` does not exist`); } } - if (this._merging) { - Object.assign(this._internals.https, value); + if (this.#merging) { + safeObjectAssign(this.#internals.https, value); } else { - this._internals.https = { ...value }; + this.#internals.https = { ...value }; } } /** [Encoding](https://nodejs.org/api/buffer.html#buffer_buffers_and_character_encodings) to be used on `setEncoding` of the response data. - To get a [`Buffer`](https://nodejs.org/api/buffer.html), you need to set `responseType` to `buffer` instead. + To get a [`Uint8Array`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array), you need to set `responseType` to `buffer` instead. Don't set this option to `null`. __Note__: This doesn't affect streams! Instead, you need to do `got.stream(...).setEncoding(encoding)`. @@ -48255,14 +48667,14 @@ class Options { @default 'utf-8' */ get encoding() { - return this._internals.encoding; + return this.#internals.encoding; } set encoding(value) { if (value === null) { - throw new TypeError('To get a Buffer, set `options.responseType` to `buffer` instead'); + throw new TypeError('To get a Uint8Array, set `options.responseType` to `buffer` instead'); } options_assertAny('encoding', [distribution.string, distribution.undefined], value); - this._internals.encoding = value; + this.#internals.encoding = value; } /** When set to `true` the promise will return the Response body instead of the Response object. @@ -48270,24 +48682,25 @@ class Options { @default false */ get resolveBodyOnly() { - return this._internals.resolveBodyOnly; + return this.#internals.resolveBodyOnly; } set resolveBodyOnly(value) { assert.boolean(value); - this._internals.resolveBodyOnly = value; + this.#internals.resolveBodyOnly = value; } /** Returns a `Stream` instead of a `Promise`. - This is equivalent to calling `got.stream(url, options?)`. + Set internally by `got.stream()`. @default false + @internal */ get isStream() { - return this._internals.isStream; + return this.#internals.isStream; } set isStream(value) { assert.boolean(value); - this._internals.isStream = value; + this.#internals.isStream = value; } /** The parsing method. @@ -48306,7 +48719,7 @@ class Options { const [response, buffer, json] = Promise.all([responsePromise, bufferPromise, jsonPromise]); // `response` is an instance of Got Response - // `buffer` is an instance of Buffer + // `buffer` is an instance of Uint8Array // `json` is an object ``` @@ -48320,28 +48733,28 @@ class Options { ``` */ get responseType() { - return this._internals.responseType; + return this.#internals.responseType; } set responseType(value) { if (value === undefined) { - this._internals.responseType = 'text'; + this.#internals.responseType = 'text'; return; } if (value !== 'text' && value !== 'buffer' && value !== 'json') { throw new Error(`Invalid \`responseType\` option: ${value}`); } - this._internals.responseType = value; + this.#internals.responseType = value; } get pagination() { - return this._internals.pagination; + return this.#internals.pagination; } set pagination(value) { assert.object(value); - if (this._merging) { - Object.assign(this._internals.pagination, value); + if (this.#merging) { + safeObjectAssign(this.#internals.pagination, value); } else { - this._internals.pagination = value; + this.#internals.pagination = value; } } get auth() { @@ -48351,25 +48764,25 @@ class Options { throw new Error('Parameter `auth` is deprecated. Use `username` / `password` instead.'); } get setHost() { - return this._internals.setHost; + return this.#internals.setHost; } set setHost(value) { assert.boolean(value); - this._internals.setHost = value; + this.#internals.setHost = value; } get maxHeaderSize() { - return this._internals.maxHeaderSize; + return this.#internals.maxHeaderSize; } set maxHeaderSize(value) { options_assertAny('maxHeaderSize', [distribution.number, distribution.undefined], value); - this._internals.maxHeaderSize = value; + this.#internals.maxHeaderSize = value; } get enableUnixSockets() { - return this._internals.enableUnixSockets; + return this.#internals.enableUnixSockets; } set enableUnixSockets(value) { assert.boolean(value); - this._internals.enableUnixSockets = value; + this.#internals.enableUnixSockets = value; } /** Throw an error if the server response's `content-length` header value doesn't match the number of bytes received. @@ -48379,24 +48792,24 @@ class Options { __Note__: Responses without a `content-length` header are not validated. __Note__: When enabled and validation fails, a `ReadError` with code `ERR_HTTP_CONTENT_LENGTH_MISMATCH` will be thrown. - @default false + @default true */ get strictContentLength() { - return this._internals.strictContentLength; + return this.#internals.strictContentLength; } set strictContentLength(value) { assert.boolean(value); - this._internals.strictContentLength = value; + this.#internals.strictContentLength = value; } // eslint-disable-next-line @typescript-eslint/naming-convention toJSON() { - return { ...this._internals }; + return { ...this.#internals }; } [Symbol.for('nodejs.util.inspect.custom')](_depth, options) { - return (0,external_node_util_.inspect)(this._internals, options); + return (0,external_node_util_.inspect)(this.#internals, options); } createNativeRequestOptions() { - const internals = this._internals; + const internals = this.#internals; const url = internals.url; let agent; if (url.protocol === 'https:') { @@ -48423,9 +48836,20 @@ class Options { passphrase: object.passphrase, })); } + const unixSocketPath = getUnixSocketPath(url); + if (usesUnixSocket(url) && !internals.enableUnixSockets) { + throw new Error('Using UNIX domain sockets but option `enableUnixSockets` is not enabled'); + } + let unixSocketGroups; + if (unixSocketPath !== undefined) { + unixSocketGroups = /^(?[^:]+):(?.+)$/v.exec(`${url.pathname}${url.search}`)?.groups; + } + const unixOptions = unixSocketGroups + ? { socketPath: unixSocketGroups.socketPath, path: unixSocketGroups.path, host: '' } + : undefined; return { ...internals.cacheOptions, - ...this._unixOptions, + ...unixOptions, // HTTPS options // eslint-disable-next-line @typescript-eslint/naming-convention ALPNProtocols: https.alpnProtocols, @@ -48433,7 +48857,7 @@ class Options { cert: https.certificate, key: https.key, passphrase: https.passphrase, - pfx: https.pfx, + pfx, rejectUnauthorized: https.rejectUnauthorized, checkServerIdentity: https.checkServerIdentity ?? external_node_tls_.checkServerIdentity, servername: https.serverName, @@ -48463,33 +48887,24 @@ class Options { }; } getRequestFunction() { - const url = this._internals.url; - const { request } = this._internals; - if (!request && url) { - return this.getFallbackRequestFunction(); - } - return request; - } - getFallbackRequestFunction() { - const url = this._internals.url; - if (!url) { - return; + const { request: customRequest } = this.#internals; + if (!customRequest) { + return this.#getFallbackRequestFunction(); } - if (url.protocol === 'https:') { - if (this._internals.http2) { - if (major < 15 || (major === 15 && minor < 10)) { - const error = new Error('To use the `http2` option, install Node.js 15.10.0 or above'); - error.code = 'EUNSUPPORTED'; - throw error; - } - return source.auto; + const requestWithFallback = (url, options, callback) => { + const result = customRequest(url, options, callback); + if (distribution.promise(result)) { + return this.#resolveRequestWithFallback(result, url, options, callback); } - return external_node_https_namespaceObject.request; - } - return external_node_http_.request; + if (result !== undefined) { + return result; + } + return this.#callFallbackRequest(url, options, callback); + }; + return requestWithFallback; } freeze() { - const options = this._internals; + const options = this.#internals; Object.freeze(options); Object.freeze(options.hooks); Object.freeze(options.hooks.afterResponse); @@ -48508,10 +48923,146 @@ class Options { Object.freeze(options.retry.methods); Object.freeze(options.retry.statusCodes); } + #createHeadersProxy() { + return new Proxy(this.#internals.headers, { + get(target, property, receiver) { + if (typeof property === 'string') { + if (Reflect.has(target, property)) { + return Reflect.get(target, property, receiver); + } + const normalizedProperty = property.toLowerCase(); + return Reflect.get(target, normalizedProperty, receiver); + } + return Reflect.get(target, property, receiver); + }, + set: (target, property, value) => { + if (typeof property === 'string') { + const normalizedProperty = property.toLowerCase(); + assertValidHeaderName(normalizedProperty); + const isSuccess = Reflect.set(target, normalizedProperty, value); + if (isSuccess) { + markHeaderAsExplicit(this.#explicitHeaders, this.#trackedStateMutations, normalizedProperty); + } + return isSuccess; + } + return Reflect.set(target, property, value); + }, + deleteProperty: (target, property) => { + if (typeof property === 'string') { + const normalizedProperty = property.toLowerCase(); + const isSuccess = Reflect.deleteProperty(target, normalizedProperty); + if (isSuccess) { + this.#explicitHeaders.delete(normalizedProperty); + trackStateMutation(this.#trackedStateMutations, normalizedProperty); + } + return isSuccess; + } + return Reflect.deleteProperty(target, property); + }, + }); + } + #getFallbackRequestFunction() { + const url = this.#internals.url; + if (!url) { + return; + } + if (url.protocol === 'https:') { + if (this.#internals.http2) { + if (major < 15 || (major === 15 && minor < 10)) { + const error = new Error('To use the `http2` option, install Node.js 15.10.0 or above'); + error.code = 'EUNSUPPORTED'; + throw error; + } + return source.auto; + } + return external_node_https_namespaceObject.request; + } + return external_node_http_.request; + } + #callFallbackRequest(url, options, callback) { + const fallbackRequest = this.#getFallbackRequestFunction(); + if (!fallbackRequest) { + throw new TypeError('The request function must return a value'); + } + const fallbackResult = fallbackRequest(url, options, callback); + if (fallbackResult === undefined) { + throw new TypeError('The request function must return a value'); + } + if (distribution.promise(fallbackResult)) { + return this.#resolveFallbackRequestResult(fallbackResult); + } + return fallbackResult; + } + async #resolveRequestWithFallback(requestResult, url, options, callback) { + const result = await requestResult; + if (result !== undefined) { + return result; + } + return this.#callFallbackRequest(url, options, callback); + } + async #resolveFallbackRequestResult(fallbackResult) { + const resolvedFallbackResult = await fallbackResult; + if (resolvedFallbackResult === undefined) { + throw new TypeError('The request function must return a value'); + } + return resolvedFallbackResult; + } } +const snapshotCrossOriginState = (options) => ({ + headers: { ...options.getInternalHeaders() }, + hadCookieJar: options.cookieJar !== undefined, + cookieWasExplicitlySet: options.isHeaderExplicitlySet('cookie'), + username: options.username, + password: options.password, + body: options.body, + json: options.json, + form: options.form, + bodySnapshot: cloneCrossOriginBodyValue(options.body), + jsonSnapshot: cloneCrossOriginBodyValue(options.json), + formSnapshot: cloneCrossOriginBodyValue(options.form), +}); +const cloneCrossOriginBodyValue = (value) => { + if (value === undefined || value === null || typeof value !== 'object') { + return value; + } + try { + return structuredClone(value); + } + catch { + return undefined; + } +}; +const isUnchangedCrossOriginBodyValue = (currentValue, previousValue, previousSnapshot) => { + if (currentValue !== previousValue) { + return false; + } + if (currentValue === undefined || currentValue === null || typeof currentValue !== 'object') { + return true; + } + if (previousSnapshot === undefined) { + return true; + } + return (0,external_node_util_.isDeepStrictEqual)(currentValue, previousSnapshot); +}; +const isCrossOriginCredentialChanged = (previousUrl, nextUrl, credential) => (nextUrl[credential] !== '' && nextUrl[credential] !== previousUrl[credential]); +const isBodyUnchanged = (options, previousState) => isUnchangedCrossOriginBodyValue(options.body, previousState.body, previousState.bodySnapshot) + && isUnchangedCrossOriginBodyValue(options.json, previousState.json, previousState.jsonSnapshot) + && isUnchangedCrossOriginBodyValue(options.form, previousState.form, previousState.formSnapshot); ;// CONCATENATED MODULE: ./node_modules/got/dist/source/core/response.js + + +const decodedBodyCache = new WeakMap(); +// Intentionally uses TextDecoder so the UTF-8 path strips a leading BOM. +const textDecoder = new TextDecoder(); +const isUtf8Encoding = (encoding) => encoding === undefined || encoding.toLowerCase().replace('-', '') === 'utf8'; +const decodeUint8Array = (data, encoding) => { + if (isUtf8Encoding(encoding)) { + return textDecoder.decode(data); + } + return external_node_buffer_.Buffer.from(data).toString(encoding); +}; const isResponseOk = (response) => { const { statusCode } = response; const { followRedirect } = response.request.options; @@ -48528,17 +49079,28 @@ class ParseError extends errors_RequestError { code = 'ERR_BODY_PARSE_FAILURE'; constructor(error, response) { const { options } = response.request; - super(`${error.message} in "${options.url.toString()}"`, error, response.request); + super(`${error.message} in "${stripUrlAuth(options.url)}"`, error, response.request); } } +const cacheDecodedBody = (response, decodedBody) => { + decodedBodyCache.set(response, decodedBody); +}; const parseBody = (response, responseType, parseJson, encoding) => { const { rawBody } = response; + const cachedDecodedBody = decodedBodyCache.get(response); try { if (responseType === 'text') { - return rawBody.toString(encoding); + if (cachedDecodedBody !== undefined) { + return cachedDecodedBody; + } + return decodeUint8Array(rawBody, encoding); } if (responseType === 'json') { - return rawBody.length === 0 ? '' : parseJson(rawBody.toString(encoding)); + if (rawBody.length === 0) { + return ''; + } + const text = cachedDecodedBody ?? decodeUint8Array(rawBody, encoding); + return parseJson(text); } if (responseType === 'buffer') { return rawBody; @@ -48559,33 +49121,6 @@ function isClientRequest(clientRequest) { } /* harmony default export */ const is_client_request = (isClientRequest); -;// CONCATENATED MODULE: ./node_modules/got/dist/source/core/utils/is-unix-socket-url.js -// eslint-disable-next-line @typescript-eslint/naming-convention -function isUnixSocketURL(url) { - return url.protocol === 'unix:' || url.hostname === 'unix'; -} -/** -Extract the socket path from a UNIX socket URL. - -@example -``` -getUnixSocketPath(new URL('http://unix/foo:/path')); -//=> '/foo' - -getUnixSocketPath(new URL('unix:/foo:/path')); -//=> '/foo' - -getUnixSocketPath(new URL('http://example.com')); -//=> undefined -``` -*/ -function getUnixSocketPath(url) { - if (!isUnixSocketURL(url)) { - return undefined; - } - return /(?.+?):(?.+)/.exec(`${url.pathname}${url.search}`)?.groups?.socketPath; -} - // EXTERNAL MODULE: external "node:diagnostics_channel" var external_node_diagnostics_channel_ = __nccwpck_require__(3053); ;// CONCATENATED MODULE: ./node_modules/got/dist/source/core/diagnostics-channel.js @@ -48603,40 +49138,31 @@ const channels = { function generateRequestId() { return (0,external_node_crypto_.randomUUID)(); } -function publishRequestCreate(message) { - if (channels.requestCreate.hasSubscribers) { - channels.requestCreate.publish(message); +const publishToChannel = (channel, message) => { + if (channel.hasSubscribers) { + channel.publish(message); } +}; +function publishRequestCreate(message) { + publishToChannel(channels.requestCreate, message); } function publishRequestStart(message) { - if (channels.requestStart.hasSubscribers) { - channels.requestStart.publish(message); - } + publishToChannel(channels.requestStart, message); } function publishResponseStart(message) { - if (channels.responseStart.hasSubscribers) { - channels.responseStart.publish(message); - } + publishToChannel(channels.responseStart, message); } function publishResponseEnd(message) { - if (channels.responseEnd.hasSubscribers) { - channels.responseEnd.publish(message); - } + publishToChannel(channels.responseEnd, message); } function publishRetry(message) { - if (channels.retry.hasSubscribers) { - channels.retry.publish(message); - } + publishToChannel(channels.retry, message); } function publishError(message) { - if (channels.error.hasSubscribers) { - channels.error.publish(message); - } + publishToChannel(channels.error, message); } function publishRedirect(message) { - if (channels.redirect.hasSubscribers) { - channels.redirect.publish(message); - } + publishToChannel(channels.redirect, message); } ;// CONCATENATED MODULE: ./node_modules/got/dist/source/core/index.js @@ -48661,13 +49187,33 @@ function publishRedirect(message) { + const supportsBrotli = distribution.string(external_node_process_namespaceObject.versions.brotli); const core_supportsZstd = distribution.string(external_node_process_namespaceObject.versions.zstd); const methodsWithoutBody = new Set(['GET', 'HEAD']); +const singleValueRequestHeaders = new Set([ + 'authorization', + 'content-length', + 'proxy-authorization', +]); const cacheableStore = new WeakableMap(); -const redirectCodes = new Set([300, 301, 302, 303, 304, 307, 308]); +const redirectCodes = new Set([301, 302, 303, 307, 308]); + +const transientWriteErrorCodes = new Set(['EPIPE', 'ECONNRESET']); +const omittedPipedHeaders = new Set([ + 'host', + 'connection', + 'keep-alive', + 'proxy-authenticate', + 'proxy-authorization', + 'proxy-connection', + 'te', + 'trailer', + 'transfer-encoding', + 'upgrade', +]); // Track errors that have been processed by beforeError hooks to preserve custom error types const errorsProcessedByHooks = new WeakSet(); const proxiedRequestEvents = [ @@ -48678,6 +49224,64 @@ const proxiedRequestEvents = [ 'upgrade', ]; const core_noop = () => { }; +const isTransientWriteError = (error) => { + const { code } = error; + return typeof code === 'string' && transientWriteErrorCodes.has(code); +}; +const getConnectionListedHeaders = (headers) => { + const connectionListedHeaders = new Set(); + for (const [header, connectionHeader] of Object.entries(headers)) { + const normalizedHeader = header.toLowerCase(); + if (normalizedHeader !== 'connection' && normalizedHeader !== 'proxy-connection') { + continue; + } + const connectionHeaderValues = Array.isArray(connectionHeader) ? connectionHeader : [connectionHeader]; + for (const value of connectionHeaderValues) { + if (typeof value !== 'string') { + continue; + } + for (const token of value.split(',')) { + const normalizedToken = token.trim().toLowerCase(); + if (normalizedToken.length > 0) { + connectionListedHeaders.add(normalizedToken); + } + } + } + } + return connectionListedHeaders; +}; +const normalizeError = (error) => { + if (error instanceof globalThis.Error) { + return error; + } + if (distribution.object(error)) { + const errorLike = error; + const message = typeof errorLike.message === 'string' ? errorLike.message : 'Non-error object thrown'; + const normalizedError = new globalThis.Error(message, { cause: error }); + if (typeof errorLike.stack === 'string') { + normalizedError.stack = errorLike.stack; + } + if (typeof errorLike.code === 'string') { + normalizedError.code = errorLike.code; + } + if (typeof errorLike.input === 'string') { + normalizedError.input = errorLike.input; + } + return normalizedError; + } + return new globalThis.Error(String(error)); +}; +const getSanitizedUrl = (options) => options?.url ? stripUrlAuth(options.url) : ''; +const makeProgress = (transferred, total) => { + let percent = 0; + if (total) { + percent = transferred / total; + } + else if (total === transferred) { + percent = 1; + } + return { percent, transferred, total }; +}; class Request extends external_node_stream_.Duplex { // @ts-expect-error - Ignoring for now. ['constructor']; @@ -48689,24 +49293,24 @@ class Request extends external_node_stream_.Duplex { redirectUrls = []; retryCount = 0; _stopReading = false; - _stopRetry = core_noop; + _stopRetry; _downloadedSize = 0; _uploadedSize = 0; _pipedServerResponses = new Set(); _request; _responseSize; _bodySize; - _unproxyEvents = core_noop; - _isFromCache; + _unproxyEvents; _triggerRead = false; _jobs = []; - _cancelTimeouts = core_noop; - _removeListeners = core_noop; - _nativeResponse; + _cancelTimeouts; + _abortListenerDisposer; _flushed = false; _aborted = false; _expectedContentLength; _compressedBytesCount; + _skipRequestEndInFinal = false; + _incrementalDecode; _requestId = generateRequestId(); // We need this because `this._request` if `undefined` when using cache _requestInitialized = false; @@ -48719,7 +49323,17 @@ class Request extends external_node_stream_.Duplex { }); this.on('pipe', (source) => { if (this.options.copyPipedHeaders && source?.headers) { - Object.assign(this.options.headers, source.headers); + const connectionListedHeaders = getConnectionListedHeaders(source.headers); + for (const [header, value] of Object.entries(source.headers)) { + const normalizedHeader = header.toLowerCase(); + if (omittedPipedHeaders.has(normalizedHeader) || connectionListedHeaders.has(normalizedHeader)) { + continue; + } + if (!this.options.shouldCopyPipedHeader(normalizedHeader)) { + continue; + } + this.options.setPipedHeader(normalizedHeader, value); + } } }); this.on('newListener', event => { @@ -48739,7 +49353,7 @@ class Request extends external_node_stream_.Duplex { // Publish request creation event publishRequestCreate({ requestId: this._requestId, - url: this.options.url?.toString() ?? '', + url: getSanitizedUrl(this.options), method: this.options.method, }); } @@ -48754,11 +49368,12 @@ class Request extends external_node_stream_.Duplex { external_node_process_namespaceObject.nextTick(() => { // _beforeError requires options to access retry logic and hooks if (this.options) { - this._beforeError(error); + this._beforeError(normalizeError(error)); } else { // Options is undefined, skip _beforeError and destroy directly - const requestError = error instanceof errors_RequestError ? error : new errors_RequestError(error.message, error, this); + const normalizedError = normalizeError(error); + const requestError = normalizedError instanceof errors_RequestError ? normalizedError : new errors_RequestError(normalizedError.message, normalizedError, this); this.destroy(requestError); } }); @@ -48769,37 +49384,7 @@ class Request extends external_node_stream_.Duplex { // The below is run only once. const { body } = this.options; if (distribution.nodeStream(body)) { - body.once('error', error => { - if (this._flushed) { - this._beforeError(new UploadError(error, this)); - } - else { - this.flush = async () => { - this.flush = async () => { }; - this._beforeError(new UploadError(error, this)); - }; - } - }); - } - if (this.options.signal) { - const abort = () => { - // See https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/timeout_static#return_value - if (this.options.signal?.reason?.name === 'TimeoutError') { - this.destroy(new TimeoutError(this.options.signal.reason, this.timings, this)); - } - else { - this.destroy(new AbortError(this)); - } - }; - if (this.options.signal.aborted) { - abort(); - } - else { - this.options.signal.addEventListener('abort', abort); - this._removeListeners = () => { - this.options.signal?.removeEventListener('abort', abort); - }; - } + body.once('error', this._onBodyError); } } async flush() { @@ -48808,6 +49393,10 @@ class Request extends external_node_stream_.Duplex { } this._flushed = true; try { + this._attachAbortListener(); + if (this.destroyed) { + return; + } await this._finalizeBody(); if (this.destroyed) { return; @@ -48826,7 +49415,7 @@ class Request extends external_node_stream_.Duplex { this._requestInitialized = true; } catch (error) { - this._beforeError(error); + this._beforeError(normalizeError(error)); } } _beforeError(error) { @@ -48852,7 +49441,7 @@ class Request extends external_node_stream_.Duplex { response.setEncoding(this.readableEncoding); const success = await this._setRawBody(response); if (success) { - response.body = response.rawBody.toString(); + response.body = decodeUint8Array(response.rawBody); } } if (this.listenerCount('retry') !== 0) { @@ -48882,7 +49471,7 @@ class Request extends external_node_stream_.Duplex { // When enforceRetryRules is true, respect the retry rules (limit, methods, statusCodes, errorCodes) // before calling the user's calculateDelay function. If computedValue is 0 (meaning retry is not allowed // based on these rules), skip calling calculateDelay entirely. - // When false (default), always call calculateDelay, allowing it to override retry decisions. + // When false, always call calculateDelay, allowing it to override retry decisions. if (retryOptions.enforceRetryRules && computedValue === 0) { backoff = 0; } @@ -48897,7 +49486,8 @@ class Request extends external_node_stream_.Duplex { } } catch (error_) { - void this._error(new errors_RequestError(error_.message, error_, this)); + const normalizedError = normalizeError(error_); + void this._error(new errors_RequestError(normalizedError.message, normalizedError, this)); return; } if (backoff) { @@ -48921,7 +49511,8 @@ class Request extends external_node_stream_.Duplex { } } catch (error_) { - void this._error(new errors_RequestError(error_.message, error_, this)); + const normalizedError = normalizeError(error_); + void this._error(new errors_RequestError(normalizedError.message, normalizedError, this)); return; } // Something forced us to abort the retry @@ -48941,30 +49532,35 @@ class Request extends external_node_stream_.Duplex { // 2. If body was reassigned, we MUST destroy the OLD stream to prevent memory leaks // 3. We must restore the body reference after destroy() for identity checks in promise wrapper // 4. We cannot use the normal setter after destroy() because it validates stream readability - if (bodyWasReassigned) { - const oldBody = bodyBeforeHooks; - // Temporarily clear body to prevent destroy() from destroying the new stream - this.options.body = undefined; - this.destroy(); - // Clean up the old stream resource if it's a stream and different from new body - // (edge case: if old and new are same stream object, don't destroy it) - if (distribution.nodeStream(oldBody) && oldBody !== bodyAfterHooks) { - oldBody.destroy(); + try { + if (bodyWasReassigned) { + const oldBody = bodyBeforeHooks; + // Temporarily clear body to prevent destroy() from destroying the new stream + this.options.body = undefined; + this.destroy(); + // Clean up the old stream resource if it's a stream and different from new body + // (edge case: if old and new are same stream object, don't destroy it) + if (distribution.nodeStream(oldBody) && oldBody !== bodyAfterHooks) { + oldBody.destroy(); + } + // Restore new body for promise wrapper's identity check + if (distribution.nodeStream(bodyAfterHooks) && (bodyAfterHooks.readableEnded || bodyAfterHooks.destroyed)) { + throw new TypeError('The reassigned stream body must be readable. Ensure you provide a fresh, readable stream in the beforeRetry hook.'); + } + this.options.body = bodyAfterHooks; } - // Restore new body for promise wrapper's identity check - // We bypass the setter because it validates stream.readable (which fails for destroyed request) - // Type assertion is necessary here to access private _internals without exposing internal API - if (distribution.nodeStream(bodyAfterHooks) && (bodyAfterHooks.readableEnded || bodyAfterHooks.destroyed)) { - throw new TypeError('The reassigned stream body must be readable. Ensure you provide a fresh, readable stream in the beforeRetry hook.'); + else { + // Body wasn't reassigned - use normal destroy flow which handles body cleanup + this.destroy(); + // Note: We do NOT restore the body reference here. The stream was destroyed by _destroy() + // and should not be accessed. The promise wrapper will see that body identity hasn't changed + // and will detect it's a consumed stream, which is the correct behavior. } - this.options._internals.body = bodyAfterHooks; } - else { - // Body wasn't reassigned - use normal destroy flow which handles body cleanup - this.destroy(); - // Note: We do NOT restore the body reference here. The stream was destroyed by _destroy() - // and should not be accessed. The promise wrapper will see that body identity hasn't changed - // and will detect it's a consumed stream, which is the correct behavior. + catch (error_) { + const normalizedError = normalizeError(error_); + void this._error(new errors_RequestError(normalizedError.message, normalizedError, this)); + return; } // Publish retry event publishRetry({ @@ -48999,11 +49595,28 @@ class Request extends external_node_stream_.Duplex { let data; while ((data = response.read()) !== null) { this._downloadedSize += data.length; // eslint-disable-line @typescript-eslint/restrict-plus-operands + if (this._incrementalDecode) { + try { + const decodedChunk = typeof data === 'string' ? data : this._incrementalDecode.decoder.decode(data, { stream: true }); + if (decodedChunk.length > 0) { + this._incrementalDecode.chunks.push(decodedChunk); + } + } + catch { + this._incrementalDecode = undefined; + } + } const progress = this.downloadProgress; if (progress.percent < 1) { this.emit('downloadProgress', progress); } + if (this._stopReading) { + return; + } this.push(data); + if (this._stopReading) { + return; + } } } } @@ -49020,22 +49633,26 @@ class Request extends external_node_stream_.Duplex { } _final(callback) { const endRequest = () => { + if (this._skipRequestEndInFinal) { + this._skipRequestEndInFinal = false; + callback(); + return; + } + const request = this._request; // We need to check if `this._request` is present, // because it isn't when we use cache. - if (!this._request || this._request.destroyed) { + if (!request || request.destroyed) { callback(); return; } - this._request.end((error) => { + request.end((error) => { // The request has been destroyed before `_final` finished. // See https://github.com/nodejs/node/issues/39356 - if (this._request?._writableState?.errored) { + if (request?._writableState?.errored) { return; } if (!error) { - this._bodySize = this._uploadedSize; - this.emit('uploadProgress', this.uploadProgress); - this._request?.emit('upload-complete'); + this._emitUploadComplete(request); } callback(error); }); @@ -49051,9 +49668,9 @@ class Request extends external_node_stream_.Duplex { this._stopReading = true; this.flush = async () => { }; // Prevent further retries - this._stopRetry(); - this._cancelTimeouts(); - this._removeListeners(); + this._stopRetry?.(); + this._cancelTimeouts?.(); + this._abortListenerDisposer?.[Symbol.dispose](); if (this.options) { const { body } = this.options; if (distribution.nodeStream(body)) { @@ -49101,6 +49718,37 @@ class Request extends external_node_stream_.Duplex { super.unpipe(destination); return this; } + _attachAbortListener() { + if (this._abortListenerDisposer) { + return; + } + const { signal } = this.options; + if (!signal) { + return; + } + const abort = () => { + // See https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/timeout_static#return_value + if (signal.reason?.name === 'TimeoutError') { + this.destroy(new TimeoutError(signal.reason, this.timings, this)); + } + else { + this.destroy(new AbortError(this)); + } + }; + if (signal.aborted) { + abort(); + } + else { + this._abortListenerDisposer = (0,external_node_events_.addAbortListener)(signal, abort); + } + } + _shouldIncrementallyDecodeBody() { + const { responseType, encoding } = this.options; + return Boolean(this._noPipe) + && (responseType === 'text' || responseType === 'json') + && isUtf8Encoding(encoding) + && typeof globalThis.TextDecoder === 'function'; + } _checkContentLengthMismatch() { if (this.options.strictContentLength && this._expectedContentLength !== undefined) { // Use compressed bytes count when available (for compressed responses), @@ -49119,7 +49767,7 @@ class Request extends external_node_stream_.Duplex { } async _finalizeBody() { const { options } = this; - const { headers } = options; + const headers = options.getInternalHeaders(); const isForm = !distribution.undefined(options.form); // eslint-disable-next-line @typescript-eslint/naming-convention const isJSON = !distribution.undefined(options.json); @@ -49132,20 +49780,16 @@ class Request extends external_node_stream_.Duplex { // Serialize body const noContentType = !distribution.string(headers['content-type']); if (isBody) { - // Body is spec-compliant FormData - if (lib_isFormData(options.body)) { - const encoder = new FormDataEncoder(options.body); + // Native FormData + if (options.body instanceof FormData) { + const response = new Response(options.body); if (noContentType) { - headers['content-type'] = encoder.headers['Content-Type']; + headers['content-type'] = response.headers.get('content-type') ?? 'multipart/form-data'; } - if ('Content-Length' in encoder.headers) { - headers['content-length'] = encoder.headers['Content-Length']; - } - options.body = encoder.encode(); + options.body = response.body; } - // Special case for https://github.com/form-data/form-data - if (is_form_data_isFormData(options.body) && noContentType) { - headers['content-type'] = `multipart/form-data; boundary=${options.body.getBoundary()}`; + else if (Object.prototype.toString.call(options.body) === '[object FormData]') { + throw new TypeError('Non-native FormData is not supported. Use globalThis.FormData instead.'); } } else if (isForm) { @@ -49164,7 +49808,7 @@ class Request extends external_node_stream_.Duplex { options.json = undefined; options.body = options.stringifyJson(json); } - const uploadBodySize = await getBodySize(options.body, options.headers); + const uploadBodySize = getBodySize(options.body, headers); // See https://tools.ietf.org/html/rfc7230#section-3.3.2 // A user agent SHOULD send a Content-Length in a request message when // no Transfer-Encoding is sent and the request method defines a meaning @@ -49178,8 +49822,8 @@ class Request extends external_node_stream_.Duplex { headers['content-length'] = String(uploadBodySize); } } - if (options.responseType === 'json' && !('accept' in options.headers)) { - options.headers.accept = 'application/json'; + if (options.responseType === 'json' && !('accept' in headers)) { + headers.accept = 'application/json'; } this._bodySize = Number(headers['content-length']) || undefined; } @@ -49190,9 +49834,12 @@ class Request extends external_node_stream_.Duplex { } const { options } = this; const { url } = options; - this._nativeResponse = response; + const nativeResponse = response; const statusCode = response.statusCode; const { method } = options; + const redirectLocationHeader = response.headers.location; + const redirectLocation = Array.isArray(redirectLocationHeader) ? redirectLocationHeader[0] : redirectLocationHeader; + const isRedirect = Boolean(redirectLocation && redirectCodes.has(statusCode)); // Skip decompression for responses that must not have bodies per RFC 9110: // - HEAD responses (any status code) // - 1xx (Informational): 100, 101, 102, 103, etc. @@ -49204,30 +49851,49 @@ class Request extends external_node_stream_.Duplex { || statusCode === 204 || statusCode === 205 || statusCode === 304; - if (options.decompress && !hasNoBody) { + const prepareResponse = (response) => { + if (!Object.hasOwn(response, 'headers')) { + Object.defineProperty(response, 'headers', { + value: response.headers, + enumerable: true, + writable: true, + configurable: true, + }); + } + response.statusMessage ||= external_node_http_.STATUS_CODES[statusCode]; // eslint-disable-line @typescript-eslint/prefer-nullish-coalescing -- The status message can be empty. + response.url = stripUrlAuth(options.url); + response.requestUrl = this.requestUrl; + response.redirectUrls = this.redirectUrls; + response.request = this; + response.isFromCache = nativeResponse.fromCache ?? false; + response.ip = this.ip; + response.retryCount = this.retryCount; + response.ok = isResponseOk(response); + return response; + }; + let typedResponse = prepareResponse(response); + // Redirect responses that will be followed are drained raw. Decompressing them can + // turn an irrelevant redirect body into a client-side failure or decompression DoS. + const shouldFollowRedirect = isRedirect && (typeof options.followRedirect === 'function' ? options.followRedirect(typedResponse) : options.followRedirect); + if (options.decompress && !hasNoBody && !shouldFollowRedirect) { // When strictContentLength is enabled, track compressed bytes by listening to // the native response's data events before decompression if (options.strictContentLength) { this._compressedBytesCount = 0; - this._nativeResponse.on('data', (chunk) => { + nativeResponse.on('data', (chunk) => { this._compressedBytesCount += byteLength(chunk); }); } response = decompressResponse(response); + typedResponse = prepareResponse(response); } - const typedResponse = response; - typedResponse.statusMessage = typedResponse.statusMessage || external_node_http_.STATUS_CODES[statusCode]; // eslint-disable-line @typescript-eslint/prefer-nullish-coalescing -- The status message can be empty. - typedResponse.url = options.url.toString(); - typedResponse.requestUrl = this.requestUrl; - typedResponse.redirectUrls = this.redirectUrls; - typedResponse.request = this; - typedResponse.isFromCache = this._nativeResponse.fromCache ?? false; - typedResponse.ip = this.ip; - typedResponse.retryCount = this.retryCount; - typedResponse.ok = isResponseOk(typedResponse); - this._isFromCache = typedResponse.isFromCache; + // `decompressResponse` wraps the response stream when it decompresses, + // so `response !== nativeResponse` indicates decompression happened. + const wasDecompressed = response !== nativeResponse; this._responseSize = Number(response.headers['content-length']) || undefined; this.response = typedResponse; + // eslint-disable-next-line @typescript-eslint/naming-convention + this._incrementalDecode = this._shouldIncrementallyDecodeBody() ? { decoder: new globalThis.TextDecoder('utf8', { ignoreBOM: true }), chunks: [] } : undefined; // Publish response start event publishResponseStart({ requestId: this._requestId, @@ -49237,13 +49903,26 @@ class Request extends external_node_stream_.Duplex { isFromCache: typedResponse.isFromCache, }); response.once('error', (error) => { + // Node synthesizes ECONNRESET for close-delimited responses after all body + // bytes have been delivered. Only ignore that late synthetic error on the + // native response. Wrapped decompression streams surface real checksum and + // truncation failures after the underlying response has completed. + if (!wasDecompressed + && response.complete + && this._responseSize === undefined + && error.code === 'ECONNRESET') { + return; + } this._aborted = true; - // Force clean-up, because some packages don't do this. - // TODO: Fix decompress-response - response.destroy(); this._beforeError(new ReadError(error, this)); }); response.once('aborted', () => { + // Without Content-Length, connection close is the intended EOF signal (RFC 9110 §8.6), + // not a premature abort. For wrapped decompression streams, rely on the native + // response completion state because the wrapper strips `content-length`. + if (this._responseSize === undefined && nativeResponse.complete) { + return; + } this._aborted = true; // Check if there's a content-length mismatch to provide a more specific error if (!this._checkContentLengthMismatch()) { @@ -49254,11 +49933,49 @@ class Request extends external_node_stream_.Duplex { }, this)); } }); + let canFinalizeResponse = false; + const handleResponseEnd = () => { + if (!canFinalizeResponse + || !response.readableEnded) { + return; + } + canFinalizeResponse = false; + if (this._stopReading) { + return; + } + // Validate content-length if it was provided + // Per RFC 9112: "If the sender closes the connection before the indicated number + // of octets are received, the recipient MUST consider the message to be incomplete" + if (this._checkContentLengthMismatch()) { + return; + } + this._responseSize = this._downloadedSize; + this.emit('downloadProgress', this.downloadProgress); + // Publish response end event + publishResponseEnd({ + requestId: this._requestId, + url: typedResponse.url, + statusCode, + bodySize: this._downloadedSize, + timings: this.timings, + }); + this.push(null); + }; + if (!shouldFollowRedirect) { + // `set-cookie` handling below awaits the cookie jar. A fast response can fully + // end during that await, so we need to observe `end` early without completing + // the outward stream until cookie handling has finished. + response.once('end', handleResponseEnd); + } + const noPipeCookieJarRawBodyPromise = this._noPipe + && distribution.object(options.cookieJar) + && !isRedirect + ? this._setRawBody(response) + : undefined; const rawCookies = response.headers['set-cookie']; if (distribution.object(options.cookieJar) && rawCookies) { let promises = rawCookies.map(async (rawCookie) => options.cookieJar.setCookie(rawCookie, url.toString())); if (options.ignoreInvalidCookies) { - // eslint-disable-next-line @typescript-eslint/no-floating-promises promises = promises.map(async (promise) => { try { await promise; @@ -49270,7 +49987,7 @@ class Request extends external_node_stream_.Duplex { await Promise.all(promises); } catch (error) { - this._beforeError(error); + this._beforeError(normalizeError(error)); return; } } @@ -49278,89 +49995,118 @@ class Request extends external_node_stream_.Duplex { if (this.isAborted) { return; } - if (response.headers.location && redirectCodes.has(statusCode)) { + if (shouldFollowRedirect) { // We're being redirected, we don't care about the response. // It'd be best to abort the request, but we can't because // we would have to sacrifice the TCP connection. We don't want that. - const shouldFollow = typeof options.followRedirect === 'function' ? options.followRedirect(typedResponse) : options.followRedirect; - if (shouldFollow) { - response.resume(); - this._cancelTimeouts(); - this._unproxyEvents(); - if (this.redirectUrls.length >= options.maxRedirects) { - this._beforeError(new MaxRedirectsError(this)); + response.resume(); + this._cancelTimeouts?.(); + this._unproxyEvents?.(); + if (this.redirectUrls.length >= options.maxRedirects) { + this._beforeError(new MaxRedirectsError(this)); + return; + } + this._request = undefined; + // Reset progress for the new request. + this._downloadedSize = 0; + this._uploadedSize = 0; + const updatedOptions = new Options(undefined, undefined, this.options); + try { + // We need this in order to support UTF-8 + const redirectBuffer = external_node_buffer_.Buffer.from(redirectLocation, 'binary').toString(); + const redirectUrl = new URL(redirectBuffer, url); + const currentUnixSocketPath = getUnixSocketPath(url); + const redirectUnixSocketPath = getUnixSocketPath(redirectUrl); + if (redirectUrl.protocol === 'unix:' && redirectUnixSocketPath === undefined) { + this._beforeError(new errors_RequestError('Cannot redirect to UNIX socket', {}, this)); return; } - this._request = undefined; - // Reset download progress for the new request - this._downloadedSize = 0; - const updatedOptions = new Options(undefined, undefined, this.options); + // Relative redirects on the same socket are fine, but a redirect must not switch to a different local socket. + if (redirectUnixSocketPath !== undefined && currentUnixSocketPath !== redirectUnixSocketPath) { + this._beforeError(new errors_RequestError('Cannot redirect to UNIX socket', {}, this)); + return; + } + // Redirecting to a different site, clear sensitive data. + // For UNIX sockets, different socket paths are also different origins. + const isDifferentOrigin = redirectUrl.origin !== url.origin + || currentUnixSocketPath !== redirectUnixSocketPath; const serverRequestedGet = statusCode === 303 && updatedOptions.method !== 'GET' && updatedOptions.method !== 'HEAD'; + // Avoid forwarding a POST body to a different origin on historical 301/302 redirects. + const crossOriginRequestedGet = isDifferentOrigin + && (statusCode === 301 || statusCode === 302) + && updatedOptions.method === 'POST'; const canRewrite = statusCode !== 307 && statusCode !== 308; const userRequestedGet = updatedOptions.methodRewriting && canRewrite; - if (serverRequestedGet || userRequestedGet) { + const shouldDropBody = serverRequestedGet || crossOriginRequestedGet || userRequestedGet; + if (shouldDropBody) { updatedOptions.method = 'GET'; - updatedOptions.body = undefined; - updatedOptions.json = undefined; - updatedOptions.form = undefined; - delete updatedOptions.headers['content-length']; + this._dropBody(updatedOptions); } - try { - // We need this in order to support UTF-8 - const redirectBuffer = external_node_buffer_.Buffer.from(response.headers.location, 'binary').toString(); - const redirectUrl = new URL(redirectBuffer, url); - if (!isUnixSocketURL(url) && isUnixSocketURL(redirectUrl)) { - this._beforeError(new errors_RequestError('Cannot redirect to UNIX socket', {}, this)); - return; - } - // Redirecting to a different site, clear sensitive data. - // For UNIX sockets, different socket paths are also different origins. - const isDifferentOrigin = redirectUrl.hostname !== url.hostname - || redirectUrl.port !== url.port - || getUnixSocketPath(url) !== getUnixSocketPath(redirectUrl); - if (isDifferentOrigin) { - if ('host' in updatedOptions.headers) { - delete updatedOptions.headers.host; - } - if ('cookie' in updatedOptions.headers) { - delete updatedOptions.headers.cookie; - } - if ('authorization' in updatedOptions.headers) { - delete updatedOptions.headers.authorization; - } - if (updatedOptions.username || updatedOptions.password) { - updatedOptions.username = ''; - updatedOptions.password = ''; - } - } - else { - redirectUrl.username = updatedOptions.username; - redirectUrl.password = updatedOptions.password; - } - this.redirectUrls.push(redirectUrl); - updatedOptions.url = redirectUrl; + if (isDifferentOrigin) { + // Also strip body on cross-origin redirects to prevent data leakage. + // 301/302 POST already drops the body (converted to GET above). + // 307/308 preserve the method per RFC, but the body must not be + // forwarded to a different origin. + // Strip credentials embedded in the redirect URL itself + // to prevent a malicious server from injecting auth to third parties. + this._stripCrossOriginState(updatedOptions, redirectUrl, shouldDropBody); + } + else { + redirectUrl.username = updatedOptions.username; + redirectUrl.password = updatedOptions.password; + } + updatedOptions.url = redirectUrl; + this.redirectUrls.push(redirectUrl); + const preHookState = isDifferentOrigin + ? undefined + : { + ...snapshotCrossOriginState(updatedOptions), + url: new URL(updatedOptions.url), + }; + const changedState = await updatedOptions.trackStateMutations(async (changedState) => { for (const hook of updatedOptions.hooks.beforeRedirect) { // eslint-disable-next-line no-await-in-loop await hook(updatedOptions, typedResponse); } - // Publish redirect event - publishRedirect({ - requestId: this._requestId, - fromUrl: url.toString(), - toUrl: redirectUrl.toString(), - statusCode, - }); - this.emit('redirect', updatedOptions, typedResponse); - this.options = updatedOptions; - await this._makeRequest(); - } - catch (error) { - this._beforeError(error); - return; + return changedState; + }); + updatedOptions.clearUnchangedCookieHeader(preHookState, changedState); + // If a beforeRedirect hook changed the URL to a different origin, + // strip sensitive headers that were preserved for the original origin. + // When isDifferentOrigin was already true, headers were already stripped above. + if (!isDifferentOrigin) { + const state = preHookState; + const hookUrl = updatedOptions.url; + if (!isSameOrigin(state.url, hookUrl)) { + this._stripUnchangedCrossOriginState(updatedOptions, hookUrl, shouldDropBody, { + ...state, + changedState, + preserveUsername: hasExplicitCredentialInUrlChange(changedState, hookUrl, 'username') + || isCrossOriginCredentialChanged(state.url, hookUrl, 'username'), + preservePassword: hasExplicitCredentialInUrlChange(changedState, hookUrl, 'password') + || isCrossOriginCredentialChanged(state.url, hookUrl, 'password'), + }); + } } + // Publish redirect event + publishRedirect({ + requestId: this._requestId, + fromUrl: url.toString(), + toUrl: (updatedOptions.url).toString(), + statusCode, + }); + this.emit('redirect', updatedOptions, typedResponse); + this.options = updatedOptions; + await this._makeRequest(); + } + catch (error) { + this._beforeError(normalizeError(error)); return; } + return; } + canFinalizeResponse = true; + handleResponseEnd(); // `HTTPError`s always have `error.response.body` defined. // Therefore, we cannot retry if `options.throwHttpErrors` is false. // On the last retry, if `options.throwHttpErrors` is false, we would need to return the body, @@ -49373,9 +50119,8 @@ class Request extends external_node_stream_.Duplex { // This is the content-length before decompression, which is what actually gets transferred. // Skip storing for responses that shouldn't have bodies per RFC 9110. // When decompression occurs, only store if strictContentLength is enabled. - const wasDecompressed = response !== this._nativeResponse; if (!hasNoBody && (!wasDecompressed || options.strictContentLength)) { - const contentLengthHeader = this._nativeResponse.headers['content-length']; + const contentLengthHeader = nativeResponse.headers['content-length']; if (contentLengthHeader !== undefined) { const expectedLength = Number(contentLengthHeader); if (!Number.isNaN(expectedLength) && expectedLength >= 0) { @@ -49383,26 +50128,6 @@ class Request extends external_node_stream_.Duplex { } } } - // Set up end listener AFTER redirect check to avoid emitting progress for redirect responses - response.once('end', () => { - // Validate content-length if it was provided - // Per RFC 9112: "If the sender closes the connection before the indicated number - // of octets are received, the recipient MUST consider the message to be incomplete" - if (this._checkContentLengthMismatch()) { - return; - } - this._responseSize = this._downloadedSize; - this.emit('downloadProgress', this.downloadProgress); - // Publish response end event - publishResponseEnd({ - requestId: this._requestId, - url: typedResponse.url, - statusCode, - bodySize: this._downloadedSize, - timings: this.timings, - }); - this.push(null); - }); this.emit('downloadProgress', this.downloadProgress); response.on('readable', () => { if (this._triggerRead) { @@ -49416,7 +50141,13 @@ class Request extends external_node_stream_.Duplex { response.pause(); }); if (this._noPipe) { - const success = await this._setRawBody(); + const captureFromResponse = response.readableEnded || noPipeCookieJarRawBodyPromise !== undefined; + const success = noPipeCookieJarRawBodyPromise + ? await noPipeCookieJarRawBodyPromise + : await this._setRawBody(captureFromResponse ? response : this); + if (captureFromResponse) { + handleResponseEnd(); + } if (success) { this.emit('response', response); } @@ -49427,10 +50158,6 @@ class Request extends external_node_stream_.Duplex { if (destination.headersSent) { continue; } - // Check if decompression actually occurred by comparing stream objects. - // decompressResponse wraps the response stream when it decompresses, - // so response !== this._nativeResponse indicates decompression happened. - const wasDecompressed = response !== this._nativeResponse; for (const key in response.headers) { if (Object.hasOwn(response.headers, key)) { const value = response.headers[key]; @@ -49449,21 +50176,39 @@ class Request extends external_node_stream_.Duplex { } } async _setRawBody(from = this) { - if (from.readableEnded) { - return false; - } try { // Errors are emitted via the `error` event const fromArray = await from.toArray(); - const rawBody = isBuffer(fromArray.at(0)) ? external_node_buffer_.Buffer.concat(fromArray) : external_node_buffer_.Buffer.from(fromArray.join('')); + const hasNonStringChunk = fromArray.some(chunk => typeof chunk !== 'string'); + const rawBody = hasNonStringChunk + ? concatUint8Arrays(fromArray.map(chunk => typeof chunk === 'string' ? stringToUint8Array(chunk) : chunk)) + : stringToUint8Array(fromArray.join('')); + const shouldUseIncrementalDecodedBody = from === this && this._incrementalDecode !== undefined; // On retry Request is destroyed with no error, therefore the above will successfully resolve. - // So in order to check if this was really successfull, we need to check if it has been properly ended. - if (!this.isAborted) { + // So in order to check if this was really successful, we need to check if it has been properly ended. + if (!this.isAborted && this.response) { this.response.rawBody = rawBody; + if (from !== this) { + this._downloadedSize = rawBody.byteLength; + } + if (shouldUseIncrementalDecodedBody) { + try { + const { decoder, chunks } = this._incrementalDecode; + const finalDecodedChunk = decoder.decode(); + if (finalDecodedChunk.length > 0) { + chunks.push(finalDecodedChunk); + } + cacheDecodedBody(this.response, chunks.join('')); + } + catch { } + } return true; } } catch { } + finally { + this._incrementalDecode = undefined; + } return false; } async _onResponse(response) { @@ -49472,7 +50217,7 @@ class Request extends external_node_stream_.Duplex { } catch (error) { /* istanbul ignore next: better safe than sorry */ - this._beforeError(error); + this._beforeError(normalizeError(error)); } } _onRequest(request) { @@ -49481,7 +50226,7 @@ class Request extends external_node_stream_.Duplex { // Publish request start event publishRequestStart({ requestId: this._requestId, - url: url?.toString() ?? '', + url: getSanitizedUrl(this.options), method: options.method, headers: options.headers, }); @@ -49499,77 +50244,336 @@ class Request extends external_node_stream_.Duplex { socket.removeAllListeners('timeout'); }); } + let lastRequestError; const responseEventName = options.cache ? 'cacheableResponse' : 'response'; request.once(responseEventName, (response) => { void this._onResponse(response); }); - request.once('error', (error) => { + const emitRequestError = (error) => { this._aborted = true; // Force clean-up, because some packages (e.g. nock) don't do this. request.destroy(); - error = error instanceof timed_out_TimeoutError ? new TimeoutError(error, this.timings, this) : new errors_RequestError(error.message, error, this); - this._beforeError(error); - }); - this._unproxyEvents = proxyEvents(request, this, proxiedRequestEvents); - this._request = request; + const wrappedError = error instanceof timed_out_TimeoutError ? new TimeoutError(error, this.timings, this) : new errors_RequestError(error.message, error, this); + this._beforeError(wrappedError); + }; + request.once('error', (error) => { + lastRequestError = error; + // Ignore errors from requests superseded by a redirect. + if (this._request !== request) { + return; + } + /* + Transient write errors (EPIPE, ECONNRESET) often fire during redirects when the + server closes the connection after sending the redirect response. Defer by one + microtask to let the response event make the request stale. + */ + if (isTransientWriteError(error)) { + queueMicrotask(() => { + if (this._isRequestStale(request)) { + return; + } + emitRequestError(error); + }); + return; + } + emitRequestError(error); + }); + if (!options.cache) { + request.once('close', () => { + if (this._request !== request || Boolean(request.res) || this._stopReading) { + return; + } + this._beforeError(lastRequestError ?? new ReadError({ + name: 'Error', + message: 'The server aborted pending request', + code: 'ECONNRESET', + }, this)); + }); + } + this._unproxyEvents = proxyEvents(request, this, proxiedRequestEvents); + this._request = request; + this.emit('uploadProgress', this.uploadProgress); + this._sendBody(); + this.emit('request', request); + } + _isRequestStale(request) { + return this._request !== request || Boolean(request.res) || request.destroyed || request.writableEnded; + } + async _asyncWrite(chunk, request = this) { + return new Promise((resolve, reject) => { + if (request === this) { + super.write(chunk, error => { + if (error) { + reject(error); + return; + } + resolve(); + }); + return; + } + this._writeRequest(chunk, undefined, error => { + if (error) { + reject(error); + return; + } + resolve(); + }, request); + }); + } + _sendBody() { + // Send body + const { body } = this.options; + const currentRequest = this.redirectUrls.length === 0 ? this : this._request ?? this; + if (distribution.nodeStream(body)) { + body.pipe(currentRequest); + } + else if (distribution.buffer(body)) { + // Buffer should be sent directly without conversion + this._writeBodyInChunks(body, currentRequest); + } + else if (distribution.typedArray(body)) { + // Typed arrays should be treated like buffers, not iterated over + // Create a Uint8Array view over the data (Node.js streams accept Uint8Array) + const typedArray = body; + const uint8View = new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength); + this._writeBodyInChunks(uint8View, currentRequest); + } + else if (distribution.asyncIterable(body) || (distribution.iterable(body) && !distribution.string(body) && !isBuffer(body))) { + (async () => { + const isInitialRequest = currentRequest === this; + try { + for await (const chunk of body) { + if (this.options.body !== body) { + return; + } + await this._asyncWrite(chunk, currentRequest); + if (this.options.body !== body) { + return; + } + } + if (this.options.body === body) { + if (isInitialRequest) { + super.end(); + return; + } + await this._endWritableRequest(currentRequest); + } + } + catch (error) { + if (this.options.body !== body) { + return; + } + this._beforeError(normalizeError(error)); + } + })(); + } + else if (distribution.undefined(body)) { + // No body to send, end the request + const cannotHaveBody = methodsWithoutBody.has(this.options.method) && !(this.options.method === 'GET' && this.options.allowGetBody); + if ((this._noPipe ?? false) || cannotHaveBody || currentRequest !== this) { + currentRequest.end(); + } + } + else { + // Handles string bodies (from json/form options). + this._writeBodyInChunks(stringToUint8Array(body), currentRequest); + } + } + /* + Write a body buffer in chunks to enable granular `uploadProgress` events. + + Without chunking, string/Uint8Array/TypedArray bodies are written in a single call, causing `uploadProgress` to only emit 0% and 100% with nothing in between. + + The 64 KB chunk size matches Node.js fs stream defaults. + */ + _writeBodyInChunks(buffer, currentRequest) { + const isInitialRequest = currentRequest === this; + (async () => { + let request; + try { + request = isInitialRequest ? this._request : currentRequest; + const activeRequest = request; + if (!activeRequest) { + if (isInitialRequest) { + super.end(); + } + return; + } + if (activeRequest.destroyed) { + return; + } + await this._writeChunksToRequest(buffer, activeRequest); + if (this._isRequestStale(activeRequest)) { + this._finalizeStaleChunkedWrite(activeRequest, isInitialRequest); + return; + } + if (isInitialRequest) { + super.end(); + return; + } + await this._endWritableRequest(activeRequest); + } + catch (error) { + const normalizedError = normalizeError(error); + // Transient write errors (EPIPE, ECONNRESET) are handled by the request-level + // error and close handlers. For initial redirected writes, still finalize + // writable state once the stale transition becomes observable. + if (isTransientWriteError(normalizedError)) { + if (isInitialRequest && request) { + const initialRequest = request; + let didFinalize = false; + const finalizeIfStale = () => { + if (didFinalize || !this._isRequestStale(initialRequest)) { + return; + } + didFinalize = true; + this._finalizeStaleChunkedWrite(initialRequest, true); + }; + finalizeIfStale(); + if (!didFinalize) { + initialRequest.once('response', finalizeIfStale); + queueMicrotask(finalizeIfStale); + } + } + return; + } + if (!isInitialRequest && this._isRequestStale(currentRequest)) { + return; + } + this._beforeError(normalizedError); + } + })(); + } + _finalizeStaleChunkedWrite(request, isInitialRequest) { + if (!request.destroyed && !request.writableEnded) { + request.destroy(); + } + if (isInitialRequest) { + // Finalize writable state without ending the active redirected request. + this._skipRequestEndInFinal = true; + super.end(); + } + } + _emitUploadComplete(request) { + this._bodySize = this._uploadedSize; this.emit('uploadProgress', this.uploadProgress); - this._sendBody(); - this.emit('request', request); + request.emit('upload-complete'); } - async _asyncWrite(chunk) { - return new Promise((resolve, reject) => { - super.write(chunk, error => { + async _endWritableRequest(request) { + await new Promise((resolve, reject) => { + request.end((error) => { if (error) { reject(error); return; } + if (this._request === request && !request.destroyed) { + this._emitUploadComplete(request); + } resolve(); }); }); } - _sendBody() { - // Send body - const { body } = this.options; - const currentRequest = this.redirectUrls.length === 0 ? this : this._request ?? this; - if (distribution.nodeStream(body)) { - body.pipe(currentRequest); + _stripCrossOriginState(options, urlToClear, bodyAlreadyDropped) { + for (const header of crossOriginStripHeaders) { + options.deleteInternalHeader(header); } - else if (distribution.buffer(body)) { - // Buffer should be sent directly without conversion - this._writeRequest(body, undefined, () => { }); - currentRequest.end(); + options.username = ''; + options.password = ''; + urlToClear.username = ''; + urlToClear.password = ''; + if (!bodyAlreadyDropped) { + this._dropBody(options); } - else if (distribution.typedArray(body)) { - // Typed arrays should be treated like buffers, not iterated over - // Create a Uint8Array view over the data (Node.js streams accept Uint8Array) - const typedArray = body; - const uint8View = new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength); - this._writeRequest(uint8View, undefined, () => { }); - currentRequest.end(); + } + _stripUnchangedCrossOriginState(options, urlToClear, bodyAlreadyDropped, state) { + const headers = options.getInternalHeaders(); + for (const header of crossOriginStripHeaders) { + if (!state.changedState.has(header) && headers[header] === state.headers[header]) { + options.deleteInternalHeader(header); + } + } + if (!state.preserveUsername) { + options.username = ''; + urlToClear.username = ''; + } + if (!state.preservePassword) { + options.password = ''; + urlToClear.password = ''; + } + if (!bodyAlreadyDropped + && !state.changedState.has('body') + && !state.changedState.has('json') + && !state.changedState.has('form') + && isBodyUnchanged(options, state)) { + this._dropBody(options); + } + } + _dropBody(updatedOptions) { + const { body } = this.options; + const hadOptionBody = !distribution.undefined(body) || !distribution.undefined(this.options.json) || !distribution.undefined(this.options.form); + this.options.clearBody(); + if (distribution.nodeStream(body)) { + body.off('error', this._onBodyError); + body.unpipe(); + body.on('error', core_noop); + body.destroy(); } else if (distribution.asyncIterable(body) || (distribution.iterable(body) && !distribution.string(body) && !isBuffer(body))) { - (async () => { + const iterableBody = body; + // Signal the iterator to clean up, but don't await it: + // the for-await loop in _sendBody exits via the options.body sentinel, + // and awaiting return() would deadlock when next() is pending. + if (typeof iterableBody.return === 'function') { try { - for await (const chunk of body) { - await this._asyncWrite(chunk); + const result = iterableBody.return(); + if (result instanceof Promise) { + // eslint-disable-next-line promise/prefer-await-to-then + result.catch(core_noop); } - super.end(); - } - catch (error) { - this._beforeError(error); } - })(); - } - else if (distribution.undefined(body)) { - // No body to send, end the request - const cannotHaveBody = methodsWithoutBody.has(this.options.method) && !(this.options.method === 'GET' && this.options.allowGetBody); - if ((this._noPipe ?? false) || cannotHaveBody || currentRequest !== this) { - currentRequest.end(); + catch { } } } + else if (!hadOptionBody && !this.writableEnded) { + this._skipRequestEndInFinal = true; + super.end(); + } + updatedOptions.clearBody(); + this._bodySize = undefined; + } + _onBodyError = (error) => { + if (this._flushed) { + this._beforeError(new UploadError(error, this)); + } else { - this._writeRequest(body, undefined, () => { }); - currentRequest.end(); + this.flush = async () => { + this.flush = async () => { }; + this._beforeError(new UploadError(error, this)); + }; + } + }; + async _writeChunksToRequest(buffer, request) { + const chunkSize = 65_536; // 64 KB + const isStale = () => this._isRequestStale(request); + for (const part of chunk(buffer, chunkSize)) { + if (isStale()) { + return; + } + // eslint-disable-next-line no-await-in-loop + await new Promise((resolve, reject) => { + this._writeRequest(part, undefined, error => { + if (isStale()) { + resolve(); + return; + } + if (error) { + reject(error); + } + else { + setImmediate(resolve); + } + }, request); + }); } } _prepareCache(cache) { @@ -49587,59 +50591,62 @@ class Request extends external_node_stream_.Duplex { Hooks use direct mutation - they can modify response.headers, response.statusCode, etc. Mutations take effect immediately and determine what gets cached. */ - const wrappedHandler = handler ? (response) => { - const { beforeCacheHooks, gotRequest } = requestOptions; - // Early return if no hooks - cache the original response - if (!beforeCacheHooks || beforeCacheHooks.length === 0) { - handler(response); - return; - } - try { - // Call each beforeCache hook with the response - // Hooks can directly mutate the response - mutations take effect immediately - for (const hook of beforeCacheHooks) { - const result = hook(response); - if (result === false) { - // Prevent caching by adding no-cache headers - // Mutate the response directly to add headers - response.headers['cache-control'] = 'no-cache, no-store, must-revalidate'; - response.headers.pragma = 'no-cache'; - response.headers.expires = '0'; - handler(response); - // Don't call remaining hooks - we've decided not to cache - return; - } - if (distribution.promise(result)) { - // BeforeCache hooks must be synchronous because cacheable-request's handler is synchronous - throw new TypeError('beforeCache hooks must be synchronous. The hook returned a Promise, but this hook must return synchronously. If you need async logic, use beforeRequest hook instead.'); - } - if (result !== undefined) { - // Hooks should return false or undefined only - // Mutations work directly - no need to return the response - throw new TypeError('beforeCache hook must return false or undefined. To modify the response, mutate it directly.'); + const wrappedHandler = handler + ? (response) => { + const { beforeCacheHooks, gotRequest } = requestOptions; + // Early return if no hooks - cache the original response + if (!beforeCacheHooks || beforeCacheHooks.length === 0) { + handler(response); + return; + } + try { + // Call each beforeCache hook with the response + // Hooks can directly mutate the response - mutations take effect immediately + for (const hook of beforeCacheHooks) { + const result = hook(response); + if (result === false) { + // Prevent caching by adding no-cache headers + // Mutate the response directly to add headers + response.headers['cache-control'] = 'no-cache, no-store, must-revalidate'; + response.headers.pragma = 'no-cache'; + response.headers.expires = '0'; + handler(response); + // Don't call remaining hooks - we've decided not to cache + return; + } + if (distribution.promise(result)) { + // BeforeCache hooks must be synchronous because cacheable-request's handler is synchronous + throw new TypeError('beforeCache hooks must be synchronous. The hook returned a Promise, but this hook must return synchronously. If you need async logic, use beforeRequest hook instead.'); + } + if (result !== undefined) { + // Hooks should return false or undefined only + // Mutations work directly - no need to return the response + throw new TypeError('beforeCache hook must return false or undefined. To modify the response, mutate it directly.'); + } + // Else: void/undefined = continue } - // Else: void/undefined = continue } - } - catch (error) { - // Convert hook errors to RequestError and propagate - // This is consistent with how other hooks handle errors - if (gotRequest) { - gotRequest._beforeError(error instanceof errors_RequestError ? error : new errors_RequestError(error.message, error, gotRequest)); - // Don't call handler when error was propagated successfully + catch (error) { + const normalizedError = normalizeError(error); + // Convert hook errors to RequestError and propagate + // This is consistent with how other hooks handle errors + if (gotRequest) { + gotRequest._beforeError(normalizedError instanceof errors_RequestError ? normalizedError : new errors_RequestError(normalizedError.message, normalizedError, gotRequest)); + // Don't call handler when error was propagated successfully + return; + } + // If gotRequest is missing, log the error to aid debugging + // We still call the handler to prevent the request from hanging + console.error('Got: beforeCache hook error (request context unavailable):', normalizedError); + // Call handler with response (potentially partially modified) + handler(response); return; } - // If gotRequest is missing, log the error to aid debugging - // We still call the handler to prevent the request from hanging - console.error('Got: beforeCache hook error (request context unavailable):', error); - // Call handler with response (potentially partially modified) + // All hooks ran successfully + // Cache the response with any mutations applied handler(response); - return; } - // All hooks ran successfully - // Cache the response with any mutations applied - handler(response); - } : handler; + : handler; const result = requestOptions._request(requestOptions, wrappedHandler); // TODO: remove this when `cacheable-request` supports async request functions. if (distribution.promise(result)) { @@ -49681,32 +50688,44 @@ class Request extends external_node_stream_.Duplex { } async _createCacheableRequest(url, options) { return new Promise((resolve, reject) => { - // TODO: Remove `utils/url-to-options.ts` when `cacheable-request` is fixed - Object.assign(options, urlToOptions(url)); + Object.assign(options, { + protocol: url.protocol, + hostname: distribution.string(url.hostname) && url.hostname.startsWith('[') ? url.hostname.slice(1, -1) : url.hostname, + host: url.host, + hash: url.hash === '' ? '' : (url.hash ?? null), + search: url.search === '' ? '' : (url.search ?? null), + pathname: url.pathname, + href: url.href, + path: `${url.pathname || ''}${url.search || ''}`, + ...(distribution.string(url.port) && url.port.length > 0 ? { port: Number(url.port) } : {}), + ...(url.username || url.password ? { auth: `${url.username || ''}:${url.password || ''}` } : {}), + }); let request; // TODO: Fix `cacheable-response`. This is ugly. - const cacheRequest = cacheableStore.get(options.cache)(options, async (response) => { - response._readableState.autoDestroy = false; - if (request) { - const fix = () => { - // For ResponseLike objects from cache, set complete to true if not already set. - // For real HTTP responses, copy from the underlying response. - if (response.req) { - response.complete = response.req.res.complete; - } - else if (response.complete === undefined) { - // ResponseLike from cache should have complete = true - response.complete = true; - } - }; - response.prependOnceListener('end', fix); - fix(); - (await request).emit('cacheableResponse', response); - } - resolve(response); + const cacheRequest = cacheableStore.get(options.cache)(options, (response) => { + void (async () => { + response._readableState.autoDestroy = false; + if (request) { + const fix = () => { + // For ResponseLike objects from cache, set complete to true if not already set. + // For real HTTP responses, copy from the underlying response. + if (response.req) { + response.complete = response.req.res.complete; + } + else if (response.complete === undefined) { + // ResponseLike from cache should have complete = true + response.complete = true; + } + }; + response.prependOnceListener('end', fix); + fix(); + (await request).emit('cacheableResponse', response); + } + resolve(response); + })(); }); cacheRequest.once('error', reject); - cacheRequest.once('request', async (requestOrPromise) => { + cacheRequest.once('request', (requestOrPromise) => { request = requestOrPromise; resolve(request); }); @@ -49714,17 +50733,63 @@ class Request extends external_node_stream_.Duplex { } async _makeRequest() { const { options } = this; - const { headers, username, password } = options; - const cookieJar = options.cookieJar; - for (const key in headers) { - if (distribution.undefined(headers[key])) { - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete - delete headers[key]; + const shouldDeleteGeneratedHeader = (currentHeader, generatedHeader) => currentHeader === generatedHeader || distribution.undefined(currentHeader); + const syncGeneratedHeader = (name, { currentHeader, explicitHeader, nextHeader, staleGeneratedHeader, }) => { + if (!distribution.undefined(nextHeader)) { + options.setInternalHeader(name, nextHeader); } - else if (distribution.null(headers[key])) { - throw new TypeError(`Use \`undefined\` instead of \`null\` to delete the \`${key}\` header`); + else if (!distribution.undefined(explicitHeader) && currentHeader === staleGeneratedHeader) { + options.setInternalHeader(name, explicitHeader); } - } + else if (shouldDeleteGeneratedHeader(currentHeader, staleGeneratedHeader)) { + options.deleteInternalHeader(name); + } + }; + const getAuthorizationHeader = (username, password, isExplicitlyOmitted) => !isExplicitlyOmitted && (username || password) + ? `Basic ${stringToBase64(`${username}:${password}`)}` + : undefined; + const sanitizeHeaders = () => { + const currentHeaders = options.getInternalHeaders(); + for (const key in currentHeaders) { + if (distribution.undefined(currentHeaders[key])) { + options.deleteInternalHeader(key); + } + else if (distribution.null(currentHeaders[key])) { + throw new TypeError(`Use \`undefined\` instead of \`null\` to delete the \`${key}\` header`); + } + else if (Array.isArray(currentHeaders[key]) && key === 'transfer-encoding') { + // Node serializes request header arrays as repeated field lines. Keep framing + // unambiguous by allowing only one transfer-encoding value here. + if (currentHeaders[key].length !== 1) { + throw new TypeError(`The \`${key}\` header must be a single value`); + } + options.setInternalHeader(key, currentHeaders[key][0]); + } + else if (Array.isArray(currentHeaders[key]) && singleValueRequestHeaders.has(key)) { + // Duplicate credential and content-length lines are not allowed on requests. + // Normalize a single-element array to match the long-supported string path. + if (currentHeaders[key].length !== 1) { + throw new TypeError(`The \`${key}\` header must be a single value`); + } + options.setInternalHeader(key, currentHeaders[key][0]); + } + } + return currentHeaders; + }; + const getCookieHeader = async (cookieJar) => { + if (!cookieJar) { + return undefined; + } + const cookieString = await cookieJar.getCookieString(options.url.toString()); + return distribution.nonEmptyString(cookieString) ? cookieString : undefined; + }; + const headers = sanitizeHeaders(); + const initialHeaders = options.getInternalHeaders(); + const authorizationWasInitiallyExplicit = options.isHeaderExplicitlySet('authorization'); + const explicitAuthorizationHeader = authorizationWasInitiallyExplicit ? initialHeaders.authorization : undefined; + const explicitCookieHeader = options.isHeaderExplicitlySet('cookie') ? initialHeaders.cookie : undefined; + const authorizationWasInitiallyOmitted = options.isHeaderExplicitlySet('authorization') && distribution.undefined(initialHeaders.authorization); + const cookieWasInitiallyOmitted = options.isHeaderExplicitlySet('cookie') && distribution.undefined(initialHeaders.cookie); if (options.decompress && distribution.undefined(headers['accept-encoding'])) { const encodings = ['gzip', 'deflate']; if (supportsBrotli) { @@ -49733,32 +50798,119 @@ class Request extends external_node_stream_.Duplex { if (core_supportsZstd) { encodings.push('zstd'); } - headers['accept-encoding'] = encodings.join(', '); + options.setInternalHeader('accept-encoding', encodings.join(', ')); } - if (username || password) { - const credentials = external_node_buffer_.Buffer.from(`${username}:${password}`).toString('base64'); - headers.authorization = `Basic ${credentials}`; - } - // Set cookies - if (cookieJar) { - const cookieString = await cookieJar.getCookieString(options.url.toString()); - if (distribution.nonEmptyString(cookieString)) { - headers.cookie = cookieString; + const { username, password } = options; + const cookieJar = options.cookieJar; + // Preserve an explicit Authorization header over URL-derived Basic auth. This keeps + // normalized single-element arrays aligned with the long-supported string behavior. + const generatedAuthorizationHeader = distribution.undefined(explicitAuthorizationHeader) + ? getAuthorizationHeader(username, password, authorizationWasInitiallyOmitted) + : undefined; + let generatedCookieHeader; + if (!distribution.undefined(generatedAuthorizationHeader)) { + options.setInternalHeader('authorization', generatedAuthorizationHeader); + } + if (!cookieWasInitiallyOmitted) { + generatedCookieHeader = await getCookieHeader(cookieJar); + if (!distribution.undefined(generatedCookieHeader)) { + options.setInternalHeader('cookie', generatedCookieHeader); } } let request; - for (const hook of options.hooks.beforeRequest) { - // eslint-disable-next-line no-await-in-loop - const result = await hook(options, { retryCount: this.retryCount }); - if (!distribution.undefined(result)) { - // @ts-expect-error Skip the type mismatch to support abstract responses - request = () => result; - break; + let shouldOmitRequestUrlCredentials = false; + const changedState = await options.trackStateMutations(async (changedState) => { + for (const hook of options.hooks.beforeRequest) { + // eslint-disable-next-line no-await-in-loop + const result = await hook(options, { retryCount: this.retryCount }); + if (!distribution.undefined(result)) { + // @ts-expect-error Skip the type mismatch to support abstract responses + request = () => result; + break; + } + } + return changedState; + }); + if (request === undefined) { + const currentHeaders = options.getInternalHeaders(); + // `headers.authorization = undefined` / `headers.cookie = undefined` is an + // explicit opt-out. Respect that instead of regenerating values from URL + // credentials or the cookie jar later in request setup. + const isHeaderExplicitlyOmitted = (header) => options.isHeaderExplicitlySet(header) + && Object.hasOwn(currentHeaders, header) + && distribution.undefined(currentHeaders[header]); + const currentAuthorizationHeader = currentHeaders.authorization; + const currentCookieHeader = currentHeaders.cookie; + // Authorization follows a small contract: + // - A concrete Authorization header is sent as-is. + // - `authorization = undefined` means omit Authorization entirely, including URL auth. + // - Deleting an Authorization header that started explicit also means omit it. + // - Otherwise, if the request did not start with explicit Authorization, Got may + // generate Basic auth from the current username/password. + const authorizationWasExplicitlyOmitted = isHeaderExplicitlyOmitted('authorization') + || (authorizationWasInitiallyExplicit && distribution.undefined(currentAuthorizationHeader)); + const cookieWasExplicitlyOmitted = distribution.undefined(currentCookieHeader) + && (cookieWasInitiallyOmitted || isHeaderExplicitlyOmitted('cookie')); + sanitizeHeaders(); + if (!distribution.undefined(currentHeaders['transfer-encoding']) && !distribution.undefined(currentHeaders['content-length'])) { + options.deleteInternalHeader('content-length'); + } + if (authorizationWasExplicitlyOmitted) { + shouldOmitRequestUrlCredentials = true; + options.deleteInternalHeader('authorization'); + if (changedState.has('authorization') && distribution.undefined(explicitAuthorizationHeader) && !authorizationWasInitiallyOmitted) { + delete options.headers.authorization; + } + } + const authorizationHeader = !authorizationWasInitiallyExplicit + && !authorizationWasInitiallyOmitted + && !authorizationWasExplicitlyOmitted + ? getAuthorizationHeader(options.username, options.password, authorizationWasExplicitlyOmitted) + : undefined; + const cookieJar = options.cookieJar; + if (changedState.has('authorization') && !distribution.undefined(currentAuthorizationHeader)) { + // A beforeRequest hook intentionally set the outgoing Authorization header. + } + else { + const restorableAuthorizationHeader = changedState.has('authorization') && distribution.undefined(currentAuthorizationHeader) + ? undefined + : explicitAuthorizationHeader; + syncGeneratedHeader('authorization', { + currentHeader: currentAuthorizationHeader, + explicitHeader: restorableAuthorizationHeader, + nextHeader: authorizationHeader, + staleGeneratedHeader: generatedAuthorizationHeader, + }); + } + if (cookieWasExplicitlyOmitted) { + options.deleteInternalHeader('cookie'); + if (changedState.has('cookie') && distribution.undefined(explicitCookieHeader) && !cookieWasInitiallyOmitted) { + delete options.headers.cookie; + } + } + else if (changedState.has('cookie')) { + // A beforeRequest hook intentionally set the outgoing Cookie header. + } + else { + const cookieHeader = !cookieWasInitiallyOmitted && !cookieWasExplicitlyOmitted + ? await getCookieHeader(cookieJar) + : undefined; + syncGeneratedHeader('cookie', { + currentHeader: currentCookieHeader, + explicitHeader: explicitCookieHeader, + nextHeader: cookieHeader, + staleGeneratedHeader: generatedCookieHeader, + }); } } - request ||= options.getRequestFunction(); - const url = options.url; + request ??= options.getRequestFunction(); + const url = shouldOmitRequestUrlCredentials + ? new URL(stripUrlAuth(options.url)) + : options.url; this._requestOptions = options.createNativeRequestOptions(); + if (shouldOmitRequestUrlCredentials) { + this._requestOptions.auth = undefined; + } if (options.cache) { this._requestOptions._request = request; this._requestOptions.cache = options.cache; @@ -49769,7 +50921,7 @@ class Request extends external_node_stream_.Duplex { this._prepareCache(options.cache); } catch (error) { - throw new CacheError(error, this); + throw new CacheError(normalizeError(error), this); } } // Cache support @@ -49781,13 +50933,6 @@ class Request extends external_node_stream_.Duplex { if (distribution.promise(requestOrResponse)) { requestOrResponse = await requestOrResponse; } - // Fallback - if (distribution.undefined(requestOrResponse)) { - requestOrResponse = options.getFallbackRequestFunction()(url, this._requestOptions); - if (distribution.promise(requestOrResponse)) { - requestOrResponse = await requestOrResponse; - } - } if (is_client_request(requestOrResponse)) { this._onRequest(requestOrResponse); } @@ -49810,12 +50955,9 @@ class Request extends external_node_stream_.Duplex { } async _error(error) { try { - if (this.options && error instanceof errors_HTTPError && !this.options.throwHttpErrors) { - // This branch can be reached only when using the Promise API - // Skip calling the hooks on purpose. - // See https://github.com/sindresorhus/got/issues/2103 - } - else if (this.options) { + // Skip calling hooks for HTTP errors when throwHttpErrors is false (Promise API only). + // See https://github.com/sindresorhus/got/issues/2103 + if (this.options && (!(error instanceof errors_HTTPError) || this.options.throwHttpErrors)) { const hooks = this.options.hooks.beforeError; if (hooks.length > 0) { for (const hook of hooks) { @@ -49836,12 +50978,13 @@ class Request extends external_node_stream_.Duplex { } } catch (error_) { - error = new errors_RequestError(error_.message, error_, this); + const normalizedError = normalizeError(error_); + error = new errors_RequestError(normalizedError.message, normalizedError, this); } // Publish error event publishError({ requestId: this._requestId, - url: this.options?.url?.toString() ?? '', + url: getSanitizedUrl(this.options), error, timings: this.timings, }); @@ -49857,16 +51000,17 @@ class Request extends external_node_stream_.Duplex { }); } } - _writeRequest(chunk, encoding, callback) { - if (!this._request || this._request.destroyed) { + _writeRequest(chunk, encoding, callback, request = this._request) { + if (!request || request.destroyed) { // When there's no request (e.g., using cached response from beforeRequest hook), // we still need to call the callback to allow the stream to finish properly. callback(); return; } - this._request.write(chunk, encoding, (error) => { - // The `!destroyed` check is required to prevent `uploadProgress` being emitted after the stream was destroyed - if (!error && !this._request.destroyed) { + request.write(chunk, encoding, (error) => { + // The `!destroyed` check is required to prevent `uploadProgress` being emitted after the stream was destroyed. + // The `this._request === request` check prevents stale write callbacks from a pre-redirect request from incrementing `_uploadedSize` after it's been reset. + if (!error && !request.destroyed && this._request === request) { // For strings, encode them first to measure the actual bytes that will be sent const bytes = typeof chunk === 'string' ? external_node_buffer_.Buffer.from(chunk, encoding) : chunk; this._uploadedSize += byteLength(bytes); @@ -49897,41 +51041,13 @@ class Request extends external_node_stream_.Duplex { Progress event for downloading (receiving a response). */ get downloadProgress() { - let percent; - if (this._responseSize) { - percent = this._downloadedSize / this._responseSize; - } - else if (this._responseSize === this._downloadedSize) { - percent = 1; - } - else { - percent = 0; - } - return { - percent, - transferred: this._downloadedSize, - total: this._responseSize, - }; + return makeProgress(this._downloadedSize, this._responseSize); } /** Progress event for uploading (sending a request). */ get uploadProgress() { - let percent; - if (this._bodySize) { - percent = this._uploadedSize / this._bodySize; - } - else if (this._bodySize === this._uploadedSize) { - percent = 1; - } - else { - percent = 0; - } - return { - percent, - transferred: this._uploadedSize, - total: this._bodySize, - }; + return makeProgress(this._uploadedSize, this._bodySize); } /** The object contains the following properties: @@ -49967,7 +51083,7 @@ class Request extends external_node_stream_.Duplex { Whether the response was retrieved from the cache. */ get isFromCache() { - return this._isFromCache; + return this.response?.isFromCache; } get reusedSocket() { return this._request?.reusedSocket; @@ -49980,25 +51096,6 @@ class Request extends external_node_stream_.Duplex { } } -;// CONCATENATED MODULE: ./node_modules/got/dist/source/as-promise/types.js - -/** -An error to be thrown when the request is aborted with `.cancel()`. -*/ -class types_CancelError extends errors_RequestError { - constructor(request) { - super('Promise was canceled', {}, request); - this.name = 'CancelError'; - this.code = 'ERR_CANCELED'; - } - /** - Whether the promise is canceled. - */ - get isCanceled() { - return true; - } -} - ;// CONCATENATED MODULE: ./node_modules/got/dist/source/as-promise/index.js @@ -50007,7 +51104,7 @@ class types_CancelError extends errors_RequestError { - +const compressedEncodings = new Set(['gzip', 'deflate', 'br', 'zstd']); const as_promise_proxiedRequestEvents = [ 'request', 'response', @@ -50018,97 +51115,116 @@ const as_promise_proxiedRequestEvents = [ function asPromise(firstRequest) { let globalRequest; let globalResponse; - let normalizedOptions; const emitter = new external_node_events_.EventEmitter(); let promiseSettled = false; - const promise = new PCancelable((resolve, reject, onCancel) => { - onCancel(() => { - globalRequest.destroy(); - }); - onCancel.shouldReject = false; - onCancel(() => { - promiseSettled = true; - reject(new types_CancelError(globalRequest)); - }); - const makeRequest = (retryCount) => { - // Errors when a new request is made after the promise settles. - // Used to detect a race condition. - // See https://github.com/sindresorhus/got/issues/1489 - onCancel(() => { }); - const request = firstRequest ?? new Request(undefined, undefined, normalizedOptions); + const promise = new Promise((resolve, reject) => { + const makeRequest = (retryCount, defaultOptions) => { + const request = firstRequest ?? new Request(undefined, undefined, defaultOptions); request.retryCount = retryCount; request._noPipe = true; globalRequest = request; - request.once('response', async (response) => { - // Parse body - const contentEncoding = (response.headers['content-encoding'] ?? '').toLowerCase(); - const isCompressed = contentEncoding === 'gzip' || contentEncoding === 'deflate' || contentEncoding === 'br' || contentEncoding === 'zstd'; - const { options } = request; - if (isCompressed && !options.decompress) { - response.body = response.rawBody; - } - else { - try { - response.body = parseBody(response, options.responseType, options.parseJson, options.encoding); + request.once('response', (response) => { + void (async () => { + // Parse body + const contentEncoding = (response.headers['content-encoding'] ?? '').toLowerCase(); + const isCompressed = compressedEncodings.has(contentEncoding); + const { options } = request; + if (isCompressed && !options.decompress) { + response.body = response.rawBody; } - catch (error) { - // Fall back to `utf8` + else { try { - response.body = response.rawBody.toString(); + response.body = parseBody(response, options.responseType, options.parseJson, options.encoding); } catch (error) { - request._beforeError(new ParseError(error, response)); - return; - } - if (isResponseOk(response)) { - request._beforeError(error); - return; + // Fall back to `utf8` + try { + response.body = decodeUint8Array(response.rawBody); + } + catch (error) { + request._beforeError(new ParseError(normalizeError(error), response)); + return; + } + if (isResponseOk(response)) { + request._beforeError(normalizeError(error)); + return; + } } } - } - try { - const hooks = options.hooks.afterResponse; - for (const [index, hook] of hooks.entries()) { - // @ts-expect-error TS doesn't notice that CancelableRequest is a Promise - // eslint-disable-next-line no-await-in-loop - response = await hook(response, async (updatedOptions) => { - const preserveHooks = updatedOptions.preserveHooks ?? false; - options.merge(updatedOptions); - options.prefixUrl = ''; - if (updatedOptions.url) { - options.url = updatedOptions.url; - } - // Remove any further hooks for that request, because we'll call them anyway. - // The loop continues. We don't want duplicates (asPromise recursion). - // Unless preserveHooks is true, in which case we keep the remaining hooks. - if (!preserveHooks) { - options.hooks.afterResponse = options.hooks.afterResponse.slice(0, index); + try { + const hooks = options.hooks.afterResponse; + for (const [index, hook] of hooks.entries()) { + const previousUrl = options.url ? new URL(options.url) : undefined; + const previousState = previousUrl ? snapshotCrossOriginState(options) : undefined; + const requestOptions = response.request.options; + const responseSnapshot = response; + // @ts-expect-error TS doesn't notice that RequestPromise is a Promise + // eslint-disable-next-line no-await-in-loop + response = await requestOptions.trackStateMutations(async (changedState) => hook(responseSnapshot, async (updatedOptions) => { + const preserveHooks = updatedOptions.preserveHooks ?? false; + const reusesRequestOptions = updatedOptions === requestOptions; + const hasExplicitBody = reusesRequestOptions + ? changedState.has('body') || changedState.has('json') || changedState.has('form') + : (Object.hasOwn(updatedOptions, 'body') && updatedOptions.body !== undefined) + || (Object.hasOwn(updatedOptions, 'json') && updatedOptions.json !== undefined) + || (Object.hasOwn(updatedOptions, 'form') && updatedOptions.form !== undefined); + const clearsCookieJar = Object.hasOwn(updatedOptions, 'cookieJar') && updatedOptions.cookieJar === undefined; + if (hasExplicitBody && !reusesRequestOptions) { + options.clearBody(); + } + if (!reusesRequestOptions && clearsCookieJar) { + options.cookieJar = undefined; + } + if (!reusesRequestOptions) { + options.merge(updatedOptions); + options.syncCookieHeaderAfterMerge(previousState, updatedOptions.headers); + } + options.clearUnchangedCookieHeader(previousState, reusesRequestOptions ? changedState : undefined); + if (updatedOptions.url) { + const nextUrl = reusesRequestOptions + ? options.url + : applyUrlOverride(options, updatedOptions.url, updatedOptions); + if (previousUrl) { + if (reusesRequestOptions && !isSameOrigin(previousUrl, nextUrl)) { + options.stripUnchangedCrossOriginState(previousState, changedState, { clearBody: !hasExplicitBody }); + } + else { + options.stripSensitiveHeaders(previousUrl, nextUrl, updatedOptions); + if (!isSameOrigin(previousUrl, nextUrl) && !hasExplicitBody) { + options.clearBody(); + } + } + } + } + // Remove any further hooks for that request, because we'll call them anyway. + // The loop continues. We don't want duplicates (asPromise recursion). + // Unless preserveHooks is true, in which case we keep the remaining hooks. + if (!preserveHooks) { + options.hooks.afterResponse = options.hooks.afterResponse.slice(0, index); + } + throw new RetryError(request); + })); + if (!(distribution.object(response) && distribution.number(response.statusCode) && 'body' in response)) { + throw new TypeError('The `afterResponse` hook returned an invalid value'); } - throw new RetryError(request); - }); - if (!(distribution.object(response) && distribution.number(response.statusCode) && 'body' in response)) { - throw new TypeError('The `afterResponse` hook returned an invalid value'); } } - } - catch (error) { - request._beforeError(error); - return; - } - globalResponse = response; - if (!isResponseOk(response)) { - request._beforeError(new errors_HTTPError(response)); - return; - } - request.destroy(); - promiseSettled = true; - resolve(request.options.resolveBodyOnly ? response.body : response); + catch (error) { + request._beforeError(normalizeError(error)); + return; + } + globalResponse = response; + if (!isResponseOk(response)) { + request._beforeError(new errors_HTTPError(response)); + return; + } + request.destroy(); + promiseSettled = true; + resolve(request.options.resolveBodyOnly ? response.body : response); + })(); }); let handledFinalError = false; const onError = (error) => { - if (promise.isCanceled) { - return; - } // Route errors emitted directly on the stream (e.g., EPIPE from Node.js) // through retry logic first, then handle them here after retries are exhausted. // See https://github.com/sindresorhus/got/issues/1995 @@ -50147,15 +51263,14 @@ function asPromise(firstRequest) { return; } const newBody = request.options.body; - if (previousBody === newBody && distribution.nodeStream(newBody)) { + if (previousBody === newBody && (distribution.nodeStream(newBody) || newBody instanceof ReadableStream)) { error.message = 'Cannot retry with consumed body stream'; onError(error); return; } // This is needed! We need to reuse `request.options` because they can get modified! // For example, by calling `promise.json()`. - normalizedOptions = request.options; - makeRequest(newRetryCount); + makeRequest(newRetryCount, request.options); }); proxyEvents(request, emitter, as_promise_proxiedRequestEvents); if (distribution.undefined(firstRequest)) { @@ -50164,19 +51279,27 @@ function asPromise(firstRequest) { }; makeRequest(0); }); - promise.on = (event, function_) => { + promise.on = function (event, function_) { emitter.on(event, function_); - return promise; + return this; + }; + promise.once = function (event, function_) { + emitter.once(event, function_); + return this; }; - promise.off = (event, function_) => { + promise.off = function (event, function_) { emitter.off(event, function_); - return promise; + return this; }; const shortcut = (promiseToAwait, responseType) => { const newPromise = (async () => { // Wait until downloading has ended await promiseToAwait; const { options } = globalResponse.request; + if (responseType === 'text') { + const text = decodeUint8Array(globalResponse.rawBody, options.encoding); + return (isUtf8Encoding(options.encoding) ? text.replace(/^\u{FEFF}/v, '') : text); + } return parseBody(globalResponse, responseType, options.parseJson, options.encoding); })(); // eslint-disable-next-line @typescript-eslint/no-floating-promises @@ -50220,6 +51343,22 @@ const aliases = [ 'head', 'delete', ]; +const optionsObjectUrlErrorMessage = 'The `url` option is not supported in options objects. Pass it as the first argument instead.'; +const assertNoUrlInOptionsObject = (options) => { + if (Object.hasOwn(options, 'url')) { + throw new TypeError(optionsObjectUrlErrorMessage); + } +}; +const cloneWithProperty = (value, property, propertyValue) => { + const clone = Object.create(Object.getPrototypeOf(value), Object.getOwnPropertyDescriptors(value)); + Object.defineProperty(clone, property, { + value: propertyValue, + enumerable: true, + configurable: true, + writable: true, + }); + return clone; +}; const create = (defaults) => { defaults = { options: new Options(undefined, undefined, defaults.options), @@ -50231,19 +51370,32 @@ const create = (defaults) => { configurable: false, writable: false, }); - // Got interface - const got = ((url, options, defaultOptions = defaults.options) => { - const request = new Request(url, options, defaultOptions); + const makeRequest = (url, options, defaultOptions, isStream) => { + if (distribution.plainObject(url)) { + assertNoUrlInOptionsObject(url); + } + if (distribution.plainObject(options)) { + assertNoUrlInOptionsObject(options); + } + // `isStream` is skipped by `merge()`, so set it via the direct setter after construction. + // Avoid a synthetic second merge only for the single-options-object stream form. + const requestUrl = isStream && distribution.plainObject(url) ? cloneWithProperty(url, 'isStream', true) : url; + const requestOptions = isStream && !distribution.plainObject(url) && options ? cloneWithProperty(options, 'isStream', true) : options; + const request = new Request(requestUrl, requestOptions, defaultOptions); + if (isStream && request.options) { + request.options.isStream = true; + } let promise; const lastHandler = (normalized) => { // Note: `options` is `undefined` when `new Options(...)` fails request.options = normalized; - request._noPipe = !normalized?.isStream; + const shouldReturnStream = normalized?.isStream ?? isStream; + request._noPipe = !shouldReturnStream; void request.flush(); - if (normalized?.isStream) { + if (shouldReturnStream) { return request; } - promise ||= asPromise(request); + promise ??= asPromise(request); return promise; }; let iteration = 0; @@ -50251,7 +51403,7 @@ const create = (defaults) => { const handler = defaults.handlers[iteration++] ?? lastHandler; const result = handler(newOptions, iterateHandlers); if (distribution.promise(result) && !request.options?.isStream) { - promise ||= asPromise(request); + promise ??= asPromise(request); if (result !== promise) { const descriptors = Object.getOwnPropertyDescriptors(promise); for (const key in descriptors) { @@ -50262,13 +51414,14 @@ const create = (defaults) => { } // eslint-disable-next-line @typescript-eslint/no-floating-promises Object.defineProperties(result, descriptors); - result.cancel = promise.cancel; } } return result; }; return iterateHandlers(request.options); - }); + }; + // Got interface + const got = ((url, options, defaultOptions = defaults.options) => makeRequest(url, options, defaultOptions, false)); got.extend = (...instancesOrOptions) => { const options = new Options(undefined, undefined, defaults.options); const handlers = [...defaults.handlers]; @@ -50280,6 +51433,7 @@ const create = (defaults) => { mutableDefaults = value.defaults.mutableDefaults; } else { + assertNoUrlInOptionsObject(value); options.merge(value); if (value.handlers) { handlers.push(...value.handlers); @@ -50295,6 +51449,12 @@ const create = (defaults) => { }; // Pagination const paginateEach = (async function* (url, options) { + if (distribution.plainObject(url)) { + assertNoUrlInOptionsObject(url); + } + if (distribution.plainObject(options)) { + assertNoUrlInOptionsObject(options); + } let normalizedOptions = new Options(url, options, defaults.options); normalizedOptions.resolveBodyOnly = false; const { pagination } = normalizedOptions; @@ -50334,21 +51494,47 @@ const create = (defaults) => { } } } - const optionsToMerge = pagination.paginate({ - response, - currentItems, - allItems, - }); + const requestOptions = response.request.options; + const previousUrl = requestOptions.url ? new URL(requestOptions.url) : undefined; + const previousState = previousUrl ? snapshotCrossOriginState(requestOptions) : undefined; + // eslint-disable-next-line no-await-in-loop + const [optionsToMerge, changedState] = await requestOptions.trackStateMutations(async (changedState) => [ + pagination.paginate({ + response, + currentItems, + allItems, + }), + changedState, + ]); if (optionsToMerge === false) { return; } if (optionsToMerge === response.request.options) { normalizedOptions = response.request.options; + normalizedOptions.clearUnchangedCookieHeader(previousState, changedState); + if (previousUrl) { + const nextUrl = normalizedOptions.url; + if (nextUrl && !isSameOrigin(previousUrl, nextUrl)) { + normalizedOptions.prefixUrl = ''; + normalizedOptions.stripUnchangedCrossOriginState(previousState, changedState); + } + } } else { + const hasExplicitBody = (Object.hasOwn(optionsToMerge, 'body') && optionsToMerge.body !== undefined) + || (Object.hasOwn(optionsToMerge, 'json') && optionsToMerge.json !== undefined) + || (Object.hasOwn(optionsToMerge, 'form') && optionsToMerge.form !== undefined); + const clearsCookieJar = Object.hasOwn(optionsToMerge, 'cookieJar') && optionsToMerge.cookieJar === undefined; + if (hasExplicitBody) { + normalizedOptions.clearBody(); + } + if (clearsCookieJar) { + normalizedOptions.cookieJar = undefined; + } normalizedOptions.merge(optionsToMerge); + normalizedOptions.syncCookieHeaderAfterMerge(previousState, optionsToMerge.headers); try { - assert.any([distribution.urlInstance, distribution.undefined], optionsToMerge.url); + assert.any([distribution.string, distribution.urlInstance, distribution.undefined], optionsToMerge.url); } catch (error) { if (error instanceof Error) { @@ -50357,29 +51543,28 @@ const create = (defaults) => { throw error; } if (optionsToMerge.url !== undefined) { - normalizedOptions.prefixUrl = ''; - normalizedOptions.url = optionsToMerge.url; + const nextUrl = applyUrlOverride(normalizedOptions, optionsToMerge.url, optionsToMerge); + if (previousUrl) { + normalizedOptions.stripSensitiveHeaders(previousUrl, nextUrl, optionsToMerge); + if (!isSameOrigin(previousUrl, nextUrl) && !hasExplicitBody) { + normalizedOptions.clearBody(); + } + } } } numberOfRequests++; } }); got.paginate = paginateEach; - got.paginate.all = (async (url, options) => { - const results = []; - for await (const item of paginateEach(url, options)) { - results.push(item); - } - return results; - }); + got.paginate.all = (async (url, options) => Array.fromAsync(paginateEach(url, options))); // For those who like very descriptive names got.paginate.each = paginateEach; // Stream API - got.stream = ((url, options) => got(url, { ...options, isStream: true })); + got.stream = ((url, options) => makeRequest(url, options, defaults.options, true)); // Shortcuts for (const method of aliases) { got[method] = ((url, options) => got(url, { ...options, method })); - got.stream[method] = ((url, options) => got(url, { ...options, method, isStream: true })); + got.stream[method] = ((url, options) => makeRequest(url, { ...options, method }, defaults.options, true)); } if (!defaults.mutableDefaults) { Object.freeze(defaults.handlers); @@ -50405,10 +51590,6 @@ const defaults = { }; const got = source_create(defaults); /* harmony default export */ const dist_source = (got); -// TODO: Remove this in the next major version. - - - @@ -50525,7 +51706,7 @@ const executableName = "enos"; const gitHubRepositoryOwner = "hashicorp"; const gitHubRepositoryRepo = "enos"; -const latestVersion = "0.0.36"; +const latestVersion = "0.0.37"; async function downloadReleaseAsset(client, releaseAsset, directory) { try { diff --git a/dist/licenses.txt b/dist/licenses.txt index 3ead635..a3a727b 100644 --- a/dist/licenses.txt +++ b/dist/licenses.txt @@ -650,7 +650,7 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -decompress-response +chunk-data MIT MIT License @@ -663,38 +663,27 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -fast-content-type-parse +decompress-response MIT MIT License -Copyright (c) 2023 The Fastify Team +Copyright (c) Sindre Sorhus (https://sindresorhus.com) -The Fastify team members are listed at https://github.com/fastify/fastify#team -and in the README file. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -form-data-encoder +fast-content-type-parse MIT -The MIT License (MIT) +MIT License -Copyright (c) 2021-present Nick K. +Copyright (c) 2023 The Fastify Team + +The Fastify team members are listed at https://github.com/fastify/fastify#team +and in the README file. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -714,7 +703,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - get-stream MIT MIT License @@ -882,19 +870,6 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -p-cancelable -MIT -MIT License - -Copyright (c) Sindre Sorhus (https://sindresorhus.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - quick-lru MIT MIT License @@ -992,6 +967,19 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +uint8array-extras +MIT +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + undici MIT MIT License diff --git a/eslint.config.js b/eslint.config.js index e2ff273..f6c7590 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,5 +1,5 @@ /** - * Copyright IBM Corp. 2022, 2025 + * Copyright IBM Corp. 2022, 2026 * SPDX-License-Identifier: MPL-2.0 */ diff --git a/package-lock.json b/package-lock.json index df8b56b..7294b97 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,44 +1,44 @@ { "name": "action-setup-enos", - "version": "1.52", + "version": "1.53", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "action-setup-enos", - "version": "1.52", + "version": "1.53", "license": "MPL-2.0", "dependencies": { - "@actions/core": "^3.0.0", + "@actions/core": "^3.0.1", "@actions/exec": "^3.0.0", - "@actions/http-client": "^4.0.0", + "@actions/http-client": "^4.0.1", "@actions/tool-cache": "^4.0.0", "@octokit/auth-unauthenticated": "^7.0.3", "@octokit/core": "^7.0.6", "@octokit/plugin-retry": "^8.1.0", "@octokit/plugin-throttling": "^11.0.3", - "got": "^14.6.6" + "got": "^15.0.5" }, "devDependencies": { "@eslint/eslintrc": "^3.3.5", "@eslint/js": "^10.0.1", "@octokit/rest": "^22.0.1", "@vercel/ncc": "^0.38.4", - "eslint": "^10.0.3", - "globals": "^17.4.0", - "nock": "^14.0.11", - "npm-check-updates": "^19.6.3", - "prettier": "^3.8.1", - "vitest": "^4.1.0" + "eslint": "^10.4.1", + "globals": "^17.6.0", + "nock": "^14.0.15", + "npm-check-updates": "^22.2.3", + "prettier": "^3.8.3", + "vitest": "^4.1.8" }, "engines": { "node": ">=24" } }, "node_modules/@actions/core": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-3.0.0.tgz", - "integrity": "sha512-zYt6cz+ivnTmiT/ksRVriMBOiuoUpDCJJlZ5KPl2/FRdvwU3f7MPh9qftvbkXJThragzUZieit2nyHUyw53Seg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-3.0.1.tgz", + "integrity": "sha512-a6d/Nwahm9fliVGRhdhofo40HjHQasUPusmc7vBfyky+7Z+P2A1J68zyFVaNcEclc/Se+eO595oAr5nwEIoIUA==", "license": "MIT", "dependencies": { "@actions/exec": "^3.0.0", @@ -55,9 +55,9 @@ } }, "node_modules/@actions/http-client": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-4.0.0.tgz", - "integrity": "sha512-QuwPsgVMsD6qaPD57GLZi9sqzAZCtiJT8kVBCDpLtxhL5MydQ4gS+DrejtZZPdIYyB1e95uCK9Luyds7ybHI3g==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-4.0.1.tgz", + "integrity": "sha512-+Nvd1ImaOZBSoPbsUtEhv+1z99H12xzncCkz0a3RuehINE81FZSe2QTj3uvAPTcJX/SCzUQHQ0D1GrPMbrPitg==", "license": "MIT", "dependencies": { "tunnel": "^0.0.6", @@ -84,21 +84,21 @@ } }, "node_modules/@emnapi/core": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.0.tgz", - "integrity": "sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.2.0", + "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.0.tgz", - "integrity": "sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "dev": true, "license": "MIT", "optional": true, @@ -107,9 +107,9 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", - "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", "dev": true, "license": "MIT", "optional": true, @@ -160,13 +160,13 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.23.3", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.3.tgz", - "integrity": "sha512-j+eEWmB6YYLwcNOdlwQ6L2OsptI/LO6lNBuLIqe5R7RetD658HLoF+Mn7LzYmAWWNNzdC6cqP+L6r8ujeYXWLw==", + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^3.0.3", + "@eslint/object-schema": "^3.0.5", "debug": "^4.3.1", "minimatch": "^10.2.4" }, @@ -185,9 +185,9 @@ } }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, "license": "MIT", "dependencies": { @@ -198,13 +198,13 @@ } }, "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^5.0.5" }, "engines": { "node": "18 || 20 || >=22" @@ -214,22 +214,22 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.3.tgz", - "integrity": "sha512-lzGN0onllOZCGroKJmRwY6QcEHxbjBw1gwB8SgRSqK8YbbtEXMvKynsXc3553ckIEBxsbMBU7oOZXKIPGZNeZw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.6.0.tgz", + "integrity": "sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^1.1.1" + "@eslint/core": "^1.2.1" }, "engines": { "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/core": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.1.tgz", - "integrity": "sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -298,9 +298,9 @@ } }, "node_modules/@eslint/object-schema": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.3.tgz", - "integrity": "sha512-iM869Pugn9Nsxbh/YHRqYiqd23AmIbxJOcpUMOuWCVNdoQJ5ZtwL6h3t0bcZzJUlC3Dq9jCFCESBZnX0GTv7iQ==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", "dev": true, "license": "Apache-2.0", "engines": { @@ -308,13 +308,13 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.6.1.tgz", - "integrity": "sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz", + "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^1.1.1", + "@eslint/core": "^1.2.1", "levn": "^0.4.1" }, "engines": { @@ -405,20 +405,22 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", - "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "funding": { "type": "github", "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" } }, "node_modules/@octokit/auth-token": { @@ -651,20 +653,10 @@ "dev": true, "license": "MIT" }, - "node_modules/@oxc-project/runtime": { - "version": "0.115.0", - "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.115.0.tgz", - "integrity": "sha512-Rg8Wlt5dCbXhQnsXPrkOjL1DTSvXLgb2R/KYfnf1/K+R0k6UMLEmbQXPM+kwrWqSmWA2t0B1EtHy2/3zikQpvQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, "node_modules/@oxc-project/types": { - "version": "0.115.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.115.0.tgz", - "integrity": "sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", + "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", "dev": true, "license": "MIT", "funding": { @@ -672,9 +664,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.9.tgz", - "integrity": "sha512-lcJL0bN5hpgJfSIz/8PIf02irmyL43P+j1pTCfbD1DbLkmGRuFIA4DD3B3ZOvGqG0XiVvRznbKtN0COQVaKUTg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", + "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", "cpu": [ "arm64" ], @@ -689,9 +681,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.9.tgz", - "integrity": "sha512-J7Zk3kLYFsLtuH6U+F4pS2sYVzac0qkjcO5QxHS7OS7yZu2LRs+IXo+uvJ/mvpyUljDJ3LROZPoQfgBIpCMhdQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", + "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", "cpu": [ "arm64" ], @@ -706,9 +698,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.9.tgz", - "integrity": "sha512-iwtmmghy8nhfRGeNAIltcNXzD0QMNaaA5U/NyZc1Ia4bxrzFByNMDoppoC+hl7cDiUq5/1CnFthpT9n+UtfFyg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", + "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", "cpu": [ "x64" ], @@ -723,9 +715,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.9.tgz", - "integrity": "sha512-DLFYI78SCiZr5VvdEplsVC2Vx53lnA4/Ga5C65iyldMVaErr86aiqCoNBLl92PXPfDtUYjUh+xFFor40ueNs4Q==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", + "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", "cpu": [ "x64" ], @@ -740,9 +732,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.9.tgz", - "integrity": "sha512-CsjTmTwd0Hri6iTw/DRMK7kOZ7FwAkrO4h8YWKoX/kcj833e4coqo2wzIFywtch/8Eb5enQ/lwLM7w6JX1W5RQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", + "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", "cpu": [ "arm" ], @@ -757,9 +749,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.9.tgz", - "integrity": "sha512-2x9O2JbSPxpxMDhP9Z74mahAStibTlrBMW0520+epJH5sac7/LwZW5Bmg/E6CXuEF53JJFW509uP+lSedaUNxg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", + "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", "cpu": [ "arm64" ], @@ -777,9 +769,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.9.tgz", - "integrity": "sha512-JA1QRW31ogheAIRhIg9tjMfsYbglXXYGNPLdPEYrwFxdbkQCAzvpSCSHCDWNl4hTtrol8WeboCSEpjdZK8qrCg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", + "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", "cpu": [ "arm64" ], @@ -797,9 +789,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.9.tgz", - "integrity": "sha512-aOKU9dJheda8Kj8Y3w9gnt9QFOO+qKPAl8SWd7JPHP+Cu0EuDAE5wokQubLzIDQWg2myXq2XhTpOVS07qqvT+w==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", + "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", "cpu": [ "ppc64" ], @@ -817,9 +809,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.9.tgz", - "integrity": "sha512-OalO94fqj7IWRn3VdXWty75jC5dk4C197AWEuMhIpvVv2lw9fiPhud0+bW2ctCxb3YoBZor71QHbY+9/WToadA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", + "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", "cpu": [ "s390x" ], @@ -837,9 +829,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.9.tgz", - "integrity": "sha512-cVEl1vZtBsBZna3YMjGXNvnYYrOJ7RzuWvZU0ffvJUexWkukMaDuGhUXn0rjnV0ptzGVkvc+vW9Yqy6h8YX4pg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", + "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", "cpu": [ "x64" ], @@ -857,9 +849,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.9.tgz", - "integrity": "sha512-UzYnKCIIc4heAKgI4PZ3dfBGUZefGCJ1TPDuLHoCzgrMYPb5Rv6TLFuYtyM4rWyHM7hymNdsg5ik2C+UD9VDbA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", + "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", "cpu": [ "x64" ], @@ -877,9 +869,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.9.tgz", - "integrity": "sha512-+6zoiF+RRyf5cdlFQP7nm58mq7+/2PFaY2DNQeD4B87N36JzfF/l9mdBkkmTvSYcYPE8tMh/o3cRlsx1ldLfog==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", + "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", "cpu": [ "arm64" ], @@ -894,9 +886,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.9.tgz", - "integrity": "sha512-rgFN6sA/dyebil3YTlL2evvi/M+ivhfnyxec7AccTpRPccno/rPoNlqybEZQBkcbZu8Hy+eqNJCqfBR8P7Pg8g==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", + "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", "cpu": [ "wasm32" ], @@ -904,16 +896,18 @@ "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^1.1.1" + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.9.tgz", - "integrity": "sha512-lHVNUG/8nlF1IQk1C0Ci574qKYyty2goMiPlRqkC5R+3LkXDkL5Dhx8ytbxq35m+pkHVIvIxviD+TWLdfeuadA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", + "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", "cpu": [ "arm64" ], @@ -928,9 +922,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.9.tgz", - "integrity": "sha512-G0oA4+w1iY5AGi5HcDTxWsoxF509hrFIPB2rduV5aDqS9FtDg1CAfa7V34qImbjfhIcA8C+RekocJZA96EarwQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", + "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", "cpu": [ "x64" ], @@ -945,9 +939,9 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.9.tgz", - "integrity": "sha512-w6oiRWgEBl04QkFZgmW+jnU1EC9b57Oihi2ot3HNWIQRqgHp5PnYDia5iZ5FF7rpa4EQdiqMDXjlqKGXBhsoXw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "dev": true, "license": "MIT" }, @@ -958,12 +952,12 @@ "license": "MIT" }, "node_modules/@sindresorhus/is": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.2.0.tgz", - "integrity": "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-8.1.0.tgz", + "integrity": "sha512-2SX/1jW6CIMAiebvVv5ZInoCEuWQmMyBoJXXGC6Vjakjp/fpxP5eHs7/V6WKuPEIbuK06+VpjH+vjLQhr98rDQ==", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=22" }, "funding": { "url": "https://github.com/sindresorhus/is?sponsor=1" @@ -977,9 +971,9 @@ "license": "MIT" }, "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", "dev": true, "license": "MIT", "optional": true, @@ -1043,31 +1037,31 @@ } }, "node_modules/@vitest/expect": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.0.tgz", - "integrity": "sha512-EIxG7k4wlWweuCLG9Y5InKFwpMEOyrMb6ZJ1ihYu02LVj/bzUwn2VMU+13PinsjRW75XnITeFrQBMH5+dLvCDA==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.8.tgz", + "integrity": "sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.0", - "@vitest/utils": "4.1.0", + "@vitest/spy": "4.1.8", + "@vitest/utils": "4.1.8", "chai": "^6.2.2", - "tinyrainbow": "^3.0.3" + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/mocker": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.0.tgz", - "integrity": "sha512-evxREh+Hork43+Y4IOhTo+h5lGmVRyjqI739Rz4RlUPqwrkFFDF6EMvOOYjTx4E8Tl6gyCLRL8Mu7Ry12a13Tw==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.8.tgz", + "integrity": "sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.0", + "@vitest/spy": "4.1.8", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -1076,7 +1070,7 @@ }, "peerDependencies": { "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0-0" + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "msw": { @@ -1088,26 +1082,26 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.0.tgz", - "integrity": "sha512-3RZLZlh88Ib0J7NQTRATfc/3ZPOnSUn2uDBUoGNn5T36+bALixmzphN26OUD3LRXWkJu4H0s5vvUeqBiw+kS0A==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.8.tgz", + "integrity": "sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==", "dev": true, "license": "MIT", "dependencies": { - "tinyrainbow": "^3.0.3" + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/runner": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.0.tgz", - "integrity": "sha512-Duvx2OzQ7d6OjchL+trw+aSrb9idh7pnNfxrklo14p3zmNL4qPCDeIJAK+eBKYjkIwG96Bc6vYuxhqDXQOWpoQ==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.8.tgz", + "integrity": "sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.0", + "@vitest/utils": "4.1.8", "pathe": "^2.0.3" }, "funding": { @@ -1115,14 +1109,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.0.tgz", - "integrity": "sha512-0Vy9euT1kgsnj1CHttwi9i9o+4rRLEaPRSOJ5gyv579GJkNpgJK+B4HSv/rAWixx2wdAFci1X4CEPjiu2bXIMg==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.8.tgz", + "integrity": "sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.0", - "@vitest/utils": "4.1.0", + "@vitest/pretty-format": "4.1.8", + "@vitest/utils": "4.1.8", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -1131,9 +1125,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.0.tgz", - "integrity": "sha512-pz77k+PgNpyMDv2FV6qmk5ZVau6c3R8HC8v342T2xlFxQKTrSeYw9waIJG8KgV9fFwAtTu4ceRzMivPTH6wSxw==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.8.tgz", + "integrity": "sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==", "dev": true, "license": "MIT", "funding": { @@ -1141,15 +1135,15 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.0.tgz", - "integrity": "sha512-XfPXT6a8TZY3dcGY8EdwsBulFCIw+BeeX0RZn2x/BtiY/75YGh8FeWGG8QISN/WhaqSrE2OrlDgtF8q5uhOTmw==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.8.tgz", + "integrity": "sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.0", + "@vitest/pretty-format": "4.1.8", "convert-source-map": "^2.0.0", - "tinyrainbow": "^3.0.3" + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" @@ -1232,9 +1226,9 @@ "license": "MIT" }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -1310,6 +1304,18 @@ "node": ">=18" } }, + "node_modules/chunk-data": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chunk-data/-/chunk-data-0.1.0.tgz", + "integrity": "sha512-zFyPtyC0SZ6Zu79b9sOYtXZcgrsXe0RpePrzRyj52hYVFG1+Rk6rBqjjOEk+GNQwc3PIX+86teQMok970pod1g==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1410,18 +1416,18 @@ } }, "node_modules/eslint": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.0.3.tgz", - "integrity": "sha512-COV33RzXZkqhG9P2rZCFl9ZmJ7WL+gQSCRzE7RhkbclbQPtLAWReL7ysA0Sh4c8Im2U9ynybdR56PV0XcKvqaQ==", + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.4.1.tgz", + "integrity": "sha512-AyIKhnOBuOAdueD7RB3xB+YeAWScb9jHsJBgH2Hcde8InP5JYhqrRR6iTMHyTEwgENK54Cp44e4v8BwNhsuHuw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", - "@eslint/config-array": "^0.23.3", - "@eslint/config-helpers": "^0.5.2", - "@eslint/core": "^1.1.1", - "@eslint/plugin-kit": "^0.6.1", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.6.0", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.2", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -1432,7 +1438,7 @@ "escape-string-regexp": "^4.0.0", "eslint-scope": "^9.1.2", "eslint-visitor-keys": "^5.0.1", - "espree": "^11.1.1", + "espree": "^11.2.0", "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -1508,9 +1514,9 @@ } }, "node_modules/eslint/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, "license": "MIT", "dependencies": { @@ -1751,21 +1757,12 @@ } }, "node_modules/flatted": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.1.tgz", - "integrity": "sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, "license": "ISC" }, - "node_modules/form-data-encoder": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-4.1.0.tgz", - "integrity": "sha512-G6NsmEW15s0Uw9XnCg+33H3ViYRyiM0hMrMhhqQOR8NFc5GhYrI+6I3u7OTw7b91J2g8rtvMBZJDbcGb2YUniw==", - "license": "MIT", - "engines": { - "node": ">= 18" - } - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1811,9 +1808,9 @@ } }, "node_modules/globals": { - "version": "17.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.4.0.tgz", - "integrity": "sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.6.0.tgz", + "integrity": "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==", "dev": true, "license": "MIT", "engines": { @@ -1824,26 +1821,26 @@ } }, "node_modules/got": { - "version": "14.6.6", - "resolved": "https://registry.npmjs.org/got/-/got-14.6.6.tgz", - "integrity": "sha512-QLV1qeYSo5l13mQzWgP/y0LbMr5Plr5fJilgAIwgnwseproEbtNym8xpLsDzeZ6MWXgNE6kdWGBjdh3zT/Qerg==", + "version": "15.0.5", + "resolved": "https://registry.npmjs.org/got/-/got-15.0.5.tgz", + "integrity": "sha512-PMIMaZuYUCK43+Z9JWEXea4kkX2b3301m81D5TS6QpfG4PmNyirzEdO/Oa2OHAN4GsjnPfvWCWsshKN2rq4/gQ==", "license": "MIT", "dependencies": { - "@sindresorhus/is": "^7.0.1", + "@sindresorhus/is": "^8.0.0", "byte-counter": "^0.1.0", "cacheable-lookup": "^7.0.0", - "cacheable-request": "^13.0.12", + "cacheable-request": "^13.0.18", + "chunk-data": "^0.1.0", "decompress-response": "^10.0.0", - "form-data-encoder": "^4.0.2", "http2-wrapper": "^2.2.1", - "keyv": "^5.5.3", - "lowercase-keys": "^3.0.0", - "p-cancelable": "^4.0.1", + "keyv": "^5.6.0", + "lowercase-keys": "^4.0.1", "responselike": "^4.0.2", - "type-fest": "^4.26.1" + "type-fest": "^5.6.0", + "uint8array-extras": "^1.5.0" }, "engines": { - "node": ">=20" + "node": ">=22" }, "funding": { "url": "https://github.com/sindresorhus/got?sponsor=1" @@ -1858,6 +1855,18 @@ "@keyv/serialize": "^1.1.1" } }, + "node_modules/got/node_modules/lowercase-keys": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-4.0.1.tgz", + "integrity": "sha512-wI9Nui/L8VfADa/cr/7NQruaASk1k23/Uh1khQ02BCVYiiy8F4AhOGnQzJy3Fl/c44GnYSbZHv8g7EcG3kJ1Qg==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/http-cache-semantics": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", @@ -2378,9 +2387,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", "dev": true, "funding": [ { @@ -2404,9 +2413,9 @@ "license": "MIT" }, "node_modules/nock": { - "version": "14.0.11", - "resolved": "https://registry.npmjs.org/nock/-/nock-14.0.11.tgz", - "integrity": "sha512-u5xUnYE+UOOBA6SpELJheMCtj2Laqx15Vl70QxKo43Wz/6nMHXS7PrEioXLjXAwhmawdEMNImwKCcPhBJWbKVw==", + "version": "14.0.15", + "resolved": "https://registry.npmjs.org/nock/-/nock-14.0.15.tgz", + "integrity": "sha512-S0a47C9pLvcYx/Ugf0H30BVBEcUgMMBDk9VJIDlJ8XGrfH2QDUD4Tgdp45qDIiHttokBG+IbsOtsvIjGR/j3bg==", "dev": true, "license": "MIT", "dependencies": { @@ -2431,9 +2440,9 @@ } }, "node_modules/npm-check-updates": { - "version": "19.6.3", - "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-19.6.3.tgz", - "integrity": "sha512-VAt9Bp26eLaymZ0nZyh5n/by+YZIuegXlvWR0yv1zBqd984f8VnEnBbn+1lS3nN5LyEjn62BJ+yYgzNSpb6Gzg==", + "version": "22.2.3", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-22.2.3.tgz", + "integrity": "sha512-n8HZ0ywZugYRgEqIm67hbZC5L/9S/gLX+MkGchJB43pP2xib1+u76OpVEJRZ4QP2BksPRi5M1CCStJVfc16+/A==", "dev": true, "license": "Apache-2.0", "bin": { @@ -2441,8 +2450,8 @@ "npm-check-updates": "build/cli.js" }, "engines": { - "node": ">=20.0.0", - "npm": ">=8.12.1" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": ">=10.0.0" } }, "node_modules/obug": { @@ -2481,15 +2490,6 @@ "dev": true, "license": "MIT" }, - "node_modules/p-cancelable": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-4.0.1.tgz", - "integrity": "sha512-wBowNApzd45EIKdO1LaU+LrMBwAcjfPaYtVzV3lmfM3gf8Z4CHZsiIqlM8TZZ8okYvh5A1cP6gTfCRQtwUpaUg==", - "license": "MIT", - "engines": { - "node": ">=14.16" - } - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -2570,9 +2570,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -2583,9 +2583,9 @@ } }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "dev": true, "funding": [ { @@ -2603,7 +2603,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -2622,9 +2622,9 @@ } }, "node_modules/prettier": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", - "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", + "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", "dev": true, "license": "MIT", "bin": { @@ -2701,14 +2701,14 @@ } }, "node_modules/rolldown": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.9.tgz", - "integrity": "sha512-9EbgWge7ZH+yqb4d2EnELAntgPTWbfL8ajiTW+SyhJEC4qhBbkCKbqFV4Ge4zmu5ziQuVbWxb/XwLZ+RIO7E8Q==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", + "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.115.0", - "@rolldown/pluginutils": "1.0.0-rc.9" + "@oxc-project/types": "=0.133.0", + "@rolldown/pluginutils": "^1.0.0" }, "bin": { "rolldown": "bin/cli.mjs" @@ -2717,21 +2717,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.9", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.9", - "@rolldown/binding-darwin-x64": "1.0.0-rc.9", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.9", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.9", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.9", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.9", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.9", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.9", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.9", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.9", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.9", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.9", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.9", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.9" + "@rolldown/binding-android-arm64": "1.0.3", + "@rolldown/binding-darwin-arm64": "1.0.3", + "@rolldown/binding-darwin-x64": "1.0.3", + "@rolldown/binding-freebsd-x64": "1.0.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", + "@rolldown/binding-linux-arm64-gnu": "1.0.3", + "@rolldown/binding-linux-arm64-musl": "1.0.3", + "@rolldown/binding-linux-ppc64-gnu": "1.0.3", + "@rolldown/binding-linux-s390x-gnu": "1.0.3", + "@rolldown/binding-linux-x64-gnu": "1.0.3", + "@rolldown/binding-linux-x64-musl": "1.0.3", + "@rolldown/binding-openharmony-arm64": "1.0.3", + "@rolldown/binding-wasm32-wasi": "1.0.3", + "@rolldown/binding-win32-arm64-msvc": "1.0.3", + "@rolldown/binding-win32-x64-msvc": "1.0.3" } }, "node_modules/semver": { @@ -2820,6 +2820,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/tagged-tag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", + "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -2838,14 +2850,14 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -2895,12 +2907,27 @@ } }, "node_modules/type-fest": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.7.0.tgz", + "integrity": "sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg==", "license": "(MIT OR CC0-1.0)", + "dependencies": { + "tagged-tag": "^1.0.0" + }, "engines": { - "node": ">=16" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/uint8array-extras": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", + "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==", + "license": "MIT", + "engines": { + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2932,18 +2959,17 @@ } }, "node_modules/vite": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.0.tgz", - "integrity": "sha512-fPGaRNj9Zytaf8LEiBhY7Z6ijnFKdzU/+mL8EFBaKr7Vw1/FWcTBAMW0wLPJAGMPX38ZPVCVgLceWiEqeoqL2Q==", + "version": "8.0.16", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", + "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/runtime": "0.115.0", "lightningcss": "^1.32.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.8", - "rolldown": "1.0.0-rc.9", - "tinyglobby": "^0.2.15" + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "1.0.3", + "tinyglobby": "^0.2.17" }, "bin": { "vite": "bin/vite.js" @@ -2959,8 +2985,8 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.0.0-alpha.31", - "esbuild": "^0.27.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", @@ -3011,19 +3037,19 @@ } }, "node_modules/vitest": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.0.tgz", - "integrity": "sha512-YbDrMF9jM2Lqc++2530UourxZHmkKLxrs4+mYhEwqWS97WJ7wOYEkcr+QfRgJ3PW9wz3odRijLZjHEaRLTNbqw==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.8.tgz", + "integrity": "sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.0", - "@vitest/mocker": "4.1.0", - "@vitest/pretty-format": "4.1.0", - "@vitest/runner": "4.1.0", - "@vitest/snapshot": "4.1.0", - "@vitest/spy": "4.1.0", - "@vitest/utils": "4.1.0", + "@vitest/expect": "4.1.8", + "@vitest/mocker": "4.1.8", + "@vitest/pretty-format": "4.1.8", + "@vitest/runner": "4.1.8", + "@vitest/snapshot": "4.1.8", + "@vitest/spy": "4.1.8", + "@vitest/utils": "4.1.8", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -3034,8 +3060,8 @@ "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.0.3", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0-0", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "bin": { @@ -3051,13 +3077,15 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.0", - "@vitest/browser-preview": "4.1.0", - "@vitest/browser-webdriverio": "4.1.0", - "@vitest/ui": "4.1.0", + "@vitest/browser-playwright": "4.1.8", + "@vitest/browser-preview": "4.1.8", + "@vitest/browser-webdriverio": "4.1.8", + "@vitest/coverage-istanbul": "4.1.8", + "@vitest/coverage-v8": "4.1.8", + "@vitest/ui": "4.1.8", "happy-dom": "*", "jsdom": "*", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0-0" + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "@edge-runtime/vm": { @@ -3078,6 +3106,12 @@ "@vitest/browser-webdriverio": { "optional": true }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, "@vitest/ui": { "optional": true }, diff --git a/package.json b/package.json index c70ed38..1a532ac 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "action-setup-enos", "type": "module", - "version": "1.52", + "version": "1.53", "description": "Setup Enos CLI for GitHub Actions", "scripts": { "all": "npm run build && npm run ci", @@ -9,7 +9,7 @@ "ci": "npm run lint && npm run format:check && npm run test", "format:write": "npx prettier --write .", "format:check": "npx prettier --check .", - "headers": "copywrite_ibm headers --year1 2022 --year2 2025", + "headers": "copywrite_ibm headers --year1 2022 --year2 2026", "lint": "npx eslint ./src", "prepare": "npx ncc build src/index.js -o dist --license licenses.txt", "test": "npx vitest run" @@ -37,15 +37,15 @@ }, "homepage": "https://github.com/hashicorp/action-setup-enos#readme", "dependencies": { - "@actions/core": "^3.0.0", + "@actions/core": "^3.0.1", "@actions/exec": "^3.0.0", - "@actions/http-client": "^4.0.0", + "@actions/http-client": "^4.0.1", "@actions/tool-cache": "^4.0.0", "@octokit/auth-unauthenticated": "^7.0.3", "@octokit/core": "^7.0.6", "@octokit/plugin-retry": "^8.1.0", "@octokit/plugin-throttling": "^11.0.3", - "got": "^14.6.6" + "got": "^15.0.5" }, "overrides": { "undici": "^6.24.0" @@ -55,11 +55,11 @@ "@eslint/js": "^10.0.1", "@octokit/rest": "^22.0.1", "@vercel/ncc": "^0.38.4", - "eslint": "^10.0.3", - "globals": "^17.4.0", - "nock": "^14.0.11", - "npm-check-updates": "^19.6.3", - "prettier": "^3.8.1", - "vitest": "^4.1.0" + "eslint": "^10.4.1", + "globals": "^17.6.0", + "nock": "^14.0.15", + "npm-check-updates": "^22.2.3", + "prettier": "^3.8.3", + "vitest": "^4.1.8" } } diff --git a/src/enos.js b/src/enos.js index db4c379..0255476 100644 --- a/src/enos.js +++ b/src/enos.js @@ -13,7 +13,7 @@ const executableName = "enos"; const gitHubRepositoryOwner = "hashicorp"; const gitHubRepositoryRepo = "enos"; -export const latestVersion = "0.0.36"; +export const latestVersion = "0.0.37"; export async function downloadReleaseAsset(client, releaseAsset, directory) { try { diff --git a/src/github-release.js b/src/github-release.js index 3bffaca..390d0ff 100644 --- a/src/github-release.js +++ b/src/github-release.js @@ -1,5 +1,5 @@ /** - * Copyright IBM Corp. 2022, 2025 + * Copyright IBM Corp. 2022, 2026 * SPDX-License-Identifier: MPL-2.0 */ diff --git a/src/github-release.test.js b/src/github-release.test.js index 05aaa53..62562a4 100644 --- a/src/github-release.test.js +++ b/src/github-release.test.js @@ -1,5 +1,5 @@ /** - * Copyright IBM Corp. 2022, 2025 + * Copyright IBM Corp. 2022, 2026 * SPDX-License-Identifier: MPL-2.0 */ diff --git a/src/index.js b/src/index.js index f31a5f2..98b61a5 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,5 @@ /** - * Copyright IBM Corp. 2022, 2025 + * Copyright IBM Corp. 2022, 2026 * SPDX-License-Identifier: MPL-2.0 */ diff --git a/src/main.js b/src/main.js index f03f22d..426ae74 100644 --- a/src/main.js +++ b/src/main.js @@ -1,5 +1,5 @@ /** - * Copyright IBM Corp. 2022, 2025 + * Copyright IBM Corp. 2022, 2026 * SPDX-License-Identifier: MPL-2.0 */ diff --git a/src/octokit.js b/src/octokit.js index c5b4f00..e5fe741 100644 --- a/src/octokit.js +++ b/src/octokit.js @@ -1,5 +1,5 @@ /** - * Copyright IBM Corp. 2022, 2025 + * Copyright IBM Corp. 2022, 2026 * SPDX-License-Identifier: MPL-2.0 */ diff --git a/vitest.config.mjs b/vitest.config.mjs index 57226ba..4ff4e88 100644 --- a/vitest.config.mjs +++ b/vitest.config.mjs @@ -1,5 +1,5 @@ /** - * Copyright IBM Corp. 2022, 2025 + * Copyright IBM Corp. 2022, 2026 * SPDX-License-Identifier: MPL-2.0 */