qznt 1.0.37 → 2.0.1

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,325 @@ 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
+ try {
167
+ this.emit("error", err);
168
+ } catch {
169
+ }
170
+ }
171
+ if (this._state === "running") {
172
+ this.startTime = Date.now();
173
+ this.remaining = 0;
174
+ this.clearTimer();
175
+ this.timeoutId = setTimeout(() => this.run(), this.delay);
176
+ }
177
+ }
178
+ clearTimer() {
179
+ if (this.timeoutId) {
180
+ clearTimeout(this.timeoutId);
181
+ this.timeoutId = null;
182
+ }
183
+ }
184
+ /**
185
+ * Creates an interval. If the function is async, it will wait for it to complete before scheduling the next run.
186
+ * @param fn The function to run.
187
+ * @param delay The delay between runs in milliseconds.
188
+ * @param immediate Whether to start the loop immediately. [default: true]
189
+ */
190
+ constructor(fn, delay, immediate = true) {
191
+ super();
192
+ this.fn = fn;
193
+ this.delay = delay;
194
+ if (immediate) this.start();
195
+ }
196
+ get state() {
197
+ return this._state;
198
+ }
199
+ /** Starts the loop. */
200
+ start() {
201
+ if (this._state !== "stopped") return;
202
+ this._state = "running";
203
+ this.emit("start");
204
+ this.run();
205
+ }
206
+ /** Resumes a paused loop. */
207
+ resume() {
208
+ if (this._state !== "paused") return;
209
+ this._state = "running";
210
+ this.emit("resume");
211
+ if (this.remaining <= 0) {
212
+ this.run();
213
+ } else {
214
+ this.timeoutId = setTimeout(() => this.run(), this.remaining);
215
+ }
216
+ }
217
+ /** Stops the loop. */
218
+ stop() {
219
+ const wasRunning = this._state !== "stopped";
220
+ this._state = "stopped";
221
+ this.remaining = 0;
222
+ this.clearTimer();
223
+ if (wasRunning) this.emit("stop");
224
+ }
225
+ /** Pauses the execution. */
226
+ pause() {
227
+ if (this._state !== "running") return;
228
+ this._state = "paused";
229
+ const elapsed = Date.now() - this.startTime;
230
+ this.remaining = Math.max(0, this.delay - elapsed);
231
+ this.emit("pause", { remaining: this.remaining });
232
+ this.clearTimer();
233
+ }
234
+ /**
235
+ * Sets the delay between runs
236
+ * @param ms The new delay in milliseconds.
237
+ */
238
+ setDelay(ms) {
239
+ this.delay = ms;
240
+ }
241
+ /** Manually trigger the function once without affecting the loop. */
242
+ async execute() {
243
+ await this.fn(this);
244
+ }
245
+ };
246
+
247
+ // src/Pipe.ts
248
+ function Pipe(value, ...fns) {
249
+ return fns.reduce((acc, fn) => fn(acc), value);
250
+ }
251
+
252
+ // src/Storage.ts
253
+ var import_node_fs = __toESM(require("fs"), 1);
254
+ var import_node_path = __toESM(require("path"), 1);
255
+ var Storage = class {
256
+ isNode = typeof window === "undefined";
257
+ filePath = null;
258
+ memoryCache = /* @__PURE__ */ new Map();
259
+ loadFromFile() {
260
+ if (this.filePath && import_node_fs.default.existsSync(this.filePath)) {
261
+ try {
262
+ const data = JSON.parse(import_node_fs.default.readFileSync(this.filePath, "utf-8"));
263
+ Object.entries(data).forEach(([k, v]) => this.memoryCache.set(k, JSON.stringify(v)));
264
+ } catch (err) {
265
+ console.error(`Store: Failed to load file '${this.filePath}'`, err);
266
+ }
267
+ }
268
+ }
269
+ persist() {
270
+ if (this.isNode && this.filePath) {
271
+ const out = {};
272
+ this.memoryCache.forEach((v, k) => out[k] = JSON.parse(v));
273
+ import_node_fs.default.writeFileSync(this.filePath, JSON.stringify(out, null, 2));
274
+ }
275
+ }
276
+ /**
277
+ * A lightweight, high-performant persistent storage system.
278
+ * Uses JSON files in Node.js, localStorage in the browser
279
+ * @param fileName Only used in Node.js to create a persistent .json file
280
+ * @param directory The directory for the file. Defaults to current working directory
281
+ */
282
+ constructor(fileName, directory = process.cwd()) {
283
+ if (this.isNode && fileName) {
284
+ this.filePath = import_node_path.default.join(directory, fileName.endsWith(".json") ? fileName : `${fileName}.json`);
285
+ this.loadFromFile();
286
+ }
287
+ }
288
+ has(key) {
289
+ if (!this.isNode && window.localStorage) {
290
+ return localStorage.getItem(key) !== null;
291
+ }
292
+ return this.memoryCache.has(key);
293
+ }
294
+ get(key) {
295
+ let raw = null;
296
+ if (!this.isNode && window.localStorage) {
297
+ raw = localStorage.getItem(key);
298
+ } else {
299
+ raw = this.memoryCache.get(key) || null;
300
+ }
301
+ if (!raw) return null;
302
+ const payload = JSON.parse(raw);
303
+ if (payload.expiry && Date.now() > payload.expiry) {
304
+ this.remove(key);
305
+ this.persist();
306
+ return null;
307
+ }
308
+ return payload.value;
309
+ }
310
+ set(key, value, ttl) {
311
+ const payload = {
312
+ value,
313
+ expiry: ttl ? Date.now() + ttl : null
314
+ };
315
+ const serialized = JSON.stringify(payload);
316
+ if (!this.isNode && window.localStorage) {
317
+ localStorage.setItem(key, serialized);
318
+ } else {
319
+ this.memoryCache.set(key, serialized);
320
+ this.persist();
321
+ }
322
+ }
323
+ remove(key) {
324
+ if (!this.isNode && window.localStorage) {
325
+ localStorage.removeItem(key);
326
+ } else {
327
+ this.memoryCache.delete(key);
328
+ this.persist();
329
+ }
330
+ }
331
+ clear() {
332
+ if (!this.isNode && window.localStorage) {
333
+ localStorage.clear();
334
+ } else {
335
+ this.memoryCache.clear();
336
+ this.persist();
337
+ }
338
+ }
339
+ };
340
+
341
+ // src/random.ts
131
342
  var LOWER = "abcdefghijklmnopqrstuvwxyz";
132
343
  var UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
133
344
  var NUM = "0123456789";
134
- function chance(percent2 = 0.5, seed) {
345
+ function rndChance(percent2 = 0.5, seed) {
135
346
  if (percent2 <= 0) return false;
136
347
  if (percent2 >= 1) return true;
137
348
  const random = seed !== void 0 ? prng(seed) : Math.random;
138
349
  return random() < percent2;
139
350
  }
140
- function choice(array, options = {}) {
351
+ function rndChoice(array, options = {}) {
141
352
  const { seed, not, maxRerolls = 10 } = options;
142
353
  const random = seed !== void 0 ? prng(seed) : Math.random;
143
354
  const rnd = () => array[Math.floor(random() * array.length)];
@@ -152,19 +363,19 @@ function choice(array, options = {}) {
152
363
  }
153
364
  return result;
154
365
  }
155
- function weighted(array, selector, seed) {
366
+ function weightedRnd(array, predicate, seed) {
156
367
  const random = seed !== void 0 ? prng(seed) : Math.random;
157
368
  const cumulativeWeights = [];
158
369
  let currentSum = 0;
159
370
  for (const item of array) {
160
- const weight = selector(item);
371
+ const weight = predicate(item);
161
372
  currentSum += weight;
162
373
  cumulativeWeights.push(currentSum);
163
374
  }
164
375
  const decider = random() * currentSum;
165
- let index2;
376
+ let index;
166
377
  if (array.length < 20) {
167
- index2 = cumulativeWeights.findIndex((w) => w >= decider);
378
+ index = cumulativeWeights.findIndex((w) => w >= decider);
168
379
  } else {
169
380
  let low = 0;
170
381
  let high = cumulativeWeights.length - 1;
@@ -176,16 +387,16 @@ function weighted(array, selector, seed) {
176
387
  high = mid;
177
388
  }
178
389
  }
179
- index2 = low;
390
+ index = low;
180
391
  }
181
- return array[index2];
392
+ return array[index];
182
393
  }
183
- function sampler(items, selector, seed) {
394
+ function createSampler(items, predicate, seed) {
184
395
  const callRandom = seed ? prng(seed) : void 0;
185
396
  const len = items.length;
186
397
  const prob = new Array(len);
187
398
  const alias = new Array(len);
188
- const weights = items.map(selector);
399
+ const weights = items.map(predicate);
189
400
  const totalWeight = weights.reduce((a, b) => a + b, 0);
190
401
  const scaledWeights = weights.map((w) => w * len / totalWeight);
191
402
  const small = [];
@@ -203,8 +414,8 @@ function sampler(items, selector, seed) {
203
414
  while (small.length) prob[small.pop()] = 1;
204
415
  return {
205
416
  /**
206
- * Returns a random item from the given array in O(1) time.
207
- * @param seed Optional seed for RNG.
417
+ * Returns a random item from the given array in O(1) time
418
+ * @param seed Optional seed for RNG
208
419
  */
209
420
  pick: (seed2) => {
210
421
  const random = seed2 !== void 0 ? prng(seed2) : callRandom || Math.random;
@@ -221,11 +432,11 @@ function prng(seed) {
221
432
  return ((t ^ t >>> 14) >>> 0) / 4294967296;
222
433
  };
223
434
  }
224
- function float(min, max, seed) {
435
+ function rndFloat(min, max, seed) {
225
436
  const random = seed !== void 0 ? prng(seed) : Math.random;
226
437
  return random() * (max - min) + min;
227
438
  }
228
- function index(array, options = {}) {
439
+ function rndIndex(array, options = {}) {
229
440
  const { seed, not, maxRerolls = 10 } = options;
230
441
  const random = seed !== void 0 ? prng(seed) : Math.random;
231
442
  const rnd = () => Math.floor(random() * array.length);
@@ -240,11 +451,11 @@ function index(array, options = {}) {
240
451
  }
241
452
  return result;
242
453
  }
243
- function int(min, max, seed) {
454
+ function rndInt(min, max, seed) {
244
455
  const random = seed !== void 0 ? prng(seed) : Math.random;
245
456
  return Math.floor(random() * (max - min + 1)) + min;
246
457
  }
247
- function str(len, mode, options = {}) {
458
+ function rndString(len, mode, options = {}) {
248
459
  const { casing = "lower", seed, customChars = "", exclude = "" } = options;
249
460
  const random = seed !== void 0 ? prng(seed) : Math.random;
250
461
  const alphaPool = { lower: LOWER, upper: UPPER, mixed: LOWER + UPPER }[casing];
@@ -262,7 +473,7 @@ function str(len, mode, options = {}) {
262
473
  return result.join("");
263
474
  }
264
475
 
265
- // src/arr.ts
476
+ // src/array.ts
266
477
  function chunk(array, size) {
267
478
  if (size <= 0) throw new Error("chunk: Size must be a positive integer.");
268
479
  const result = [];
@@ -313,7 +524,7 @@ function cluster(array, iteratee, maxChunkSize) {
313
524
  }
314
525
  return result;
315
526
  }
316
- function compact(array, mode = "nullable") {
527
+ function compactArray(array, mode = "nullable") {
317
528
  if (mode === "falsy") {
318
529
  return array.filter(Boolean);
319
530
  }
@@ -322,7 +533,7 @@ function compact(array, mode = "nullable") {
322
533
  function forceArray(item) {
323
534
  return Array.isArray(item) ? item : [item];
324
535
  }
325
- function search(array, target, comparator = (a, b) => a > b ? 1 : a < b ? -1 : 0) {
536
+ function searchSorted(array, target, comparator = (a, b) => a > b ? 1 : a < b ? -1 : 0) {
326
537
  let low = 0;
327
538
  let high = array.length - 1;
328
539
  while (low <= high) {
@@ -385,13 +596,8 @@ function unique(array, key) {
385
596
  }
386
597
 
387
598
  // 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;
599
+ async function retryPromise(fn, options = {}) {
600
+ const { attempts = 3, delay = 500, timeout, signal } = options;
395
601
  if (signal?.aborted) throw new Error("Operation aborted");
396
602
  const executeWithTimeout = async () => {
397
603
  if (!timeout) return fn(signal);
@@ -410,7 +616,7 @@ async function retry(fn, options = {}) {
410
616
  return await executeWithTimeout();
411
617
  } catch (error) {
412
618
  if (signal?.aborted) throw error;
413
- if (retries <= 0) throw error;
619
+ if (attempts <= 0) throw error;
414
620
  const jitter = Math.random() * 200;
415
621
  const totalDelay = delay + jitter;
416
622
  await new Promise((resolve, reject) => {
@@ -424,51 +630,14 @@ async function retry(fn, options = {}) {
424
630
  { once: true }
425
631
  );
426
632
  });
427
- return retry(fn, { ...options, retries: retries - 1, delay: delay * 2 });
633
+ return retryPromise(fn, { ...options, attempts: attempts - 1, delay: delay * 2 });
428
634
  }
429
635
  }
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;
636
+ function wait(ms) {
637
+ return new Promise((resolve) => setTimeout(() => resolve(true), ms));
462
638
  }
463
639
 
464
640
  // 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
641
  var MS_MAP = {
473
642
  ms: 1,
474
643
  s: 1e3,
@@ -479,64 +648,18 @@ var MS_MAP = {
479
648
  mth: 24192e5,
480
649
  y: 31536e6
481
650
  };
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
651
  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()) {
652
+ const today = /* @__PURE__ */ new Date();
653
+ let age = today.getFullYear() - birthdate.getFullYear();
654
+ const monthDiff = today.getMonth() - birthdate.getMonth();
655
+ if (monthDiff < 0 || monthDiff === 0 && today.getDate() < birthdate.getDate()) {
533
656
  age--;
534
657
  }
535
658
  return age;
536
659
  }
537
- function parse(str2, options = {}) {
538
- if (typeof str2 === "number") return str2;
539
- const matches = str2.matchAll(/(-?\d+)([a-z]+)/gi);
660
+ function parseTime(str, options = {}) {
661
+ if (typeof str === "number") return str;
662
+ const matches = str.matchAll(/(-?\d+)([a-z]+)/gi);
540
663
  let totalMs = 0;
541
664
  let found = false;
542
665
  for (const [_, value, unit] of matches) {
@@ -547,39 +670,85 @@ function parse(str2, options = {}) {
547
670
  found = true;
548
671
  }
549
672
  }
550
- if (!found) throw new Error(`parse: Invalid time format: "${str2}"`);
673
+ if (!found) throw new Error(`parse: Invalid time format: "${str}"`);
551
674
  const result = options.unit === "s" ? totalMs / 1e3 : totalMs;
552
675
  return options.fromNow ? Date.now() + result : result;
553
676
  }
554
677
 
678
+ // src/exec.ts
679
+ function debounce(fn, wait2, options = {}) {
680
+ let timeoutId;
681
+ const leading = options.immediate ?? false;
682
+ const debounced = function(...args) {
683
+ const callNow = leading && !timeoutId;
684
+ if (timeoutId) clearTimeout(timeoutId);
685
+ timeoutId = setTimeout(() => {
686
+ timeoutId = void 0;
687
+ if (!leading) fn.apply(this, args);
688
+ }, wait2);
689
+ if (callNow) fn.apply(this, args);
690
+ };
691
+ debounced.cancel = () => {
692
+ if (timeoutId) {
693
+ clearTimeout(timeoutId);
694
+ timeoutId = void 0;
695
+ }
696
+ };
697
+ return debounced;
698
+ }
699
+ function throttle(fn, limit) {
700
+ let inThrottle = false;
701
+ return function(...args) {
702
+ if (!inThrottle) {
703
+ fn.apply(this, args);
704
+ inThrottle = true;
705
+ setTimeout(() => inThrottle = false, limit);
706
+ }
707
+ };
708
+ }
709
+
710
+ // src/fn.ts
711
+ function memoize(fn, options = {}) {
712
+ const cache = /* @__PURE__ */ new Map();
713
+ const { resolver, maxAge } = options;
714
+ const memoized = function(...args) {
715
+ const key = resolver ? resolver(...args) : JSON.stringify(args);
716
+ const now = Date.now();
717
+ const entry = cache.get(key);
718
+ if (entry) {
719
+ if (!maxAge || now - entry.timestamp < maxAge) {
720
+ return entry.value;
721
+ }
722
+ cache.delete(key);
723
+ }
724
+ const result = fn.apply(this, args);
725
+ cache.set(key, { value: result, timestamp: now });
726
+ return result;
727
+ };
728
+ memoized.clear = () => cache.clear();
729
+ return memoized;
730
+ }
731
+
555
732
  // 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 = {}) {
733
+ function formatCurrency(num, options = {}) {
565
734
  return new Intl.NumberFormat(options.locale, {
566
735
  style: "currency",
567
736
  currency: options.currency
568
737
  }).format(num);
569
738
  }
570
- function number(num, options = {}) {
739
+ function formatNumber(num, options = {}) {
571
740
  return new Intl.NumberFormat(options.locale, {
572
741
  minimumFractionDigits: options.precision,
573
742
  maximumFractionDigits: options.precision
574
743
  }).format(num);
575
744
  }
576
- function memory(bytes, decimals = 1, units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]) {
745
+ function formatMemory(bytes, decimals = 1, units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]) {
577
746
  if (bytes <= 0) return `0 ${units[0]}`;
578
747
  const i = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
579
748
  const val = bytes / Math.pow(1024, i);
580
749
  return `${val.toFixed(i === 0 ? 0 : decimals)} ${units[i]}`;
581
750
  }
582
- function ordinal(num, locale) {
751
+ function formatOrdinal(num, locale) {
583
752
  const _num = Number(num);
584
753
  if (isNaN(_num)) throw new TypeError("Invalid input");
585
754
  const pr = new Intl.PluralRules(locale, { type: "ordinal" });
@@ -593,35 +762,77 @@ function ordinal(num, locale) {
593
762
  const suffix = suffixes[rule] || "th";
594
763
  return _num.toLocaleString(locale) + suffix;
595
764
  }
596
- function compactNumber(num, locale) {
765
+ function FormatNumberCompact(num, locale) {
597
766
  return new Intl.NumberFormat(locale, {
598
767
  notation: "compact",
599
768
  compactDisplay: "short",
600
769
  maximumFractionDigits: 1
601
770
  }).format(num);
602
771
  }
772
+ function formatDuration(target, style = "hms", options = {}) {
773
+ const targetMs = target instanceof Date ? target.getTime() : Number(target);
774
+ const sinceMs = options.since instanceof Date ? options.since.getTime() : Number(options.since) || Date.now();
775
+ const diff = Math.abs(targetMs - sinceMs);
776
+ if (diff === 0) return style === "digital" ? "00:00" : "now";
777
+ const s = Math.floor(diff / 1e3) % 60;
778
+ const m = Math.floor(diff / 6e4) % 60;
779
+ const h = Math.floor(diff / 36e5) % 24;
780
+ const d = Math.floor(diff / 864e5);
781
+ if (style === "digital") {
782
+ const parts = [m, s].map((v) => String(v).padStart(2, "0"));
783
+ if (h > 0 || d > 0) parts.unshift(String(h).padStart(2, "0"));
784
+ if (d > 0) parts.unshift(String(d));
785
+ return parts.join(":");
786
+ }
787
+ const result = [];
788
+ const push = (val, label) => {
789
+ if (val > 0) result.push(`${val} ${label}${val === 1 ? "" : "s"}`);
790
+ };
791
+ if (style === "ymdhms") push(d, "day");
792
+ push(h, "hour");
793
+ push(m, "minute");
794
+ push(s, "second");
795
+ if (result.length === 0) return "0 seconds";
796
+ if (result.length === 1) return result[0];
797
+ const last = result.pop();
798
+ return `${result.join(", ")} and ${last}`;
799
+ }
800
+ function formatETA(date, locale) {
801
+ const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
802
+ const elapsed = (typeof date === "number" ? date : date.getTime()) - Date.now();
803
+ const units = [
804
+ { unit: "year", ms: 31536e6 },
805
+ { unit: "month", ms: 2628e6 },
806
+ { unit: "day", ms: 864e5 },
807
+ { unit: "hour", ms: 36e5 },
808
+ { unit: "minute", ms: 6e4 },
809
+ { unit: "second", ms: 1e3 }
810
+ ];
811
+ for (const { unit, ms } of units) {
812
+ if (Math.abs(elapsed) >= ms || unit === "second") {
813
+ return rtf.format(Math.round(elapsed / ms), unit);
814
+ }
815
+ }
816
+ return "";
817
+ }
603
818
 
604
819
  // src/fs.ts
605
- var fs_exports = {};
606
- __export(fs_exports, {
607
- readDir: () => readDir
608
- });
609
- var import_node_fs = __toESM(require("fs"), 1);
610
- var import_node_path = require("path");
820
+ var import_node_fs2 = __toESM(require("fs"), 1);
821
+ var import_node_path2 = require("path");
611
822
  function readDir(path2, options = {}) {
612
823
  const { recursive = true } = options;
613
- if (!import_node_fs.default.existsSync(path2)) return [];
824
+ if (!import_node_fs2.default.existsSync(path2)) return [];
614
825
  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();
826
+ return import_node_fs2.default.readdirSync(path2).filter((fn) => {
827
+ return import_node_fs2.default.statSync((0, import_node_path2.join)(path2, fn)).isFile();
617
828
  });
618
829
  }
619
830
  const walk = (dir, base = "") => {
620
831
  const results = [];
621
- const entries = import_node_fs.default.readdirSync(dir, { withFileTypes: true });
832
+ const entries = import_node_fs2.default.readdirSync(dir, { withFileTypes: true });
622
833
  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);
834
+ const relativePath = base ? (0, import_node_path2.join)(base, entry.name) : entry.name;
835
+ const fullPath = (0, import_node_path2.join)(dir, entry.name);
625
836
  if (entry.isDirectory()) {
626
837
  results.push(...walk(fullPath, relativePath));
627
838
  } else if (entry.isFile()) {
@@ -634,77 +845,58 @@ function readDir(path2, options = {}) {
634
845
  }
635
846
 
636
847
  // 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) {
848
+ function isDefined(val) {
648
849
  return val !== void 0 && val !== null;
649
850
  }
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;
851
+ function isEmpty(val) {
852
+ if (!isDefined(val)) return true;
853
+ if (isString(val) || Array.isArray(val)) return val.length === 0;
854
+ if (isObject(val)) return Object.keys(val).length === 0;
654
855
  return false;
655
856
  }
656
- function inRange(num, a, b) {
857
+ function isObject(val) {
858
+ return val !== null && typeof val === "object" && !Array.isArray(val);
859
+ }
860
+ function isString(val) {
861
+ return typeof val === "string";
862
+ }
863
+ function isInRange(num, a, b) {
657
864
  let min = b !== void 0 ? a : 0;
658
865
  let max = b !== void 0 ? b : a;
659
866
  if (min > max) [min, max] = [max, min];
660
867
  return num >= min && num <= max;
661
868
  }
662
- function object(val) {
663
- return val !== null && typeof val === "object" && !Array.isArray(val);
664
- }
665
- function sorted(arr, comparator) {
869
+ function isSortedArray(arr, comparator) {
666
870
  for (let i = 0; i < arr.length - 1; i++) {
667
871
  const comp = comparator ? comparator(arr[i], arr[i + 1]) : arr[i] > arr[i + 1] ? 1 : -1;
668
872
  if (comp > 0) return false;
669
873
  }
670
874
  return true;
671
875
  }
672
- function string(val) {
673
- return typeof val === "string";
674
- }
675
- function today(date) {
876
+ function isToday(date) {
676
877
  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();
878
+ const today = /* @__PURE__ */ new Date();
879
+ return d.getDate() === today.getDate() && d.getMonth() === today.getMonth() && d.getFullYear() === today.getFullYear();
679
880
  }
680
881
 
681
882
  // 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) {
883
+ function clampNumber(num, a, b) {
695
884
  let min = b !== void 0 ? a : 0;
696
885
  let max = b !== void 0 ? b : a;
697
886
  if (min > max) [min, max] = [max, min];
698
887
  return Math.max(min, Math.min(num, max));
699
888
  }
700
- function invLerp(start, end, value) {
889
+ function lerp(start, end, t) {
890
+ return start + (end - start) * t;
891
+ }
892
+ function inverseLerp(start, end, value) {
701
893
  if (start === end) return 0;
702
894
  return (value - start) / (end - start);
703
895
  }
704
- function lerp(start, end, t) {
705
- return start + (end - start) * t;
896
+ function msToSecs(num) {
897
+ return Math.floor(num / 1e3);
706
898
  }
707
- function ms(num) {
899
+ function secsToMs(num) {
708
900
  return Math.floor(num * 1e3);
709
901
  }
710
902
  function percent(a, b, round = true) {
@@ -712,36 +904,19 @@ function percent(a, b, round = true) {
712
904
  return round ? Math.floor(result) : result;
713
905
  }
714
906
  function remap(value, inMin, inMax, outMin, outMax) {
715
- const t = invLerp(inMin, inMax, value);
907
+ const t = inverseLerp(inMin, inMax, value);
716
908
  return lerp(outMin, outMax, t);
717
909
  }
718
- function secs(num) {
719
- return Math.floor(num / 1e3);
720
- }
721
910
  function sum(array, selector) {
722
911
  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);
912
+ return _array.reduce((a, b) => b < 0 ? a - -b : a + (b || 0), 0);
729
913
  }
730
914
  function wrap(num, max) {
731
915
  return (num % max + max) % max;
732
916
  }
733
917
 
734
918
  // 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) {
919
+ function getProp(obj, path2, defaultValue) {
745
920
  if (!obj) throw new Error("get: Target object is null or undefined");
746
921
  const parts = path2.replace(/\[(\d+)\]/g, ".$1").split(".");
747
922
  let current = obj;
@@ -760,7 +935,7 @@ function get(obj, path2, defaultValue) {
760
935
  }
761
936
  return current;
762
937
  }
763
- function has(obj, path2) {
938
+ function hasProp(obj, path2) {
764
939
  if (!obj || !path2) return false;
765
940
  const parts = path2.replace(/\[(\d+)\]/g, ".$1").split(".");
766
941
  let current = obj;
@@ -776,7 +951,7 @@ function has(obj, path2) {
776
951
  }
777
952
  return true;
778
953
  }
779
- function set(obj, path2, value) {
954
+ function setProp(obj, path2, value) {
780
955
  const parts = path2.replace(/\[(\d+)\]/g, ".$1").split(".");
781
956
  let current = obj;
782
957
  for (let i = 0; i < parts.length; i++) {
@@ -828,36 +1003,32 @@ function omit(obj, keys) {
828
1003
  }
829
1004
 
830
1005
  // 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, "\\$&");
1006
+ function escapeRegex(str) {
1007
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
840
1008
  }
841
- function getFlag(str2, flag, length) {
1009
+ function getFlag(str, flag, length) {
842
1010
  const regex = flag instanceof RegExp ? flag : new RegExp(`${escapeRegex(flag)}\\b`, "g");
843
- const match = regex.exec(str2);
1011
+ const match = regex.exec(str);
844
1012
  if (!match) return null;
845
1013
  const startIndex = match.index + match[0].length;
846
- let result = str2.slice(startIndex).trimStart();
1014
+ let result = str.slice(startIndex).trimStart();
847
1015
  if (length !== void 0) {
848
1016
  return result.split(/\s+/).slice(0, length).join(" ");
849
1017
  }
850
1018
  return result || null;
851
1019
  }
852
- function hasFlag(str2, flag) {
853
- if (flag instanceof RegExp) return flag.test(str2);
1020
+ function hasFlag(str, flag) {
1021
+ if (flag instanceof RegExp) return flag.test(str);
854
1022
  const pattern = new RegExp(`${escapeRegex(flag)}\\b`);
855
- return pattern.test(str2);
1023
+ return pattern.test(str);
856
1024
  }
857
- function toTitleCase(str2, smart = true) {
1025
+ function pluralize(count, singular, plural = `${singular}s`) {
1026
+ return count === 1 ? singular : plural;
1027
+ }
1028
+ function toTitleCase(str, smart = true) {
858
1029
  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)) {
1030
+ return str.replace(/\w\S*/g, (txt, index) => {
1031
+ if (smart && index !== 0 && minorWords.test(txt)) {
861
1032
  return txt.toLowerCase();
862
1033
  }
863
1034
  if (smart && txt.length > 1 && txt === txt.toUpperCase()) {
@@ -866,391 +1037,71 @@ function toTitleCase(str2, smart = true) {
866
1037
  return txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase();
867
1038
  });
868
1039
  }
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"), 1);
936
- var import_node_path2 = __toESM(require("path"), 1);
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"), 1);
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
1040
  // Annotate the CommonJS export names for ESM import in node:
1189
1041
  0 && (module.exports = {
1190
- $,
1191
1042
  Cache,
1043
+ FormatNumberCompact,
1192
1044
  Loop,
1193
1045
  Pipe,
1194
1046
  Storage,
1195
- chance,
1196
- choice,
1197
1047
  chunk,
1198
1048
  chunkAdj,
1199
- clamp,
1049
+ clampNumber,
1200
1050
  cluster,
1201
- compact,
1202
- compactNumber,
1203
- currency,
1051
+ compactArray,
1052
+ createSampler,
1204
1053
  debounce,
1205
- defined,
1206
- duration,
1207
- empty,
1208
1054
  escapeRegex,
1209
- eta,
1210
- float,
1211
1055
  forceArray,
1212
- get,
1056
+ formatCurrency,
1057
+ formatDuration,
1058
+ formatETA,
1059
+ formatMemory,
1060
+ formatNumber,
1061
+ formatOrdinal,
1213
1062
  getAge,
1214
1063
  getFlag,
1215
- has,
1064
+ getProp,
1216
1065
  hasFlag,
1217
- inRange,
1218
- index,
1219
- int,
1220
- invLerp,
1066
+ hasProp,
1067
+ inverseLerp,
1068
+ isDefined,
1069
+ isEmpty,
1070
+ isInRange,
1071
+ isObject,
1072
+ isSortedArray,
1073
+ isString,
1074
+ isToday,
1221
1075
  lerp,
1222
1076
  memoize,
1223
- memory,
1224
1077
  merge,
1225
- ms,
1226
- number,
1227
- object,
1078
+ msToSecs,
1228
1079
  omit,
1229
- ordinal,
1230
- parse,
1080
+ parseTime,
1231
1081
  percent,
1232
1082
  pick,
1083
+ pluralize,
1233
1084
  prng,
1234
1085
  readDir,
1235
- record,
1236
1086
  remap,
1237
- retry,
1238
- sampler,
1239
- search,
1240
- secs,
1087
+ retryPromise,
1088
+ rndChance,
1089
+ rndChoice,
1090
+ rndFloat,
1091
+ rndIndex,
1092
+ rndInt,
1093
+ rndString,
1094
+ searchSorted,
1095
+ secsToMs,
1241
1096
  seqMap,
1242
- set,
1097
+ setProp,
1243
1098
  shuffle,
1244
1099
  sortBy,
1245
- sorted,
1246
- str,
1247
- string,
1248
1100
  sum,
1249
1101
  throttle,
1250
1102
  toTitleCase,
1251
- today,
1252
1103
  unique,
1253
1104
  wait,
1254
- weighted,
1105
+ weightedRnd,
1255
1106
  wrap
1256
1107
  });