Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign 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.10.0
to
1.11.0
+1
-0
distribution/core/Ky.d.ts

@@ -11,2 +11,3 @@ import type { Input, InternalOptions, Options } from '../types/options.js';

protected _options: InternalOptions;
protected _originalRequest?: Request;
constructor(input: Input, options?: Options);

@@ -13,0 +14,0 @@ protected _calculateRetryDelay(error: unknown): number;

+13
-7

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

// Before using ky.request, _fetch clones it and saves the clone for future retries to use.
// If retry is not needed, close the cloned request's ReadableStream for memory safety.
// If retry is not needed, close both the original and cloned request's ReadableStream for memory safety.
let response = await ky._fetch();

@@ -54,6 +54,11 @@ for (const hook of ky._options.hooks.afterResponse) {

.finally(async () => {
// Now that we know a retry is not needed, close the ReadableStream of the cloned request.
const originalRequest = ky._originalRequest;
const cleanupPromises = [];
if (originalRequest && !originalRequest.bodyUsed) {
cleanupPromises.push(originalRequest.body?.cancel());
}
if (!ky.request.bodyUsed) {
await ky.request.body?.cancel();
cleanupPromises.push(ky.request.body?.cancel());
}
await Promise.all(cleanupPromises);
});

@@ -101,2 +106,3 @@ for (const [type, mimeType] of Object.entries(responseTypes)) {

_options;
_originalRequest;
// eslint-disable-next-line complexity

@@ -257,10 +263,10 @@ constructor(input, options = {}) {

// Cloning is done here to prepare in advance for retries
const mainRequest = this.request;
this.request = mainRequest.clone();
this._originalRequest = this.request;
this.request = this._originalRequest.clone();
if (this._options.timeout === false) {
return this._options.fetch(mainRequest, nonRequestOptions);
return this._options.fetch(this._originalRequest, nonRequestOptions);
}
return timeout(mainRequest, nonRequestOptions, this.abortController, this._options);
return timeout(this._originalRequest, nonRequestOptions, this.abortController, this._options);
}
}
//# sourceMappingURL=Ky.js.map

@@ -7,3 +7,3 @@ export class HTTPError extends Error {

const code = (response.status || response.status === 0) ? response.status : '';
const title = response.statusText || '';
const title = response.statusText ?? '';
const status = `${code} ${title}`.trim();

@@ -10,0 +10,0 @@ const reason = status ? `status code ${status}` : 'an unknown error';

@@ -45,9 +45,34 @@ import { usualFormBoundarySize } from '../core/constants.js';

};
const withProgress = (stream, totalBytes, onProgress) => {
let previousChunk;
let transferredBytes = 0;
return stream.pipeThrough(new TransformStream({
transform(currentChunk, controller) {
controller.enqueue(currentChunk);
if (previousChunk) {
transferredBytes += previousChunk.byteLength;
let percent = totalBytes === 0 ? 0 : transferredBytes / totalBytes;
// Avoid reporting 100% progress before the stream is actually finished (in case totalBytes is inaccurate)
if (percent >= 1) {
// Epsilon is used here to get as close as possible to 100% without reaching it.
// If we were to use 0.99 here, percent could potentially go backwards.
percent = 1 - Number.EPSILON;
}
onProgress?.({ percent, totalBytes: Math.max(totalBytes, transferredBytes), transferredBytes }, previousChunk);
}
previousChunk = currentChunk;
},
flush() {
if (previousChunk) {
transferredBytes += previousChunk.byteLength;
onProgress?.({ percent: 1, totalBytes: Math.max(totalBytes, transferredBytes), transferredBytes }, previousChunk);
}
},
}));
};
export const streamResponse = (response, onDownloadProgress) => {
const totalBytes = Number(response.headers.get('content-length')) || 0;
let transferredBytes = 0;
if (!response.body) {
return response;
}
if (response.status === 204) {
if (onDownloadProgress) {
onDownloadProgress({ percent: 1, totalBytes, transferredBytes }, new Uint8Array());
}
return new Response(null, {

@@ -59,25 +84,4 @@ status: response.status,

}
return new Response(new ReadableStream({
async start(controller) {
const reader = response.body.getReader();
if (onDownloadProgress) {
onDownloadProgress({ percent: 0, transferredBytes: 0, totalBytes }, new Uint8Array());
}
async function read() {
const { done, value } = await reader.read();
if (done) {
controller.close();
return;
}
if (onDownloadProgress) {
transferredBytes += value.byteLength;
const percent = totalBytes === 0 ? 0 : transferredBytes / totalBytes;
onDownloadProgress({ percent, transferredBytes, totalBytes }, value);
}
controller.enqueue(value);
await read();
}
await read();
},
}), {
const totalBytes = Number(response.headers.get('content-length')) || 0;
return new Response(withProgress(response.body, totalBytes, onDownloadProgress), {
status: response.status,

@@ -90,37 +94,13 @@ statusText: response.statusText,

export const streamRequest = (request, onUploadProgress, originalBody) => {
if (!request.body) {
return request;
}
// Use original body for size calculation since request.body is already a stream
const totalBytes = getBodySize(originalBody ?? request.body);
let transferredBytes = 0;
return new Request(request, {
// @ts-expect-error - Types are outdated.
duplex: 'half',
body: new ReadableStream({
async start(controller) {
const reader = request.body instanceof ReadableStream ? request.body.getReader() : new Response('').body.getReader();
async function read() {
const { done, value } = await reader.read();
if (done) {
// Ensure 100% progress is reported when the upload is complete
if (onUploadProgress) {
onUploadProgress({ percent: 1, transferredBytes, totalBytes: Math.max(totalBytes, transferredBytes) }, new Uint8Array());
}
controller.close();
return;
}
transferredBytes += value.byteLength;
let percent = totalBytes === 0 ? 0 : transferredBytes / totalBytes;
if (totalBytes < transferredBytes || percent === 1) {
percent = 0.99;
}
if (onUploadProgress) {
onUploadProgress({ percent: Number(percent.toFixed(2)), transferredBytes, totalBytes }, value);
}
controller.enqueue(value);
await read();
}
await read();
},
}),
body: withProgress(request.body, totalBytes, onUploadProgress),
});
};
//# sourceMappingURL=body.js.map
{
"name": "ky",
"version": "1.10.0",
"version": "1.11.0",
"description": "Tiny and elegant HTTP client based on the Fetch API",

@@ -70,3 +70,3 @@ "license": "MIT",

"express": "^4.18.2",
"jest-leak-detector": "^29.7.0",
"jest-leak-detector": "^30.1.0",
"pify": "^6.1.0",

@@ -73,0 +73,0 @@ "playwright": "^1.45.3",

@@ -625,6 +625,8 @@ <div align="center">

```js
import { HTTPError } from "ky";
try {
await ky('https://example.com').json();
} catch (error) {
if (error.name === 'HTTPError') {
if (error instanceof HTTPError) {
const errorJson = await error.response.json();

@@ -631,0 +633,0 @@ }

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