@ztimson/utils 0.25.27 → 0.25.28
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 +383 -382
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +383 -382
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -396,315 +396,6 @@ ${opts.message || this.desc}`;
|
|
|
396
396
|
function makeArray(value) {
|
|
397
397
|
return Array.isArray(value) ? value : [value];
|
|
398
398
|
}
|
|
399
|
-
function adjustedInterval(cb, ms) {
|
|
400
|
-
let cancel = false, timeout = null;
|
|
401
|
-
const p = async () => {
|
|
402
|
-
if (cancel) return;
|
|
403
|
-
const start = (/* @__PURE__ */ new Date()).getTime();
|
|
404
|
-
await cb();
|
|
405
|
-
const end = (/* @__PURE__ */ new Date()).getTime();
|
|
406
|
-
timeout = setTimeout(() => p(), ms - (end - start) || 1);
|
|
407
|
-
};
|
|
408
|
-
p();
|
|
409
|
-
return () => {
|
|
410
|
-
cancel = true;
|
|
411
|
-
if (timeout) clearTimeout(timeout);
|
|
412
|
-
};
|
|
413
|
-
}
|
|
414
|
-
function formatDate(format = "YYYY-MM-DD H:mm", date = /* @__PURE__ */ new Date(), tz) {
|
|
415
|
-
const timezones = [
|
|
416
|
-
["IDLW", -12],
|
|
417
|
-
["SST", -11],
|
|
418
|
-
["HST", -10],
|
|
419
|
-
["AKST", -9],
|
|
420
|
-
["PST", -8],
|
|
421
|
-
["MST", -7],
|
|
422
|
-
["CST", -6],
|
|
423
|
-
["EST", -5],
|
|
424
|
-
["AST", -4],
|
|
425
|
-
["BRT", -3],
|
|
426
|
-
["MAT", -2],
|
|
427
|
-
["AZOT", -1],
|
|
428
|
-
["UTC", 0],
|
|
429
|
-
["CET", 1],
|
|
430
|
-
["EET", 2],
|
|
431
|
-
["MSK", 3],
|
|
432
|
-
["AST", 4],
|
|
433
|
-
["PKT", 5],
|
|
434
|
-
["IST", 5.5],
|
|
435
|
-
["BST", 6],
|
|
436
|
-
["ICT", 7],
|
|
437
|
-
["CST", 8],
|
|
438
|
-
["JST", 9],
|
|
439
|
-
["AEST", 10],
|
|
440
|
-
["SBT", 11],
|
|
441
|
-
["FJT", 12],
|
|
442
|
-
["TOT", 13],
|
|
443
|
-
["LINT", 14]
|
|
444
|
-
];
|
|
445
|
-
function adjustTz(date2, gmt) {
|
|
446
|
-
const currentOffset = date2.getTimezoneOffset();
|
|
447
|
-
const adjustedOffset = gmt * 60;
|
|
448
|
-
return new Date(date2.getTime() + (adjustedOffset + currentOffset) * 6e4);
|
|
449
|
-
}
|
|
450
|
-
function day(num) {
|
|
451
|
-
return ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][num] || "Unknown";
|
|
452
|
-
}
|
|
453
|
-
function doy(date2) {
|
|
454
|
-
const start = /* @__PURE__ */ new Date(`${date2.getFullYear()}-01-01 0:00:00`);
|
|
455
|
-
return Math.ceil((date2.getTime() - start.getTime()) / (1e3 * 60 * 60 * 24));
|
|
456
|
-
}
|
|
457
|
-
function month(num) {
|
|
458
|
-
return ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"][num] || "Unknown";
|
|
459
|
-
}
|
|
460
|
-
function suffix(num) {
|
|
461
|
-
if (num % 100 >= 11 && num % 100 <= 13) return `${num}th`;
|
|
462
|
-
switch (num % 10) {
|
|
463
|
-
case 1:
|
|
464
|
-
return `${num}st`;
|
|
465
|
-
case 2:
|
|
466
|
-
return `${num}nd`;
|
|
467
|
-
case 3:
|
|
468
|
-
return `${num}rd`;
|
|
469
|
-
default:
|
|
470
|
-
return `${num}th`;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
function tzOffset(offset) {
|
|
474
|
-
const hours = ~~(offset / 60);
|
|
475
|
-
const minutes = offset % 60;
|
|
476
|
-
return (offset > 0 ? "-" : "") + `${hours}:${minutes.toString().padStart(2, "0")}`;
|
|
477
|
-
}
|
|
478
|
-
if (typeof date == "number" || typeof date == "string" || date == null) date = new Date(date);
|
|
479
|
-
let t;
|
|
480
|
-
if (tz == null) tz = -(date.getTimezoneOffset() / 60);
|
|
481
|
-
t = timezones.find((t2) => isNaN(tz) ? t2[0] == tz : t2[1] == tz);
|
|
482
|
-
if (!t) throw new Error(`Unknown timezone: ${tz}`);
|
|
483
|
-
date = adjustTz(date, t[1]);
|
|
484
|
-
const tokens = {
|
|
485
|
-
"YYYY": date.getFullYear().toString(),
|
|
486
|
-
"YY": date.getFullYear().toString().slice(2),
|
|
487
|
-
"MMMM": month(date.getMonth()),
|
|
488
|
-
"MMM": month(date.getMonth()).slice(0, 3),
|
|
489
|
-
"MM": (date.getMonth() + 1).toString().padStart(2, "0"),
|
|
490
|
-
"M": (date.getMonth() + 1).toString(),
|
|
491
|
-
"DDD": doy(date).toString(),
|
|
492
|
-
"DD": date.getDate().toString().padStart(2, "0"),
|
|
493
|
-
"Do": suffix(date.getDate()),
|
|
494
|
-
"D": date.getDate().toString(),
|
|
495
|
-
"dddd": day(date.getDay()),
|
|
496
|
-
"ddd": day(date.getDay()).slice(0, 3),
|
|
497
|
-
"HH": date.getHours().toString().padStart(2, "0"),
|
|
498
|
-
"H": date.getHours().toString(),
|
|
499
|
-
"hh": (date.getHours() % 12 || 12).toString().padStart(2, "0"),
|
|
500
|
-
"h": (date.getHours() % 12 || 12).toString(),
|
|
501
|
-
"mm": date.getMinutes().toString().padStart(2, "0"),
|
|
502
|
-
"m": date.getMinutes().toString(),
|
|
503
|
-
"ss": date.getSeconds().toString().padStart(2, "0"),
|
|
504
|
-
"s": date.getSeconds().toString(),
|
|
505
|
-
"SSS": date.getMilliseconds().toString().padStart(3, "0"),
|
|
506
|
-
"A": date.getHours() >= 12 ? "PM" : "AM",
|
|
507
|
-
"a": date.getHours() >= 12 ? "pm" : "am",
|
|
508
|
-
"ZZ": tzOffset(t[1] * 60).replace(":", ""),
|
|
509
|
-
"Z": tzOffset(t[1] * 60),
|
|
510
|
-
"z": typeof tz == "string" ? tz : t[0]
|
|
511
|
-
};
|
|
512
|
-
return format.replace(/YYYY|YY|MMMM|MMM|MM|M|DDD|DD|Do|D|dddd|ddd|HH|H|hh|h|mm|m|ss|s|SSS|A|a|ZZ|Z|z/g, (token) => tokens[token]);
|
|
513
|
-
}
|
|
514
|
-
function instantInterval(fn2, interval) {
|
|
515
|
-
fn2();
|
|
516
|
-
return setInterval(fn2, interval);
|
|
517
|
-
}
|
|
518
|
-
function sleep(ms) {
|
|
519
|
-
return new Promise((res) => setTimeout(res, ms));
|
|
520
|
-
}
|
|
521
|
-
async function sleepWhile(fn2, checkInterval = 100) {
|
|
522
|
-
while (await fn2()) await sleep(checkInterval);
|
|
523
|
-
}
|
|
524
|
-
function timeUntil(date) {
|
|
525
|
-
return (date instanceof Date ? date.getTime() : date) - (/* @__PURE__ */ new Date()).getTime();
|
|
526
|
-
}
|
|
527
|
-
function timezoneOffset(tz, date = /* @__PURE__ */ new Date()) {
|
|
528
|
-
const dtf = new Intl.DateTimeFormat("en-US", {
|
|
529
|
-
timeZone: tz,
|
|
530
|
-
hour12: false,
|
|
531
|
-
year: "numeric",
|
|
532
|
-
month: "2-digit",
|
|
533
|
-
day: "2-digit",
|
|
534
|
-
hour: "2-digit",
|
|
535
|
-
minute: "2-digit",
|
|
536
|
-
second: "2-digit"
|
|
537
|
-
});
|
|
538
|
-
const parts = dtf.formatToParts(date);
|
|
539
|
-
const get = (type) => {
|
|
540
|
-
var _a;
|
|
541
|
-
return Number((_a = parts.find((v) => v.type === type)) == null ? void 0 : _a.value);
|
|
542
|
-
};
|
|
543
|
-
const y = get("year");
|
|
544
|
-
const mo = get("month");
|
|
545
|
-
const d = get("day");
|
|
546
|
-
const h = get("hour");
|
|
547
|
-
const m = get("minute");
|
|
548
|
-
const s = get("second");
|
|
549
|
-
const asUTC = Date.UTC(y, mo - 1, d, h, m, s);
|
|
550
|
-
const asLocal = date.getTime();
|
|
551
|
-
return Math.round((asLocal - asUTC) / 6e4);
|
|
552
|
-
}
|
|
553
|
-
class AsyncLock {
|
|
554
|
-
constructor() {
|
|
555
|
-
__publicField(this, "p", Promise.resolve());
|
|
556
|
-
}
|
|
557
|
-
run(fn2) {
|
|
558
|
-
const res = this.p.then(fn2, fn2);
|
|
559
|
-
this.p = res.then(() => {
|
|
560
|
-
}, () => {
|
|
561
|
-
});
|
|
562
|
-
return res;
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
class Database {
|
|
566
|
-
constructor(database, tables, version) {
|
|
567
|
-
__publicField(this, "schemaLock", new AsyncLock());
|
|
568
|
-
__publicField(this, "upgrading", false);
|
|
569
|
-
__publicField(this, "connection");
|
|
570
|
-
__publicField(this, "tables");
|
|
571
|
-
__publicField(this, "waitForUpgrade", () => sleepWhile(() => this.upgrading));
|
|
572
|
-
this.database = database;
|
|
573
|
-
this.version = version;
|
|
574
|
-
this.connection = new Promise((resolve, reject) => {
|
|
575
|
-
const req = indexedDB.open(this.database, this.version);
|
|
576
|
-
this.tables = !tables ? [] : tables.map((t) => {
|
|
577
|
-
t = typeof t == "object" ? t : { name: t };
|
|
578
|
-
return { ...t, name: t.name.toString() };
|
|
579
|
-
});
|
|
580
|
-
req.onerror = () => reject(req.error);
|
|
581
|
-
req.onsuccess = () => {
|
|
582
|
-
const db = req.result;
|
|
583
|
-
const existing = Array.from(db.objectStoreNames);
|
|
584
|
-
if (!tables) this.tables = existing.map((t) => {
|
|
585
|
-
const tx = db.transaction(t, "readonly");
|
|
586
|
-
const store = tx.objectStore(t);
|
|
587
|
-
return { name: t, key: store.keyPath };
|
|
588
|
-
});
|
|
589
|
-
const desired = new ASet((tables || []).map((t) => typeof t == "string" ? t : t.name));
|
|
590
|
-
if (tables && desired.symmetricDifference(new ASet(existing)).length) {
|
|
591
|
-
db.close();
|
|
592
|
-
Object.assign(this, new Database(this.database, this.tables, db.version + 1));
|
|
593
|
-
this.connection.then(resolve);
|
|
594
|
-
} else {
|
|
595
|
-
this.version = db.version;
|
|
596
|
-
resolve(db);
|
|
597
|
-
}
|
|
598
|
-
this.upgrading = false;
|
|
599
|
-
};
|
|
600
|
-
req.onupgradeneeded = () => {
|
|
601
|
-
this.upgrading = true;
|
|
602
|
-
const db = req.result;
|
|
603
|
-
const existingTables = new ASet(Array.from(db.objectStoreNames));
|
|
604
|
-
if (tables) {
|
|
605
|
-
const desired = new ASet((tables || []).map((t) => typeof t == "string" ? t : t.name));
|
|
606
|
-
existingTables.difference(desired).forEach((name) => db.deleteObjectStore(name));
|
|
607
|
-
desired.difference(existingTables).forEach((name) => {
|
|
608
|
-
const t = this.tables.find(findByProp("name", name));
|
|
609
|
-
db.createObjectStore(name, {
|
|
610
|
-
keyPath: t == null ? void 0 : t.key,
|
|
611
|
-
autoIncrement: (t == null ? void 0 : t.autoIncrement) || !(t == null ? void 0 : t.key)
|
|
612
|
-
});
|
|
613
|
-
});
|
|
614
|
-
}
|
|
615
|
-
};
|
|
616
|
-
});
|
|
617
|
-
}
|
|
618
|
-
get ready() {
|
|
619
|
-
return !this.upgrading;
|
|
620
|
-
}
|
|
621
|
-
async createTable(table) {
|
|
622
|
-
return this.schemaLock.run(async () => {
|
|
623
|
-
if (typeof table == "string") table = { name: table };
|
|
624
|
-
const conn = await this.connection;
|
|
625
|
-
if (!this.includes(table.name)) {
|
|
626
|
-
const newDb = new Database(this.database, [...this.tables, table], (this.version ?? 0) + 1);
|
|
627
|
-
conn.close();
|
|
628
|
-
Object.assign(this, newDb);
|
|
629
|
-
await this.connection;
|
|
630
|
-
}
|
|
631
|
-
return this.table(table.name);
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
|
-
async deleteTable(table) {
|
|
635
|
-
return this.schemaLock.run(async () => {
|
|
636
|
-
if (typeof table == "string") table = { name: table };
|
|
637
|
-
if (!this.includes(table.name)) return;
|
|
638
|
-
const conn = await this.connection;
|
|
639
|
-
const newDb = new Database(this.database, this.tables.filter((t) => t.name != table.name), (this.version ?? 0) + 1);
|
|
640
|
-
conn.close();
|
|
641
|
-
Object.assign(this, newDb);
|
|
642
|
-
await this.connection;
|
|
643
|
-
});
|
|
644
|
-
}
|
|
645
|
-
includes(name) {
|
|
646
|
-
return !!this.tables.find((t) => t.name == (typeof name == "object" ? name.name : name.toString()));
|
|
647
|
-
}
|
|
648
|
-
table(name) {
|
|
649
|
-
return new Table(this, name.toString());
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
class Table {
|
|
653
|
-
constructor(database, name, key = "id") {
|
|
654
|
-
__publicField(this, "all", this.getAll);
|
|
655
|
-
__publicField(this, "create", this.add);
|
|
656
|
-
__publicField(this, "update", this.set);
|
|
657
|
-
this.database = database;
|
|
658
|
-
this.name = name;
|
|
659
|
-
this.key = key;
|
|
660
|
-
this.database.connection.then(() => {
|
|
661
|
-
const exists = !!this.database.tables.find(findByProp("name", this.name));
|
|
662
|
-
if (!exists) this.database.createTable(this.name);
|
|
663
|
-
});
|
|
664
|
-
}
|
|
665
|
-
async tx(table, fn2, readonly = false) {
|
|
666
|
-
await this.database.waitForUpgrade();
|
|
667
|
-
const db = await this.database.connection;
|
|
668
|
-
const tx = db.transaction(table, readonly ? "readonly" : "readwrite");
|
|
669
|
-
const store = tx.objectStore(table);
|
|
670
|
-
return new Promise((resolve, reject) => {
|
|
671
|
-
const request = fn2(store);
|
|
672
|
-
request.onsuccess = () => resolve(request.result);
|
|
673
|
-
request.onerror = () => reject(request.error);
|
|
674
|
-
});
|
|
675
|
-
}
|
|
676
|
-
add(value, key) {
|
|
677
|
-
return this.tx(this.name, (store) => store.add(value, key));
|
|
678
|
-
}
|
|
679
|
-
clear() {
|
|
680
|
-
return this.tx(this.name, (store) => store.clear());
|
|
681
|
-
}
|
|
682
|
-
count() {
|
|
683
|
-
return this.tx(this.name, (store) => store.count(), true);
|
|
684
|
-
}
|
|
685
|
-
delete(key) {
|
|
686
|
-
return this.tx(this.name, (store) => store.delete(key));
|
|
687
|
-
}
|
|
688
|
-
get(key) {
|
|
689
|
-
return this.tx(this.name, (store) => store.get(key), true);
|
|
690
|
-
}
|
|
691
|
-
getAll() {
|
|
692
|
-
return this.tx(this.name, (store) => store.getAll(), true);
|
|
693
|
-
}
|
|
694
|
-
getAllKeys() {
|
|
695
|
-
return this.tx(this.name, (store) => store.getAllKeys(), true);
|
|
696
|
-
}
|
|
697
|
-
put(key, value) {
|
|
698
|
-
return this.tx(this.name, (store) => store.put(value, key));
|
|
699
|
-
}
|
|
700
|
-
read(key) {
|
|
701
|
-
return key ? this.get(key) : this.getAll();
|
|
702
|
-
}
|
|
703
|
-
set(value, key) {
|
|
704
|
-
if (!key && !value[this.key]) return this.add(value);
|
|
705
|
-
return this.put(key || value[this.key], value);
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
399
|
class Cache {
|
|
709
400
|
/**
|
|
710
401
|
* Create new cache
|
|
@@ -765,9 +456,10 @@ ${opts.message || this.desc}`;
|
|
|
765
456
|
return value[this.key];
|
|
766
457
|
}
|
|
767
458
|
save(key) {
|
|
459
|
+
var _a, _b;
|
|
768
460
|
const persists = this.options.persistentStorage;
|
|
769
461
|
if (!!(persists == null ? void 0 : persists.storage)) {
|
|
770
|
-
if (persists.storage
|
|
462
|
+
if (((_a = persists.storage) == null ? void 0 : _a.constructor.name) == "Database") {
|
|
771
463
|
persists.storage.createTable({ name: persists.storage.key, key: this.key }).then((table) => {
|
|
772
464
|
if (key) {
|
|
773
465
|
table.set(key, this.get(key));
|
|
@@ -776,7 +468,7 @@ ${opts.message || this.desc}`;
|
|
|
776
468
|
this.all().forEach((row) => table.add(row));
|
|
777
469
|
}
|
|
778
470
|
});
|
|
779
|
-
} else {
|
|
471
|
+
} else if (((_b = persists.storage) == null ? void 0 : _b.constructor.name) == "Storage") {
|
|
780
472
|
persists.storage.setItem(persists.storage.key, JSONSanitize(this.all(true)));
|
|
781
473
|
}
|
|
782
474
|
}
|
|
@@ -1052,87 +744,396 @@ ${opts.message || this.desc}`;
|
|
|
1052
744
|
function md5_gg(d, _, m, f, r, i, n) {
|
|
1053
745
|
return md5_cmn(_ & f | m & ~f, d, _, r, i, n);
|
|
1054
746
|
}
|
|
1055
|
-
function md5_hh(d, _, m, f, r, i, n) {
|
|
1056
|
-
return md5_cmn(_ ^ m ^ f, d, _, r, i, n);
|
|
747
|
+
function md5_hh(d, _, m, f, r, i, n) {
|
|
748
|
+
return md5_cmn(_ ^ m ^ f, d, _, r, i, n);
|
|
749
|
+
}
|
|
750
|
+
function md5_ii(d, _, m, f, r, i, n) {
|
|
751
|
+
return md5_cmn(m ^ (_ | ~f), d, _, r, i, n);
|
|
752
|
+
}
|
|
753
|
+
function safe_add(d, _) {
|
|
754
|
+
var m = (65535 & d) + (65535 & _);
|
|
755
|
+
return (d >> 16) + (_ >> 16) + (m >> 16) << 16 | 65535 & m;
|
|
756
|
+
}
|
|
757
|
+
function bit_rol(d, _) {
|
|
758
|
+
return d << _ | d >>> 32 - _;
|
|
759
|
+
}
|
|
760
|
+
function wordSegments(str) {
|
|
761
|
+
if (!str) return [];
|
|
762
|
+
return str.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/([0-9]+)([a-zA-Z])/g, "$1 $2").replace(/([a-zA-Z])([0-9]+)/g, "$1 $2").replace(/[_\-\s]+/g, " ").trim().split(/\s+/).filter(Boolean);
|
|
763
|
+
}
|
|
764
|
+
function validateEmail(email) {
|
|
765
|
+
return /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/.test(email);
|
|
766
|
+
}
|
|
767
|
+
function fromCsv(csv, hasHeaders = true) {
|
|
768
|
+
var _a;
|
|
769
|
+
function parseLine(line) {
|
|
770
|
+
const columns = [];
|
|
771
|
+
let current = "", inQuotes2 = false;
|
|
772
|
+
for (let i = 0; i < line.length; i++) {
|
|
773
|
+
const char = line[i];
|
|
774
|
+
const nextChar = line[i + 1];
|
|
775
|
+
if (char === '"') {
|
|
776
|
+
if (inQuotes2 && nextChar === '"') {
|
|
777
|
+
current += '"';
|
|
778
|
+
i++;
|
|
779
|
+
} else inQuotes2 = !inQuotes2;
|
|
780
|
+
} else if (char === "," && !inQuotes2) {
|
|
781
|
+
columns.push(current.trim());
|
|
782
|
+
current = "";
|
|
783
|
+
} else current += char;
|
|
784
|
+
}
|
|
785
|
+
columns.push(current.trim());
|
|
786
|
+
return columns.map((col) => col.replace(/^"|"$/g, "").replace(/""/g, '"'));
|
|
787
|
+
}
|
|
788
|
+
const rows = [];
|
|
789
|
+
let currentRow = "", inQuotes = false;
|
|
790
|
+
for (const char of csv.replace(/\r\n/g, "\n")) {
|
|
791
|
+
if (char === '"') inQuotes = !inQuotes;
|
|
792
|
+
if (char === "\n" && !inQuotes) {
|
|
793
|
+
rows.push(currentRow.trim());
|
|
794
|
+
currentRow = "";
|
|
795
|
+
} else currentRow += char;
|
|
796
|
+
}
|
|
797
|
+
if (currentRow) rows.push(currentRow.trim());
|
|
798
|
+
let headers = hasHeaders ? rows.splice(0, 1)[0] : null;
|
|
799
|
+
if (headers) headers = (_a = headers.match(/(?:[^,"']+|"(?:[^"]|"")*"|'(?:[^']|'')*')+/g)) == null ? void 0 : _a.map((h) => h.trim());
|
|
800
|
+
return rows.map((r) => {
|
|
801
|
+
const props = parseLine(r);
|
|
802
|
+
const h = headers || Array(props.length).fill(null).map((_, i) => {
|
|
803
|
+
let letter = "";
|
|
804
|
+
const first = i / 26;
|
|
805
|
+
if (first > 1) letter += LETTER_LIST[Math.floor(first - 1)];
|
|
806
|
+
letter += LETTER_LIST[i % 26];
|
|
807
|
+
return letter;
|
|
808
|
+
});
|
|
809
|
+
return h.reduce((acc, h2, i) => {
|
|
810
|
+
dotNotation(acc, h2, props[i]);
|
|
811
|
+
return acc;
|
|
812
|
+
}, {});
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
function toCsv(target, flatten = true) {
|
|
816
|
+
const t = makeArray(target);
|
|
817
|
+
const headers = new ASet(t.reduce((acc, row) => [...acc, ...Object.keys(flatten ? flattenObj(row) : row)], []));
|
|
818
|
+
return [
|
|
819
|
+
headers.join(","),
|
|
820
|
+
...t.map((row) => headers.map((h) => {
|
|
821
|
+
const value = dotNotation(row, h);
|
|
822
|
+
if (value == null) return "";
|
|
823
|
+
if (typeof value == "object") return `"${JSONSanitize(value).replaceAll('"', '""')}"`;
|
|
824
|
+
if (typeof value == "string" && /[\n",]/g.test(value)) return `"${value.replaceAll('"', '""')}"`;
|
|
825
|
+
return value;
|
|
826
|
+
}).join(","))
|
|
827
|
+
].join("\n");
|
|
828
|
+
}
|
|
829
|
+
function adjustedInterval(cb, ms) {
|
|
830
|
+
let cancel = false, timeout = null;
|
|
831
|
+
const p = async () => {
|
|
832
|
+
if (cancel) return;
|
|
833
|
+
const start = (/* @__PURE__ */ new Date()).getTime();
|
|
834
|
+
await cb();
|
|
835
|
+
const end = (/* @__PURE__ */ new Date()).getTime();
|
|
836
|
+
timeout = setTimeout(() => p(), ms - (end - start) || 1);
|
|
837
|
+
};
|
|
838
|
+
p();
|
|
839
|
+
return () => {
|
|
840
|
+
cancel = true;
|
|
841
|
+
if (timeout) clearTimeout(timeout);
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
function formatDate(format = "YYYY-MM-DD H:mm", date = /* @__PURE__ */ new Date(), tz) {
|
|
845
|
+
const timezones = [
|
|
846
|
+
["IDLW", -12],
|
|
847
|
+
["SST", -11],
|
|
848
|
+
["HST", -10],
|
|
849
|
+
["AKST", -9],
|
|
850
|
+
["PST", -8],
|
|
851
|
+
["MST", -7],
|
|
852
|
+
["CST", -6],
|
|
853
|
+
["EST", -5],
|
|
854
|
+
["AST", -4],
|
|
855
|
+
["BRT", -3],
|
|
856
|
+
["MAT", -2],
|
|
857
|
+
["AZOT", -1],
|
|
858
|
+
["UTC", 0],
|
|
859
|
+
["CET", 1],
|
|
860
|
+
["EET", 2],
|
|
861
|
+
["MSK", 3],
|
|
862
|
+
["AST", 4],
|
|
863
|
+
["PKT", 5],
|
|
864
|
+
["IST", 5.5],
|
|
865
|
+
["BST", 6],
|
|
866
|
+
["ICT", 7],
|
|
867
|
+
["CST", 8],
|
|
868
|
+
["JST", 9],
|
|
869
|
+
["AEST", 10],
|
|
870
|
+
["SBT", 11],
|
|
871
|
+
["FJT", 12],
|
|
872
|
+
["TOT", 13],
|
|
873
|
+
["LINT", 14]
|
|
874
|
+
];
|
|
875
|
+
function adjustTz(date2, gmt) {
|
|
876
|
+
const currentOffset = date2.getTimezoneOffset();
|
|
877
|
+
const adjustedOffset = gmt * 60;
|
|
878
|
+
return new Date(date2.getTime() + (adjustedOffset + currentOffset) * 6e4);
|
|
879
|
+
}
|
|
880
|
+
function day(num) {
|
|
881
|
+
return ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][num] || "Unknown";
|
|
882
|
+
}
|
|
883
|
+
function doy(date2) {
|
|
884
|
+
const start = /* @__PURE__ */ new Date(`${date2.getFullYear()}-01-01 0:00:00`);
|
|
885
|
+
return Math.ceil((date2.getTime() - start.getTime()) / (1e3 * 60 * 60 * 24));
|
|
886
|
+
}
|
|
887
|
+
function month(num) {
|
|
888
|
+
return ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"][num] || "Unknown";
|
|
889
|
+
}
|
|
890
|
+
function suffix(num) {
|
|
891
|
+
if (num % 100 >= 11 && num % 100 <= 13) return `${num}th`;
|
|
892
|
+
switch (num % 10) {
|
|
893
|
+
case 1:
|
|
894
|
+
return `${num}st`;
|
|
895
|
+
case 2:
|
|
896
|
+
return `${num}nd`;
|
|
897
|
+
case 3:
|
|
898
|
+
return `${num}rd`;
|
|
899
|
+
default:
|
|
900
|
+
return `${num}th`;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
function tzOffset(offset) {
|
|
904
|
+
const hours = ~~(offset / 60);
|
|
905
|
+
const minutes = offset % 60;
|
|
906
|
+
return (offset > 0 ? "-" : "") + `${hours}:${minutes.toString().padStart(2, "0")}`;
|
|
907
|
+
}
|
|
908
|
+
if (typeof date == "number" || typeof date == "string" || date == null) date = new Date(date);
|
|
909
|
+
let t;
|
|
910
|
+
if (tz == null) tz = -(date.getTimezoneOffset() / 60);
|
|
911
|
+
t = timezones.find((t2) => isNaN(tz) ? t2[0] == tz : t2[1] == tz);
|
|
912
|
+
if (!t) throw new Error(`Unknown timezone: ${tz}`);
|
|
913
|
+
date = adjustTz(date, t[1]);
|
|
914
|
+
const tokens = {
|
|
915
|
+
"YYYY": date.getFullYear().toString(),
|
|
916
|
+
"YY": date.getFullYear().toString().slice(2),
|
|
917
|
+
"MMMM": month(date.getMonth()),
|
|
918
|
+
"MMM": month(date.getMonth()).slice(0, 3),
|
|
919
|
+
"MM": (date.getMonth() + 1).toString().padStart(2, "0"),
|
|
920
|
+
"M": (date.getMonth() + 1).toString(),
|
|
921
|
+
"DDD": doy(date).toString(),
|
|
922
|
+
"DD": date.getDate().toString().padStart(2, "0"),
|
|
923
|
+
"Do": suffix(date.getDate()),
|
|
924
|
+
"D": date.getDate().toString(),
|
|
925
|
+
"dddd": day(date.getDay()),
|
|
926
|
+
"ddd": day(date.getDay()).slice(0, 3),
|
|
927
|
+
"HH": date.getHours().toString().padStart(2, "0"),
|
|
928
|
+
"H": date.getHours().toString(),
|
|
929
|
+
"hh": (date.getHours() % 12 || 12).toString().padStart(2, "0"),
|
|
930
|
+
"h": (date.getHours() % 12 || 12).toString(),
|
|
931
|
+
"mm": date.getMinutes().toString().padStart(2, "0"),
|
|
932
|
+
"m": date.getMinutes().toString(),
|
|
933
|
+
"ss": date.getSeconds().toString().padStart(2, "0"),
|
|
934
|
+
"s": date.getSeconds().toString(),
|
|
935
|
+
"SSS": date.getMilliseconds().toString().padStart(3, "0"),
|
|
936
|
+
"A": date.getHours() >= 12 ? "PM" : "AM",
|
|
937
|
+
"a": date.getHours() >= 12 ? "pm" : "am",
|
|
938
|
+
"ZZ": tzOffset(t[1] * 60).replace(":", ""),
|
|
939
|
+
"Z": tzOffset(t[1] * 60),
|
|
940
|
+
"z": typeof tz == "string" ? tz : t[0]
|
|
941
|
+
};
|
|
942
|
+
return format.replace(/YYYY|YY|MMMM|MMM|MM|M|DDD|DD|Do|D|dddd|ddd|HH|H|hh|h|mm|m|ss|s|SSS|A|a|ZZ|Z|z/g, (token) => tokens[token]);
|
|
943
|
+
}
|
|
944
|
+
function instantInterval(fn2, interval) {
|
|
945
|
+
fn2();
|
|
946
|
+
return setInterval(fn2, interval);
|
|
1057
947
|
}
|
|
1058
|
-
function
|
|
1059
|
-
return
|
|
948
|
+
function sleep(ms) {
|
|
949
|
+
return new Promise((res) => setTimeout(res, ms));
|
|
1060
950
|
}
|
|
1061
|
-
function
|
|
1062
|
-
|
|
1063
|
-
return (d >> 16) + (_ >> 16) + (m >> 16) << 16 | 65535 & m;
|
|
951
|
+
async function sleepWhile(fn2, checkInterval = 100) {
|
|
952
|
+
while (await fn2()) await sleep(checkInterval);
|
|
1064
953
|
}
|
|
1065
|
-
function
|
|
1066
|
-
return
|
|
954
|
+
function timeUntil(date) {
|
|
955
|
+
return (date instanceof Date ? date.getTime() : date) - (/* @__PURE__ */ new Date()).getTime();
|
|
1067
956
|
}
|
|
1068
|
-
function
|
|
1069
|
-
|
|
1070
|
-
|
|
957
|
+
function timezoneOffset(tz, date = /* @__PURE__ */ new Date()) {
|
|
958
|
+
const dtf = new Intl.DateTimeFormat("en-US", {
|
|
959
|
+
timeZone: tz,
|
|
960
|
+
hour12: false,
|
|
961
|
+
year: "numeric",
|
|
962
|
+
month: "2-digit",
|
|
963
|
+
day: "2-digit",
|
|
964
|
+
hour: "2-digit",
|
|
965
|
+
minute: "2-digit",
|
|
966
|
+
second: "2-digit"
|
|
967
|
+
});
|
|
968
|
+
const parts = dtf.formatToParts(date);
|
|
969
|
+
const get = (type) => {
|
|
970
|
+
var _a;
|
|
971
|
+
return Number((_a = parts.find((v) => v.type === type)) == null ? void 0 : _a.value);
|
|
972
|
+
};
|
|
973
|
+
const y = get("year");
|
|
974
|
+
const mo = get("month");
|
|
975
|
+
const d = get("day");
|
|
976
|
+
const h = get("hour");
|
|
977
|
+
const m = get("minute");
|
|
978
|
+
const s = get("second");
|
|
979
|
+
const asUTC = Date.UTC(y, mo - 1, d, h, m, s);
|
|
980
|
+
const asLocal = date.getTime();
|
|
981
|
+
return Math.round((asLocal - asUTC) / 6e4);
|
|
1071
982
|
}
|
|
1072
|
-
|
|
1073
|
-
|
|
983
|
+
class AsyncLock {
|
|
984
|
+
constructor() {
|
|
985
|
+
__publicField(this, "p", Promise.resolve());
|
|
986
|
+
}
|
|
987
|
+
run(fn2) {
|
|
988
|
+
const res = this.p.then(fn2, fn2);
|
|
989
|
+
this.p = res.then(() => {
|
|
990
|
+
}, () => {
|
|
991
|
+
});
|
|
992
|
+
return res;
|
|
993
|
+
}
|
|
1074
994
|
}
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
995
|
+
class Database {
|
|
996
|
+
constructor(database, tables, version) {
|
|
997
|
+
__publicField(this, "schemaLock", new AsyncLock());
|
|
998
|
+
__publicField(this, "upgrading", false);
|
|
999
|
+
__publicField(this, "connection");
|
|
1000
|
+
__publicField(this, "tables");
|
|
1001
|
+
__publicField(this, "waitForUpgrade", () => sleepWhile(() => this.upgrading));
|
|
1002
|
+
this.database = database;
|
|
1003
|
+
this.version = version;
|
|
1004
|
+
this.connection = new Promise((resolve, reject) => {
|
|
1005
|
+
const req = indexedDB.open(this.database, this.version);
|
|
1006
|
+
this.tables = !tables ? [] : tables.map((t) => {
|
|
1007
|
+
t = typeof t == "object" ? t : { name: t };
|
|
1008
|
+
return { ...t, name: t.name.toString() };
|
|
1009
|
+
});
|
|
1010
|
+
req.onerror = () => reject(req.error);
|
|
1011
|
+
req.onsuccess = () => {
|
|
1012
|
+
const db = req.result;
|
|
1013
|
+
const existing = Array.from(db.objectStoreNames);
|
|
1014
|
+
if (!tables) this.tables = existing.map((t) => {
|
|
1015
|
+
const tx = db.transaction(t, "readonly");
|
|
1016
|
+
const store = tx.objectStore(t);
|
|
1017
|
+
return { name: t, key: store.keyPath };
|
|
1018
|
+
});
|
|
1019
|
+
const desired = new ASet((tables || []).map((t) => typeof t == "string" ? t : t.name));
|
|
1020
|
+
if (tables && desired.symmetricDifference(new ASet(existing)).length) {
|
|
1021
|
+
db.close();
|
|
1022
|
+
Object.assign(this, new Database(this.database, this.tables, db.version + 1));
|
|
1023
|
+
this.connection.then(resolve);
|
|
1024
|
+
} else {
|
|
1025
|
+
this.version = db.version;
|
|
1026
|
+
resolve(db);
|
|
1027
|
+
}
|
|
1028
|
+
this.upgrading = false;
|
|
1029
|
+
};
|
|
1030
|
+
req.onupgradeneeded = () => {
|
|
1031
|
+
this.upgrading = true;
|
|
1032
|
+
const db = req.result;
|
|
1033
|
+
const existingTables = new ASet(Array.from(db.objectStoreNames));
|
|
1034
|
+
if (tables) {
|
|
1035
|
+
const desired = new ASet((tables || []).map((t) => typeof t == "string" ? t : t.name));
|
|
1036
|
+
existingTables.difference(desired).forEach((name) => db.deleteObjectStore(name));
|
|
1037
|
+
desired.difference(existingTables).forEach((name) => {
|
|
1038
|
+
const t = this.tables.find(findByProp("name", name));
|
|
1039
|
+
db.createObjectStore(name, {
|
|
1040
|
+
keyPath: t == null ? void 0 : t.key,
|
|
1041
|
+
autoIncrement: (t == null ? void 0 : t.autoIncrement) || !(t == null ? void 0 : t.key)
|
|
1042
|
+
});
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
};
|
|
1046
|
+
});
|
|
1095
1047
|
}
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
for (const char of csv.replace(/\r\n/g, "\n")) {
|
|
1099
|
-
if (char === '"') inQuotes = !inQuotes;
|
|
1100
|
-
if (char === "\n" && !inQuotes) {
|
|
1101
|
-
rows.push(currentRow.trim());
|
|
1102
|
-
currentRow = "";
|
|
1103
|
-
} else currentRow += char;
|
|
1048
|
+
get ready() {
|
|
1049
|
+
return !this.upgrading;
|
|
1104
1050
|
}
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
return
|
|
1051
|
+
async createTable(table) {
|
|
1052
|
+
return this.schemaLock.run(async () => {
|
|
1053
|
+
if (typeof table == "string") table = { name: table };
|
|
1054
|
+
const conn = await this.connection;
|
|
1055
|
+
if (!this.includes(table.name)) {
|
|
1056
|
+
const newDb = new Database(this.database, [...this.tables, table], (this.version ?? 0) + 1);
|
|
1057
|
+
conn.close();
|
|
1058
|
+
Object.assign(this, newDb);
|
|
1059
|
+
await this.connection;
|
|
1060
|
+
}
|
|
1061
|
+
return this.table(table.name);
|
|
1116
1062
|
});
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1063
|
+
}
|
|
1064
|
+
async deleteTable(table) {
|
|
1065
|
+
return this.schemaLock.run(async () => {
|
|
1066
|
+
if (typeof table == "string") table = { name: table };
|
|
1067
|
+
if (!this.includes(table.name)) return;
|
|
1068
|
+
const conn = await this.connection;
|
|
1069
|
+
const newDb = new Database(this.database, this.tables.filter((t) => t.name != table.name), (this.version ?? 0) + 1);
|
|
1070
|
+
conn.close();
|
|
1071
|
+
Object.assign(this, newDb);
|
|
1072
|
+
await this.connection;
|
|
1073
|
+
});
|
|
1074
|
+
}
|
|
1075
|
+
includes(name) {
|
|
1076
|
+
return !!this.tables.find((t) => t.name == (typeof name == "object" ? name.name : name.toString()));
|
|
1077
|
+
}
|
|
1078
|
+
table(name) {
|
|
1079
|
+
return new Table(this, name.toString());
|
|
1080
|
+
}
|
|
1122
1081
|
}
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
})
|
|
1135
|
-
|
|
1082
|
+
class Table {
|
|
1083
|
+
constructor(database, name, key = "id") {
|
|
1084
|
+
__publicField(this, "all", this.getAll);
|
|
1085
|
+
__publicField(this, "create", this.add);
|
|
1086
|
+
__publicField(this, "update", this.set);
|
|
1087
|
+
this.database = database;
|
|
1088
|
+
this.name = name;
|
|
1089
|
+
this.key = key;
|
|
1090
|
+
this.database.connection.then(() => {
|
|
1091
|
+
const exists = !!this.database.tables.find(findByProp("name", this.name));
|
|
1092
|
+
if (!exists) this.database.createTable(this.name);
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1095
|
+
async tx(table, fn2, readonly = false) {
|
|
1096
|
+
await this.database.waitForUpgrade();
|
|
1097
|
+
const db = await this.database.connection;
|
|
1098
|
+
const tx = db.transaction(table, readonly ? "readonly" : "readwrite");
|
|
1099
|
+
const store = tx.objectStore(table);
|
|
1100
|
+
return new Promise((resolve, reject) => {
|
|
1101
|
+
const request = fn2(store);
|
|
1102
|
+
request.onsuccess = () => resolve(request.result);
|
|
1103
|
+
request.onerror = () => reject(request.error);
|
|
1104
|
+
});
|
|
1105
|
+
}
|
|
1106
|
+
add(value, key) {
|
|
1107
|
+
return this.tx(this.name, (store) => store.add(value, key));
|
|
1108
|
+
}
|
|
1109
|
+
clear() {
|
|
1110
|
+
return this.tx(this.name, (store) => store.clear());
|
|
1111
|
+
}
|
|
1112
|
+
count() {
|
|
1113
|
+
return this.tx(this.name, (store) => store.count(), true);
|
|
1114
|
+
}
|
|
1115
|
+
delete(key) {
|
|
1116
|
+
return this.tx(this.name, (store) => store.delete(key));
|
|
1117
|
+
}
|
|
1118
|
+
get(key) {
|
|
1119
|
+
return this.tx(this.name, (store) => store.get(key), true);
|
|
1120
|
+
}
|
|
1121
|
+
getAll() {
|
|
1122
|
+
return this.tx(this.name, (store) => store.getAll(), true);
|
|
1123
|
+
}
|
|
1124
|
+
getAllKeys() {
|
|
1125
|
+
return this.tx(this.name, (store) => store.getAllKeys(), true);
|
|
1126
|
+
}
|
|
1127
|
+
put(key, value) {
|
|
1128
|
+
return this.tx(this.name, (store) => store.put(value, key));
|
|
1129
|
+
}
|
|
1130
|
+
read(key) {
|
|
1131
|
+
return key ? this.get(key) : this.getAll();
|
|
1132
|
+
}
|
|
1133
|
+
set(value, key) {
|
|
1134
|
+
if (!key && !value[this.key]) return this.add(value);
|
|
1135
|
+
return this.put(key || value[this.key], value);
|
|
1136
|
+
}
|
|
1136
1137
|
}
|
|
1137
1138
|
class PromiseProgress extends Promise {
|
|
1138
1139
|
constructor(executor) {
|