{"version":3,"file":"promises.cjs","names":["resolve: DeferredPromiseReturn<T>[\"resolve\"]","reject: DeferredPromiseReturn<T>[\"reject\"]","settledPromises: Promise<T>[]","rotateQueue: (value: void) => void","timeout: ReturnType<typeof setTimeout> | undefined","ret: TimeoutPromise"],"sources":["../../src/helpers/promises.ts"],"sourcesContent":["import type { MaybePromise } from \"./types.ts\";\n\n/**\n * Some environments don't allow access to the global queueMicrotask(). While we\n * had assumed this was only true for those powered by earlier versions of Node\n * (<14) that we don't officially support, Vercel's Edge Functions also obscure\n * the function in dev, even though the platform it's based on (Cloudflare\n * Workers) appropriately exposes it. Even worse, production Vercel Edge\n * Functions can see the function, but it immediately blows up the function when\n * used.\n *\n * Therefore, we can fall back to a reasonable alternative of\n * `Promise.resolve().then(fn)` instead. This _may_ be slightly slower in modern\n * environments, but at least we can still work in these environments.\n */\nconst shimQueueMicrotask = (callback: () => void): void => {\n  void Promise.resolve().then(callback);\n};\n\n/**\n * A helper function to create a `Promise` that will never settle.\n *\n * It purposefully creates no references to `resolve` or `reject` so that the\n * returned `Promise` will remain unsettled until it falls out of scope and is\n * garbage collected.\n *\n * This should be used within transient closures to fake asynchronous action, so\n * long as it's guaranteed that they will fall out of scope.\n */\nexport const createFrozenPromise = (): Promise<unknown> => {\n  return new Promise(() => undefined);\n};\n\n/**\n * Returns a Promise that resolves after the current event loop's microtasks\n * have finished, but before the next event loop tick.\n */\nexport const resolveAfterPending = (count = 100): Promise<void> => {\n  /**\n   * This uses a brute force implementation that will continue to enqueue\n   * microtasks 10 times before resolving. This is to ensure that the microtask\n   * queue is drained, even if the microtask queue is being manipulated by other\n   * code.\n   *\n   * While this still doesn't guarantee that the microtask queue is drained,\n   * it's our best bet for giving other non-controlled promises a chance to\n   * resolve before we continue without resorting to falling in to the next\n   * tick.\n   */\n  return new Promise((resolve) => {\n    let i = 0;\n\n    const iterate = () => {\n      shimQueueMicrotask(() => {\n        if (i++ > count) {\n          return resolve();\n        }\n\n        iterate();\n      });\n    };\n\n    iterate();\n  });\n};\n\nexport type DeferredPromiseReturn<T> = {\n  promise: Promise<T>;\n  resolve: (value: T) => DeferredPromiseReturn<T>;\n  // biome-ignore lint/suspicious/noExplicitAny: intentional\n  reject: (reason: any) => DeferredPromiseReturn<T>;\n};\n\n/**\n * Creates and returns Promise that can be resolved or rejected with the\n * returned `resolve` and `reject` functions.\n *\n * Resolving or rejecting the function will return a new set of Promise control\n * functions. These can be ignored if the original Promise is all that's needed.\n */\nexport const createDeferredPromise = <T>(): DeferredPromiseReturn<T> => {\n  let resolve: DeferredPromiseReturn<T>[\"resolve\"];\n  let reject: DeferredPromiseReturn<T>[\"reject\"];\n\n  const promise = new Promise<T>((_resolve, _reject) => {\n    resolve = (value: T) => {\n      _resolve(value);\n      return createDeferredPromise<T>();\n    };\n\n    reject = (reason) => {\n      _reject(reason);\n      return createDeferredPromise<T>();\n    };\n  });\n\n  return { promise, resolve: resolve!, reject: reject! };\n};\n\n/**\n * Creates and returns a deferred Promise that can be resolved or rejected with\n * the returned `resolve` and `reject` functions.\n *\n * For each Promise resolved or rejected this way, this will also keep a stack\n * of all unhandled Promises, resolved or rejected.\n *\n * Once a Promise is read, it is removed from the stack.\n */\nexport const createDeferredPromiseWithStack = <T>(): {\n  deferred: DeferredPromiseReturn<T>;\n  results: AsyncGenerator<Awaited<T>, void, void>;\n} => {\n  const settledPromises: Promise<T>[] = [];\n  // biome-ignore lint/suspicious/noConfusingVoidType: intentional\n  let rotateQueue: (value: void) => void = () => {};\n\n  const results = (async function* () {\n    while (true) {\n      const next = settledPromises.shift();\n\n      if (next) {\n        yield next;\n      } else {\n        await new Promise<void>((resolve) => {\n          rotateQueue = resolve;\n        });\n      }\n    }\n  })();\n\n  const shimDeferredPromise = (deferred: DeferredPromiseReturn<T>) => {\n    const originalResolve = deferred.resolve;\n    const originalReject = deferred.reject;\n\n    deferred.resolve = (value: T) => {\n      settledPromises.push(deferred.promise);\n      rotateQueue();\n      return shimDeferredPromise(originalResolve(value));\n    };\n\n    deferred.reject = (reason) => {\n      settledPromises.push(deferred.promise);\n      rotateQueue();\n      return shimDeferredPromise(originalReject(reason));\n    };\n\n    return deferred;\n  };\n\n  const deferred = shimDeferredPromise(createDeferredPromise<T>());\n\n  return { deferred, results };\n};\n\ninterface TimeoutPromise extends Promise<void> {\n  /**\n   * Starts the timeout. If the timer is already started, this does nothing.\n   *\n   * @returns The promise that will resolve when the timeout expires.\n   */\n  start: () => TimeoutPromise;\n\n  /**\n   * Clears the timeout.\n   */\n  clear: () => void;\n\n  /**\n   * Clears the timeout and starts it again.\n   *\n   * @returns The promise that will resolve when the timeout expires.\n   */\n  reset: () => TimeoutPromise;\n}\n\n/**\n * Creates a Promise that will resolve after the given duration, along with\n * methods to start, clear, and reset the timeout.\n */\nexport const createTimeoutPromise = (duration: number): TimeoutPromise => {\n  const { promise, resolve } = createDeferredPromise<void>();\n\n  let timeout: ReturnType<typeof setTimeout> | undefined;\n  // biome-ignore lint/style/useConst: intentional\n  let ret: TimeoutPromise;\n\n  const start = () => {\n    if (timeout) return ret;\n\n    timeout = setTimeout(() => {\n      resolve();\n    }, duration);\n\n    return ret;\n  };\n\n  const clear = () => {\n    clearTimeout(timeout);\n    timeout = undefined;\n  };\n\n  const reset = () => {\n    clear();\n    return start();\n  };\n\n  ret = Object.assign(promise, { start, clear, reset });\n\n  return ret;\n};\n\n/**\n * Take any function and safely promisify such that both synchronous and\n * asynchronous errors are caught and returned as a rejected Promise.\n *\n * The passed `fn` can be undefined to support functions that may conditionally\n * be defined.\n */\n// biome-ignore lint/suspicious/noExplicitAny: intentional\nexport const runAsPromise = <T extends (() => any) | undefined>(\n  fn: T,\n  // biome-ignore lint/suspicious/noExplicitAny: intentional\n): Promise<T extends () => any ? Awaited<ReturnType<T>> : T> => {\n  return Promise.resolve().then(fn);\n};\n\n/**\n * Returns a Promise that resolve after the current event loop tick.\n */\nexport const resolveNextTick = (): Promise<void> => {\n  return new Promise((resolve) => setTimeout(resolve));\n};\n\nexport const retryWithBackoff = async <T>(\n  fn: () => MaybePromise<T>,\n  opts?: {\n    maxAttempts?: number;\n    baseDelay?: number;\n  },\n): Promise<T> => {\n  const maxAttempts = opts?.maxAttempts || 5;\n  const baseDelay = opts?.baseDelay ?? 100;\n\n  for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n    try {\n      return await fn();\n    } catch (err) {\n      if (attempt >= maxAttempts) {\n        throw err;\n      }\n\n      const jitter = Math.random() * baseDelay;\n      const delay = baseDelay * Math.pow(2, attempt - 1) + jitter;\n      await new Promise((resolve) => setTimeout(resolve, delay));\n    }\n  }\n\n  throw new Error(\"Max retries reached; this should be unreachable.\");\n};\n\nexport type GoInterval = {\n  a: number;\n  b: number;\n};\n\n/**\n * Given a function, returns a Promise that resolves with the result of the\n * function and a Go-compatible `interval.Interval` timing object.\n */\n// biome-ignore lint/suspicious/noExplicitAny: match any fn\nexport const goIntervalTiming = async <T extends (...args: any[]) => any>(\n  fn: T,\n): Promise<{\n  resultPromise: Promise<Awaited<ReturnType<T>>>;\n  interval: { a: number; b: number };\n}> => {\n  // Ideally this would use process.hrtime, but that's not available in all\n  // runtimes, so we must revert to less accurate timing and `Date`.\n  const start = Date.now();\n  const resultPromise = runAsPromise(fn) as Promise<Awaited<ReturnType<T>>>;\n\n  // Let the function run to completion.\n  try {\n    await resultPromise;\n  } catch {\n    // no-op\n  }\n\n  const end = Date.now();\n\n  const interval = {\n    a: start * 1_000_000,\n    b: (end - start) * 1_000_000,\n  };\n\n  return { resultPromise, interval };\n};\n"],"mappings":";;;;;;;;;;;;;;;AAeA,MAAM,sBAAsB,aAA+B;AACzD,CAAK,QAAQ,SAAS,CAAC,KAAK,SAAS;;;;;;AAqBvC,MAAa,uBAAuB,QAAQ,QAAuB;;;;;;;;;;;;AAYjE,QAAO,IAAI,SAAS,YAAY;EAC9B,IAAI,IAAI;EAER,MAAM,gBAAgB;AACpB,4BAAyB;AACvB,QAAI,MAAM,MACR,QAAO,SAAS;AAGlB,aAAS;KACT;;AAGJ,WAAS;GACT;;;;;;;;;AAiBJ,MAAa,8BAA2D;CACtE,IAAIA;CACJ,IAAIC;AAcJ,QAAO;EAAE,SAZO,IAAI,SAAY,UAAU,YAAY;AACpD,cAAW,UAAa;AACtB,aAAS,MAAM;AACf,WAAO,uBAA0B;;AAGnC,aAAU,WAAW;AACnB,YAAQ,OAAO;AACf,WAAO,uBAA0B;;IAEnC;EAEyB;EAAkB;EAAS;;;;;;;;;;;AAYxD,MAAa,uCAGR;CACH,MAAMC,kBAAgC,EAAE;CAExC,IAAIC,oBAA2C;CAE/C,MAAM,WAAW,mBAAmB;AAClC,SAAO,MAAM;GACX,MAAM,OAAO,gBAAgB,OAAO;AAEpC,OAAI,KACF,OAAM;OAEN,OAAM,IAAI,SAAe,YAAY;AACnC,kBAAc;KACd;;KAGJ;CAEJ,MAAM,uBAAuB,aAAuC;EAClE,MAAM,kBAAkB,SAAS;EACjC,MAAM,iBAAiB,SAAS;AAEhC,WAAS,WAAW,UAAa;AAC/B,mBAAgB,KAAK,SAAS,QAAQ;AACtC,gBAAa;AACb,UAAO,oBAAoB,gBAAgB,MAAM,CAAC;;AAGpD,WAAS,UAAU,WAAW;AAC5B,mBAAgB,KAAK,SAAS,QAAQ;AACtC,gBAAa;AACb,UAAO,oBAAoB,eAAe,OAAO,CAAC;;AAGpD,SAAO;;AAKT,QAAO;EAAE,UAFQ,oBAAoB,uBAA0B,CAAC;EAE7C;EAAS;;;;;;AA4B9B,MAAa,wBAAwB,aAAqC;CACxE,MAAM,EAAE,SAAS,YAAY,uBAA6B;CAE1D,IAAIC;CAEJ,IAAIC;CAEJ,MAAM,cAAc;AAClB,MAAI,QAAS,QAAO;AAEpB,YAAU,iBAAiB;AACzB,YAAS;KACR,SAAS;AAEZ,SAAO;;CAGT,MAAM,cAAc;AAClB,eAAa,QAAQ;AACrB,YAAU;;CAGZ,MAAM,cAAc;AAClB,SAAO;AACP,SAAO,OAAO;;AAGhB,OAAM,OAAO,OAAO,SAAS;EAAE;EAAO;EAAO;EAAO,CAAC;AAErD,QAAO;;;;;;;;;AAWT,MAAa,gBACX,OAE8D;AAC9D,QAAO,QAAQ,SAAS,CAAC,KAAK,GAAG;;;;;AAMnC,MAAa,wBAAuC;AAClD,QAAO,IAAI,SAAS,YAAY,WAAW,QAAQ,CAAC;;AAGtD,MAAa,mBAAmB,OAC9B,IACA,SAIe;CACf,MAAM,cAAc,MAAM,eAAe;CACzC,MAAM,YAAY,MAAM,aAAa;AAErC,MAAK,IAAI,UAAU,GAAG,WAAW,aAAa,UAC5C,KAAI;AACF,SAAO,MAAM,IAAI;UACV,KAAK;AACZ,MAAI,WAAW,YACb,OAAM;EAGR,MAAM,SAAS,KAAK,QAAQ,GAAG;EAC/B,MAAM,QAAQ,YAAY,KAAK,IAAI,GAAG,UAAU,EAAE,GAAG;AACrD,QAAM,IAAI,SAAS,YAAY,WAAW,SAAS,MAAM,CAAC;;AAI9D,OAAM,IAAI,MAAM,mDAAmD;;;;;;AAarE,MAAa,mBAAmB,OAC9B,OAII;CAGJ,MAAM,QAAQ,KAAK,KAAK;CACxB,MAAM,gBAAgB,aAAa,GAAG;AAGtC,KAAI;AACF,QAAM;SACA;CAIR,MAAM,MAAM,KAAK,KAAK;AAOtB,QAAO;EAAE;EAAe,UALP;GACf,GAAG,QAAQ;GACX,IAAI,MAAM,SAAS;GACpB;EAEiC"}