edmaxlabs-core 2.5.0 → 2.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +419 -466
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -14
- package/dist/index.d.ts +14 -14
- package/dist/index.mjs +419 -466
- 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
|
};
|
|
@@ -129,91 +133,123 @@ var HttpsRequest = class {
|
|
|
129
133
|
|
|
130
134
|
// src/authentication/Authentication.ts
|
|
131
135
|
var _Authentication = class _Authentication {
|
|
132
|
-
// Re-entrancy guard
|
|
133
136
|
constructor() {
|
|
134
|
-
this.eUser = null;
|
|
135
|
-
this.client = null;
|
|
136
|
-
this.app = null;
|
|
137
|
-
// Dedicated lightweight instance for auth
|
|
138
137
|
this.eventListeners = /* @__PURE__ */ new Map();
|
|
139
|
-
this.
|
|
140
|
-
|
|
138
|
+
this.eventWaiters = /* @__PURE__ */ new Map();
|
|
139
|
+
this.unsubscribers = /* @__PURE__ */ new Set();
|
|
140
|
+
this.isSameCredentials = (a, b) => {
|
|
141
|
+
if (!a && !b)
|
|
142
|
+
return true;
|
|
143
|
+
if (!a || !b)
|
|
144
|
+
return false;
|
|
145
|
+
return JSON.stringify(a.toMap()) === JSON.stringify(b.toMap());
|
|
146
|
+
};
|
|
141
147
|
this.createUserWithEmailAndPassword = async ({
|
|
142
148
|
email,
|
|
143
149
|
password
|
|
144
150
|
}) => {
|
|
151
|
+
this.eUser = void 0;
|
|
145
152
|
this.saveCredentials(null);
|
|
146
|
-
const app = this.app
|
|
147
|
-
const
|
|
148
|
-
|
|
153
|
+
const app = this.app?.getDatabase;
|
|
154
|
+
const data = await app?.collection("users").query.where({
|
|
155
|
+
key: "email",
|
|
156
|
+
op: "===",
|
|
157
|
+
value: email
|
|
158
|
+
}).get();
|
|
159
|
+
if (data.length > 0) {
|
|
149
160
|
throw new Error("Email Already In Use.");
|
|
150
161
|
}
|
|
151
|
-
const userRef = await app
|
|
162
|
+
const userRef = await app?.collection("users").add({
|
|
152
163
|
email,
|
|
153
164
|
password,
|
|
154
|
-
token: this.client.getConfig().token,
|
|
155
165
|
logged: true,
|
|
156
|
-
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
|
+
}
|
|
157
175
|
});
|
|
158
|
-
if (!userRef?.id) {
|
|
159
|
-
throw new Error("Something went wrong
|
|
176
|
+
if (!userRef?.id || userRef?.id === "") {
|
|
177
|
+
throw new Error("Something went wrong try Again.");
|
|
160
178
|
}
|
|
161
|
-
|
|
162
|
-
this.saveCredentials(
|
|
163
|
-
return
|
|
179
|
+
this.eUser = Credentials.fromMap(userRef);
|
|
180
|
+
this.saveCredentials(this.eUser);
|
|
181
|
+
return Credentials.fromMap(userRef.toMap());
|
|
164
182
|
};
|
|
165
183
|
this.signInWithEmailAndPassword = async ({
|
|
166
184
|
email,
|
|
167
185
|
password
|
|
168
186
|
}) => {
|
|
169
|
-
const app = this.app
|
|
170
|
-
const data = await app
|
|
171
|
-
|
|
187
|
+
const app = this.app?.getDatabase;
|
|
188
|
+
const data = await app?.collection("users").query.where({
|
|
189
|
+
key: "email",
|
|
190
|
+
op: "===",
|
|
191
|
+
value: email
|
|
192
|
+
}).where({
|
|
193
|
+
key: "password",
|
|
194
|
+
op: "===",
|
|
195
|
+
value: password
|
|
196
|
+
}).get();
|
|
197
|
+
if (data === void 0) {
|
|
198
|
+
throw new Error("Auth Failed.");
|
|
199
|
+
}
|
|
200
|
+
if (data?.length === 0) {
|
|
172
201
|
throw new Error("User Not Found.");
|
|
173
202
|
}
|
|
174
|
-
const
|
|
175
|
-
await app
|
|
203
|
+
const _data = data[0];
|
|
204
|
+
await app?.collection("users").doc(_data.id).update({
|
|
176
205
|
logged: true,
|
|
177
206
|
lastLogged: Date.now()
|
|
178
207
|
});
|
|
179
|
-
|
|
180
|
-
this.saveCredentials(
|
|
181
|
-
return
|
|
182
|
-
};
|
|
183
|
-
this.signOut = async () => {
|
|
184
|
-
const current = this.currentUser();
|
|
185
|
-
if (!current)
|
|
186
|
-
return;
|
|
187
|
-
const app = this.app.getDatabase;
|
|
188
|
-
await app.collection("users").doc(current.uid).update({
|
|
189
|
-
logged: false,
|
|
190
|
-
lastLogged: Date.now()
|
|
191
|
-
});
|
|
192
|
-
this.saveCredentials(null);
|
|
208
|
+
this.eUser = Credentials.fromMap(_data);
|
|
209
|
+
this.saveCredentials(this.eUser);
|
|
210
|
+
return Credentials.fromMap(_data);
|
|
193
211
|
};
|
|
194
212
|
this.deleteUser = async () => {
|
|
195
|
-
if (!this.eUser)
|
|
213
|
+
if (!this.eUser) {
|
|
196
214
|
throw new Error("No User Signed in");
|
|
197
|
-
|
|
198
|
-
|
|
215
|
+
}
|
|
216
|
+
const app = this.app?.getDatabase;
|
|
217
|
+
const userRef = await app?.collection("users").doc(this.eUser.uid).delete();
|
|
218
|
+
if (userRef) {
|
|
219
|
+
throw new Error("Something went wrong try Again.");
|
|
220
|
+
}
|
|
221
|
+
this.eUser = void 0;
|
|
222
|
+
this.saveCredentials(null);
|
|
223
|
+
};
|
|
224
|
+
this.signOut = async () => {
|
|
225
|
+
const app = this.app?.getDatabase;
|
|
226
|
+
const luid = this.currentUser();
|
|
227
|
+
this.eUser = void 0;
|
|
199
228
|
this.saveCredentials(null);
|
|
229
|
+
if (luid)
|
|
230
|
+
await app?.collection("users").doc(luid?.uid).update({
|
|
231
|
+
logged: false,
|
|
232
|
+
lastLogged: Date.now()
|
|
233
|
+
});
|
|
234
|
+
return;
|
|
200
235
|
};
|
|
201
|
-
// Optional: Rules verification
|
|
202
236
|
this.rules = async (path, context) => {
|
|
203
237
|
const res = await new HttpsRequest({
|
|
204
238
|
method: "POST" /* POST */,
|
|
205
|
-
endpoint:
|
|
239
|
+
endpoint: this.client.getBaseUrl() + "/auth/rules/verify",
|
|
206
240
|
headers: {
|
|
207
241
|
authorization: this.client.getConfig().token,
|
|
208
242
|
project: this.client.getConfig().project
|
|
209
243
|
},
|
|
210
|
-
body: {
|
|
244
|
+
body: {
|
|
245
|
+
path,
|
|
246
|
+
context
|
|
247
|
+
}
|
|
211
248
|
}).sendRequest();
|
|
212
249
|
return res;
|
|
213
250
|
};
|
|
214
|
-
if (_Authentication.instance)
|
|
251
|
+
if (_Authentication.instance)
|
|
215
252
|
return _Authentication.instance;
|
|
216
|
-
}
|
|
217
253
|
this.client = EdmaxLabs.instance;
|
|
218
254
|
this.app = new EdmaxLabs({
|
|
219
255
|
token: "auth",
|
|
@@ -222,16 +258,26 @@ var _Authentication = class _Authentication {
|
|
|
222
258
|
_Authentication.instance = this;
|
|
223
259
|
this.restoreSession();
|
|
224
260
|
}
|
|
261
|
+
restoreSession() {
|
|
262
|
+
const saved = this.currentUser();
|
|
263
|
+
if (saved) {
|
|
264
|
+
this.eUser = saved;
|
|
265
|
+
this.emitValue("creds", saved);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
// Better singleton
|
|
225
269
|
static getInstance() {
|
|
226
270
|
if (!_Authentication.instance) {
|
|
227
271
|
_Authentication.instance = new _Authentication();
|
|
228
272
|
}
|
|
229
273
|
return _Authentication.instance;
|
|
230
274
|
}
|
|
231
|
-
// ====================== EVENT SYSTEM ======================
|
|
232
275
|
emitValue(key, value) {
|
|
233
276
|
const listeners = this.eventListeners.get(key) || [];
|
|
234
|
-
|
|
277
|
+
listeners.forEach((l) => l(value));
|
|
278
|
+
const waiters = this.eventWaiters.get(key) || [];
|
|
279
|
+
waiters.forEach((resolve) => resolve(value));
|
|
280
|
+
this.eventWaiters.delete(key);
|
|
235
281
|
}
|
|
236
282
|
onValue(key, callback) {
|
|
237
283
|
const listeners = this.eventListeners.get(key) || [];
|
|
@@ -242,7 +288,6 @@ var _Authentication = class _Authentication {
|
|
|
242
288
|
this.eventListeners.set(key, filtered);
|
|
243
289
|
};
|
|
244
290
|
}
|
|
245
|
-
// ====================== CREDENTIALS ======================
|
|
246
291
|
currentUser() {
|
|
247
292
|
const data = localStorage.getItem("eauth");
|
|
248
293
|
if (!data)
|
|
@@ -265,71 +310,50 @@ var _Authentication = class _Authentication {
|
|
|
265
310
|
this.eUser = credentials;
|
|
266
311
|
this.emitValue("creds", credentials);
|
|
267
312
|
}
|
|
268
|
-
|
|
269
|
-
if (!a && !b)
|
|
270
|
-
return true;
|
|
271
|
-
if (!a || !b)
|
|
272
|
-
return false;
|
|
273
|
-
return a.uid === b.uid && a.displayInfo.email === b.displayInfo.email && a.lastLogged === b.lastLogged;
|
|
274
|
-
}
|
|
275
|
-
restoreSession() {
|
|
276
|
-
const saved = this.currentUser();
|
|
277
|
-
if (saved) {
|
|
278
|
-
this.eUser = saved;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
// ====================== MAIN AUTH STATE LISTENER ======================
|
|
282
|
-
/**
|
|
283
|
-
* Main method to listen to authentication state changes.
|
|
284
|
-
* This listener stays alive for the entire app lifetime.
|
|
285
|
-
*/
|
|
313
|
+
// Main auth state listener - should be called ONCE at app root
|
|
286
314
|
authState({
|
|
287
315
|
onChange,
|
|
288
316
|
onSignOut,
|
|
289
317
|
onDeleted
|
|
290
318
|
}) {
|
|
291
319
|
let userDocUnsubscribe;
|
|
292
|
-
let credsUnsub;
|
|
293
320
|
const handleCredsChange = (creds) => {
|
|
294
|
-
if (
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
userDocUnsubscribe = void 0;
|
|
321
|
+
if (userDocUnsubscribe) {
|
|
322
|
+
userDocUnsubscribe();
|
|
323
|
+
userDocUnsubscribe = void 0;
|
|
324
|
+
}
|
|
299
325
|
if (!creds) {
|
|
300
326
|
this.eUser = null;
|
|
301
327
|
onSignOut?.();
|
|
302
|
-
this.isHandlingChange = false;
|
|
303
328
|
return;
|
|
304
329
|
}
|
|
305
|
-
const userRef = this.app
|
|
330
|
+
const userRef = this.app?.getDatabase.collection("users").doc(creds.uid);
|
|
331
|
+
if (!userRef)
|
|
332
|
+
return;
|
|
306
333
|
userDocUnsubscribe = userRef.onSnapshot(
|
|
307
334
|
(snapshot, change) => {
|
|
335
|
+
console.log(snapshot);
|
|
308
336
|
if (change === "delete") {
|
|
309
337
|
this.saveCredentials(null);
|
|
310
338
|
onSignOut?.();
|
|
311
339
|
onDeleted?.();
|
|
312
|
-
this.isHandlingChange = false;
|
|
313
340
|
return;
|
|
314
341
|
}
|
|
315
342
|
if (change === "insert" || change === "update") {
|
|
316
|
-
if (!snapshot
|
|
317
|
-
this.isHandlingChange = false;
|
|
343
|
+
if (!snapshot)
|
|
318
344
|
return;
|
|
319
|
-
}
|
|
320
345
|
if (snapshot.data.logged === false || snapshot.data.logged === "false") {
|
|
321
346
|
this.saveCredentials(null);
|
|
322
347
|
onSignOut?.();
|
|
323
|
-
this.isHandlingChange = false;
|
|
324
348
|
return;
|
|
325
349
|
}
|
|
326
350
|
const newCreds = Credentials.fromMap(snapshot.toMap());
|
|
327
351
|
if (!this.isSameCredentials(this.eUser, newCreds)) {
|
|
352
|
+
this.eUser = newCreds;
|
|
328
353
|
this.saveCredentials(newCreds);
|
|
329
354
|
onChange(newCreds);
|
|
330
355
|
}
|
|
331
356
|
}
|
|
332
|
-
this.isHandlingChange = false;
|
|
333
357
|
}
|
|
334
358
|
);
|
|
335
359
|
};
|
|
@@ -338,10 +362,10 @@ var _Authentication = class _Authentication {
|
|
|
338
362
|
this.eUser = initialUser;
|
|
339
363
|
onChange(initialUser);
|
|
340
364
|
}
|
|
341
|
-
credsUnsub = this.onValue("creds", handleCredsChange);
|
|
342
365
|
handleCredsChange(initialUser);
|
|
366
|
+
const credsUnsub = this.onValue("creds", handleCredsChange);
|
|
343
367
|
return () => {
|
|
344
|
-
credsUnsub
|
|
368
|
+
credsUnsub();
|
|
345
369
|
userDocUnsubscribe?.();
|
|
346
370
|
};
|
|
347
371
|
}
|
|
@@ -368,308 +392,6 @@ var DocumentSnapshot = class _DocumentSnapshot {
|
|
|
368
392
|
}
|
|
369
393
|
};
|
|
370
394
|
|
|
371
|
-
// src/database/Timestamp.ts
|
|
372
|
-
var Timestamp = class _Timestamp {
|
|
373
|
-
constructor(seconds, nanoseconds = 0) {
|
|
374
|
-
this.seconds = seconds;
|
|
375
|
-
this.nanoseconds = nanoseconds;
|
|
376
|
-
}
|
|
377
|
-
static now() {
|
|
378
|
-
return _Timestamp.fromMillis(Date.now());
|
|
379
|
-
}
|
|
380
|
-
static fromDate(date) {
|
|
381
|
-
return new _Timestamp(
|
|
382
|
-
Math.floor(date.getTime() / 1e3),
|
|
383
|
-
date.getTime() % 1e3 * 1e6
|
|
384
|
-
);
|
|
385
|
-
}
|
|
386
|
-
static fromMillis(ms) {
|
|
387
|
-
return new _Timestamp(Math.floor(ms / 1e3), ms % 1e3 * 1e6);
|
|
388
|
-
}
|
|
389
|
-
static fromMongo(dateObj) {
|
|
390
|
-
return _Timestamp.fromMillis(dateObj.getTime());
|
|
391
|
-
}
|
|
392
|
-
static fromJSON(obj) {
|
|
393
|
-
return new _Timestamp(obj.seconds, obj.nanoseconds);
|
|
394
|
-
}
|
|
395
|
-
toDate() {
|
|
396
|
-
return new Date(this.toMillis());
|
|
397
|
-
}
|
|
398
|
-
toMillis() {
|
|
399
|
-
return this.seconds * 1e3 + Math.floor(this.nanoseconds / 1e6);
|
|
400
|
-
}
|
|
401
|
-
sinceEpoch() {
|
|
402
|
-
return this.seconds;
|
|
403
|
-
}
|
|
404
|
-
toMongo() {
|
|
405
|
-
return new Date(this.toMillis());
|
|
406
|
-
}
|
|
407
|
-
format(pattern = "dd-MM-yyyy HH:mm:ss") {
|
|
408
|
-
const d = this.toDate();
|
|
409
|
-
const monthsShort = [
|
|
410
|
-
"Jan",
|
|
411
|
-
"Feb",
|
|
412
|
-
"Mar",
|
|
413
|
-
"Apr",
|
|
414
|
-
"May",
|
|
415
|
-
"Jun",
|
|
416
|
-
"Jul",
|
|
417
|
-
"Aug",
|
|
418
|
-
"Sep",
|
|
419
|
-
"Oct",
|
|
420
|
-
"Nov",
|
|
421
|
-
"Dec"
|
|
422
|
-
];
|
|
423
|
-
const monthsLong = [
|
|
424
|
-
"January",
|
|
425
|
-
"February",
|
|
426
|
-
"March",
|
|
427
|
-
"April",
|
|
428
|
-
"May",
|
|
429
|
-
"June",
|
|
430
|
-
"July",
|
|
431
|
-
"August",
|
|
432
|
-
"September",
|
|
433
|
-
"October",
|
|
434
|
-
"November",
|
|
435
|
-
"December"
|
|
436
|
-
];
|
|
437
|
-
const hours = d.getHours();
|
|
438
|
-
const hours12 = hours % 12 === 0 ? 12 : hours % 12;
|
|
439
|
-
const ampm = hours < 12 ? "AM" : "PM";
|
|
440
|
-
const map = {
|
|
441
|
-
dd: String(d.getDate()).padStart(2, "0"),
|
|
442
|
-
MM: String(d.getMonth() + 1).padStart(2, "0"),
|
|
443
|
-
yyyy: d.getFullYear(),
|
|
444
|
-
HH: String(d.getHours()).padStart(2, "0"),
|
|
445
|
-
mm: String(d.getMinutes()).padStart(2, "0"),
|
|
446
|
-
ss: String(d.getSeconds()).padStart(2, "0"),
|
|
447
|
-
SSS: String(d.getMilliseconds()).padStart(3, "0"),
|
|
448
|
-
MMM: monthsShort[d.getMonth()],
|
|
449
|
-
MMMM: monthsLong[d.getMonth()],
|
|
450
|
-
a: ampm.toLowerCase(),
|
|
451
|
-
// am/pm
|
|
452
|
-
A: ampm
|
|
453
|
-
// AM/PM
|
|
454
|
-
};
|
|
455
|
-
return pattern.replace(
|
|
456
|
-
/MMMM|MMM|dd|MM|yyyy|HH|mm|ss|SSS|a|A/g,
|
|
457
|
-
(match) => String(map[match])
|
|
458
|
-
);
|
|
459
|
-
}
|
|
460
|
-
compare(other) {
|
|
461
|
-
if (this.seconds !== other.seconds) {
|
|
462
|
-
return this.seconds - other.seconds;
|
|
463
|
-
}
|
|
464
|
-
return this.nanoseconds - other.nanoseconds;
|
|
465
|
-
}
|
|
466
|
-
relative(fmt = "dd-MM-yyyy HH:mm:ss") {
|
|
467
|
-
const now = Date.now();
|
|
468
|
-
const diff = now - this.toMillis();
|
|
469
|
-
const sec = Math.floor(diff / 1e3);
|
|
470
|
-
if (sec < 60)
|
|
471
|
-
return `${sec}s ago`;
|
|
472
|
-
const min = Math.floor(sec / 60);
|
|
473
|
-
if (min < 60)
|
|
474
|
-
return `${min}m ago`;
|
|
475
|
-
const hrs = Math.floor(min / 60);
|
|
476
|
-
if (hrs < 24)
|
|
477
|
-
return `${hrs}h ago`;
|
|
478
|
-
const days = Math.floor(hrs / 24);
|
|
479
|
-
if (days < 3)
|
|
480
|
-
return `${days}d ago`;
|
|
481
|
-
return this.format(fmt);
|
|
482
|
-
}
|
|
483
|
-
add({
|
|
484
|
-
seconds = 0,
|
|
485
|
-
minutes = 0,
|
|
486
|
-
hours = 0,
|
|
487
|
-
days = 0
|
|
488
|
-
}) {
|
|
489
|
-
const totalMs = seconds * 1e3 + minutes * 6e4 + hours * 36e5 + days * 864e5;
|
|
490
|
-
return _Timestamp.fromMillis(this.toMillis() + totalMs);
|
|
491
|
-
}
|
|
492
|
-
weekdayName() {
|
|
493
|
-
return ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][this.toDate().getDay()];
|
|
494
|
-
}
|
|
495
|
-
toJSON() {
|
|
496
|
-
return {
|
|
497
|
-
_type: "timestamp",
|
|
498
|
-
seconds: this.seconds,
|
|
499
|
-
nanoseconds: this.nanoseconds
|
|
500
|
-
};
|
|
501
|
-
}
|
|
502
|
-
toString() {
|
|
503
|
-
return this.format("yyyy-MM-dd HH:mm:ss");
|
|
504
|
-
}
|
|
505
|
-
};
|
|
506
|
-
|
|
507
|
-
// src/database/ArraySnapshot.ts
|
|
508
|
-
var ArraySnapshot = class _ArraySnapshot {
|
|
509
|
-
constructor(id = "", index, data, dt) {
|
|
510
|
-
this.data = data;
|
|
511
|
-
this.id = id;
|
|
512
|
-
this.dt = dt ?? Timestamp.now();
|
|
513
|
-
}
|
|
514
|
-
static fromMap(map) {
|
|
515
|
-
const index = map.index ?? map.index ?? -1;
|
|
516
|
-
const id = map.id ?? map._id ?? "";
|
|
517
|
-
const document2 = map.data ?? map.document ?? map;
|
|
518
|
-
return new _ArraySnapshot(id, index, document2);
|
|
519
|
-
}
|
|
520
|
-
toMap() {
|
|
521
|
-
return {
|
|
522
|
-
id: this.id ?? "",
|
|
523
|
-
data: this.data,
|
|
524
|
-
dt: this.dt
|
|
525
|
-
};
|
|
526
|
-
}
|
|
527
|
-
};
|
|
528
|
-
|
|
529
|
-
// src/database/Array.ts
|
|
530
|
-
var Array2 = class {
|
|
531
|
-
constructor(app, collection, key, id) {
|
|
532
|
-
this.app = app;
|
|
533
|
-
this.collection = collection;
|
|
534
|
-
this.key = key;
|
|
535
|
-
this.docID = id;
|
|
536
|
-
this.persistence = app.offline().persistence;
|
|
537
|
-
this.syncEngine = app.offline().syncEngine;
|
|
538
|
-
this.localStore = app.offline().localStore;
|
|
539
|
-
}
|
|
540
|
-
/**
|
|
541
|
-
* Get current array elements (offline-first: prefers local cache)
|
|
542
|
-
*/
|
|
543
|
-
async show() {
|
|
544
|
-
if (this.persistence) {
|
|
545
|
-
const doc = await this.persistence.getDoc(this.collection, this.docID);
|
|
546
|
-
if (doc?.exists && !doc.deleted) {
|
|
547
|
-
const arrayData = doc.data[this.key] || [];
|
|
548
|
-
return arrayData.map((item) => ArraySnapshot.fromMap(item));
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
if (typeof navigator === "undefined" || navigator.onLine) {
|
|
552
|
-
this.refreshFromRemote().catch(() => {
|
|
553
|
-
});
|
|
554
|
-
}
|
|
555
|
-
return [];
|
|
556
|
-
}
|
|
557
|
-
async refreshFromRemote() {
|
|
558
|
-
try {
|
|
559
|
-
const res = await new HttpsRequest({
|
|
560
|
-
method: "POST" /* POST */,
|
|
561
|
-
endpoint: `${this.app.getBaseUrl()}/db/array/show`,
|
|
562
|
-
headers: { authorization: this.app.getConfig().token, "x-project": this.app.getConfig().project },
|
|
563
|
-
body: {
|
|
564
|
-
collection: this.collection,
|
|
565
|
-
document: this.docID,
|
|
566
|
-
array: this.key
|
|
567
|
-
}
|
|
568
|
-
}).sendRequest();
|
|
569
|
-
if (!res?.success || !globalThis.Array.isArray(res.documents)) {
|
|
570
|
-
return [];
|
|
571
|
-
}
|
|
572
|
-
const snapshots = res.documents.filter((d) => d != null).map((d) => ArraySnapshot.fromMap(d));
|
|
573
|
-
if (this.persistence) {
|
|
574
|
-
const currentDoc = await this.persistence.getDoc(this.collection, this.docID);
|
|
575
|
-
if (currentDoc) {
|
|
576
|
-
await this.persistence.upsertDoc({
|
|
577
|
-
...currentDoc,
|
|
578
|
-
data: { ...currentDoc.data, [this.key]: res.documents },
|
|
579
|
-
pending: 0,
|
|
580
|
-
status: "synced",
|
|
581
|
-
lastSyncedAt: Date.now()
|
|
582
|
-
});
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
return snapshots;
|
|
586
|
-
} catch {
|
|
587
|
-
return [];
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
async push(data, id) {
|
|
591
|
-
const payload = {
|
|
592
|
-
data,
|
|
593
|
-
id: id || this.persistence?.createLocalId?.() || void 0,
|
|
594
|
-
dt: Timestamp.now()
|
|
595
|
-
};
|
|
596
|
-
if (this.persistence) {
|
|
597
|
-
await this.persistence.enqueueMutation({
|
|
598
|
-
mutationId: this.persistence.createMutationId(),
|
|
599
|
-
collection: this.collection,
|
|
600
|
-
documentId: this.docID,
|
|
601
|
-
type: "array_push",
|
|
602
|
-
// custom type
|
|
603
|
-
payload: { arrayKey: this.key, ...payload }
|
|
604
|
-
});
|
|
605
|
-
this.syncEngine?.flush().catch(console.error);
|
|
606
|
-
const doc = await this.persistence.getDoc(this.collection, this.docID);
|
|
607
|
-
if (doc) {
|
|
608
|
-
const updatedArray = [...doc.data[this.key] || [], payload];
|
|
609
|
-
const snap = ArraySnapshot.fromMap(payload);
|
|
610
|
-
this.localStore?.emitDocument(
|
|
611
|
-
this.collection,
|
|
612
|
-
this.docID,
|
|
613
|
-
DocumentSnapshot.fromMap({ ...doc.data, [this.key]: updatedArray }),
|
|
614
|
-
"update"
|
|
615
|
-
);
|
|
616
|
-
}
|
|
617
|
-
return ArraySnapshot.fromMap(payload);
|
|
618
|
-
}
|
|
619
|
-
const res = await new HttpsRequest({
|
|
620
|
-
method: "POST" /* POST */,
|
|
621
|
-
endpoint: `${this.app.getBaseUrl()}/db/array/push`,
|
|
622
|
-
headers: { authorization: this.app.getConfig().token, "x-project": this.app.getConfig().project },
|
|
623
|
-
body: {
|
|
624
|
-
collection: this.collection,
|
|
625
|
-
document: this.docID,
|
|
626
|
-
array: this.key,
|
|
627
|
-
...payload
|
|
628
|
-
}
|
|
629
|
-
}).sendRequest();
|
|
630
|
-
return res?.success ? ArraySnapshot.fromMap(res.document) : null;
|
|
631
|
-
}
|
|
632
|
-
// Similar pattern for update, insert, remove, get...
|
|
633
|
-
// (I'll show one more as example; apply the same logic to the rest)
|
|
634
|
-
async update(position, data, id) {
|
|
635
|
-
if (this.persistence) {
|
|
636
|
-
await this.persistence.enqueueMutation({
|
|
637
|
-
mutationId: this.persistence.createMutationId(),
|
|
638
|
-
collection: this.collection,
|
|
639
|
-
documentId: this.docID,
|
|
640
|
-
type: "array_update",
|
|
641
|
-
payload: { arrayKey: this.key, position, data, id }
|
|
642
|
-
});
|
|
643
|
-
this.syncEngine?.flush().catch(console.error);
|
|
644
|
-
return ArraySnapshot.fromMap({ ...data, id });
|
|
645
|
-
}
|
|
646
|
-
const res = await new HttpsRequest({
|
|
647
|
-
method: "POST" /* POST */,
|
|
648
|
-
endpoint: `${this.app.getBaseUrl()}/db/array/update`,
|
|
649
|
-
headers: { authorization: this.app.getConfig().token, "x-project": this.app.getConfig().project },
|
|
650
|
-
body: {
|
|
651
|
-
collection: this.collection,
|
|
652
|
-
document: this.docID,
|
|
653
|
-
array: this.key,
|
|
654
|
-
position,
|
|
655
|
-
data,
|
|
656
|
-
id
|
|
657
|
-
}
|
|
658
|
-
}).sendRequest();
|
|
659
|
-
return res?.success ? ArraySnapshot.fromMap(res.document) : null;
|
|
660
|
-
}
|
|
661
|
-
// TODO: Implement insert(), get(), remove() using the exact same offline pattern as push/update
|
|
662
|
-
async insert(position, data, id) {
|
|
663
|
-
return null;
|
|
664
|
-
}
|
|
665
|
-
async get(position) {
|
|
666
|
-
return null;
|
|
667
|
-
}
|
|
668
|
-
async remove(position) {
|
|
669
|
-
return null;
|
|
670
|
-
}
|
|
671
|
-
};
|
|
672
|
-
|
|
673
395
|
// src/utils/documentNomalizer.ts
|
|
674
396
|
function normalizePayload(payload) {
|
|
675
397
|
const raw = payload?.document ?? payload?.data ?? payload;
|
|
@@ -689,30 +411,19 @@ function validateDocumentData(data, operation) {
|
|
|
689
411
|
if (data === null || data === void 0) {
|
|
690
412
|
throw new Error(`${operation}: data cannot be null or undefined`);
|
|
691
413
|
}
|
|
692
|
-
if (typeof data !== "object") {
|
|
693
|
-
throw new Error(`${operation}: data must be
|
|
694
|
-
}
|
|
695
|
-
if (data instanceof Array2) {
|
|
696
|
-
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`);
|
|
697
416
|
}
|
|
698
|
-
const reservedFields = ["
|
|
417
|
+
const reservedFields = ["_id", "_createdAt", "_updatedAt", "_deleted", "_v", "_s"];
|
|
699
418
|
for (const field of reservedFields) {
|
|
700
419
|
if (field in data) {
|
|
701
420
|
throw new Error(`${operation}: '${field}' is a reserved field and cannot be set manually`);
|
|
702
421
|
}
|
|
703
422
|
}
|
|
704
|
-
const dataSize = JSON.stringify(data).length;
|
|
705
|
-
if (dataSize > 1024 * 1024) {
|
|
706
|
-
throw new Error(`${operation}: document size (${Math.round(dataSize / 1024)}KB) exceeds maximum allowed size (1MB)`);
|
|
707
|
-
}
|
|
708
|
-
try {
|
|
709
|
-
JSON.stringify(data);
|
|
710
|
-
} catch {
|
|
711
|
-
throw new Error(`${operation}: data contains circular references`);
|
|
712
|
-
}
|
|
713
423
|
}
|
|
714
424
|
var DocumentRef = class {
|
|
715
425
|
constructor(app, collection, id) {
|
|
426
|
+
this._isUpdating = false;
|
|
716
427
|
this.app = app;
|
|
717
428
|
this.collection = collection;
|
|
718
429
|
this.id = id;
|
|
@@ -720,58 +431,60 @@ var DocumentRef = class {
|
|
|
720
431
|
this.syncEngine = app.offline().syncEngine;
|
|
721
432
|
this.localStore = app.offline().localStore;
|
|
722
433
|
}
|
|
434
|
+
// ====================== GET ======================
|
|
723
435
|
async get() {
|
|
724
436
|
if (this.persistence) {
|
|
725
437
|
try {
|
|
726
438
|
const localSnap = await this.persistence.getDocSnapshot(this.collection, this.id);
|
|
727
439
|
if (localSnap)
|
|
728
|
-
return localSnap;
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
localOnly: false,
|
|
755
|
-
status: "pending"
|
|
756
|
-
});
|
|
757
|
-
await this.persistence.enqueueMutation({
|
|
758
|
-
mutationId: this.persistence.createMutationId(),
|
|
759
|
-
collection: this.collection,
|
|
760
|
-
documentId: this.id,
|
|
761
|
-
type: "insert",
|
|
762
|
-
// or "create" if you want to distinguish truly new docs
|
|
763
|
-
payload: data
|
|
764
|
-
});
|
|
765
|
-
const snap = DocumentSnapshot.fromMap(updated.data);
|
|
766
|
-
this.localStore?.emitDocument(this.collection, this.id, snap, "update");
|
|
767
|
-
const currentCollection = await this.persistence.getCollectionSnapshots(this.collection);
|
|
768
|
-
this.localStore?.emitCollection(this.collection, currentCollection, "update", this.id);
|
|
769
|
-
this.syncEngine?.flush().catch(console.error);
|
|
770
|
-
return snap;
|
|
440
|
+
return localSnap;
|
|
441
|
+
} catch (error) {
|
|
442
|
+
console.error("[EdmaxLabs] Cache read error:", error);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
try {
|
|
446
|
+
const res = await new HttpsRequest({
|
|
447
|
+
method: "POST" /* POST */,
|
|
448
|
+
endpoint: `${this.app.getBaseUrl()}/db/read`,
|
|
449
|
+
headers: {
|
|
450
|
+
authorization: this.app.getConfig().token,
|
|
451
|
+
"x-project": this.app.getConfig().project
|
|
452
|
+
},
|
|
453
|
+
body: {
|
|
454
|
+
collection: this.collection,
|
|
455
|
+
id: this.id,
|
|
456
|
+
single: true
|
|
457
|
+
}
|
|
458
|
+
}).sendRequest();
|
|
459
|
+
if (!res?.success || !res.document)
|
|
460
|
+
return null;
|
|
461
|
+
return DocumentSnapshot.fromMap(res.document);
|
|
462
|
+
} catch (error) {
|
|
463
|
+
console.error(`[DocumentRef] get(${this.collection}/${this.id}) failed:`, error);
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
771
466
|
}
|
|
467
|
+
// ====================== UPDATE ======================
|
|
772
468
|
async update(data) {
|
|
773
|
-
|
|
774
|
-
|
|
469
|
+
if (this._isUpdating) {
|
|
470
|
+
console.warn(`[DocumentRef] update recursion blocked on ${this.collection}/${this.id}`);
|
|
471
|
+
return null;
|
|
472
|
+
}
|
|
473
|
+
this._isUpdating = true;
|
|
474
|
+
try {
|
|
475
|
+
validateDocumentData(data, "DocumentRef.update");
|
|
476
|
+
if (!this.persistence) {
|
|
477
|
+
const res = await new HttpsRequest({
|
|
478
|
+
method: "POST" /* POST */,
|
|
479
|
+
endpoint: `${this.app.getBaseUrl()}/db/update`,
|
|
480
|
+
headers: {
|
|
481
|
+
authorization: this.app.getConfig().token,
|
|
482
|
+
"x-project": this.app.getConfig().project
|
|
483
|
+
},
|
|
484
|
+
body: { collection: this.collection, id: this.id, data }
|
|
485
|
+
}).sendRequest();
|
|
486
|
+
return res?.success ? DocumentSnapshot.fromMap({ ...data, id: this.id }) : null;
|
|
487
|
+
}
|
|
775
488
|
const old = await this.persistence.getDoc(this.collection, this.id);
|
|
776
489
|
if (!old || old.deleted)
|
|
777
490
|
return null;
|
|
@@ -801,9 +514,49 @@ var DocumentRef = class {
|
|
|
801
514
|
this.localStore?.notifyCollectionChanged(this.collection, this.id, "update");
|
|
802
515
|
this.syncEngine?.flush().catch(console.error);
|
|
803
516
|
return snap;
|
|
517
|
+
} finally {
|
|
518
|
+
this._isUpdating = false;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
// ====================== SET ======================
|
|
522
|
+
async set(data) {
|
|
523
|
+
validateDocumentData(data, "DocumentRef.set");
|
|
524
|
+
if (!this.persistence) {
|
|
525
|
+
const res = await new HttpsRequest({
|
|
526
|
+
method: "POST" /* POST */,
|
|
527
|
+
endpoint: `${this.app.getBaseUrl()}/db/create`,
|
|
528
|
+
headers: {
|
|
529
|
+
authorization: this.app.getConfig().token,
|
|
530
|
+
"x-project": this.app.getConfig().project
|
|
531
|
+
},
|
|
532
|
+
body: { collection: this.collection, data: { ...data, id: this.id } }
|
|
533
|
+
}).sendRequest();
|
|
534
|
+
return res?.success ? DocumentSnapshot.fromMap({ ...data, id: this.id }) : null;
|
|
804
535
|
}
|
|
805
|
-
|
|
536
|
+
const updated = await this.persistence.upsertDoc({
|
|
537
|
+
collection: this.collection,
|
|
538
|
+
id: this.id,
|
|
539
|
+
data: { ...data, id: this.id },
|
|
540
|
+
exists: true,
|
|
541
|
+
deleted: false,
|
|
542
|
+
pending: 1,
|
|
543
|
+
localOnly: false,
|
|
544
|
+
status: "pending"
|
|
545
|
+
});
|
|
546
|
+
await this.persistence.enqueueMutation({
|
|
547
|
+
mutationId: this.persistence.createMutationId(),
|
|
548
|
+
collection: this.collection,
|
|
549
|
+
documentId: this.id,
|
|
550
|
+
type: "insert",
|
|
551
|
+
payload: data
|
|
552
|
+
});
|
|
553
|
+
const snap = DocumentSnapshot.fromMap(updated.data);
|
|
554
|
+
this.localStore?.emitDocument(this.collection, this.id, snap, "update");
|
|
555
|
+
this.localStore?.notifyCollectionChanged(this.collection, this.id, "update");
|
|
556
|
+
this.syncEngine?.flush().catch(console.error);
|
|
557
|
+
return snap;
|
|
806
558
|
}
|
|
559
|
+
// ====================== DELETE ======================
|
|
807
560
|
async delete() {
|
|
808
561
|
if (this.persistence) {
|
|
809
562
|
await this.persistence.markDeleted(this.collection, this.id, 1);
|
|
@@ -819,19 +572,22 @@ var DocumentRef = class {
|
|
|
819
572
|
this.syncEngine?.flush().catch(console.error);
|
|
820
573
|
return true;
|
|
821
574
|
}
|
|
822
|
-
|
|
575
|
+
const res = await new HttpsRequest({
|
|
576
|
+
method: "POST" /* POST */,
|
|
577
|
+
endpoint: `${this.app.getBaseUrl()}/db/delete`,
|
|
578
|
+
headers: {
|
|
579
|
+
authorization: this.app.getConfig().token,
|
|
580
|
+
"x-project": this.app.getConfig().project
|
|
581
|
+
},
|
|
582
|
+
body: { collection: this.collection, id: this.id }
|
|
583
|
+
}).sendRequest();
|
|
584
|
+
return !!res?.success;
|
|
823
585
|
}
|
|
824
|
-
//
|
|
825
|
-
// return new Array(this.app, this.collection, key, this.id);
|
|
826
|
-
// }
|
|
586
|
+
// ====================== SNAPSHOT ======================
|
|
827
587
|
onSnapshot(callback) {
|
|
828
|
-
if (this.
|
|
588
|
+
if (this.persistence && this.localStore && this.app.offline().realtimeBridge) {
|
|
829
589
|
this.app.offline().realtimeBridge?.watchDocument(this.collection, this.id);
|
|
830
|
-
return this.
|
|
831
|
-
this.collection,
|
|
832
|
-
this.id,
|
|
833
|
-
callback
|
|
834
|
-
) || (() => {
|
|
590
|
+
return this.localStore.subscribeToDocument(this.collection, this.id, callback) || (() => {
|
|
835
591
|
});
|
|
836
592
|
}
|
|
837
593
|
return this.app.rtdb().subscribeToDocumentRaw(this.collection, this.id, (snapshot, change) => {
|
|
@@ -1059,15 +815,42 @@ var CollectionRef = class {
|
|
|
1059
815
|
}
|
|
1060
816
|
return local;
|
|
1061
817
|
}
|
|
1062
|
-
|
|
1063
|
-
|
|
818
|
+
try {
|
|
819
|
+
const res = await new HttpsRequest({
|
|
820
|
+
method: "POST" /* POST */,
|
|
821
|
+
endpoint: `${this.app.getBaseUrl()}/db/read`,
|
|
822
|
+
headers: {
|
|
823
|
+
authorization: this.app.getConfig().token,
|
|
824
|
+
"x-project": this.app.getConfig().project
|
|
825
|
+
},
|
|
826
|
+
body: {
|
|
827
|
+
collection: this.collection,
|
|
828
|
+
filter: {}
|
|
829
|
+
}
|
|
830
|
+
}).sendRequest();
|
|
831
|
+
if (!res?.success || !Array.isArray(res.documents)) {
|
|
832
|
+
return [];
|
|
833
|
+
}
|
|
834
|
+
return res.documents.map((d) => {
|
|
835
|
+
delete d.token;
|
|
836
|
+
d.id = d.id ?? d._id;
|
|
837
|
+
delete d._id;
|
|
838
|
+
return DocumentSnapshot.fromMap(d);
|
|
839
|
+
});
|
|
840
|
+
} catch (error) {
|
|
841
|
+
console.error("[EdmaxLabs] Collection get failed:", error);
|
|
842
|
+
return [];
|
|
843
|
+
}
|
|
1064
844
|
}
|
|
1065
845
|
async refreshFromRemote() {
|
|
1066
846
|
try {
|
|
1067
847
|
const res = await new HttpsRequest({
|
|
1068
848
|
method: "POST" /* POST */,
|
|
1069
849
|
endpoint: `${this.app.getBaseUrl()}/db/read`,
|
|
1070
|
-
headers: {
|
|
850
|
+
headers: {
|
|
851
|
+
authorization: this.app.getConfig().token,
|
|
852
|
+
"x-project": this.app.getConfig().project
|
|
853
|
+
},
|
|
1071
854
|
body: {
|
|
1072
855
|
collection: this.collection,
|
|
1073
856
|
filter: {}
|
|
@@ -1093,7 +876,8 @@ var CollectionRef = class {
|
|
|
1093
876
|
delete d._id;
|
|
1094
877
|
return DocumentSnapshot.fromMap(d);
|
|
1095
878
|
});
|
|
1096
|
-
} catch {
|
|
879
|
+
} catch (error) {
|
|
880
|
+
console.error("[EdmaxLabs] refreshFromRemote failed:", error);
|
|
1097
881
|
return [];
|
|
1098
882
|
}
|
|
1099
883
|
}
|
|
@@ -1123,13 +907,24 @@ var CollectionRef = class {
|
|
|
1123
907
|
this.syncEngine?.flush().catch(console.error);
|
|
1124
908
|
return snap;
|
|
1125
909
|
}
|
|
1126
|
-
|
|
1127
|
-
|
|
910
|
+
const res = await new HttpsRequest({
|
|
911
|
+
method: "POST" /* POST */,
|
|
912
|
+
endpoint: `${this.app.getBaseUrl()}/db/create`,
|
|
913
|
+
headers: {
|
|
914
|
+
authorization: this.app.getConfig().token,
|
|
915
|
+
"x-project": this.app.getConfig().project
|
|
916
|
+
},
|
|
917
|
+
body: { collection: this.collection, data: { ...data, id: "" } }
|
|
918
|
+
// server will generate id
|
|
919
|
+
}).sendRequest();
|
|
920
|
+
if (!res?.success || !res.document)
|
|
921
|
+
return null;
|
|
922
|
+
return DocumentSnapshot.fromMap(res.document);
|
|
1128
923
|
}
|
|
1129
924
|
onSnapshot(callback) {
|
|
1130
|
-
if (this.app.offline().
|
|
925
|
+
if (this.persistence && this.localStore && this.app.offline().realtimeBridge) {
|
|
1131
926
|
this.app.offline().realtimeBridge?.watchCollection(this.collection);
|
|
1132
|
-
return this.
|
|
927
|
+
return this.localStore.subscribeToCollection(this.collection, callback) ?? (() => {
|
|
1133
928
|
});
|
|
1134
929
|
}
|
|
1135
930
|
return this.app.rtdb().subscribeToCollectionRaw(this.collection, (payload, changes) => {
|
|
@@ -2722,6 +2517,164 @@ var _EdmaxLabs = class _EdmaxLabs {
|
|
|
2722
2517
|
_EdmaxLabs.instance = null;
|
|
2723
2518
|
var EdmaxLabs = _EdmaxLabs;
|
|
2724
2519
|
|
|
2520
|
+
// src/database/Timestamp.ts
|
|
2521
|
+
var Timestamp = class _Timestamp {
|
|
2522
|
+
constructor(seconds, nanoseconds = 0) {
|
|
2523
|
+
this.seconds = seconds;
|
|
2524
|
+
this.nanoseconds = nanoseconds;
|
|
2525
|
+
}
|
|
2526
|
+
static now() {
|
|
2527
|
+
return _Timestamp.fromMillis(Date.now());
|
|
2528
|
+
}
|
|
2529
|
+
static fromDate(date) {
|
|
2530
|
+
return new _Timestamp(
|
|
2531
|
+
Math.floor(date.getTime() / 1e3),
|
|
2532
|
+
date.getTime() % 1e3 * 1e6
|
|
2533
|
+
);
|
|
2534
|
+
}
|
|
2535
|
+
static fromMillis(ms) {
|
|
2536
|
+
return new _Timestamp(Math.floor(ms / 1e3), ms % 1e3 * 1e6);
|
|
2537
|
+
}
|
|
2538
|
+
static fromMongo(dateObj) {
|
|
2539
|
+
return _Timestamp.fromMillis(dateObj.getTime());
|
|
2540
|
+
}
|
|
2541
|
+
static fromJSON(obj) {
|
|
2542
|
+
return new _Timestamp(obj.seconds, obj.nanoseconds);
|
|
2543
|
+
}
|
|
2544
|
+
toDate() {
|
|
2545
|
+
return new Date(this.toMillis());
|
|
2546
|
+
}
|
|
2547
|
+
toMillis() {
|
|
2548
|
+
return this.seconds * 1e3 + Math.floor(this.nanoseconds / 1e6);
|
|
2549
|
+
}
|
|
2550
|
+
sinceEpoch() {
|
|
2551
|
+
return this.seconds;
|
|
2552
|
+
}
|
|
2553
|
+
toMongo() {
|
|
2554
|
+
return new Date(this.toMillis());
|
|
2555
|
+
}
|
|
2556
|
+
format(pattern = "dd-MM-yyyy HH:mm:ss") {
|
|
2557
|
+
const d = this.toDate();
|
|
2558
|
+
const monthsShort = [
|
|
2559
|
+
"Jan",
|
|
2560
|
+
"Feb",
|
|
2561
|
+
"Mar",
|
|
2562
|
+
"Apr",
|
|
2563
|
+
"May",
|
|
2564
|
+
"Jun",
|
|
2565
|
+
"Jul",
|
|
2566
|
+
"Aug",
|
|
2567
|
+
"Sep",
|
|
2568
|
+
"Oct",
|
|
2569
|
+
"Nov",
|
|
2570
|
+
"Dec"
|
|
2571
|
+
];
|
|
2572
|
+
const monthsLong = [
|
|
2573
|
+
"January",
|
|
2574
|
+
"February",
|
|
2575
|
+
"March",
|
|
2576
|
+
"April",
|
|
2577
|
+
"May",
|
|
2578
|
+
"June",
|
|
2579
|
+
"July",
|
|
2580
|
+
"August",
|
|
2581
|
+
"September",
|
|
2582
|
+
"October",
|
|
2583
|
+
"November",
|
|
2584
|
+
"December"
|
|
2585
|
+
];
|
|
2586
|
+
const hours = d.getHours();
|
|
2587
|
+
const hours12 = hours % 12 === 0 ? 12 : hours % 12;
|
|
2588
|
+
const ampm = hours < 12 ? "AM" : "PM";
|
|
2589
|
+
const map = {
|
|
2590
|
+
dd: String(d.getDate()).padStart(2, "0"),
|
|
2591
|
+
MM: String(d.getMonth() + 1).padStart(2, "0"),
|
|
2592
|
+
yyyy: d.getFullYear(),
|
|
2593
|
+
HH: String(d.getHours()).padStart(2, "0"),
|
|
2594
|
+
mm: String(d.getMinutes()).padStart(2, "0"),
|
|
2595
|
+
ss: String(d.getSeconds()).padStart(2, "0"),
|
|
2596
|
+
SSS: String(d.getMilliseconds()).padStart(3, "0"),
|
|
2597
|
+
MMM: monthsShort[d.getMonth()],
|
|
2598
|
+
MMMM: monthsLong[d.getMonth()],
|
|
2599
|
+
a: ampm.toLowerCase(),
|
|
2600
|
+
// am/pm
|
|
2601
|
+
A: ampm
|
|
2602
|
+
// AM/PM
|
|
2603
|
+
};
|
|
2604
|
+
return pattern.replace(
|
|
2605
|
+
/MMMM|MMM|dd|MM|yyyy|HH|mm|ss|SSS|a|A/g,
|
|
2606
|
+
(match) => String(map[match])
|
|
2607
|
+
);
|
|
2608
|
+
}
|
|
2609
|
+
compare(other) {
|
|
2610
|
+
if (this.seconds !== other.seconds) {
|
|
2611
|
+
return this.seconds - other.seconds;
|
|
2612
|
+
}
|
|
2613
|
+
return this.nanoseconds - other.nanoseconds;
|
|
2614
|
+
}
|
|
2615
|
+
relative(fmt = "dd-MM-yyyy HH:mm:ss") {
|
|
2616
|
+
const now = Date.now();
|
|
2617
|
+
const diff = now - this.toMillis();
|
|
2618
|
+
const sec = Math.floor(diff / 1e3);
|
|
2619
|
+
if (sec < 60)
|
|
2620
|
+
return `${sec}s ago`;
|
|
2621
|
+
const min = Math.floor(sec / 60);
|
|
2622
|
+
if (min < 60)
|
|
2623
|
+
return `${min}m ago`;
|
|
2624
|
+
const hrs = Math.floor(min / 60);
|
|
2625
|
+
if (hrs < 24)
|
|
2626
|
+
return `${hrs}h ago`;
|
|
2627
|
+
const days = Math.floor(hrs / 24);
|
|
2628
|
+
if (days < 3)
|
|
2629
|
+
return `${days}d ago`;
|
|
2630
|
+
return this.format(fmt);
|
|
2631
|
+
}
|
|
2632
|
+
add({
|
|
2633
|
+
seconds = 0,
|
|
2634
|
+
minutes = 0,
|
|
2635
|
+
hours = 0,
|
|
2636
|
+
days = 0
|
|
2637
|
+
}) {
|
|
2638
|
+
const totalMs = seconds * 1e3 + minutes * 6e4 + hours * 36e5 + days * 864e5;
|
|
2639
|
+
return _Timestamp.fromMillis(this.toMillis() + totalMs);
|
|
2640
|
+
}
|
|
2641
|
+
weekdayName() {
|
|
2642
|
+
return ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][this.toDate().getDay()];
|
|
2643
|
+
}
|
|
2644
|
+
toJSON() {
|
|
2645
|
+
return {
|
|
2646
|
+
_type: "timestamp",
|
|
2647
|
+
seconds: this.seconds,
|
|
2648
|
+
nanoseconds: this.nanoseconds
|
|
2649
|
+
};
|
|
2650
|
+
}
|
|
2651
|
+
toString() {
|
|
2652
|
+
return this.format("yyyy-MM-dd HH:mm:ss");
|
|
2653
|
+
}
|
|
2654
|
+
};
|
|
2655
|
+
|
|
2656
|
+
// src/database/ArraySnapshot.ts
|
|
2657
|
+
var ArraySnapshot = class _ArraySnapshot {
|
|
2658
|
+
constructor(id = "", index, data, dt) {
|
|
2659
|
+
this.data = data;
|
|
2660
|
+
this.id = id;
|
|
2661
|
+
this.dt = dt ?? Timestamp.now();
|
|
2662
|
+
}
|
|
2663
|
+
static fromMap(map) {
|
|
2664
|
+
const index = map.index ?? map.index ?? -1;
|
|
2665
|
+
const id = map.id ?? map._id ?? "";
|
|
2666
|
+
const document2 = map.data ?? map.document ?? map;
|
|
2667
|
+
return new _ArraySnapshot(id, index, document2);
|
|
2668
|
+
}
|
|
2669
|
+
toMap() {
|
|
2670
|
+
return {
|
|
2671
|
+
id: this.id ?? "",
|
|
2672
|
+
data: this.data,
|
|
2673
|
+
dt: this.dt
|
|
2674
|
+
};
|
|
2675
|
+
}
|
|
2676
|
+
};
|
|
2677
|
+
|
|
2725
2678
|
// src/index.ts
|
|
2726
2679
|
var src_default = EdmaxLabs;
|
|
2727
2680
|
// Annotate the CommonJS export names for ESM import in node:
|