@alwaysmeticulous/downloading-helpers
Advanced tools
Comparing version 2.136.1 to 2.137.0
@@ -1,3 +0,13 @@ | ||
export declare const downloadFile: (fileUrl: string, path: string) => Promise<void>; | ||
/** | ||
* Warning: this function is not thread safe. Do not try downloading a file to a path that may already be in use by another process. | ||
* | ||
* (for example most downloads are generally done at the test run level rather than the replay level) | ||
*/ | ||
export declare const downloadFile: (fileUrl: string, path: string, opts?: { | ||
firstDataTimeoutInMs?: number; | ||
downloadCompleteTimeoutInMs?: number; | ||
maxDownloadContentRetries?: number; | ||
downloadContentRetryDelay?: number; | ||
}) => Promise<void>; | ||
/** | ||
* Download a file from a URL and extract it to a directory. | ||
@@ -7,3 +17,5 @@ * The zip file will be deleted after extraction, keeping only the extracted files. | ||
* Returns a list of the extracted files. | ||
* | ||
* Warning: this function is not thread safe. Do not try downloading a file to an extractPath that may already be in use by another process. | ||
*/ | ||
export declare const downloadAndExtractFile: (fileUrl: string, tmpZipFilePath: string, extractPath: string) => Promise<string[]>; |
@@ -15,13 +15,57 @@ "use strict"; | ||
const promisifiedFinished = (0, util_1.promisify)(stream_1.finished); | ||
const downloadFile = async (fileUrl, path) => { | ||
/** | ||
* Warning: this function is not thread safe. Do not try downloading a file to a path that may already be in use by another process. | ||
* | ||
* (for example most downloads are generally done at the test run level rather than the replay level) | ||
*/ | ||
const downloadFile = async (fileUrl, path, opts = {}) => { | ||
var _a, _b, _c, _d; | ||
// Using the same timeout as the standard client in meticulous-sdk/packages/client/src/client.ts | ||
const client = axios_1.default.create({ timeout: 60000 }); | ||
const firstDataTimeoutInMs = (_a = opts.firstDataTimeoutInMs) !== null && _a !== void 0 ? _a : 60000; | ||
const downloadCompleteTimeoutInMs = (_b = opts.downloadCompleteTimeoutInMs) !== null && _b !== void 0 ? _b : 120000; | ||
const maxDownloadContentRetries = (_c = opts.maxDownloadContentRetries) !== null && _c !== void 0 ? _c : 3; | ||
const downloadContentRetryDelay = (_d = opts.downloadContentRetryDelay) !== null && _d !== void 0 ? _d : 1000; | ||
const client = axios_1.default.create({ timeout: firstDataTimeoutInMs }); | ||
(0, axios_retry_1.default)(client, { retries: 3, shouldResetTimeout: true }); | ||
const source = axios_1.default.CancelToken.source(); | ||
const response = await client.request({ | ||
method: "GET", | ||
url: fileUrl, | ||
responseType: "stream", | ||
cancelToken: source.token, | ||
}); | ||
const writer = (0, fs_1.createWriteStream)(path); | ||
return client | ||
.request({ method: "GET", url: fileUrl, responseType: "stream" }) | ||
.then(async (response) => { | ||
response.data.pipe(writer); | ||
return promisifiedFinished(writer); | ||
}); | ||
response.data.pipe(writer); | ||
const timeoutId = setTimeout(async () => { | ||
const error = `Download timed out after ${downloadCompleteTimeoutInMs}ms`; | ||
source.cancel(error); | ||
writer.destroy(new Error(error)); | ||
}, downloadCompleteTimeoutInMs); | ||
try { | ||
await promisifiedFinished(writer); | ||
if (timeoutId) { | ||
clearTimeout(timeoutId); | ||
} | ||
} | ||
catch (err) { | ||
if (timeoutId) { | ||
clearTimeout(timeoutId); | ||
} | ||
await new Promise((resolve) => writer.close(resolve)); | ||
if ((0, fs_1.existsSync)(path)) { | ||
// If we errored at this stage and not earlier then we've likely already written to and corrupted the file, | ||
// so let's delete it. | ||
await (0, promises_1.rm)(path); | ||
} | ||
if (maxDownloadContentRetries === 0) { | ||
throw err; | ||
} | ||
// Let's try again after a short delay | ||
await new Promise((resolve) => setTimeout(resolve, downloadContentRetryDelay)); | ||
await (0, exports.downloadFile)(fileUrl, path, { | ||
firstDataTimeoutInMs, | ||
downloadCompleteTimeoutInMs, | ||
maxDownloadContentRetries: maxDownloadContentRetries - 1, | ||
}); | ||
} | ||
}; | ||
@@ -34,2 +78,4 @@ exports.downloadFile = downloadFile; | ||
* Returns a list of the extracted files. | ||
* | ||
* Warning: this function is not thread safe. Do not try downloading a file to an extractPath that may already be in use by another process. | ||
*/ | ||
@@ -36,0 +82,0 @@ const downloadAndExtractFile = async (fileUrl, filePath, extractPath) => { |
@@ -5,3 +5,7 @@ /** | ||
* The associated source map will also be downloaded if present to sit alongside the main JS file and if the base snippets URL is a localhost URL. | ||
* | ||
* Warning: this function is not thread safe. Do not try downloading a file to a path that may already be in use by another process. | ||
* | ||
* (for example most downloads are generally done at the test run level rather than the replay level) | ||
*/ | ||
export declare const fetchAsset: (path: string) => Promise<string>; |
@@ -22,2 +22,6 @@ "use strict"; | ||
* The associated source map will also be downloaded if present to sit alongside the main JS file and if the base snippets URL is a localhost URL. | ||
* | ||
* Warning: this function is not thread safe. Do not try downloading a file to a path that may already be in use by another process. | ||
* | ||
* (for example most downloads are generally done at the test run level rather than the replay level) | ||
*/ | ||
@@ -24,0 +28,0 @@ const fetchAsset = async (path) => { |
{ | ||
"name": "@alwaysmeticulous/downloading-helpers", | ||
"version": "2.136.1", | ||
"version": "2.137.0", | ||
"description": "Helper utilities for downloading files & scripts required to execute replays", | ||
@@ -19,8 +19,9 @@ "license": "ISC", | ||
"lint:fix": "eslint src --ext=ts,tsx,js --cache --fix", | ||
"depcheck": "depcheck --ignore-patterns=dist" | ||
"depcheck": "depcheck --ignore-patterns=dist", | ||
"test": "jest" | ||
}, | ||
"dependencies": { | ||
"@alwaysmeticulous/api": "^2.133.0", | ||
"@alwaysmeticulous/client": "^2.136.1", | ||
"@alwaysmeticulous/common": "^2.134.0", | ||
"@alwaysmeticulous/api": "^2.137.0", | ||
"@alwaysmeticulous/client": "^2.137.0", | ||
"@alwaysmeticulous/common": "^2.137.0", | ||
"axios": "^1.2.6", | ||
@@ -55,3 +56,6 @@ "axios-retry": "^4.1.0", | ||
}, | ||
"gitHead": "e122b0ba5a024395e3c8e2e37b56b67a558901e4" | ||
"jest": { | ||
"preset": "../../jest.config.js" | ||
}, | ||
"gitHead": "e2e4acc7ab9ddbdb8ce6dc191692812156c29c06" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
56422
27
700
10
1