@andrew_l/toolkit 0.0.1 → 0.2.4

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
@@ -6,7 +6,6 @@ const _cloneDeepWith = require('lodash/cloneDeepWith');
6
6
  const _defaultsDeep = require('lodash/defaultsDeep');
7
7
  const _set = require('lodash/set');
8
8
  const _unset = require('lodash/unset');
9
- const lodash = require('lodash');
10
9
 
11
10
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
12
11
 
@@ -27,8 +26,21 @@ const isBigInt = (val) => typeof val === "bigint";
27
26
  const isBoolean = (val) => typeof val === "boolean";
28
27
  const isFunction = (val) => typeof val === "function";
29
28
  const isNumber = (val) => typeof val === "number" && !isNaN(val);
29
+ const isInfinity = (val) => val === Infinity || val === -Infinity;
30
30
  const isString = (val) => typeof val === "string";
31
31
  const isObject = (val) => toString.call(val) === "[object Object]";
32
+ const isPlainObject = (val) => {
33
+ let ctor, prot;
34
+ if (!isObject(val)) return false;
35
+ ctor = val.constructor;
36
+ if (ctor === void 0) return true;
37
+ prot = ctor.prototype;
38
+ if (isObject(prot) === false) return false;
39
+ if (prot.hasOwnProperty("isPrototypeOf") === false) {
40
+ return false;
41
+ }
42
+ return true;
43
+ };
32
44
  const isDate = (val) => val instanceof Date && !isNaN(val);
33
45
  const noop = () => {
34
46
  };
@@ -43,28 +55,89 @@ function isEqual(a, b) {
43
55
  if (Object.is(a, b)) {
44
56
  return true;
45
57
  }
46
- if (a instanceof Date && b instanceof Date) {
58
+ if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) {
59
+ return false;
60
+ }
61
+ if (a.constructor !== b.constructor) {
62
+ return false;
63
+ }
64
+ if (Array.isArray(a)) {
65
+ const { length } = a;
66
+ if (length !== b.length) {
67
+ return false;
68
+ }
69
+ for (let i = length; i-- !== 0; ) {
70
+ if (!isEqual(a[i], b[i])) {
71
+ return false;
72
+ }
73
+ }
74
+ return true;
75
+ }
76
+ if (a instanceof Date) {
47
77
  return a.getTime() === b.getTime();
48
78
  }
49
- if (a instanceof RegExp && b instanceof RegExp) {
79
+ if (a instanceof RegExp) {
50
80
  return a.source === b.source && a.flags === b.flags;
51
81
  }
52
- if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) {
53
- return false;
82
+ if (a instanceof Set) {
83
+ if (a.size !== b.size) {
84
+ return false;
85
+ }
86
+ for (const value of a) {
87
+ if (!b.has(value)) {
88
+ return false;
89
+ }
90
+ }
91
+ return true;
92
+ }
93
+ if (a instanceof Map) {
94
+ if (a.size !== b.size) {
95
+ return false;
96
+ }
97
+ for (const entry of a) {
98
+ if (!b.has(entry[0]) || !isEqual(entry[1], b.get(entry[0]))) {
99
+ return false;
100
+ }
101
+ }
102
+ return true;
103
+ }
104
+ if (a instanceof DataView) {
105
+ const { byteLength } = a;
106
+ if (byteLength !== b.byteLength) {
107
+ return false;
108
+ }
109
+ for (let i = byteLength; i-- !== 0; ) {
110
+ if (a.getUint8(i) !== b.getUint8(i)) {
111
+ return false;
112
+ }
113
+ }
114
+ return true;
115
+ }
116
+ if (a instanceof ArrayBuffer && b instanceof ArrayBuffer) {
117
+ a = new Uint8Array(a);
118
+ b = new Uint8Array(b);
119
+ }
120
+ if (ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
121
+ const { length } = a;
122
+ if (length !== b.length) {
123
+ return false;
124
+ }
125
+ for (let i = length; i-- !== 0; ) {
126
+ if (a[i] !== b[i]) {
127
+ return false;
128
+ }
129
+ }
130
+ return true;
54
131
  }
55
132
  const aKeys = Object.keys(a);
56
133
  const bKeys = Object.keys(b);
57
134
  if (aKeys.length !== bKeys.length) {
58
135
  return false;
59
136
  }
60
- if (Array.from(new Set(aKeys.concat(bKeys))).length !== aKeys.length) {
61
- return false;
62
- }
63
- for (let i = 0; i < aKeys.length; i++) {
64
- const propKey = aKeys[i];
65
- const aProp = a[propKey];
66
- const bProp = b[propKey];
67
- if (!isEqual(aProp, bProp)) {
137
+ let key;
138
+ for (let i = aKeys.length; i-- !== 0; ) {
139
+ key = aKeys[i];
140
+ if (!Object.hasOwn(b, key) || !isEqual(a[key], b[key])) {
68
141
  return false;
69
142
  }
70
143
  }
@@ -155,6 +228,35 @@ function chunkSeries(list, step = 1) {
155
228
  return result;
156
229
  }
157
230
 
231
+ function difference(...arrays) {
232
+ if (arrays.length === 0) return [];
233
+ if (arrays.length === 1) return [...arrays[0]];
234
+ const [first, ...rest] = arrays;
235
+ const blacklist = /* @__PURE__ */ new Set();
236
+ const set = new Set(first);
237
+ for (const items of rest) {
238
+ for (const item of items) {
239
+ if (blacklist.has(item)) continue;
240
+ if (set.has(item)) {
241
+ set.delete(item);
242
+ blacklist.add(item);
243
+ continue;
244
+ }
245
+ set.add(item);
246
+ }
247
+ }
248
+ return Array.from(set);
249
+ }
250
+
251
+ function intersection(...arrays) {
252
+ if (arrays.length === 0) return [];
253
+ if (arrays.length === 1) return arrays[0];
254
+ return arrays.reduce((acc, curr) => {
255
+ const set = new Set(curr);
256
+ return acc.filter((item) => set.has(item));
257
+ });
258
+ }
259
+
158
260
  function keyBy(array, keyBy2, objectMode) {
159
261
  const getItemKey = isFunction(keyBy2) ? keyBy2 : (item) => item?.[keyBy2];
160
262
  if (objectMode === true) {
@@ -205,6 +307,15 @@ function orderBy(array, fields, orders) {
205
307
  });
206
308
  }
207
309
 
310
+ function shuffle(arr) {
311
+ const result = arr.slice();
312
+ for (let i = result.length - 1; i >= 1; i--) {
313
+ const j = Math.floor(Math.random() * (i + 1));
314
+ [result[i], result[j]] = [result[j], result[i]];
315
+ }
316
+ return result;
317
+ }
318
+
208
319
  const sum = (values) => {
209
320
  return values.reduce((a, b) => a + (isNumber(b) ? b : 0), 0);
210
321
  };
@@ -216,8 +327,11 @@ function uniq(value) {
216
327
  return [...new Set(value)];
217
328
  }
218
329
 
219
- function union(arr1, arr2) {
220
- return uniq(arr1.concat(arr2));
330
+ function union(...arrays) {
331
+ if (arrays.length === 0) return [];
332
+ if (arrays.length === 1) return [...arrays[0]];
333
+ const [first, ...rest] = arrays;
334
+ return uniq(first.concat(...rest));
221
335
  }
222
336
 
223
337
  const get = _get__default;
@@ -336,6 +450,202 @@ const assert = {
336
450
  string: string
337
451
  };
338
452
 
453
+ class Base64Encoding {
454
+ alphabet;
455
+ padding;
456
+ decodeMap = /* @__PURE__ */ new Map();
457
+ constructor(alphabet, options) {
458
+ if (alphabet.length !== 64) {
459
+ throw new Error("Invalid alphabet");
460
+ }
461
+ this.alphabet = alphabet;
462
+ this.padding = options?.padding ?? "=";
463
+ if (this.alphabet.includes(this.padding) || this.padding.length !== 1) {
464
+ throw new Error("Invalid padding");
465
+ }
466
+ for (let i = 0; i < alphabet.length; i++) {
467
+ this.decodeMap.set(alphabet[i], i);
468
+ }
469
+ }
470
+ encode(data, options) {
471
+ let result = "";
472
+ let buffer = 0;
473
+ let shift = 0;
474
+ for (let i = 0; i < data.length; i++) {
475
+ buffer = buffer << 8 | data[i];
476
+ shift += 8;
477
+ while (shift >= 6) {
478
+ shift += -6;
479
+ result += this.alphabet[buffer >> shift & 63];
480
+ }
481
+ }
482
+ if (shift > 0) {
483
+ result += this.alphabet[buffer << 6 - shift & 63];
484
+ }
485
+ const includePadding = options?.includePadding ?? true;
486
+ if (includePadding) {
487
+ const padCount = (4 - result.length % 4) % 4;
488
+ for (let i = 0; i < padCount; i++) {
489
+ result += "=";
490
+ }
491
+ }
492
+ return result;
493
+ }
494
+ decode(data, options) {
495
+ const strict = options?.strict ?? true;
496
+ const chunkCount = Math.ceil(data.length / 4);
497
+ const result = [];
498
+ for (let i = 0; i < chunkCount; i++) {
499
+ let padCount = 0;
500
+ let buffer = 0;
501
+ for (let j = 0; j < 4; j++) {
502
+ const encoded = data[i * 4 + j];
503
+ if (encoded === "=") {
504
+ if (i + 1 !== chunkCount) {
505
+ throw new Error(`Invalid character: ${encoded}`);
506
+ }
507
+ padCount += 1;
508
+ continue;
509
+ }
510
+ if (encoded === void 0) {
511
+ if (strict) {
512
+ throw new Error("Invalid data");
513
+ }
514
+ padCount += 1;
515
+ continue;
516
+ }
517
+ const value = this.decodeMap.get(encoded) ?? null;
518
+ if (value === null) {
519
+ throw new Error(`Invalid character: ${encoded}`);
520
+ }
521
+ buffer += value << 6 * (3 - j);
522
+ }
523
+ result.push(buffer >> 16 & 255);
524
+ if (padCount < 2) {
525
+ result.push(buffer >> 8 & 255);
526
+ }
527
+ if (padCount < 1) {
528
+ result.push(buffer & 255);
529
+ }
530
+ }
531
+ return Uint8Array.from(result);
532
+ }
533
+ }
534
+
535
+ const base64 = new Base64Encoding(
536
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
537
+ );
538
+ const base64url = new Base64Encoding(
539
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
540
+ );
541
+
542
+ function base64ToBytes(data, { encoding = "base64", strict } = {}) {
543
+ if (encoding === "base64") {
544
+ return base64.decode(data, { strict: strict ?? true });
545
+ } else if (encoding === "base64url") {
546
+ return base64url.decode(data, { strict: strict ?? false });
547
+ }
548
+ ok(false, "Invalid encoding options: " + encoding);
549
+ }
550
+
551
+ function bigIntBytes(value) {
552
+ if (value < 0n) {
553
+ value = value * -1n;
554
+ }
555
+ let byteLength = 1;
556
+ while (value > 2n ** BigInt(byteLength * 8) - 1n) {
557
+ byteLength++;
558
+ }
559
+ const encoded = new Uint8Array(byteLength);
560
+ for (let i = 0; i < encoded.byteLength; i++) {
561
+ encoded[i] = Number(
562
+ value >> BigInt((encoded.byteLength - i - 1) * 8) & 0xffn
563
+ );
564
+ }
565
+ return encoded;
566
+ }
567
+
568
+ function bigIntFromBytes(bytes) {
569
+ ok(bytes.byteLength > 0, "Empty Uint8Array");
570
+ let decoded = 0n;
571
+ for (let i = 0; i < bytes.byteLength; i++) {
572
+ decoded += BigInt(bytes[i]) << BigInt((bytes.byteLength - 1 - i) * 8);
573
+ }
574
+ return decoded;
575
+ }
576
+
577
+ function bytesToBase64(data, { encoding = "base64", padding } = {}) {
578
+ if (encoding === "base64") {
579
+ return base64.encode(data, { includePadding: padding ?? true });
580
+ } else if (encoding === "base64url") {
581
+ return base64url.encode(data, { includePadding: padding ?? false });
582
+ }
583
+ ok(false, "Invalid encoding options: " + encoding);
584
+ }
585
+
586
+ function compareBytes(a, b) {
587
+ if (a.byteLength !== b.byteLength) {
588
+ return false;
589
+ }
590
+ for (let i = 0; i < b.byteLength; i++) {
591
+ if (a[i] !== b[i]) {
592
+ return false;
593
+ }
594
+ }
595
+ return true;
596
+ }
597
+
598
+ function concatenateBytes(a, b) {
599
+ const result = new Uint8Array(a.byteLength + b.byteLength);
600
+ result.set(a);
601
+ result.set(b, a.byteLength);
602
+ return result;
603
+ }
604
+
605
+ function uint16ToUint8(value) {
606
+ const uint8Array = new Uint8Array(value.length * 2);
607
+ for (let i = 0; i < value.length; i++) {
608
+ uint8Array[i * 2] = value[i] & 255;
609
+ uint8Array[i * 2 + 1] = value[i] >> 8;
610
+ }
611
+ return uint8Array;
612
+ }
613
+
614
+ function uint32ToUint8(value) {
615
+ const uint8Array = new Uint8Array(value.length * 4);
616
+ for (let i = 0; i < value.length; i++) {
617
+ uint8Array[i * 4] = value[i] & 255;
618
+ uint8Array[i * 4 + 1] = value[i] >> 8 & 255;
619
+ uint8Array[i * 4 + 2] = value[i] >> 16 & 255;
620
+ uint8Array[i * 4 + 3] = value[i] >> 24 & 255;
621
+ }
622
+ return uint8Array;
623
+ }
624
+
625
+ function uint8ToUint16(value) {
626
+ ok(
627
+ value.length % 2 === 0,
628
+ "Uint8Array length must be even for conversion to Uint16Array"
629
+ );
630
+ const uint16Array = new Uint16Array(value.length / 2);
631
+ for (let i = 0; i < uint16Array.length; i++) {
632
+ uint16Array[i] = value[i * 2] << 8 | value[i * 2 + 1];
633
+ }
634
+ return uint16Array;
635
+ }
636
+
637
+ function uint8ToUint32(value) {
638
+ ok(
639
+ value.length % 4 === 0,
640
+ "Uint8Array length must be a multiple of 4 for conversion to Uint32Array"
641
+ );
642
+ const uint32Array = new Uint32Array(value.length / 4);
643
+ for (let i = 0; i < uint32Array.length; i++) {
644
+ uint32Array[i] = value[i * 4] << 24 | value[i * 4 + 1] << 16 | value[i * 4 + 2] << 8 | value[i * 4 + 3];
645
+ }
646
+ return uint32Array;
647
+ }
648
+
339
649
  const def = (obj, key, value, writable = false) => {
340
650
  Object.defineProperty(obj, key, {
341
651
  configurable: true,
@@ -1739,18 +2049,6 @@ function percentOf(value, percent, digits) {
1739
2049
  return result;
1740
2050
  }
1741
2051
 
1742
- function timestamp(fromValue = Date.now()) {
1743
- if (isDate(fromValue)) {
1744
- fromValue = fromValue.getTime();
1745
- }
1746
- return Math.floor(fromValue / 1e3);
1747
- }
1748
-
1749
- function timestampToDate(value) {
1750
- if (!isNumber(value)) return null;
1751
- return new Date(value * 1e3);
1752
- }
1753
-
1754
2052
  const rgb3Numbers = new RegExp(
1755
2053
  `^
1756
2054
  rgba?\\(
@@ -2054,6 +2352,664 @@ function crc32(str, seed = 0) {
2054
2352
  return ~C;
2055
2353
  }
2056
2354
 
2355
+ function isDateObject(value) {
2356
+ return has(value, ["year", "month", "date"]) && isNumber(value.year) && isNumber(value.month) && isNumber(value.date);
2357
+ }
2358
+
2359
+ function createDateObject(value, returnsNullWhenInvalid = false) {
2360
+ let result = null;
2361
+ let inputValue = value;
2362
+ if (isNumber(inputValue) || isString(inputValue)) {
2363
+ inputValue = new Date(inputValue);
2364
+ }
2365
+ if (isDate(inputValue)) {
2366
+ result = {
2367
+ year: inputValue.getFullYear(),
2368
+ month: inputValue.getMonth() + 1,
2369
+ date: inputValue.getDate()
2370
+ };
2371
+ } else if (isDateObject(inputValue)) {
2372
+ result = { ...inputValue };
2373
+ }
2374
+ ok(
2375
+ returnsNullWhenInvalid || !!result,
2376
+ `Failed to date parse: ${value}.`
2377
+ );
2378
+ return result;
2379
+ }
2380
+
2381
+ function isTimeObject(value) {
2382
+ 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;
2383
+ }
2384
+
2385
+ function createTimeObject(value, returnsNullWhenInvalid = false) {
2386
+ let result = null;
2387
+ let inputValue = value;
2388
+ if (isNumber(inputValue)) {
2389
+ inputValue = new Date(inputValue);
2390
+ } else if (isString(inputValue)) {
2391
+ const [h, m] = inputValue.split(":").map((v) => v.trim().padStart(2, "0")).map((v) => parseInt(v));
2392
+ inputValue = { h, m };
2393
+ }
2394
+ if (isDate(inputValue)) {
2395
+ result = {
2396
+ h: inputValue.getHours(),
2397
+ m: inputValue.getMinutes()
2398
+ };
2399
+ } else if (isTimeObject(inputValue)) {
2400
+ result = { ...inputValue };
2401
+ }
2402
+ ok(
2403
+ returnsNullWhenInvalid || !!result,
2404
+ `Failed to time parse: ${value}.`
2405
+ );
2406
+ return result;
2407
+ }
2408
+
2409
+ const UNIT_TO_MS = {
2410
+ ms: 1,
2411
+ s: 1e3,
2412
+ m: 1e3 * 60,
2413
+ h: 1e3 * 60 * 60,
2414
+ d: 1e3 * 60 * 60 * 24,
2415
+ w: 1e3 * 60 * 60 * 24 * 7
2416
+ };
2417
+ class TimeSpan {
2418
+ constructor(value, unit) {
2419
+ this.value = value;
2420
+ this.unit = unit;
2421
+ }
2422
+ /**
2423
+ * The numeric value of the time span
2424
+ */
2425
+ value;
2426
+ /**
2427
+ * The unit of the time span.
2428
+ */
2429
+ unit;
2430
+ /**
2431
+ * Converts the time span to milliseconds.
2432
+ *
2433
+ * @returns {number} The equivalent time span in milliseconds.
2434
+ * @example
2435
+ * const ts = new TimeSpan(2, 'h');
2436
+ * ts.milliseconds(); // Returns 7200000
2437
+ */
2438
+ milliseconds() {
2439
+ const multiplier = UNIT_TO_MS[this.unit];
2440
+ return this.value * multiplier;
2441
+ }
2442
+ /**
2443
+ * Converts the time span to seconds.
2444
+ *
2445
+ * @returns {number} The equivalent time span in seconds.
2446
+ * @example
2447
+ * const ts = new TimeSpan(2, 'm');
2448
+ * ts.seconds(); // Returns 120
2449
+ */
2450
+ seconds() {
2451
+ return this.milliseconds() / UNIT_TO_MS.s;
2452
+ }
2453
+ /**
2454
+ * Converts the time span to minutes.
2455
+ *
2456
+ * @returns {number} The equivalent time span in minutes.
2457
+ * @example
2458
+ * const ts = new TimeSpan(120, 's');
2459
+ * ts.minutes(); // Returns 2
2460
+ */
2461
+ minutes() {
2462
+ return this.milliseconds() / UNIT_TO_MS.m;
2463
+ }
2464
+ /**
2465
+ * Converts the time span to hours.
2466
+ *
2467
+ * @returns {number} The equivalent time span in hours.
2468
+ * @example
2469
+ * const ts = new TimeSpan(120, 'm');
2470
+ * ts.hours(); // Returns 2
2471
+ */
2472
+ hours() {
2473
+ return this.milliseconds() / UNIT_TO_MS.h;
2474
+ }
2475
+ /**
2476
+ * Converts the time span to days.
2477
+ *
2478
+ * @returns {number} The equivalent time span in days.
2479
+ * @example
2480
+ * const ts = new TimeSpan(48, 'h');
2481
+ * ts.days(); // Returns 2
2482
+ */
2483
+ days() {
2484
+ return this.milliseconds() / UNIT_TO_MS.d;
2485
+ }
2486
+ /**
2487
+ * Converts the time span to weeks.
2488
+ *
2489
+ * @returns {number} The equivalent time span in weeks.
2490
+ * @example
2491
+ * const ts = new TimeSpan(14, 'd');
2492
+ * ts.weeks(); // Returns 2
2493
+ */
2494
+ weeks() {
2495
+ return this.milliseconds() / UNIT_TO_MS.w;
2496
+ }
2497
+ /**
2498
+ * Adds a specified value and unit to the current time span.
2499
+ *
2500
+ * Returns new instance.
2501
+ *
2502
+ * @param {number} value - The value to add.
2503
+ * @param {TimeSpanUnit} [unit='ms'] - The unit of the value to add (default is milliseconds).
2504
+ * @returns {TimeSpan} A new TimeSpan instance with the added value.
2505
+ * @example
2506
+ * const ts = new TimeSpan(1, 'h');
2507
+ * ts.add(30, 'm'); // Represents 1.5 hours
2508
+ */
2509
+ add(value, unit = "ms") {
2510
+ const multiplier = UNIT_TO_MS[unit];
2511
+ return new TimeSpan(this.milliseconds() + value * multiplier, "ms");
2512
+ }
2513
+ /**
2514
+ * Subtracts a specified value and unit from the current time span.
2515
+ *
2516
+ * Returns new instance.
2517
+ *
2518
+ * @param {number} value - The value to subtract.
2519
+ * @param {TimeSpanUnit} [unit='ms'] - The unit of the value to subtract (default is milliseconds).
2520
+ * @returns {TimeSpan} A new TimeSpan instance with the subtracted value.
2521
+ * @example
2522
+ * const ts = new TimeSpan(1, 'h');
2523
+ * ts.subtract(30, 'm'); // Represents 30 minutes less than 1 hour
2524
+ */
2525
+ subtract(value, unit = "ms") {
2526
+ const multiplier = UNIT_TO_MS[unit];
2527
+ return new TimeSpan(this.milliseconds() - value * multiplier, "ms");
2528
+ }
2529
+ }
2530
+
2531
+ function createTimeSpan(value, unit = "ms") {
2532
+ return new TimeSpan(value, unit);
2533
+ }
2534
+
2535
+ function timestampMs(fromValue = Date.now()) {
2536
+ if (isDate(fromValue)) {
2537
+ fromValue = fromValue.getTime();
2538
+ } else if (isString(fromValue)) {
2539
+ const dt = new Date(fromValue);
2540
+ fromValue = isDate(dt) ? dt.getTime() : 0;
2541
+ }
2542
+ return isNumber(fromValue) ? fromValue : 0;
2543
+ }
2544
+
2545
+ function dateInDays(days, fromValue = Date.now()) {
2546
+ return new Date(timestampMs(fromValue) + days * 60 * 60 * 24 * 1e3);
2547
+ }
2548
+
2549
+ function dateInSeconds(seconds, fromValue = Date.now()) {
2550
+ return new Date(timestampMs(fromValue) + seconds * 1e3);
2551
+ }
2552
+
2553
+ function getRandomTime(startTime = { h: 0, m: 0 }, endTime = { h: 23, m: 59 }) {
2554
+ const h = getRandomInt(startTime.h, endTime.h);
2555
+ if (startTime.h === endTime.h) {
2556
+ return { h, m: getRandomInt(startTime.m, endTime.m) };
2557
+ }
2558
+ if (h === startTime.h) {
2559
+ return { h, m: getRandomInt(startTime.m, 59) };
2560
+ }
2561
+ if (h === endTime.h) {
2562
+ return { h, m: getRandomInt(0, endTime.m) };
2563
+ }
2564
+ return { h, m: getRandomInt(0, 59) };
2565
+ }
2566
+
2567
+ function hmToSeconds(hm) {
2568
+ hm = Number(hm);
2569
+ number$1(hm, "expected number value");
2570
+ const h = Math.floor(hm);
2571
+ const m = round2digits(hm - h) * 100;
2572
+ return h * 3600 + m * 60;
2573
+ }
2574
+
2575
+ function isTimeString(value) {
2576
+ if (!isString(value)) return false;
2577
+ const parts = value.split(":").map(Number);
2578
+ if (parts.length !== 2) return false;
2579
+ const [h, m] = parts;
2580
+ return h >= 0 && h < 24 && m >= 0 && m < 60;
2581
+ }
2582
+
2583
+ function isTimeValue(value) {
2584
+ return isTimeString(value) || isTimeObject(value);
2585
+ }
2586
+
2587
+ function isValidWeekDay(value) {
2588
+ return isNumber(value) && Number.isInteger(value) && value >= 1 && value <= 7;
2589
+ }
2590
+
2591
+ function secondsToHm(seconds) {
2592
+ const value = Number(seconds);
2593
+ number$1(value, "expected number value");
2594
+ const h = Math.floor(value / 3600);
2595
+ const m = Math.floor(value % 3600 / 60);
2596
+ return round2digits(h + m / 100, 2);
2597
+ }
2598
+
2599
+ function timeFromMinutes(value, returnsNullWhenInvalid = false) {
2600
+ if (!isNumber(value)) {
2601
+ ok(
2602
+ returnsNullWhenInvalid,
2603
+ "Failed to time parse from minutes: " + value
2604
+ );
2605
+ return null;
2606
+ }
2607
+ if (value === 0) {
2608
+ return { h: 0, m: 0 };
2609
+ }
2610
+ value = value % 1440;
2611
+ if (value < 0) {
2612
+ value += 1440;
2613
+ }
2614
+ const h = Math.floor(value / 60);
2615
+ const m = value % 60;
2616
+ return { h, m };
2617
+ }
2618
+
2619
+ function timestamp(fromValue = Date.now()) {
2620
+ if (isDate(fromValue)) {
2621
+ fromValue = fromValue.getTime();
2622
+ }
2623
+ return Math.floor(fromValue / 1e3);
2624
+ }
2625
+
2626
+ function timestampToDate(value) {
2627
+ if (!isNumber(value)) return null;
2628
+ return new Date(value * 1e3);
2629
+ }
2630
+
2631
+ function timeStringify(value, returnsNullWhenInvalid = false) {
2632
+ const timeObject = createTimeObject(value, true);
2633
+ if (!timeObject) {
2634
+ ok(
2635
+ returnsNullWhenInvalid,
2636
+ "Failed to stringify time from: " + JSON.stringify(value)
2637
+ );
2638
+ return null;
2639
+ }
2640
+ let { h, m } = timeObject;
2641
+ const hStr = Math.ceil(h).toString().padStart(2, "0").slice(-2);
2642
+ const mStr = Math.ceil(m).toString().padStart(2, "0").slice(-2);
2643
+ return `${hStr}:${mStr}`;
2644
+ }
2645
+
2646
+ function timeToMinutes(value) {
2647
+ const time = createTimeObject(value);
2648
+ return time.h * 60 + time.m;
2649
+ }
2650
+
2651
+ function weeksInYear(year) {
2652
+ const target = new Date(Date.UTC(year + 1, 0, 1));
2653
+ const dayNumber = target.getDay();
2654
+ return dayNumber < 4 ? 52 : 53;
2655
+ }
2656
+
2657
+ const DateType = {
2658
+ placeholder: "$date",
2659
+ encode: (value) => {
2660
+ if (value instanceof Date) {
2661
+ return value.getTime();
2662
+ }
2663
+ },
2664
+ decode(value) {
2665
+ return new Date(value);
2666
+ }
2667
+ };
2668
+ const BinaryType = {
2669
+ placeholder: "$binary",
2670
+ encode: (value) => {
2671
+ if (value instanceof Uint8Array) {
2672
+ return base64.encode(value, { includePadding: true });
2673
+ } else if (value instanceof Uint16Array) {
2674
+ return {
2675
+ value: base64.encode(uint16ToUint8(value), { includePadding: true }),
2676
+ bit: 16
2677
+ };
2678
+ } else if (value instanceof Uint32Array) {
2679
+ return {
2680
+ value: base64.encode(uint32ToUint8(value), { includePadding: true }),
2681
+ bit: 32
2682
+ };
2683
+ }
2684
+ },
2685
+ decode(value) {
2686
+ if (typeof value === "string") {
2687
+ return base64.decode(value, { strict: true });
2688
+ } else if (value.bit === 16) {
2689
+ return uint8ToUint16(base64.decode(value.value, { strict: true }));
2690
+ } else if (value.bit === 32) {
2691
+ return uint8ToUint32(base64.decode(value.value, { strict: true }));
2692
+ }
2693
+ throw new Error("Unexpected $binary bit value: " + value.bit);
2694
+ }
2695
+ };
2696
+ const BigIntType = {
2697
+ placeholder: "$bigint",
2698
+ encode: (value) => {
2699
+ if (typeof value === "bigint") {
2700
+ return base64.encode(bigIntBytes(value), { includePadding: false });
2701
+ }
2702
+ },
2703
+ decode(value) {
2704
+ return bigIntFromBytes(base64.decode(value, { strict: false }));
2705
+ }
2706
+ };
2707
+ const MapType = {
2708
+ placeholder: "$map",
2709
+ encode: (value, encode) => {
2710
+ if (value instanceof Map) {
2711
+ return encode(Array.from(value.entries()));
2712
+ }
2713
+ },
2714
+ decode(value) {
2715
+ return new Map(value);
2716
+ }
2717
+ };
2718
+ const SetType = {
2719
+ placeholder: "$set",
2720
+ encode: (value, encode) => {
2721
+ if (value instanceof Set) {
2722
+ return encode(Array.from(value.values()));
2723
+ }
2724
+ },
2725
+ decode(value) {
2726
+ return new Set(value);
2727
+ }
2728
+ };
2729
+ const RegexType = {
2730
+ placeholder: "$regex",
2731
+ encode: (value, encode) => {
2732
+ if (value instanceof RegExp) {
2733
+ const regStr = value.toString();
2734
+ const patternStart = regStr.lastIndexOf("/");
2735
+ return {
2736
+ pattern: value.toString().slice(1, patternStart),
2737
+ flags: regStr.slice(patternStart + 1)
2738
+ };
2739
+ }
2740
+ },
2741
+ decode(value) {
2742
+ return new RegExp(value.pattern, value.flags);
2743
+ }
2744
+ };
2745
+ const InfinityType = {
2746
+ placeholder: "$inf",
2747
+ encode: (value, encode) => {
2748
+ if (value === Infinity) {
2749
+ return 1;
2750
+ } else if (value === -Infinity) {
2751
+ return -1;
2752
+ }
2753
+ },
2754
+ decode(value) {
2755
+ if (value === 1) return Infinity;
2756
+ if (value === -1) return -Infinity;
2757
+ throw new Error("Unexpected $inf value: " + value);
2758
+ }
2759
+ };
2760
+
2761
+ class EJSON {
2762
+ /** @internal */
2763
+ typeHandlers = /* @__PURE__ */ new Map();
2764
+ /** @internal */
2765
+ replacerReady;
2766
+ /** @internal */
2767
+ encode;
2768
+ /** @internal */
2769
+ reviewerReady;
2770
+ /** @internal */
2771
+ pure = true;
2772
+ _vendorName = null;
2773
+ /**
2774
+ * MIME type based on the provided vendor name or defaults to 'application/json'.
2775
+ */
2776
+ mimetype = "application/json";
2777
+ Type = {
2778
+ Date: DateType,
2779
+ Map: MapType,
2780
+ Set: SetType,
2781
+ RegExp: RegexType,
2782
+ Infinity: InfinityType,
2783
+ BigInt: BigIntType,
2784
+ Binary: BinaryType
2785
+ };
2786
+ constructor() {
2787
+ this.replacerReady = this._replacer.bind(this);
2788
+ this.reviewerReady = this._reviewer.bind(this);
2789
+ this.encode = (value) => {
2790
+ return deepCloneWith(value, this.replacerReady);
2791
+ };
2792
+ }
2793
+ /**
2794
+ * The vendor name used for the custom MIME type definition.
2795
+ * If null, defaults to 'application/json'.
2796
+ */
2797
+ get vendorName() {
2798
+ return this._vendorName;
2799
+ }
2800
+ set vendorName(value) {
2801
+ this._vendorName = value;
2802
+ if (!value) {
2803
+ this.mimetype = "application/json";
2804
+ } else {
2805
+ const vendorName = value.split(" ").map((v) => v.toLowerCase()).join(".").replace(/\.\.+/g, ".").replace(/\.$/, "");
2806
+ this.mimetype = `application/vnd.${vendorName}+json`;
2807
+ }
2808
+ }
2809
+ /**
2810
+ * Adds a custom type handler for encoding/decoding logic.
2811
+ * Ensures type placeholders are unique and adhere to conventions.
2812
+ */
2813
+ addType(type) {
2814
+ ok(
2815
+ !this.typeHandlers.has(type.placeholder),
2816
+ `type with ${type.placeholder} already taken.`
2817
+ );
2818
+ ok(
2819
+ type.placeholder.startsWith("$"),
2820
+ "type placeholder must starts with $ symbol."
2821
+ );
2822
+ this.pure = false;
2823
+ this.typeHandlers.set(type.placeholder, type);
2824
+ return this;
2825
+ }
2826
+ /**
2827
+ * Stringifies a JavaScript value using custom encoding logic.
2828
+ * @param {any} value - The value to encode and stringify.
2829
+ * @param {string | number} [space] - Optional space for pretty-printing.
2830
+ * @returns {string} - The JSON stringified value.
2831
+ */
2832
+ stringify(value, space) {
2833
+ if (this.pure) {
2834
+ return JSON.stringify(value, void 0, space);
2835
+ }
2836
+ return JSON.stringify(this.encode(value), void 0, space);
2837
+ }
2838
+ /**
2839
+ * Parses a JSON string using custom decoding logic.
2840
+ * @param {string} value - The JSON string to parse.
2841
+ * @returns {any} - The decoded JavaScript object.
2842
+ */
2843
+ parse(value) {
2844
+ if (this.pure) {
2845
+ return JSON.parse(value);
2846
+ }
2847
+ return JSON.parse(value, this.reviewerReady);
2848
+ }
2849
+ /** @internal */
2850
+ _replacer(value, key) {
2851
+ if (isPlainObject(value)) return;
2852
+ if (Array.isArray(value)) return;
2853
+ if (!isInfinity(value) && !isBigInt(value)) {
2854
+ if (isPrimitive(value)) return;
2855
+ }
2856
+ for (const type of this.typeHandlers.values()) {
2857
+ const res = type.encode(value, this.encode);
2858
+ if (res !== void 0) {
2859
+ return type.encodeInline ? res : { [type.placeholder]: res };
2860
+ }
2861
+ }
2862
+ return value;
2863
+ }
2864
+ /** @internal */
2865
+ _reviewer(_, value) {
2866
+ const key = firstKey(value);
2867
+ if (!key || key[0] !== "$") return value;
2868
+ const type = this.typeHandlers.get(key);
2869
+ if (type) {
2870
+ return type.decode(value[key]);
2871
+ }
2872
+ return value;
2873
+ }
2874
+ }
2875
+ function firstKey(value) {
2876
+ if (!isObject(value)) return null;
2877
+ for (const key in value) {
2878
+ return key;
2879
+ }
2880
+ return null;
2881
+ }
2882
+
2883
+ function createEJSON(withBasicTypes = false) {
2884
+ const ejson = new EJSON();
2885
+ if (withBasicTypes) {
2886
+ ejson.addType(MapType);
2887
+ ejson.addType(SetType);
2888
+ ejson.addType(DateType);
2889
+ ejson.addType(InfinityType);
2890
+ ejson.addType(BigIntType);
2891
+ ejson.addType(BinaryType);
2892
+ ejson.addType(RegexType);
2893
+ }
2894
+ return ejson;
2895
+ }
2896
+
2897
+ class EJSONStream extends TransformStream {
2898
+ ejson;
2899
+ constructor({ ejson, cl, op, sep, onFlush, onStart }) {
2900
+ let firstChunk = true;
2901
+ super({
2902
+ async start(controller) {
2903
+ if (onStart) {
2904
+ await onStart(controller);
2905
+ }
2906
+ controller.enqueue(op);
2907
+ },
2908
+ transform(chunk, controller) {
2909
+ const jsonString = ejson.stringify(chunk);
2910
+ if (firstChunk) {
2911
+ firstChunk = false;
2912
+ } else {
2913
+ controller.enqueue(sep);
2914
+ }
2915
+ controller.enqueue(jsonString);
2916
+ },
2917
+ flush(controller) {
2918
+ controller.enqueue(cl);
2919
+ if (onFlush) {
2920
+ return onFlush(controller);
2921
+ }
2922
+ }
2923
+ });
2924
+ this.ejson = ejson;
2925
+ }
2926
+ /**
2927
+ * The vendor name used for the custom MIME type definition.
2928
+ * If null, defaults to 'application/json'.
2929
+ */
2930
+ get vendorName() {
2931
+ return this.ejson.vendorName;
2932
+ }
2933
+ /**
2934
+ * MIME type based on the provided vendor name or defaults to 'application/json'.
2935
+ */
2936
+ get mimetype() {
2937
+ return this.ejson.mimetype;
2938
+ }
2939
+ }
2940
+
2941
+ const instance = createEJSON(true);
2942
+
2943
+ function createEJSONStream(options = {}) {
2944
+ if (options.resultKey || options.append || options.prepend) {
2945
+ return createEJSONStreamPayload(options);
2946
+ }
2947
+ return new EJSONStream(getOptions(options));
2948
+ }
2949
+ function createEJSONStreamPayload(options) {
2950
+ let { cl, ejson, op, sep } = getOptions(options);
2951
+ const { append, prepend, resultKey } = options;
2952
+ notEmptyString(resultKey, "resultKey required.");
2953
+ const stream = new EJSONStream({
2954
+ ejson,
2955
+ cl,
2956
+ op,
2957
+ sep,
2958
+ async onStart(controller) {
2959
+ if (!prepend) {
2960
+ controller.enqueue(`{"${resultKey}":`);
2961
+ return;
2962
+ }
2963
+ const data = await prepend();
2964
+ if (data === null || data === void 0) {
2965
+ controller.enqueue(`{"${resultKey}":`);
2966
+ return;
2967
+ }
2968
+ ok(
2969
+ isPlainObject(data),
2970
+ "prepend result expected to be plain object"
2971
+ );
2972
+ const dataPart = instance.stringify(data).slice(0, -1);
2973
+ if (dataPart === "{") {
2974
+ controller.enqueue(`{"${resultKey}":`);
2975
+ return;
2976
+ }
2977
+ controller.enqueue(`${dataPart}${sep}"${resultKey}":`);
2978
+ },
2979
+ async onFlush(controller) {
2980
+ if (!append) {
2981
+ controller.enqueue("}");
2982
+ return;
2983
+ }
2984
+ const data = await append();
2985
+ if (data === null || data === void 0) {
2986
+ controller.enqueue("}");
2987
+ return;
2988
+ }
2989
+ ok(
2990
+ isPlainObject(data),
2991
+ "prepend result expected to be plain object"
2992
+ );
2993
+ const dataPart = instance.stringify(data).slice(1);
2994
+ if (dataPart === "}") {
2995
+ controller.enqueue(`}`);
2996
+ return;
2997
+ }
2998
+ controller.enqueue(`${sep}${dataPart}`);
2999
+ }
3000
+ });
3001
+ return stream;
3002
+ }
3003
+ function getOptions(options) {
3004
+ const { ejson = instance, cl = "]", op = "[", sep = "," } = options;
3005
+ return {
3006
+ cl,
3007
+ ejson,
3008
+ op,
3009
+ sep
3010
+ };
3011
+ }
3012
+
2057
3013
  const env = (() => {
2058
3014
  if (globalThis?.process) {
2059
3015
  return createEnvParser(process.env);
@@ -2086,7 +3042,7 @@ function createEnvParser(targetObject) {
2086
3042
  return parseDecimal(targetObject[key], dights) ?? defaultValue;
2087
3043
  },
2088
3044
  string(key, defaultValue = "") {
2089
- return targetObject[key] || defaultValue;
3045
+ return targetObject[key] ?? defaultValue;
2090
3046
  },
2091
3047
  list(key, type, defaultValue = []) {
2092
3048
  if (!(key in targetObject)) {
@@ -2783,9 +3739,9 @@ function typeOf(value) {
2783
3739
  if (value === null) return "null";
2784
3740
  if (Array.isArray(value)) return "array";
2785
3741
  if (isSet(value)) return "set";
2786
- if (lodash.isWeakSet(value)) return "weakset";
3742
+ if (isWeakSet(value)) return "weakset";
2787
3743
  if (isMap(value)) return "map";
2788
- if (lodash.isWeakMap(value)) return "weakmap";
3744
+ if (isWeakMap(value)) return "weakmap";
2789
3745
  if (isDate(value)) return "date";
2790
3746
  if (isObject(value)) return "object";
2791
3747
  return "unknown";
@@ -2995,10 +3951,11 @@ function parseValue(value, asType) {
2995
3951
  return void 0;
2996
3952
  }
2997
3953
 
3954
+ const noopShouldRetryBasedOnError = () => true;
2998
3955
  function retryOnError({
2999
3956
  beforeRetryCallback,
3957
+ shouldRetryBasedOnError = noopShouldRetryBasedOnError,
3000
3958
  maxRetriesNumber,
3001
- shouldRetryBasedOnError,
3002
3959
  delayFactor = 0,
3003
3960
  delayMaxMs = 1e3,
3004
3961
  delayMinMs = 100
@@ -3279,6 +4236,9 @@ exports.AsyncIterableQueue = AsyncIterableQueue;
3279
4236
  exports.BrowserAssertionError = BrowserAssertionError;
3280
4237
  exports.CancellablePromise = CancellablePromise;
3281
4238
  exports.ColorParser = ColorParser;
4239
+ exports.EJSON = instance;
4240
+ exports.EJSONStream = EJSONStream;
4241
+ exports.FindMean = FindMean;
3282
4242
  exports.FixedMap = FixedMap;
3283
4243
  exports.FixedWeakMap = FixedWeakMap;
3284
4244
  exports.LruCache = LruCache;
@@ -3286,6 +4246,7 @@ exports.Queue = Queue;
3286
4246
  exports.SimpleEventEmitter = SimpleEventEmitter;
3287
4247
  exports.TWEMOJI_REGEX = TWEMOJI_REGEX;
3288
4248
  exports.TimeBucket = TimeBucket;
4249
+ exports.TimeSpan = TimeSpan;
3289
4250
  exports.alpha = alpha;
3290
4251
  exports.arrayable = arrayable;
3291
4252
  exports.assert = assert;
@@ -3294,8 +4255,12 @@ exports.asyncFind = asyncFind;
3294
4255
  exports.asyncForEach = asyncForEach;
3295
4256
  exports.asyncMap = asyncMap;
3296
4257
  exports.avg = avg;
4258
+ exports.base64ToBytes = base64ToBytes;
4259
+ exports.bigIntBytes = bigIntBytes;
4260
+ exports.bigIntFromBytes = bigIntFromBytes;
3297
4261
  exports.blendColors = blendColors;
3298
4262
  exports.buildCssColor = buildCssColor;
4263
+ exports.bytesToBase64 = bytesToBase64;
3299
4264
  exports.cache = cache;
3300
4265
  exports.cacheBucket = cacheBucket;
3301
4266
  exports.cacheFixed = cacheFixed;
@@ -3314,17 +4279,26 @@ exports.clamp = clamp;
3314
4279
  exports.cleanEmpty = cleanEmpty;
3315
4280
  exports.cleanObject = cleanObject;
3316
4281
  exports.colorToChannels = colorToChannels;
4282
+ exports.compareBytes = compareBytes;
4283
+ exports.concatenateBytes = concatenateBytes;
3317
4284
  exports.contrastRatio = contrastRatio;
3318
4285
  exports.convertToUnit = convertToUnit;
3319
4286
  exports.crc32 = crc32;
3320
4287
  exports.createCustomizer = createCustomizer;
3321
4288
  exports.createCustomizerFactory = createCustomizerFactory;
4289
+ exports.createDateObject = createDateObject;
3322
4290
  exports.createDeepCloneWith = createDeepCloneWith;
4291
+ exports.createEJSON = createEJSON;
4292
+ exports.createEJSONStream = createEJSONStream;
3323
4293
  exports.createEnvParser = createEnvParser;
3324
4294
  exports.createRandomizer = createRandomizer;
3325
4295
  exports.createSecureCustomizer = createSecureCustomizer;
4296
+ exports.createTimeObject = createTimeObject;
4297
+ exports.createTimeSpan = createTimeSpan;
3326
4298
  exports.createWithCache = createWithCache;
3327
4299
  exports.cssVariable = cssVariable;
4300
+ exports.dateInDays = dateInDays;
4301
+ exports.dateInSeconds = dateInSeconds;
3328
4302
  exports.deepAssign = deepAssign;
3329
4303
  exports.deepClone = deepClone;
3330
4304
  exports.deepCloneWith = deepCloneWith;
@@ -3333,6 +4307,7 @@ exports.deepFreeze = deepFreeze;
3333
4307
  exports.def = def;
3334
4308
  exports.defer = defer;
3335
4309
  exports.delay = delay;
4310
+ exports.difference = difference;
3336
4311
  exports.dropCache = dropCache;
3337
4312
  exports.env = env;
3338
4313
  exports.escapeHtml = escapeHtml;
@@ -3351,16 +4326,19 @@ exports.getFileExtension = getFileExtension;
3351
4326
  exports.getFileName = getFileName;
3352
4327
  exports.getInitials = getInitials;
3353
4328
  exports.getRandomInt = getRandomInt;
4329
+ exports.getRandomTime = getRandomTime;
3354
4330
  exports.getWords = getWords;
3355
4331
  exports.has = has;
3356
4332
  exports.hasOwn = hasOwn;
3357
4333
  exports.hasProtocol = hasProtocol;
3358
4334
  exports.hex = hex;
3359
4335
  exports.hexToChannels = hexToChannels;
4336
+ exports.hmToSeconds = hmToSeconds;
3360
4337
  exports.hslToChannels = hslToChannels;
3361
4338
  exports.humanFileSize = humanFileSize;
3362
4339
  exports.humanize = humanize;
3363
4340
  exports.interpolateColor = interpolateColor;
4341
+ exports.intersection = intersection;
3364
4342
  exports.isBigInt = isBigInt;
3365
4343
  exports.isBoolean = isBoolean;
3366
4344
  exports.isCached = isCached;
@@ -3368,16 +4346,19 @@ exports.isClient = isClient;
3368
4346
  exports.isColorChannels = isColorChannels;
3369
4347
  exports.isCustomizerFactory = isCustomizerFactory;
3370
4348
  exports.isDate = isDate;
4349
+ exports.isDateObject = isDateObject;
3371
4350
  exports.isDef = isDef;
3372
4351
  exports.isEmpty = isEmpty;
3373
4352
  exports.isEqual = isEqual;
3374
4353
  exports.isError = isError;
3375
4354
  exports.isFunction = isFunction;
4355
+ exports.isInfinity = isInfinity;
3376
4356
  exports.isMap = isMap;
3377
4357
  exports.isNullOrUndefined = isNullOrUndefined;
3378
4358
  exports.isNumber = isNumber;
3379
4359
  exports.isObject = isObject;
3380
4360
  exports.isOneEmoji = isOneEmoji;
4361
+ exports.isPlainObject = isPlainObject;
3381
4362
  exports.isPrimitive = isPrimitive;
3382
4363
  exports.isPromise = isPromise;
3383
4364
  exports.isSet = isSet;
@@ -3385,6 +4366,10 @@ exports.isSkip = isSkip;
3385
4366
  exports.isString = isString;
3386
4367
  exports.isSuccess = isSuccess;
3387
4368
  exports.isSymbol = isSymbol;
4369
+ exports.isTimeObject = isTimeObject;
4370
+ exports.isTimeString = isTimeString;
4371
+ exports.isTimeValue = isTimeValue;
4372
+ exports.isValidWeekDay = isValidWeekDay;
3388
4373
  exports.isWeakMap = isWeakMap;
3389
4374
  exports.isWeakSet = isWeakSet;
3390
4375
  exports.isWithCache = isWithCache;
@@ -3416,25 +4401,36 @@ exports.removeVS16s = removeVS16s;
3416
4401
  exports.retryOnError = retryOnError;
3417
4402
  exports.rgbToChannels = rgbToChannels;
3418
4403
  exports.round2digits = round2digits;
4404
+ exports.secondsToHm = secondsToHm;
3419
4405
  exports.set = set;
4406
+ exports.shuffle = shuffle;
3420
4407
  exports.snakeCase = snakeCase;
3421
4408
  exports.sprintf = sprintf;
3422
4409
  exports.startCase = startCase;
3423
4410
  exports.strAssign = strAssign;
3424
4411
  exports.sum = sum;
4412
+ exports.timeFromMinutes = timeFromMinutes;
4413
+ exports.timeStringify = timeStringify;
4414
+ exports.timeToMinutes = timeToMinutes;
3425
4415
  exports.timeout = timeout;
3426
4416
  exports.timestamp = timestamp;
4417
+ exports.timestampMs = timestampMs;
3427
4418
  exports.timestampToDate = timestampToDate;
3428
4419
  exports.tintedTextColor = tintedTextColor;
3429
4420
  exports.toError = toError;
3430
4421
  exports.toMap = toMap;
3431
4422
  exports.truncate = truncate;
3432
4423
  exports.typeOf = typeOf;
4424
+ exports.uint16ToUint8 = uint16ToUint8;
4425
+ exports.uint32ToUint8 = uint32ToUint8;
4426
+ exports.uint8ToUint16 = uint8ToUint16;
4427
+ exports.uint8ToUint32 = uint8ToUint32;
3433
4428
  exports.unflatten = unflatten;
3434
4429
  exports.union = union;
3435
4430
  exports.uniq = uniq;
3436
4431
  exports.uniqBy = uniqBy;
3437
4432
  exports.unset = unset;
4433
+ exports.weeksInYear = weeksInYear;
3438
4434
  exports.withCache = withCache;
3439
4435
  exports.withCacheBucket = withCacheBucket;
3440
4436
  exports.withCacheBucketBatch = withCacheBucketBatch;