@ts-utilities/core 1.3.4 → 1.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- const e=e=>!e,t=e=>e==null,n=e=>typeof e==`boolean`,r=e=>typeof e==`string`,i=e=>{if(typeof e==`number`)return Number.isFinite(e);if(typeof e==`string`){let t=Number(e);return Number.isFinite(t)}return!1},a=e=>Array.isArray(e),o=e=>typeof e==`function`,s=e=>{if(e==null)return!0;switch(typeof e){case`string`:case`number`:case`bigint`:case`boolean`:case`symbol`:return!0;default:return!1}};function c(e){if(typeof e!=`object`||!e||Object.prototype.toString.call(e)!==`[object Object]`)return!1;let t=Object.getPrototypeOf(e);return t===null||t===Object.prototype}function l(e,...t){let n,r={},i=t[t.length-1];i&&typeof i==`object`&&!Array.isArray(i)&&(i.arrayMerge!==void 0||i.clone!==void 0||i.customMerge!==void 0||i.functionMerge!==void 0||i.maxDepth!==void 0)?(r={...r,...i},n=t.slice(0,-1)):n=t;let{arrayMerge:a=`replace`,clone:o=!0,functionMerge:s=`replace`,maxDepth:l=100,customMerge:u}=r,d=new WeakMap;return f(e,n,0);function f(e,t,n){if(n>=l)return console.warn(`[deepmerge] Maximum depth ${l} exceeded. Returning target as-is.`),e;if(!c(e)&&!Array.isArray(e)){for(let n of t)if(n!==void 0){if(u){let t=u(``,e,n);if(t!==void 0)return t}return typeof e==`function`&&typeof n==`function`&&s===`compose`?(...t)=>{e(...t),n(...t)}:n}return e}let r=o?Array.isArray(e)?[...e]:{...e}:e;for(let e of t)if(e!=null&&!d.has(e))if(d.set(e,r),Array.isArray(r)&&Array.isArray(e))r=p(r,e,a);else if(c(r)&&c(e)){let t=new Set([...Object.keys(r),...Object.keys(e),...Object.getOwnPropertySymbols(r),...Object.getOwnPropertySymbols(e)]);for(let i of t){let t=r[i],o=e[i];u&&u(i,t,o)!==void 0?r[i]=u(i,t,o):typeof t==`function`&&typeof o==`function`?s===`compose`?r[i]=(...e)=>{t(...e),o(...e)}:r[i]=o:c(t)&&c(o)?r[i]=f(t,[o],n+1):Array.isArray(t)&&Array.isArray(o)?r[i]=p(t,o,a):o!==void 0&&(r[i]=o)}}else r=e;return r}function p(e,t,n){if(typeof n==`function`)return n(e,t);switch(n){case`concat`:return[...e,...t];case`merge`:let n=Math.max(e.length,t.length),r=[];for(let i=0;i<n;i++)i<e.length&&i<t.length?c(e[i])&&c(t[i])?r[i]=f(e[i],[t[i]],0):r[i]=t[i]:i<e.length?r[i]=e[i]:r[i]=t[i];return r;case`replace`:default:return[...t]}}}function u(e,t,n){if(Array.isArray(t))return t.map(t=>u(e,t,n));if(typeof t==`object`&&t&&!Array.isArray(t)){let r={};for(let i in t)t.hasOwnProperty(i)&&(r[i]=u(e,t[i],n));return r}if(typeof t!=`string`)return n;let r=(()=>t===``?[]:t.split(`.`).filter(e=>e!==``))(),i=e;for(let e of r){if(i==null)return n;let t=typeof e==`string`&&Array.isArray(i)&&/^\d+$/.test(e)?Number.parseInt(e,10):e;i=i[t]}return i===void 0?n:i}function d(e){return f(e)}function f(e){if(e!==null){if(typeof e!=`object`||!e)return e;if(Array.isArray(e))return e.map(f);if(c(e)){let t={};for(let n in e)t[n]=f(e[n]);return t}return e}}function p(e,t){return e==null?e:Object.assign(e,t)}function m(e){return(e.split(`.`).pop()||e).replace(/([a-z])([A-Z])/g,`$1 $2`).split(/[-_|�\s]+/).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `)}const h=`àáãäâèéëêìíïîòóöôùúüûñç·/_,:;`,g=`aaaaaeeeeiiiioooouuuunc------`,_=e=>{if(typeof e!=`string`)throw TypeError(`Input must be a string`);let t=e.trim().toLowerCase(),n={};for(let e=0;e<29;e++)n[h.charAt(e)]=`aaaaaeeeeiiiioooouuuunc------`.charAt(e);return t=t.replace(RegExp(`[${h}]`,`g`),e=>n[e]||e),t.replace(/[^a-z0-9 -]/g,``).replace(/\s+/g,`-`).replace(/-+/g,`-`).replace(/^-+/,``).replace(/-+$/,``)||``},v=(e=1e3,t)=>new Promise(n=>{if(t?.aborted)return n();let r=setTimeout(()=>{a(),n()},e);function i(){clearTimeout(r),a(),n()}function a(){t?.removeEventListener(`abort`,i)}t&&t.addEventListener(`abort`,i,{once:!0})});function y(e,t=100,n){if(typeof e!=`function`)throw TypeError(`Expected the first parameter to be a function, got \`${typeof e}\`.`);if(t<0)throw RangeError("`wait` must not be negative.");let r=n?.immediate??!1,i,a,o,s;function c(){return s=e.apply(o,a),a=void 0,o=void 0,s}let l=function(...e){return a=e,o=this,i===void 0&&r&&(s=c.call(this)),i!==void 0&&clearTimeout(i),i=setTimeout(c.bind(this),t),s};return Object.defineProperty(l,`isPending`,{get(){return i!==void 0}}),l}function b(e,t=100,n){if(typeof e!=`function`)throw TypeError(`Expected the first parameter to be a function, got \`${typeof e}\`.`);if(t<0)throw RangeError("`wait` must not be negative.");let r=n?.leading??!0,i=n?.trailing??!0,a,o,s,c,l;function u(){c=Date.now(),l=e.apply(s,o),o=void 0,s=void 0}function d(){a=void 0,i&&o&&u()}let f=function(...e){let n=c?Date.now()-c:1/0;return o=e,s=this,n>=t?r?u():a=setTimeout(d,t):!a&&i&&(a=setTimeout(d,t-n)),l};return Object.defineProperty(f,`isPending`,{get(){return a!==void 0}}),f}function x(e,...t){let n=t.length===1&&Array.isArray(t[0])?t[0]:t,r=0;return e.replace(/%s/g,()=>{let e=n[r++];return e===void 0?``:String(e)})}function S(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function C(e,t={}){if(!e)return``;let{lowercase:n=!0,removeAccents:r=!0,removeNonAlphanumeric:i=!0}=t,a=e.normalize(`NFC`);return r&&(a=a.normalize(`NFD`).replace(/\p{M}/gu,``)),i&&(a=a.replace(/^[^\p{L}\p{N}]*|[^\p{L}\p{N}]*$/gu,``)),n&&(a=a.toLocaleLowerCase()),a}function w(e,...t){return typeof e==`function`?e(...t):e}async function T(e,{interval:t=5e3,timeout:n=300*1e3,jitter:r=!0,signal:i}={}){let a=Date.now(),o=i?.aborted??!1,s=()=>{o=!0};i?.addEventListener(`abort`,s,{once:!0});try{for(let s=0;;s++){if(o)throw Error(`Polling aborted`);let s=await e();if(s)return s;if(Date.now()-a>=n)throw Error(`Polling timed out`,{cause:`Polling timed out after ${n}ms`});await v(r?t+(Math.random()-.5)*t*.2:t,i)}}catch(e){throw e}finally{i?.removeEventListener(`abort`,s)}}async function E(e,t={}){let{concurrency:n=1/0,timeout:r=1/0,signal:i,retry:a=0,retryDelay:o=0,throwOnFirstError:s=!1,ignoreErrors:c=!1}=t,l=Array.isArray(e),u={};l?e.forEach((e,t)=>{u[t.toString()]=e}):Object.entries(e).forEach(([e,t])=>{u[e]=t});let d=Object.keys(u);if(d.length===0)return{results:l?[]:{},errors:[],succeeded:0,failed:0,duration:0};let f=Date.now(),p=[],m=[],h=0,g=0,_=0,y=!1,b=s?null:void 0,x=async e=>{let t=0;for(;t<=a&&!y;)try{let t=u[e],n=await(typeof t==`function`?t():t);p.push([e,n]),g++;return}catch(e){if(t===a){let t=e instanceof Error?e:Error(String(e));m.push(t),_++,!c&&s&&!b&&(b=t,y=!0);return}t++,o>0&&await v(o,i)}},S=Array.from({length:Math.min(n,d.length)},async()=>{for(;!y;){let e=h++;if(e>=d.length)return;if(i?.aborted){y=!0;return}await x(d[e])}}),C=Promise.all(S);if(r===1/0?await C:await Promise.race([C,v(r,i).then(()=>{throw y=!0,Error(`Concurrence timed out after ${r}ms`)})]),b&&s)throw b;return l?{results:p.sort((e,t)=>Number(e[0])-Number(t[0])).map(([,e])=>e),errors:m,succeeded:g,failed:_,duration:Date.now()-f}:{results:Object.fromEntries(p),errors:m,succeeded:g,failed:_,duration:Date.now()-f}}function D(e,t={}){let{retry:n=0,delay:r=0}=t,i=Date.now(),a=async t=>{try{await e();let t=Date.now()-i;console.log(`⚡[schedule.ts] Completed in ${t}ms`)}catch(e){if(console.log(`⚡[schedule.ts] err:`,e),t>0)console.log(`⚡[schedule.ts] Retrying in ${r}ms...`),setTimeout(()=>a(t-1),r);else{let e=Date.now()-i;console.log(`⚡[schedule.ts] Failed after ${e}ms`)}}};setTimeout(()=>a(n),0)}function O(e){if(e instanceof Promise)return e.then(e=>[null,e]).catch(e=>[e,null]);try{return[null,e()]}catch(t){return console.log(`\x1b[31m🛡 [shield]\x1b[0m ${e.name} failed →`,t),[t,null]}}exports.convertToNormalCase=m,exports.convertToSlug=_,exports.debounce=y,exports.deepmerge=l,exports.escapeRegExp=S,exports.extendProps=p,exports.extract=u,exports.hydrate=d,exports.isArray=a,exports.isBoolean=n,exports.isFalsy=e,exports.isFiniteNumber=i,exports.isFunction=o,exports.isNullish=t,exports.isPlainObject=c,exports.isPrimitive=s,exports.isString=r,exports.normalizeText=C,exports.poll=T,exports.printf=x,exports.schedule=D,exports.shield=O,exports.sleep=v,exports.throttle=b,exports.unwrap=w,exports.withConcurrency=E;
1
+ const e=e=>!e,t=e=>e==null,n=e=>typeof e==`boolean`,r=e=>typeof e==`string`,i=e=>{if(typeof e==`number`)return Number.isFinite(e);if(typeof e==`string`){let t=Number(e);return Number.isFinite(t)}return!1},a=e=>Array.isArray(e),o=e=>typeof e==`function`,s=e=>{if(e==null)return!0;switch(typeof e){case`string`:case`number`:case`bigint`:case`boolean`:case`symbol`:return!0;default:return!1}};function c(e){if(typeof e!=`object`||!e||Object.prototype.toString.call(e)!==`[object Object]`)return!1;let t=Object.getPrototypeOf(e);return t===null||t===Object.prototype}function l(e,...t){let n,r={},i=t[t.length-1];i&&typeof i==`object`&&!Array.isArray(i)&&(i.arrayMerge!==void 0||i.clone!==void 0||i.customMerge!==void 0||i.functionMerge!==void 0||i.maxDepth!==void 0)?(r={...r,...i},n=t.slice(0,-1)):n=t;let{arrayMerge:a=`replace`,clone:o=!0,functionMerge:s=`replace`,maxDepth:l=100,customMerge:u}=r,d=new WeakMap;return f(e,n,0);function f(e,t,n){if(n>=l)return console.warn(`[deepmerge] Maximum depth ${l} exceeded. Returning target as-is.`),e;if(!c(e)&&!Array.isArray(e)){for(let n of t)if(n!==void 0){if(u){let t=u(``,e,n);if(t!==void 0)return t}return typeof e==`function`&&typeof n==`function`&&s===`compose`?(...t)=>{e(...t),n(...t)}:n}return e}let r=o?Array.isArray(e)?[...e]:{...e}:e;for(let e of t)if(e!=null&&!d.has(e))if(d.set(e,r),Array.isArray(r)&&Array.isArray(e))r=p(r,e,a);else if(c(r)&&c(e)){let t=new Set([...Object.keys(r),...Object.keys(e),...Object.getOwnPropertySymbols(r),...Object.getOwnPropertySymbols(e)]);for(let i of t){let t=r[i],o=e[i];u&&u(i,t,o)!==void 0?r[i]=u(i,t,o):typeof t==`function`&&typeof o==`function`?s===`compose`?r[i]=(...e)=>{t(...e),o(...e)}:r[i]=o:c(t)&&c(o)?r[i]=f(t,[o],n+1):Array.isArray(t)&&Array.isArray(o)?r[i]=p(t,o,a):o!==void 0&&(r[i]=o)}}else r=e;return r}function p(e,t,n){if(typeof n==`function`)return n(e,t);switch(n){case`concat`:return[...e,...t];case`merge`:let n=Math.max(e.length,t.length),r=[];for(let i=0;i<n;i++)i<e.length&&i<t.length?c(e[i])&&c(t[i])?r[i]=f(e[i],[t[i]],0):r[i]=t[i]:i<e.length?r[i]=e[i]:r[i]=t[i];return r;case`replace`:default:return[...t]}}}function u(e,t,n){if(Array.isArray(t))return t.map(t=>u(e,t,n));if(typeof t==`object`&&t&&!Array.isArray(t)){let r={};for(let i in t)t.hasOwnProperty(i)&&(r[i]=u(e,t[i],n));return r}if(typeof t!=`string`)return n;let r=(()=>t===``?[]:t.split(`.`).filter(e=>e!==``))(),i=e;for(let e of r){if(i==null)return n;let t=typeof e==`string`&&Array.isArray(i)&&/^\d+$/.test(e)?Number.parseInt(e,10):e;i=i[t]}return i===void 0?n:i}function d(e){return f(e)}function f(e){if(e!==null){if(typeof e!=`object`||!e)return e;if(Array.isArray(e))return e.map(f);if(c(e)){let t={};for(let n in e)t[n]=f(e[n]);return t}return e}}function p(e,t){return e==null?e:Object.assign(e,t)}function m(e){return(e.split(`.`).pop()||e).replace(/([a-z])([A-Z])/g,`$1 $2`).split(/[-_|�\s]+/).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `)}const h=`àáãäâèéëêìíïîòóöôùúüûñç·/_,:;`,g=`aaaaaeeeeiiiioooouuuunc------`,_=e=>{if(typeof e!=`string`)throw TypeError(`Input must be a string`);let t=e.trim().toLowerCase(),n={};for(let e=0;e<29;e++)n[h.charAt(e)]=`aaaaaeeeeiiiioooouuuunc------`.charAt(e);return t=t.replace(RegExp(`[${h}]`,`g`),e=>n[e]||e),t.replace(/[^a-z0-9 -]/g,``).replace(/\s+/g,`-`).replace(/-+/g,`-`).replace(/^-+/,``).replace(/-+$/,``)||``},v=(e=1e3,t)=>new Promise(n=>{if(t?.aborted)return n();let r=setTimeout(()=>{a(),n()},e);function i(){clearTimeout(r),a(),n()}function a(){t?.removeEventListener(`abort`,i)}t&&t.addEventListener(`abort`,i,{once:!0})});function y(e,t=100,n){if(typeof e!=`function`)throw TypeError(`Expected the first parameter to be a function, got \`${typeof e}\`.`);if(t<0)throw RangeError("`wait` must not be negative.");let r=n?.immediate??!1,i,a,o,s;function c(){return s=e.apply(o,a),a=void 0,o=void 0,s}let l=function(...e){return a=e,o=this,i===void 0&&r&&(s=c.call(this)),i!==void 0&&clearTimeout(i),i=setTimeout(c.bind(this),t),s};return Object.defineProperty(l,`isPending`,{get(){return i!==void 0}}),l}function b(e,t=100,n){if(typeof e!=`function`)throw TypeError(`Expected the first parameter to be a function, got \`${typeof e}\`.`);if(t<0)throw RangeError("`wait` must not be negative.");let r=n?.leading??!0,i=n?.trailing??!0,a,o,s,c,l;function u(){c=Date.now(),l=e.apply(s,o),o=void 0,s=void 0}function d(){a=void 0,i&&o&&u()}let f=function(...e){let n=c?Date.now()-c:1/0;return o=e,s=this,n>=t?r?u():a=setTimeout(d,t):!a&&i&&(a=setTimeout(d,t-n)),l};return Object.defineProperty(f,`isPending`,{get(){return a!==void 0}}),f}function x(e,...t){let n=t.length===1&&Array.isArray(t[0])?t[0]:t,r=0;return e.replace(/%s/g,()=>{let e=n[r++];return e===void 0?``:String(e)})}function S(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function C(e,t={}){if(!e)return``;let{lowercase:n=!0,removeAccents:r=!0,removeNonAlphanumeric:i=!0}=t,a=e.normalize(`NFC`);return r&&(a=a.normalize(`NFD`).replace(/\p{M}/gu,``)),i&&(a=a.replace(/^[^\p{L}\p{N}]*|[^\p{L}\p{N}]*$/gu,``)),n&&(a=a.toLocaleLowerCase()),a}function w(e,...t){return typeof e==`function`?e(...t):e}const T=Symbol(`poll.signal.abort`),E=Symbol(`poll.signal.retry`);async function*D(e,{interval:t=5e3,timeout:n=300*1e3,jitter:r=!0,signal:i}={}){let a=Date.now();for(;;){if(i?.aborted)throw new DOMException(`Polling aborted`,`AbortError`);let o=await e();if(o===T)return;if(o===E){await v(r?t+(Math.random()-.5)*t*.2:t,i);continue}if(o){yield o;return}if(Date.now()-a>=n)throw Error(`Polling timed out after ${n}ms`);yield null,await v(r?t+(Math.random()-.5)*t*.2:t,i)}}async function O(e,t={}){for await(let n of D(e,t))if(n)return n}const k={wait:O,watch:D,signal:{abort:T,retry:E}};async function A(e,t={}){let{concurrency:n=1/0,timeout:r=1/0,signal:i,retry:a=0,retryDelay:o=0,throwOnFirstError:s=!1,ignoreErrors:c=!1}=t,l=Array.isArray(e),u={};l?e.forEach((e,t)=>{u[t.toString()]=e}):Object.entries(e).forEach(([e,t])=>{u[e]=t});let d=Object.keys(u);if(d.length===0)return{results:l?[]:{},errors:[],succeeded:0,failed:0,duration:0};let f=Date.now(),p=[],m=[],h=0,g=0,_=0,y=!1,b=s?null:void 0,x=async e=>{let t=0;for(;t<=a&&!y;)try{let t=u[e],n=await(typeof t==`function`?t():t);p.push([e,n]),g++;return}catch(e){if(t===a){let t=e instanceof Error?e:Error(String(e));m.push(t),_++,!c&&s&&!b&&(b=t,y=!0);return}t++,o>0&&await v(o,i)}},S=Array.from({length:Math.min(n,d.length)},async()=>{for(;!y;){let e=h++;if(e>=d.length)return;if(i?.aborted){y=!0;return}await x(d[e])}}),C=Promise.all(S);if(r===1/0?await C:await Promise.race([C,v(r,i).then(()=>{throw y=!0,Error(`Concurrence timed out after ${r}ms`)})]),b&&s)throw b;return l?{results:p.sort((e,t)=>Number(e[0])-Number(t[0])).map(([,e])=>e),errors:m,succeeded:g,failed:_,duration:Date.now()-f}:{results:Object.fromEntries(p),errors:m,succeeded:g,failed:_,duration:Date.now()-f}}function j(e,t={}){let{retry:n=0,delay:r=0,debug:i=!1}=t,a=Date.now(),o=async t=>{try{if(await e(),i){let e=Date.now()-a;console.log(`⚡[schedule.ts] Completed in ${e}ms`)}}catch(e){if(i&&console.log(`⚡[schedule.ts] err:`,e),t>0)i&&console.log(`⚡[schedule.ts] Retrying in ${r}ms...`),setTimeout(()=>o(t-1),r);else if(i){let e=Date.now()-a;console.log(`⚡[schedule.ts] Failed after ${e}ms`)}}};setTimeout(()=>o(n),0)}function M(e){if(e instanceof Promise)return e.then(e=>[null,e]).catch(e=>[e,null]);try{return[null,e()]}catch(t){return console.log(`\x1b[31m🛡 [shield]\x1b[0m ${e.name} failed →`,t),[t,null]}}exports.convertToNormalCase=m,exports.convertToSlug=_,exports.debounce=y,exports.deepmerge=l,exports.escapeRegExp=S,exports.extendProps=p,exports.extract=u,exports.hydrate=d,exports.isArray=a,exports.isBoolean=n,exports.isFalsy=e,exports.isFiniteNumber=i,exports.isFunction=o,exports.isNullish=t,exports.isPlainObject=c,exports.isPrimitive=s,exports.isString=r,exports.normalizeText=C,exports.poll=k,exports.printf=x,exports.schedule=j,exports.shield=M,exports.sleep=v,exports.throttle=b,exports.unwrap=w,exports.withConcurrency=A;
package/dist/index.d.cts CHANGED
@@ -994,17 +994,93 @@ declare function hydrate<T>(data: T): Hydrate<T>;
994
994
  declare function extendProps<T, P$1 extends object>(base: T, props: P$1): T extends null | undefined ? T : T & P$1;
995
995
  //#endregion
996
996
  //#region src/functions/poll.d.ts
997
+ type PollOptions = Partial<{
998
+ interval: number;
999
+ timeout: number;
1000
+ signal: AbortSignal;
1001
+ jitter: boolean;
1002
+ }>;
1003
+ declare const ABORT: unique symbol;
1004
+ declare const RETRY: unique symbol;
1005
+ type PollControl = typeof ABORT | typeof RETRY;
1006
+ /**
1007
+ * Streams an async `cond` function, yielding `null` while waiting and the
1008
+ * final truthy value `T` when resolved.
1009
+ *
1010
+ * Designed for use in tRPC subscriptions or any async generator context where
1011
+ * you want to stream progress to the client instead of blocking.
1012
+ *
1013
+ * Keeps SSE/WebSocket connections alive on edge runtimes (e.g. Vercel) by
1014
+ * continuously emitting values rather than holding a silent open connection.
1015
+ *
1016
+ * @template T The type of the successful result.
1017
+ *
1018
+ * @param cond
1019
+ * A function returning a Promise that resolves to:
1020
+ * - a truthy value `T` → stop polling and yield it
1021
+ * - `poll.signal.abort` → stop polling cleanly with no error
1022
+ * - `poll.signal.retry` → skip this tick silently, no null emitted
1023
+ * - falsy/null/undefined → yield `null` and continue polling
1024
+ *
1025
+ * @param options
1026
+ * Configuration options:
1027
+ * - `interval` (number) — Time between polls in ms (default: 5000 ms)
1028
+ * - `timeout` (number) — Max total duration before failing (default: 5 min)
1029
+ * - `jitter` (boolean) — Add small random offset (±10%) to intervals to avoid sync bursts (default: true)
1030
+ * - `signal` (AbortSignal) — Optional abort signal to cancel polling
1031
+ *
1032
+ * @throws `AbortError` if aborted via signal
1033
+ * @throws `Error` if timed out
1034
+ *
1035
+ * @example
1036
+ * ```ts
1037
+ * // tRPC subscription — stream null while job is pending, emit result when done
1038
+ * syncImageJob: privateProcedure
1039
+ * .input(z.object({ id: z.coerce.number() }))
1040
+ * .subscription(async function* ({ ctx, input, signal }) {
1041
+ * yield* poll.watch(
1042
+ * async () => {
1043
+ * const job = await getJob(input.id);
1044
+ * if (job?.is_cancelled) return poll.signal.abort; // stop cleanly
1045
+ * if (job?.is_paused) return poll.signal.retry; // skip this tick
1046
+ * return job?.is_finished ? job : null;
1047
+ * },
1048
+ * { interval: 15000, signal },
1049
+ * );
1050
+ * }),
1051
+ * ```
1052
+ *
1053
+ * @example
1054
+ * ```ts
1055
+ * // Manually iterate
1056
+ * for await (const result of poll.watch(() => getJobStatus(), { interval: 3000 })) {
1057
+ * if (result === null) console.log('still waiting...');
1058
+ * else console.log('done!', result);
1059
+ * }
1060
+ * ```
1061
+ */
1062
+ declare function watch<T>(cond: () => Promise<T | null | false | undefined | PollControl>, {
1063
+ interval,
1064
+ timeout,
1065
+ jitter,
1066
+ signal
1067
+ }?: PollOptions): AsyncGenerator<T | null>;
997
1068
  /**
998
1069
  * Repeatedly polls an async `cond` function UNTIL it returns a TRUTHY value,
999
1070
  * or until the operation times out or is aborted.
1000
1071
  *
1001
- * Designed for waiting on async jobs, external state, or delayed availability.
1072
+ * Designed for waiting on async jobs, external state, or delayed availability
1073
+ * where you only care about the final result and not intermediate states.
1074
+ *
1075
+ * Use `poll.watch` instead if you need to stream progress (e.g. tRPC subscriptions).
1002
1076
  *
1003
1077
  * @template T The type of the successful result.
1004
1078
  *
1005
1079
  * @param cond
1006
1080
  * A function returning a Promise that resolves to:
1007
1081
  * - a truthy value `T` → stop polling and return it
1082
+ * - `poll.signal.abort` → stop polling cleanly, resolves with undefined
1083
+ * - `poll.signal.retry` → skip this tick silently
1008
1084
  * - falsy/null/undefined → continue polling
1009
1085
  *
1010
1086
  * @param options
@@ -1014,14 +1090,14 @@ declare function extendProps<T, P$1 extends object>(base: T, props: P$1): T exte
1014
1090
  * - `jitter` (boolean) — Add small random offset (±10%) to intervals to avoid sync bursts (default: true)
1015
1091
  * - `signal` (AbortSignal) — Optional abort signal to cancel polling
1016
1092
  *
1017
- * @returns
1018
- * Resolves with the truthy value `T` when successful.
1019
- * Throws `AbortError` if aborted
1093
+ * @returns Resolves with the truthy value `T` when successful.
1094
+ * @throws `AbortError` if aborted via signal
1095
+ * @throws `Error` if timed out
1020
1096
  *
1021
1097
  * @example
1022
1098
  * ```ts
1023
- * // Poll for job completion
1024
- * const job = await poll(async () => {
1099
+ * // Wait for a job to complete
1100
+ * const job = await poll.wait(async () => {
1025
1101
  * const status = await getJobStatus();
1026
1102
  * return status === 'done' ? status : null;
1027
1103
  * }, { interval: 3000, timeout: 60000 });
@@ -1029,27 +1105,24 @@ declare function extendProps<T, P$1 extends object>(base: T, props: P$1): T exte
1029
1105
  *
1030
1106
  * @example
1031
1107
  * ```ts
1032
- * // Wait for API endpoint to be ready
1033
- * const apiReady = await poll(async () => {
1034
- * try {
1035
- * await fetch('/api/health');
1036
- * return true;
1037
- * } catch {
1038
- * return null;
1039
- * }
1040
- * }, { interval: 1000, timeout: 30000 });
1108
+ * // Abort early based on domain logic
1109
+ * const job = await poll.wait(async () => {
1110
+ * const job = await getJob(id);
1111
+ * if (job?.is_cancelled) return poll.signal.abort;
1112
+ * return job?.is_finished ? job : null;
1113
+ * }, { timeout: 60000 });
1041
1114
  * ```
1042
1115
  *
1043
1116
  * @example
1044
1117
  * ```ts
1045
- * // Poll with abort signal for cancellation
1118
+ * // Cancel polling with an AbortSignal
1046
1119
  * const controller = new AbortController();
1047
- * setTimeout(() => controller.abort(), 10000); // Cancel after 10s
1120
+ * setTimeout(() => controller.abort(), 10000);
1048
1121
  *
1049
1122
  * try {
1050
- * const result = await poll(
1123
+ * const result = await poll.wait(
1051
1124
  * () => checkExternalService(),
1052
- * { interval: 2000, signal: controller.signal }
1125
+ * { interval: 2000, signal: controller.signal },
1053
1126
  * );
1054
1127
  * } catch (err) {
1055
1128
  * if (err.name === 'AbortError') {
@@ -1057,29 +1130,20 @@ declare function extendProps<T, P$1 extends object>(base: T, props: P$1): T exte
1057
1130
  * }
1058
1131
  * }
1059
1132
  * ```
1060
- *
1061
- * @example
1062
- * ```ts
1063
- * // Poll for user action completion
1064
- * const userConfirmed = await poll(async () => {
1065
- * const confirmations = await getPendingConfirmations();
1066
- * return confirmations.length > 0 ? confirmations[0] : null;
1067
- * }, { interval: 5000, timeout: 300000 }); // 5 min timeout
1068
- * ```
1069
1133
  */
1070
- declare function poll<T>(cond: () => Promise<T | null | false | undefined>, {
1071
- interval,
1072
- timeout,
1073
- jitter,
1074
- signal
1075
- }?: Partial<{
1076
- interval: number;
1077
- timeout: number;
1078
- signal: AbortSignal;
1079
- jitter: boolean;
1080
- }>): Promise<T>;
1134
+ declare function wait<T>(cond: () => Promise<T | null | false | undefined | PollControl>, options?: PollOptions): Promise<T | undefined>;
1135
+ declare const poll: {
1136
+ readonly wait: typeof wait;
1137
+ readonly watch: typeof watch;
1138
+ readonly signal: {
1139
+ /** Stop polling cleanly with no error */
1140
+ readonly abort: typeof ABORT;
1141
+ /** Skip this tick silently without emitting null */
1142
+ readonly retry: typeof RETRY;
1143
+ };
1144
+ };
1081
1145
  //#endregion
1082
- //#region src/functions/promise.d.ts
1146
+ //#region src/functions/concurrency.d.ts
1083
1147
  type TaskType<T> = Promise<T> | (() => Promise<T>);
1084
1148
  type AwaitedTuple<T extends readonly TaskType<any>[] | []> = { -readonly [P in keyof T]: Awaited<T[P] extends (() => Promise<infer R>) ? R : T[P]> };
1085
1149
  type ObjectValues<T extends Record<string, TaskType<any>>> = { [K in keyof T]: Awaited<T[K] extends (() => Promise<infer R>) ? R : T[K]> };
@@ -1117,6 +1181,8 @@ interface ScheduleOpts {
1117
1181
  delay?: number;
1118
1182
  /** Maximum time in milliseconds to wait for the task to complete. */
1119
1183
  timeout?: number;
1184
+ /** Enable debug logging. Defaults to false. */
1185
+ debug?: boolean;
1120
1186
  }
1121
1187
  /**
1122
1188
  * Runs a function asynchronously in the background without blocking the main thread.
package/dist/index.d.ts CHANGED
@@ -994,17 +994,93 @@ declare function hydrate<T>(data: T): Hydrate<T>;
994
994
  declare function extendProps<T, P$1 extends object>(base: T, props: P$1): T extends null | undefined ? T : T & P$1;
995
995
  //#endregion
996
996
  //#region src/functions/poll.d.ts
997
+ type PollOptions = Partial<{
998
+ interval: number;
999
+ timeout: number;
1000
+ signal: AbortSignal;
1001
+ jitter: boolean;
1002
+ }>;
1003
+ declare const ABORT: unique symbol;
1004
+ declare const RETRY: unique symbol;
1005
+ type PollControl = typeof ABORT | typeof RETRY;
1006
+ /**
1007
+ * Streams an async `cond` function, yielding `null` while waiting and the
1008
+ * final truthy value `T` when resolved.
1009
+ *
1010
+ * Designed for use in tRPC subscriptions or any async generator context where
1011
+ * you want to stream progress to the client instead of blocking.
1012
+ *
1013
+ * Keeps SSE/WebSocket connections alive on edge runtimes (e.g. Vercel) by
1014
+ * continuously emitting values rather than holding a silent open connection.
1015
+ *
1016
+ * @template T The type of the successful result.
1017
+ *
1018
+ * @param cond
1019
+ * A function returning a Promise that resolves to:
1020
+ * - a truthy value `T` → stop polling and yield it
1021
+ * - `poll.signal.abort` → stop polling cleanly with no error
1022
+ * - `poll.signal.retry` → skip this tick silently, no null emitted
1023
+ * - falsy/null/undefined → yield `null` and continue polling
1024
+ *
1025
+ * @param options
1026
+ * Configuration options:
1027
+ * - `interval` (number) — Time between polls in ms (default: 5000 ms)
1028
+ * - `timeout` (number) — Max total duration before failing (default: 5 min)
1029
+ * - `jitter` (boolean) — Add small random offset (±10%) to intervals to avoid sync bursts (default: true)
1030
+ * - `signal` (AbortSignal) — Optional abort signal to cancel polling
1031
+ *
1032
+ * @throws `AbortError` if aborted via signal
1033
+ * @throws `Error` if timed out
1034
+ *
1035
+ * @example
1036
+ * ```ts
1037
+ * // tRPC subscription — stream null while job is pending, emit result when done
1038
+ * syncImageJob: privateProcedure
1039
+ * .input(z.object({ id: z.coerce.number() }))
1040
+ * .subscription(async function* ({ ctx, input, signal }) {
1041
+ * yield* poll.watch(
1042
+ * async () => {
1043
+ * const job = await getJob(input.id);
1044
+ * if (job?.is_cancelled) return poll.signal.abort; // stop cleanly
1045
+ * if (job?.is_paused) return poll.signal.retry; // skip this tick
1046
+ * return job?.is_finished ? job : null;
1047
+ * },
1048
+ * { interval: 15000, signal },
1049
+ * );
1050
+ * }),
1051
+ * ```
1052
+ *
1053
+ * @example
1054
+ * ```ts
1055
+ * // Manually iterate
1056
+ * for await (const result of poll.watch(() => getJobStatus(), { interval: 3000 })) {
1057
+ * if (result === null) console.log('still waiting...');
1058
+ * else console.log('done!', result);
1059
+ * }
1060
+ * ```
1061
+ */
1062
+ declare function watch<T>(cond: () => Promise<T | null | false | undefined | PollControl>, {
1063
+ interval,
1064
+ timeout,
1065
+ jitter,
1066
+ signal
1067
+ }?: PollOptions): AsyncGenerator<T | null>;
997
1068
  /**
998
1069
  * Repeatedly polls an async `cond` function UNTIL it returns a TRUTHY value,
999
1070
  * or until the operation times out or is aborted.
1000
1071
  *
1001
- * Designed for waiting on async jobs, external state, or delayed availability.
1072
+ * Designed for waiting on async jobs, external state, or delayed availability
1073
+ * where you only care about the final result and not intermediate states.
1074
+ *
1075
+ * Use `poll.watch` instead if you need to stream progress (e.g. tRPC subscriptions).
1002
1076
  *
1003
1077
  * @template T The type of the successful result.
1004
1078
  *
1005
1079
  * @param cond
1006
1080
  * A function returning a Promise that resolves to:
1007
1081
  * - a truthy value `T` → stop polling and return it
1082
+ * - `poll.signal.abort` → stop polling cleanly, resolves with undefined
1083
+ * - `poll.signal.retry` → skip this tick silently
1008
1084
  * - falsy/null/undefined → continue polling
1009
1085
  *
1010
1086
  * @param options
@@ -1014,14 +1090,14 @@ declare function extendProps<T, P$1 extends object>(base: T, props: P$1): T exte
1014
1090
  * - `jitter` (boolean) — Add small random offset (±10%) to intervals to avoid sync bursts (default: true)
1015
1091
  * - `signal` (AbortSignal) — Optional abort signal to cancel polling
1016
1092
  *
1017
- * @returns
1018
- * Resolves with the truthy value `T` when successful.
1019
- * Throws `AbortError` if aborted
1093
+ * @returns Resolves with the truthy value `T` when successful.
1094
+ * @throws `AbortError` if aborted via signal
1095
+ * @throws `Error` if timed out
1020
1096
  *
1021
1097
  * @example
1022
1098
  * ```ts
1023
- * // Poll for job completion
1024
- * const job = await poll(async () => {
1099
+ * // Wait for a job to complete
1100
+ * const job = await poll.wait(async () => {
1025
1101
  * const status = await getJobStatus();
1026
1102
  * return status === 'done' ? status : null;
1027
1103
  * }, { interval: 3000, timeout: 60000 });
@@ -1029,27 +1105,24 @@ declare function extendProps<T, P$1 extends object>(base: T, props: P$1): T exte
1029
1105
  *
1030
1106
  * @example
1031
1107
  * ```ts
1032
- * // Wait for API endpoint to be ready
1033
- * const apiReady = await poll(async () => {
1034
- * try {
1035
- * await fetch('/api/health');
1036
- * return true;
1037
- * } catch {
1038
- * return null;
1039
- * }
1040
- * }, { interval: 1000, timeout: 30000 });
1108
+ * // Abort early based on domain logic
1109
+ * const job = await poll.wait(async () => {
1110
+ * const job = await getJob(id);
1111
+ * if (job?.is_cancelled) return poll.signal.abort;
1112
+ * return job?.is_finished ? job : null;
1113
+ * }, { timeout: 60000 });
1041
1114
  * ```
1042
1115
  *
1043
1116
  * @example
1044
1117
  * ```ts
1045
- * // Poll with abort signal for cancellation
1118
+ * // Cancel polling with an AbortSignal
1046
1119
  * const controller = new AbortController();
1047
- * setTimeout(() => controller.abort(), 10000); // Cancel after 10s
1120
+ * setTimeout(() => controller.abort(), 10000);
1048
1121
  *
1049
1122
  * try {
1050
- * const result = await poll(
1123
+ * const result = await poll.wait(
1051
1124
  * () => checkExternalService(),
1052
- * { interval: 2000, signal: controller.signal }
1125
+ * { interval: 2000, signal: controller.signal },
1053
1126
  * );
1054
1127
  * } catch (err) {
1055
1128
  * if (err.name === 'AbortError') {
@@ -1057,29 +1130,20 @@ declare function extendProps<T, P$1 extends object>(base: T, props: P$1): T exte
1057
1130
  * }
1058
1131
  * }
1059
1132
  * ```
1060
- *
1061
- * @example
1062
- * ```ts
1063
- * // Poll for user action completion
1064
- * const userConfirmed = await poll(async () => {
1065
- * const confirmations = await getPendingConfirmations();
1066
- * return confirmations.length > 0 ? confirmations[0] : null;
1067
- * }, { interval: 5000, timeout: 300000 }); // 5 min timeout
1068
- * ```
1069
1133
  */
1070
- declare function poll<T>(cond: () => Promise<T | null | false | undefined>, {
1071
- interval,
1072
- timeout,
1073
- jitter,
1074
- signal
1075
- }?: Partial<{
1076
- interval: number;
1077
- timeout: number;
1078
- signal: AbortSignal;
1079
- jitter: boolean;
1080
- }>): Promise<T>;
1134
+ declare function wait<T>(cond: () => Promise<T | null | false | undefined | PollControl>, options?: PollOptions): Promise<T | undefined>;
1135
+ declare const poll: {
1136
+ readonly wait: typeof wait;
1137
+ readonly watch: typeof watch;
1138
+ readonly signal: {
1139
+ /** Stop polling cleanly with no error */
1140
+ readonly abort: typeof ABORT;
1141
+ /** Skip this tick silently without emitting null */
1142
+ readonly retry: typeof RETRY;
1143
+ };
1144
+ };
1081
1145
  //#endregion
1082
- //#region src/functions/promise.d.ts
1146
+ //#region src/functions/concurrency.d.ts
1083
1147
  type TaskType<T> = Promise<T> | (() => Promise<T>);
1084
1148
  type AwaitedTuple<T extends readonly TaskType<any>[] | []> = { -readonly [P in keyof T]: Awaited<T[P] extends (() => Promise<infer R>) ? R : T[P]> };
1085
1149
  type ObjectValues<T extends Record<string, TaskType<any>>> = { [K in keyof T]: Awaited<T[K] extends (() => Promise<infer R>) ? R : T[K]> };
@@ -1117,6 +1181,8 @@ interface ScheduleOpts {
1117
1181
  delay?: number;
1118
1182
  /** Maximum time in milliseconds to wait for the task to complete. */
1119
1183
  timeout?: number;
1184
+ /** Enable debug logging. Defaults to false. */
1185
+ debug?: boolean;
1120
1186
  }
1121
1187
  /**
1122
1188
  * Runs a function asynchronously in the background without blocking the main thread.
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- const e=e=>!e,t=e=>e==null,n=e=>typeof e==`boolean`,r=e=>typeof e==`string`,i=e=>{if(typeof e==`number`)return Number.isFinite(e);if(typeof e==`string`){let t=Number(e);return Number.isFinite(t)}return!1},a=e=>Array.isArray(e),o=e=>typeof e==`function`,s=e=>{if(e==null)return!0;switch(typeof e){case`string`:case`number`:case`bigint`:case`boolean`:case`symbol`:return!0;default:return!1}};function c(e){if(typeof e!=`object`||!e||Object.prototype.toString.call(e)!==`[object Object]`)return!1;let t=Object.getPrototypeOf(e);return t===null||t===Object.prototype}function l(e,...t){let n,r={},i=t[t.length-1];i&&typeof i==`object`&&!Array.isArray(i)&&(i.arrayMerge!==void 0||i.clone!==void 0||i.customMerge!==void 0||i.functionMerge!==void 0||i.maxDepth!==void 0)?(r={...r,...i},n=t.slice(0,-1)):n=t;let{arrayMerge:a=`replace`,clone:o=!0,functionMerge:s=`replace`,maxDepth:l=100,customMerge:u}=r,d=new WeakMap;return f(e,n,0);function f(e,t,n){if(n>=l)return console.warn(`[deepmerge] Maximum depth ${l} exceeded. Returning target as-is.`),e;if(!c(e)&&!Array.isArray(e)){for(let n of t)if(n!==void 0){if(u){let t=u(``,e,n);if(t!==void 0)return t}return typeof e==`function`&&typeof n==`function`&&s===`compose`?(...t)=>{e(...t),n(...t)}:n}return e}let r=o?Array.isArray(e)?[...e]:{...e}:e;for(let e of t)if(e!=null&&!d.has(e))if(d.set(e,r),Array.isArray(r)&&Array.isArray(e))r=p(r,e,a);else if(c(r)&&c(e)){let t=new Set([...Object.keys(r),...Object.keys(e),...Object.getOwnPropertySymbols(r),...Object.getOwnPropertySymbols(e)]);for(let i of t){let t=r[i],o=e[i];u&&u(i,t,o)!==void 0?r[i]=u(i,t,o):typeof t==`function`&&typeof o==`function`?s===`compose`?r[i]=(...e)=>{t(...e),o(...e)}:r[i]=o:c(t)&&c(o)?r[i]=f(t,[o],n+1):Array.isArray(t)&&Array.isArray(o)?r[i]=p(t,o,a):o!==void 0&&(r[i]=o)}}else r=e;return r}function p(e,t,n){if(typeof n==`function`)return n(e,t);switch(n){case`concat`:return[...e,...t];case`merge`:let n=Math.max(e.length,t.length),r=[];for(let i=0;i<n;i++)i<e.length&&i<t.length?c(e[i])&&c(t[i])?r[i]=f(e[i],[t[i]],0):r[i]=t[i]:i<e.length?r[i]=e[i]:r[i]=t[i];return r;case`replace`:default:return[...t]}}}function u(e,t,n){if(Array.isArray(t))return t.map(t=>u(e,t,n));if(typeof t==`object`&&t&&!Array.isArray(t)){let r={};for(let i in t)t.hasOwnProperty(i)&&(r[i]=u(e,t[i],n));return r}if(typeof t!=`string`)return n;let r=(()=>t===``?[]:t.split(`.`).filter(e=>e!==``))(),i=e;for(let e of r){if(i==null)return n;let t=typeof e==`string`&&Array.isArray(i)&&/^\d+$/.test(e)?Number.parseInt(e,10):e;i=i[t]}return i===void 0?n:i}function d(e){return f(e)}function f(e){if(e!==null){if(typeof e!=`object`||!e)return e;if(Array.isArray(e))return e.map(f);if(c(e)){let t={};for(let n in e)t[n]=f(e[n]);return t}return e}}function p(e,t){return e==null?e:Object.assign(e,t)}function m(e){return(e.split(`.`).pop()||e).replace(/([a-z])([A-Z])/g,`$1 $2`).split(/[-_|�\s]+/).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `)}const h=`àáãäâèéëêìíïîòóöôùúüûñç·/_,:;`,g=e=>{if(typeof e!=`string`)throw TypeError(`Input must be a string`);let t=e.trim().toLowerCase(),n={};for(let e=0;e<29;e++)n[h.charAt(e)]=`aaaaaeeeeiiiioooouuuunc------`.charAt(e);return t=t.replace(RegExp(`[${h}]`,`g`),e=>n[e]||e),t.replace(/[^a-z0-9 -]/g,``).replace(/\s+/g,`-`).replace(/-+/g,`-`).replace(/^-+/,``).replace(/-+$/,``)||``},_=(e=1e3,t)=>new Promise(n=>{if(t?.aborted)return n();let r=setTimeout(()=>{a(),n()},e);function i(){clearTimeout(r),a(),n()}function a(){t?.removeEventListener(`abort`,i)}t&&t.addEventListener(`abort`,i,{once:!0})});function v(e,t=100,n){if(typeof e!=`function`)throw TypeError(`Expected the first parameter to be a function, got \`${typeof e}\`.`);if(t<0)throw RangeError("`wait` must not be negative.");let r=n?.immediate??!1,i,a,o,s;function c(){return s=e.apply(o,a),a=void 0,o=void 0,s}let l=function(...e){return a=e,o=this,i===void 0&&r&&(s=c.call(this)),i!==void 0&&clearTimeout(i),i=setTimeout(c.bind(this),t),s};return Object.defineProperty(l,`isPending`,{get(){return i!==void 0}}),l}function y(e,t=100,n){if(typeof e!=`function`)throw TypeError(`Expected the first parameter to be a function, got \`${typeof e}\`.`);if(t<0)throw RangeError("`wait` must not be negative.");let r=n?.leading??!0,i=n?.trailing??!0,a,o,s,c,l;function u(){c=Date.now(),l=e.apply(s,o),o=void 0,s=void 0}function d(){a=void 0,i&&o&&u()}let f=function(...e){let n=c?Date.now()-c:1/0;return o=e,s=this,n>=t?r?u():a=setTimeout(d,t):!a&&i&&(a=setTimeout(d,t-n)),l};return Object.defineProperty(f,`isPending`,{get(){return a!==void 0}}),f}function b(e,...t){let n=t.length===1&&Array.isArray(t[0])?t[0]:t,r=0;return e.replace(/%s/g,()=>{let e=n[r++];return e===void 0?``:String(e)})}function x(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function S(e,t={}){if(!e)return``;let{lowercase:n=!0,removeAccents:r=!0,removeNonAlphanumeric:i=!0}=t,a=e.normalize(`NFC`);return r&&(a=a.normalize(`NFD`).replace(/\p{M}/gu,``)),i&&(a=a.replace(/^[^\p{L}\p{N}]*|[^\p{L}\p{N}]*$/gu,``)),n&&(a=a.toLocaleLowerCase()),a}function C(e,...t){return typeof e==`function`?e(...t):e}async function w(e,{interval:t=5e3,timeout:n=300*1e3,jitter:r=!0,signal:i}={}){let a=Date.now(),o=i?.aborted??!1,s=()=>{o=!0};i?.addEventListener(`abort`,s,{once:!0});try{for(let s=0;;s++){if(o)throw Error(`Polling aborted`);let s=await e();if(s)return s;if(Date.now()-a>=n)throw Error(`Polling timed out`,{cause:`Polling timed out after ${n}ms`});await _(r?t+(Math.random()-.5)*t*.2:t,i)}}catch(e){throw e}finally{i?.removeEventListener(`abort`,s)}}async function T(e,t={}){let{concurrency:n=1/0,timeout:r=1/0,signal:i,retry:a=0,retryDelay:o=0,throwOnFirstError:s=!1,ignoreErrors:c=!1}=t,l=Array.isArray(e),u={};l?e.forEach((e,t)=>{u[t.toString()]=e}):Object.entries(e).forEach(([e,t])=>{u[e]=t});let d=Object.keys(u);if(d.length===0)return{results:l?[]:{},errors:[],succeeded:0,failed:0,duration:0};let f=Date.now(),p=[],m=[],h=0,g=0,v=0,y=!1,b=s?null:void 0,x=async e=>{let t=0;for(;t<=a&&!y;)try{let t=u[e],n=await(typeof t==`function`?t():t);p.push([e,n]),g++;return}catch(e){if(t===a){let t=e instanceof Error?e:Error(String(e));m.push(t),v++,!c&&s&&!b&&(b=t,y=!0);return}t++,o>0&&await _(o,i)}},S=Array.from({length:Math.min(n,d.length)},async()=>{for(;!y;){let e=h++;if(e>=d.length)return;if(i?.aborted){y=!0;return}await x(d[e])}}),C=Promise.all(S);if(r===1/0?await C:await Promise.race([C,_(r,i).then(()=>{throw y=!0,Error(`Concurrence timed out after ${r}ms`)})]),b&&s)throw b;return l?{results:p.sort((e,t)=>Number(e[0])-Number(t[0])).map(([,e])=>e),errors:m,succeeded:g,failed:v,duration:Date.now()-f}:{results:Object.fromEntries(p),errors:m,succeeded:g,failed:v,duration:Date.now()-f}}function E(e,t={}){let{retry:n=0,delay:r=0}=t,i=Date.now(),a=async t=>{try{await e();let t=Date.now()-i;console.log(`⚡[schedule.ts] Completed in ${t}ms`)}catch(e){if(console.log(`⚡[schedule.ts] err:`,e),t>0)console.log(`⚡[schedule.ts] Retrying in ${r}ms...`),setTimeout(()=>a(t-1),r);else{let e=Date.now()-i;console.log(`⚡[schedule.ts] Failed after ${e}ms`)}}};setTimeout(()=>a(n),0)}function D(e){if(e instanceof Promise)return e.then(e=>[null,e]).catch(e=>[e,null]);try{return[null,e()]}catch(t){return console.log(`\x1b[31m🛡 [shield]\x1b[0m ${e.name} failed →`,t),[t,null]}}export{m as convertToNormalCase,g as convertToSlug,v as debounce,l as deepmerge,x as escapeRegExp,p as extendProps,u as extract,d as hydrate,a as isArray,n as isBoolean,e as isFalsy,i as isFiniteNumber,o as isFunction,t as isNullish,c as isPlainObject,s as isPrimitive,r as isString,S as normalizeText,w as poll,b as printf,E as schedule,D as shield,_ as sleep,y as throttle,C as unwrap,T as withConcurrency};
1
+ const e=e=>!e,t=e=>e==null,n=e=>typeof e==`boolean`,r=e=>typeof e==`string`,i=e=>{if(typeof e==`number`)return Number.isFinite(e);if(typeof e==`string`){let t=Number(e);return Number.isFinite(t)}return!1},a=e=>Array.isArray(e),o=e=>typeof e==`function`,s=e=>{if(e==null)return!0;switch(typeof e){case`string`:case`number`:case`bigint`:case`boolean`:case`symbol`:return!0;default:return!1}};function c(e){if(typeof e!=`object`||!e||Object.prototype.toString.call(e)!==`[object Object]`)return!1;let t=Object.getPrototypeOf(e);return t===null||t===Object.prototype}function l(e,...t){let n,r={},i=t[t.length-1];i&&typeof i==`object`&&!Array.isArray(i)&&(i.arrayMerge!==void 0||i.clone!==void 0||i.customMerge!==void 0||i.functionMerge!==void 0||i.maxDepth!==void 0)?(r={...r,...i},n=t.slice(0,-1)):n=t;let{arrayMerge:a=`replace`,clone:o=!0,functionMerge:s=`replace`,maxDepth:l=100,customMerge:u}=r,d=new WeakMap;return f(e,n,0);function f(e,t,n){if(n>=l)return console.warn(`[deepmerge] Maximum depth ${l} exceeded. Returning target as-is.`),e;if(!c(e)&&!Array.isArray(e)){for(let n of t)if(n!==void 0){if(u){let t=u(``,e,n);if(t!==void 0)return t}return typeof e==`function`&&typeof n==`function`&&s===`compose`?(...t)=>{e(...t),n(...t)}:n}return e}let r=o?Array.isArray(e)?[...e]:{...e}:e;for(let e of t)if(e!=null&&!d.has(e))if(d.set(e,r),Array.isArray(r)&&Array.isArray(e))r=p(r,e,a);else if(c(r)&&c(e)){let t=new Set([...Object.keys(r),...Object.keys(e),...Object.getOwnPropertySymbols(r),...Object.getOwnPropertySymbols(e)]);for(let i of t){let t=r[i],o=e[i];u&&u(i,t,o)!==void 0?r[i]=u(i,t,o):typeof t==`function`&&typeof o==`function`?s===`compose`?r[i]=(...e)=>{t(...e),o(...e)}:r[i]=o:c(t)&&c(o)?r[i]=f(t,[o],n+1):Array.isArray(t)&&Array.isArray(o)?r[i]=p(t,o,a):o!==void 0&&(r[i]=o)}}else r=e;return r}function p(e,t,n){if(typeof n==`function`)return n(e,t);switch(n){case`concat`:return[...e,...t];case`merge`:let n=Math.max(e.length,t.length),r=[];for(let i=0;i<n;i++)i<e.length&&i<t.length?c(e[i])&&c(t[i])?r[i]=f(e[i],[t[i]],0):r[i]=t[i]:i<e.length?r[i]=e[i]:r[i]=t[i];return r;case`replace`:default:return[...t]}}}function u(e,t,n){if(Array.isArray(t))return t.map(t=>u(e,t,n));if(typeof t==`object`&&t&&!Array.isArray(t)){let r={};for(let i in t)t.hasOwnProperty(i)&&(r[i]=u(e,t[i],n));return r}if(typeof t!=`string`)return n;let r=(()=>t===``?[]:t.split(`.`).filter(e=>e!==``))(),i=e;for(let e of r){if(i==null)return n;let t=typeof e==`string`&&Array.isArray(i)&&/^\d+$/.test(e)?Number.parseInt(e,10):e;i=i[t]}return i===void 0?n:i}function d(e){return f(e)}function f(e){if(e!==null){if(typeof e!=`object`||!e)return e;if(Array.isArray(e))return e.map(f);if(c(e)){let t={};for(let n in e)t[n]=f(e[n]);return t}return e}}function p(e,t){return e==null?e:Object.assign(e,t)}function m(e){return(e.split(`.`).pop()||e).replace(/([a-z])([A-Z])/g,`$1 $2`).split(/[-_|�\s]+/).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `)}const h=`àáãäâèéëêìíïîòóöôùúüûñç·/_,:;`,g=e=>{if(typeof e!=`string`)throw TypeError(`Input must be a string`);let t=e.trim().toLowerCase(),n={};for(let e=0;e<29;e++)n[h.charAt(e)]=`aaaaaeeeeiiiioooouuuunc------`.charAt(e);return t=t.replace(RegExp(`[${h}]`,`g`),e=>n[e]||e),t.replace(/[^a-z0-9 -]/g,``).replace(/\s+/g,`-`).replace(/-+/g,`-`).replace(/^-+/,``).replace(/-+$/,``)||``},_=(e=1e3,t)=>new Promise(n=>{if(t?.aborted)return n();let r=setTimeout(()=>{a(),n()},e);function i(){clearTimeout(r),a(),n()}function a(){t?.removeEventListener(`abort`,i)}t&&t.addEventListener(`abort`,i,{once:!0})});function v(e,t=100,n){if(typeof e!=`function`)throw TypeError(`Expected the first parameter to be a function, got \`${typeof e}\`.`);if(t<0)throw RangeError("`wait` must not be negative.");let r=n?.immediate??!1,i,a,o,s;function c(){return s=e.apply(o,a),a=void 0,o=void 0,s}let l=function(...e){return a=e,o=this,i===void 0&&r&&(s=c.call(this)),i!==void 0&&clearTimeout(i),i=setTimeout(c.bind(this),t),s};return Object.defineProperty(l,`isPending`,{get(){return i!==void 0}}),l}function y(e,t=100,n){if(typeof e!=`function`)throw TypeError(`Expected the first parameter to be a function, got \`${typeof e}\`.`);if(t<0)throw RangeError("`wait` must not be negative.");let r=n?.leading??!0,i=n?.trailing??!0,a,o,s,c,l;function u(){c=Date.now(),l=e.apply(s,o),o=void 0,s=void 0}function d(){a=void 0,i&&o&&u()}let f=function(...e){let n=c?Date.now()-c:1/0;return o=e,s=this,n>=t?r?u():a=setTimeout(d,t):!a&&i&&(a=setTimeout(d,t-n)),l};return Object.defineProperty(f,`isPending`,{get(){return a!==void 0}}),f}function b(e,...t){let n=t.length===1&&Array.isArray(t[0])?t[0]:t,r=0;return e.replace(/%s/g,()=>{let e=n[r++];return e===void 0?``:String(e)})}function x(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function S(e,t={}){if(!e)return``;let{lowercase:n=!0,removeAccents:r=!0,removeNonAlphanumeric:i=!0}=t,a=e.normalize(`NFC`);return r&&(a=a.normalize(`NFD`).replace(/\p{M}/gu,``)),i&&(a=a.replace(/^[^\p{L}\p{N}]*|[^\p{L}\p{N}]*$/gu,``)),n&&(a=a.toLocaleLowerCase()),a}function C(e,...t){return typeof e==`function`?e(...t):e}const w=Symbol(`poll.signal.abort`),T=Symbol(`poll.signal.retry`);async function*E(e,{interval:t=5e3,timeout:n=300*1e3,jitter:r=!0,signal:i}={}){let a=Date.now();for(;;){if(i?.aborted)throw new DOMException(`Polling aborted`,`AbortError`);let o=await e();if(o===w)return;if(o===T){await _(r?t+(Math.random()-.5)*t*.2:t,i);continue}if(o){yield o;return}if(Date.now()-a>=n)throw Error(`Polling timed out after ${n}ms`);yield null,await _(r?t+(Math.random()-.5)*t*.2:t,i)}}async function D(e,t={}){for await(let n of E(e,t))if(n)return n}const O={wait:D,watch:E,signal:{abort:w,retry:T}};async function k(e,t={}){let{concurrency:n=1/0,timeout:r=1/0,signal:i,retry:a=0,retryDelay:o=0,throwOnFirstError:s=!1,ignoreErrors:c=!1}=t,l=Array.isArray(e),u={};l?e.forEach((e,t)=>{u[t.toString()]=e}):Object.entries(e).forEach(([e,t])=>{u[e]=t});let d=Object.keys(u);if(d.length===0)return{results:l?[]:{},errors:[],succeeded:0,failed:0,duration:0};let f=Date.now(),p=[],m=[],h=0,g=0,v=0,y=!1,b=s?null:void 0,x=async e=>{let t=0;for(;t<=a&&!y;)try{let t=u[e],n=await(typeof t==`function`?t():t);p.push([e,n]),g++;return}catch(e){if(t===a){let t=e instanceof Error?e:Error(String(e));m.push(t),v++,!c&&s&&!b&&(b=t,y=!0);return}t++,o>0&&await _(o,i)}},S=Array.from({length:Math.min(n,d.length)},async()=>{for(;!y;){let e=h++;if(e>=d.length)return;if(i?.aborted){y=!0;return}await x(d[e])}}),C=Promise.all(S);if(r===1/0?await C:await Promise.race([C,_(r,i).then(()=>{throw y=!0,Error(`Concurrence timed out after ${r}ms`)})]),b&&s)throw b;return l?{results:p.sort((e,t)=>Number(e[0])-Number(t[0])).map(([,e])=>e),errors:m,succeeded:g,failed:v,duration:Date.now()-f}:{results:Object.fromEntries(p),errors:m,succeeded:g,failed:v,duration:Date.now()-f}}function A(e,t={}){let{retry:n=0,delay:r=0,debug:i=!1}=t,a=Date.now(),o=async t=>{try{if(await e(),i){let e=Date.now()-a;console.log(`⚡[schedule.ts] Completed in ${e}ms`)}}catch(e){if(i&&console.log(`⚡[schedule.ts] err:`,e),t>0)i&&console.log(`⚡[schedule.ts] Retrying in ${r}ms...`),setTimeout(()=>o(t-1),r);else if(i){let e=Date.now()-a;console.log(`⚡[schedule.ts] Failed after ${e}ms`)}}};setTimeout(()=>o(n),0)}function j(e){if(e instanceof Promise)return e.then(e=>[null,e]).catch(e=>[e,null]);try{return[null,e()]}catch(t){return console.log(`\x1b[31m🛡 [shield]\x1b[0m ${e.name} failed →`,t),[t,null]}}export{m as convertToNormalCase,g as convertToSlug,v as debounce,l as deepmerge,x as escapeRegExp,p as extendProps,u as extract,d as hydrate,a as isArray,n as isBoolean,e as isFalsy,i as isFiniteNumber,o as isFunction,t as isNullish,c as isPlainObject,s as isPrimitive,r as isString,S as normalizeText,O as poll,b as printf,A as schedule,j as shield,_ as sleep,y as throttle,C as unwrap,k as withConcurrency};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ts-utilities/core",
3
- "version": "1.3.4",
3
+ "version": "1.3.6",
4
4
  "author": "Sohan Emon <sohanemon@outlook.com>",
5
5
  "description": "Core utilities for JavaScript/TypeScript projects",
6
6
  "type": "module",