edmaxlabs-core 2.4.9 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +332 -383
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.mjs +332 -383
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -32,12 +32,13 @@ module.exports = __toCommonJS(src_exports);
|
|
|
32
32
|
|
|
33
33
|
// src/authentication/Credentials.ts
|
|
34
34
|
var Credentials = class _Credentials {
|
|
35
|
-
constructor(uid, displayInfo, createdAt, updatedAt, lastLogged) {
|
|
35
|
+
constructor(uid, displayInfo, createdAt, updatedAt, lastLogged, logged) {
|
|
36
36
|
this.uid = uid;
|
|
37
37
|
this.displayInfo = displayInfo;
|
|
38
38
|
this.createdAt = createdAt;
|
|
39
39
|
this.updatedAt = updatedAt;
|
|
40
40
|
this.lastLogged = lastLogged;
|
|
41
|
+
this.logged = logged === true;
|
|
41
42
|
}
|
|
42
43
|
static fromMap(map) {
|
|
43
44
|
const uid = map.id ?? map.uid ?? "";
|
|
@@ -46,12 +47,14 @@ var Credentials = class _Credentials {
|
|
|
46
47
|
const createdAt = data.createdAt;
|
|
47
48
|
const updatedAt = data.updatedAt;
|
|
48
49
|
const lastLogged = data.lastLogged;
|
|
50
|
+
const logged = data.logged;
|
|
49
51
|
const result = new _Credentials(
|
|
50
52
|
uid,
|
|
51
53
|
d_info,
|
|
52
54
|
createdAt,
|
|
53
55
|
updatedAt,
|
|
54
|
-
lastLogged
|
|
56
|
+
lastLogged,
|
|
57
|
+
logged
|
|
55
58
|
);
|
|
56
59
|
return result;
|
|
57
60
|
}
|
|
@@ -61,7 +64,8 @@ var Credentials = class _Credentials {
|
|
|
61
64
|
displayInfo: this.displayInfo,
|
|
62
65
|
createdAt: this.createdAt,
|
|
63
66
|
updatedAt: this.updatedAt,
|
|
64
|
-
lastLogged: this.lastLogged
|
|
67
|
+
lastLogged: this.lastLogged,
|
|
68
|
+
logged: this.logged
|
|
65
69
|
};
|
|
66
70
|
}
|
|
67
71
|
};
|
|
@@ -158,9 +162,16 @@ var _Authentication = class _Authentication {
|
|
|
158
162
|
const userRef = await app?.collection("users").add({
|
|
159
163
|
email,
|
|
160
164
|
password,
|
|
161
|
-
token: this.client?.getConfig().token,
|
|
162
165
|
logged: true,
|
|
163
|
-
lastLogged: Date.now()
|
|
166
|
+
lastLogged: Date.now(),
|
|
167
|
+
displayInfo: {
|
|
168
|
+
firstname: email.split("@")[0],
|
|
169
|
+
lastname: "",
|
|
170
|
+
surname: "",
|
|
171
|
+
profile: "./logo.png",
|
|
172
|
+
email,
|
|
173
|
+
phone: ""
|
|
174
|
+
}
|
|
164
175
|
});
|
|
165
176
|
if (!userRef?.id || userRef?.id === "") {
|
|
166
177
|
throw new Error("Something went wrong try Again.");
|
|
@@ -190,13 +201,13 @@ var _Authentication = class _Authentication {
|
|
|
190
201
|
throw new Error("User Not Found.");
|
|
191
202
|
}
|
|
192
203
|
const _data = data[0];
|
|
193
|
-
await app?.collection("users").doc(
|
|
204
|
+
await app?.collection("users").doc(_data.id).update({
|
|
194
205
|
logged: true,
|
|
195
206
|
lastLogged: Date.now()
|
|
196
207
|
});
|
|
197
208
|
this.eUser = Credentials.fromMap(_data);
|
|
198
209
|
this.saveCredentials(this.eUser);
|
|
199
|
-
return Credentials.fromMap(
|
|
210
|
+
return Credentials.fromMap(_data);
|
|
200
211
|
};
|
|
201
212
|
this.deleteUser = async () => {
|
|
202
213
|
if (!this.eUser) {
|
|
@@ -321,6 +332,7 @@ var _Authentication = class _Authentication {
|
|
|
321
332
|
return;
|
|
322
333
|
userDocUnsubscribe = userRef.onSnapshot(
|
|
323
334
|
(snapshot, change) => {
|
|
335
|
+
console.log(snapshot);
|
|
324
336
|
if (change === "delete") {
|
|
325
337
|
this.saveCredentials(null);
|
|
326
338
|
onSignOut?.();
|
|
@@ -380,308 +392,6 @@ var DocumentSnapshot = class _DocumentSnapshot {
|
|
|
380
392
|
}
|
|
381
393
|
};
|
|
382
394
|
|
|
383
|
-
// src/database/Timestamp.ts
|
|
384
|
-
var Timestamp = class _Timestamp {
|
|
385
|
-
constructor(seconds, nanoseconds = 0) {
|
|
386
|
-
this.seconds = seconds;
|
|
387
|
-
this.nanoseconds = nanoseconds;
|
|
388
|
-
}
|
|
389
|
-
static now() {
|
|
390
|
-
return _Timestamp.fromMillis(Date.now());
|
|
391
|
-
}
|
|
392
|
-
static fromDate(date) {
|
|
393
|
-
return new _Timestamp(
|
|
394
|
-
Math.floor(date.getTime() / 1e3),
|
|
395
|
-
date.getTime() % 1e3 * 1e6
|
|
396
|
-
);
|
|
397
|
-
}
|
|
398
|
-
static fromMillis(ms) {
|
|
399
|
-
return new _Timestamp(Math.floor(ms / 1e3), ms % 1e3 * 1e6);
|
|
400
|
-
}
|
|
401
|
-
static fromMongo(dateObj) {
|
|
402
|
-
return _Timestamp.fromMillis(dateObj.getTime());
|
|
403
|
-
}
|
|
404
|
-
static fromJSON(obj) {
|
|
405
|
-
return new _Timestamp(obj.seconds, obj.nanoseconds);
|
|
406
|
-
}
|
|
407
|
-
toDate() {
|
|
408
|
-
return new Date(this.toMillis());
|
|
409
|
-
}
|
|
410
|
-
toMillis() {
|
|
411
|
-
return this.seconds * 1e3 + Math.floor(this.nanoseconds / 1e6);
|
|
412
|
-
}
|
|
413
|
-
sinceEpoch() {
|
|
414
|
-
return this.seconds;
|
|
415
|
-
}
|
|
416
|
-
toMongo() {
|
|
417
|
-
return new Date(this.toMillis());
|
|
418
|
-
}
|
|
419
|
-
format(pattern = "dd-MM-yyyy HH:mm:ss") {
|
|
420
|
-
const d = this.toDate();
|
|
421
|
-
const monthsShort = [
|
|
422
|
-
"Jan",
|
|
423
|
-
"Feb",
|
|
424
|
-
"Mar",
|
|
425
|
-
"Apr",
|
|
426
|
-
"May",
|
|
427
|
-
"Jun",
|
|
428
|
-
"Jul",
|
|
429
|
-
"Aug",
|
|
430
|
-
"Sep",
|
|
431
|
-
"Oct",
|
|
432
|
-
"Nov",
|
|
433
|
-
"Dec"
|
|
434
|
-
];
|
|
435
|
-
const monthsLong = [
|
|
436
|
-
"January",
|
|
437
|
-
"February",
|
|
438
|
-
"March",
|
|
439
|
-
"April",
|
|
440
|
-
"May",
|
|
441
|
-
"June",
|
|
442
|
-
"July",
|
|
443
|
-
"August",
|
|
444
|
-
"September",
|
|
445
|
-
"October",
|
|
446
|
-
"November",
|
|
447
|
-
"December"
|
|
448
|
-
];
|
|
449
|
-
const hours = d.getHours();
|
|
450
|
-
const hours12 = hours % 12 === 0 ? 12 : hours % 12;
|
|
451
|
-
const ampm = hours < 12 ? "AM" : "PM";
|
|
452
|
-
const map = {
|
|
453
|
-
dd: String(d.getDate()).padStart(2, "0"),
|
|
454
|
-
MM: String(d.getMonth() + 1).padStart(2, "0"),
|
|
455
|
-
yyyy: d.getFullYear(),
|
|
456
|
-
HH: String(d.getHours()).padStart(2, "0"),
|
|
457
|
-
mm: String(d.getMinutes()).padStart(2, "0"),
|
|
458
|
-
ss: String(d.getSeconds()).padStart(2, "0"),
|
|
459
|
-
SSS: String(d.getMilliseconds()).padStart(3, "0"),
|
|
460
|
-
MMM: monthsShort[d.getMonth()],
|
|
461
|
-
MMMM: monthsLong[d.getMonth()],
|
|
462
|
-
a: ampm.toLowerCase(),
|
|
463
|
-
// am/pm
|
|
464
|
-
A: ampm
|
|
465
|
-
// AM/PM
|
|
466
|
-
};
|
|
467
|
-
return pattern.replace(
|
|
468
|
-
/MMMM|MMM|dd|MM|yyyy|HH|mm|ss|SSS|a|A/g,
|
|
469
|
-
(match) => String(map[match])
|
|
470
|
-
);
|
|
471
|
-
}
|
|
472
|
-
compare(other) {
|
|
473
|
-
if (this.seconds !== other.seconds) {
|
|
474
|
-
return this.seconds - other.seconds;
|
|
475
|
-
}
|
|
476
|
-
return this.nanoseconds - other.nanoseconds;
|
|
477
|
-
}
|
|
478
|
-
relative(fmt = "dd-MM-yyyy HH:mm:ss") {
|
|
479
|
-
const now = Date.now();
|
|
480
|
-
const diff = now - this.toMillis();
|
|
481
|
-
const sec = Math.floor(diff / 1e3);
|
|
482
|
-
if (sec < 60)
|
|
483
|
-
return `${sec}s ago`;
|
|
484
|
-
const min = Math.floor(sec / 60);
|
|
485
|
-
if (min < 60)
|
|
486
|
-
return `${min}m ago`;
|
|
487
|
-
const hrs = Math.floor(min / 60);
|
|
488
|
-
if (hrs < 24)
|
|
489
|
-
return `${hrs}h ago`;
|
|
490
|
-
const days = Math.floor(hrs / 24);
|
|
491
|
-
if (days < 3)
|
|
492
|
-
return `${days}d ago`;
|
|
493
|
-
return this.format(fmt);
|
|
494
|
-
}
|
|
495
|
-
add({
|
|
496
|
-
seconds = 0,
|
|
497
|
-
minutes = 0,
|
|
498
|
-
hours = 0,
|
|
499
|
-
days = 0
|
|
500
|
-
}) {
|
|
501
|
-
const totalMs = seconds * 1e3 + minutes * 6e4 + hours * 36e5 + days * 864e5;
|
|
502
|
-
return _Timestamp.fromMillis(this.toMillis() + totalMs);
|
|
503
|
-
}
|
|
504
|
-
weekdayName() {
|
|
505
|
-
return ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][this.toDate().getDay()];
|
|
506
|
-
}
|
|
507
|
-
toJSON() {
|
|
508
|
-
return {
|
|
509
|
-
_type: "timestamp",
|
|
510
|
-
seconds: this.seconds,
|
|
511
|
-
nanoseconds: this.nanoseconds
|
|
512
|
-
};
|
|
513
|
-
}
|
|
514
|
-
toString() {
|
|
515
|
-
return this.format("yyyy-MM-dd HH:mm:ss");
|
|
516
|
-
}
|
|
517
|
-
};
|
|
518
|
-
|
|
519
|
-
// src/database/ArraySnapshot.ts
|
|
520
|
-
var ArraySnapshot = class _ArraySnapshot {
|
|
521
|
-
constructor(id = "", index, data, dt) {
|
|
522
|
-
this.data = data;
|
|
523
|
-
this.id = id;
|
|
524
|
-
this.dt = dt ?? Timestamp.now();
|
|
525
|
-
}
|
|
526
|
-
static fromMap(map) {
|
|
527
|
-
const index = map.index ?? map.index ?? -1;
|
|
528
|
-
const id = map.id ?? map._id ?? "";
|
|
529
|
-
const document2 = map.data ?? map.document ?? map;
|
|
530
|
-
return new _ArraySnapshot(id, index, document2);
|
|
531
|
-
}
|
|
532
|
-
toMap() {
|
|
533
|
-
return {
|
|
534
|
-
id: this.id ?? "",
|
|
535
|
-
data: this.data,
|
|
536
|
-
dt: this.dt
|
|
537
|
-
};
|
|
538
|
-
}
|
|
539
|
-
};
|
|
540
|
-
|
|
541
|
-
// src/database/Array.ts
|
|
542
|
-
var Array2 = class {
|
|
543
|
-
constructor(app, collection, key, id) {
|
|
544
|
-
this.app = app;
|
|
545
|
-
this.collection = collection;
|
|
546
|
-
this.key = key;
|
|
547
|
-
this.docID = id;
|
|
548
|
-
this.persistence = app.offline().persistence;
|
|
549
|
-
this.syncEngine = app.offline().syncEngine;
|
|
550
|
-
this.localStore = app.offline().localStore;
|
|
551
|
-
}
|
|
552
|
-
/**
|
|
553
|
-
* Get current array elements (offline-first: prefers local cache)
|
|
554
|
-
*/
|
|
555
|
-
async show() {
|
|
556
|
-
if (this.persistence) {
|
|
557
|
-
const doc = await this.persistence.getDoc(this.collection, this.docID);
|
|
558
|
-
if (doc?.exists && !doc.deleted) {
|
|
559
|
-
const arrayData = doc.data[this.key] || [];
|
|
560
|
-
return arrayData.map((item) => ArraySnapshot.fromMap(item));
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
if (typeof navigator === "undefined" || navigator.onLine) {
|
|
564
|
-
this.refreshFromRemote().catch(() => {
|
|
565
|
-
});
|
|
566
|
-
}
|
|
567
|
-
return [];
|
|
568
|
-
}
|
|
569
|
-
async refreshFromRemote() {
|
|
570
|
-
try {
|
|
571
|
-
const res = await new HttpsRequest({
|
|
572
|
-
method: "POST" /* POST */,
|
|
573
|
-
endpoint: `${this.app.getBaseUrl()}/db/array/show`,
|
|
574
|
-
headers: { authorization: this.app.getConfig().token, "x-project": this.app.getConfig().project },
|
|
575
|
-
body: {
|
|
576
|
-
collection: this.collection,
|
|
577
|
-
document: this.docID,
|
|
578
|
-
array: this.key
|
|
579
|
-
}
|
|
580
|
-
}).sendRequest();
|
|
581
|
-
if (!res?.success || !globalThis.Array.isArray(res.documents)) {
|
|
582
|
-
return [];
|
|
583
|
-
}
|
|
584
|
-
const snapshots = res.documents.filter((d) => d != null).map((d) => ArraySnapshot.fromMap(d));
|
|
585
|
-
if (this.persistence) {
|
|
586
|
-
const currentDoc = await this.persistence.getDoc(this.collection, this.docID);
|
|
587
|
-
if (currentDoc) {
|
|
588
|
-
await this.persistence.upsertDoc({
|
|
589
|
-
...currentDoc,
|
|
590
|
-
data: { ...currentDoc.data, [this.key]: res.documents },
|
|
591
|
-
pending: 0,
|
|
592
|
-
status: "synced",
|
|
593
|
-
lastSyncedAt: Date.now()
|
|
594
|
-
});
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
return snapshots;
|
|
598
|
-
} catch {
|
|
599
|
-
return [];
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
async push(data, id) {
|
|
603
|
-
const payload = {
|
|
604
|
-
data,
|
|
605
|
-
id: id || this.persistence?.createLocalId?.() || void 0,
|
|
606
|
-
dt: Timestamp.now()
|
|
607
|
-
};
|
|
608
|
-
if (this.persistence) {
|
|
609
|
-
await this.persistence.enqueueMutation({
|
|
610
|
-
mutationId: this.persistence.createMutationId(),
|
|
611
|
-
collection: this.collection,
|
|
612
|
-
documentId: this.docID,
|
|
613
|
-
type: "array_push",
|
|
614
|
-
// custom type
|
|
615
|
-
payload: { arrayKey: this.key, ...payload }
|
|
616
|
-
});
|
|
617
|
-
this.syncEngine?.flush().catch(console.error);
|
|
618
|
-
const doc = await this.persistence.getDoc(this.collection, this.docID);
|
|
619
|
-
if (doc) {
|
|
620
|
-
const updatedArray = [...doc.data[this.key] || [], payload];
|
|
621
|
-
const snap = ArraySnapshot.fromMap(payload);
|
|
622
|
-
this.localStore?.emitDocument(
|
|
623
|
-
this.collection,
|
|
624
|
-
this.docID,
|
|
625
|
-
DocumentSnapshot.fromMap({ ...doc.data, [this.key]: updatedArray }),
|
|
626
|
-
"update"
|
|
627
|
-
);
|
|
628
|
-
}
|
|
629
|
-
return ArraySnapshot.fromMap(payload);
|
|
630
|
-
}
|
|
631
|
-
const res = await new HttpsRequest({
|
|
632
|
-
method: "POST" /* POST */,
|
|
633
|
-
endpoint: `${this.app.getBaseUrl()}/db/array/push`,
|
|
634
|
-
headers: { authorization: this.app.getConfig().token, "x-project": this.app.getConfig().project },
|
|
635
|
-
body: {
|
|
636
|
-
collection: this.collection,
|
|
637
|
-
document: this.docID,
|
|
638
|
-
array: this.key,
|
|
639
|
-
...payload
|
|
640
|
-
}
|
|
641
|
-
}).sendRequest();
|
|
642
|
-
return res?.success ? ArraySnapshot.fromMap(res.document) : null;
|
|
643
|
-
}
|
|
644
|
-
// Similar pattern for update, insert, remove, get...
|
|
645
|
-
// (I'll show one more as example; apply the same logic to the rest)
|
|
646
|
-
async update(position, data, id) {
|
|
647
|
-
if (this.persistence) {
|
|
648
|
-
await this.persistence.enqueueMutation({
|
|
649
|
-
mutationId: this.persistence.createMutationId(),
|
|
650
|
-
collection: this.collection,
|
|
651
|
-
documentId: this.docID,
|
|
652
|
-
type: "array_update",
|
|
653
|
-
payload: { arrayKey: this.key, position, data, id }
|
|
654
|
-
});
|
|
655
|
-
this.syncEngine?.flush().catch(console.error);
|
|
656
|
-
return ArraySnapshot.fromMap({ ...data, id });
|
|
657
|
-
}
|
|
658
|
-
const res = await new HttpsRequest({
|
|
659
|
-
method: "POST" /* POST */,
|
|
660
|
-
endpoint: `${this.app.getBaseUrl()}/db/array/update`,
|
|
661
|
-
headers: { authorization: this.app.getConfig().token, "x-project": this.app.getConfig().project },
|
|
662
|
-
body: {
|
|
663
|
-
collection: this.collection,
|
|
664
|
-
document: this.docID,
|
|
665
|
-
array: this.key,
|
|
666
|
-
position,
|
|
667
|
-
data,
|
|
668
|
-
id
|
|
669
|
-
}
|
|
670
|
-
}).sendRequest();
|
|
671
|
-
return res?.success ? ArraySnapshot.fromMap(res.document) : null;
|
|
672
|
-
}
|
|
673
|
-
// TODO: Implement insert(), get(), remove() using the exact same offline pattern as push/update
|
|
674
|
-
async insert(position, data, id) {
|
|
675
|
-
return null;
|
|
676
|
-
}
|
|
677
|
-
async get(position) {
|
|
678
|
-
return null;
|
|
679
|
-
}
|
|
680
|
-
async remove(position) {
|
|
681
|
-
return null;
|
|
682
|
-
}
|
|
683
|
-
};
|
|
684
|
-
|
|
685
395
|
// src/utils/documentNomalizer.ts
|
|
686
396
|
function normalizePayload(payload) {
|
|
687
397
|
const raw = payload?.document ?? payload?.data ?? payload;
|
|
@@ -701,11 +411,8 @@ function validateDocumentData(data, operation) {
|
|
|
701
411
|
if (data === null || data === void 0) {
|
|
702
412
|
throw new Error(`${operation}: data cannot be null or undefined`);
|
|
703
413
|
}
|
|
704
|
-
if (typeof data !== "object") {
|
|
705
|
-
throw new Error(`${operation}: data must be
|
|
706
|
-
}
|
|
707
|
-
if (data instanceof Array2) {
|
|
708
|
-
throw new Error(`${operation}: data cannot be an array`);
|
|
414
|
+
if (typeof data !== "object" || Array.isArray(data)) {
|
|
415
|
+
throw new Error(`${operation}: data must be a plain object`);
|
|
709
416
|
}
|
|
710
417
|
const reservedFields = ["id", "_id", "_createdAt", "_updatedAt", "_deleted"];
|
|
711
418
|
for (const field of reservedFields) {
|
|
@@ -713,18 +420,18 @@ function validateDocumentData(data, operation) {
|
|
|
713
420
|
throw new Error(`${operation}: '${field}' is a reserved field and cannot be set manually`);
|
|
714
421
|
}
|
|
715
422
|
}
|
|
716
|
-
const dataSize = JSON.stringify(data).length;
|
|
717
|
-
if (dataSize > 1024 * 1024) {
|
|
718
|
-
throw new Error(`${operation}: document size (${Math.round(dataSize / 1024)}KB) exceeds maximum allowed size (1MB)`);
|
|
719
|
-
}
|
|
720
423
|
try {
|
|
721
|
-
JSON.stringify(data);
|
|
424
|
+
const size = JSON.stringify(data).length;
|
|
425
|
+
if (size > 1024 * 1024) {
|
|
426
|
+
throw new Error(`${operation}: document too large (max 1MB)`);
|
|
427
|
+
}
|
|
722
428
|
} catch {
|
|
723
429
|
throw new Error(`${operation}: data contains circular references`);
|
|
724
430
|
}
|
|
725
431
|
}
|
|
726
432
|
var DocumentRef = class {
|
|
727
433
|
constructor(app, collection, id) {
|
|
434
|
+
this._isUpdating = false;
|
|
728
435
|
this.app = app;
|
|
729
436
|
this.collection = collection;
|
|
730
437
|
this.id = id;
|
|
@@ -732,58 +439,60 @@ var DocumentRef = class {
|
|
|
732
439
|
this.syncEngine = app.offline().syncEngine;
|
|
733
440
|
this.localStore = app.offline().localStore;
|
|
734
441
|
}
|
|
442
|
+
// ====================== GET ======================
|
|
735
443
|
async get() {
|
|
736
444
|
if (this.persistence) {
|
|
737
445
|
try {
|
|
738
446
|
const localSnap = await this.persistence.getDocSnapshot(this.collection, this.id);
|
|
739
447
|
if (localSnap)
|
|
740
|
-
return localSnap;
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
localOnly: false,
|
|
767
|
-
status: "pending"
|
|
768
|
-
});
|
|
769
|
-
await this.persistence.enqueueMutation({
|
|
770
|
-
mutationId: this.persistence.createMutationId(),
|
|
771
|
-
collection: this.collection,
|
|
772
|
-
documentId: this.id,
|
|
773
|
-
type: "insert",
|
|
774
|
-
// or "create" if you want to distinguish truly new docs
|
|
775
|
-
payload: data
|
|
776
|
-
});
|
|
777
|
-
const snap = DocumentSnapshot.fromMap(updated.data);
|
|
778
|
-
this.localStore?.emitDocument(this.collection, this.id, snap, "update");
|
|
779
|
-
const currentCollection = await this.persistence.getCollectionSnapshots(this.collection);
|
|
780
|
-
this.localStore?.emitCollection(this.collection, currentCollection, "update", this.id);
|
|
781
|
-
this.syncEngine?.flush().catch(console.error);
|
|
782
|
-
return snap;
|
|
448
|
+
return localSnap;
|
|
449
|
+
} catch (error) {
|
|
450
|
+
console.error("[EdmaxLabs] Cache read error:", error);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
try {
|
|
454
|
+
const res = await new HttpsRequest({
|
|
455
|
+
method: "POST" /* POST */,
|
|
456
|
+
endpoint: `${this.app.getBaseUrl()}/db/read`,
|
|
457
|
+
headers: {
|
|
458
|
+
authorization: this.app.getConfig().token,
|
|
459
|
+
"x-project": this.app.getConfig().project
|
|
460
|
+
},
|
|
461
|
+
body: {
|
|
462
|
+
collection: this.collection,
|
|
463
|
+
id: this.id,
|
|
464
|
+
single: true
|
|
465
|
+
}
|
|
466
|
+
}).sendRequest();
|
|
467
|
+
if (!res?.success || !res.document)
|
|
468
|
+
return null;
|
|
469
|
+
return DocumentSnapshot.fromMap(res.document);
|
|
470
|
+
} catch (error) {
|
|
471
|
+
console.error(`[DocumentRef] get(${this.collection}/${this.id}) failed:`, error);
|
|
472
|
+
return null;
|
|
473
|
+
}
|
|
783
474
|
}
|
|
475
|
+
// ====================== UPDATE ======================
|
|
784
476
|
async update(data) {
|
|
785
|
-
|
|
786
|
-
|
|
477
|
+
if (this._isUpdating) {
|
|
478
|
+
console.warn(`[DocumentRef] update recursion blocked on ${this.collection}/${this.id}`);
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
this._isUpdating = true;
|
|
482
|
+
try {
|
|
483
|
+
validateDocumentData(data, "DocumentRef.update");
|
|
484
|
+
if (!this.persistence) {
|
|
485
|
+
const res = await new HttpsRequest({
|
|
486
|
+
method: "POST" /* POST */,
|
|
487
|
+
endpoint: `${this.app.getBaseUrl()}/db/update`,
|
|
488
|
+
headers: {
|
|
489
|
+
authorization: this.app.getConfig().token,
|
|
490
|
+
"x-project": this.app.getConfig().project
|
|
491
|
+
},
|
|
492
|
+
body: { collection: this.collection, id: this.id, data }
|
|
493
|
+
}).sendRequest();
|
|
494
|
+
return res?.success ? DocumentSnapshot.fromMap({ ...data, id: this.id }) : null;
|
|
495
|
+
}
|
|
787
496
|
const old = await this.persistence.getDoc(this.collection, this.id);
|
|
788
497
|
if (!old || old.deleted)
|
|
789
498
|
return null;
|
|
@@ -813,9 +522,49 @@ var DocumentRef = class {
|
|
|
813
522
|
this.localStore?.notifyCollectionChanged(this.collection, this.id, "update");
|
|
814
523
|
this.syncEngine?.flush().catch(console.error);
|
|
815
524
|
return snap;
|
|
525
|
+
} finally {
|
|
526
|
+
this._isUpdating = false;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
// ====================== SET ======================
|
|
530
|
+
async set(data) {
|
|
531
|
+
validateDocumentData(data, "DocumentRef.set");
|
|
532
|
+
if (!this.persistence) {
|
|
533
|
+
const res = await new HttpsRequest({
|
|
534
|
+
method: "POST" /* POST */,
|
|
535
|
+
endpoint: `${this.app.getBaseUrl()}/db/create`,
|
|
536
|
+
headers: {
|
|
537
|
+
authorization: this.app.getConfig().token,
|
|
538
|
+
"x-project": this.app.getConfig().project
|
|
539
|
+
},
|
|
540
|
+
body: { collection: this.collection, data: { ...data, id: this.id } }
|
|
541
|
+
}).sendRequest();
|
|
542
|
+
return res?.success ? DocumentSnapshot.fromMap({ ...data, id: this.id }) : null;
|
|
816
543
|
}
|
|
817
|
-
|
|
544
|
+
const updated = await this.persistence.upsertDoc({
|
|
545
|
+
collection: this.collection,
|
|
546
|
+
id: this.id,
|
|
547
|
+
data: { ...data, id: this.id },
|
|
548
|
+
exists: true,
|
|
549
|
+
deleted: false,
|
|
550
|
+
pending: 1,
|
|
551
|
+
localOnly: false,
|
|
552
|
+
status: "pending"
|
|
553
|
+
});
|
|
554
|
+
await this.persistence.enqueueMutation({
|
|
555
|
+
mutationId: this.persistence.createMutationId(),
|
|
556
|
+
collection: this.collection,
|
|
557
|
+
documentId: this.id,
|
|
558
|
+
type: "insert",
|
|
559
|
+
payload: data
|
|
560
|
+
});
|
|
561
|
+
const snap = DocumentSnapshot.fromMap(updated.data);
|
|
562
|
+
this.localStore?.emitDocument(this.collection, this.id, snap, "update");
|
|
563
|
+
this.localStore?.notifyCollectionChanged(this.collection, this.id, "update");
|
|
564
|
+
this.syncEngine?.flush().catch(console.error);
|
|
565
|
+
return snap;
|
|
818
566
|
}
|
|
567
|
+
// ====================== DELETE ======================
|
|
819
568
|
async delete() {
|
|
820
569
|
if (this.persistence) {
|
|
821
570
|
await this.persistence.markDeleted(this.collection, this.id, 1);
|
|
@@ -831,19 +580,22 @@ var DocumentRef = class {
|
|
|
831
580
|
this.syncEngine?.flush().catch(console.error);
|
|
832
581
|
return true;
|
|
833
582
|
}
|
|
834
|
-
|
|
583
|
+
const res = await new HttpsRequest({
|
|
584
|
+
method: "POST" /* POST */,
|
|
585
|
+
endpoint: `${this.app.getBaseUrl()}/db/delete`,
|
|
586
|
+
headers: {
|
|
587
|
+
authorization: this.app.getConfig().token,
|
|
588
|
+
"x-project": this.app.getConfig().project
|
|
589
|
+
},
|
|
590
|
+
body: { collection: this.collection, id: this.id }
|
|
591
|
+
}).sendRequest();
|
|
592
|
+
return !!res?.success;
|
|
835
593
|
}
|
|
836
|
-
//
|
|
837
|
-
// return new Array(this.app, this.collection, key, this.id);
|
|
838
|
-
// }
|
|
594
|
+
// ====================== SNAPSHOT ======================
|
|
839
595
|
onSnapshot(callback) {
|
|
840
|
-
if (this.
|
|
596
|
+
if (this.persistence && this.localStore && this.app.offline().realtimeBridge) {
|
|
841
597
|
this.app.offline().realtimeBridge?.watchDocument(this.collection, this.id);
|
|
842
|
-
return this.
|
|
843
|
-
this.collection,
|
|
844
|
-
this.id,
|
|
845
|
-
callback
|
|
846
|
-
) || (() => {
|
|
598
|
+
return this.localStore.subscribeToDocument(this.collection, this.id, callback) || (() => {
|
|
847
599
|
});
|
|
848
600
|
}
|
|
849
601
|
return this.app.rtdb().subscribeToDocumentRaw(this.collection, this.id, (snapshot, change) => {
|
|
@@ -1071,15 +823,42 @@ var CollectionRef = class {
|
|
|
1071
823
|
}
|
|
1072
824
|
return local;
|
|
1073
825
|
}
|
|
1074
|
-
|
|
1075
|
-
|
|
826
|
+
try {
|
|
827
|
+
const res = await new HttpsRequest({
|
|
828
|
+
method: "POST" /* POST */,
|
|
829
|
+
endpoint: `${this.app.getBaseUrl()}/db/read`,
|
|
830
|
+
headers: {
|
|
831
|
+
authorization: this.app.getConfig().token,
|
|
832
|
+
"x-project": this.app.getConfig().project
|
|
833
|
+
},
|
|
834
|
+
body: {
|
|
835
|
+
collection: this.collection,
|
|
836
|
+
filter: {}
|
|
837
|
+
}
|
|
838
|
+
}).sendRequest();
|
|
839
|
+
if (!res?.success || !Array.isArray(res.documents)) {
|
|
840
|
+
return [];
|
|
841
|
+
}
|
|
842
|
+
return res.documents.map((d) => {
|
|
843
|
+
delete d.token;
|
|
844
|
+
d.id = d.id ?? d._id;
|
|
845
|
+
delete d._id;
|
|
846
|
+
return DocumentSnapshot.fromMap(d);
|
|
847
|
+
});
|
|
848
|
+
} catch (error) {
|
|
849
|
+
console.error("[EdmaxLabs] Collection get failed:", error);
|
|
850
|
+
return [];
|
|
851
|
+
}
|
|
1076
852
|
}
|
|
1077
853
|
async refreshFromRemote() {
|
|
1078
854
|
try {
|
|
1079
855
|
const res = await new HttpsRequest({
|
|
1080
856
|
method: "POST" /* POST */,
|
|
1081
857
|
endpoint: `${this.app.getBaseUrl()}/db/read`,
|
|
1082
|
-
headers: {
|
|
858
|
+
headers: {
|
|
859
|
+
authorization: this.app.getConfig().token,
|
|
860
|
+
"x-project": this.app.getConfig().project
|
|
861
|
+
},
|
|
1083
862
|
body: {
|
|
1084
863
|
collection: this.collection,
|
|
1085
864
|
filter: {}
|
|
@@ -1105,7 +884,8 @@ var CollectionRef = class {
|
|
|
1105
884
|
delete d._id;
|
|
1106
885
|
return DocumentSnapshot.fromMap(d);
|
|
1107
886
|
});
|
|
1108
|
-
} catch {
|
|
887
|
+
} catch (error) {
|
|
888
|
+
console.error("[EdmaxLabs] refreshFromRemote failed:", error);
|
|
1109
889
|
return [];
|
|
1110
890
|
}
|
|
1111
891
|
}
|
|
@@ -1135,13 +915,24 @@ var CollectionRef = class {
|
|
|
1135
915
|
this.syncEngine?.flush().catch(console.error);
|
|
1136
916
|
return snap;
|
|
1137
917
|
}
|
|
1138
|
-
|
|
1139
|
-
|
|
918
|
+
const res = await new HttpsRequest({
|
|
919
|
+
method: "POST" /* POST */,
|
|
920
|
+
endpoint: `${this.app.getBaseUrl()}/db/create`,
|
|
921
|
+
headers: {
|
|
922
|
+
authorization: this.app.getConfig().token,
|
|
923
|
+
"x-project": this.app.getConfig().project
|
|
924
|
+
},
|
|
925
|
+
body: { collection: this.collection, data: { ...data, id: "" } }
|
|
926
|
+
// server will generate id
|
|
927
|
+
}).sendRequest();
|
|
928
|
+
if (!res?.success || !res.document)
|
|
929
|
+
return null;
|
|
930
|
+
return DocumentSnapshot.fromMap(res.document);
|
|
1140
931
|
}
|
|
1141
932
|
onSnapshot(callback) {
|
|
1142
|
-
if (this.app.offline().
|
|
933
|
+
if (this.persistence && this.localStore && this.app.offline().realtimeBridge) {
|
|
1143
934
|
this.app.offline().realtimeBridge?.watchCollection(this.collection);
|
|
1144
|
-
return this.
|
|
935
|
+
return this.localStore.subscribeToCollection(this.collection, callback) ?? (() => {
|
|
1145
936
|
});
|
|
1146
937
|
}
|
|
1147
938
|
return this.app.rtdb().subscribeToCollectionRaw(this.collection, (payload, changes) => {
|
|
@@ -2734,6 +2525,164 @@ var _EdmaxLabs = class _EdmaxLabs {
|
|
|
2734
2525
|
_EdmaxLabs.instance = null;
|
|
2735
2526
|
var EdmaxLabs = _EdmaxLabs;
|
|
2736
2527
|
|
|
2528
|
+
// src/database/Timestamp.ts
|
|
2529
|
+
var Timestamp = class _Timestamp {
|
|
2530
|
+
constructor(seconds, nanoseconds = 0) {
|
|
2531
|
+
this.seconds = seconds;
|
|
2532
|
+
this.nanoseconds = nanoseconds;
|
|
2533
|
+
}
|
|
2534
|
+
static now() {
|
|
2535
|
+
return _Timestamp.fromMillis(Date.now());
|
|
2536
|
+
}
|
|
2537
|
+
static fromDate(date) {
|
|
2538
|
+
return new _Timestamp(
|
|
2539
|
+
Math.floor(date.getTime() / 1e3),
|
|
2540
|
+
date.getTime() % 1e3 * 1e6
|
|
2541
|
+
);
|
|
2542
|
+
}
|
|
2543
|
+
static fromMillis(ms) {
|
|
2544
|
+
return new _Timestamp(Math.floor(ms / 1e3), ms % 1e3 * 1e6);
|
|
2545
|
+
}
|
|
2546
|
+
static fromMongo(dateObj) {
|
|
2547
|
+
return _Timestamp.fromMillis(dateObj.getTime());
|
|
2548
|
+
}
|
|
2549
|
+
static fromJSON(obj) {
|
|
2550
|
+
return new _Timestamp(obj.seconds, obj.nanoseconds);
|
|
2551
|
+
}
|
|
2552
|
+
toDate() {
|
|
2553
|
+
return new Date(this.toMillis());
|
|
2554
|
+
}
|
|
2555
|
+
toMillis() {
|
|
2556
|
+
return this.seconds * 1e3 + Math.floor(this.nanoseconds / 1e6);
|
|
2557
|
+
}
|
|
2558
|
+
sinceEpoch() {
|
|
2559
|
+
return this.seconds;
|
|
2560
|
+
}
|
|
2561
|
+
toMongo() {
|
|
2562
|
+
return new Date(this.toMillis());
|
|
2563
|
+
}
|
|
2564
|
+
format(pattern = "dd-MM-yyyy HH:mm:ss") {
|
|
2565
|
+
const d = this.toDate();
|
|
2566
|
+
const monthsShort = [
|
|
2567
|
+
"Jan",
|
|
2568
|
+
"Feb",
|
|
2569
|
+
"Mar",
|
|
2570
|
+
"Apr",
|
|
2571
|
+
"May",
|
|
2572
|
+
"Jun",
|
|
2573
|
+
"Jul",
|
|
2574
|
+
"Aug",
|
|
2575
|
+
"Sep",
|
|
2576
|
+
"Oct",
|
|
2577
|
+
"Nov",
|
|
2578
|
+
"Dec"
|
|
2579
|
+
];
|
|
2580
|
+
const monthsLong = [
|
|
2581
|
+
"January",
|
|
2582
|
+
"February",
|
|
2583
|
+
"March",
|
|
2584
|
+
"April",
|
|
2585
|
+
"May",
|
|
2586
|
+
"June",
|
|
2587
|
+
"July",
|
|
2588
|
+
"August",
|
|
2589
|
+
"September",
|
|
2590
|
+
"October",
|
|
2591
|
+
"November",
|
|
2592
|
+
"December"
|
|
2593
|
+
];
|
|
2594
|
+
const hours = d.getHours();
|
|
2595
|
+
const hours12 = hours % 12 === 0 ? 12 : hours % 12;
|
|
2596
|
+
const ampm = hours < 12 ? "AM" : "PM";
|
|
2597
|
+
const map = {
|
|
2598
|
+
dd: String(d.getDate()).padStart(2, "0"),
|
|
2599
|
+
MM: String(d.getMonth() + 1).padStart(2, "0"),
|
|
2600
|
+
yyyy: d.getFullYear(),
|
|
2601
|
+
HH: String(d.getHours()).padStart(2, "0"),
|
|
2602
|
+
mm: String(d.getMinutes()).padStart(2, "0"),
|
|
2603
|
+
ss: String(d.getSeconds()).padStart(2, "0"),
|
|
2604
|
+
SSS: String(d.getMilliseconds()).padStart(3, "0"),
|
|
2605
|
+
MMM: monthsShort[d.getMonth()],
|
|
2606
|
+
MMMM: monthsLong[d.getMonth()],
|
|
2607
|
+
a: ampm.toLowerCase(),
|
|
2608
|
+
// am/pm
|
|
2609
|
+
A: ampm
|
|
2610
|
+
// AM/PM
|
|
2611
|
+
};
|
|
2612
|
+
return pattern.replace(
|
|
2613
|
+
/MMMM|MMM|dd|MM|yyyy|HH|mm|ss|SSS|a|A/g,
|
|
2614
|
+
(match) => String(map[match])
|
|
2615
|
+
);
|
|
2616
|
+
}
|
|
2617
|
+
compare(other) {
|
|
2618
|
+
if (this.seconds !== other.seconds) {
|
|
2619
|
+
return this.seconds - other.seconds;
|
|
2620
|
+
}
|
|
2621
|
+
return this.nanoseconds - other.nanoseconds;
|
|
2622
|
+
}
|
|
2623
|
+
relative(fmt = "dd-MM-yyyy HH:mm:ss") {
|
|
2624
|
+
const now = Date.now();
|
|
2625
|
+
const diff = now - this.toMillis();
|
|
2626
|
+
const sec = Math.floor(diff / 1e3);
|
|
2627
|
+
if (sec < 60)
|
|
2628
|
+
return `${sec}s ago`;
|
|
2629
|
+
const min = Math.floor(sec / 60);
|
|
2630
|
+
if (min < 60)
|
|
2631
|
+
return `${min}m ago`;
|
|
2632
|
+
const hrs = Math.floor(min / 60);
|
|
2633
|
+
if (hrs < 24)
|
|
2634
|
+
return `${hrs}h ago`;
|
|
2635
|
+
const days = Math.floor(hrs / 24);
|
|
2636
|
+
if (days < 3)
|
|
2637
|
+
return `${days}d ago`;
|
|
2638
|
+
return this.format(fmt);
|
|
2639
|
+
}
|
|
2640
|
+
add({
|
|
2641
|
+
seconds = 0,
|
|
2642
|
+
minutes = 0,
|
|
2643
|
+
hours = 0,
|
|
2644
|
+
days = 0
|
|
2645
|
+
}) {
|
|
2646
|
+
const totalMs = seconds * 1e3 + minutes * 6e4 + hours * 36e5 + days * 864e5;
|
|
2647
|
+
return _Timestamp.fromMillis(this.toMillis() + totalMs);
|
|
2648
|
+
}
|
|
2649
|
+
weekdayName() {
|
|
2650
|
+
return ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][this.toDate().getDay()];
|
|
2651
|
+
}
|
|
2652
|
+
toJSON() {
|
|
2653
|
+
return {
|
|
2654
|
+
_type: "timestamp",
|
|
2655
|
+
seconds: this.seconds,
|
|
2656
|
+
nanoseconds: this.nanoseconds
|
|
2657
|
+
};
|
|
2658
|
+
}
|
|
2659
|
+
toString() {
|
|
2660
|
+
return this.format("yyyy-MM-dd HH:mm:ss");
|
|
2661
|
+
}
|
|
2662
|
+
};
|
|
2663
|
+
|
|
2664
|
+
// src/database/ArraySnapshot.ts
|
|
2665
|
+
var ArraySnapshot = class _ArraySnapshot {
|
|
2666
|
+
constructor(id = "", index, data, dt) {
|
|
2667
|
+
this.data = data;
|
|
2668
|
+
this.id = id;
|
|
2669
|
+
this.dt = dt ?? Timestamp.now();
|
|
2670
|
+
}
|
|
2671
|
+
static fromMap(map) {
|
|
2672
|
+
const index = map.index ?? map.index ?? -1;
|
|
2673
|
+
const id = map.id ?? map._id ?? "";
|
|
2674
|
+
const document2 = map.data ?? map.document ?? map;
|
|
2675
|
+
return new _ArraySnapshot(id, index, document2);
|
|
2676
|
+
}
|
|
2677
|
+
toMap() {
|
|
2678
|
+
return {
|
|
2679
|
+
id: this.id ?? "",
|
|
2680
|
+
data: this.data,
|
|
2681
|
+
dt: this.dt
|
|
2682
|
+
};
|
|
2683
|
+
}
|
|
2684
|
+
};
|
|
2685
|
+
|
|
2737
2686
|
// src/index.ts
|
|
2738
2687
|
var src_default = EdmaxLabs;
|
|
2739
2688
|
// Annotate the CommonJS export names for ESM import in node:
|