@andrew_l/toolkit 0.0.1 → 0.0.2

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.mjs CHANGED
@@ -4,7 +4,6 @@ import _cloneDeepWith from 'lodash/cloneDeepWith';
4
4
  import _defaultsDeep from 'lodash/defaultsDeep';
5
5
  import _set from 'lodash/set';
6
6
  import _unset from 'lodash/unset';
7
- import { isWeakSet as isWeakSet$1, isWeakMap as isWeakMap$1 } from 'lodash';
8
7
 
9
8
  const isClient = typeof globalThis?.window !== "undefined";
10
9
  const isDef = (val) => typeof val !== "undefined";
@@ -16,8 +15,21 @@ const isBigInt = (val) => typeof val === "bigint";
16
15
  const isBoolean = (val) => typeof val === "boolean";
17
16
  const isFunction = (val) => typeof val === "function";
18
17
  const isNumber = (val) => typeof val === "number" && !isNaN(val);
18
+ const isInfinity = (val) => val === Infinity || val === -Infinity;
19
19
  const isString = (val) => typeof val === "string";
20
20
  const isObject = (val) => toString.call(val) === "[object Object]";
21
+ const isPlainObject = (val) => {
22
+ let ctor, prot;
23
+ if (!isObject(val)) return false;
24
+ ctor = val.constructor;
25
+ if (ctor === void 0) return true;
26
+ prot = ctor.prototype;
27
+ if (isObject(prot) === false) return false;
28
+ if (prot.hasOwnProperty("isPrototypeOf") === false) {
29
+ return false;
30
+ }
31
+ return true;
32
+ };
21
33
  const isDate = (val) => val instanceof Date && !isNaN(val);
22
34
  const noop = () => {
23
35
  };
@@ -32,28 +44,89 @@ function isEqual(a, b) {
32
44
  if (Object.is(a, b)) {
33
45
  return true;
34
46
  }
35
- if (a instanceof Date && b instanceof Date) {
47
+ if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) {
48
+ return false;
49
+ }
50
+ if (a.constructor !== b.constructor) {
51
+ return false;
52
+ }
53
+ if (Array.isArray(a)) {
54
+ const { length } = a;
55
+ if (length !== b.length) {
56
+ return false;
57
+ }
58
+ for (let i = length; i-- !== 0; ) {
59
+ if (!isEqual(a[i], b[i])) {
60
+ return false;
61
+ }
62
+ }
63
+ return true;
64
+ }
65
+ if (a instanceof Date) {
36
66
  return a.getTime() === b.getTime();
37
67
  }
38
- if (a instanceof RegExp && b instanceof RegExp) {
68
+ if (a instanceof RegExp) {
39
69
  return a.source === b.source && a.flags === b.flags;
40
70
  }
41
- if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) {
42
- return false;
71
+ if (a instanceof Set) {
72
+ if (a.size !== b.size) {
73
+ return false;
74
+ }
75
+ for (const value of a) {
76
+ if (!b.has(value)) {
77
+ return false;
78
+ }
79
+ }
80
+ return true;
81
+ }
82
+ if (a instanceof Map) {
83
+ if (a.size !== b.size) {
84
+ return false;
85
+ }
86
+ for (const entry of a) {
87
+ if (!b.has(entry[0]) || !isEqual(entry[1], b.get(entry[0]))) {
88
+ return false;
89
+ }
90
+ }
91
+ return true;
92
+ }
93
+ if (a instanceof DataView) {
94
+ const { byteLength } = a;
95
+ if (byteLength !== b.byteLength) {
96
+ return false;
97
+ }
98
+ for (let i = byteLength; i-- !== 0; ) {
99
+ if (a.getUint8(i) !== b.getUint8(i)) {
100
+ return false;
101
+ }
102
+ }
103
+ return true;
104
+ }
105
+ if (a instanceof ArrayBuffer && b instanceof ArrayBuffer) {
106
+ a = new Uint8Array(a);
107
+ b = new Uint8Array(b);
108
+ }
109
+ if (ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
110
+ const { length } = a;
111
+ if (length !== b.length) {
112
+ return false;
113
+ }
114
+ for (let i = length; i-- !== 0; ) {
115
+ if (a[i] !== b[i]) {
116
+ return false;
117
+ }
118
+ }
119
+ return true;
43
120
  }
44
121
  const aKeys = Object.keys(a);
45
122
  const bKeys = Object.keys(b);
46
123
  if (aKeys.length !== bKeys.length) {
47
124
  return false;
48
125
  }
49
- if (Array.from(new Set(aKeys.concat(bKeys))).length !== aKeys.length) {
50
- return false;
51
- }
52
- for (let i = 0; i < aKeys.length; i++) {
53
- const propKey = aKeys[i];
54
- const aProp = a[propKey];
55
- const bProp = b[propKey];
56
- if (!isEqual(aProp, bProp)) {
126
+ let key;
127
+ for (let i = aKeys.length; i-- !== 0; ) {
128
+ key = aKeys[i];
129
+ if (!Object.hasOwn(b, key) || !isEqual(a[key], b[key])) {
57
130
  return false;
58
131
  }
59
132
  }
@@ -144,6 +217,35 @@ function chunkSeries(list, step = 1) {
144
217
  return result;
145
218
  }
146
219
 
220
+ function difference(...arrays) {
221
+ if (arrays.length === 0) return [];
222
+ if (arrays.length === 1) return [...arrays[0]];
223
+ const [first, ...rest] = arrays;
224
+ const blacklist = /* @__PURE__ */ new Set();
225
+ const set = new Set(first);
226
+ for (const items of rest) {
227
+ for (const item of items) {
228
+ if (blacklist.has(item)) continue;
229
+ if (set.has(item)) {
230
+ set.delete(item);
231
+ blacklist.add(item);
232
+ continue;
233
+ }
234
+ set.add(item);
235
+ }
236
+ }
237
+ return Array.from(set);
238
+ }
239
+
240
+ function intersection(...arrays) {
241
+ if (arrays.length === 0) return [];
242
+ if (arrays.length === 1) return arrays[0];
243
+ return arrays.reduce((acc, curr) => {
244
+ const set = new Set(curr);
245
+ return acc.filter((item) => set.has(item));
246
+ });
247
+ }
248
+
147
249
  function keyBy(array, keyBy2, objectMode) {
148
250
  const getItemKey = isFunction(keyBy2) ? keyBy2 : (item) => item?.[keyBy2];
149
251
  if (objectMode === true) {
@@ -194,6 +296,15 @@ function orderBy(array, fields, orders) {
194
296
  });
195
297
  }
196
298
 
299
+ function shuffle(arr) {
300
+ const result = arr.slice();
301
+ for (let i = result.length - 1; i >= 1; i--) {
302
+ const j = Math.floor(Math.random() * (i + 1));
303
+ [result[i], result[j]] = [result[j], result[i]];
304
+ }
305
+ return result;
306
+ }
307
+
197
308
  const sum = (values) => {
198
309
  return values.reduce((a, b) => a + (isNumber(b) ? b : 0), 0);
199
310
  };
@@ -205,8 +316,11 @@ function uniq(value) {
205
316
  return [...new Set(value)];
206
317
  }
207
318
 
208
- function union(arr1, arr2) {
209
- return uniq(arr1.concat(arr2));
319
+ function union(...arrays) {
320
+ if (arrays.length === 0) return [];
321
+ if (arrays.length === 1) return [...arrays[0]];
322
+ const [first, ...rest] = arrays;
323
+ return uniq(first.concat(...rest));
210
324
  }
211
325
 
212
326
  const get = _get;
@@ -325,6 +439,202 @@ const assert = {
325
439
  string: string
326
440
  };
327
441
 
442
+ class Base64Encoding {
443
+ alphabet;
444
+ padding;
445
+ decodeMap = /* @__PURE__ */ new Map();
446
+ constructor(alphabet, options) {
447
+ if (alphabet.length !== 64) {
448
+ throw new Error("Invalid alphabet");
449
+ }
450
+ this.alphabet = alphabet;
451
+ this.padding = options?.padding ?? "=";
452
+ if (this.alphabet.includes(this.padding) || this.padding.length !== 1) {
453
+ throw new Error("Invalid padding");
454
+ }
455
+ for (let i = 0; i < alphabet.length; i++) {
456
+ this.decodeMap.set(alphabet[i], i);
457
+ }
458
+ }
459
+ encode(data, options) {
460
+ let result = "";
461
+ let buffer = 0;
462
+ let shift = 0;
463
+ for (let i = 0; i < data.length; i++) {
464
+ buffer = buffer << 8 | data[i];
465
+ shift += 8;
466
+ while (shift >= 6) {
467
+ shift += -6;
468
+ result += this.alphabet[buffer >> shift & 63];
469
+ }
470
+ }
471
+ if (shift > 0) {
472
+ result += this.alphabet[buffer << 6 - shift & 63];
473
+ }
474
+ const includePadding = options?.includePadding ?? true;
475
+ if (includePadding) {
476
+ const padCount = (4 - result.length % 4) % 4;
477
+ for (let i = 0; i < padCount; i++) {
478
+ result += "=";
479
+ }
480
+ }
481
+ return result;
482
+ }
483
+ decode(data, options) {
484
+ const strict = options?.strict ?? true;
485
+ const chunkCount = Math.ceil(data.length / 4);
486
+ const result = [];
487
+ for (let i = 0; i < chunkCount; i++) {
488
+ let padCount = 0;
489
+ let buffer = 0;
490
+ for (let j = 0; j < 4; j++) {
491
+ const encoded = data[i * 4 + j];
492
+ if (encoded === "=") {
493
+ if (i + 1 !== chunkCount) {
494
+ throw new Error(`Invalid character: ${encoded}`);
495
+ }
496
+ padCount += 1;
497
+ continue;
498
+ }
499
+ if (encoded === void 0) {
500
+ if (strict) {
501
+ throw new Error("Invalid data");
502
+ }
503
+ padCount += 1;
504
+ continue;
505
+ }
506
+ const value = this.decodeMap.get(encoded) ?? null;
507
+ if (value === null) {
508
+ throw new Error(`Invalid character: ${encoded}`);
509
+ }
510
+ buffer += value << 6 * (3 - j);
511
+ }
512
+ result.push(buffer >> 16 & 255);
513
+ if (padCount < 2) {
514
+ result.push(buffer >> 8 & 255);
515
+ }
516
+ if (padCount < 1) {
517
+ result.push(buffer & 255);
518
+ }
519
+ }
520
+ return Uint8Array.from(result);
521
+ }
522
+ }
523
+
524
+ const base64 = new Base64Encoding(
525
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
526
+ );
527
+ const base64url = new Base64Encoding(
528
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
529
+ );
530
+
531
+ function base64ToBytes(data, { encoding = "base64", strict } = {}) {
532
+ if (encoding === "base64") {
533
+ return base64.decode(data, { strict: strict ?? true });
534
+ } else if (encoding === "base64url") {
535
+ return base64url.decode(data, { strict: strict ?? false });
536
+ }
537
+ ok(false, "Invalid encoding options: " + encoding);
538
+ }
539
+
540
+ function bigIntBytes(value) {
541
+ if (value < 0n) {
542
+ value = value * -1n;
543
+ }
544
+ let byteLength = 1;
545
+ while (value > 2n ** BigInt(byteLength * 8) - 1n) {
546
+ byteLength++;
547
+ }
548
+ const encoded = new Uint8Array(byteLength);
549
+ for (let i = 0; i < encoded.byteLength; i++) {
550
+ encoded[i] = Number(
551
+ value >> BigInt((encoded.byteLength - i - 1) * 8) & 0xffn
552
+ );
553
+ }
554
+ return encoded;
555
+ }
556
+
557
+ function bigIntFromBytes(bytes) {
558
+ ok(bytes.byteLength > 0, "Empty Uint8Array");
559
+ let decoded = 0n;
560
+ for (let i = 0; i < bytes.byteLength; i++) {
561
+ decoded += BigInt(bytes[i]) << BigInt((bytes.byteLength - 1 - i) * 8);
562
+ }
563
+ return decoded;
564
+ }
565
+
566
+ function bytesToBase64(data, { encoding = "base64", padding } = {}) {
567
+ if (encoding === "base64") {
568
+ return base64.encode(data, { includePadding: padding ?? true });
569
+ } else if (encoding === "base64url") {
570
+ return base64url.encode(data, { includePadding: padding ?? false });
571
+ }
572
+ ok(false, "Invalid encoding options: " + encoding);
573
+ }
574
+
575
+ function compareBytes(a, b) {
576
+ if (a.byteLength !== b.byteLength) {
577
+ return false;
578
+ }
579
+ for (let i = 0; i < b.byteLength; i++) {
580
+ if (a[i] !== b[i]) {
581
+ return false;
582
+ }
583
+ }
584
+ return true;
585
+ }
586
+
587
+ function concatenateBytes(a, b) {
588
+ const result = new Uint8Array(a.byteLength + b.byteLength);
589
+ result.set(a);
590
+ result.set(b, a.byteLength);
591
+ return result;
592
+ }
593
+
594
+ function uint16ToUint8(value) {
595
+ const uint8Array = new Uint8Array(value.length * 2);
596
+ for (let i = 0; i < value.length; i++) {
597
+ uint8Array[i * 2] = value[i] & 255;
598
+ uint8Array[i * 2 + 1] = value[i] >> 8;
599
+ }
600
+ return uint8Array;
601
+ }
602
+
603
+ function uint32ToUint8(value) {
604
+ const uint8Array = new Uint8Array(value.length * 4);
605
+ for (let i = 0; i < value.length; i++) {
606
+ uint8Array[i * 4] = value[i] & 255;
607
+ uint8Array[i * 4 + 1] = value[i] >> 8 & 255;
608
+ uint8Array[i * 4 + 2] = value[i] >> 16 & 255;
609
+ uint8Array[i * 4 + 3] = value[i] >> 24 & 255;
610
+ }
611
+ return uint8Array;
612
+ }
613
+
614
+ function uint8ToUint16(value) {
615
+ ok(
616
+ value.length % 2 === 0,
617
+ "Uint8Array length must be even for conversion to Uint16Array"
618
+ );
619
+ const uint16Array = new Uint16Array(value.length / 2);
620
+ for (let i = 0; i < uint16Array.length; i++) {
621
+ uint16Array[i] = value[i * 2] << 8 | value[i * 2 + 1];
622
+ }
623
+ return uint16Array;
624
+ }
625
+
626
+ function uint8ToUint32(value) {
627
+ ok(
628
+ value.length % 4 === 0,
629
+ "Uint8Array length must be a multiple of 4 for conversion to Uint32Array"
630
+ );
631
+ const uint32Array = new Uint32Array(value.length / 4);
632
+ for (let i = 0; i < uint32Array.length; i++) {
633
+ uint32Array[i] = value[i * 4] << 24 | value[i * 4 + 1] << 16 | value[i * 4 + 2] << 8 | value[i * 4 + 3];
634
+ }
635
+ return uint32Array;
636
+ }
637
+
328
638
  const def = (obj, key, value, writable = false) => {
329
639
  Object.defineProperty(obj, key, {
330
640
  configurable: true,
@@ -1728,18 +2038,6 @@ function percentOf(value, percent, digits) {
1728
2038
  return result;
1729
2039
  }
1730
2040
 
1731
- function timestamp(fromValue = Date.now()) {
1732
- if (isDate(fromValue)) {
1733
- fromValue = fromValue.getTime();
1734
- }
1735
- return Math.floor(fromValue / 1e3);
1736
- }
1737
-
1738
- function timestampToDate(value) {
1739
- if (!isNumber(value)) return null;
1740
- return new Date(value * 1e3);
1741
- }
1742
-
1743
2041
  const rgb3Numbers = new RegExp(
1744
2042
  `^
1745
2043
  rgba?\\(
@@ -2043,6 +2341,664 @@ function crc32(str, seed = 0) {
2043
2341
  return ~C;
2044
2342
  }
2045
2343
 
2344
+ function isDateObject(value) {
2345
+ return has(value, ["year", "month", "date"]) && isNumber(value.year) && isNumber(value.month) && isNumber(value.date);
2346
+ }
2347
+
2348
+ function createDateObject(value, returnsNullWhenInvalid = false) {
2349
+ let result = null;
2350
+ let inputValue = value;
2351
+ if (isNumber(inputValue) || isString(inputValue)) {
2352
+ inputValue = new Date(inputValue);
2353
+ }
2354
+ if (isDate(inputValue)) {
2355
+ result = {
2356
+ year: inputValue.getFullYear(),
2357
+ month: inputValue.getMonth() + 1,
2358
+ date: inputValue.getDate()
2359
+ };
2360
+ } else if (isDateObject(inputValue)) {
2361
+ result = { ...inputValue };
2362
+ }
2363
+ ok(
2364
+ returnsNullWhenInvalid || !!result,
2365
+ `Failed to date parse: ${value}.`
2366
+ );
2367
+ return result;
2368
+ }
2369
+
2370
+ function isTimeObject(value) {
2371
+ return isPlainObject(value) && "h" in value && "m" in value && isNumber(value.h) && Number.isInteger(value.h) && isNumber(value.m) && Number.isInteger(value.m) && value.h >= 0 && value.h < 24 && value.m >= 0 && value.m < 60;
2372
+ }
2373
+
2374
+ function createTimeObject(value, returnsNullWhenInvalid = false) {
2375
+ let result = null;
2376
+ let inputValue = value;
2377
+ if (isNumber(inputValue)) {
2378
+ inputValue = new Date(inputValue);
2379
+ } else if (isString(inputValue)) {
2380
+ const [h, m] = inputValue.split(":").map((v) => v.trim().padStart(2, "0")).map((v) => parseInt(v));
2381
+ inputValue = { h, m };
2382
+ }
2383
+ if (isDate(inputValue)) {
2384
+ result = {
2385
+ h: inputValue.getHours(),
2386
+ m: inputValue.getMinutes()
2387
+ };
2388
+ } else if (isTimeObject(inputValue)) {
2389
+ result = { ...inputValue };
2390
+ }
2391
+ ok(
2392
+ returnsNullWhenInvalid || !!result,
2393
+ `Failed to time parse: ${value}.`
2394
+ );
2395
+ return result;
2396
+ }
2397
+
2398
+ const UNIT_TO_MS = {
2399
+ ms: 1,
2400
+ s: 1e3,
2401
+ m: 1e3 * 60,
2402
+ h: 1e3 * 60 * 60,
2403
+ d: 1e3 * 60 * 60 * 24,
2404
+ w: 1e3 * 60 * 60 * 24 * 7
2405
+ };
2406
+ class TimeSpan {
2407
+ constructor(value, unit) {
2408
+ this.value = value;
2409
+ this.unit = unit;
2410
+ }
2411
+ /**
2412
+ * The numeric value of the time span
2413
+ */
2414
+ value;
2415
+ /**
2416
+ * The unit of the time span.
2417
+ */
2418
+ unit;
2419
+ /**
2420
+ * Converts the time span to milliseconds.
2421
+ *
2422
+ * @returns {number} The equivalent time span in milliseconds.
2423
+ * @example
2424
+ * const ts = new TimeSpan(2, 'h');
2425
+ * ts.milliseconds(); // Returns 7200000
2426
+ */
2427
+ milliseconds() {
2428
+ const multiplier = UNIT_TO_MS[this.unit];
2429
+ return this.value * multiplier;
2430
+ }
2431
+ /**
2432
+ * Converts the time span to seconds.
2433
+ *
2434
+ * @returns {number} The equivalent time span in seconds.
2435
+ * @example
2436
+ * const ts = new TimeSpan(2, 'm');
2437
+ * ts.seconds(); // Returns 120
2438
+ */
2439
+ seconds() {
2440
+ return this.milliseconds() / UNIT_TO_MS.s;
2441
+ }
2442
+ /**
2443
+ * Converts the time span to minutes.
2444
+ *
2445
+ * @returns {number} The equivalent time span in minutes.
2446
+ * @example
2447
+ * const ts = new TimeSpan(120, 's');
2448
+ * ts.minutes(); // Returns 2
2449
+ */
2450
+ minutes() {
2451
+ return this.milliseconds() / UNIT_TO_MS.m;
2452
+ }
2453
+ /**
2454
+ * Converts the time span to hours.
2455
+ *
2456
+ * @returns {number} The equivalent time span in hours.
2457
+ * @example
2458
+ * const ts = new TimeSpan(120, 'm');
2459
+ * ts.hours(); // Returns 2
2460
+ */
2461
+ hours() {
2462
+ return this.milliseconds() / UNIT_TO_MS.h;
2463
+ }
2464
+ /**
2465
+ * Converts the time span to days.
2466
+ *
2467
+ * @returns {number} The equivalent time span in days.
2468
+ * @example
2469
+ * const ts = new TimeSpan(48, 'h');
2470
+ * ts.days(); // Returns 2
2471
+ */
2472
+ days() {
2473
+ return this.milliseconds() / UNIT_TO_MS.d;
2474
+ }
2475
+ /**
2476
+ * Converts the time span to weeks.
2477
+ *
2478
+ * @returns {number} The equivalent time span in weeks.
2479
+ * @example
2480
+ * const ts = new TimeSpan(14, 'd');
2481
+ * ts.weeks(); // Returns 2
2482
+ */
2483
+ weeks() {
2484
+ return this.milliseconds() / UNIT_TO_MS.w;
2485
+ }
2486
+ /**
2487
+ * Adds a specified value and unit to the current time span.
2488
+ *
2489
+ * Returns new instance.
2490
+ *
2491
+ * @param {number} value - The value to add.
2492
+ * @param {TimeSpanUnit} [unit='ms'] - The unit of the value to add (default is milliseconds).
2493
+ * @returns {TimeSpan} A new TimeSpan instance with the added value.
2494
+ * @example
2495
+ * const ts = new TimeSpan(1, 'h');
2496
+ * ts.add(30, 'm'); // Represents 1.5 hours
2497
+ */
2498
+ add(value, unit = "ms") {
2499
+ const multiplier = UNIT_TO_MS[unit];
2500
+ return new TimeSpan(this.milliseconds() + value * multiplier, "ms");
2501
+ }
2502
+ /**
2503
+ * Subtracts a specified value and unit from the current time span.
2504
+ *
2505
+ * Returns new instance.
2506
+ *
2507
+ * @param {number} value - The value to subtract.
2508
+ * @param {TimeSpanUnit} [unit='ms'] - The unit of the value to subtract (default is milliseconds).
2509
+ * @returns {TimeSpan} A new TimeSpan instance with the subtracted value.
2510
+ * @example
2511
+ * const ts = new TimeSpan(1, 'h');
2512
+ * ts.subtract(30, 'm'); // Represents 30 minutes less than 1 hour
2513
+ */
2514
+ subtract(value, unit = "ms") {
2515
+ const multiplier = UNIT_TO_MS[unit];
2516
+ return new TimeSpan(this.milliseconds() - value * multiplier, "ms");
2517
+ }
2518
+ }
2519
+
2520
+ function createTimeSpan(value, unit = "ms") {
2521
+ return new TimeSpan(value, unit);
2522
+ }
2523
+
2524
+ function timestampMs(fromValue = Date.now()) {
2525
+ if (isDate(fromValue)) {
2526
+ fromValue = fromValue.getTime();
2527
+ } else if (isString(fromValue)) {
2528
+ const dt = new Date(fromValue);
2529
+ fromValue = isDate(dt) ? dt.getTime() : 0;
2530
+ }
2531
+ return isNumber(fromValue) ? fromValue : 0;
2532
+ }
2533
+
2534
+ function dateInDays(days, fromValue = Date.now()) {
2535
+ return new Date(timestampMs(fromValue) + days * 60 * 60 * 24 * 1e3);
2536
+ }
2537
+
2538
+ function dateInSeconds(seconds, fromValue = Date.now()) {
2539
+ return new Date(timestampMs(fromValue) + seconds * 1e3);
2540
+ }
2541
+
2542
+ function getRandomTime(startTime = { h: 0, m: 0 }, endTime = { h: 23, m: 59 }) {
2543
+ const h = getRandomInt(startTime.h, endTime.h);
2544
+ if (startTime.h === endTime.h) {
2545
+ return { h, m: getRandomInt(startTime.m, endTime.m) };
2546
+ }
2547
+ if (h === startTime.h) {
2548
+ return { h, m: getRandomInt(startTime.m, 59) };
2549
+ }
2550
+ if (h === endTime.h) {
2551
+ return { h, m: getRandomInt(0, endTime.m) };
2552
+ }
2553
+ return { h, m: getRandomInt(0, 59) };
2554
+ }
2555
+
2556
+ function hmToSeconds(hm) {
2557
+ hm = Number(hm);
2558
+ number$1(hm, "expected number value");
2559
+ const h = Math.floor(hm);
2560
+ const m = round2digits(hm - h) * 100;
2561
+ return h * 3600 + m * 60;
2562
+ }
2563
+
2564
+ function isTimeString(value) {
2565
+ if (!isString(value)) return false;
2566
+ const parts = value.split(":").map(Number);
2567
+ if (parts.length !== 2) return false;
2568
+ const [h, m] = parts;
2569
+ return h >= 0 && h < 24 && m >= 0 && m < 60;
2570
+ }
2571
+
2572
+ function isTimeValue(value) {
2573
+ return isTimeString(value) || isTimeObject(value);
2574
+ }
2575
+
2576
+ function isValidWeekDay(value) {
2577
+ return isNumber(value) && Number.isInteger(value) && value >= 1 && value <= 7;
2578
+ }
2579
+
2580
+ function secondsToHm(seconds) {
2581
+ const value = Number(seconds);
2582
+ number$1(value, "expected number value");
2583
+ const h = Math.floor(value / 3600);
2584
+ const m = Math.floor(value % 3600 / 60);
2585
+ return round2digits(h + m / 100, 2);
2586
+ }
2587
+
2588
+ function timeFromMinutes(value, returnsNullWhenInvalid = false) {
2589
+ if (!isNumber(value)) {
2590
+ ok(
2591
+ returnsNullWhenInvalid,
2592
+ "Failed to time parse from minutes: " + value
2593
+ );
2594
+ return null;
2595
+ }
2596
+ if (value === 0) {
2597
+ return { h: 0, m: 0 };
2598
+ }
2599
+ value = value % 1440;
2600
+ if (value < 0) {
2601
+ value += 1440;
2602
+ }
2603
+ const h = Math.floor(value / 60);
2604
+ const m = value % 60;
2605
+ return { h, m };
2606
+ }
2607
+
2608
+ function timestamp(fromValue = Date.now()) {
2609
+ if (isDate(fromValue)) {
2610
+ fromValue = fromValue.getTime();
2611
+ }
2612
+ return Math.floor(fromValue / 1e3);
2613
+ }
2614
+
2615
+ function timestampToDate(value) {
2616
+ if (!isNumber(value)) return null;
2617
+ return new Date(value * 1e3);
2618
+ }
2619
+
2620
+ function timeStringify(value, returnsNullWhenInvalid = false) {
2621
+ const timeObject = createTimeObject(value, true);
2622
+ if (!timeObject) {
2623
+ ok(
2624
+ returnsNullWhenInvalid,
2625
+ "Failed to stringify time from: " + JSON.stringify(value)
2626
+ );
2627
+ return null;
2628
+ }
2629
+ let { h, m } = timeObject;
2630
+ const hStr = Math.ceil(h).toString().padStart(2, "0").slice(-2);
2631
+ const mStr = Math.ceil(m).toString().padStart(2, "0").slice(-2);
2632
+ return `${hStr}:${mStr}`;
2633
+ }
2634
+
2635
+ function timeToMinutes(value) {
2636
+ const time = createTimeObject(value);
2637
+ return time.h * 60 + time.m;
2638
+ }
2639
+
2640
+ function weeksInYear(year) {
2641
+ const target = new Date(Date.UTC(year + 1, 0, 1));
2642
+ const dayNumber = target.getDay();
2643
+ return dayNumber < 4 ? 52 : 53;
2644
+ }
2645
+
2646
+ const DateType = {
2647
+ placeholder: "$date",
2648
+ encode: (value) => {
2649
+ if (value instanceof Date) {
2650
+ return value.getTime();
2651
+ }
2652
+ },
2653
+ decode(value) {
2654
+ return new Date(value);
2655
+ }
2656
+ };
2657
+ const BinaryType = {
2658
+ placeholder: "$binary",
2659
+ encode: (value) => {
2660
+ if (value instanceof Uint8Array) {
2661
+ return base64.encode(value, { includePadding: true });
2662
+ } else if (value instanceof Uint16Array) {
2663
+ return {
2664
+ value: base64.encode(uint16ToUint8(value), { includePadding: true }),
2665
+ bit: 16
2666
+ };
2667
+ } else if (value instanceof Uint32Array) {
2668
+ return {
2669
+ value: base64.encode(uint32ToUint8(value), { includePadding: true }),
2670
+ bit: 32
2671
+ };
2672
+ }
2673
+ },
2674
+ decode(value) {
2675
+ if (typeof value === "string") {
2676
+ return base64.decode(value, { strict: true });
2677
+ } else if (value.bit === 16) {
2678
+ return uint8ToUint16(base64.decode(value.value, { strict: true }));
2679
+ } else if (value.bit === 32) {
2680
+ return uint8ToUint32(base64.decode(value.value, { strict: true }));
2681
+ }
2682
+ throw new Error("Unexpected $binary bit value: " + value.bit);
2683
+ }
2684
+ };
2685
+ const BigIntType = {
2686
+ placeholder: "$bigint",
2687
+ encode: (value) => {
2688
+ if (typeof value === "bigint") {
2689
+ return base64.encode(bigIntBytes(value), { includePadding: false });
2690
+ }
2691
+ },
2692
+ decode(value) {
2693
+ return bigIntFromBytes(base64.decode(value, { strict: false }));
2694
+ }
2695
+ };
2696
+ const MapType = {
2697
+ placeholder: "$map",
2698
+ encode: (value, encode) => {
2699
+ if (value instanceof Map) {
2700
+ return encode(Array.from(value.entries()));
2701
+ }
2702
+ },
2703
+ decode(value) {
2704
+ return new Map(value);
2705
+ }
2706
+ };
2707
+ const SetType = {
2708
+ placeholder: "$set",
2709
+ encode: (value, encode) => {
2710
+ if (value instanceof Set) {
2711
+ return encode(Array.from(value.values()));
2712
+ }
2713
+ },
2714
+ decode(value) {
2715
+ return new Set(value);
2716
+ }
2717
+ };
2718
+ const RegexType = {
2719
+ placeholder: "$regex",
2720
+ encode: (value, encode) => {
2721
+ if (value instanceof RegExp) {
2722
+ const regStr = value.toString();
2723
+ const patternStart = regStr.lastIndexOf("/");
2724
+ return {
2725
+ pattern: value.toString().slice(1, patternStart),
2726
+ flags: regStr.slice(patternStart + 1)
2727
+ };
2728
+ }
2729
+ },
2730
+ decode(value) {
2731
+ return new RegExp(value.pattern, value.flags);
2732
+ }
2733
+ };
2734
+ const InfinityType = {
2735
+ placeholder: "$inf",
2736
+ encode: (value, encode) => {
2737
+ if (value === Infinity) {
2738
+ return 1;
2739
+ } else if (value === -Infinity) {
2740
+ return -1;
2741
+ }
2742
+ },
2743
+ decode(value) {
2744
+ if (value === 1) return Infinity;
2745
+ if (value === -1) return -Infinity;
2746
+ throw new Error("Unexpected $inf value: " + value);
2747
+ }
2748
+ };
2749
+
2750
+ class EJSON {
2751
+ /** @internal */
2752
+ typeHandlers = /* @__PURE__ */ new Map();
2753
+ /** @internal */
2754
+ replacerReady;
2755
+ /** @internal */
2756
+ encode;
2757
+ /** @internal */
2758
+ reviewerReady;
2759
+ /** @internal */
2760
+ pure = true;
2761
+ _vendorName = null;
2762
+ /**
2763
+ * MIME type based on the provided vendor name or defaults to 'application/json'.
2764
+ */
2765
+ mimetype = "application/json";
2766
+ Type = {
2767
+ Date: DateType,
2768
+ Map: MapType,
2769
+ Set: SetType,
2770
+ RegExp: RegexType,
2771
+ Infinity: InfinityType,
2772
+ BigInt: BigIntType,
2773
+ Binary: BinaryType
2774
+ };
2775
+ constructor() {
2776
+ this.replacerReady = this._replacer.bind(this);
2777
+ this.reviewerReady = this._reviewer.bind(this);
2778
+ this.encode = (value) => {
2779
+ return deepCloneWith(value, this.replacerReady);
2780
+ };
2781
+ }
2782
+ /**
2783
+ * The vendor name used for the custom MIME type definition.
2784
+ * If null, defaults to 'application/json'.
2785
+ */
2786
+ get vendorName() {
2787
+ return this._vendorName;
2788
+ }
2789
+ set vendorName(value) {
2790
+ this._vendorName = value;
2791
+ if (!value) {
2792
+ this.mimetype = "application/json";
2793
+ } else {
2794
+ const vendorName = value.split(" ").map((v) => v.toLowerCase()).join(".").replace(/\.\.+/g, ".").replace(/\.$/, "");
2795
+ this.mimetype = `application/vnd.${vendorName}+json`;
2796
+ }
2797
+ }
2798
+ /**
2799
+ * Adds a custom type handler for encoding/decoding logic.
2800
+ * Ensures type placeholders are unique and adhere to conventions.
2801
+ */
2802
+ addType(type) {
2803
+ ok(
2804
+ !this.typeHandlers.has(type.placeholder),
2805
+ `type with ${type.placeholder} already taken.`
2806
+ );
2807
+ ok(
2808
+ type.placeholder.startsWith("$"),
2809
+ "type placeholder must starts with $ symbol."
2810
+ );
2811
+ this.pure = false;
2812
+ this.typeHandlers.set(type.placeholder, type);
2813
+ return this;
2814
+ }
2815
+ /**
2816
+ * Stringifies a JavaScript value using custom encoding logic.
2817
+ * @param {any} value - The value to encode and stringify.
2818
+ * @param {string | number} [space] - Optional space for pretty-printing.
2819
+ * @returns {string} - The JSON stringified value.
2820
+ */
2821
+ stringify(value, space) {
2822
+ if (this.pure) {
2823
+ return JSON.stringify(value, void 0, space);
2824
+ }
2825
+ return JSON.stringify(this.encode(value), void 0, space);
2826
+ }
2827
+ /**
2828
+ * Parses a JSON string using custom decoding logic.
2829
+ * @param {string} value - The JSON string to parse.
2830
+ * @returns {any} - The decoded JavaScript object.
2831
+ */
2832
+ parse(value) {
2833
+ if (this.pure) {
2834
+ return JSON.parse(value);
2835
+ }
2836
+ return JSON.parse(value, this.reviewerReady);
2837
+ }
2838
+ /** @internal */
2839
+ _replacer(value, key) {
2840
+ if (isPlainObject(value)) return;
2841
+ if (Array.isArray(value)) return;
2842
+ if (!isInfinity(value) && !isBigInt(value)) {
2843
+ if (isPrimitive(value)) return;
2844
+ }
2845
+ for (const type of this.typeHandlers.values()) {
2846
+ const res = type.encode(value, this.encode);
2847
+ if (res !== void 0) {
2848
+ return type.encodeInline ? res : { [type.placeholder]: res };
2849
+ }
2850
+ }
2851
+ return value;
2852
+ }
2853
+ /** @internal */
2854
+ _reviewer(_, value) {
2855
+ const key = firstKey(value);
2856
+ if (!key || key[0] !== "$") return value;
2857
+ const type = this.typeHandlers.get(key);
2858
+ if (type) {
2859
+ return type.decode(value[key]);
2860
+ }
2861
+ return value;
2862
+ }
2863
+ }
2864
+ function firstKey(value) {
2865
+ if (!isObject(value)) return null;
2866
+ for (const key in value) {
2867
+ return key;
2868
+ }
2869
+ return null;
2870
+ }
2871
+
2872
+ function createEJSON(withBasicTypes = false) {
2873
+ const ejson = new EJSON();
2874
+ if (withBasicTypes) {
2875
+ ejson.addType(MapType);
2876
+ ejson.addType(SetType);
2877
+ ejson.addType(DateType);
2878
+ ejson.addType(InfinityType);
2879
+ ejson.addType(BigIntType);
2880
+ ejson.addType(BinaryType);
2881
+ ejson.addType(RegexType);
2882
+ }
2883
+ return ejson;
2884
+ }
2885
+
2886
+ class EJSONStream extends TransformStream {
2887
+ ejson;
2888
+ constructor({ ejson, cl, op, sep, onFlush, onStart }) {
2889
+ let firstChunk = true;
2890
+ super({
2891
+ async start(controller) {
2892
+ if (onStart) {
2893
+ await onStart(controller);
2894
+ }
2895
+ controller.enqueue(op);
2896
+ },
2897
+ transform(chunk, controller) {
2898
+ const jsonString = ejson.stringify(chunk);
2899
+ if (firstChunk) {
2900
+ firstChunk = false;
2901
+ } else {
2902
+ controller.enqueue(sep);
2903
+ }
2904
+ controller.enqueue(jsonString);
2905
+ },
2906
+ flush(controller) {
2907
+ controller.enqueue(cl);
2908
+ if (onFlush) {
2909
+ return onFlush(controller);
2910
+ }
2911
+ }
2912
+ });
2913
+ this.ejson = ejson;
2914
+ }
2915
+ /**
2916
+ * The vendor name used for the custom MIME type definition.
2917
+ * If null, defaults to 'application/json'.
2918
+ */
2919
+ get vendorName() {
2920
+ return this.ejson.vendorName;
2921
+ }
2922
+ /**
2923
+ * MIME type based on the provided vendor name or defaults to 'application/json'.
2924
+ */
2925
+ get mimetype() {
2926
+ return this.ejson.mimetype;
2927
+ }
2928
+ }
2929
+
2930
+ const instance = createEJSON(true);
2931
+
2932
+ function createEJSONStream(options = {}) {
2933
+ if (options.resultKey || options.append || options.prepend) {
2934
+ return createEJSONStreamPayload(options);
2935
+ }
2936
+ return new EJSONStream(getOptions(options));
2937
+ }
2938
+ function createEJSONStreamPayload(options) {
2939
+ let { cl, ejson, op, sep } = getOptions(options);
2940
+ const { append, prepend, resultKey } = options;
2941
+ notEmptyString(resultKey, "resultKey required.");
2942
+ const stream = new EJSONStream({
2943
+ ejson,
2944
+ cl,
2945
+ op,
2946
+ sep,
2947
+ async onStart(controller) {
2948
+ if (!prepend) {
2949
+ controller.enqueue(`{"${resultKey}":`);
2950
+ return;
2951
+ }
2952
+ const data = await prepend();
2953
+ if (data === null || data === void 0) {
2954
+ controller.enqueue(`{"${resultKey}":`);
2955
+ return;
2956
+ }
2957
+ ok(
2958
+ isPlainObject(data),
2959
+ "prepend result expected to be plain object"
2960
+ );
2961
+ const dataPart = instance.stringify(data).slice(0, -1);
2962
+ if (dataPart === "{") {
2963
+ controller.enqueue(`{"${resultKey}":`);
2964
+ return;
2965
+ }
2966
+ controller.enqueue(`${dataPart}${sep}"${resultKey}":`);
2967
+ },
2968
+ async onFlush(controller) {
2969
+ if (!append) {
2970
+ controller.enqueue("}");
2971
+ return;
2972
+ }
2973
+ const data = await append();
2974
+ if (data === null || data === void 0) {
2975
+ controller.enqueue("}");
2976
+ return;
2977
+ }
2978
+ ok(
2979
+ isPlainObject(data),
2980
+ "prepend result expected to be plain object"
2981
+ );
2982
+ const dataPart = instance.stringify(data).slice(1);
2983
+ if (dataPart === "}") {
2984
+ controller.enqueue(`}`);
2985
+ return;
2986
+ }
2987
+ controller.enqueue(`${sep}${dataPart}`);
2988
+ }
2989
+ });
2990
+ return stream;
2991
+ }
2992
+ function getOptions(options) {
2993
+ const { ejson = instance, cl = "]", op = "[", sep = "," } = options;
2994
+ return {
2995
+ cl,
2996
+ ejson,
2997
+ op,
2998
+ sep
2999
+ };
3000
+ }
3001
+
2046
3002
  const env = (() => {
2047
3003
  if (globalThis?.process) {
2048
3004
  return createEnvParser(process.env);
@@ -2075,7 +3031,7 @@ function createEnvParser(targetObject) {
2075
3031
  return parseDecimal(targetObject[key], dights) ?? defaultValue;
2076
3032
  },
2077
3033
  string(key, defaultValue = "") {
2078
- return targetObject[key] || defaultValue;
3034
+ return targetObject[key] ?? defaultValue;
2079
3035
  },
2080
3036
  list(key, type, defaultValue = []) {
2081
3037
  if (!(key in targetObject)) {
@@ -2772,9 +3728,9 @@ function typeOf(value) {
2772
3728
  if (value === null) return "null";
2773
3729
  if (Array.isArray(value)) return "array";
2774
3730
  if (isSet(value)) return "set";
2775
- if (isWeakSet$1(value)) return "weakset";
3731
+ if (isWeakSet(value)) return "weakset";
2776
3732
  if (isMap(value)) return "map";
2777
- if (isWeakMap$1(value)) return "weakmap";
3733
+ if (isWeakMap(value)) return "weakmap";
2778
3734
  if (isDate(value)) return "date";
2779
3735
  if (isObject(value)) return "object";
2780
3736
  return "unknown";
@@ -2984,10 +3940,11 @@ function parseValue(value, asType) {
2984
3940
  return void 0;
2985
3941
  }
2986
3942
 
3943
+ const noopShouldRetryBasedOnError = () => true;
2987
3944
  function retryOnError({
2988
3945
  beforeRetryCallback,
3946
+ shouldRetryBasedOnError = noopShouldRetryBasedOnError,
2989
3947
  maxRetriesNumber,
2990
- shouldRetryBasedOnError,
2991
3948
  delayFactor = 0,
2992
3949
  delayMaxMs = 1e3,
2993
3950
  delayMinMs = 100
@@ -3263,5 +4220,5 @@ function wrapText(value, maxLength = 30) {
3263
4220
  return value;
3264
4221
  }
3265
4222
 
3266
- export { AppError, AsyncIterableQueue, BrowserAssertionError, CancellablePromise, ColorParser, FixedMap, FixedWeakMap, LruCache, Queue, SimpleEventEmitter, TWEMOJI_REGEX, TimeBucket, alpha, arrayable, assert, asyncFilter, asyncFind, asyncForEach, asyncMap, avg, blendColors, buildCssColor, cache, cacheBucket, cacheFixed, cacheLRU, camelCase, capitalize, captureStackTrace, catchError, channelsToHSL, channelsToHex, channelsToRGB, checkBitmask, chunk, chunkSeries, clamp, cleanEmpty, cleanObject, colorToChannels, contrastRatio, convertToUnit, crc32, createCustomizer, createCustomizerFactory, createDeepCloneWith, createEnvParser, createRandomizer, createSecureCustomizer, createWithCache, cssVariable, deepAssign, deepClone, deepCloneWith, deepDefaults, deepFreeze, def, defer, delay, dropCache, env, escapeHtml, escapeNumeric, escapeRegExp, fastIdle, fastIdlePromise, fastRaf, findMean, flagsToMap, flatten, formatMoney, formatNumber, get, getFileExtension, getFileName, getInitials, getRandomInt, getWords, has, hasOwn, hasProtocol, hex, hexToChannels, hslToChannels, humanFileSize, humanize, interpolateColor, isBigInt, isBoolean, isCached, isClient, isColorChannels, isCustomizerFactory, isDate, isDef, isEmpty, isEqual, isError, isFunction, isMap, isNullOrUndefined, isNumber, isObject, isOneEmoji, isPrimitive, isPromise, isSet, isSkip, isString, isSuccess, isSymbol, isWeakMap, isWeakSet, isWithCache, isoToFlagEmoji, kebabCase, keyBy, logger, lowerCase, luminance, maskingEmail, maskingPhone, maskingWords, nextTickIteration, noop, objectId, omit, omitPrefixed, orderBy, parseAllNumbers, parseAlpha, parsePercentage, percentOf, pick, pickPrefixed, qs, rafPromise, randomString, removeVS16s, retryOnError, rgbToChannels, round2digits, set, snakeCase, sprintf, startCase, strAssign, sum, timeout, timestamp, timestampToDate, tintedTextColor, toError, toMap, truncate, typeOf, unflatten, union, uniq, uniqBy, unset, withCache, withCacheBucket, withCacheBucketBatch, withCacheFixed, withCacheLRU, withDeepClone, withPointerCache, wrapText };
4223
+ export { AppError, AsyncIterableQueue, BrowserAssertionError, CancellablePromise, ColorParser, instance as EJSON, EJSONStream, FindMean, FixedMap, FixedWeakMap, LruCache, Queue, SimpleEventEmitter, TWEMOJI_REGEX, TimeBucket, TimeSpan, alpha, arrayable, assert, asyncFilter, asyncFind, asyncForEach, asyncMap, avg, base64ToBytes, bigIntBytes, bigIntFromBytes, blendColors, buildCssColor, bytesToBase64, cache, cacheBucket, cacheFixed, cacheLRU, camelCase, capitalize, captureStackTrace, catchError, channelsToHSL, channelsToHex, channelsToRGB, checkBitmask, chunk, chunkSeries, clamp, cleanEmpty, cleanObject, colorToChannels, compareBytes, concatenateBytes, contrastRatio, convertToUnit, crc32, createCustomizer, createCustomizerFactory, createDateObject, createDeepCloneWith, createEJSON, createEJSONStream, createEnvParser, createRandomizer, createSecureCustomizer, createTimeObject, createTimeSpan, createWithCache, cssVariable, dateInDays, dateInSeconds, deepAssign, deepClone, deepCloneWith, deepDefaults, deepFreeze, def, defer, delay, difference, dropCache, env, escapeHtml, escapeNumeric, escapeRegExp, fastIdle, fastIdlePromise, fastRaf, findMean, flagsToMap, flatten, formatMoney, formatNumber, get, getFileExtension, getFileName, getInitials, getRandomInt, getRandomTime, getWords, has, hasOwn, hasProtocol, hex, hexToChannels, hmToSeconds, hslToChannels, humanFileSize, humanize, interpolateColor, intersection, isBigInt, isBoolean, isCached, isClient, isColorChannels, isCustomizerFactory, isDate, isDateObject, isDef, isEmpty, isEqual, isError, isFunction, isInfinity, isMap, isNullOrUndefined, isNumber, isObject, isOneEmoji, isPlainObject, isPrimitive, isPromise, isSet, isSkip, isString, isSuccess, isSymbol, isTimeObject, isTimeString, isTimeValue, isValidWeekDay, isWeakMap, isWeakSet, isWithCache, isoToFlagEmoji, kebabCase, keyBy, logger, lowerCase, luminance, maskingEmail, maskingPhone, maskingWords, nextTickIteration, noop, objectId, omit, omitPrefixed, orderBy, parseAllNumbers, parseAlpha, parsePercentage, percentOf, pick, pickPrefixed, qs, rafPromise, randomString, removeVS16s, retryOnError, rgbToChannels, round2digits, secondsToHm, set, shuffle, snakeCase, sprintf, startCase, strAssign, sum, timeFromMinutes, timeStringify, timeToMinutes, timeout, timestamp, timestampMs, timestampToDate, tintedTextColor, toError, toMap, truncate, typeOf, uint16ToUint8, uint32ToUint8, uint8ToUint16, uint8ToUint32, unflatten, union, uniq, uniqBy, unset, weeksInYear, withCache, withCacheBucket, withCacheBucketBatch, withCacheFixed, withCacheLRU, withDeepClone, withPointerCache, wrapText };
3267
4224
  //# sourceMappingURL=index.mjs.map