{"version":3,"file":"index.cjs","names":["isInteger","getPreciseType","safeStableStringify","isNull","AbortError","createMessage"],"sources":["../../src/promises/CustomPromise.ts","../../src/promises/delay.ts"],"sourcesContent":["import type { CustomPromiseType } from \"@rzl-zone/ts-types-plus\";\n\nexport type { CustomPromiseType };\n\n/** -------------------------------------------------------------\n * * ***Utility Class: `CustomPromise`.***\n * --------------------------------------------------------------\n * **A strongly typed extension of the native {@link Promise | **`Promise`**}.**\n *\n * ---\n *  1. **Behaves exactly like a normal Promise** for `then`/`catch`\n *      and `await` semantics.\n *  2. **Stores the final resolution or rejection internally** so\n *      it can be retrieved by a custom `finish` handler.\n *  3. **Adds a `finish` method** which runs once after settlement\n *      with access to both the fulfilled value *and* the rejection\n *      reason (only one will be defined).\n *\n * ---\n * - **Key Differences from a Native `Promise`:**\n *     - Every call to `then`/`catch` returns **`CustomPromise`**\n *       again, so the `finish` method remains available on the\n *       entire chain.\n *     - `finish` provides a tuple-like callback:\n *        - `val`  ➔ defined when fulfilled.\n *        - `err`  ➔ defined when rejected.\n *\n * ---\n * @template Success  Type of the resolved value.\n * @template Error    Type of the rejection reason (default `unknown`).\n *\n * ---\n * @example\n *  ```ts\n *  import { CustomPromise, type CustomPromiseType } from \"@rzl-zone/utils-js/promises\";\n *\n *  type User = { id: number; name: string };\n *  type ApiError = { message: string };\n *\n *  function fetchUser(): CustomPromiseType<User, ApiError> {\n *    return new CustomPromise<User, ApiError>((resolve, reject) => {\n *      setTimeout(\n *        () =>\n *          void (Math.random() > 0.5\n *            ? resolve({ id: 1, name: \"Alice\" })\n *            : reject({ message: \"Random failure\" })),\n *        500\n *      );\n *    });\n *  }\n *\n *  fetchUser()\n *    .then(user => {\n *       console.log(\"SUCCESS:\", user);\n *       return user;\n *     })\n *    .catch(err => {\n *       console.error(\"ERROR:\", err);\n *       throw err;\n *     })\n *    .finish((val, err) => {\n *      // Runs once after settle, regardless of outcome\n *      console.log(\"FINISH:\", { val, err });\n *    });\n *  ```\n * ---\n * - **Implementation Notes:**\n *     - Uses `Object.setPrototypeOf` to preserve the prototype chain\n *       for environments targeting ES5 or when subclassing Promise.\n *     - Internal settlement state is tracked automatically,\n *       allowing `finish` to access the final result even\n *       when registered after settlement.\n */\nexport class CustomPromise<Success, Failure = unknown>\n  extends Promise<Success>\n  implements CustomPromiseType<Success, Failure>\n{\n  /** ------------------------------------------------------------\n   *\n   * @internal\n   * Stores the resolved value after promise settlement.\n   *\n   * -------------------------------------------------------------\n   */\n  private _value?: Success;\n  /** ------------------------------------------------------------\n   *\n   * @internal\n   * Stores the rejection reason after promise settlement.\n   *\n   * -------------------------------------------------------------\n   */\n  private _error?: Failure;\n  /** ------------------------------------------------------------\n   *\n   * @internal\n   * Stores registered `finish` callbacks until the\n   * promise settles.\n   *\n   * -------------------------------------------------------------\n   */\n  private _finish: Array<(v?: Success, e?: Failure) => void> = [];\n\n  /** ------------------------------------------------------------\n   * * ***Constructor: `CustomPromise`.***\n   * -------------------------------------------------------------\n   * **Creates a new `CustomPromise` instance using a custom executor.**\n   *\n   * ---\n   * - **Behavior:**\n   *     - Behaves similarly to the native\n   *       ***`Promise`*** constructor.\n   *     - Receives custom `resolve` and `reject`\n   *       functions through the executor callback.\n   *     - Stores the resolved value or rejection reason\n   *       internally for use by `finish`.\n   *     - Preserves the `CustomPromise` prototype chain\n   *       for subclassed promise behavior.\n   *     - Ensures chained `then` and `catch`\n   *       operations continue returning\n   *       ***`CustomPromise`*** instances.\n   *\n   * ---\n   * @param {(resolve, reject) => void} executor\n   * ***Executor function responsible for controlling the asynchronous operation lifecycle.***\n   *\n   * @param {(value: Success) => void} executor.resolve\n   * ***Function used to resolve the promise with a value.***\n   *\n   * @param {(error: Error) => void} executor.reject\n   * ***Function used to reject the promise with an error.***\n   *\n   * ---\n   * @throws **{@link Error | `Error`}**\n   * Any uncaught exception thrown inside the executor\n   * automatically rejects the promise.\n   *\n   * ---\n   * @example\n   * ```ts\n   * const promise = new CustomPromise<string>(\n   *   (resolve) => {\n   *     setTimeout(\n   *       () => resolve(\"Done\"),\n   *       1000\n   *     );\n   *   }\n   * );\n   * ```\n   * ---\n   * @example\n   * ```ts\n   * const promise = new CustomPromise<\n   *   string,\n   *   Error\n   * >((resolve, reject) => {\n   *   Math.random() > 0.5\n   *     ? resolve(\"Success\")\n   *     : reject(\n   *         new Error(\"Failed\")\n   *       );\n   * });\n   * ```\n   */\n  constructor(\n    executor: (\n      /**\n       * * ***Function used to resolve the promise with a value.***\n       */\n      resolve: (value: Success) => void,\n\n      /**\n       * * ***Function used to reject the promise with an error.***\n       */\n      reject: (error: Failure) => void\n    ) => void\n  ) {\n    let resolveOuter: (v: Success) => void;\n    let rejectOuter: (e: Failure) => void;\n\n    super((resolve, reject) => {\n      resolveOuter = resolve;\n      rejectOuter = reject;\n    });\n\n    executor(\n      async (val) => {\n        this._value = await val;\n        resolveOuter(val);\n        this._finish.forEach(async (fn) => fn(await val, undefined));\n      },\n      async (err) => {\n        this._error = await err;\n        rejectOuter(err);\n        this._finish.forEach(async (fn) => fn(undefined, await err));\n      }\n    );\n\n    Object.setPrototypeOf(this, new.target.prototype);\n  }\n\n  /** ---------------------------------------------------------------\n   * * ***Overrides `Promise.then()` while preserving the\n   * `CustomPromise` prototype chain.***\n   * ----------------------------------------------------------------\n   * **Registers callbacks for both fulfillment and rejection.**\n   *\n   * ---\n   * Unlike the native `Promise`, this override ensures the returned\n   * value remains a ***`CustomPromise`*** so additional methods\n   * such as `finish()` continue to be available throughout the chain.\n   *\n   * ---\n   * @template TResult1\n   * ***Result type returned by the fulfillment handler.***\n   *\n   * @template TResult2\n   * ***Result type returned by the rejection handler.***\n   *\n   * ---\n   * @param onfulfilled\n   * ***Callback executed when the promise resolves successfully.***\n   *\n   * @param onfulfilled.value\n   * ***Resolved value from the current promise.***\n   *\n   * @param onrejected\n   * ***Callback executed when the promise is rejected.***\n   *\n   * @param onrejected.reason\n   * ***Rejection reason from the current promise.***\n   *\n   * ---\n   * @returns A new ***`CustomPromise`*** containing the transformed result.\n   */\n  override then<TResult1 = Success, TResult2 = never>(\n    onfulfilled?:\n      | ((\n          /**\n           * * ***Resolved value from the current promise.***\n           */\n          value: Success\n        ) => TResult1 | PromiseLike<TResult1>)\n      | null,\n    onrejected?:\n      | ((\n          /**\n           * * ***Rejection reason from the current promise.***\n           */\n          reason: Failure\n        ) => TResult2 | PromiseLike<TResult2>)\n      | null\n  ): CustomPromise<TResult1 | TResult2, Failure> {\n    return super.then(onfulfilled, onrejected) as unknown as CustomPromise<\n      TResult1 | TResult2,\n      Failure\n    >;\n  }\n\n  /** ---------------------------------------------------------------\n   * * ***Overrides `Promise.catch()` while preserving the\n   * `CustomPromise` prototype chain.***\n   * ----------------------------------------------------------------\n   * **Registers a callback for promise rejection handling.**\n   *\n   * ---\n   * Unlike the native `Promise`, this override ensures the returned\n   * value remains a ***`CustomPromise`*** so additional methods\n   * such as `finish()` continue to be available throughout the chain.\n   *\n   * ---\n   * @template TResult\n   * ***Result type returned by the rejection handler.***\n   *\n   * ---\n   * @param onrejected\n   * ***Callback executed when the promise is rejected.***\n   *\n   * @param onrejected.reason\n   * ***Rejection reason from the current promise.***\n   *\n   * ---\n   * @returns A new ***`CustomPromise`*** containing either the\n   * original success value or the transformed rejection result.\n   */\n  override catch<TResult = never>(\n    onrejected?:\n      | ((\n          /**\n           * * ***Rejection reason from the current promise.***\n           */\n          reason: Failure\n        ) => TResult | PromiseLike<TResult>)\n      | null\n  ): CustomPromise<Success | TResult, Failure> {\n    return super.catch(onrejected) as unknown as CustomPromise<\n      Success | TResult,\n      Failure\n    >;\n  }\n\n  /** ---------------------------------------------------------------\n   * * ***Registers a callback to be invoked exactly once when the\n   * promise settles.***\n   * ----------------------------------------------------------------\n   * *If the promise is already settled when `finish()` is called,\n   * the callback executes immediately on the same tick.*\n   *\n   * ---\n   * @param callback\n   * ***Callback receiving the final settlement result.***\n   *\n   * @param callback.value\n   * ***Resolved value when the promise is fulfilled.***\n   *\n   * @param callback.error\n   * ***Rejection reason when the promise is rejected.***\n   *\n   * ---\n   * @returns `this` for fluent chaining.\n   */\n  finish(\n    callback: (\n      /**\n       * * ***Resolved value when the promise is fulfilled.***\n       */\n      value?: Success,\n\n      /**\n       * * ***Rejection reason when the promise is rejected.***\n       */\n      error?: Failure\n    ) => void\n  ): this {\n    if (this._value !== undefined || this._error !== undefined) {\n      callback(this._value, this._error);\n    } else {\n      this._finish.push(callback);\n    }\n    return this;\n  }\n}\n","import { createMessage } from \"@/_private/logger\";\n\nimport { AbortError } from \"@/errors/AbortError\";\nimport { isNull } from \"@/predicates/is/isNull\";\nimport { isInteger } from \"@/predicates/is/isInteger\";\nimport { getPreciseType } from \"@/predicates/type/getPreciseType\";\nimport { safeStableStringify } from \"@/conversions/stringify/safeStableStringify\";\n\n/** ------------------------------------------------------------\n * * ***Utility: `delay`.***\n * -------------------------------------------------------------\n * **Creates a Promise-based delay that resolves after a given number\n * of milliseconds, optionally supports cancellation with `AbortSignal`.**\n *\n * ---\n * - **Behavior:**\n *     - Validates `milliSeconds` is a non-zero, non-negative integer.\n *     - Validates `signal` is an `AbortSignal` instance when provided.\n *     - Cleans up event listeners and timers properly.\n *\n * ---\n * @param {number} [milliSeconds=1000]\n *  The duration of the delay in milliseconds, default is `1000`.\n * @param {AbortSignal} [signal]\n *  An optional `AbortSignal` that can cancel the delay.\n *\n * ---\n * @throws **{@link TypeError | `TypeError`}** while validates `milliSeconds` and `signal`:\n *  - If `milliSeconds` **is not a valid** an `integer-number`, `NaN`, `negative-number`, or `≤ 0`.\n *  - If `signal` **is not a valid** an`AbortSignal`.\n * @throws **{@link AbortError | `AbortError`}** if the delay is aborted using the provided signal.\n *\n * ---\n * @returns {Promise<void>}\n *  A promise that resolves after the specified delay or\n *  rejects with an `AbortError` if aborted.\n *\n * ---\n * @example\n * 1. #### Waits for 2 seconds:\n *    ```ts\n *    await delay(2000);\n *    ```\n *    ---\n * 2. #### Delay with AbortSignal:\n *    ```ts\n *    const controller = new AbortController();\n *    delay(5000, controller.signal).catch(err => {\n *     console.log(err.name)\n *     // ➔ \"AbortError:['@rzl-zone/utils-js/promises:delay']\"\n *    });\n *    controller.abort();\n *    ```\n */\nexport const delay = (\n  milliSeconds: number = 1000,\n  signal?: AbortSignal\n): Promise<void> => {\n  if (!isInteger(milliSeconds) || milliSeconds <= 0) {\n    throw new TypeError(\n      errorMsg(\n        `First parameter (\\`milliSeconds\\`) must be of type \\`number\\` and value must be a \\`non-zero\\`, \\`non-NaN\\`, \\`non-negative\\`, and \\`integer-number\\`, but received: \\`${getPreciseType(\n          milliSeconds\n        )}\\`, with value: \\`${safeStableStringify(milliSeconds, {\n          keepUndefined: true\n        })}\\`.`\n      )\n    );\n  }\n\n  if (isNull(signal) || (signal && !(signal instanceof AbortSignal))) {\n    throw new TypeError(\n      errorMsg(\n        \"Second parameter (`signal`) must be an `instance of AbortSignal` if provided.\"\n      )\n    );\n  }\n\n  return new Promise<void>((resolve, reject) => {\n    const timer = setTimeout(() => {\n      cleanup();\n      resolve();\n    }, milliSeconds);\n\n    const cleanup = () => {\n      clearTimeout(timer);\n      if (signal) signal.removeEventListener(\"abort\", onAbort);\n    };\n\n    const onAbort = () => {\n      cleanup();\n      reject(\n        new AbortError(\n          \"Function `delay` from `@rzl-zone/utils-js` was aborted.\",\n          {\n            suffix: \":['@rzl-zone/utils-js/promises:delay']\"\n          }\n        )\n      );\n    };\n\n    if (signal) {\n      if (signal.aborted) {\n        onAbort();\n        return;\n      }\n\n      signal.addEventListener(\"abort\", onAbort, { once: true });\n    }\n  });\n};\n\n/**\n * @internal ***`Not part of the public API.`***\n */\nconst errorMsg = (msg: string) => createMessage(\"delay\", msg);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyEA,IAAa,gBAAb,cACU,QAEV;;;;;;;;CAQE,AAAQ;;;;;;;;CAQR,AAAQ;;;;;;;;;CASR,AAAQ,UAAqD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+D9D,YACE,UAWA;EACA,IAAI;EACJ,IAAI;EAEJ,OAAO,SAAS,WAAW;GACzB,eAAe;GACf,cAAc;EAChB,CAAC;EAED,SACE,OAAO,QAAQ;GACb,KAAK,SAAS,MAAM;GACpB,aAAa,GAAG;GAChB,KAAK,QAAQ,QAAQ,OAAO,OAAO,GAAG,MAAM,KAAK,MAAS,CAAC;EAC7D,GACA,OAAO,QAAQ;GACb,KAAK,SAAS,MAAM;GACpB,YAAY,GAAG;GACf,KAAK,QAAQ,QAAQ,OAAO,OAAO,GAAG,QAAW,MAAM,GAAG,CAAC;EAC7D,CACF;EAEA,OAAO,eAAe,MAAM,IAAI,OAAO,SAAS;CAClD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoCA,AAAS,KACP,aAQA,YAQ6C;EAC7C,OAAO,MAAM,KAAK,aAAa,UAAU;CAI3C;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BA,AAAS,MACP,YAQ2C;EAC3C,OAAO,MAAM,MAAM,UAAU;CAI/B;;;;;;;;;;;;;;;;;;;;;CAsBA,OACE,UAWM;EACN,IAAI,KAAK,WAAW,UAAa,KAAK,WAAW,QAC/C,SAAS,KAAK,QAAQ,KAAK,MAAM;OAEjC,KAAK,QAAQ,KAAK,QAAQ;EAE5B,OAAO;CACT;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/RA,MAAa,SACX,eAAuB,KACvB,WACkB;CAClB,IAAI,CAACA,4BAAU,YAAY,KAAK,gBAAgB,GAC9C,MAAM,IAAI,UACR,SACE,0KAA0KC,8BACxK,YACF,EAAE,oBAAoBC,gDAAoB,cAAc,EACtD,eAAe,KACjB,CAAC,EAAE,IACL,CACF;CAGF,IAAIC,sBAAO,MAAM,KAAM,UAAU,EAAE,kBAAkB,cACnD,MAAM,IAAI,UACR,SACE,+EACF,CACF;CAGF,OAAO,IAAI,SAAe,SAAS,WAAW;EAC5C,MAAM,QAAQ,iBAAiB;GAC7B,QAAQ;GACR,QAAQ;EACV,GAAG,YAAY;EAEf,MAAM,gBAAgB;GACpB,aAAa,KAAK;GAClB,IAAI,QAAQ,OAAO,oBAAoB,SAAS,OAAO;EACzD;EAEA,MAAM,gBAAgB;GACpB,QAAQ;GACR,OACE,IAAIC,8BACF,2DACA,EACE,QAAQ,yCACV,CACF,CACF;EACF;EAEA,IAAI,QAAQ;GACV,IAAI,OAAO,SAAS;IAClB,QAAQ;IACR;GACF;GAEA,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;EAC1D;CACF,CAAC;AACH;;;;AAKA,MAAM,YAAY,QAAgBC,6BAAc,SAAS,GAAG"}
