@apify/timeout
Advanced tools
Comparing version 0.2.1 to 0.3.0
161
index.js
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.addTimeoutToPromise = exports.tryCancel = exports.TimeoutError = exports.storage = void 0; | ||
// eslint-disable-next-line max-classes-per-file | ||
const async_hooks_1 = require("async_hooks"); | ||
/** | ||
* `AsyncLocalStorage` instance that is used for baring the AbortContext inside user provided handler. | ||
* We can use it to access the `AbortContext` instance via `storage.getStore()`, and there we can access | ||
* `cancelTask` instance of `AbortController`. | ||
*/ | ||
exports.storage = new async_hooks_1.AsyncLocalStorage(); | ||
/** | ||
* Custom error class that will be used for timeout error. | ||
*/ | ||
class TimeoutError extends Error { | ||
} | ||
exports.TimeoutError = TimeoutError; | ||
/** | ||
* Custom error class to handle `tryCancel()` checks. | ||
* This should not be exposed to user land, as it will be caught in. | ||
*/ | ||
class InternalTimeoutError extends TimeoutError { | ||
} | ||
/** | ||
* Checks whether we are inside timeout handler created by this package, and cancels current | ||
* task execution by throwing `TimeoutError`. This error will be ignored if the promise timed | ||
* out already, or explicitly skipped in `addTimeoutToPromise`. | ||
* | ||
* Use this function after every async call that runs inside the timeout handler: | ||
* | ||
* ```ts | ||
* async function doSomething() { | ||
* await doSomethingTimeConsuming(); | ||
* tryCancel(); | ||
* await doSomethingElse(); | ||
* tryCancel(); | ||
* } | ||
* ``` | ||
*/ | ||
var __defProp = Object.defineProperty; | ||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
var __getOwnPropNames = Object.getOwnPropertyNames; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); | ||
var __export = (target, all) => { | ||
for (var name in all) | ||
__defProp(target, name, { get: all[name], enumerable: true }); | ||
}; | ||
var __copyProps = (to, from, except, desc) => { | ||
if (from && typeof from === "object" || typeof from === "function") { | ||
for (let key of __getOwnPropNames(from)) | ||
if (!__hasOwnProp.call(to, key) && key !== except) | ||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
} | ||
return to; | ||
}; | ||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
// src/index.ts | ||
var src_exports = {}; | ||
__export(src_exports, { | ||
TimeoutError: () => TimeoutError, | ||
addTimeoutToPromise: () => addTimeoutToPromise, | ||
storage: () => storage, | ||
tryCancel: () => tryCancel | ||
}); | ||
module.exports = __toCommonJS(src_exports); | ||
var import_async_hooks = require("async_hooks"); | ||
var storage = new import_async_hooks.AsyncLocalStorage(); | ||
var TimeoutError = class extends Error { | ||
}; | ||
__name(TimeoutError, "TimeoutError"); | ||
var InternalTimeoutError = class extends TimeoutError { | ||
}; | ||
__name(InternalTimeoutError, "InternalTimeoutError"); | ||
function tryCancel() { | ||
var _a; | ||
const signal = (_a = exports.storage.getStore()) === null || _a === void 0 ? void 0 : _a.cancelTask.signal; | ||
if (signal === null || signal === void 0 ? void 0 : signal.aborted) { | ||
throw new InternalTimeoutError('Promise handler has been canceled due to a timeout'); | ||
} | ||
const signal = storage.getStore()?.cancelTask.signal; | ||
if (signal?.aborted) { | ||
throw new InternalTimeoutError("Promise handler has been canceled due to a timeout"); | ||
} | ||
} | ||
exports.tryCancel = tryCancel; | ||
/** | ||
* Runs given handler and rejects with the given `errorMessage` (or `Error` instance) | ||
* after given `timeoutMillis`, unless the original promise resolves or rejects earlier. | ||
* Use `tryCancel()` function inside the handler after each await to finish its execution | ||
* early when the timeout appears. | ||
* | ||
* ```ts | ||
* const res = await addTimeoutToPromise( | ||
* () => handler(), | ||
* 200, | ||
* 'Handler timed out after 200ms!', | ||
* ); | ||
* ``` | ||
*/ | ||
__name(tryCancel, "tryCancel"); | ||
async function addTimeoutToPromise(handler, timeoutMillis, errorMessage) { | ||
var _a; | ||
// respect existing context to support nesting | ||
const context = (_a = exports.storage.getStore()) !== null && _a !== void 0 ? _a : { | ||
cancelTask: new AbortController(), | ||
}; | ||
let returnValue; | ||
// calls handler, skips internal `TimeoutError`s that might have been thrown | ||
// via `tryCancel()` and aborts the timeout promise after the handler finishes | ||
const wrap = async () => { | ||
try { | ||
returnValue = await handler(); | ||
} | ||
catch (e) { | ||
if (!(e instanceof InternalTimeoutError)) { | ||
throw e; | ||
} | ||
} | ||
}; | ||
return new Promise((resolve, reject) => { | ||
const timeout = setTimeout(() => { | ||
context.cancelTask.abort(); | ||
const error = errorMessage instanceof Error ? errorMessage : new TimeoutError(errorMessage); | ||
reject(error); | ||
}, timeoutMillis); | ||
exports.storage.run(context, () => { | ||
wrap() | ||
.then(() => resolve(returnValue)) | ||
.catch(reject) | ||
.finally(() => clearTimeout(timeout)); | ||
}); | ||
const context = storage.getStore() ?? { | ||
cancelTask: new AbortController() | ||
}; | ||
let returnValue; | ||
const wrap = /* @__PURE__ */ __name(async () => { | ||
try { | ||
returnValue = await handler(); | ||
} catch (e) { | ||
if (!(e instanceof InternalTimeoutError)) { | ||
throw e; | ||
} | ||
} | ||
}, "wrap"); | ||
return new Promise((resolve, reject) => { | ||
const timeout = setTimeout(() => { | ||
context.cancelTask.abort(); | ||
const error = errorMessage instanceof Error ? errorMessage : new TimeoutError(errorMessage); | ||
reject(error); | ||
}, timeoutMillis); | ||
storage.run(context, () => { | ||
wrap().then(() => resolve(returnValue)).catch(reject).finally(() => clearTimeout(timeout)); | ||
}); | ||
}); | ||
} | ||
exports.addTimeoutToPromise = addTimeoutToPromise; | ||
__name(addTimeoutToPromise, "addTimeoutToPromise"); | ||
// Annotate the CommonJS export names for ESM import in node: | ||
0 && (module.exports = { | ||
TimeoutError, | ||
addTimeoutToPromise, | ||
storage, | ||
tryCancel | ||
}); | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@apify/timeout", | ||
"version": "0.2.1", | ||
"version": "0.3.0", | ||
"description": "Helper for adding timeouts to promises that support easy cancellation.", | ||
"main": "index.js", | ||
"typings": "index.d.ts", | ||
"main": "./index.js", | ||
"module": "./index.mjs", | ||
"typings": "./index.d.ts", | ||
"exports": { | ||
".": { | ||
"import": "./index.mjs", | ||
"require": "./index.js", | ||
"types": "./index.d.ts" | ||
} | ||
}, | ||
"keywords": [ | ||
@@ -30,3 +38,3 @@ "apify" | ||
"clean": "rimraf ./dist", | ||
"compile": "tsc -p tsconfig.build.json", | ||
"compile": "tsup && tsc -p tsconfig.build.json", | ||
"copy": "ts-node -T ../../scripts/copy.ts" | ||
@@ -37,3 +45,3 @@ }, | ||
}, | ||
"gitHead": "971456698159558dc8b7f2577a65d7a88f0eee28" | ||
"gitHead": "9e31c174fe30c8c5b517b0d26874d123e233d807" | ||
} |
@@ -15,2 +15,4 @@ # Apify shared library | ||
`@apify/markdown` | [![NPM version](https://img.shields.io/npm/v/@apify/markdown.svg)](https://www.npmjs.com/package/@apify/markdown) | ||
`@apify/payment_qr_codes` | [![NPM version](https://img.shields.io/npm/v/@apify/payment_qr_codes.svg)](https://www.npmjs.com/package/@apify/payment_qr_codes) | ||
`@apify/pseudo_url` | [![NPM version](https://img.shields.io/npm/v/@apify/pseudo_url.svg)](https://www.npmjs.com/package/@apify/pseudo_url) | ||
`@apify/salesforce_client` | [![NPM version](https://img.shields.io/npm/v/@apify/salesforce_client.svg)](https://www.npmjs.com/package/@apify/salesforce_client) | ||
@@ -17,0 +19,0 @@ `@apify/utilities` | [![NPM version](https://img.shields.io/npm/v/@apify/utilities.svg)](https://www.npmjs.com/package/@apify/utilities) |
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
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
29484
8
175
24
2