react-firebase-ql 0.1.0
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/LICENSE +21 -0
- package/README.md +15 -0
- package/dist/index.d.ts +304 -0
- package/dist/index.js +1366 -0
- package/dist/index.mjs +1359 -0
- package/package.json +48 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1366 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
AUTH_PROVIDERS: () => AUTH_PROVIDERS,
|
|
24
|
+
BaseModel: () => BaseModel,
|
|
25
|
+
StorageUpload: () => StorageUpload,
|
|
26
|
+
UPLOADTYPES: () => UPLOADTYPES,
|
|
27
|
+
Users: () => Users,
|
|
28
|
+
camelCaseToNormal: () => camelCaseToNormal,
|
|
29
|
+
camelToTitleCase: () => camelToTitleCase,
|
|
30
|
+
convertUnicode: () => convertUnicode,
|
|
31
|
+
errorLogger: () => errorLogger,
|
|
32
|
+
fbsession: () => fbsession,
|
|
33
|
+
fetchCurrentTimestamp: () => fetchCurrentTimestamp,
|
|
34
|
+
formHasError: () => formHasError,
|
|
35
|
+
generateRandomString: () => generateRandomString,
|
|
36
|
+
getDaysAgo: () => getDaysAgo,
|
|
37
|
+
getInitials: () => getInitials,
|
|
38
|
+
getNthNumberOfArray: () => getNthNumberOfArray,
|
|
39
|
+
isValidEmail: () => isValidEmail,
|
|
40
|
+
isValidPassword: () => isValidPassword,
|
|
41
|
+
moneyFormatter: () => moneyFormatter,
|
|
42
|
+
nairaFormatter: () => nairaFormatter,
|
|
43
|
+
noEmptyField: () => noEmptyField,
|
|
44
|
+
numberToAlphabet: () => numberToAlphabet,
|
|
45
|
+
range: () => range,
|
|
46
|
+
timeAgo: () => timeAgo,
|
|
47
|
+
useAuth: () => useAuth,
|
|
48
|
+
useCount: () => useCount,
|
|
49
|
+
useFetch: () => useFetch,
|
|
50
|
+
useStream: () => useStream
|
|
51
|
+
});
|
|
52
|
+
module.exports = __toCommonJS(src_exports);
|
|
53
|
+
|
|
54
|
+
// src/Users.ts
|
|
55
|
+
var import_auth = require("firebase/auth");
|
|
56
|
+
|
|
57
|
+
// src/BaseModel.ts
|
|
58
|
+
var import_firestore = require("firebase/firestore");
|
|
59
|
+
|
|
60
|
+
// src/helpers.ts
|
|
61
|
+
var generateRandomString = (length) => {
|
|
62
|
+
if (length > 60) {
|
|
63
|
+
throw new Error(`Maximum generatable character is 60, ${length} was required`);
|
|
64
|
+
}
|
|
65
|
+
var result = "";
|
|
66
|
+
var characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
67
|
+
var charactersLength = characters.length;
|
|
68
|
+
for (var i = 0; i < length; i++) {
|
|
69
|
+
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
};
|
|
73
|
+
var camelToTitleCase = (key) => {
|
|
74
|
+
const topic = key[0].toUpperCase() + key.slice(1);
|
|
75
|
+
let result = "";
|
|
76
|
+
let i = 0;
|
|
77
|
+
while (i < topic.length) {
|
|
78
|
+
if (i === 0) {
|
|
79
|
+
result += topic.charAt(i);
|
|
80
|
+
} else {
|
|
81
|
+
if (topic.charAt(i) === topic.charAt(i).toUpperCase()) {
|
|
82
|
+
result += ` ${topic.charAt(i)}`;
|
|
83
|
+
} else {
|
|
84
|
+
result += topic.charAt(i);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
i++;
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
};
|
|
91
|
+
function convertUnicode(input) {
|
|
92
|
+
return input.replace(/\\+u([0-9a-fA-F]{4})/g, (a, b) => String.fromCharCode(parseInt(b, 16)));
|
|
93
|
+
}
|
|
94
|
+
var moneyFormatter = (x, shorten = true, decimailPlaces) => {
|
|
95
|
+
if (x === void 0) {
|
|
96
|
+
return "";
|
|
97
|
+
}
|
|
98
|
+
const base = 1e5;
|
|
99
|
+
const num = parseInt(x);
|
|
100
|
+
if (num < base || !shorten) {
|
|
101
|
+
return num.toFixed(decimailPlaces).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
102
|
+
} else {
|
|
103
|
+
let val = "";
|
|
104
|
+
if (num / base < 10) {
|
|
105
|
+
val = (num / 1e3).toFixed(decimailPlaces) + "K";
|
|
106
|
+
} else if (num < base * 1e4) {
|
|
107
|
+
val = (num / (base * 10)).toFixed(decimailPlaces) + "M";
|
|
108
|
+
} else {
|
|
109
|
+
val = (num / (base * 1e4)).toFixed(decimailPlaces) + "B";
|
|
110
|
+
}
|
|
111
|
+
return val;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
function getDaysAgo(startDate, daysApart) {
|
|
115
|
+
const localCopy = new Date(startDate.toDateString());
|
|
116
|
+
return new Date(localCopy.setDate(localCopy.getDate() + daysApart));
|
|
117
|
+
}
|
|
118
|
+
function timeAgo(dateInput) {
|
|
119
|
+
const date = new Date(dateInput);
|
|
120
|
+
if (isNaN(date.getTime())) {
|
|
121
|
+
throw new Error("Invalid date input");
|
|
122
|
+
}
|
|
123
|
+
const now = /* @__PURE__ */ new Date();
|
|
124
|
+
const secondsAgo = Math.floor((now.getTime() - date.getTime()) / 1e3);
|
|
125
|
+
const minutesAgo = Math.floor(secondsAgo / 60);
|
|
126
|
+
if (minutesAgo < 1)
|
|
127
|
+
return "Just now";
|
|
128
|
+
const hoursAgo = Math.floor(minutesAgo / 60);
|
|
129
|
+
if (hoursAgo < 1)
|
|
130
|
+
return `${minutesAgo} minute${minutesAgo !== 1 ? "s" : ""} ago`;
|
|
131
|
+
const daysAgo = Math.floor(hoursAgo / 24);
|
|
132
|
+
if (daysAgo < 1)
|
|
133
|
+
return `${hoursAgo} hour${hoursAgo !== 1 ? "s" : ""} ago`;
|
|
134
|
+
const monthsAgo = Math.floor(daysAgo / 30);
|
|
135
|
+
if (daysAgo < 30)
|
|
136
|
+
return `${daysAgo} day${daysAgo !== 1 ? "s" : ""} ago`;
|
|
137
|
+
const yearsAgo = Math.floor(monthsAgo / 12);
|
|
138
|
+
if (monthsAgo < 12)
|
|
139
|
+
return `${monthsAgo} month${monthsAgo !== 1 ? "s" : ""} ago`;
|
|
140
|
+
return `${yearsAgo} year${yearsAgo !== 1 ? "s" : ""} ago`;
|
|
141
|
+
}
|
|
142
|
+
var range = (start, end) => Array.from({ length: end - start + 1 }, (_, i) => start + i);
|
|
143
|
+
var nairaFormatter = (amount) => {
|
|
144
|
+
return `\u20A6${moneyFormatter(amount, true, 2)}`;
|
|
145
|
+
};
|
|
146
|
+
var camelCaseToNormal = (camelCaseStr) => {
|
|
147
|
+
return camelCaseStr.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/^./, (str) => str.toUpperCase());
|
|
148
|
+
};
|
|
149
|
+
var errorLogger = (...error) => {
|
|
150
|
+
if (window.location.hostname === "localhost") {
|
|
151
|
+
console.log(error);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
function isValidEmail(email) {
|
|
155
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
156
|
+
const pass = emailRegex.test(email);
|
|
157
|
+
if (!pass) {
|
|
158
|
+
return "Invalid email address";
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function isValidPassword(password) {
|
|
162
|
+
if (password.length < 8) {
|
|
163
|
+
return "Password cannot be less than 8 characters in length";
|
|
164
|
+
}
|
|
165
|
+
const hasUppercase = /[A-Z]/.test(password);
|
|
166
|
+
if (!hasUppercase) {
|
|
167
|
+
return "Password must contain at least 1 uppercase letter";
|
|
168
|
+
}
|
|
169
|
+
const isAllUppercase = /^[A-Z]+$/.test(password);
|
|
170
|
+
if (isAllUppercase) {
|
|
171
|
+
return "Password cannot be all uppercase letter";
|
|
172
|
+
}
|
|
173
|
+
const hasSpecialCharacter = /[!@#$%^&*(),.?":{}|<>]/.test(password);
|
|
174
|
+
if (!hasSpecialCharacter) {
|
|
175
|
+
return "Password must contain at least 1 special character";
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function numberToAlphabet(num) {
|
|
179
|
+
let result = "";
|
|
180
|
+
while (num > 0) {
|
|
181
|
+
num--;
|
|
182
|
+
const charCode = num % 26 + 65;
|
|
183
|
+
result = String.fromCharCode(charCode) + result;
|
|
184
|
+
num = Math.floor(num / 26);
|
|
185
|
+
}
|
|
186
|
+
return result;
|
|
187
|
+
}
|
|
188
|
+
var getNthNumberOfArray = (param) => {
|
|
189
|
+
const { num, step, start } = param;
|
|
190
|
+
if (num <= 0 || step <= 0) {
|
|
191
|
+
throw new Error("Both number and step must be greater than 0");
|
|
192
|
+
}
|
|
193
|
+
return Array.from({ length: Math.floor(num / step) }, (_, i) => {
|
|
194
|
+
if (start) {
|
|
195
|
+
i = start + i - 1;
|
|
196
|
+
return (i + 1) * step;
|
|
197
|
+
}
|
|
198
|
+
return (i + 1) * step;
|
|
199
|
+
});
|
|
200
|
+
};
|
|
201
|
+
var noEmptyField = (args) => {
|
|
202
|
+
return args.requiredFields.every(
|
|
203
|
+
(field) => Object.keys(FormData).includes(field) && args.formData[field] !== void 0 && args.formData[field] !== null && args.formData[field] !== ""
|
|
204
|
+
);
|
|
205
|
+
};
|
|
206
|
+
var getInitials = (fullName) => {
|
|
207
|
+
if (fullName) {
|
|
208
|
+
const names = fullName.trim().split(/\s+/);
|
|
209
|
+
if (names.length >= 2) {
|
|
210
|
+
const firstInitial = names[0].charAt(0).toUpperCase();
|
|
211
|
+
const lastInitial = names[names.length - 1].charAt(0).toUpperCase();
|
|
212
|
+
return `${firstInitial}${lastInitial}`;
|
|
213
|
+
}
|
|
214
|
+
if (names.length === 1) {
|
|
215
|
+
const name = names[0];
|
|
216
|
+
return `${name.charAt(0).toUpperCase()}${name.charAt(name.length - 1).toUpperCase()}`;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return "";
|
|
220
|
+
};
|
|
221
|
+
var fetchCurrentTimestamp = async () => {
|
|
222
|
+
const res = await fetch("https://worldtimeapi.org/api/timezone/etc/utc");
|
|
223
|
+
if (!res.ok)
|
|
224
|
+
throw new Error("Failed to fetch time");
|
|
225
|
+
const data = await res.json();
|
|
226
|
+
return {
|
|
227
|
+
iso: data.datetime,
|
|
228
|
+
unix: data.unixtime * 1e3
|
|
229
|
+
// Convert to milliseconds if needed
|
|
230
|
+
};
|
|
231
|
+
};
|
|
232
|
+
var formHasError = (formError) => {
|
|
233
|
+
return Object.values(formError).every((item) => item !== void 0);
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
// src/BaseModel.ts
|
|
237
|
+
var BaseModel = class {
|
|
238
|
+
// offset data
|
|
239
|
+
// offset?: QueryDocumentSnapshot<DocumentData>;
|
|
240
|
+
constructor(table, db) {
|
|
241
|
+
// Get a new write batch
|
|
242
|
+
// protected batch?: WriteBatch
|
|
243
|
+
// Database table name
|
|
244
|
+
this.table = "";
|
|
245
|
+
this.table = table;
|
|
246
|
+
this.firestorDB = db;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* save multiple documents
|
|
250
|
+
* @param param0
|
|
251
|
+
*/
|
|
252
|
+
async saveBatch({ data }) {
|
|
253
|
+
try {
|
|
254
|
+
const batch = (0, import_firestore.writeBatch)(this.firestorDB);
|
|
255
|
+
const obj = data;
|
|
256
|
+
obj.forEach((document) => {
|
|
257
|
+
const docRef = document.reference ? (0, import_firestore.doc)(this.firestorDB, this.table, document.reference) : (0, import_firestore.doc)((0, import_firestore.collection)(this.firestorDB, this.table));
|
|
258
|
+
if (document.reference) {
|
|
259
|
+
delete document.reference;
|
|
260
|
+
}
|
|
261
|
+
batch.set(docRef, document);
|
|
262
|
+
});
|
|
263
|
+
await batch.commit();
|
|
264
|
+
return true;
|
|
265
|
+
} catch (error) {
|
|
266
|
+
throw new Error(`saveBatch: , ${error}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* update multiple documents
|
|
271
|
+
* @param param0
|
|
272
|
+
*/
|
|
273
|
+
async updateBatch({ data }) {
|
|
274
|
+
try {
|
|
275
|
+
const batch = (0, import_firestore.writeBatch)(this.firestorDB);
|
|
276
|
+
const obj = data;
|
|
277
|
+
obj.forEach((document) => {
|
|
278
|
+
const docRef = (0, import_firestore.doc)(this.firestorDB, this.table, document.reference);
|
|
279
|
+
delete document.reference;
|
|
280
|
+
batch.update(docRef, document);
|
|
281
|
+
});
|
|
282
|
+
await batch.commit();
|
|
283
|
+
return true;
|
|
284
|
+
} catch (error) {
|
|
285
|
+
throw new Error(`updateBatch: , ${error}`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* delete multiple documents
|
|
290
|
+
* @param param0
|
|
291
|
+
*/
|
|
292
|
+
async deleteBatch({ ids }) {
|
|
293
|
+
try {
|
|
294
|
+
const batch = (0, import_firestore.writeBatch)(this.firestorDB);
|
|
295
|
+
ids.forEach((id) => {
|
|
296
|
+
const docRef = (0, import_firestore.doc)(this.firestorDB, this.table, id);
|
|
297
|
+
batch.delete(docRef);
|
|
298
|
+
});
|
|
299
|
+
await batch.commit();
|
|
300
|
+
return true;
|
|
301
|
+
} catch (error) {
|
|
302
|
+
throw new Error(`deleteBatch: , ${error}`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Get realtime update from the database
|
|
307
|
+
* @param id
|
|
308
|
+
*/
|
|
309
|
+
stream(callBack, id) {
|
|
310
|
+
const ref2 = id ? (0, import_firestore.doc)(this.firestorDB, this.table, id) : (0, import_firestore.collection)(this.firestorDB, this.table);
|
|
311
|
+
try {
|
|
312
|
+
if (id) {
|
|
313
|
+
return (0, import_firestore.onSnapshot)(ref2, (doc2) => {
|
|
314
|
+
callBack(doc2.exists() ? { ...doc2.data(), reference: ref2.id } : void 0);
|
|
315
|
+
});
|
|
316
|
+
} else {
|
|
317
|
+
return (0, import_firestore.onSnapshot)(ref2, (snapShot) => {
|
|
318
|
+
callBack(
|
|
319
|
+
snapShot.docs.map((value) => {
|
|
320
|
+
const data = { ...value.data(), reference: value.id };
|
|
321
|
+
return data;
|
|
322
|
+
})
|
|
323
|
+
);
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
} catch (error) {
|
|
327
|
+
callBack(void 0);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Get realtime value from database with where clause
|
|
332
|
+
* @param wh
|
|
333
|
+
* @param lim
|
|
334
|
+
* @param order
|
|
335
|
+
*/
|
|
336
|
+
streamWhere(wh, callBack, lim, order, offset) {
|
|
337
|
+
try {
|
|
338
|
+
const whereParameter = wh.map((clause) => (0, import_firestore.where)(
|
|
339
|
+
clause.key,
|
|
340
|
+
clause.operator,
|
|
341
|
+
clause.value
|
|
342
|
+
));
|
|
343
|
+
let constraint = [];
|
|
344
|
+
if (wh) {
|
|
345
|
+
constraint.push(...whereParameter);
|
|
346
|
+
}
|
|
347
|
+
if (order) {
|
|
348
|
+
constraint.push((0, import_firestore.orderBy)(order.parameter, order.direction));
|
|
349
|
+
}
|
|
350
|
+
if (offset) {
|
|
351
|
+
(0, import_firestore.getDoc)((0, import_firestore.doc)(this.firestorDB, this.table, offset)).then((off) => {
|
|
352
|
+
constraint.push((0, import_firestore.startAfter)(off));
|
|
353
|
+
}).catch((error) => errorLogger(error));
|
|
354
|
+
}
|
|
355
|
+
if (lim) {
|
|
356
|
+
constraint.push((0, import_firestore.limit)(lim));
|
|
357
|
+
}
|
|
358
|
+
const ref2 = (0, import_firestore.collection)(this.firestorDB, this.table);
|
|
359
|
+
return (0, import_firestore.onSnapshot)((0, import_firestore.query)(
|
|
360
|
+
ref2,
|
|
361
|
+
...constraint
|
|
362
|
+
), (snapShot) => {
|
|
363
|
+
callBack(snapShot.docs.map((value) => {
|
|
364
|
+
const data = { ...value.data(), reference: value.id };
|
|
365
|
+
return data;
|
|
366
|
+
}));
|
|
367
|
+
});
|
|
368
|
+
} catch (error) {
|
|
369
|
+
throw new Error(`streamWhere: , ${error}`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Fetch a single item from database
|
|
374
|
+
* @param id
|
|
375
|
+
*/
|
|
376
|
+
async find(id) {
|
|
377
|
+
try {
|
|
378
|
+
const ref2 = (0, import_firestore.doc)(this.firestorDB, this.table, id);
|
|
379
|
+
const docSnap = await (0, import_firestore.getDoc)(ref2);
|
|
380
|
+
if (docSnap.exists()) {
|
|
381
|
+
this.data = { ...docSnap.data(), reference: id };
|
|
382
|
+
return true;
|
|
383
|
+
}
|
|
384
|
+
return false;
|
|
385
|
+
} catch (error) {
|
|
386
|
+
throw new Error(`find: , ${error}`);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* check if data exists
|
|
391
|
+
* @param id
|
|
392
|
+
* @returns
|
|
393
|
+
*/
|
|
394
|
+
async dataExists(id) {
|
|
395
|
+
try {
|
|
396
|
+
const ref2 = (0, import_firestore.doc)(this.firestorDB, this.table, id);
|
|
397
|
+
const docSanp = await (0, import_firestore.getDoc)(ref2);
|
|
398
|
+
return docSanp.exists();
|
|
399
|
+
} catch (error) {
|
|
400
|
+
throw new Error(`dataExists: , ${error}`);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Update part of a data
|
|
405
|
+
* @param data
|
|
406
|
+
* @param id
|
|
407
|
+
* @returns
|
|
408
|
+
*/
|
|
409
|
+
async update(data, id) {
|
|
410
|
+
try {
|
|
411
|
+
delete data.reference;
|
|
412
|
+
const docRef = (0, import_firestore.doc)(this.firestorDB, this.table, id);
|
|
413
|
+
await (0, import_firestore.updateDoc)(docRef, data);
|
|
414
|
+
return true;
|
|
415
|
+
} catch (error) {
|
|
416
|
+
throw new Error(`update: , ${error}`);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* update an array in a document
|
|
421
|
+
* @param {Array<any>} data array of data to be saved
|
|
422
|
+
* @param {string} reference document reference
|
|
423
|
+
* @param {string} key document object key containing the array
|
|
424
|
+
* @returns {boolean}
|
|
425
|
+
*/
|
|
426
|
+
async updateAtomicArray(data, reference, key) {
|
|
427
|
+
try {
|
|
428
|
+
const docRef = (0, import_firestore.doc)(this.firestorDB, this.table, reference);
|
|
429
|
+
await (0, import_firestore.updateDoc)(docRef, { [key]: (0, import_firestore.arrayUnion)(...data) });
|
|
430
|
+
return true;
|
|
431
|
+
} catch (error) {
|
|
432
|
+
throw new Error(`updateAtomicArray error: ${error}`);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* removes items from document array
|
|
437
|
+
* @param {Array<any>} data array of data to be removed
|
|
438
|
+
* @param {string} id document reference
|
|
439
|
+
* @param {string} key key to reference
|
|
440
|
+
* @returns {boolean}
|
|
441
|
+
*/
|
|
442
|
+
async removeFromArray(data, id, key) {
|
|
443
|
+
try {
|
|
444
|
+
const docRef = (0, import_firestore.doc)(this.firestorDB, this.table, id);
|
|
445
|
+
await (0, import_firestore.updateDoc)(docRef, { [key]: (0, import_firestore.arrayRemove)(...data) });
|
|
446
|
+
return true;
|
|
447
|
+
} catch (error) {
|
|
448
|
+
throw new Error(`updateAtomicArray error: ${error}`);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Get all items from database
|
|
453
|
+
* @returns void
|
|
454
|
+
*/
|
|
455
|
+
async findAll(ids) {
|
|
456
|
+
try {
|
|
457
|
+
const colRef = (0, import_firestore.collection)(this.firestorDB, this.table);
|
|
458
|
+
if (ids) {
|
|
459
|
+
const results = [];
|
|
460
|
+
for (let id of ids) {
|
|
461
|
+
const found = await this.find(id);
|
|
462
|
+
if (found) {
|
|
463
|
+
results.push(this.data);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
this.data = results;
|
|
467
|
+
return true;
|
|
468
|
+
} else {
|
|
469
|
+
const snaptshots = await (0, import_firestore.getDocs)(colRef);
|
|
470
|
+
if (!snaptshots.empty) {
|
|
471
|
+
this.data = snaptshots.docs.map((document) => {
|
|
472
|
+
return { ...document.data(), reference: document.id };
|
|
473
|
+
});
|
|
474
|
+
return true;
|
|
475
|
+
} else {
|
|
476
|
+
return false;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
} catch (error) {
|
|
480
|
+
throw new Error(`findAll: , ${error}`);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* perform complex query
|
|
485
|
+
* @param param0
|
|
486
|
+
*/
|
|
487
|
+
async findWhereOrAnd({ wh, lim, order, offset }) {
|
|
488
|
+
try {
|
|
489
|
+
const colRef = (0, import_firestore.collection)(this.firestorDB, this.table);
|
|
490
|
+
const andWhere = [];
|
|
491
|
+
const orWhere = [];
|
|
492
|
+
let filterConstraint = (0, import_firestore.and)();
|
|
493
|
+
if (wh) {
|
|
494
|
+
wh.parameter.forEach((clause) => {
|
|
495
|
+
const whe = (0, import_firestore.where)(
|
|
496
|
+
clause.key,
|
|
497
|
+
clause.operator,
|
|
498
|
+
clause.value
|
|
499
|
+
);
|
|
500
|
+
clause.type === "and" ? andWhere.push(whe) : orWhere.push(whe);
|
|
501
|
+
});
|
|
502
|
+
if (wh.type === "andOr") {
|
|
503
|
+
filterConstraint = (0, import_firestore.and)(...andWhere, (0, import_firestore.or)(...orWhere));
|
|
504
|
+
} else if (wh.type === "or") {
|
|
505
|
+
filterConstraint = (0, import_firestore.or)(...orWhere);
|
|
506
|
+
} else {
|
|
507
|
+
filterConstraint = (0, import_firestore.and)(...andWhere);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
let constraint = [];
|
|
511
|
+
if (order) {
|
|
512
|
+
constraint.push((0, import_firestore.orderBy)(order.parameter, order.direction));
|
|
513
|
+
}
|
|
514
|
+
if (offset) {
|
|
515
|
+
const off = await (0, import_firestore.getDoc)((0, import_firestore.doc)(this.firestorDB, this.table, offset));
|
|
516
|
+
constraint.push((0, import_firestore.startAfter)(off));
|
|
517
|
+
}
|
|
518
|
+
if (lim) {
|
|
519
|
+
constraint.push((0, import_firestore.limit)(lim));
|
|
520
|
+
}
|
|
521
|
+
const snapshot = await (0, import_firestore.getDocs)(
|
|
522
|
+
(0, import_firestore.query)(
|
|
523
|
+
colRef,
|
|
524
|
+
filterConstraint,
|
|
525
|
+
...constraint
|
|
526
|
+
)
|
|
527
|
+
);
|
|
528
|
+
if (!snapshot.empty) {
|
|
529
|
+
this.data = snapshot.docs.map((document) => {
|
|
530
|
+
return { ...document.data(), reference: document.id };
|
|
531
|
+
});
|
|
532
|
+
return true;
|
|
533
|
+
} else {
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
} catch (error) {
|
|
537
|
+
throw new Error(`findWhereOrAnd: ${error}`);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* complex query with and only
|
|
542
|
+
* @param param0
|
|
543
|
+
* @returns
|
|
544
|
+
*/
|
|
545
|
+
async findWhere({ wh, lim, order, offset }) {
|
|
546
|
+
try {
|
|
547
|
+
const whereParameter = wh ? wh.map((clause) => (0, import_firestore.where)(
|
|
548
|
+
clause.key,
|
|
549
|
+
clause.operator,
|
|
550
|
+
clause.value
|
|
551
|
+
)) : [];
|
|
552
|
+
let constraint = [];
|
|
553
|
+
if (wh) {
|
|
554
|
+
constraint.push(...whereParameter);
|
|
555
|
+
}
|
|
556
|
+
if (order) {
|
|
557
|
+
constraint.push((0, import_firestore.orderBy)(order.parameter, order.direction));
|
|
558
|
+
}
|
|
559
|
+
if (offset) {
|
|
560
|
+
const off = await (0, import_firestore.getDoc)((0, import_firestore.doc)(this.firestorDB, this.table, offset));
|
|
561
|
+
constraint.push((0, import_firestore.startAfter)(off));
|
|
562
|
+
}
|
|
563
|
+
if (lim) {
|
|
564
|
+
constraint.push((0, import_firestore.limit)(lim));
|
|
565
|
+
}
|
|
566
|
+
const ref2 = (0, import_firestore.collection)(this.firestorDB, this.table);
|
|
567
|
+
const snapshot = await (0, import_firestore.getDocs)(
|
|
568
|
+
(0, import_firestore.query)(
|
|
569
|
+
ref2,
|
|
570
|
+
...constraint
|
|
571
|
+
)
|
|
572
|
+
);
|
|
573
|
+
if (!snapshot.empty) {
|
|
574
|
+
return snapshot.docs.map((document) => {
|
|
575
|
+
return { ...document.data(), reference: document.id };
|
|
576
|
+
});
|
|
577
|
+
} else {
|
|
578
|
+
return [];
|
|
579
|
+
}
|
|
580
|
+
} catch (error) {
|
|
581
|
+
throw new Error(`findWhere: , ${error}`);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* create or update data
|
|
586
|
+
* @param data
|
|
587
|
+
*/
|
|
588
|
+
async save(data, id) {
|
|
589
|
+
delete data.reference;
|
|
590
|
+
try {
|
|
591
|
+
if (id === void 0) {
|
|
592
|
+
const documentRef = await (0, import_firestore.addDoc)((0, import_firestore.collection)(this.firestorDB, this.table), data);
|
|
593
|
+
return documentRef.id;
|
|
594
|
+
} else {
|
|
595
|
+
await (0, import_firestore.setDoc)((0, import_firestore.doc)(this.firestorDB, this.table, id), data);
|
|
596
|
+
return id;
|
|
597
|
+
}
|
|
598
|
+
} catch (error) {
|
|
599
|
+
throw new Error(`save error: , ${error}`);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Delete document from database
|
|
604
|
+
* @param id
|
|
605
|
+
*/
|
|
606
|
+
async delete(id) {
|
|
607
|
+
try {
|
|
608
|
+
await (0, import_firestore.deleteDoc)((0, import_firestore.doc)(this.firestorDB, this.table, id));
|
|
609
|
+
return true;
|
|
610
|
+
} catch (error) {
|
|
611
|
+
throw new Error(`delete: , ${error}`);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Increment or decrement counters
|
|
616
|
+
* @param param0
|
|
617
|
+
*/
|
|
618
|
+
async incrementDecrement({ dbReference, key, isIncrement = true, incrementalValue }) {
|
|
619
|
+
try {
|
|
620
|
+
const docRef = (0, import_firestore.doc)(this.firestorDB, this.table, dbReference);
|
|
621
|
+
const value = isIncrement ? incrementalValue != null ? incrementalValue : 1 : (incrementalValue != null ? incrementalValue : 1) * -1;
|
|
622
|
+
await (0, import_firestore.updateDoc)(docRef, { [key]: (0, import_firestore.increment)(value) });
|
|
623
|
+
return true;
|
|
624
|
+
} catch (error) {
|
|
625
|
+
throw new Error(`incrementDecrement: , ${error}`);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Count data in database
|
|
630
|
+
* @param {whereClause[]} wh - query parameter (e.g. [
|
|
631
|
+
* {
|
|
632
|
+
*/
|
|
633
|
+
async countData(wh) {
|
|
634
|
+
try {
|
|
635
|
+
const qryParameter = wh.map((clause) => (0, import_firestore.where)(
|
|
636
|
+
clause.key,
|
|
637
|
+
clause.operator,
|
|
638
|
+
clause.value
|
|
639
|
+
));
|
|
640
|
+
const qry = (0, import_firestore.query)(
|
|
641
|
+
(0, import_firestore.collection)(this.firestorDB, this.table),
|
|
642
|
+
...qryParameter
|
|
643
|
+
);
|
|
644
|
+
const aggregate = await (0, import_firestore.getCountFromServer)(qry);
|
|
645
|
+
return aggregate.data().count;
|
|
646
|
+
} catch (error) {
|
|
647
|
+
throw new Error(`countData error: ,${error}`);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Get realtime value from database with where clause
|
|
652
|
+
* @param wh
|
|
653
|
+
* @param lim
|
|
654
|
+
* @param order
|
|
655
|
+
*/
|
|
656
|
+
async streamCount(wh, callBack, order, offset) {
|
|
657
|
+
try {
|
|
658
|
+
const whereParameter = wh.map(
|
|
659
|
+
(clause) => (0, import_firestore.where)(clause.key, clause.operator, clause.value)
|
|
660
|
+
);
|
|
661
|
+
const constraint = [...whereParameter];
|
|
662
|
+
if (order)
|
|
663
|
+
constraint.push((0, import_firestore.orderBy)(order.parameter, order.direction));
|
|
664
|
+
if (offset) {
|
|
665
|
+
const off = await (0, import_firestore.getDoc)((0, import_firestore.doc)(this.firestorDB, this.table, offset));
|
|
666
|
+
constraint.push((0, import_firestore.startAfter)(off));
|
|
667
|
+
}
|
|
668
|
+
const streamerConstraint = [...constraint, (0, import_firestore.limit)(1)];
|
|
669
|
+
const ref2 = (0, import_firestore.collection)(this.firestorDB, this.table);
|
|
670
|
+
const unsubscribe = (0, import_firestore.onSnapshot)(
|
|
671
|
+
(0, import_firestore.query)(ref2, ...streamerConstraint),
|
|
672
|
+
async (snapShot) => {
|
|
673
|
+
if (snapShot.empty)
|
|
674
|
+
return;
|
|
675
|
+
const aggregate = await (0, import_firestore.getCountFromServer)((0, import_firestore.query)(
|
|
676
|
+
(0, import_firestore.collection)(this.firestorDB, this.table),
|
|
677
|
+
...constraint
|
|
678
|
+
));
|
|
679
|
+
callBack(aggregate.data().count);
|
|
680
|
+
}
|
|
681
|
+
);
|
|
682
|
+
return unsubscribe;
|
|
683
|
+
} catch (error) {
|
|
684
|
+
throw new Error(`streamCount: ${error}`);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
|
|
689
|
+
// src/Users.ts
|
|
690
|
+
var Users = class extends BaseModel {
|
|
691
|
+
constructor() {
|
|
692
|
+
super(...arguments);
|
|
693
|
+
/**
|
|
694
|
+
* fetch phone number from database
|
|
695
|
+
* @param uid
|
|
696
|
+
* @returns
|
|
697
|
+
*/
|
|
698
|
+
this.getPhoneNumber = async (uid) => {
|
|
699
|
+
let phoneNumber = null;
|
|
700
|
+
const dbUser = await this.find(uid);
|
|
701
|
+
if (dbUser) {
|
|
702
|
+
const dUser = this.data;
|
|
703
|
+
phoneNumber = dUser.phoneNumber;
|
|
704
|
+
}
|
|
705
|
+
return phoneNumber;
|
|
706
|
+
};
|
|
707
|
+
/**
|
|
708
|
+
* send OTP to enable 2 factor authentication
|
|
709
|
+
* @param user
|
|
710
|
+
* @param recaptchaverifier
|
|
711
|
+
*/
|
|
712
|
+
this.setMultiFactorEnrollment = async (user, recaptchaverifier, auth, phoneNumber) => {
|
|
713
|
+
try {
|
|
714
|
+
const multifactorSession = await (0, import_auth.multiFactor)(user).getSession();
|
|
715
|
+
const phoneInfoOptions = {
|
|
716
|
+
phoneNumber,
|
|
717
|
+
session: multifactorSession
|
|
718
|
+
};
|
|
719
|
+
const phoneAuthProvider = new import_auth.PhoneAuthProvider(auth);
|
|
720
|
+
return await phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaverifier);
|
|
721
|
+
} catch (e) {
|
|
722
|
+
throw new Error(`setMultiFactorEnrollment error: , ${e}`);
|
|
723
|
+
}
|
|
724
|
+
};
|
|
725
|
+
/**
|
|
726
|
+
* complete user signIn process with OTP
|
|
727
|
+
* @param param0
|
|
728
|
+
* @param userCode
|
|
729
|
+
* @param user
|
|
730
|
+
* @param onSuccess
|
|
731
|
+
* @returns {User | null}
|
|
732
|
+
*/
|
|
733
|
+
this.confirmOTP = async (verifier, userCode) => {
|
|
734
|
+
try {
|
|
735
|
+
const { verificationId, resolver } = verifier;
|
|
736
|
+
const cred = import_auth.PhoneAuthProvider.credential(verificationId, userCode);
|
|
737
|
+
const multiFactorAssertion = import_auth.PhoneMultiFactorGenerator.assertion(cred);
|
|
738
|
+
let user = null;
|
|
739
|
+
if (resolver) {
|
|
740
|
+
const credential = await resolver.resolveSignIn(multiFactorAssertion);
|
|
741
|
+
user = credential.user;
|
|
742
|
+
} else {
|
|
743
|
+
if (verifier.user) {
|
|
744
|
+
await (0, import_auth.multiFactor)(verifier.user).enroll(multiFactorAssertion, "primary phone");
|
|
745
|
+
user = verifier.user;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
return user;
|
|
749
|
+
} catch (error) {
|
|
750
|
+
throw new Error(`confirmOTP error: , ${error}`);
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
/**
|
|
754
|
+
* send OTP to member
|
|
755
|
+
* @param resolver
|
|
756
|
+
* @param recaptchaVerifier
|
|
757
|
+
* @param setter
|
|
758
|
+
* @returns {MFAVerifier | null}
|
|
759
|
+
*/
|
|
760
|
+
this.sendOTP = async (resolver, recaptchaVerifier, auth) => {
|
|
761
|
+
try {
|
|
762
|
+
if (resolver.hints[0].factorId === import_auth.PhoneMultiFactorGenerator.FACTOR_ID) {
|
|
763
|
+
const phoneInfoOptions = {
|
|
764
|
+
multiFactorHint: resolver.hints[0],
|
|
765
|
+
session: resolver.session
|
|
766
|
+
};
|
|
767
|
+
const phoneAuthProvider = new import_auth.PhoneAuthProvider(auth);
|
|
768
|
+
const verificationId = await phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier);
|
|
769
|
+
return { verificationId, resolver };
|
|
770
|
+
} else {
|
|
771
|
+
return null;
|
|
772
|
+
}
|
|
773
|
+
} catch (e) {
|
|
774
|
+
throw new Error(`sendOTP error: , ${e}`);
|
|
775
|
+
}
|
|
776
|
+
};
|
|
777
|
+
/**
|
|
778
|
+
* Handle email verification for user
|
|
779
|
+
* @param auth
|
|
780
|
+
* @param actionCode
|
|
781
|
+
* @returns {error: string | null}
|
|
782
|
+
*/
|
|
783
|
+
this.verifyEmail = async (auth, actionCode) => {
|
|
784
|
+
try {
|
|
785
|
+
await (0, import_auth.applyActionCode)(auth, actionCode);
|
|
786
|
+
return true;
|
|
787
|
+
} catch (error) {
|
|
788
|
+
throw new Error(`verifyEmail error: , ${error}`);
|
|
789
|
+
}
|
|
790
|
+
};
|
|
791
|
+
/**
|
|
792
|
+
* confirm that password reset link is correct
|
|
793
|
+
* @param auth
|
|
794
|
+
* @param actionCode
|
|
795
|
+
* @returns {email: string | null}
|
|
796
|
+
*/
|
|
797
|
+
this.verifyPasswordResetLink = async (auth, actionCode) => {
|
|
798
|
+
try {
|
|
799
|
+
return await (0, import_auth.verifyPasswordResetCode)(auth, actionCode);
|
|
800
|
+
} catch (error) {
|
|
801
|
+
throw new Error(`passwordResetLink error: , ${error}`);
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* register user and send email verification
|
|
807
|
+
* delete user if registration is not successful
|
|
808
|
+
* @param param0
|
|
809
|
+
*/
|
|
810
|
+
async registerWithEmailAndPassword({
|
|
811
|
+
auth,
|
|
812
|
+
email,
|
|
813
|
+
password,
|
|
814
|
+
userData,
|
|
815
|
+
persist = "session"
|
|
816
|
+
}) {
|
|
817
|
+
try {
|
|
818
|
+
if (persist) {
|
|
819
|
+
await (0, import_auth.setPersistence)(auth, persist === "local" ? import_auth.browserLocalPersistence : import_auth.browserSessionPersistence);
|
|
820
|
+
}
|
|
821
|
+
const credential = await (0, import_auth.createUserWithEmailAndPassword)(auth, email, password);
|
|
822
|
+
this.user = credential.user;
|
|
823
|
+
if (userData) {
|
|
824
|
+
await this.save(userData, credential.user.uid);
|
|
825
|
+
}
|
|
826
|
+
return credential.user.uid;
|
|
827
|
+
} catch (error) {
|
|
828
|
+
if (this.user) {
|
|
829
|
+
this.deleteAccount(this.user);
|
|
830
|
+
}
|
|
831
|
+
throw new Error(`registerWithEmailAndPassword error: , ${error}`);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* confirm user is valid and get their information
|
|
836
|
+
* from firestore users table if exists
|
|
837
|
+
* @param { string , string, boolean} credentials - login credentials
|
|
838
|
+
* @returns {Promise<QueryReturn>}
|
|
839
|
+
*/
|
|
840
|
+
async login({ email, password, auth, persist = "session", verifyEmail = false }) {
|
|
841
|
+
try {
|
|
842
|
+
if (persist) {
|
|
843
|
+
await (0, import_auth.setPersistence)(auth, persist === "local" ? import_auth.browserLocalPersistence : import_auth.browserSessionPersistence);
|
|
844
|
+
}
|
|
845
|
+
const userAuth = await (0, import_auth.signInWithEmailAndPassword)(auth, email, password);
|
|
846
|
+
if (userAuth) {
|
|
847
|
+
if (verifyEmail && !userAuth.user.emailVerified) {
|
|
848
|
+
return { message: "Email is not verified", status: "error" };
|
|
849
|
+
} else {
|
|
850
|
+
return { message: "User successfully logged in", status: "success", data: userAuth.user };
|
|
851
|
+
}
|
|
852
|
+
} else {
|
|
853
|
+
return { message: "Unknown account", status: "error" };
|
|
854
|
+
}
|
|
855
|
+
} catch (error) {
|
|
856
|
+
throw new Error(`login error: , ${error}`);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* sign user with user's number
|
|
861
|
+
* @param param0
|
|
862
|
+
* @returns
|
|
863
|
+
*/
|
|
864
|
+
async signInWithPhoneNumber({ auth, phoneNumber, appVerifier }) {
|
|
865
|
+
try {
|
|
866
|
+
return await (0, import_auth.signInWithPhoneNumber)(auth, phoneNumber, appVerifier);
|
|
867
|
+
} catch (error) {
|
|
868
|
+
throw new Error(`signInWithPhoneNumber error: , ${error}`);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
/**
|
|
872
|
+
* Check if user is currently logged in
|
|
873
|
+
* @param auth
|
|
874
|
+
* @returns
|
|
875
|
+
*/
|
|
876
|
+
isLoggedIn(auth) {
|
|
877
|
+
try {
|
|
878
|
+
if (auth.currentUser) {
|
|
879
|
+
return true;
|
|
880
|
+
} else {
|
|
881
|
+
return false;
|
|
882
|
+
}
|
|
883
|
+
} catch (error) {
|
|
884
|
+
throw new Error(`isLoggedIn error: , ${error}`);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
/**
|
|
888
|
+
* Reset logged in user's password
|
|
889
|
+
* @param {Auth, string} param0
|
|
890
|
+
* @returns {boolean}
|
|
891
|
+
*/
|
|
892
|
+
async resetPassword({ auth, newPassword }) {
|
|
893
|
+
try {
|
|
894
|
+
await (0, import_auth.updatePassword)(auth.currentUser, newPassword);
|
|
895
|
+
return true;
|
|
896
|
+
} catch (e) {
|
|
897
|
+
throw new Error(`resetPassword error: , ${e}`);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* send password reset message to user's email address
|
|
902
|
+
* @param param0
|
|
903
|
+
* @returns
|
|
904
|
+
*/
|
|
905
|
+
async sendPasswordResetMessage({ auth, email }) {
|
|
906
|
+
try {
|
|
907
|
+
await (0, import_auth.sendPasswordResetEmail)(auth, email);
|
|
908
|
+
return true;
|
|
909
|
+
} catch (e) {
|
|
910
|
+
throw new Error(`sendPasswordResetMessage error: , ${e}`);
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
914
|
+
* logout users and end current session
|
|
915
|
+
* @param param0
|
|
916
|
+
* @returns
|
|
917
|
+
*/
|
|
918
|
+
async logout({ auth }) {
|
|
919
|
+
try {
|
|
920
|
+
await (0, import_auth.signOut)(auth);
|
|
921
|
+
return true;
|
|
922
|
+
} catch (e) {
|
|
923
|
+
throw new Error(`logout error: , ${e}`);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
/**
|
|
927
|
+
* create and validate users
|
|
928
|
+
* @param param0
|
|
929
|
+
*/
|
|
930
|
+
async loginWithMultiAuthFactor({ email, password, auth, recaptcha, getNumber, persist = true, verifyEmail = false }) {
|
|
931
|
+
try {
|
|
932
|
+
if (persist) {
|
|
933
|
+
await (0, import_auth.setPersistence)(auth, import_auth.browserSessionPersistence);
|
|
934
|
+
}
|
|
935
|
+
const credential = await (0, import_auth.signInWithEmailAndPassword)(auth, email, password);
|
|
936
|
+
if (credential) {
|
|
937
|
+
if (verifyEmail && !credential.user.emailVerified) {
|
|
938
|
+
await this.sendEmailVerification(credential.user);
|
|
939
|
+
throw new Error("Email is not verified");
|
|
940
|
+
}
|
|
941
|
+
let phoneNumber;
|
|
942
|
+
if (getNumber) {
|
|
943
|
+
phoneNumber = await this.getPhoneNumber(credential.user.uid);
|
|
944
|
+
}
|
|
945
|
+
const user = credential.user;
|
|
946
|
+
const verificationId = await this.setMultiFactorEnrollment(user, recaptcha, auth, phoneNumber != null ? phoneNumber : credential.user.phoneNumber);
|
|
947
|
+
if (verificationId) {
|
|
948
|
+
return { verificationId, user };
|
|
949
|
+
} else {
|
|
950
|
+
return null;
|
|
951
|
+
}
|
|
952
|
+
} else {
|
|
953
|
+
return null;
|
|
954
|
+
}
|
|
955
|
+
} catch (e) {
|
|
956
|
+
const error = e;
|
|
957
|
+
if (error.code === "auth/multi-factor-auth-required") {
|
|
958
|
+
const resolver = (0, import_auth.getMultiFactorResolver)(auth, error);
|
|
959
|
+
return await this.sendOTP(resolver, recaptcha, auth);
|
|
960
|
+
} else {
|
|
961
|
+
throw new Error(`loginWithMultiAuthFactor error: ${error}`);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
/**
|
|
966
|
+
* delete user account
|
|
967
|
+
* @param user
|
|
968
|
+
*/
|
|
969
|
+
async deleteAccount(user) {
|
|
970
|
+
try {
|
|
971
|
+
await Promise.all([
|
|
972
|
+
(0, import_auth.deleteUser)(user),
|
|
973
|
+
this.delete(user.uid)
|
|
974
|
+
]);
|
|
975
|
+
} catch (error) {
|
|
976
|
+
throw new Error(`deleteAccount error: ,${error}`);
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
/**
|
|
980
|
+
* resend email verification for expired link
|
|
981
|
+
* @param auth
|
|
982
|
+
* @returns
|
|
983
|
+
*/
|
|
984
|
+
async sendEmailVerification(user) {
|
|
985
|
+
try {
|
|
986
|
+
if (user) {
|
|
987
|
+
(0, import_auth.sendEmailVerification)(user);
|
|
988
|
+
return null;
|
|
989
|
+
} else {
|
|
990
|
+
return "Unknown user account, please sign up!";
|
|
991
|
+
}
|
|
992
|
+
} catch (error) {
|
|
993
|
+
throw new Error(`sendEmailVerification error: , ${error}`);
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
async doPasswordReset(auth, actionCode, newPassword) {
|
|
997
|
+
try {
|
|
998
|
+
await (0, import_auth.confirmPasswordReset)(auth, actionCode, newPassword);
|
|
999
|
+
return true;
|
|
1000
|
+
} catch (e) {
|
|
1001
|
+
throw new Error(`doPasswordReset error: , ${e}`);
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
};
|
|
1005
|
+
|
|
1006
|
+
// src/Storage.ts
|
|
1007
|
+
var import_storage = require("firebase/storage");
|
|
1008
|
+
|
|
1009
|
+
// src/constants.ts
|
|
1010
|
+
var fbsession = /^firebase:authUser:/;
|
|
1011
|
+
var UPLOADTYPES = /* @__PURE__ */ ((UPLOADTYPES2) => {
|
|
1012
|
+
UPLOADTYPES2["IMAGES"] = "images";
|
|
1013
|
+
UPLOADTYPES2["DOCUMENTS"] = "documents";
|
|
1014
|
+
UPLOADTYPES2["VIDEOS"] = "videos";
|
|
1015
|
+
UPLOADTYPES2["AUDIOS"] = "audios";
|
|
1016
|
+
return UPLOADTYPES2;
|
|
1017
|
+
})(UPLOADTYPES || {});
|
|
1018
|
+
var AUTH_PROVIDERS = /* @__PURE__ */ ((AUTH_PROVIDERS2) => {
|
|
1019
|
+
AUTH_PROVIDERS2[AUTH_PROVIDERS2["GOOGLE"] = 0] = "GOOGLE";
|
|
1020
|
+
AUTH_PROVIDERS2[AUTH_PROVIDERS2["APPLE"] = 1] = "APPLE";
|
|
1021
|
+
AUTH_PROVIDERS2[AUTH_PROVIDERS2["FACEBOOK"] = 2] = "FACEBOOK";
|
|
1022
|
+
AUTH_PROVIDERS2[AUTH_PROVIDERS2["TWITTER"] = 3] = "TWITTER";
|
|
1023
|
+
return AUTH_PROVIDERS2;
|
|
1024
|
+
})(AUTH_PROVIDERS || {});
|
|
1025
|
+
|
|
1026
|
+
// src/Storage.ts
|
|
1027
|
+
var StorageUpload = class {
|
|
1028
|
+
constructor(props) {
|
|
1029
|
+
// validate file (size, type)
|
|
1030
|
+
this.validateFile = (file, storageRef) => {
|
|
1031
|
+
var _a;
|
|
1032
|
+
let goodSize = false;
|
|
1033
|
+
let goodType = false;
|
|
1034
|
+
let extension = "";
|
|
1035
|
+
let goodTypes = [];
|
|
1036
|
+
if (typeof file !== "string") {
|
|
1037
|
+
if (storageRef === "images" /* IMAGES */) {
|
|
1038
|
+
goodTypes = ["image/png", "image/jpg", "image/jpeg"];
|
|
1039
|
+
extension = this.getExtensionName(file.type);
|
|
1040
|
+
} else if (storageRef === "documents" /* DOCUMENTS */) {
|
|
1041
|
+
goodTypes = [
|
|
1042
|
+
"application/pdf",
|
|
1043
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
1044
|
+
"application/vnd.ms-excel"
|
|
1045
|
+
];
|
|
1046
|
+
extension = this.getDocExtensionName(file.type);
|
|
1047
|
+
} else if (storageRef === "videos" /* VIDEOS */) {
|
|
1048
|
+
goodTypes = ["video/mp4", "video/m4v"];
|
|
1049
|
+
} else if (storageRef === "audios" /* AUDIOS */) {
|
|
1050
|
+
goodTypes = ["audio/mp3", "audio/mpeg"];
|
|
1051
|
+
}
|
|
1052
|
+
goodType = goodTypes.includes(file.type);
|
|
1053
|
+
goodSize = file.size > 0 && file.size <= this.maxSize;
|
|
1054
|
+
} else {
|
|
1055
|
+
goodType = true;
|
|
1056
|
+
goodSize = true;
|
|
1057
|
+
}
|
|
1058
|
+
if (!goodSize || !goodType) {
|
|
1059
|
+
this.setUploadError(storageRef, (_a = this.maxSize) != null ? _a : 1e6, goodSize);
|
|
1060
|
+
} else {
|
|
1061
|
+
this.setFilePath(storageRef, extension);
|
|
1062
|
+
}
|
|
1063
|
+
};
|
|
1064
|
+
/**
|
|
1065
|
+
* Get human readable form for file size
|
|
1066
|
+
* @param size
|
|
1067
|
+
* @returns
|
|
1068
|
+
*/
|
|
1069
|
+
this.sizeMetric = (size) => {
|
|
1070
|
+
let result = `${size} bytes`;
|
|
1071
|
+
if (size <= 999999) {
|
|
1072
|
+
result = `${Math.round(size / 1e3)} Kb`;
|
|
1073
|
+
} else if (size <= 999999999) {
|
|
1074
|
+
result = `${Math.round(size / 1e6)} Mb`;
|
|
1075
|
+
} else if (size <= 999999999999) {
|
|
1076
|
+
result = `${Math.round(size / 1e9)} Gb`;
|
|
1077
|
+
} else if (size <= 999999999999999) {
|
|
1078
|
+
result = `${Math.round(size / 1e12)} T`;
|
|
1079
|
+
}
|
|
1080
|
+
return result;
|
|
1081
|
+
};
|
|
1082
|
+
/**
|
|
1083
|
+
* Get file extensions
|
|
1084
|
+
* @param fileType
|
|
1085
|
+
* @returns
|
|
1086
|
+
*/
|
|
1087
|
+
this.getExtensionName = (fileType) => {
|
|
1088
|
+
let ext = "";
|
|
1089
|
+
if (fileType === "application/pdf") {
|
|
1090
|
+
ext = "pdf";
|
|
1091
|
+
}
|
|
1092
|
+
if (fileType === "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") {
|
|
1093
|
+
ext = ".xlsx";
|
|
1094
|
+
}
|
|
1095
|
+
if (fileType === "application/vnd.ms-excel") {
|
|
1096
|
+
ext = ".xls";
|
|
1097
|
+
}
|
|
1098
|
+
return ext;
|
|
1099
|
+
};
|
|
1100
|
+
this.getDocExtensionName = (fileType) => {
|
|
1101
|
+
let ext = "";
|
|
1102
|
+
if (fileType === "image/png") {
|
|
1103
|
+
ext = "png";
|
|
1104
|
+
}
|
|
1105
|
+
if (fileType === "image/jpg") {
|
|
1106
|
+
ext = "jpg";
|
|
1107
|
+
}
|
|
1108
|
+
if (fileType === "image/jpeg") {
|
|
1109
|
+
ext = "jpeg";
|
|
1110
|
+
}
|
|
1111
|
+
return ext;
|
|
1112
|
+
};
|
|
1113
|
+
/**
|
|
1114
|
+
* setting error messages for failed file validation
|
|
1115
|
+
* @param ref
|
|
1116
|
+
* @param maxSize
|
|
1117
|
+
* @param isGoodSize
|
|
1118
|
+
* @param isGoodType
|
|
1119
|
+
*/
|
|
1120
|
+
this.setUploadError = (ref2, maxSize, isGoodSize) => {
|
|
1121
|
+
this.uploadError = !isGoodSize ? `File size is must not be larger than ${this.sizeMetric(maxSize)}` : `File is not a valid ${ref2 === "images" /* IMAGES */ ? "image" : ref2 === "documents" /* DOCUMENTS */ ? "document" : ref2 === "videos" /* VIDEOS */ ? "video" : "audio"}`;
|
|
1122
|
+
};
|
|
1123
|
+
// generate new file name and extension
|
|
1124
|
+
this.setFilePath = (ref2, ext) => {
|
|
1125
|
+
const d = /* @__PURE__ */ new Date();
|
|
1126
|
+
const fileExtension = ref2 === "images" /* IMAGES */ || ref2 === "documents" /* DOCUMENTS */ ? "." + ext : (
|
|
1127
|
+
// (ref===UPLOADTYPES.DOCUMENTS?'.pdf':(
|
|
1128
|
+
ref2 === "videos" /* VIDEOS */ ? ".mp4" : ".mp3"
|
|
1129
|
+
);
|
|
1130
|
+
const fileName = generateRandomString(30);
|
|
1131
|
+
this.fullPath = ref2.concat(
|
|
1132
|
+
`/`,
|
|
1133
|
+
`${this.additionalPath}/`,
|
|
1134
|
+
`${fileName}_${d.getTime()}${fileExtension}`
|
|
1135
|
+
);
|
|
1136
|
+
};
|
|
1137
|
+
/**
|
|
1138
|
+
* upload base64 data_url
|
|
1139
|
+
* @param reference
|
|
1140
|
+
*/
|
|
1141
|
+
this.uploadAsString = async (reference) => {
|
|
1142
|
+
try {
|
|
1143
|
+
const result = await (0, import_storage.uploadString)(reference, this.file, "data_url");
|
|
1144
|
+
if (result) {
|
|
1145
|
+
return await (0, import_storage.getDownloadURL)((0, import_storage.ref)(this.storage, result.ref.fullPath));
|
|
1146
|
+
} else {
|
|
1147
|
+
return false;
|
|
1148
|
+
}
|
|
1149
|
+
} catch (error) {
|
|
1150
|
+
throw new Error(`uploadAsString: , ${error}`);
|
|
1151
|
+
}
|
|
1152
|
+
};
|
|
1153
|
+
/**
|
|
1154
|
+
* upload blobs and files
|
|
1155
|
+
* @param reference
|
|
1156
|
+
*/
|
|
1157
|
+
this.uploadAsFile = async (reference) => {
|
|
1158
|
+
try {
|
|
1159
|
+
const snapShot = await (0, import_storage.uploadBytesResumable)(reference, this.file);
|
|
1160
|
+
if (snapShot) {
|
|
1161
|
+
return await (0, import_storage.getDownloadURL)((0, import_storage.ref)(this.storage, this.fullPath));
|
|
1162
|
+
} else {
|
|
1163
|
+
return false;
|
|
1164
|
+
}
|
|
1165
|
+
} catch (error) {
|
|
1166
|
+
throw new Error(`uploadAsFile: , ${error}`);
|
|
1167
|
+
}
|
|
1168
|
+
};
|
|
1169
|
+
const { file, basePath, otherPath, maxSize, storage } = props;
|
|
1170
|
+
this.storage = storage;
|
|
1171
|
+
if (file) {
|
|
1172
|
+
this.additionalPath = otherPath;
|
|
1173
|
+
this.maxSize = maxSize != null ? maxSize : 1e6;
|
|
1174
|
+
this.file = file;
|
|
1175
|
+
this.validateFile(file, basePath);
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
/**
|
|
1179
|
+
* Upload images, documents and videos
|
|
1180
|
+
* @param progressMonitor
|
|
1181
|
+
*/
|
|
1182
|
+
async doUpload() {
|
|
1183
|
+
if (this.uploadError) {
|
|
1184
|
+
throw new Error(`doUPload Error: ,${this.uploadError}`);
|
|
1185
|
+
} else {
|
|
1186
|
+
try {
|
|
1187
|
+
const reference = (0, import_storage.ref)(this.storage, this.fullPath);
|
|
1188
|
+
if (typeof this.file === "string") {
|
|
1189
|
+
console.log("uploading as string");
|
|
1190
|
+
return await this.uploadAsString(reference);
|
|
1191
|
+
} else {
|
|
1192
|
+
console.log("uploading as file");
|
|
1193
|
+
return await this.uploadAsFile(reference);
|
|
1194
|
+
}
|
|
1195
|
+
} catch (error) {
|
|
1196
|
+
throw new Error(`doUPload Error: ,${error}`);
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
/**
|
|
1201
|
+
* delete files from storage
|
|
1202
|
+
* @param filePath
|
|
1203
|
+
* @param storage
|
|
1204
|
+
* @returns {boolean}
|
|
1205
|
+
*/
|
|
1206
|
+
static async deleteFile(filePath, storage) {
|
|
1207
|
+
try {
|
|
1208
|
+
const delRef = (0, import_storage.ref)(storage, filePath);
|
|
1209
|
+
await (0, import_storage.deleteObject)(delRef);
|
|
1210
|
+
return true;
|
|
1211
|
+
} catch (error) {
|
|
1212
|
+
return false;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
};
|
|
1216
|
+
|
|
1217
|
+
// src/useAuth.ts
|
|
1218
|
+
var import_react = require("react");
|
|
1219
|
+
var import_auth2 = require("firebase/auth");
|
|
1220
|
+
function useAuth(auth, callback) {
|
|
1221
|
+
(0, import_react.useEffect)(() => {
|
|
1222
|
+
const unsubscribe = (0, import_auth2.onAuthStateChanged)(auth, async (authUser) => {
|
|
1223
|
+
callback(authUser);
|
|
1224
|
+
});
|
|
1225
|
+
return () => unsubscribe();
|
|
1226
|
+
}, []);
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
// src/useCounter.ts
|
|
1230
|
+
var import_react2 = require("react");
|
|
1231
|
+
var useCount = (param) => {
|
|
1232
|
+
const [data, setData] = (0, import_react2.useState)(0);
|
|
1233
|
+
const [loading, setLoading] = (0, import_react2.useState)(true);
|
|
1234
|
+
const fetcher = (0, import_react2.useCallback)(async () => {
|
|
1235
|
+
if (!param.where)
|
|
1236
|
+
return;
|
|
1237
|
+
try {
|
|
1238
|
+
const model = param.model;
|
|
1239
|
+
const found = await model.countData(param.where);
|
|
1240
|
+
setData(found);
|
|
1241
|
+
} catch (error) {
|
|
1242
|
+
errorLogger("useCount: ", error);
|
|
1243
|
+
} finally {
|
|
1244
|
+
setLoading(false);
|
|
1245
|
+
}
|
|
1246
|
+
}, [
|
|
1247
|
+
JSON.stringify(param.where),
|
|
1248
|
+
loading
|
|
1249
|
+
]);
|
|
1250
|
+
(0, import_react2.useEffect)(() => {
|
|
1251
|
+
fetcher();
|
|
1252
|
+
}, [fetcher]);
|
|
1253
|
+
return [data, loading, setLoading];
|
|
1254
|
+
};
|
|
1255
|
+
|
|
1256
|
+
// src/useFetch.ts
|
|
1257
|
+
var import_react3 = require("react");
|
|
1258
|
+
var useFetch = (param) => {
|
|
1259
|
+
const [data, setData] = (0, import_react3.useState)();
|
|
1260
|
+
const [loading, setLoading] = (0, import_react3.useState)(true);
|
|
1261
|
+
const fetcher = (0, import_react3.useCallback)(async () => {
|
|
1262
|
+
var _a, _b, _c, _d;
|
|
1263
|
+
if (!param.reference && !param.where)
|
|
1264
|
+
return;
|
|
1265
|
+
try {
|
|
1266
|
+
const model = param.model;
|
|
1267
|
+
if (param.reference) {
|
|
1268
|
+
const found = await model.find(param.reference);
|
|
1269
|
+
if (found)
|
|
1270
|
+
setData(model.data);
|
|
1271
|
+
} else if (param.where) {
|
|
1272
|
+
const found = await model.findWhere({
|
|
1273
|
+
wh: param.where,
|
|
1274
|
+
lim: (_b = (_a = param.filter) == null ? void 0 : _a.limit) != null ? _b : 100,
|
|
1275
|
+
order: (_c = param.filter) == null ? void 0 : _c.orderBy,
|
|
1276
|
+
offset: (_d = param.filter) == null ? void 0 : _d.offset
|
|
1277
|
+
});
|
|
1278
|
+
setData(found);
|
|
1279
|
+
}
|
|
1280
|
+
} catch (error) {
|
|
1281
|
+
errorLogger("useFetch: ", error);
|
|
1282
|
+
} finally {
|
|
1283
|
+
setLoading(false);
|
|
1284
|
+
}
|
|
1285
|
+
}, [
|
|
1286
|
+
param.reference,
|
|
1287
|
+
JSON.stringify(param.where),
|
|
1288
|
+
JSON.stringify(param.filter),
|
|
1289
|
+
loading
|
|
1290
|
+
]);
|
|
1291
|
+
(0, import_react3.useEffect)(() => {
|
|
1292
|
+
fetcher();
|
|
1293
|
+
}, [fetcher]);
|
|
1294
|
+
return [data, loading, setLoading];
|
|
1295
|
+
};
|
|
1296
|
+
|
|
1297
|
+
// src/useStream.ts
|
|
1298
|
+
var import_react4 = require("react");
|
|
1299
|
+
var useStream = (param, callback) => {
|
|
1300
|
+
(0, import_react4.useEffect)(() => {
|
|
1301
|
+
let unsubscribe;
|
|
1302
|
+
try {
|
|
1303
|
+
const { model, reference, where: where2, filter } = param;
|
|
1304
|
+
if (reference) {
|
|
1305
|
+
unsubscribe = model.stream((data) => {
|
|
1306
|
+
if (data)
|
|
1307
|
+
callback(data);
|
|
1308
|
+
}, reference);
|
|
1309
|
+
} else if (where2) {
|
|
1310
|
+
const allInvalid = where2.every((item) => item.value === void 0);
|
|
1311
|
+
if (allInvalid) {
|
|
1312
|
+
callback([]);
|
|
1313
|
+
return;
|
|
1314
|
+
}
|
|
1315
|
+
unsubscribe = model.streamWhere(
|
|
1316
|
+
where2,
|
|
1317
|
+
(data) => {
|
|
1318
|
+
if (data)
|
|
1319
|
+
callback(data);
|
|
1320
|
+
},
|
|
1321
|
+
100,
|
|
1322
|
+
filter == null ? void 0 : filter.orderBy,
|
|
1323
|
+
filter == null ? void 0 : filter.offset
|
|
1324
|
+
);
|
|
1325
|
+
}
|
|
1326
|
+
} catch (error) {
|
|
1327
|
+
errorLogger("useStream error:", error);
|
|
1328
|
+
}
|
|
1329
|
+
return () => {
|
|
1330
|
+
if (typeof unsubscribe === "function") {
|
|
1331
|
+
unsubscribe();
|
|
1332
|
+
}
|
|
1333
|
+
};
|
|
1334
|
+
}, [JSON.stringify(param.where), JSON.stringify(param.filter), param.reference]);
|
|
1335
|
+
};
|
|
1336
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1337
|
+
0 && (module.exports = {
|
|
1338
|
+
AUTH_PROVIDERS,
|
|
1339
|
+
BaseModel,
|
|
1340
|
+
StorageUpload,
|
|
1341
|
+
UPLOADTYPES,
|
|
1342
|
+
Users,
|
|
1343
|
+
camelCaseToNormal,
|
|
1344
|
+
camelToTitleCase,
|
|
1345
|
+
convertUnicode,
|
|
1346
|
+
errorLogger,
|
|
1347
|
+
fbsession,
|
|
1348
|
+
fetchCurrentTimestamp,
|
|
1349
|
+
formHasError,
|
|
1350
|
+
generateRandomString,
|
|
1351
|
+
getDaysAgo,
|
|
1352
|
+
getInitials,
|
|
1353
|
+
getNthNumberOfArray,
|
|
1354
|
+
isValidEmail,
|
|
1355
|
+
isValidPassword,
|
|
1356
|
+
moneyFormatter,
|
|
1357
|
+
nairaFormatter,
|
|
1358
|
+
noEmptyField,
|
|
1359
|
+
numberToAlphabet,
|
|
1360
|
+
range,
|
|
1361
|
+
timeAgo,
|
|
1362
|
+
useAuth,
|
|
1363
|
+
useCount,
|
|
1364
|
+
useFetch,
|
|
1365
|
+
useStream
|
|
1366
|
+
});
|