eigent/package/@stackframe/stack-shared/dist/esm/utils/promises.js

233 lines
6.2 KiB
JavaScript

// src/utils/promises.tsx
import { KnownError } from "..";
import { StackAssertionError, captureError, concatStacktraces } from "./errors";
import { DependenciesMap } from "./maps";
import { Result } from "./results";
import { generateUuid } from "./uuids";
function createPromise(callback) {
let status = "pending";
let valueOrReason = void 0;
let resolve = null;
let reject = null;
const promise = new Promise((res, rej) => {
resolve = (value) => {
if (status !== "pending") return;
status = "fulfilled";
valueOrReason = value;
res(value);
};
reject = (reason) => {
if (status !== "pending") return;
status = "rejected";
valueOrReason = reason;
rej(reason);
};
});
callback(resolve, reject);
return Object.assign(promise, {
status,
...status === "fulfilled" ? { value: valueOrReason } : {},
...status === "rejected" ? { reason: valueOrReason } : {}
});
}
var resolvedCache = null;
function resolved(value) {
resolvedCache ??= new DependenciesMap();
if (resolvedCache.has([value])) {
return resolvedCache.get([value]);
}
const res = Object.assign(Promise.resolve(value), {
status: "fulfilled",
value
});
resolvedCache.set([value], res);
return res;
}
var rejectedCache = null;
function rejected(reason) {
rejectedCache ??= new DependenciesMap();
if (rejectedCache.has([reason])) {
return rejectedCache.get([reason]);
}
const promise = Promise.reject(reason);
ignoreUnhandledRejection(promise);
const res = Object.assign(promise, {
status: "rejected",
reason
});
rejectedCache.set([reason], res);
return res;
}
var neverResolvePromise = pending(new Promise(() => {
}));
function neverResolve() {
return neverResolvePromise;
}
function pending(promise, options = {}) {
const res = promise.then(
(value) => {
res.status = "fulfilled";
res.value = value;
return value;
},
(actualReason) => {
res.status = "rejected";
res.reason = actualReason;
throw actualReason;
}
);
res.status = "pending";
return res;
}
function ignoreUnhandledRejection(promise) {
promise.catch(() => {
});
}
async function wait(ms) {
if (!Number.isFinite(ms) || ms < 0) {
throw new StackAssertionError(`wait() requires a non-negative integer number of milliseconds to wait. (found: ${ms}ms)`);
}
if (ms >= 2 ** 31) {
throw new StackAssertionError("The maximum timeout for wait() is 2147483647ms (2**31 - 1). (found: ${ms}ms)");
}
return await new Promise((resolve) => setTimeout(resolve, ms));
}
async function waitUntil(date) {
return await wait(date.getTime() - Date.now());
}
function runAsynchronouslyWithAlert(...args) {
return runAsynchronously(
args[0],
{
...args[1],
onError: (error) => {
if (KnownError.isKnownError(error) && typeof process !== "undefined" && process.env.NODE_ENV?.includes("production")) {
alert(error.message);
} else {
alert(`An unhandled error occurred. Please ${process.env.NODE_ENV === "development" ? `check the browser console for the full error.` : "report this to the developer."}
${error}`);
}
args[1]?.onError?.(error);
}
},
...args.slice(2)
);
}
function runAsynchronously(promiseOrFunc, options = {}) {
if (typeof promiseOrFunc === "function") {
promiseOrFunc = promiseOrFunc();
}
const duringError = new Error();
promiseOrFunc?.catch((error) => {
options.onError?.(error);
const newError = new StackAssertionError(
"Uncaught error in asynchronous function: " + error.toString(),
{ cause: error }
);
concatStacktraces(newError, duringError);
if (!options.noErrorLogging) {
captureError("runAsynchronously", newError);
}
});
}
var TimeoutError = class extends Error {
constructor(ms) {
super(`Timeout after ${ms}ms`);
this.ms = ms;
this.name = "TimeoutError";
}
};
async function timeout(promise, ms) {
return await Promise.race([
promise.then((value) => Result.ok(value)),
wait(ms).then(() => Result.error(new TimeoutError(ms)))
]);
}
async function timeoutThrow(promise, ms) {
return Result.orThrow(await timeout(promise, ms));
}
function rateLimited(func, options) {
let waitUntil2 = performance.now();
let queue = [];
let addedToQueueCallbacks = /* @__PURE__ */ new Map();
const next = async () => {
while (true) {
if (waitUntil2 > performance.now()) {
await wait(Math.max(1, waitUntil2 - performance.now() + 1));
} else if (queue.length === 0) {
const uuid = generateUuid();
await new Promise((resolve) => {
addedToQueueCallbacks.set(uuid, resolve);
});
addedToQueueCallbacks.delete(uuid);
} else {
break;
}
}
const nextFuncs = options.batchCalls ? queue.splice(0, queue.length) : [queue.shift()];
const start = performance.now();
const value = await Result.fromPromise(func());
const end = performance.now();
waitUntil2 = Math.max(
waitUntil2,
start + (options.throttleMs ?? 0),
end + (options.gapMs ?? 0)
);
for (const nextFunc of nextFuncs) {
if (value.status === "ok") {
nextFunc[0](value.data);
} else {
nextFunc[1](value.error);
}
}
};
runAsynchronously(async () => {
while (true) {
await next();
}
});
return () => {
return new Promise((resolve, reject) => {
waitUntil2 = Math.max(
waitUntil2,
performance.now() + (options.debounceMs ?? 0)
);
queue.push([resolve, reject]);
addedToQueueCallbacks.forEach((cb) => cb());
});
};
}
function throttled(func, delayMs) {
let timeout2 = null;
let nextAvailable = null;
return async (...args) => {
while (nextAvailable !== null) {
await nextAvailable;
}
nextAvailable = new Promise((resolve) => {
timeout2 = setTimeout(() => {
nextAvailable = null;
resolve(func(...args));
}, delayMs);
});
return await nextAvailable;
};
}
export {
createPromise,
ignoreUnhandledRejection,
neverResolve,
pending,
rateLimited,
rejected,
resolved,
runAsynchronously,
runAsynchronouslyWithAlert,
throttled,
timeout,
timeoutThrow,
wait,
waitUntil
};
//# sourceMappingURL=promises.js.map