qznt 1.0.36 → 2.0.0

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
@@ -30,114 +30,322 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
- $: () => $,
34
33
  Cache: () => Cache,
34
+ FormatNumberCompact: () => FormatNumberCompact,
35
35
  Loop: () => Loop,
36
36
  Pipe: () => Pipe,
37
37
  Storage: () => Storage,
38
- chance: () => chance,
39
- choice: () => choice,
40
38
  chunk: () => chunk,
41
39
  chunkAdj: () => chunkAdj,
42
- clamp: () => clamp,
40
+ clampNumber: () => clampNumber,
43
41
  cluster: () => cluster,
44
- compact: () => compact,
45
- compactNumber: () => compactNumber,
46
- currency: () => currency,
42
+ compactArray: () => compactArray,
43
+ createSampler: () => createSampler,
47
44
  debounce: () => debounce,
48
- default: () => index_default,
49
- defined: () => defined,
50
- duration: () => duration,
51
- empty: () => empty,
52
45
  escapeRegex: () => escapeRegex,
53
- eta: () => eta,
54
- float: () => float,
55
46
  forceArray: () => forceArray,
56
- get: () => get,
47
+ formatCurrency: () => formatCurrency,
48
+ formatDuration: () => formatDuration,
49
+ formatETA: () => formatETA,
50
+ formatMemory: () => formatMemory,
51
+ formatNumber: () => formatNumber,
52
+ formatOrdinal: () => formatOrdinal,
57
53
  getAge: () => getAge,
58
54
  getFlag: () => getFlag,
59
- has: () => has,
55
+ getProp: () => getProp,
60
56
  hasFlag: () => hasFlag,
61
- inRange: () => inRange,
62
- index: () => index,
63
- int: () => int,
64
- invLerp: () => invLerp,
57
+ hasProp: () => hasProp,
58
+ inverseLerp: () => inverseLerp,
59
+ isDefined: () => isDefined,
60
+ isEmpty: () => isEmpty,
61
+ isInRange: () => isInRange,
62
+ isObject: () => isObject,
63
+ isSortedArray: () => isSortedArray,
64
+ isString: () => isString,
65
+ isToday: () => isToday,
65
66
  lerp: () => lerp,
66
67
  memoize: () => memoize,
67
- memory: () => memory,
68
68
  merge: () => merge,
69
- ms: () => ms,
70
- number: () => number,
71
- object: () => object,
69
+ msToSecs: () => msToSecs,
72
70
  omit: () => omit,
73
- ordinal: () => ordinal,
74
- parse: () => parse,
71
+ parseTime: () => parseTime,
75
72
  percent: () => percent,
76
73
  pick: () => pick,
74
+ pluralize: () => pluralize,
77
75
  prng: () => prng,
78
76
  readDir: () => readDir,
79
- record: () => record,
80
77
  remap: () => remap,
81
- retry: () => retry,
82
- sampler: () => sampler,
83
- search: () => search,
84
- secs: () => secs,
78
+ retryPromise: () => retryPromise,
79
+ rndChance: () => rndChance,
80
+ rndChoice: () => rndChoice,
81
+ rndFloat: () => rndFloat,
82
+ rndIndex: () => rndIndex,
83
+ rndInt: () => rndInt,
84
+ rndString: () => rndString,
85
+ searchSorted: () => searchSorted,
86
+ secsToMs: () => secsToMs,
85
87
  seqMap: () => seqMap,
86
- set: () => set,
88
+ setProp: () => setProp,
87
89
  shuffle: () => shuffle,
88
90
  sortBy: () => sortBy,
89
- sorted: () => sorted,
90
- str: () => str,
91
- string: () => string,
92
91
  sum: () => sum,
93
92
  throttle: () => throttle,
94
93
  toTitleCase: () => toTitleCase,
95
- today: () => today,
96
94
  unique: () => unique,
97
95
  wait: () => wait,
98
- weighted: () => weighted,
96
+ weightedRnd: () => weightedRnd,
99
97
  wrap: () => wrap
100
98
  });
101
99
  module.exports = __toCommonJS(index_exports);
102
100
 
103
- // src/arr.ts
104
- var arr_exports = {};
105
- __export(arr_exports, {
106
- chunk: () => chunk,
107
- chunkAdj: () => chunkAdj,
108
- cluster: () => cluster,
109
- compact: () => compact,
110
- forceArray: () => forceArray,
111
- search: () => search,
112
- seqMap: () => seqMap,
113
- shuffle: () => shuffle,
114
- sortBy: () => sortBy,
115
- unique: () => unique
116
- });
101
+ // src/Cache.ts
102
+ var Cache = class {
103
+ cache = /* @__PURE__ */ new Map();
104
+ interval;
105
+ /**
106
+ * A lightweight, high-performant in-memory cache.
107
+ * Uses Map for O(1) lookups and an optional cleanup interval.
108
+ * @param cleanupMs The interval in milliseconds to run the cleanup function. [default: 60000 (1 minute)]
109
+ */
110
+ constructor(cleanupMs = 6e4) {
111
+ if (cleanupMs > 0) {
112
+ this.interval = setInterval(() => this.cleanup(), cleanupMs);
113
+ if (this.interval.unref) this.interval.unref();
114
+ }
115
+ }
116
+ set(key, value, ttlMs) {
117
+ this.cache.set(key, {
118
+ value,
119
+ expiresAt: ttlMs ? Date.now() + ttlMs : null
120
+ });
121
+ }
122
+ get(key) {
123
+ const data = this.cache.get(key);
124
+ if (!data) return null;
125
+ if (data.expiresAt && Date.now() > data.expiresAt) {
126
+ this.cache.delete(key);
127
+ return null;
128
+ }
129
+ return data.value;
130
+ }
131
+ cleanup() {
132
+ if (this.cache.size === 0) return;
133
+ const now = Date.now();
134
+ let keysProcessed = 0;
135
+ const maxKeysToScan = 20;
136
+ for (const [key, data] of this.cache) {
137
+ if (data.expiresAt && now > data.expiresAt) {
138
+ this.cache.delete(key);
139
+ }
140
+ keysProcessed++;
141
+ if (keysProcessed >= maxKeysToScan) break;
142
+ }
143
+ }
144
+ clear() {
145
+ this.cache.clear();
146
+ }
147
+ };
117
148
 
118
- // src/rnd.ts
119
- var rnd_exports = {};
120
- __export(rnd_exports, {
121
- chance: () => chance,
122
- choice: () => choice,
123
- float: () => float,
124
- index: () => index,
125
- int: () => int,
126
- prng: () => prng,
127
- sampler: () => sampler,
128
- str: () => str,
129
- weighted: () => weighted
130
- });
149
+ // src/Loop.ts
150
+ var import_node_events = __toESM(require("events"), 1);
151
+ var TypedEmitterBase = import_node_events.default;
152
+ var Loop = class extends TypedEmitterBase {
153
+ _state = "stopped";
154
+ timeoutId = null;
155
+ delay;
156
+ fn;
157
+ startTime = 0;
158
+ remaining = 0;
159
+ async run() {
160
+ const currentState = this._state;
161
+ if (currentState === "stopped" || currentState === "paused") return;
162
+ try {
163
+ const result = await this.fn(this);
164
+ this.emit("tick", result);
165
+ } catch (err) {
166
+ this.emit("error", err);
167
+ }
168
+ if (this._state === "running") {
169
+ this.startTime = Date.now();
170
+ this.remaining = 0;
171
+ this.clearTimer();
172
+ this.timeoutId = setTimeout(() => this.run(), this.delay);
173
+ }
174
+ }
175
+ clearTimer() {
176
+ if (this.timeoutId) {
177
+ clearTimeout(this.timeoutId);
178
+ this.timeoutId = null;
179
+ }
180
+ }
181
+ /**
182
+ * Creates an interval. If the function is async, it will wait for it to complete before scheduling the next run.
183
+ * @param fn The function to run.
184
+ * @param delay The delay between runs in milliseconds.
185
+ * @param immediate Whether to start the loop immediately. [default: true]
186
+ */
187
+ constructor(fn, delay, immediate = true) {
188
+ super();
189
+ this.fn = fn;
190
+ this.delay = delay;
191
+ if (immediate) this.start();
192
+ }
193
+ get state() {
194
+ return this._state;
195
+ }
196
+ /** Starts the loop. */
197
+ start() {
198
+ if (this._state !== "stopped") return;
199
+ this._state = "running";
200
+ this.emit("start");
201
+ this.run();
202
+ }
203
+ /** Resumes a paused loop. */
204
+ resume() {
205
+ if (this._state !== "paused") return;
206
+ this._state = "running";
207
+ this.emit("resume");
208
+ if (this.remaining <= 0) {
209
+ this.run();
210
+ } else {
211
+ this.timeoutId = setTimeout(() => this.run(), this.remaining);
212
+ }
213
+ }
214
+ /** Stops the loop. */
215
+ stop() {
216
+ const wasRunning = this._state !== "stopped";
217
+ this._state = "stopped";
218
+ this.remaining = 0;
219
+ this.clearTimer();
220
+ if (wasRunning) this.emit("stop");
221
+ }
222
+ /** Pauses the execution. */
223
+ pause() {
224
+ if (this._state !== "running") return;
225
+ this._state = "paused";
226
+ const elapsed = Date.now() - this.startTime;
227
+ this.remaining = Math.max(0, this.delay - elapsed);
228
+ this.emit("pause", { remaining: this.remaining });
229
+ this.clearTimer();
230
+ }
231
+ /**
232
+ * Sets the delay between runs
233
+ * @param ms The new delay in milliseconds.
234
+ */
235
+ setDelay(ms) {
236
+ this.delay = ms;
237
+ }
238
+ /** Manually trigger the function once without affecting the loop. */
239
+ async execute() {
240
+ await this.fn(this);
241
+ }
242
+ };
243
+
244
+ // src/Pipe.ts
245
+ function Pipe(value, ...fns) {
246
+ return fns.reduce((acc, fn) => fn(acc), value);
247
+ }
248
+
249
+ // src/Storage.ts
250
+ var import_node_fs = __toESM(require("fs"), 1);
251
+ var import_node_path = __toESM(require("path"), 1);
252
+ var Storage = class {
253
+ isNode = typeof window === "undefined";
254
+ filePath = null;
255
+ memoryCache = /* @__PURE__ */ new Map();
256
+ loadFromFile() {
257
+ if (this.filePath && import_node_fs.default.existsSync(this.filePath)) {
258
+ try {
259
+ const data = JSON.parse(import_node_fs.default.readFileSync(this.filePath, "utf-8"));
260
+ Object.entries(data).forEach(([k, v]) => this.memoryCache.set(k, JSON.stringify(v)));
261
+ } catch (err) {
262
+ console.error(`Store: Failed to load file '${this.filePath}'`, err);
263
+ }
264
+ }
265
+ }
266
+ persist() {
267
+ if (this.isNode && this.filePath) {
268
+ const out = {};
269
+ this.memoryCache.forEach((v, k) => out[k] = JSON.parse(v));
270
+ import_node_fs.default.writeFileSync(this.filePath, JSON.stringify(out, null, 2));
271
+ }
272
+ }
273
+ /**
274
+ * A lightweight, high-performant persistent storage system.
275
+ * Uses JSON files in Node.js, localStorage in the browser
276
+ * @param fileName Only used in Node.js to create a persistent .json file
277
+ * @param directory The directory for the file. Defaults to current working directory
278
+ */
279
+ constructor(fileName, directory = process.cwd()) {
280
+ if (this.isNode && fileName) {
281
+ this.filePath = import_node_path.default.join(directory, fileName.endsWith(".json") ? fileName : `${fileName}.json`);
282
+ this.loadFromFile();
283
+ }
284
+ }
285
+ has(key) {
286
+ if (!this.isNode && window.localStorage) {
287
+ return localStorage.getItem(key) !== null;
288
+ }
289
+ return this.memoryCache.has(key);
290
+ }
291
+ get(key) {
292
+ let raw = null;
293
+ if (!this.isNode && window.localStorage) {
294
+ raw = localStorage.getItem(key);
295
+ } else {
296
+ raw = this.memoryCache.get(key) || null;
297
+ }
298
+ if (!raw) return null;
299
+ const payload = JSON.parse(raw);
300
+ if (payload.expiry && Date.now() > payload.expiry) {
301
+ this.remove(key);
302
+ this.persist();
303
+ return null;
304
+ }
305
+ return payload.value;
306
+ }
307
+ set(key, value, ttl) {
308
+ const payload = {
309
+ value,
310
+ expiry: ttl ? Date.now() + ttl : null
311
+ };
312
+ const serialized = JSON.stringify(payload);
313
+ if (!this.isNode && window.localStorage) {
314
+ localStorage.setItem(key, serialized);
315
+ } else {
316
+ this.memoryCache.set(key, serialized);
317
+ this.persist();
318
+ }
319
+ }
320
+ remove(key) {
321
+ if (!this.isNode && window.localStorage) {
322
+ localStorage.removeItem(key);
323
+ } else {
324
+ this.memoryCache.delete(key);
325
+ this.persist();
326
+ }
327
+ }
328
+ clear() {
329
+ if (!this.isNode && window.localStorage) {
330
+ localStorage.clear();
331
+ } else {
332
+ this.memoryCache.clear();
333
+ this.persist();
334
+ }
335
+ }
336
+ };
337
+
338
+ // src/random.ts
131
339
  var LOWER = "abcdefghijklmnopqrstuvwxyz";
132
340
  var UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
133
341
  var NUM = "0123456789";
134
- function chance(percent2 = 0.5, seed) {
342
+ function rndChance(percent2 = 0.5, seed) {
135
343
  if (percent2 <= 0) return false;
136
344
  if (percent2 >= 1) return true;
137
345
  const random = seed !== void 0 ? prng(seed) : Math.random;
138
346
  return random() < percent2;
139
347
  }
140
- function choice(array, options = {}) {
348
+ function rndChoice(array, options = {}) {
141
349
  const { seed, not, maxRerolls = 10 } = options;
142
350
  const random = seed !== void 0 ? prng(seed) : Math.random;
143
351
  const rnd = () => array[Math.floor(random() * array.length)];
@@ -152,19 +360,19 @@ function choice(array, options = {}) {
152
360
  }
153
361
  return result;
154
362
  }
155
- function weighted(array, selector, seed) {
363
+ function weightedRnd(array, predicate, seed) {
156
364
  const random = seed !== void 0 ? prng(seed) : Math.random;
157
365
  const cumulativeWeights = [];
158
366
  let currentSum = 0;
159
367
  for (const item of array) {
160
- const weight = selector(item);
368
+ const weight = predicate(item);
161
369
  currentSum += weight;
162
370
  cumulativeWeights.push(currentSum);
163
371
  }
164
372
  const decider = random() * currentSum;
165
- let index2;
373
+ let index;
166
374
  if (array.length < 20) {
167
- index2 = cumulativeWeights.findIndex((w) => w >= decider);
375
+ index = cumulativeWeights.findIndex((w) => w >= decider);
168
376
  } else {
169
377
  let low = 0;
170
378
  let high = cumulativeWeights.length - 1;
@@ -176,16 +384,16 @@ function weighted(array, selector, seed) {
176
384
  high = mid;
177
385
  }
178
386
  }
179
- index2 = low;
387
+ index = low;
180
388
  }
181
- return array[index2];
389
+ return array[index];
182
390
  }
183
- function sampler(items, selector, seed) {
391
+ function createSampler(items, predicate, seed) {
184
392
  const callRandom = seed ? prng(seed) : void 0;
185
393
  const len = items.length;
186
394
  const prob = new Array(len);
187
395
  const alias = new Array(len);
188
- const weights = items.map(selector);
396
+ const weights = items.map(predicate);
189
397
  const totalWeight = weights.reduce((a, b) => a + b, 0);
190
398
  const scaledWeights = weights.map((w) => w * len / totalWeight);
191
399
  const small = [];
@@ -203,8 +411,8 @@ function sampler(items, selector, seed) {
203
411
  while (small.length) prob[small.pop()] = 1;
204
412
  return {
205
413
  /**
206
- * Returns a random item from the given array in O(1) time.
207
- * @param seed Optional seed for RNG.
414
+ * Returns a random item from the given array in O(1) time
415
+ * @param seed Optional seed for RNG
208
416
  */
209
417
  pick: (seed2) => {
210
418
  const random = seed2 !== void 0 ? prng(seed2) : callRandom || Math.random;
@@ -221,11 +429,11 @@ function prng(seed) {
221
429
  return ((t ^ t >>> 14) >>> 0) / 4294967296;
222
430
  };
223
431
  }
224
- function float(min, max, seed) {
432
+ function rndFloat(min, max, seed) {
225
433
  const random = seed !== void 0 ? prng(seed) : Math.random;
226
434
  return random() * (max - min) + min;
227
435
  }
228
- function index(array, options = {}) {
436
+ function rndIndex(array, options = {}) {
229
437
  const { seed, not, maxRerolls = 10 } = options;
230
438
  const random = seed !== void 0 ? prng(seed) : Math.random;
231
439
  const rnd = () => Math.floor(random() * array.length);
@@ -240,11 +448,11 @@ function index(array, options = {}) {
240
448
  }
241
449
  return result;
242
450
  }
243
- function int(min, max, seed) {
451
+ function rndInt(min, max, seed) {
244
452
  const random = seed !== void 0 ? prng(seed) : Math.random;
245
453
  return Math.floor(random() * (max - min + 1)) + min;
246
454
  }
247
- function str(len, mode, options = {}) {
455
+ function rndString(len, mode, options = {}) {
248
456
  const { casing = "lower", seed, customChars = "", exclude = "" } = options;
249
457
  const random = seed !== void 0 ? prng(seed) : Math.random;
250
458
  const alphaPool = { lower: LOWER, upper: UPPER, mixed: LOWER + UPPER }[casing];
@@ -313,7 +521,7 @@ function cluster(array, iteratee, maxChunkSize) {
313
521
  }
314
522
  return result;
315
523
  }
316
- function compact(array, mode = "nullable") {
524
+ function compactArray(array, mode = "nullable") {
317
525
  if (mode === "falsy") {
318
526
  return array.filter(Boolean);
319
527
  }
@@ -322,7 +530,7 @@ function compact(array, mode = "nullable") {
322
530
  function forceArray(item) {
323
531
  return Array.isArray(item) ? item : [item];
324
532
  }
325
- function search(array, target, comparator = (a, b) => a > b ? 1 : a < b ? -1 : 0) {
533
+ function searchSorted(array, target, comparator = (a, b) => a > b ? 1 : a < b ? -1 : 0) {
326
534
  let low = 0;
327
535
  let high = array.length - 1;
328
536
  while (low <= high) {
@@ -385,13 +593,8 @@ function unique(array, key) {
385
593
  }
386
594
 
387
595
  // src/async.ts
388
- var async_exports = {};
389
- __export(async_exports, {
390
- retry: () => retry,
391
- wait: () => wait
392
- });
393
- async function retry(fn, options = {}) {
394
- const { retries = 3, delay = 500, timeout, signal } = options;
596
+ async function retryPromise(fn, options = {}) {
597
+ const { attempts = 3, delay = 500, timeout, signal } = options;
395
598
  if (signal?.aborted) throw new Error("Operation aborted");
396
599
  const executeWithTimeout = async () => {
397
600
  if (!timeout) return fn(signal);
@@ -410,7 +613,7 @@ async function retry(fn, options = {}) {
410
613
  return await executeWithTimeout();
411
614
  } catch (error) {
412
615
  if (signal?.aborted) throw error;
413
- if (retries <= 0) throw error;
616
+ if (attempts <= 0) throw error;
414
617
  const jitter = Math.random() * 200;
415
618
  const totalDelay = delay + jitter;
416
619
  await new Promise((resolve, reject) => {
@@ -424,51 +627,14 @@ async function retry(fn, options = {}) {
424
627
  { once: true }
425
628
  );
426
629
  });
427
- return retry(fn, { ...options, retries: retries - 1, delay: delay * 2 });
630
+ return retryPromise(fn, { ...options, attempts: attempts - 1, delay: delay * 2 });
428
631
  }
429
632
  }
430
- function wait(ms2) {
431
- return new Promise(
432
- (resolve) => setTimeout(() => {
433
- resolve(true);
434
- }, ms2)
435
- );
436
- }
437
-
438
- // src/fn.ts
439
- var fn_exports = {};
440
- __export(fn_exports, {
441
- memoize: () => memoize
442
- });
443
- function memoize(fn, options = {}) {
444
- const cache = /* @__PURE__ */ new Map();
445
- const { resolver, maxAge } = options;
446
- const memoized = function(...args) {
447
- const key = resolver ? resolver(...args) : JSON.stringify(args);
448
- const now = Date.now();
449
- const entry = cache.get(key);
450
- if (entry) {
451
- if (!maxAge || now - entry.timestamp < maxAge) {
452
- return entry.value;
453
- }
454
- cache.delete(key);
455
- }
456
- const result = fn.apply(this, args);
457
- cache.set(key, { value: result, timestamp: now });
458
- return result;
459
- };
460
- memoized.clear = () => cache.clear();
461
- return memoized;
633
+ function wait(ms) {
634
+ return new Promise((resolve) => setTimeout(() => resolve(true), ms));
462
635
  }
463
636
 
464
637
  // src/date.ts
465
- var date_exports = {};
466
- __export(date_exports, {
467
- duration: () => duration,
468
- eta: () => eta,
469
- getAge: () => getAge,
470
- parse: () => parse
471
- });
472
638
  var MS_MAP = {
473
639
  ms: 1,
474
640
  s: 1e3,
@@ -479,64 +645,18 @@ var MS_MAP = {
479
645
  mth: 24192e5,
480
646
  y: 31536e6
481
647
  };
482
- function duration(target, style = "hms", options = {}) {
483
- const targetMs = target instanceof Date ? target.getTime() : Number(target);
484
- const sinceMs = options.since instanceof Date ? options.since.getTime() : Number(options.since) || Date.now();
485
- const diff = Math.abs(targetMs - sinceMs);
486
- if (diff === 0) return style === "digital" ? "00:00" : "now";
487
- const s = Math.floor(diff / 1e3) % 60;
488
- const m = Math.floor(diff / 6e4) % 60;
489
- const h = Math.floor(diff / 36e5) % 24;
490
- const d = Math.floor(diff / 864e5);
491
- if (style === "digital") {
492
- const parts = [m, s].map((v) => String(v).padStart(2, "0"));
493
- if (h > 0 || d > 0) parts.unshift(String(h).padStart(2, "0"));
494
- if (d > 0) parts.unshift(String(d));
495
- return parts.join(":");
496
- }
497
- const result = [];
498
- const push = (val, label) => {
499
- if (val > 0) result.push(`${val} ${label}${val === 1 ? "" : "s"}`);
500
- };
501
- if (style === "ymdhms") push(d, "day");
502
- push(h, "hour");
503
- push(m, "minute");
504
- push(s, "second");
505
- if (result.length === 0) return "0 seconds";
506
- if (result.length === 1) return result[0];
507
- const last = result.pop();
508
- return `${result.join(", ")} and ${last}`;
509
- }
510
- function eta(date, locale) {
511
- const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
512
- const elapsed = (typeof date === "number" ? date : date.getTime()) - Date.now();
513
- const units = [
514
- { unit: "year", ms: 31536e6 },
515
- { unit: "month", ms: 2628e6 },
516
- { unit: "day", ms: 864e5 },
517
- { unit: "hour", ms: 36e5 },
518
- { unit: "minute", ms: 6e4 },
519
- { unit: "second", ms: 1e3 }
520
- ];
521
- for (const { unit, ms: ms2 } of units) {
522
- if (Math.abs(elapsed) >= ms2 || unit === "second") {
523
- return rtf.format(Math.round(elapsed / ms2), unit);
524
- }
525
- }
526
- return "";
527
- }
528
648
  function getAge(birthdate) {
529
- const today2 = /* @__PURE__ */ new Date();
530
- let age = today2.getFullYear() - birthdate.getFullYear();
531
- const monthDiff = today2.getMonth() - birthdate.getMonth();
532
- if (monthDiff < 0 || monthDiff === 0 && today2.getDate() < birthdate.getDate()) {
649
+ const today = /* @__PURE__ */ new Date();
650
+ let age = today.getFullYear() - birthdate.getFullYear();
651
+ const monthDiff = today.getMonth() - birthdate.getMonth();
652
+ if (monthDiff < 0 || monthDiff === 0 && today.getDate() < birthdate.getDate()) {
533
653
  age--;
534
654
  }
535
655
  return age;
536
656
  }
537
- function parse(str2, options = {}) {
538
- if (typeof str2 === "number") return str2;
539
- const matches = str2.matchAll(/(-?\d+)([a-z]+)/gi);
657
+ function parseTime(str, options = {}) {
658
+ if (typeof str === "number") return str;
659
+ const matches = str.matchAll(/(-?\d+)([a-z]+)/gi);
540
660
  let totalMs = 0;
541
661
  let found = false;
542
662
  for (const [_, value, unit] of matches) {
@@ -547,39 +667,85 @@ function parse(str2, options = {}) {
547
667
  found = true;
548
668
  }
549
669
  }
550
- if (!found) throw new Error(`parse: Invalid time format: "${str2}"`);
670
+ if (!found) throw new Error(`parse: Invalid time format: "${str}"`);
551
671
  const result = options.unit === "s" ? totalMs / 1e3 : totalMs;
552
672
  return options.fromNow ? Date.now() + result : result;
553
673
  }
554
674
 
675
+ // src/exec.ts
676
+ function debounce(fn, wait2, options = {}) {
677
+ let timeoutId;
678
+ const leading = options.immediate ?? false;
679
+ const debounced = function(...args) {
680
+ const callNow = leading && !timeoutId;
681
+ if (timeoutId) clearTimeout(timeoutId);
682
+ timeoutId = setTimeout(() => {
683
+ timeoutId = void 0;
684
+ if (!leading) fn.apply(this, args);
685
+ }, wait2);
686
+ if (callNow) fn.apply(this, args);
687
+ };
688
+ debounced.cancel = () => {
689
+ if (timeoutId) {
690
+ clearTimeout(timeoutId);
691
+ timeoutId = void 0;
692
+ }
693
+ };
694
+ return debounced;
695
+ }
696
+ function throttle(fn, limit) {
697
+ let inThrottle = false;
698
+ return function(...args) {
699
+ if (!inThrottle) {
700
+ fn.apply(this, args);
701
+ inThrottle = true;
702
+ setTimeout(() => inThrottle = false, limit);
703
+ }
704
+ };
705
+ }
706
+
707
+ // src/fn.ts
708
+ function memoize(fn, options = {}) {
709
+ const cache = /* @__PURE__ */ new Map();
710
+ const { resolver, maxAge } = options;
711
+ const memoized = function(...args) {
712
+ const key = resolver ? resolver(...args) : JSON.stringify(args);
713
+ const now = Date.now();
714
+ const entry = cache.get(key);
715
+ if (entry) {
716
+ if (!maxAge || now - entry.timestamp < maxAge) {
717
+ return entry.value;
718
+ }
719
+ cache.delete(key);
720
+ }
721
+ const result = fn.apply(this, args);
722
+ cache.set(key, { value: result, timestamp: now });
723
+ return result;
724
+ };
725
+ memoized.clear = () => cache.clear();
726
+ return memoized;
727
+ }
728
+
555
729
  // src/format.ts
556
- var format_exports = {};
557
- __export(format_exports, {
558
- compactNumber: () => compactNumber,
559
- currency: () => currency,
560
- memory: () => memory,
561
- number: () => number,
562
- ordinal: () => ordinal
563
- });
564
- function currency(num, options = {}) {
730
+ function formatCurrency(num, options = {}) {
565
731
  return new Intl.NumberFormat(options.locale, {
566
732
  style: "currency",
567
733
  currency: options.currency
568
734
  }).format(num);
569
735
  }
570
- function number(num, options = {}) {
736
+ function formatNumber(num, options = {}) {
571
737
  return new Intl.NumberFormat(options.locale, {
572
738
  minimumFractionDigits: options.precision,
573
739
  maximumFractionDigits: options.precision
574
740
  }).format(num);
575
741
  }
576
- function memory(bytes, decimals = 1, units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]) {
742
+ function formatMemory(bytes, decimals = 1, units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]) {
577
743
  if (bytes <= 0) return `0 ${units[0]}`;
578
744
  const i = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
579
745
  const val = bytes / Math.pow(1024, i);
580
746
  return `${val.toFixed(i === 0 ? 0 : decimals)} ${units[i]}`;
581
747
  }
582
- function ordinal(num, locale) {
748
+ function formatOrdinal(num, locale) {
583
749
  const _num = Number(num);
584
750
  if (isNaN(_num)) throw new TypeError("Invalid input");
585
751
  const pr = new Intl.PluralRules(locale, { type: "ordinal" });
@@ -593,35 +759,77 @@ function ordinal(num, locale) {
593
759
  const suffix = suffixes[rule] || "th";
594
760
  return _num.toLocaleString(locale) + suffix;
595
761
  }
596
- function compactNumber(num, locale) {
762
+ function FormatNumberCompact(num, locale) {
597
763
  return new Intl.NumberFormat(locale, {
598
764
  notation: "compact",
599
765
  compactDisplay: "short",
600
766
  maximumFractionDigits: 1
601
767
  }).format(num);
602
768
  }
769
+ function formatDuration(target, style = "hms", options = {}) {
770
+ const targetMs = target instanceof Date ? target.getTime() : Number(target);
771
+ const sinceMs = options.since instanceof Date ? options.since.getTime() : Number(options.since) || Date.now();
772
+ const diff = Math.abs(targetMs - sinceMs);
773
+ if (diff === 0) return style === "digital" ? "00:00" : "now";
774
+ const s = Math.floor(diff / 1e3) % 60;
775
+ const m = Math.floor(diff / 6e4) % 60;
776
+ const h = Math.floor(diff / 36e5) % 24;
777
+ const d = Math.floor(diff / 864e5);
778
+ if (style === "digital") {
779
+ const parts = [m, s].map((v) => String(v).padStart(2, "0"));
780
+ if (h > 0 || d > 0) parts.unshift(String(h).padStart(2, "0"));
781
+ if (d > 0) parts.unshift(String(d));
782
+ return parts.join(":");
783
+ }
784
+ const result = [];
785
+ const push = (val, label) => {
786
+ if (val > 0) result.push(`${val} ${label}${val === 1 ? "" : "s"}`);
787
+ };
788
+ if (style === "ymdhms") push(d, "day");
789
+ push(h, "hour");
790
+ push(m, "minute");
791
+ push(s, "second");
792
+ if (result.length === 0) return "0 seconds";
793
+ if (result.length === 1) return result[0];
794
+ const last = result.pop();
795
+ return `${result.join(", ")} and ${last}`;
796
+ }
797
+ function formatETA(date, locale) {
798
+ const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
799
+ const elapsed = (typeof date === "number" ? date : date.getTime()) - Date.now();
800
+ const units = [
801
+ { unit: "year", ms: 31536e6 },
802
+ { unit: "month", ms: 2628e6 },
803
+ { unit: "day", ms: 864e5 },
804
+ { unit: "hour", ms: 36e5 },
805
+ { unit: "minute", ms: 6e4 },
806
+ { unit: "second", ms: 1e3 }
807
+ ];
808
+ for (const { unit, ms } of units) {
809
+ if (Math.abs(elapsed) >= ms || unit === "second") {
810
+ return rtf.format(Math.round(elapsed / ms), unit);
811
+ }
812
+ }
813
+ return "";
814
+ }
603
815
 
604
816
  // src/fs.ts
605
- var fs_exports = {};
606
- __export(fs_exports, {
607
- readDir: () => readDir
608
- });
609
- var import_node_fs = __toESM(require("fs"));
610
- var import_node_path = require("path");
817
+ var import_node_fs2 = __toESM(require("fs"), 1);
818
+ var import_node_path2 = require("path");
611
819
  function readDir(path2, options = {}) {
612
820
  const { recursive = true } = options;
613
- if (!import_node_fs.default.existsSync(path2)) return [];
821
+ if (!import_node_fs2.default.existsSync(path2)) return [];
614
822
  if (!recursive) {
615
- return import_node_fs.default.readdirSync(path2).filter((fn) => {
616
- return import_node_fs.default.statSync((0, import_node_path.join)(path2, fn)).isFile();
823
+ return import_node_fs2.default.readdirSync(path2).filter((fn) => {
824
+ return import_node_fs2.default.statSync((0, import_node_path2.join)(path2, fn)).isFile();
617
825
  });
618
826
  }
619
827
  const walk = (dir, base = "") => {
620
828
  const results = [];
621
- const entries = import_node_fs.default.readdirSync(dir, { withFileTypes: true });
829
+ const entries = import_node_fs2.default.readdirSync(dir, { withFileTypes: true });
622
830
  for (const entry of entries) {
623
- const relativePath = base ? (0, import_node_path.join)(base, entry.name) : entry.name;
624
- const fullPath = (0, import_node_path.join)(dir, entry.name);
831
+ const relativePath = base ? (0, import_node_path2.join)(base, entry.name) : entry.name;
832
+ const fullPath = (0, import_node_path2.join)(dir, entry.name);
625
833
  if (entry.isDirectory()) {
626
834
  results.push(...walk(fullPath, relativePath));
627
835
  } else if (entry.isFile()) {
@@ -634,77 +842,58 @@ function readDir(path2, options = {}) {
634
842
  }
635
843
 
636
844
  // src/is.ts
637
- var is_exports = {};
638
- __export(is_exports, {
639
- defined: () => defined,
640
- empty: () => empty,
641
- inRange: () => inRange,
642
- object: () => object,
643
- sorted: () => sorted,
644
- string: () => string,
645
- today: () => today
646
- });
647
- function defined(val) {
845
+ function isDefined(val) {
648
846
  return val !== void 0 && val !== null;
649
847
  }
650
- function empty(val) {
651
- if (!defined(val)) return true;
652
- if (string(val) || Array.isArray(val)) return val.length === 0;
653
- if (object(val)) return Object.keys(val).length === 0;
848
+ function isEmpty(val) {
849
+ if (!isDefined(val)) return true;
850
+ if (isString(val) || Array.isArray(val)) return val.length === 0;
851
+ if (isObject(val)) return Object.keys(val).length === 0;
654
852
  return false;
655
853
  }
656
- function inRange(num, a, b) {
854
+ function isObject(val) {
855
+ return val !== null && typeof val === "object" && !Array.isArray(val);
856
+ }
857
+ function isString(val) {
858
+ return typeof val === "string";
859
+ }
860
+ function isInRange(num, a, b) {
657
861
  let min = b !== void 0 ? a : 0;
658
862
  let max = b !== void 0 ? b : a;
659
863
  if (min > max) [min, max] = [max, min];
660
864
  return num >= min && num <= max;
661
865
  }
662
- function object(val) {
663
- return val !== null && typeof val === "object" && !Array.isArray(val);
664
- }
665
- function sorted(arr, comparator) {
866
+ function isSortedArray(arr, comparator) {
666
867
  for (let i = 0; i < arr.length - 1; i++) {
667
868
  const comp = comparator ? comparator(arr[i], arr[i + 1]) : arr[i] > arr[i + 1] ? 1 : -1;
668
869
  if (comp > 0) return false;
669
870
  }
670
871
  return true;
671
872
  }
672
- function string(val) {
673
- return typeof val === "string";
674
- }
675
- function today(date) {
873
+ function isToday(date) {
676
874
  const d = date instanceof Date ? date : new Date(date);
677
- const today2 = /* @__PURE__ */ new Date();
678
- return d.getDate() === today2.getDate() && d.getMonth() === today2.getMonth() && d.getFullYear() === today2.getFullYear();
875
+ const today = /* @__PURE__ */ new Date();
876
+ return d.getDate() === today.getDate() && d.getMonth() === today.getMonth() && d.getFullYear() === today.getFullYear();
679
877
  }
680
878
 
681
879
  // src/math.ts
682
- var math_exports = {};
683
- __export(math_exports, {
684
- clamp: () => clamp,
685
- invLerp: () => invLerp,
686
- lerp: () => lerp,
687
- ms: () => ms,
688
- percent: () => percent,
689
- remap: () => remap,
690
- secs: () => secs,
691
- sum: () => sum,
692
- wrap: () => wrap
693
- });
694
- function clamp(num, a, b) {
880
+ function clampNumber(num, a, b) {
695
881
  let min = b !== void 0 ? a : 0;
696
882
  let max = b !== void 0 ? b : a;
697
883
  if (min > max) [min, max] = [max, min];
698
884
  return Math.max(min, Math.min(num, max));
699
885
  }
700
- function invLerp(start, end, value) {
886
+ function lerp(start, end, t) {
887
+ return start + (end - start) * t;
888
+ }
889
+ function inverseLerp(start, end, value) {
701
890
  if (start === end) return 0;
702
891
  return (value - start) / (end - start);
703
892
  }
704
- function lerp(start, end, t) {
705
- return start + (end - start) * t;
893
+ function msToSecs(num) {
894
+ return Math.floor(num / 1e3);
706
895
  }
707
- function ms(num) {
896
+ function secsToMs(num) {
708
897
  return Math.floor(num * 1e3);
709
898
  }
710
899
  function percent(a, b, round = true) {
@@ -712,36 +901,19 @@ function percent(a, b, round = true) {
712
901
  return round ? Math.floor(result) : result;
713
902
  }
714
903
  function remap(value, inMin, inMax, outMin, outMax) {
715
- const t = invLerp(inMin, inMax, value);
904
+ const t = inverseLerp(inMin, inMax, value);
716
905
  return lerp(outMin, outMax, t);
717
906
  }
718
- function secs(num) {
719
- return Math.floor(num / 1e3);
720
- }
721
907
  function sum(array, selector) {
722
908
  const _array = selector ? array.map(selector) : array;
723
- if (!_array.every((v) => typeof v === "number")) {
724
- throw new TypeError(`sum: Array must only contain numbers.`);
725
- }
726
- return _array.reduce((a, b) => {
727
- return (isNaN(b) ? 0 : b) < 0 ? a - -b : a + (b || 0);
728
- }, 0);
909
+ return _array.reduce((a, b) => b < 0 ? a - -b : a + (b || 0), 0);
729
910
  }
730
911
  function wrap(num, max) {
731
912
  return (num % max + max) % max;
732
913
  }
733
914
 
734
915
  // src/obj.ts
735
- var obj_exports = {};
736
- __export(obj_exports, {
737
- get: () => get,
738
- has: () => has,
739
- merge: () => merge,
740
- omit: () => omit,
741
- pick: () => pick,
742
- set: () => set
743
- });
744
- function get(obj, path2, defaultValue) {
916
+ function getProp(obj, path2, defaultValue) {
745
917
  if (!obj) throw new Error("get: Target object is null or undefined");
746
918
  const parts = path2.replace(/\[(\d+)\]/g, ".$1").split(".");
747
919
  let current = obj;
@@ -760,7 +932,7 @@ function get(obj, path2, defaultValue) {
760
932
  }
761
933
  return current;
762
934
  }
763
- function has(obj, path2) {
935
+ function hasProp(obj, path2) {
764
936
  if (!obj || !path2) return false;
765
937
  const parts = path2.replace(/\[(\d+)\]/g, ".$1").split(".");
766
938
  let current = obj;
@@ -776,7 +948,7 @@ function has(obj, path2) {
776
948
  }
777
949
  return true;
778
950
  }
779
- function set(obj, path2, value) {
951
+ function setProp(obj, path2, value) {
780
952
  const parts = path2.replace(/\[(\d+)\]/g, ".$1").split(".");
781
953
  let current = obj;
782
954
  for (let i = 0; i < parts.length; i++) {
@@ -828,36 +1000,32 @@ function omit(obj, keys) {
828
1000
  }
829
1001
 
830
1002
  // src/str.ts
831
- var str_exports = {};
832
- __export(str_exports, {
833
- escapeRegex: () => escapeRegex,
834
- getFlag: () => getFlag,
835
- hasFlag: () => hasFlag,
836
- toTitleCase: () => toTitleCase
837
- });
838
- function escapeRegex(str2) {
839
- return str2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1003
+ function escapeRegex(str) {
1004
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
840
1005
  }
841
- function getFlag(str2, flag, length) {
1006
+ function getFlag(str, flag, length) {
842
1007
  const regex = flag instanceof RegExp ? flag : new RegExp(`${escapeRegex(flag)}\\b`, "g");
843
- const match = regex.exec(str2);
1008
+ const match = regex.exec(str);
844
1009
  if (!match) return null;
845
1010
  const startIndex = match.index + match[0].length;
846
- let result = str2.slice(startIndex).trimStart();
1011
+ let result = str.slice(startIndex).trimStart();
847
1012
  if (length !== void 0) {
848
1013
  return result.split(/\s+/).slice(0, length).join(" ");
849
1014
  }
850
1015
  return result || null;
851
1016
  }
852
- function hasFlag(str2, flag) {
853
- if (flag instanceof RegExp) return flag.test(str2);
1017
+ function hasFlag(str, flag) {
1018
+ if (flag instanceof RegExp) return flag.test(str);
854
1019
  const pattern = new RegExp(`${escapeRegex(flag)}\\b`);
855
- return pattern.test(str2);
1020
+ return pattern.test(str);
1021
+ }
1022
+ function pluralize(count, singular, plural = `${singular}s`) {
1023
+ return count === 1 ? singular : plural;
856
1024
  }
857
- function toTitleCase(str2, smart = true) {
1025
+ function toTitleCase(str, smart = true) {
858
1026
  const minorWords = /^(a|an|and|as|at|but|by|en|for|if|in|of|on|or|the|to|v\.?|via)$/i;
859
- return str2.replace(/\w\S*/g, (txt, index2) => {
860
- if (smart && index2 !== 0 && minorWords.test(txt)) {
1027
+ return str.replace(/\w\S*/g, (txt, index) => {
1028
+ if (smart && index !== 0 && minorWords.test(txt)) {
861
1029
  return txt.toLowerCase();
862
1030
  }
863
1031
  if (smart && txt.length > 1 && txt === txt.toUpperCase()) {
@@ -866,392 +1034,71 @@ function toTitleCase(str2, smart = true) {
866
1034
  return txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase();
867
1035
  });
868
1036
  }
869
-
870
- // src/timing.ts
871
- var timing_exports = {};
872
- __export(timing_exports, {
873
- debounce: () => debounce,
874
- throttle: () => throttle
875
- });
876
- function debounce(fn, wait2, options = {}) {
877
- let timeoutId;
878
- const leading = options.immediate ?? false;
879
- const debounced = function(...args) {
880
- const callNow = leading && !timeoutId;
881
- if (timeoutId) clearTimeout(timeoutId);
882
- timeoutId = setTimeout(() => {
883
- timeoutId = void 0;
884
- if (!leading) fn.apply(this, args);
885
- }, wait2);
886
- if (callNow) fn.apply(this, args);
887
- };
888
- debounced.cancel = () => {
889
- if (timeoutId) {
890
- clearTimeout(timeoutId);
891
- timeoutId = void 0;
892
- }
893
- };
894
- return debounced;
895
- }
896
- function throttle(fn, limit) {
897
- let inThrottle = false;
898
- return function(...args) {
899
- if (!inThrottle) {
900
- fn.apply(this, args);
901
- inThrottle = true;
902
- setTimeout(() => inThrottle = false, limit);
903
- }
904
- };
905
- }
906
-
907
- // src/to.ts
908
- var to_exports = {};
909
- __export(to_exports, {
910
- record: () => record
911
- });
912
- function record(array, callback) {
913
- const result = {};
914
- let lastValue = void 0;
915
- for (let i = 0; i < array.length; i++) {
916
- const { key, value } = callback(array[i], {
917
- index: i,
918
- lastValue,
919
- // NOTE: This is a reference to the object currently being built
920
- newRecord: result,
921
- originalArray: array
922
- });
923
- result[key] = value;
924
- lastValue = value;
925
- }
926
- return result;
927
- }
928
-
929
- // src/Pipe.ts
930
- function Pipe(value, ...fns) {
931
- return fns.reduce((acc, fn) => fn(acc), value);
932
- }
933
-
934
- // src/Storage.ts
935
- var import_node_fs2 = __toESM(require("fs"));
936
- var import_node_path2 = __toESM(require("path"));
937
- var Storage = class {
938
- isNode = typeof window === "undefined";
939
- filePath = null;
940
- memoryCache = /* @__PURE__ */ new Map();
941
- loadFromFile() {
942
- if (this.filePath && import_node_fs2.default.existsSync(this.filePath)) {
943
- try {
944
- const data = JSON.parse(import_node_fs2.default.readFileSync(this.filePath, "utf-8"));
945
- Object.entries(data).forEach(([k, v]) => this.memoryCache.set(k, JSON.stringify(v)));
946
- } catch (err) {
947
- console.error(`Store: Failed to load file '${this.filePath}'`, err);
948
- }
949
- }
950
- }
951
- persist() {
952
- if (this.isNode && this.filePath) {
953
- const out = {};
954
- this.memoryCache.forEach((v, k) => out[k] = JSON.parse(v));
955
- import_node_fs2.default.writeFileSync(this.filePath, JSON.stringify(out, null, 2));
956
- }
957
- }
958
- /**
959
- * A lightweight, high-performant persistent storage system.
960
- * Uses JSON files in Node.js, localStorage in the browser.
961
- * @param fileName Only used in Node.js to create a persistent .json file.
962
- * @param directory The directory for the file. Defaults to current working directory.
963
- */
964
- constructor(fileName, directory = process.cwd()) {
965
- if (this.isNode && fileName) {
966
- this.filePath = import_node_path2.default.join(directory, fileName.endsWith(".json") ? fileName : `${fileName}.json`);
967
- this.loadFromFile();
968
- }
969
- }
970
- has(key) {
971
- if (!this.isNode && window.localStorage) {
972
- return localStorage.getItem(key) !== null;
973
- }
974
- return this.memoryCache.has(key);
975
- }
976
- get(key) {
977
- let raw = null;
978
- if (!this.isNode && window.localStorage) {
979
- raw = localStorage.getItem(key);
980
- } else {
981
- raw = this.memoryCache.get(key) || null;
982
- }
983
- if (!raw) return null;
984
- const payload = JSON.parse(raw);
985
- if (payload.expiry && Date.now() > payload.expiry) {
986
- this.remove(key);
987
- this.persist();
988
- return null;
989
- }
990
- return payload.value;
991
- }
992
- set(key, value, ttl) {
993
- const payload = {
994
- value,
995
- expiry: ttl ? Date.now() + ttl : null
996
- };
997
- const serialized = JSON.stringify(payload);
998
- if (!this.isNode && window.localStorage) {
999
- localStorage.setItem(key, serialized);
1000
- } else {
1001
- this.memoryCache.set(key, serialized);
1002
- this.persist();
1003
- }
1004
- }
1005
- remove(key) {
1006
- if (!this.isNode && window.localStorage) {
1007
- localStorage.removeItem(key);
1008
- } else {
1009
- this.memoryCache.delete(key);
1010
- this.persist();
1011
- }
1012
- }
1013
- clear() {
1014
- if (!this.isNode && window.localStorage) {
1015
- localStorage.clear();
1016
- } else {
1017
- this.memoryCache.clear();
1018
- this.persist();
1019
- }
1020
- }
1021
- };
1022
-
1023
- // src/Cache.ts
1024
- var Cache = class {
1025
- cache = /* @__PURE__ */ new Map();
1026
- interval;
1027
- /**
1028
- * A lightweight, high-performant in-memory cache.
1029
- * Uses Map for O(1) lookups and an optional cleanup interval.
1030
- * @param cleanupMs The interval in milliseconds to run the cleanup function. [default: 60000 (1 minute)]
1031
- */
1032
- constructor(cleanupMs = 6e4) {
1033
- if (cleanupMs > 0) {
1034
- this.interval = setInterval(() => this.cleanup(), cleanupMs);
1035
- if (this.interval.unref) this.interval.unref();
1036
- }
1037
- }
1038
- set(key, value, ttlMs) {
1039
- this.cache.set(key, {
1040
- value,
1041
- expiresAt: ttlMs ? Date.now() + ttlMs : null
1042
- });
1043
- }
1044
- get(key) {
1045
- const data = this.cache.get(key);
1046
- if (!data) return null;
1047
- if (data.expiresAt && Date.now() > data.expiresAt) {
1048
- this.cache.delete(key);
1049
- return null;
1050
- }
1051
- return data.value;
1052
- }
1053
- cleanup() {
1054
- if (this.cache.size === 0) return;
1055
- const now = Date.now();
1056
- let keysProcessed = 0;
1057
- const maxKeysToScan = 20;
1058
- for (const [key, data] of this.cache) {
1059
- if (data.expiresAt && now > data.expiresAt) {
1060
- this.cache.delete(key);
1061
- }
1062
- keysProcessed++;
1063
- if (keysProcessed >= maxKeysToScan) break;
1064
- }
1065
- }
1066
- clear() {
1067
- this.cache.clear();
1068
- }
1069
- };
1070
-
1071
- // src/Loop.ts
1072
- var import_node_events = __toESM(require("events"));
1073
- var TypedEmitterBase = import_node_events.default;
1074
- var Loop = class extends TypedEmitterBase {
1075
- _state = "stopped";
1076
- timeoutId = null;
1077
- delay;
1078
- fn;
1079
- startTime = 0;
1080
- remaining = 0;
1081
- async run() {
1082
- const currentState = this._state;
1083
- if (currentState === "stopped" || currentState === "paused") return;
1084
- try {
1085
- const result = await this.fn(this);
1086
- this.emit("tick", result);
1087
- } catch (err) {
1088
- this.emit("error", err);
1089
- }
1090
- if (this._state === "running") {
1091
- this.startTime = Date.now();
1092
- this.remaining = 0;
1093
- this.clearTimer();
1094
- this.timeoutId = setTimeout(() => this.run(), this.delay);
1095
- }
1096
- }
1097
- clearTimer() {
1098
- if (this.timeoutId) {
1099
- clearTimeout(this.timeoutId);
1100
- this.timeoutId = null;
1101
- }
1102
- }
1103
- /**
1104
- * Creates an interval. If the function is async, it will wait for it to complete before scheduling the next run.
1105
- * @param fn The function to run.
1106
- * @param delay The delay between runs in milliseconds.
1107
- * @param immediate Whether to start the loop immediately. [default: true]
1108
- */
1109
- constructor(fn, delay, immediate = true) {
1110
- super();
1111
- this.fn = fn;
1112
- this.delay = delay;
1113
- if (immediate) this.start();
1114
- }
1115
- get state() {
1116
- return this._state;
1117
- }
1118
- /** Starts the loop. */
1119
- start() {
1120
- if (this._state !== "stopped") return;
1121
- this._state = "running";
1122
- this.emit("start");
1123
- this.run();
1124
- }
1125
- /** Resumes a paused loop. */
1126
- resume() {
1127
- if (this._state !== "paused") return;
1128
- this._state = "running";
1129
- this.emit("resume");
1130
- if (this.remaining <= 0) {
1131
- this.run();
1132
- } else {
1133
- this.timeoutId = setTimeout(() => this.run(), this.remaining);
1134
- }
1135
- }
1136
- /** Stops the loop. */
1137
- stop() {
1138
- const wasRunning = this._state !== "stopped";
1139
- this._state = "stopped";
1140
- this.remaining = 0;
1141
- this.clearTimer();
1142
- if (wasRunning) this.emit("stop");
1143
- }
1144
- /** Pauses the execution. */
1145
- pause() {
1146
- if (this._state !== "running") return;
1147
- this._state = "paused";
1148
- const elapsed = Date.now() - this.startTime;
1149
- this.remaining = Math.max(0, this.delay - elapsed);
1150
- this.emit("pause", { remaining: this.remaining });
1151
- this.clearTimer();
1152
- }
1153
- /**
1154
- * Sets the delay between runs
1155
- * @param ms The new delay in milliseconds.
1156
- */
1157
- setDelay(ms2) {
1158
- this.delay = ms2;
1159
- }
1160
- /** Manually trigger the function once without affecting the loop. */
1161
- async execute() {
1162
- await this.fn(this);
1163
- }
1164
- };
1165
-
1166
- // src/index.ts
1167
- var qznt = {
1168
- arr: arr_exports,
1169
- async: async_exports,
1170
- fn: fn_exports,
1171
- date: date_exports,
1172
- format: format_exports,
1173
- fs: fs_exports,
1174
- is: is_exports,
1175
- math: math_exports,
1176
- obj: obj_exports,
1177
- timing: timing_exports,
1178
- rnd: rnd_exports,
1179
- str: str_exports,
1180
- to: to_exports,
1181
- Pipe,
1182
- Storage,
1183
- Cache,
1184
- Loop
1185
- };
1186
- var $ = qznt;
1187
- var index_default = qznt;
1188
1037
  // Annotate the CommonJS export names for ESM import in node:
1189
1038
  0 && (module.exports = {
1190
- $,
1191
1039
  Cache,
1040
+ FormatNumberCompact,
1192
1041
  Loop,
1193
1042
  Pipe,
1194
1043
  Storage,
1195
- chance,
1196
- choice,
1197
1044
  chunk,
1198
1045
  chunkAdj,
1199
- clamp,
1046
+ clampNumber,
1200
1047
  cluster,
1201
- compact,
1202
- compactNumber,
1203
- currency,
1048
+ compactArray,
1049
+ createSampler,
1204
1050
  debounce,
1205
- defined,
1206
- duration,
1207
- empty,
1208
1051
  escapeRegex,
1209
- eta,
1210
- float,
1211
1052
  forceArray,
1212
- get,
1053
+ formatCurrency,
1054
+ formatDuration,
1055
+ formatETA,
1056
+ formatMemory,
1057
+ formatNumber,
1058
+ formatOrdinal,
1213
1059
  getAge,
1214
1060
  getFlag,
1215
- has,
1061
+ getProp,
1216
1062
  hasFlag,
1217
- inRange,
1218
- index,
1219
- int,
1220
- invLerp,
1063
+ hasProp,
1064
+ inverseLerp,
1065
+ isDefined,
1066
+ isEmpty,
1067
+ isInRange,
1068
+ isObject,
1069
+ isSortedArray,
1070
+ isString,
1071
+ isToday,
1221
1072
  lerp,
1222
1073
  memoize,
1223
- memory,
1224
1074
  merge,
1225
- ms,
1226
- number,
1227
- object,
1075
+ msToSecs,
1228
1076
  omit,
1229
- ordinal,
1230
- parse,
1077
+ parseTime,
1231
1078
  percent,
1232
1079
  pick,
1080
+ pluralize,
1233
1081
  prng,
1234
1082
  readDir,
1235
- record,
1236
1083
  remap,
1237
- retry,
1238
- sampler,
1239
- search,
1240
- secs,
1084
+ retryPromise,
1085
+ rndChance,
1086
+ rndChoice,
1087
+ rndFloat,
1088
+ rndIndex,
1089
+ rndInt,
1090
+ rndString,
1091
+ searchSorted,
1092
+ secsToMs,
1241
1093
  seqMap,
1242
- set,
1094
+ setProp,
1243
1095
  shuffle,
1244
1096
  sortBy,
1245
- sorted,
1246
- str,
1247
- string,
1248
1097
  sum,
1249
1098
  throttle,
1250
1099
  toTitleCase,
1251
- today,
1252
1100
  unique,
1253
1101
  wait,
1254
- weighted,
1102
+ weightedRnd,
1255
1103
  wrap
1256
1104
  });
1257
- //# sourceMappingURL=index.cjs.map