You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

ky

Package Overview
Dependencies
Maintainers
1
Versions
95
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ky - npm Package Compare versions

Comparing version
1.14.1
to
1.14.2
+43
-21
distribution/core/Ky.js

@@ -27,17 +27,31 @@ import { HTTPError } from '../errors/HTTPError.js';

const clonedResponse = ky.#decorateResponse(response.clone());
// eslint-disable-next-line no-await-in-loop
const modifiedResponse = await hook(ky.request, ky.#getNormalizedOptions(), clonedResponse, { retryCount: ky.#retryCount });
if (modifiedResponse instanceof globalThis.Response) {
response = modifiedResponse;
let modifiedResponse;
try {
// eslint-disable-next-line no-await-in-loop
modifiedResponse = await hook(ky.request, ky.#getNormalizedOptions(), clonedResponse, { retryCount: ky.#retryCount });
}
catch (error) {
// Cancel both responses to prevent memory leaks when hook throws
ky.#cancelResponseBody(clonedResponse);
ky.#cancelResponseBody(response);
throw error;
}
if (modifiedResponse instanceof RetryMarker) {
// Cancel both the cloned response passed to the hook and the current response
// to prevent resource leaks (especially important in Deno/Bun)
// eslint-disable-next-line no-await-in-loop
await Promise.all([
clonedResponse.body?.cancel(),
response.body?.cancel(),
]);
// Cancel both the cloned response passed to the hook and the current response to prevent resource leaks (especially important in Deno/Bun).
// Do not await cancellation since hooks can clone the response, leaving extra tee branches that keep cancel promises pending per the Streams spec.
ky.#cancelResponseBody(clonedResponse);
ky.#cancelResponseBody(response);
throw new ForceRetryError(modifiedResponse.options);
}
// Determine which response to use going forward
const nextResponse = modifiedResponse instanceof globalThis.Response ? modifiedResponse : response;
// Cancel any response bodies we won't use to prevent memory leaks.
// Uses fire-and-forget since hooks may have cloned the response, creating tee branches that block cancellation.
if (clonedResponse !== nextResponse) {
ky.#cancelResponseBody(clonedResponse);
}
if (response !== nextResponse) {
ky.#cancelResponseBody(response);
}
response = nextResponse;
}

@@ -63,3 +77,5 @@ ky.#decorateResponse(response);

}
return streamResponse(response.clone(), ky.#options.onDownloadProgress);
const progressResponse = response.clone();
ky.#cancelResponseBody(response);
return streamResponse(progressResponse, ky.#options.onDownloadProgress);
}

@@ -71,12 +87,7 @@ return response;

const result = ky.#retry(function_)
.finally(async () => {
.finally(() => {
const originalRequest = ky.#originalRequest;
const cleanupPromises = [];
if (originalRequest && !originalRequest.bodyUsed) {
cleanupPromises.push(originalRequest.body?.cancel());
}
if (!ky.request.bodyUsed) {
cleanupPromises.push(ky.request.body?.cancel());
}
await Promise.all(cleanupPromises);
// Ignore cancellation errors from already-locked or already-consumed streams.
ky.#cancelBody(originalRequest?.body ?? undefined);
ky.#cancelBody(ky.request.body ?? undefined);
});

@@ -287,2 +298,13 @@ for (const [type, mimeType] of Object.entries(responseTypes)) {

}
#cancelBody(body) {
if (!body) {
return;
}
// Ignore cancellation failures from already-locked or already-consumed streams.
void body.cancel().catch(() => undefined);
}
#cancelResponseBody(response) {
// Ignore cancellation failures from already-locked or already-consumed streams.
this.#cancelBody(response.body ?? undefined);
}
async #retry(function_) {

@@ -289,0 +311,0 @@ try {

@@ -6,3 +6,4 @@ import type { LiteralUnion, Required } from './common.js';

export type SearchParamsOption = SearchParamsInit | Record<string, string | number | boolean | undefined> | Array<Array<string | number | boolean>>;
export type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete';
export type RequestHttpMethod = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete';
export type HttpMethod = LiteralUnion<RequestHttpMethod | 'options' | 'trace', string>;
export type Input = string | URL | Request;

@@ -9,0 +10,0 @@ export type Progress = {

@@ -0,1 +1,2 @@

import type { HttpMethod } from './options.js';
export type ShouldRetryState = {

@@ -23,3 +24,3 @@ /**

*/
methods?: string[];
methods?: HttpMethod[];
/**

@@ -26,0 +27,0 @@ The HTTP status codes allowed to retry.

@@ -27,2 +27,3 @@ import { requestMethods } from '../core/constants.js';

}
retry.methods &&= retry.methods.map(method => method.toLowerCase());
if (retry.statusCodes && !Array.isArray(retry.statusCodes)) {

@@ -29,0 +30,0 @@ throw new Error('retry.statusCodes must be an array');

@@ -5,3 +5,3 @@ import { HTTPError } from '../errors/HTTPError.js';

/**
Type guard to check if an error is a Ky error (HTTPError or TimeoutError).
Type guard to check if an error is a Ky error.

@@ -27,3 +27,3 @@ @param error - The error to check

*/
export declare function isKyError(error: unknown): error is HTTPError | TimeoutError;
export declare function isKyError(error: unknown): error is HTTPError | TimeoutError | ForceRetryError;
/**

@@ -30,0 +30,0 @@ Type guard to check if an error is an HTTPError.

@@ -5,3 +5,3 @@ import { HTTPError } from '../errors/HTTPError.js';

/**
Type guard to check if an error is a Ky error (HTTPError or TimeoutError).
Type guard to check if an error is a Ky error.

@@ -28,3 +28,3 @@ @param error - The error to check

export function isKyError(error) {
return isHTTPError(error) || isTimeoutError(error);
return isHTTPError(error) || isTimeoutError(error) || isForceRetryError(error);
}

@@ -31,0 +31,0 @@ /**

{
"name": "ky",
"version": "1.14.1",
"version": "1.14.2",
"description": "Tiny and elegant HTTP client based on the Fetch API",

@@ -5,0 +5,0 @@ "license": "MIT",

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet