{"version":3,"sources":["../../src/ForgetConfig.ts","../../src/ForgetNodeConfig.ts","../../src/ForgetPromise.ts","../../src/ForgetPromiseNode.ts","../../src/forgetNode.ts"],"sourcesContent":["/**\n * Configuration options for fire-and-forget promises.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface ForgetConfig<T = any> {\n  /** Optional name for identifying the forgotten promise in logs. */\n  name?: string\n  /** Called when the promise is cancelled due to timeout. */\n  onCancel?: () => void\n  /** Called when the promise completes, with a tuple of [result, error]. */\n  onComplete?: (result: [T | undefined, Error | undefined]) => void\n  /** Called when an exception occurs outside the promise itself. */\n  onException?: (error: Error) => void\n  /** Timeout in milliseconds after which the promise is considered timed out. */\n  timeout?: number\n}\n\n/** Default forget configuration with a 30-second timeout. */\nexport const defaultForgetConfig: ForgetConfig<unknown> = { timeout: 30_000 }\n","import { defaultForgetConfig, type ForgetConfig } from './ForgetConfig.ts'\n\n/**\n * Node.js-specific forget configuration that extends ForgetConfig with process termination options.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface ForgetNodeConfig<T = any> extends ForgetConfig<T> {\n  /** Terminate the process on an exception that happens outside of the promise being forgotten. */\n  terminateOnException?: boolean\n  /** Terminate the process if the promise times out. */\n  terminateOnTimeout?: boolean\n}\n\n/** Default Node.js forget configuration with termination disabled. */\nexport const defaultForgetNodeConfig: ForgetNodeConfig<unknown> = {\n  ...defaultForgetConfig,\n  terminateOnTimeout: false,\n  terminateOnException: false,\n}\n","import { delay } from '@xylabs/delay'\nimport type { Logger } from '@xylabs/logger'\nimport type { Promisable, PromiseEx } from '@xylabs/promise'\nimport { isPromise } from '@xylabs/promise'\nimport { isNumber } from '@xylabs/typeof'\n\nimport { defaultForgetConfig, type ForgetConfig } from './ForgetConfig.ts'\n\n/** A function that returns a promisable value. */\ntype PromisableFunction<T> = () => Promisable<T>\n\n/**\n * Manages fire-and-forget promises with tracking, timeouts, and error handling.\n */\n// eslint-disable-next-line unicorn/no-static-only-class\nexport class ForgetPromise {\n  /** Number of currently active (unresolved) forgotten promises. */\n  static activeForgets = 0\n  /** Number of forgotten promises that threw exceptions. */\n  static exceptedForgets = 0\n  /** Logger instance used for error and warning output. */\n  static logger: Logger = console\n\n  /** Whether any forgotten promises are still active. */\n  static get active() {\n    return this.activeForgets > 0\n  }\n\n  /**\n   * Waits until all forgotten promises have completed.\n   * @param interval - Polling interval in milliseconds.\n   * @param timeout - Optional maximum wait time in milliseconds.\n   * @returns The number of remaining active forgets (0 if all completed).\n   */\n  static async awaitInactive(interval = 100, timeout?: number) {\n    let timeoutRemaining = timeout\n    while (this.active) {\n      await delay(interval)\n      if (timeoutRemaining !== undefined) {\n        timeoutRemaining -= interval\n        if (timeoutRemaining <= 0) {\n          return this.activeForgets\n        }\n      }\n    }\n    return 0\n  }\n\n  /** Handles exceptions from forgotten promises by logging error details. */\n  static exceptionHandler(error: Error, { name }: ForgetConfig, externalStackTrace?: string) {\n    this.logger.error(`forget promise handler excepted [${name}]: ${error.message}`, error)\n    if (externalStackTrace !== undefined) {\n      this.logger.warn(`External Stack trace [${name}]:`, externalStackTrace)\n    }\n  }\n\n  /**\n   * Used to explicitly launch an async function (or Promise) with awaiting it\n   * @param promise The promise to forget\n   * @param config Configuration of forget settings\n   */\n  static forget<T>(promise: Promise<T> | PromiseEx<T> | PromisableFunction<T> | T, config?: ForgetConfig<T>) {\n    const externalStackTrace = (new Error('Stack')).stack\n\n    // default | global | provided priorities for config (not deep merge)\n    const resolvedConfig = {\n      ...defaultForgetConfig, ...globalThis.xy?.forget?.config, ...config,\n    }\n    const resolvedPromise = typeof promise === 'function' ? (promise as PromisableFunction<T>)() : promise\n    if (isPromise(resolvedPromise)) {\n      try {\n        let completed = false\n        this.activeForgets++\n\n        const promiseWrapper = async () => {\n          await resolvedPromise\n            .then((result: T) => {\n              this.activeForgets--\n              completed = true\n              resolvedConfig?.onComplete?.([result, undefined])\n            })\n            .catch((error) => {\n              this.activeForgets--\n              completed = true\n              this.logger.error(`forgotten promise excepted [${config?.name ?? 'unknown'}]: ${error.message}`, error)\n              resolvedConfig?.onComplete?.([undefined, error])\n            })\n        }\n\n        const promises = [promiseWrapper()]\n\n        // if there is a timeout, add it to the race\n        const timeout = resolvedConfig.timeout ?? defaultForgetConfig.timeout\n        if (isNumber(timeout)) {\n          const timeoutFunc = async () => {\n            await delay(timeout)\n            if (!completed) {\n              resolvedConfig.onCancel?.()\n              this.timeoutHandler(timeout, resolvedConfig, externalStackTrace)\n            }\n          }\n          promises.push(timeoutFunc())\n        }\n\n        const all = Promise.race(promises)\n\n        all\n          .then(() => {\n            return\n          })\n          .catch(() => {\n            return\n          })\n      } catch (ex) {\n        this.exceptedForgets += 1\n        resolvedConfig?.onException?.(ex as Error)\n        this.exceptionHandler(ex as Error, resolvedConfig, externalStackTrace)\n      }\n    } else {\n      // we do nothing here since if it was a non-promise, it already got invoked.\n      return\n    }\n  }\n\n  /** Handles timeout events for forgotten promises by logging timeout details. */\n  static timeoutHandler(time: number, { name = 'unknown' }: ForgetConfig, externalStackTrace?: string) {\n    this.logger.error(`forget promise timeout out after ${time}ms [Cancelling] [${name}]`)\n    if (externalStackTrace !== undefined) {\n      this.logger.warn(`External Stack trace [${name}]:`, externalStackTrace)\n    }\n  }\n}\n","/// <reference types=\"node\" />\n\nimport type { Promisable } from '@xylabs/promise'\n\nimport { defaultForgetNodeConfig, type ForgetNodeConfig } from './ForgetNodeConfig.ts'\nimport { ForgetPromise } from './ForgetPromise.ts'\n\n/**\n * Node.js extension of ForgetPromise that can terminate the process on exceptions or timeouts.\n */\nexport class ForgetPromiseNode extends ForgetPromise {\n  /** Handles exceptions, optionally terminating the process based on config. */\n  static override exceptionHandler(error: Error, config: ForgetNodeConfig, externalStackTrace?: string) {\n    // default | global | provided priorities for config (not deep merge)\n    super.exceptionHandler(error, config, externalStackTrace)\n    if (config?.terminateOnException === true) {\n      this.logger.error(`Attempting to terminate process [${config?.name ?? 'unknown'}]...`)\n      // eslint-disable-next-line unicorn/no-process-exit\n      process.exit(1)\n    }\n  }\n\n  /** Forgets a promise using Node.js-specific configuration with process termination support. */\n  static override forget<T>(promise: Promisable<T>, config?: ForgetNodeConfig<T>) {\n    const resolvedConfig = {\n      ...defaultForgetNodeConfig, ...globalThis.xy?.forget?.config, ...config,\n    }\n    super.forget(promise, resolvedConfig)\n  }\n\n  /** Handles timeouts, optionally terminating the process based on config. */\n  static override timeoutHandler(time: number, config: ForgetNodeConfig, externalStackTrace?: string) {\n    super.timeoutHandler(time, config, externalStackTrace)\n    if (config?.terminateOnTimeout === true) {\n      this.logger.error(`Attempting to terminate process [${config?.name ?? 'unknown'}]...`)\n      // eslint-disable-next-line unicorn/no-process-exit\n      process.exit(2)\n    }\n  }\n}\n","import { type Promisable } from '@xylabs/promise'\n\nimport type { ForgetNodeConfig } from './ForgetNodeConfig.ts'\nimport { ForgetPromiseNode } from './ForgetPromiseNode.ts'\n\n/**\n * Node.js variant of forget that can optionally terminate the process on exceptions or timeouts.\n * @param promise - The promise or promisable value to forget.\n * @param config - Optional Node.js-specific configuration including process termination options.\n */\nexport const forgetNode = <T>(promise: Promisable<T>, config?: ForgetNodeConfig<T>) => {\n  ForgetPromiseNode.forget<T>(promise, config)\n}\n"],"mappings":";AAkBO,IAAM,sBAA6C,EAAE,SAAS,IAAO;;;ACJrE,IAAM,0BAAqD;AAAA,EAChE,GAAG;AAAA,EACH,oBAAoB;AAAA,EACpB,sBAAsB;AACxB;;;AClBA,SAAS,aAAa;AAGtB,SAAS,iBAAiB;AAC1B,SAAS,gBAAgB;AAWlB,IAAM,gBAAN,MAAoB;AAAA;AAAA,EAEzB,OAAO,gBAAgB;AAAA;AAAA,EAEvB,OAAO,kBAAkB;AAAA;AAAA,EAEzB,OAAO,SAAiB;AAAA;AAAA,EAGxB,WAAW,SAAS;AAClB,WAAO,KAAK,gBAAgB;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,aAAa,cAAc,WAAW,KAAK,SAAkB;AAC3D,QAAI,mBAAmB;AACvB,WAAO,KAAK,QAAQ;AAClB,YAAM,MAAM,QAAQ;AACpB,UAAI,qBAAqB,QAAW;AAClC,4BAAoB;AACpB,YAAI,oBAAoB,GAAG;AACzB,iBAAO,KAAK;AAAA,QACd;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,OAAO,iBAAiB,OAAc,EAAE,KAAK,GAAiB,oBAA6B;AACzF,SAAK,OAAO,MAAM,oCAAoC,IAAI,MAAM,MAAM,OAAO,IAAI,KAAK;AACtF,QAAI,uBAAuB,QAAW;AACpC,WAAK,OAAO,KAAK,yBAAyB,IAAI,MAAM,kBAAkB;AAAA,IACxE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,OAAU,SAAgE,QAA0B;AACzG,UAAM,qBAAsB,IAAI,MAAM,OAAO,EAAG;AAGhD,UAAM,iBAAiB;AAAA,MACrB,GAAG;AAAA,MAAqB,GAAG,WAAW,IAAI,QAAQ;AAAA,MAAQ,GAAG;AAAA,IAC/D;AACA,UAAM,kBAAkB,OAAO,YAAY,aAAc,QAAkC,IAAI;AAC/F,QAAI,UAAU,eAAe,GAAG;AAC9B,UAAI;AACF,YAAI,YAAY;AAChB,aAAK;AAEL,cAAM,iBAAiB,YAAY;AACjC,gBAAM,gBACH,KAAK,CAAC,WAAc;AACnB,iBAAK;AACL,wBAAY;AACZ,4BAAgB,aAAa,CAAC,QAAQ,MAAS,CAAC;AAAA,UAClD,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,iBAAK;AACL,wBAAY;AACZ,iBAAK,OAAO,MAAM,+BAA+B,QAAQ,QAAQ,SAAS,MAAM,MAAM,OAAO,IAAI,KAAK;AACtG,4BAAgB,aAAa,CAAC,QAAW,KAAK,CAAC;AAAA,UACjD,CAAC;AAAA,QACL;AAEA,cAAM,WAAW,CAAC,eAAe,CAAC;AAGlC,cAAM,UAAU,eAAe,WAAW,oBAAoB;AAC9D,YAAI,SAAS,OAAO,GAAG;AACrB,gBAAM,cAAc,YAAY;AAC9B,kBAAM,MAAM,OAAO;AACnB,gBAAI,CAAC,WAAW;AACd,6BAAe,WAAW;AAC1B,mBAAK,eAAe,SAAS,gBAAgB,kBAAkB;AAAA,YACjE;AAAA,UACF;AACA,mBAAS,KAAK,YAAY,CAAC;AAAA,QAC7B;AAEA,cAAM,MAAM,QAAQ,KAAK,QAAQ;AAEjC,YACG,KAAK,MAAM;AACV;AAAA,QACF,CAAC,EACA,MAAM,MAAM;AACX;AAAA,QACF,CAAC;AAAA,MACL,SAAS,IAAI;AACX,aAAK,mBAAmB;AACxB,wBAAgB,cAAc,EAAW;AACzC,aAAK,iBAAiB,IAAa,gBAAgB,kBAAkB;AAAA,MACvE;AAAA,IACF,OAAO;AAEL;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,OAAO,eAAe,MAAc,EAAE,OAAO,UAAU,GAAiB,oBAA6B;AACnG,SAAK,OAAO,MAAM,oCAAoC,IAAI,oBAAoB,IAAI,GAAG;AACrF,QAAI,uBAAuB,QAAW;AACpC,WAAK,OAAO,KAAK,yBAAyB,IAAI,MAAM,kBAAkB;AAAA,IACxE;AAAA,EACF;AACF;;;ACzHO,IAAM,oBAAN,cAAgC,cAAc;AAAA;AAAA,EAEnD,OAAgB,iBAAiB,OAAc,QAA0B,oBAA6B;AAEpG,UAAM,iBAAiB,OAAO,QAAQ,kBAAkB;AACxD,QAAI,QAAQ,yBAAyB,MAAM;AACzC,WAAK,OAAO,MAAM,oCAAoC,QAAQ,QAAQ,SAAS,MAAM;AAErF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAAA;AAAA,EAGA,OAAgB,OAAU,SAAwB,QAA8B;AAC9E,UAAM,iBAAiB;AAAA,MACrB,GAAG;AAAA,MAAyB,GAAG,WAAW,IAAI,QAAQ;AAAA,MAAQ,GAAG;AAAA,IACnE;AACA,UAAM,OAAO,SAAS,cAAc;AAAA,EACtC;AAAA;AAAA,EAGA,OAAgB,eAAe,MAAc,QAA0B,oBAA6B;AAClG,UAAM,eAAe,MAAM,QAAQ,kBAAkB;AACrD,QAAI,QAAQ,uBAAuB,MAAM;AACvC,WAAK,OAAO,MAAM,oCAAoC,QAAQ,QAAQ,SAAS,MAAM;AAErF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AACF;;;AC7BO,IAAM,aAAa,CAAI,SAAwB,WAAiC;AACrF,oBAAkB,OAAU,SAAS,MAAM;AAC7C;","names":[]}