edmaxlabs-core 2.5.0 → 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 +422 -461
- 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 +422 -461
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// src/authentication/Credentials.ts
|
|
2
2
|
var Credentials = class _Credentials {
|
|
3
|
-
constructor(uid, displayInfo, createdAt, updatedAt, lastLogged) {
|
|
3
|
+
constructor(uid, displayInfo, createdAt, updatedAt, lastLogged, logged) {
|
|
4
4
|
this.uid = uid;
|
|
5
5
|
this.displayInfo = displayInfo;
|
|
6
6
|
this.createdAt = createdAt;
|
|
7
7
|
this.updatedAt = updatedAt;
|
|
8
8
|
this.lastLogged = lastLogged;
|
|
9
|
+
this.logged = logged === true;
|
|
9
10
|
}
|
|
10
11
|
static fromMap(map) {
|
|
11
12
|
const uid = map.id ?? map.uid ?? "";
|
|
@@ -14,12 +15,14 @@ var Credentials = class _Credentials {
|
|
|
14
15
|
const createdAt = data.createdAt;
|
|
15
16
|
const updatedAt = data.updatedAt;
|
|
16
17
|
const lastLogged = data.lastLogged;
|
|
18
|
+
const logged = data.logged;
|
|
17
19
|
const result = new _Credentials(
|
|
18
20
|
uid,
|
|
19
21
|
d_info,
|
|
20
22
|
createdAt,
|
|
21
23
|
updatedAt,
|
|
22
|
-
lastLogged
|
|
24
|
+
lastLogged,
|
|
25
|
+
logged
|
|
23
26
|
);
|
|
24
27
|
return result;
|
|
25
28
|
}
|
|
@@ -29,7 +32,8 @@ var Credentials = class _Credentials {
|
|
|
29
32
|
displayInfo: this.displayInfo,
|
|
30
33
|
createdAt: this.createdAt,
|
|
31
34
|
updatedAt: this.updatedAt,
|
|
32
|
-
lastLogged: this.lastLogged
|
|
35
|
+
lastLogged: this.lastLogged,
|
|
36
|
+
logged: this.logged
|
|
33
37
|
};
|
|
34
38
|
}
|
|
35
39
|
};
|
|
@@ -97,91 +101,123 @@ var HttpsRequest = class {
|
|
|
97
101
|
|
|
98
102
|
// src/authentication/Authentication.ts
|
|
99
103
|
var _Authentication = class _Authentication {
|
|
100
|
-
// Re-entrancy guard
|
|
101
104
|
constructor() {
|
|
102
|
-
this.eUser = null;
|
|
103
|
-
this.client = null;
|
|
104
|
-
this.app = null;
|
|
105
|
-
// Dedicated lightweight instance for auth
|
|
106
105
|
this.eventListeners = /* @__PURE__ */ new Map();
|
|
107
|
-
this.
|
|
108
|
-
|
|
106
|
+
this.eventWaiters = /* @__PURE__ */ new Map();
|
|
107
|
+
this.unsubscribers = /* @__PURE__ */ new Set();
|
|
108
|
+
this.isSameCredentials = (a, b) => {
|
|
109
|
+
if (!a && !b)
|
|
110
|
+
return true;
|
|
111
|
+
if (!a || !b)
|
|
112
|
+
return false;
|
|
113
|
+
return JSON.stringify(a.toMap()) === JSON.stringify(b.toMap());
|
|
114
|
+
};
|
|
109
115
|
this.createUserWithEmailAndPassword = async ({
|
|
110
116
|
email,
|
|
111
117
|
password
|
|
112
118
|
}) => {
|
|
119
|
+
this.eUser = void 0;
|
|
113
120
|
this.saveCredentials(null);
|
|
114
|
-
const app = this.app
|
|
115
|
-
const
|
|
116
|
-
|
|
121
|
+
const app = this.app?.getDatabase;
|
|
122
|
+
const data = await app?.collection("users").query.where({
|
|
123
|
+
key: "email",
|
|
124
|
+
op: "===",
|
|
125
|
+
value: email
|
|
126
|
+
}).get();
|
|
127
|
+
if (data.length > 0) {
|
|
117
128
|
throw new Error("Email Already In Use.");
|
|
118
129
|
}
|
|
119
|
-
const userRef = await app
|
|
130
|
+
const userRef = await app?.collection("users").add({
|
|
120
131
|
email,
|
|
121
132
|
password,
|
|
122
|
-
token: this.client.getConfig().token,
|
|
123
133
|
logged: true,
|
|
124
|
-
lastLogged: Date.now()
|
|
134
|
+
lastLogged: Date.now(),
|
|
135
|
+
displayInfo: {
|
|
136
|
+
firstname: email.split("@")[0],
|
|
137
|
+
lastname: "",
|
|
138
|
+
surname: "",
|
|
139
|
+
profile: "./logo.png",
|
|
140
|
+
email,
|
|
141
|
+
phone: ""
|
|
142
|
+
}
|
|
125
143
|
});
|
|
126
|
-
if (!userRef?.id) {
|
|
127
|
-
throw new Error("Something went wrong
|
|
144
|
+
if (!userRef?.id || userRef?.id === "") {
|
|
145
|
+
throw new Error("Something went wrong try Again.");
|
|
128
146
|
}
|
|
129
|
-
|
|
130
|
-
this.saveCredentials(
|
|
131
|
-
return
|
|
147
|
+
this.eUser = Credentials.fromMap(userRef);
|
|
148
|
+
this.saveCredentials(this.eUser);
|
|
149
|
+
return Credentials.fromMap(userRef.toMap());
|
|
132
150
|
};
|
|
133
151
|
this.signInWithEmailAndPassword = async ({
|
|
134
152
|
email,
|
|
135
153
|
password
|
|
136
154
|
}) => {
|
|
137
|
-
const app = this.app
|
|
138
|
-
const data = await app
|
|
139
|
-
|
|
155
|
+
const app = this.app?.getDatabase;
|
|
156
|
+
const data = await app?.collection("users").query.where({
|
|
157
|
+
key: "email",
|
|
158
|
+
op: "===",
|
|
159
|
+
value: email
|
|
160
|
+
}).where({
|
|
161
|
+
key: "password",
|
|
162
|
+
op: "===",
|
|
163
|
+
value: password
|
|
164
|
+
}).get();
|
|
165
|
+
if (data === void 0) {
|
|
166
|
+
throw new Error("Auth Failed.");
|
|
167
|
+
}
|
|
168
|
+
if (data?.length === 0) {
|
|
140
169
|
throw new Error("User Not Found.");
|
|
141
170
|
}
|
|
142
|
-
const
|
|
143
|
-
await app
|
|
171
|
+
const _data = data[0];
|
|
172
|
+
await app?.collection("users").doc(_data.id).update({
|
|
144
173
|
logged: true,
|
|
145
174
|
lastLogged: Date.now()
|
|
146
175
|
});
|
|
147
|
-
|
|
148
|
-
this.saveCredentials(
|
|
149
|
-
return
|
|
150
|
-
};
|
|
151
|
-
this.signOut = async () => {
|
|
152
|
-
const current = this.currentUser();
|
|
153
|
-
if (!current)
|
|
154
|
-
return;
|
|
155
|
-
const app = this.app.getDatabase;
|
|
156
|
-
await app.collection("users").doc(current.uid).update({
|
|
157
|
-
logged: false,
|
|
158
|
-
lastLogged: Date.now()
|
|
159
|
-
});
|
|
160
|
-
this.saveCredentials(null);
|
|
176
|
+
this.eUser = Credentials.fromMap(_data);
|
|
177
|
+
this.saveCredentials(this.eUser);
|
|
178
|
+
return Credentials.fromMap(_data);
|
|
161
179
|
};
|
|
162
180
|
this.deleteUser = async () => {
|
|
163
|
-
if (!this.eUser)
|
|
181
|
+
if (!this.eUser) {
|
|
164
182
|
throw new Error("No User Signed in");
|
|
165
|
-
|
|
166
|
-
|
|
183
|
+
}
|
|
184
|
+
const app = this.app?.getDatabase;
|
|
185
|
+
const userRef = await app?.collection("users").doc(this.eUser.uid).delete();
|
|
186
|
+
if (userRef) {
|
|
187
|
+
throw new Error("Something went wrong try Again.");
|
|
188
|
+
}
|
|
189
|
+
this.eUser = void 0;
|
|
190
|
+
this.saveCredentials(null);
|
|
191
|
+
};
|
|
192
|
+
this.signOut = async () => {
|
|
193
|
+
const app = this.app?.getDatabase;
|
|
194
|
+
const luid = this.currentUser();
|
|
195
|
+
this.eUser = void 0;
|
|
167
196
|
this.saveCredentials(null);
|
|
197
|
+
if (luid)
|
|
198
|
+
await app?.collection("users").doc(luid?.uid).update({
|
|
199
|
+
logged: false,
|
|
200
|
+
lastLogged: Date.now()
|
|
201
|
+
});
|
|
202
|
+
return;
|
|
168
203
|
};
|
|
169
|
-
// Optional: Rules verification
|
|
170
204
|
this.rules = async (path, context) => {
|
|
171
205
|
const res = await new HttpsRequest({
|
|
172
206
|
method: "POST" /* POST */,
|
|
173
|
-
endpoint:
|
|
207
|
+
endpoint: this.client.getBaseUrl() + "/auth/rules/verify",
|
|
174
208
|
headers: {
|
|
175
209
|
authorization: this.client.getConfig().token,
|
|
176
210
|
project: this.client.getConfig().project
|
|
177
211
|
},
|
|
178
|
-
body: {
|
|
212
|
+
body: {
|
|
213
|
+
path,
|
|
214
|
+
context
|
|
215
|
+
}
|
|
179
216
|
}).sendRequest();
|
|
180
217
|
return res;
|
|
181
218
|
};
|
|
182
|
-
if (_Authentication.instance)
|
|
219
|
+
if (_Authentication.instance)
|
|
183
220
|
return _Authentication.instance;
|
|
184
|
-
}
|
|
185
221
|
this.client = EdmaxLabs.instance;
|
|
186
222
|
this.app = new EdmaxLabs({
|
|
187
223
|
token: "auth",
|
|
@@ -190,16 +226,26 @@ var _Authentication = class _Authentication {
|
|
|
190
226
|
_Authentication.instance = this;
|
|
191
227
|
this.restoreSession();
|
|
192
228
|
}
|
|
229
|
+
restoreSession() {
|
|
230
|
+
const saved = this.currentUser();
|
|
231
|
+
if (saved) {
|
|
232
|
+
this.eUser = saved;
|
|
233
|
+
this.emitValue("creds", saved);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
// Better singleton
|
|
193
237
|
static getInstance() {
|
|
194
238
|
if (!_Authentication.instance) {
|
|
195
239
|
_Authentication.instance = new _Authentication();
|
|
196
240
|
}
|
|
197
241
|
return _Authentication.instance;
|
|
198
242
|
}
|
|
199
|
-
// ====================== EVENT SYSTEM ======================
|
|
200
243
|
emitValue(key, value) {
|
|
201
244
|
const listeners = this.eventListeners.get(key) || [];
|
|
202
|
-
|
|
245
|
+
listeners.forEach((l) => l(value));
|
|
246
|
+
const waiters = this.eventWaiters.get(key) || [];
|
|
247
|
+
waiters.forEach((resolve) => resolve(value));
|
|
248
|
+
this.eventWaiters.delete(key);
|
|
203
249
|
}
|
|
204
250
|
onValue(key, callback) {
|
|
205
251
|
const listeners = this.eventListeners.get(key) || [];
|
|
@@ -210,7 +256,6 @@ var _Authentication = class _Authentication {
|
|
|
210
256
|
this.eventListeners.set(key, filtered);
|
|
211
257
|
};
|
|
212
258
|
}
|
|
213
|
-
// ====================== CREDENTIALS ======================
|
|
214
259
|
currentUser() {
|
|
215
260
|
const data = localStorage.getItem("eauth");
|
|
216
261
|
if (!data)
|
|
@@ -233,71 +278,50 @@ var _Authentication = class _Authentication {
|
|
|
233
278
|
this.eUser = credentials;
|
|
234
279
|
this.emitValue("creds", credentials);
|
|
235
280
|
}
|
|
236
|
-
|
|
237
|
-
if (!a && !b)
|
|
238
|
-
return true;
|
|
239
|
-
if (!a || !b)
|
|
240
|
-
return false;
|
|
241
|
-
return a.uid === b.uid && a.displayInfo.email === b.displayInfo.email && a.lastLogged === b.lastLogged;
|
|
242
|
-
}
|
|
243
|
-
restoreSession() {
|
|
244
|
-
const saved = this.currentUser();
|
|
245
|
-
if (saved) {
|
|
246
|
-
this.eUser = saved;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
// ====================== MAIN AUTH STATE LISTENER ======================
|
|
250
|
-
/**
|
|
251
|
-
* Main method to listen to authentication state changes.
|
|
252
|
-
* This listener stays alive for the entire app lifetime.
|
|
253
|
-
*/
|
|
281
|
+
// Main auth state listener - should be called ONCE at app root
|
|
254
282
|
authState({
|
|
255
283
|
onChange,
|
|
256
284
|
onSignOut,
|
|
257
285
|
onDeleted
|
|
258
286
|
}) {
|
|
259
287
|
let userDocUnsubscribe;
|
|
260
|
-
let credsUnsub;
|
|
261
288
|
const handleCredsChange = (creds) => {
|
|
262
|
-
if (
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
userDocUnsubscribe = void 0;
|
|
289
|
+
if (userDocUnsubscribe) {
|
|
290
|
+
userDocUnsubscribe();
|
|
291
|
+
userDocUnsubscribe = void 0;
|
|
292
|
+
}
|
|
267
293
|
if (!creds) {
|
|
268
294
|
this.eUser = null;
|
|
269
295
|
onSignOut?.();
|
|
270
|
-
this.isHandlingChange = false;
|
|
271
296
|
return;
|
|
272
297
|
}
|
|
273
|
-
const userRef = this.app
|
|
298
|
+
const userRef = this.app?.getDatabase.collection("users").doc(creds.uid);
|
|
299
|
+
if (!userRef)
|
|
300
|
+
return;
|
|
274
301
|
userDocUnsubscribe = userRef.onSnapshot(
|
|
275
302
|
(snapshot, change) => {
|
|
303
|
+
console.log(snapshot);
|
|
276
304
|
if (change === "delete") {
|
|
277
305
|
this.saveCredentials(null);
|
|
278
306
|
onSignOut?.();
|
|
279
307
|
onDeleted?.();
|
|
280
|
-
this.isHandlingChange = false;
|
|
281
308
|
return;
|
|
282
309
|
}
|
|
283
310
|
if (change === "insert" || change === "update") {
|
|
284
|
-
if (!snapshot
|
|
285
|
-
this.isHandlingChange = false;
|
|
311
|
+
if (!snapshot)
|
|
286
312
|
return;
|
|
287
|
-
}
|
|
288
313
|
if (snapshot.data.logged === false || snapshot.data.logged === "false") {
|
|
289
314
|
this.saveCredentials(null);
|
|
290
315
|
onSignOut?.();
|
|
291
|
-
this.isHandlingChange = false;
|
|
292
316
|
return;
|
|
293
317
|
}
|
|
294
318
|
const newCreds = Credentials.fromMap(snapshot.toMap());
|
|
295
319
|
if (!this.isSameCredentials(this.eUser, newCreds)) {
|
|
320
|
+
this.eUser = newCreds;
|
|
296
321
|
this.saveCredentials(newCreds);
|
|
297
322
|
onChange(newCreds);
|
|
298
323
|
}
|
|
299
324
|
}
|
|
300
|
-
this.isHandlingChange = false;
|
|
301
325
|
}
|
|
302
326
|
);
|
|
303
327
|
};
|
|
@@ -306,10 +330,10 @@ var _Authentication = class _Authentication {
|
|
|
306
330
|
this.eUser = initialUser;
|
|
307
331
|
onChange(initialUser);
|
|
308
332
|
}
|
|
309
|
-
credsUnsub = this.onValue("creds", handleCredsChange);
|
|
310
333
|
handleCredsChange(initialUser);
|
|
334
|
+
const credsUnsub = this.onValue("creds", handleCredsChange);
|
|
311
335
|
return () => {
|
|
312
|
-
credsUnsub
|
|
336
|
+
credsUnsub();
|
|
313
337
|
userDocUnsubscribe?.();
|
|
314
338
|
};
|
|
315
339
|
}
|
|
@@ -336,308 +360,6 @@ var DocumentSnapshot = class _DocumentSnapshot {
|
|
|
336
360
|
}
|
|
337
361
|
};
|
|
338
362
|
|
|
339
|
-
// src/database/Timestamp.ts
|
|
340
|
-
var Timestamp = class _Timestamp {
|
|
341
|
-
constructor(seconds, nanoseconds = 0) {
|
|
342
|
-
this.seconds = seconds;
|
|
343
|
-
this.nanoseconds = nanoseconds;
|
|
344
|
-
}
|
|
345
|
-
static now() {
|
|
346
|
-
return _Timestamp.fromMillis(Date.now());
|
|
347
|
-
}
|
|
348
|
-
static fromDate(date) {
|
|
349
|
-
return new _Timestamp(
|
|
350
|
-
Math.floor(date.getTime() / 1e3),
|
|
351
|
-
date.getTime() % 1e3 * 1e6
|
|
352
|
-
);
|
|
353
|
-
}
|
|
354
|
-
static fromMillis(ms) {
|
|
355
|
-
return new _Timestamp(Math.floor(ms / 1e3), ms % 1e3 * 1e6);
|
|
356
|
-
}
|
|
357
|
-
static fromMongo(dateObj) {
|
|
358
|
-
return _Timestamp.fromMillis(dateObj.getTime());
|
|
359
|
-
}
|
|
360
|
-
static fromJSON(obj) {
|
|
361
|
-
return new _Timestamp(obj.seconds, obj.nanoseconds);
|
|
362
|
-
}
|
|
363
|
-
toDate() {
|
|
364
|
-
return new Date(this.toMillis());
|
|
365
|
-
}
|
|
366
|
-
toMillis() {
|
|
367
|
-
return this.seconds * 1e3 + Math.floor(this.nanoseconds / 1e6);
|
|
368
|
-
}
|
|
369
|
-
sinceEpoch() {
|
|
370
|
-
return this.seconds;
|
|
371
|
-
}
|
|
372
|
-
toMongo() {
|
|
373
|
-
return new Date(this.toMillis());
|
|
374
|
-
}
|
|
375
|
-
format(pattern = "dd-MM-yyyy HH:mm:ss") {
|
|
376
|
-
const d = this.toDate();
|
|
377
|
-
const monthsShort = [
|
|
378
|
-
"Jan",
|
|
379
|
-
"Feb",
|
|
380
|
-
"Mar",
|
|
381
|
-
"Apr",
|
|
382
|
-
"May",
|
|
383
|
-
"Jun",
|
|
384
|
-
"Jul",
|
|
385
|
-
"Aug",
|
|
386
|
-
"Sep",
|
|
387
|
-
"Oct",
|
|
388
|
-
"Nov",
|
|
389
|
-
"Dec"
|
|
390
|
-
];
|
|
391
|
-
const monthsLong = [
|
|
392
|
-
"January",
|
|
393
|
-
"February",
|
|
394
|
-
"March",
|
|
395
|
-
"April",
|
|
396
|
-
"May",
|
|
397
|
-
"June",
|
|
398
|
-
"July",
|
|
399
|
-
"August",
|
|
400
|
-
"September",
|
|
401
|
-
"October",
|
|
402
|
-
"November",
|
|
403
|
-
"December"
|
|
404
|
-
];
|
|
405
|
-
const hours = d.getHours();
|
|
406
|
-
const hours12 = hours % 12 === 0 ? 12 : hours % 12;
|
|
407
|
-
const ampm = hours < 12 ? "AM" : "PM";
|
|
408
|
-
const map = {
|
|
409
|
-
dd: String(d.getDate()).padStart(2, "0"),
|
|
410
|
-
MM: String(d.getMonth() + 1).padStart(2, "0"),
|
|
411
|
-
yyyy: d.getFullYear(),
|
|
412
|
-
HH: String(d.getHours()).padStart(2, "0"),
|
|
413
|
-
mm: String(d.getMinutes()).padStart(2, "0"),
|
|
414
|
-
ss: String(d.getSeconds()).padStart(2, "0"),
|
|
415
|
-
SSS: String(d.getMilliseconds()).padStart(3, "0"),
|
|
416
|
-
MMM: monthsShort[d.getMonth()],
|
|
417
|
-
MMMM: monthsLong[d.getMonth()],
|
|
418
|
-
a: ampm.toLowerCase(),
|
|
419
|
-
// am/pm
|
|
420
|
-
A: ampm
|
|
421
|
-
// AM/PM
|
|
422
|
-
};
|
|
423
|
-
return pattern.replace(
|
|
424
|
-
/MMMM|MMM|dd|MM|yyyy|HH|mm|ss|SSS|a|A/g,
|
|
425
|
-
(match) => String(map[match])
|
|
426
|
-
);
|
|
427
|
-
}
|
|
428
|
-
compare(other) {
|
|
429
|
-
if (this.seconds !== other.seconds) {
|
|
430
|
-
return this.seconds - other.seconds;
|
|
431
|
-
}
|
|
432
|
-
return this.nanoseconds - other.nanoseconds;
|
|
433
|
-
}
|
|
434
|
-
relative(fmt = "dd-MM-yyyy HH:mm:ss") {
|
|
435
|
-
const now = Date.now();
|
|
436
|
-
const diff = now - this.toMillis();
|
|
437
|
-
const sec = Math.floor(diff / 1e3);
|
|
438
|
-
if (sec < 60)
|
|
439
|
-
return `${sec}s ago`;
|
|
440
|
-
const min = Math.floor(sec / 60);
|
|
441
|
-
if (min < 60)
|
|
442
|
-
return `${min}m ago`;
|
|
443
|
-
const hrs = Math.floor(min / 60);
|
|
444
|
-
if (hrs < 24)
|
|
445
|
-
return `${hrs}h ago`;
|
|
446
|
-
const days = Math.floor(hrs / 24);
|
|
447
|
-
if (days < 3)
|
|
448
|
-
return `${days}d ago`;
|
|
449
|
-
return this.format(fmt);
|
|
450
|
-
}
|
|
451
|
-
add({
|
|
452
|
-
seconds = 0,
|
|
453
|
-
minutes = 0,
|
|
454
|
-
hours = 0,
|
|
455
|
-
days = 0
|
|
456
|
-
}) {
|
|
457
|
-
const totalMs = seconds * 1e3 + minutes * 6e4 + hours * 36e5 + days * 864e5;
|
|
458
|
-
return _Timestamp.fromMillis(this.toMillis() + totalMs);
|
|
459
|
-
}
|
|
460
|
-
weekdayName() {
|
|
461
|
-
return ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][this.toDate().getDay()];
|
|
462
|
-
}
|
|
463
|
-
toJSON() {
|
|
464
|
-
return {
|
|
465
|
-
_type: "timestamp",
|
|
466
|
-
seconds: this.seconds,
|
|
467
|
-
nanoseconds: this.nanoseconds
|
|
468
|
-
};
|
|
469
|
-
}
|
|
470
|
-
toString() {
|
|
471
|
-
return this.format("yyyy-MM-dd HH:mm:ss");
|
|
472
|
-
}
|
|
473
|
-
};
|
|
474
|
-
|
|
475
|
-
// src/database/ArraySnapshot.ts
|
|
476
|
-
var ArraySnapshot = class _ArraySnapshot {
|
|
477
|
-
constructor(id = "", index, data, dt) {
|
|
478
|
-
this.data = data;
|
|
479
|
-
this.id = id;
|
|
480
|
-
this.dt = dt ?? Timestamp.now();
|
|
481
|
-
}
|
|
482
|
-
static fromMap(map) {
|
|
483
|
-
const index = map.index ?? map.index ?? -1;
|
|
484
|
-
const id = map.id ?? map._id ?? "";
|
|
485
|
-
const document2 = map.data ?? map.document ?? map;
|
|
486
|
-
return new _ArraySnapshot(id, index, document2);
|
|
487
|
-
}
|
|
488
|
-
toMap() {
|
|
489
|
-
return {
|
|
490
|
-
id: this.id ?? "",
|
|
491
|
-
data: this.data,
|
|
492
|
-
dt: this.dt
|
|
493
|
-
};
|
|
494
|
-
}
|
|
495
|
-
};
|
|
496
|
-
|
|
497
|
-
// src/database/Array.ts
|
|
498
|
-
var Array2 = class {
|
|
499
|
-
constructor(app, collection, key, id) {
|
|
500
|
-
this.app = app;
|
|
501
|
-
this.collection = collection;
|
|
502
|
-
this.key = key;
|
|
503
|
-
this.docID = id;
|
|
504
|
-
this.persistence = app.offline().persistence;
|
|
505
|
-
this.syncEngine = app.offline().syncEngine;
|
|
506
|
-
this.localStore = app.offline().localStore;
|
|
507
|
-
}
|
|
508
|
-
/**
|
|
509
|
-
* Get current array elements (offline-first: prefers local cache)
|
|
510
|
-
*/
|
|
511
|
-
async show() {
|
|
512
|
-
if (this.persistence) {
|
|
513
|
-
const doc = await this.persistence.getDoc(this.collection, this.docID);
|
|
514
|
-
if (doc?.exists && !doc.deleted) {
|
|
515
|
-
const arrayData = doc.data[this.key] || [];
|
|
516
|
-
return arrayData.map((item) => ArraySnapshot.fromMap(item));
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
if (typeof navigator === "undefined" || navigator.onLine) {
|
|
520
|
-
this.refreshFromRemote().catch(() => {
|
|
521
|
-
});
|
|
522
|
-
}
|
|
523
|
-
return [];
|
|
524
|
-
}
|
|
525
|
-
async refreshFromRemote() {
|
|
526
|
-
try {
|
|
527
|
-
const res = await new HttpsRequest({
|
|
528
|
-
method: "POST" /* POST */,
|
|
529
|
-
endpoint: `${this.app.getBaseUrl()}/db/array/show`,
|
|
530
|
-
headers: { authorization: this.app.getConfig().token, "x-project": this.app.getConfig().project },
|
|
531
|
-
body: {
|
|
532
|
-
collection: this.collection,
|
|
533
|
-
document: this.docID,
|
|
534
|
-
array: this.key
|
|
535
|
-
}
|
|
536
|
-
}).sendRequest();
|
|
537
|
-
if (!res?.success || !globalThis.Array.isArray(res.documents)) {
|
|
538
|
-
return [];
|
|
539
|
-
}
|
|
540
|
-
const snapshots = res.documents.filter((d) => d != null).map((d) => ArraySnapshot.fromMap(d));
|
|
541
|
-
if (this.persistence) {
|
|
542
|
-
const currentDoc = await this.persistence.getDoc(this.collection, this.docID);
|
|
543
|
-
if (currentDoc) {
|
|
544
|
-
await this.persistence.upsertDoc({
|
|
545
|
-
...currentDoc,
|
|
546
|
-
data: { ...currentDoc.data, [this.key]: res.documents },
|
|
547
|
-
pending: 0,
|
|
548
|
-
status: "synced",
|
|
549
|
-
lastSyncedAt: Date.now()
|
|
550
|
-
});
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
return snapshots;
|
|
554
|
-
} catch {
|
|
555
|
-
return [];
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
async push(data, id) {
|
|
559
|
-
const payload = {
|
|
560
|
-
data,
|
|
561
|
-
id: id || this.persistence?.createLocalId?.() || void 0,
|
|
562
|
-
dt: Timestamp.now()
|
|
563
|
-
};
|
|
564
|
-
if (this.persistence) {
|
|
565
|
-
await this.persistence.enqueueMutation({
|
|
566
|
-
mutationId: this.persistence.createMutationId(),
|
|
567
|
-
collection: this.collection,
|
|
568
|
-
documentId: this.docID,
|
|
569
|
-
type: "array_push",
|
|
570
|
-
// custom type
|
|
571
|
-
payload: { arrayKey: this.key, ...payload }
|
|
572
|
-
});
|
|
573
|
-
this.syncEngine?.flush().catch(console.error);
|
|
574
|
-
const doc = await this.persistence.getDoc(this.collection, this.docID);
|
|
575
|
-
if (doc) {
|
|
576
|
-
const updatedArray = [...doc.data[this.key] || [], payload];
|
|
577
|
-
const snap = ArraySnapshot.fromMap(payload);
|
|
578
|
-
this.localStore?.emitDocument(
|
|
579
|
-
this.collection,
|
|
580
|
-
this.docID,
|
|
581
|
-
DocumentSnapshot.fromMap({ ...doc.data, [this.key]: updatedArray }),
|
|
582
|
-
"update"
|
|
583
|
-
);
|
|
584
|
-
}
|
|
585
|
-
return ArraySnapshot.fromMap(payload);
|
|
586
|
-
}
|
|
587
|
-
const res = await new HttpsRequest({
|
|
588
|
-
method: "POST" /* POST */,
|
|
589
|
-
endpoint: `${this.app.getBaseUrl()}/db/array/push`,
|
|
590
|
-
headers: { authorization: this.app.getConfig().token, "x-project": this.app.getConfig().project },
|
|
591
|
-
body: {
|
|
592
|
-
collection: this.collection,
|
|
593
|
-
document: this.docID,
|
|
594
|
-
array: this.key,
|
|
595
|
-
...payload
|
|
596
|
-
}
|
|
597
|
-
}).sendRequest();
|
|
598
|
-
return res?.success ? ArraySnapshot.fromMap(res.document) : null;
|
|
599
|
-
}
|
|
600
|
-
// Similar pattern for update, insert, remove, get...
|
|
601
|
-
// (I'll show one more as example; apply the same logic to the rest)
|
|
602
|
-
async update(position, data, id) {
|
|
603
|
-
if (this.persistence) {
|
|
604
|
-
await this.persistence.enqueueMutation({
|
|
605
|
-
mutationId: this.persistence.createMutationId(),
|
|
606
|
-
collection: this.collection,
|
|
607
|
-
documentId: this.docID,
|
|
608
|
-
type: "array_update",
|
|
609
|
-
payload: { arrayKey: this.key, position, data, id }
|
|
610
|
-
});
|
|
611
|
-
this.syncEngine?.flush().catch(console.error);
|
|
612
|
-
return ArraySnapshot.fromMap({ ...data, id });
|
|
613
|
-
}
|
|
614
|
-
const res = await new HttpsRequest({
|
|
615
|
-
method: "POST" /* POST */,
|
|
616
|
-
endpoint: `${this.app.getBaseUrl()}/db/array/update`,
|
|
617
|
-
headers: { authorization: this.app.getConfig().token, "x-project": this.app.getConfig().project },
|
|
618
|
-
body: {
|
|
619
|
-
collection: this.collection,
|
|
620
|
-
document: this.docID,
|
|
621
|
-
array: this.key,
|
|
622
|
-
position,
|
|
623
|
-
data,
|
|
624
|
-
id
|
|
625
|
-
}
|
|
626
|
-
}).sendRequest();
|
|
627
|
-
return res?.success ? ArraySnapshot.fromMap(res.document) : null;
|
|
628
|
-
}
|
|
629
|
-
// TODO: Implement insert(), get(), remove() using the exact same offline pattern as push/update
|
|
630
|
-
async insert(position, data, id) {
|
|
631
|
-
return null;
|
|
632
|
-
}
|
|
633
|
-
async get(position) {
|
|
634
|
-
return null;
|
|
635
|
-
}
|
|
636
|
-
async remove(position) {
|
|
637
|
-
return null;
|
|
638
|
-
}
|
|
639
|
-
};
|
|
640
|
-
|
|
641
363
|
// src/utils/documentNomalizer.ts
|
|
642
364
|
function normalizePayload(payload) {
|
|
643
365
|
const raw = payload?.document ?? payload?.data ?? payload;
|
|
@@ -657,11 +379,8 @@ function validateDocumentData(data, operation) {
|
|
|
657
379
|
if (data === null || data === void 0) {
|
|
658
380
|
throw new Error(`${operation}: data cannot be null or undefined`);
|
|
659
381
|
}
|
|
660
|
-
if (typeof data !== "object") {
|
|
661
|
-
throw new Error(`${operation}: data must be
|
|
662
|
-
}
|
|
663
|
-
if (data instanceof Array2) {
|
|
664
|
-
throw new Error(`${operation}: data cannot be an array`);
|
|
382
|
+
if (typeof data !== "object" || Array.isArray(data)) {
|
|
383
|
+
throw new Error(`${operation}: data must be a plain object`);
|
|
665
384
|
}
|
|
666
385
|
const reservedFields = ["id", "_id", "_createdAt", "_updatedAt", "_deleted"];
|
|
667
386
|
for (const field of reservedFields) {
|
|
@@ -669,18 +388,18 @@ function validateDocumentData(data, operation) {
|
|
|
669
388
|
throw new Error(`${operation}: '${field}' is a reserved field and cannot be set manually`);
|
|
670
389
|
}
|
|
671
390
|
}
|
|
672
|
-
const dataSize = JSON.stringify(data).length;
|
|
673
|
-
if (dataSize > 1024 * 1024) {
|
|
674
|
-
throw new Error(`${operation}: document size (${Math.round(dataSize / 1024)}KB) exceeds maximum allowed size (1MB)`);
|
|
675
|
-
}
|
|
676
391
|
try {
|
|
677
|
-
JSON.stringify(data);
|
|
392
|
+
const size = JSON.stringify(data).length;
|
|
393
|
+
if (size > 1024 * 1024) {
|
|
394
|
+
throw new Error(`${operation}: document too large (max 1MB)`);
|
|
395
|
+
}
|
|
678
396
|
} catch {
|
|
679
397
|
throw new Error(`${operation}: data contains circular references`);
|
|
680
398
|
}
|
|
681
399
|
}
|
|
682
400
|
var DocumentRef = class {
|
|
683
401
|
constructor(app, collection, id) {
|
|
402
|
+
this._isUpdating = false;
|
|
684
403
|
this.app = app;
|
|
685
404
|
this.collection = collection;
|
|
686
405
|
this.id = id;
|
|
@@ -688,58 +407,60 @@ var DocumentRef = class {
|
|
|
688
407
|
this.syncEngine = app.offline().syncEngine;
|
|
689
408
|
this.localStore = app.offline().localStore;
|
|
690
409
|
}
|
|
410
|
+
// ====================== GET ======================
|
|
691
411
|
async get() {
|
|
692
412
|
if (this.persistence) {
|
|
693
413
|
try {
|
|
694
414
|
const localSnap = await this.persistence.getDocSnapshot(this.collection, this.id);
|
|
695
415
|
if (localSnap)
|
|
696
|
-
return localSnap;
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
localOnly: false,
|
|
723
|
-
status: "pending"
|
|
724
|
-
});
|
|
725
|
-
await this.persistence.enqueueMutation({
|
|
726
|
-
mutationId: this.persistence.createMutationId(),
|
|
727
|
-
collection: this.collection,
|
|
728
|
-
documentId: this.id,
|
|
729
|
-
type: "insert",
|
|
730
|
-
// or "create" if you want to distinguish truly new docs
|
|
731
|
-
payload: data
|
|
732
|
-
});
|
|
733
|
-
const snap = DocumentSnapshot.fromMap(updated.data);
|
|
734
|
-
this.localStore?.emitDocument(this.collection, this.id, snap, "update");
|
|
735
|
-
const currentCollection = await this.persistence.getCollectionSnapshots(this.collection);
|
|
736
|
-
this.localStore?.emitCollection(this.collection, currentCollection, "update", this.id);
|
|
737
|
-
this.syncEngine?.flush().catch(console.error);
|
|
738
|
-
return snap;
|
|
416
|
+
return localSnap;
|
|
417
|
+
} catch (error) {
|
|
418
|
+
console.error("[EdmaxLabs] Cache read error:", error);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
try {
|
|
422
|
+
const res = await new HttpsRequest({
|
|
423
|
+
method: "POST" /* POST */,
|
|
424
|
+
endpoint: `${this.app.getBaseUrl()}/db/read`,
|
|
425
|
+
headers: {
|
|
426
|
+
authorization: this.app.getConfig().token,
|
|
427
|
+
"x-project": this.app.getConfig().project
|
|
428
|
+
},
|
|
429
|
+
body: {
|
|
430
|
+
collection: this.collection,
|
|
431
|
+
id: this.id,
|
|
432
|
+
single: true
|
|
433
|
+
}
|
|
434
|
+
}).sendRequest();
|
|
435
|
+
if (!res?.success || !res.document)
|
|
436
|
+
return null;
|
|
437
|
+
return DocumentSnapshot.fromMap(res.document);
|
|
438
|
+
} catch (error) {
|
|
439
|
+
console.error(`[DocumentRef] get(${this.collection}/${this.id}) failed:`, error);
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
739
442
|
}
|
|
443
|
+
// ====================== UPDATE ======================
|
|
740
444
|
async update(data) {
|
|
741
|
-
|
|
742
|
-
|
|
445
|
+
if (this._isUpdating) {
|
|
446
|
+
console.warn(`[DocumentRef] update recursion blocked on ${this.collection}/${this.id}`);
|
|
447
|
+
return null;
|
|
448
|
+
}
|
|
449
|
+
this._isUpdating = true;
|
|
450
|
+
try {
|
|
451
|
+
validateDocumentData(data, "DocumentRef.update");
|
|
452
|
+
if (!this.persistence) {
|
|
453
|
+
const res = await new HttpsRequest({
|
|
454
|
+
method: "POST" /* POST */,
|
|
455
|
+
endpoint: `${this.app.getBaseUrl()}/db/update`,
|
|
456
|
+
headers: {
|
|
457
|
+
authorization: this.app.getConfig().token,
|
|
458
|
+
"x-project": this.app.getConfig().project
|
|
459
|
+
},
|
|
460
|
+
body: { collection: this.collection, id: this.id, data }
|
|
461
|
+
}).sendRequest();
|
|
462
|
+
return res?.success ? DocumentSnapshot.fromMap({ ...data, id: this.id }) : null;
|
|
463
|
+
}
|
|
743
464
|
const old = await this.persistence.getDoc(this.collection, this.id);
|
|
744
465
|
if (!old || old.deleted)
|
|
745
466
|
return null;
|
|
@@ -769,9 +490,49 @@ var DocumentRef = class {
|
|
|
769
490
|
this.localStore?.notifyCollectionChanged(this.collection, this.id, "update");
|
|
770
491
|
this.syncEngine?.flush().catch(console.error);
|
|
771
492
|
return snap;
|
|
493
|
+
} finally {
|
|
494
|
+
this._isUpdating = false;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
// ====================== SET ======================
|
|
498
|
+
async set(data) {
|
|
499
|
+
validateDocumentData(data, "DocumentRef.set");
|
|
500
|
+
if (!this.persistence) {
|
|
501
|
+
const res = await new HttpsRequest({
|
|
502
|
+
method: "POST" /* POST */,
|
|
503
|
+
endpoint: `${this.app.getBaseUrl()}/db/create`,
|
|
504
|
+
headers: {
|
|
505
|
+
authorization: this.app.getConfig().token,
|
|
506
|
+
"x-project": this.app.getConfig().project
|
|
507
|
+
},
|
|
508
|
+
body: { collection: this.collection, data: { ...data, id: this.id } }
|
|
509
|
+
}).sendRequest();
|
|
510
|
+
return res?.success ? DocumentSnapshot.fromMap({ ...data, id: this.id }) : null;
|
|
772
511
|
}
|
|
773
|
-
|
|
512
|
+
const updated = await this.persistence.upsertDoc({
|
|
513
|
+
collection: this.collection,
|
|
514
|
+
id: this.id,
|
|
515
|
+
data: { ...data, id: this.id },
|
|
516
|
+
exists: true,
|
|
517
|
+
deleted: false,
|
|
518
|
+
pending: 1,
|
|
519
|
+
localOnly: false,
|
|
520
|
+
status: "pending"
|
|
521
|
+
});
|
|
522
|
+
await this.persistence.enqueueMutation({
|
|
523
|
+
mutationId: this.persistence.createMutationId(),
|
|
524
|
+
collection: this.collection,
|
|
525
|
+
documentId: this.id,
|
|
526
|
+
type: "insert",
|
|
527
|
+
payload: data
|
|
528
|
+
});
|
|
529
|
+
const snap = DocumentSnapshot.fromMap(updated.data);
|
|
530
|
+
this.localStore?.emitDocument(this.collection, this.id, snap, "update");
|
|
531
|
+
this.localStore?.notifyCollectionChanged(this.collection, this.id, "update");
|
|
532
|
+
this.syncEngine?.flush().catch(console.error);
|
|
533
|
+
return snap;
|
|
774
534
|
}
|
|
535
|
+
// ====================== DELETE ======================
|
|
775
536
|
async delete() {
|
|
776
537
|
if (this.persistence) {
|
|
777
538
|
await this.persistence.markDeleted(this.collection, this.id, 1);
|
|
@@ -787,19 +548,22 @@ var DocumentRef = class {
|
|
|
787
548
|
this.syncEngine?.flush().catch(console.error);
|
|
788
549
|
return true;
|
|
789
550
|
}
|
|
790
|
-
|
|
551
|
+
const res = await new HttpsRequest({
|
|
552
|
+
method: "POST" /* POST */,
|
|
553
|
+
endpoint: `${this.app.getBaseUrl()}/db/delete`,
|
|
554
|
+
headers: {
|
|
555
|
+
authorization: this.app.getConfig().token,
|
|
556
|
+
"x-project": this.app.getConfig().project
|
|
557
|
+
},
|
|
558
|
+
body: { collection: this.collection, id: this.id }
|
|
559
|
+
}).sendRequest();
|
|
560
|
+
return !!res?.success;
|
|
791
561
|
}
|
|
792
|
-
//
|
|
793
|
-
// return new Array(this.app, this.collection, key, this.id);
|
|
794
|
-
// }
|
|
562
|
+
// ====================== SNAPSHOT ======================
|
|
795
563
|
onSnapshot(callback) {
|
|
796
|
-
if (this.
|
|
564
|
+
if (this.persistence && this.localStore && this.app.offline().realtimeBridge) {
|
|
797
565
|
this.app.offline().realtimeBridge?.watchDocument(this.collection, this.id);
|
|
798
|
-
return this.
|
|
799
|
-
this.collection,
|
|
800
|
-
this.id,
|
|
801
|
-
callback
|
|
802
|
-
) || (() => {
|
|
566
|
+
return this.localStore.subscribeToDocument(this.collection, this.id, callback) || (() => {
|
|
803
567
|
});
|
|
804
568
|
}
|
|
805
569
|
return this.app.rtdb().subscribeToDocumentRaw(this.collection, this.id, (snapshot, change) => {
|
|
@@ -1027,15 +791,42 @@ var CollectionRef = class {
|
|
|
1027
791
|
}
|
|
1028
792
|
return local;
|
|
1029
793
|
}
|
|
1030
|
-
|
|
1031
|
-
|
|
794
|
+
try {
|
|
795
|
+
const res = await new HttpsRequest({
|
|
796
|
+
method: "POST" /* POST */,
|
|
797
|
+
endpoint: `${this.app.getBaseUrl()}/db/read`,
|
|
798
|
+
headers: {
|
|
799
|
+
authorization: this.app.getConfig().token,
|
|
800
|
+
"x-project": this.app.getConfig().project
|
|
801
|
+
},
|
|
802
|
+
body: {
|
|
803
|
+
collection: this.collection,
|
|
804
|
+
filter: {}
|
|
805
|
+
}
|
|
806
|
+
}).sendRequest();
|
|
807
|
+
if (!res?.success || !Array.isArray(res.documents)) {
|
|
808
|
+
return [];
|
|
809
|
+
}
|
|
810
|
+
return res.documents.map((d) => {
|
|
811
|
+
delete d.token;
|
|
812
|
+
d.id = d.id ?? d._id;
|
|
813
|
+
delete d._id;
|
|
814
|
+
return DocumentSnapshot.fromMap(d);
|
|
815
|
+
});
|
|
816
|
+
} catch (error) {
|
|
817
|
+
console.error("[EdmaxLabs] Collection get failed:", error);
|
|
818
|
+
return [];
|
|
819
|
+
}
|
|
1032
820
|
}
|
|
1033
821
|
async refreshFromRemote() {
|
|
1034
822
|
try {
|
|
1035
823
|
const res = await new HttpsRequest({
|
|
1036
824
|
method: "POST" /* POST */,
|
|
1037
825
|
endpoint: `${this.app.getBaseUrl()}/db/read`,
|
|
1038
|
-
headers: {
|
|
826
|
+
headers: {
|
|
827
|
+
authorization: this.app.getConfig().token,
|
|
828
|
+
"x-project": this.app.getConfig().project
|
|
829
|
+
},
|
|
1039
830
|
body: {
|
|
1040
831
|
collection: this.collection,
|
|
1041
832
|
filter: {}
|
|
@@ -1061,7 +852,8 @@ var CollectionRef = class {
|
|
|
1061
852
|
delete d._id;
|
|
1062
853
|
return DocumentSnapshot.fromMap(d);
|
|
1063
854
|
});
|
|
1064
|
-
} catch {
|
|
855
|
+
} catch (error) {
|
|
856
|
+
console.error("[EdmaxLabs] refreshFromRemote failed:", error);
|
|
1065
857
|
return [];
|
|
1066
858
|
}
|
|
1067
859
|
}
|
|
@@ -1091,13 +883,24 @@ var CollectionRef = class {
|
|
|
1091
883
|
this.syncEngine?.flush().catch(console.error);
|
|
1092
884
|
return snap;
|
|
1093
885
|
}
|
|
1094
|
-
|
|
1095
|
-
|
|
886
|
+
const res = await new HttpsRequest({
|
|
887
|
+
method: "POST" /* POST */,
|
|
888
|
+
endpoint: `${this.app.getBaseUrl()}/db/create`,
|
|
889
|
+
headers: {
|
|
890
|
+
authorization: this.app.getConfig().token,
|
|
891
|
+
"x-project": this.app.getConfig().project
|
|
892
|
+
},
|
|
893
|
+
body: { collection: this.collection, data: { ...data, id: "" } }
|
|
894
|
+
// server will generate id
|
|
895
|
+
}).sendRequest();
|
|
896
|
+
if (!res?.success || !res.document)
|
|
897
|
+
return null;
|
|
898
|
+
return DocumentSnapshot.fromMap(res.document);
|
|
1096
899
|
}
|
|
1097
900
|
onSnapshot(callback) {
|
|
1098
|
-
if (this.app.offline().
|
|
901
|
+
if (this.persistence && this.localStore && this.app.offline().realtimeBridge) {
|
|
1099
902
|
this.app.offline().realtimeBridge?.watchCollection(this.collection);
|
|
1100
|
-
return this.
|
|
903
|
+
return this.localStore.subscribeToCollection(this.collection, callback) ?? (() => {
|
|
1101
904
|
});
|
|
1102
905
|
}
|
|
1103
906
|
return this.app.rtdb().subscribeToCollectionRaw(this.collection, (payload, changes) => {
|
|
@@ -2690,6 +2493,164 @@ var _EdmaxLabs = class _EdmaxLabs {
|
|
|
2690
2493
|
_EdmaxLabs.instance = null;
|
|
2691
2494
|
var EdmaxLabs = _EdmaxLabs;
|
|
2692
2495
|
|
|
2496
|
+
// src/database/Timestamp.ts
|
|
2497
|
+
var Timestamp = class _Timestamp {
|
|
2498
|
+
constructor(seconds, nanoseconds = 0) {
|
|
2499
|
+
this.seconds = seconds;
|
|
2500
|
+
this.nanoseconds = nanoseconds;
|
|
2501
|
+
}
|
|
2502
|
+
static now() {
|
|
2503
|
+
return _Timestamp.fromMillis(Date.now());
|
|
2504
|
+
}
|
|
2505
|
+
static fromDate(date) {
|
|
2506
|
+
return new _Timestamp(
|
|
2507
|
+
Math.floor(date.getTime() / 1e3),
|
|
2508
|
+
date.getTime() % 1e3 * 1e6
|
|
2509
|
+
);
|
|
2510
|
+
}
|
|
2511
|
+
static fromMillis(ms) {
|
|
2512
|
+
return new _Timestamp(Math.floor(ms / 1e3), ms % 1e3 * 1e6);
|
|
2513
|
+
}
|
|
2514
|
+
static fromMongo(dateObj) {
|
|
2515
|
+
return _Timestamp.fromMillis(dateObj.getTime());
|
|
2516
|
+
}
|
|
2517
|
+
static fromJSON(obj) {
|
|
2518
|
+
return new _Timestamp(obj.seconds, obj.nanoseconds);
|
|
2519
|
+
}
|
|
2520
|
+
toDate() {
|
|
2521
|
+
return new Date(this.toMillis());
|
|
2522
|
+
}
|
|
2523
|
+
toMillis() {
|
|
2524
|
+
return this.seconds * 1e3 + Math.floor(this.nanoseconds / 1e6);
|
|
2525
|
+
}
|
|
2526
|
+
sinceEpoch() {
|
|
2527
|
+
return this.seconds;
|
|
2528
|
+
}
|
|
2529
|
+
toMongo() {
|
|
2530
|
+
return new Date(this.toMillis());
|
|
2531
|
+
}
|
|
2532
|
+
format(pattern = "dd-MM-yyyy HH:mm:ss") {
|
|
2533
|
+
const d = this.toDate();
|
|
2534
|
+
const monthsShort = [
|
|
2535
|
+
"Jan",
|
|
2536
|
+
"Feb",
|
|
2537
|
+
"Mar",
|
|
2538
|
+
"Apr",
|
|
2539
|
+
"May",
|
|
2540
|
+
"Jun",
|
|
2541
|
+
"Jul",
|
|
2542
|
+
"Aug",
|
|
2543
|
+
"Sep",
|
|
2544
|
+
"Oct",
|
|
2545
|
+
"Nov",
|
|
2546
|
+
"Dec"
|
|
2547
|
+
];
|
|
2548
|
+
const monthsLong = [
|
|
2549
|
+
"January",
|
|
2550
|
+
"February",
|
|
2551
|
+
"March",
|
|
2552
|
+
"April",
|
|
2553
|
+
"May",
|
|
2554
|
+
"June",
|
|
2555
|
+
"July",
|
|
2556
|
+
"August",
|
|
2557
|
+
"September",
|
|
2558
|
+
"October",
|
|
2559
|
+
"November",
|
|
2560
|
+
"December"
|
|
2561
|
+
];
|
|
2562
|
+
const hours = d.getHours();
|
|
2563
|
+
const hours12 = hours % 12 === 0 ? 12 : hours % 12;
|
|
2564
|
+
const ampm = hours < 12 ? "AM" : "PM";
|
|
2565
|
+
const map = {
|
|
2566
|
+
dd: String(d.getDate()).padStart(2, "0"),
|
|
2567
|
+
MM: String(d.getMonth() + 1).padStart(2, "0"),
|
|
2568
|
+
yyyy: d.getFullYear(),
|
|
2569
|
+
HH: String(d.getHours()).padStart(2, "0"),
|
|
2570
|
+
mm: String(d.getMinutes()).padStart(2, "0"),
|
|
2571
|
+
ss: String(d.getSeconds()).padStart(2, "0"),
|
|
2572
|
+
SSS: String(d.getMilliseconds()).padStart(3, "0"),
|
|
2573
|
+
MMM: monthsShort[d.getMonth()],
|
|
2574
|
+
MMMM: monthsLong[d.getMonth()],
|
|
2575
|
+
a: ampm.toLowerCase(),
|
|
2576
|
+
// am/pm
|
|
2577
|
+
A: ampm
|
|
2578
|
+
// AM/PM
|
|
2579
|
+
};
|
|
2580
|
+
return pattern.replace(
|
|
2581
|
+
/MMMM|MMM|dd|MM|yyyy|HH|mm|ss|SSS|a|A/g,
|
|
2582
|
+
(match) => String(map[match])
|
|
2583
|
+
);
|
|
2584
|
+
}
|
|
2585
|
+
compare(other) {
|
|
2586
|
+
if (this.seconds !== other.seconds) {
|
|
2587
|
+
return this.seconds - other.seconds;
|
|
2588
|
+
}
|
|
2589
|
+
return this.nanoseconds - other.nanoseconds;
|
|
2590
|
+
}
|
|
2591
|
+
relative(fmt = "dd-MM-yyyy HH:mm:ss") {
|
|
2592
|
+
const now = Date.now();
|
|
2593
|
+
const diff = now - this.toMillis();
|
|
2594
|
+
const sec = Math.floor(diff / 1e3);
|
|
2595
|
+
if (sec < 60)
|
|
2596
|
+
return `${sec}s ago`;
|
|
2597
|
+
const min = Math.floor(sec / 60);
|
|
2598
|
+
if (min < 60)
|
|
2599
|
+
return `${min}m ago`;
|
|
2600
|
+
const hrs = Math.floor(min / 60);
|
|
2601
|
+
if (hrs < 24)
|
|
2602
|
+
return `${hrs}h ago`;
|
|
2603
|
+
const days = Math.floor(hrs / 24);
|
|
2604
|
+
if (days < 3)
|
|
2605
|
+
return `${days}d ago`;
|
|
2606
|
+
return this.format(fmt);
|
|
2607
|
+
}
|
|
2608
|
+
add({
|
|
2609
|
+
seconds = 0,
|
|
2610
|
+
minutes = 0,
|
|
2611
|
+
hours = 0,
|
|
2612
|
+
days = 0
|
|
2613
|
+
}) {
|
|
2614
|
+
const totalMs = seconds * 1e3 + minutes * 6e4 + hours * 36e5 + days * 864e5;
|
|
2615
|
+
return _Timestamp.fromMillis(this.toMillis() + totalMs);
|
|
2616
|
+
}
|
|
2617
|
+
weekdayName() {
|
|
2618
|
+
return ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][this.toDate().getDay()];
|
|
2619
|
+
}
|
|
2620
|
+
toJSON() {
|
|
2621
|
+
return {
|
|
2622
|
+
_type: "timestamp",
|
|
2623
|
+
seconds: this.seconds,
|
|
2624
|
+
nanoseconds: this.nanoseconds
|
|
2625
|
+
};
|
|
2626
|
+
}
|
|
2627
|
+
toString() {
|
|
2628
|
+
return this.format("yyyy-MM-dd HH:mm:ss");
|
|
2629
|
+
}
|
|
2630
|
+
};
|
|
2631
|
+
|
|
2632
|
+
// src/database/ArraySnapshot.ts
|
|
2633
|
+
var ArraySnapshot = class _ArraySnapshot {
|
|
2634
|
+
constructor(id = "", index, data, dt) {
|
|
2635
|
+
this.data = data;
|
|
2636
|
+
this.id = id;
|
|
2637
|
+
this.dt = dt ?? Timestamp.now();
|
|
2638
|
+
}
|
|
2639
|
+
static fromMap(map) {
|
|
2640
|
+
const index = map.index ?? map.index ?? -1;
|
|
2641
|
+
const id = map.id ?? map._id ?? "";
|
|
2642
|
+
const document2 = map.data ?? map.document ?? map;
|
|
2643
|
+
return new _ArraySnapshot(id, index, document2);
|
|
2644
|
+
}
|
|
2645
|
+
toMap() {
|
|
2646
|
+
return {
|
|
2647
|
+
id: this.id ?? "",
|
|
2648
|
+
data: this.data,
|
|
2649
|
+
dt: this.dt
|
|
2650
|
+
};
|
|
2651
|
+
}
|
|
2652
|
+
};
|
|
2653
|
+
|
|
2693
2654
|
// src/index.ts
|
|
2694
2655
|
var src_default = EdmaxLabs;
|
|
2695
2656
|
export {
|