UNPKG

@socketsecurity/lib

Version:

Core utilities and infrastructure for Socket.dev security tools

273 lines (272 loc) 8.15 kB
"use strict"; /* Socket Lib - Built with esbuild */ var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; 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); var promises_exports = {}; __export(promises_exports, { normalizeIterationOptions: () => normalizeIterationOptions, normalizeRetryOptions: () => normalizeRetryOptions, pEach: () => pEach, pEachChunk: () => pEachChunk, pFilter: () => pFilter, pFilterChunk: () => pFilterChunk, pRetry: () => pRetry, resolveRetryOptions: () => resolveRetryOptions }); module.exports = __toCommonJS(promises_exports); var import_core = require("./constants/core"); var import_process = require("./constants/process"); var import_arrays = require("./arrays"); const abortSignal = (0, import_process.getAbortSignal)(); let _timers; // @__NO_SIDE_EFFECTS__ function getTimers() { if (_timers === void 0) { _timers = require("node:timers/promises"); } return _timers; } // @__NO_SIDE_EFFECTS__ function normalizeIterationOptions(options) { const opts = typeof options === "number" ? { concurrency: options } : options; const { // The number of concurrent executions performed at one time. concurrency = 1, // Retries as a number or options object. retries, // AbortSignal used to support cancellation. signal = abortSignal } = { __proto__: null, ...opts }; const normalizedConcurrency = Math.max(1, concurrency); const retryOpts = /* @__PURE__ */ resolveRetryOptions(retries); return { __proto__: null, concurrency: normalizedConcurrency, retries: /* @__PURE__ */ normalizeRetryOptions({ signal, ...retryOpts }), signal }; } // @__NO_SIDE_EFFECTS__ function normalizeRetryOptions(options) { const resolved = /* @__PURE__ */ resolveRetryOptions(options); const { // Arguments to pass to the callback function. args = [], // Multiplier for exponential backoff (e.g., 2 doubles delay each retry). backoffFactor = 2, // Initial delay before the first retry (in milliseconds). baseDelayMs = 200, // Whether to apply randomness to spread out retries. jitter = true, // Upper limit for any backoff delay (in milliseconds). maxDelayMs = 1e4, // Optional callback invoked on each retry attempt: // (attempt: number, error: unknown, delay: number) => void onRetry, // Whether onRetry can cancel retries by returning `false`. onRetryCancelOnFalse = false, // Whether onRetry will rethrow errors. onRetryRethrow = false, // Number of retry attempts (0 = no retries, only initial attempt). retries = 0, // AbortSignal used to support cancellation. signal = abortSignal } = resolved; return { args, backoffFactor, baseDelayMs, jitter, maxDelayMs, onRetry, onRetryCancelOnFalse, onRetryRethrow, retries, signal }; } // @__NO_SIDE_EFFECTS__ function resolveRetryOptions(options) { const defaults = { __proto__: null, retries: 0, baseDelayMs: 200, maxDelayMs: 1e4, backoffFactor: 2 }; if (typeof options === "number") { return { ...defaults, retries: options }; } return options ? { ...defaults, ...options } : defaults; } // @__NO_SIDE_EFFECTS__ async function pEach(array, callbackFn, options) { const iterOpts = /* @__PURE__ */ normalizeIterationOptions(options); const { concurrency, retries, signal } = iterOpts; const chunks = (0, import_arrays.arrayChunk)(array, concurrency); for (const chunk of chunks) { if (signal?.aborted) { return; } await Promise.allSettled( chunk.map( (item) => /* @__PURE__ */ pRetry((...args) => callbackFn(args[0]), { ...retries, args: [item], signal }) ) ); } } // @__NO_SIDE_EFFECTS__ async function pFilter(array, callbackFn, options) { const iterOpts = /* @__PURE__ */ normalizeIterationOptions(options); return (await /* @__PURE__ */ pFilterChunk( (0, import_arrays.arrayChunk)(array, iterOpts.concurrency), callbackFn, iterOpts.retries )).flat(); } // @__NO_SIDE_EFFECTS__ async function pEachChunk(array, callbackFn, options) { const { chunkSize = 100, ...retryOpts } = options || {}; const chunks = (0, import_arrays.arrayChunk)(array, chunkSize); const normalizedRetryOpts = /* @__PURE__ */ normalizeRetryOptions(retryOpts); const { signal } = normalizedRetryOpts; for (const chunk of chunks) { if (signal?.aborted) { return; } await /* @__PURE__ */ pRetry((...args) => callbackFn(args[0]), { ...normalizedRetryOpts, args: [chunk] }); } } // @__NO_SIDE_EFFECTS__ async function pFilterChunk(chunks, callbackFn, options) { const retryOpts = /* @__PURE__ */ normalizeRetryOptions(options); const { signal } = retryOpts; const { length } = chunks; const filteredChunks = Array(length); for (let i = 0; i < length; i += 1) { if (signal?.aborted) { filteredChunks[i] = []; } else { const chunk = chunks[i]; const settled = await Promise.allSettled( chunk.map( (value) => /* @__PURE__ */ pRetry((...args) => callbackFn(args[0]), { ...retryOpts, args: [value] }) ) ); const predicateResults = settled.map( (r) => r.status === "fulfilled" ? r.value : false ); filteredChunks[i] = chunk.filter((_v, i2) => predicateResults[i2]); } } return filteredChunks; } // @__NO_SIDE_EFFECTS__ async function pRetry(callbackFn, options) { const { args, backoffFactor, baseDelayMs, jitter, maxDelayMs, onRetry, onRetryCancelOnFalse, onRetryRethrow, retries, signal } = /* @__PURE__ */ normalizeRetryOptions(options); if (signal?.aborted) { return void 0; } if (retries === 0) { return await callbackFn(...args || [], { signal }); } const timers = /* @__PURE__ */ getTimers(); let attempts = retries; let delay = baseDelayMs; let error = import_core.UNDEFINED_TOKEN; while (attempts-- >= 0) { if (signal?.aborted) { return void 0; } try { return await callbackFn(...args || [], { signal }); } catch (e) { if (error === import_core.UNDEFINED_TOKEN) { error = e; } if (attempts < 0) { break; } let waitTime = delay; if (jitter) { waitTime += Math.floor(Math.random() * delay); } waitTime = Math.min(waitTime, maxDelayMs); if (typeof onRetry === "function") { try { const result = onRetry(retries - attempts, e, waitTime); if (result === false && onRetryCancelOnFalse) { break; } if (typeof result === "number" && result >= 0) { waitTime = Math.min(result, maxDelayMs); } } catch (e2) { if (onRetryRethrow) { throw e2; } } } try { await timers.setTimeout(waitTime, void 0, { signal }); } catch { return void 0; } if (signal?.aborted) { return void 0; } delay = Math.min(delay * backoffFactor, maxDelayMs); } } if (error !== import_core.UNDEFINED_TOKEN) { throw error; } return void 0; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { normalizeIterationOptions, normalizeRetryOptions, pEach, pEachChunk, pFilter, pFilterChunk, pRetry, resolveRetryOptions });