@progressive-development/pd-provider-firebase-functions 1.3.0 → 1.3.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/auth-trash.js +118 -107
- package/dist/auth.js +30 -23
- package/dist/changes.js +53 -60
- package/dist/counter.js +19 -17
- package/dist/errors.js +41 -40
- package/dist/firestore.js +17 -11
- package/dist/history.js +74 -45
- package/dist/import-templates.js +102 -106
- package/dist/index.js +16 -15
- package/dist/logger.js +11 -8
- package/dist/mail.js +56 -35
- package/dist/response.js +35 -26
- package/dist/script-helpers.js +55 -44
- package/dist/trash.js +105 -72
- package/dist/types.js +10 -9
- package/dist/visits.js +124 -82
- package/package.json +11 -8
package/dist/auth-trash.js
CHANGED
|
@@ -1,116 +1,127 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
1
|
+
import { NotFoundError } from "./errors.js";
|
|
2
|
+
import { logger } from "./logger.js";
|
|
3
|
+
import { getTrashItem, moveToTrash, permanentDelete, restoreFromTrash } from "./trash.js";
|
|
4
|
+
import { getAuth } from "firebase-admin/auth";
|
|
5
|
+
//#region src/auth-trash.ts
|
|
6
|
+
/**
|
|
7
|
+
* Auth-aware Trash Functions
|
|
8
|
+
*
|
|
9
|
+
* Extends the generic trash service with Firebase Auth user handling.
|
|
10
|
+
* Use these when the trashed document is linked to an Auth user.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Extract Auth UID from trash item based on options.
|
|
14
|
+
*/
|
|
6
15
|
function getAuthUidFromTrashItem(trashItem, options) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const uid = data[source];
|
|
13
|
-
if (typeof uid !== "string" || !uid) {
|
|
14
|
-
throw new Error(
|
|
15
|
-
`Auth UID field '${source}' not found or empty in trash item data`
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
return uid;
|
|
16
|
+
const source = options?.authUidSource ?? "documentId";
|
|
17
|
+
if (source === "documentId") return trashItem.originalId;
|
|
18
|
+
const uid = trashItem.data[source];
|
|
19
|
+
if (typeof uid !== "string" || !uid) throw new Error(`Auth UID field '${source}' not found or empty in trash item data`);
|
|
20
|
+
return uid;
|
|
19
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Move document to trash AND disable the associated Auth user.
|
|
24
|
+
*
|
|
25
|
+
* Order of operations:
|
|
26
|
+
* 1. Disable Auth user (if user doesn't exist, continue anyway)
|
|
27
|
+
* 2. Move document to trash
|
|
28
|
+
*
|
|
29
|
+
* @param collection - The collection path
|
|
30
|
+
* @param documentId - The document ID to trash
|
|
31
|
+
* @param deletedBy - UID of the user performing the deletion
|
|
32
|
+
* @param objectType - Type identifier for filtering
|
|
33
|
+
* @param options - Auth and database options
|
|
34
|
+
* @returns The created trash item
|
|
35
|
+
*/
|
|
20
36
|
async function moveToTrashWithAuth(collection, documentId, deletedBy, objectType, options) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const trashItem = await moveToTrash(
|
|
41
|
-
collection,
|
|
42
|
-
documentId,
|
|
43
|
-
deletedBy,
|
|
44
|
-
objectType,
|
|
45
|
-
options?.databaseId
|
|
46
|
-
);
|
|
47
|
-
logger.info("Document moved to trash with Auth disabled", {
|
|
48
|
-
trashItemId: trashItem.id,
|
|
49
|
-
authUid
|
|
50
|
-
});
|
|
51
|
-
return trashItem;
|
|
37
|
+
const authUid = options?.authUidSource === "documentId" || !options?.authUidSource ? documentId : documentId;
|
|
38
|
+
logger.info("Disabling Auth user before trash", {
|
|
39
|
+
authUid,
|
|
40
|
+
collection,
|
|
41
|
+
documentId
|
|
42
|
+
});
|
|
43
|
+
try {
|
|
44
|
+
await getAuth().updateUser(authUid, { disabled: true });
|
|
45
|
+
logger.info("Auth user disabled", { authUid });
|
|
46
|
+
} catch (error) {
|
|
47
|
+
if (error.code === "auth/user-not-found") logger.info("Auth user not found, continuing with trash operation", { authUid });
|
|
48
|
+
else throw error;
|
|
49
|
+
}
|
|
50
|
+
const trashItem = await moveToTrash(collection, documentId, deletedBy, objectType, options?.databaseId);
|
|
51
|
+
logger.info("Document moved to trash with Auth disabled", {
|
|
52
|
+
trashItemId: trashItem.id,
|
|
53
|
+
authUid
|
|
54
|
+
});
|
|
55
|
+
return trashItem;
|
|
52
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Restore document from trash AND re-enable the Auth user.
|
|
59
|
+
*
|
|
60
|
+
* Order of operations:
|
|
61
|
+
* 1. Get trash item to find Auth UID
|
|
62
|
+
* 2. Restore document from trash
|
|
63
|
+
* 3. Re-enable Auth user (if user doesn't exist, log warning)
|
|
64
|
+
*
|
|
65
|
+
* @param trashItemId - The trash document ID
|
|
66
|
+
* @param options - Auth and database options
|
|
67
|
+
*/
|
|
53
68
|
async function restoreFromTrashWithAuth(trashItemId, options) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
{
|
|
77
|
-
trashItemId,
|
|
78
|
-
authUid
|
|
79
|
-
}
|
|
80
|
-
);
|
|
81
|
-
} else {
|
|
82
|
-
throw error;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
69
|
+
const trashItem = await getTrashItem(trashItemId, options?.databaseId);
|
|
70
|
+
if (!trashItem) throw new NotFoundError(`Trash item ${trashItemId} not found`);
|
|
71
|
+
const authUid = getAuthUidFromTrashItem(trashItem, options);
|
|
72
|
+
logger.info("Restoring from trash with Auth re-enable", {
|
|
73
|
+
trashItemId,
|
|
74
|
+
authUid,
|
|
75
|
+
originalCollection: trashItem.originalCollection
|
|
76
|
+
});
|
|
77
|
+
await restoreFromTrash(trashItemId, options?.databaseId);
|
|
78
|
+
try {
|
|
79
|
+
await getAuth().updateUser(authUid, { disabled: false });
|
|
80
|
+
logger.info("Document restored and Auth user re-enabled", {
|
|
81
|
+
trashItemId,
|
|
82
|
+
authUid
|
|
83
|
+
});
|
|
84
|
+
} catch (error) {
|
|
85
|
+
if (error.code === "auth/user-not-found") logger.warn("Document restored but Auth user not found - manual Auth user creation required", {
|
|
86
|
+
trashItemId,
|
|
87
|
+
authUid
|
|
88
|
+
});
|
|
89
|
+
else throw error;
|
|
90
|
+
}
|
|
85
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Permanently delete from trash AND delete the Auth user.
|
|
94
|
+
*
|
|
95
|
+
* Order of operations:
|
|
96
|
+
* 1. Get trash item to find Auth UID
|
|
97
|
+
* 2. Delete from trash
|
|
98
|
+
* 3. Delete Auth user (ignore if user doesn't exist)
|
|
99
|
+
*
|
|
100
|
+
* @param trashItemId - The trash document ID
|
|
101
|
+
* @param options - Auth and database options
|
|
102
|
+
*/
|
|
86
103
|
async function permanentDeleteWithAuth(trashItemId, options) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
authUid
|
|
109
|
-
});
|
|
110
|
-
} else {
|
|
111
|
-
throw error;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
104
|
+
const trashItem = await getTrashItem(trashItemId, options?.databaseId);
|
|
105
|
+
if (!trashItem) throw new NotFoundError(`Trash item ${trashItemId} not found`);
|
|
106
|
+
const authUid = getAuthUidFromTrashItem(trashItem, options);
|
|
107
|
+
logger.info("Permanently deleting with Auth user deletion", {
|
|
108
|
+
trashItemId,
|
|
109
|
+
authUid
|
|
110
|
+
});
|
|
111
|
+
await permanentDelete(trashItemId, options?.databaseId);
|
|
112
|
+
try {
|
|
113
|
+
await getAuth().deleteUser(authUid);
|
|
114
|
+
logger.info("Trash item and Auth user permanently deleted", {
|
|
115
|
+
trashItemId,
|
|
116
|
+
authUid
|
|
117
|
+
});
|
|
118
|
+
} catch (error) {
|
|
119
|
+
if (error.code === "auth/user-not-found") logger.info("Auth user not found, trash item deleted", {
|
|
120
|
+
trashItemId,
|
|
121
|
+
authUid
|
|
122
|
+
});
|
|
123
|
+
else throw error;
|
|
124
|
+
}
|
|
114
125
|
}
|
|
115
|
-
|
|
126
|
+
//#endregion
|
|
116
127
|
export { moveToTrashWithAuth, permanentDeleteWithAuth, restoreFromTrashWithAuth };
|
package/dist/auth.js
CHANGED
|
@@ -1,30 +1,37 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { logger } from
|
|
3
|
-
|
|
1
|
+
import { ForbiddenError, UnauthorizedError } from "./errors.js";
|
|
2
|
+
import { logger } from "./logger.js";
|
|
3
|
+
//#region src/auth.ts
|
|
4
|
+
/**
|
|
5
|
+
* Require authenticated user
|
|
6
|
+
*/
|
|
4
7
|
function requireAuth(request) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
claims: request.auth.token
|
|
12
|
-
};
|
|
8
|
+
if (!request.auth) throw new UnauthorizedError();
|
|
9
|
+
return {
|
|
10
|
+
uid: request.auth.uid,
|
|
11
|
+
email: request.auth.token.email ?? null,
|
|
12
|
+
claims: request.auth.token
|
|
13
|
+
};
|
|
13
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Require specific role claims.
|
|
17
|
+
* Supports Firebase standard format: { admin: true, developer: true }
|
|
18
|
+
*/
|
|
14
19
|
function requireClaims(request, allowedRoles) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
throw new ForbiddenError();
|
|
19
|
-
}
|
|
20
|
-
return auth;
|
|
20
|
+
const auth = requireAuth(request);
|
|
21
|
+
if (!allowedRoles.some((role) => auth.claims[role] === true)) throw new ForbiddenError();
|
|
22
|
+
return auth;
|
|
21
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Ensure user can only access own resources
|
|
26
|
+
*/
|
|
22
27
|
function requireOwnership(auth, resourceOwnerId) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
if (!(auth.claims.admin === true) && auth.uid !== resourceOwnerId) {
|
|
29
|
+
logger.warn("Ownership violation", {
|
|
30
|
+
uid: auth.uid,
|
|
31
|
+
resourceOwnerId
|
|
32
|
+
});
|
|
33
|
+
throw new ForbiddenError("Cannot access other user's resources");
|
|
34
|
+
}
|
|
28
35
|
}
|
|
29
|
-
|
|
36
|
+
//#endregion
|
|
30
37
|
export { requireAuth, requireClaims, requireOwnership };
|
package/dist/changes.js
CHANGED
|
@@ -1,69 +1,62 @@
|
|
|
1
|
+
//#region src/changes.ts
|
|
1
2
|
function hasIsEqual(value) {
|
|
2
|
-
|
|
3
|
+
return typeof value === "object" && value !== null && typeof value.isEqual === "function";
|
|
3
4
|
}
|
|
5
|
+
/** undefined, null and missing keys all count as "not set" and equal. */
|
|
4
6
|
function isUnset(value) {
|
|
5
|
-
|
|
7
|
+
return value === void 0 || value === null;
|
|
6
8
|
}
|
|
7
9
|
function isEqualValue(a, b) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
if (a instanceof Date && b instanceof Date) {
|
|
31
|
-
return a.getTime() === b.getTime();
|
|
32
|
-
}
|
|
33
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
34
|
-
return a.length === b.length && a.every((item, i) => isEqualValue(item, b[i]));
|
|
35
|
-
}
|
|
36
|
-
if (Array.isArray(a) || Array.isArray(b)) {
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
if (typeof a === "object" && typeof b === "object") {
|
|
40
|
-
const aObj = a;
|
|
41
|
-
const bObj = b;
|
|
42
|
-
const keys = /* @__PURE__ */ new Set([...Object.keys(aObj), ...Object.keys(bObj)]);
|
|
43
|
-
for (const key of keys) {
|
|
44
|
-
if (!isEqualValue(aObj[key], bObj[key])) {
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
return true;
|
|
49
|
-
}
|
|
50
|
-
return false;
|
|
10
|
+
if (isUnset(a) && isUnset(b)) return true;
|
|
11
|
+
if (isUnset(a) || isUnset(b)) return false;
|
|
12
|
+
if (a === b) return true;
|
|
13
|
+
if (typeof a === "number" && typeof b === "number" && Number.isNaN(a) && Number.isNaN(b)) return true;
|
|
14
|
+
if (hasIsEqual(a) && hasIsEqual(b)) try {
|
|
15
|
+
return a.isEqual(b);
|
|
16
|
+
} catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
if (hasIsEqual(a) || hasIsEqual(b)) return false;
|
|
20
|
+
if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();
|
|
21
|
+
if (Array.isArray(a) && Array.isArray(b)) return a.length === b.length && a.every((item, i) => isEqualValue(item, b[i]));
|
|
22
|
+
if (Array.isArray(a) || Array.isArray(b)) return false;
|
|
23
|
+
if (typeof a === "object" && typeof b === "object") {
|
|
24
|
+
const aObj = a;
|
|
25
|
+
const bObj = b;
|
|
26
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(aObj), ...Object.keys(bObj)]);
|
|
27
|
+
for (const key of keys) if (!isEqualValue(aObj[key], bObj[key])) return false;
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
51
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Compute which top-level fields changed between two object states.
|
|
34
|
+
*
|
|
35
|
+
* Values are compared deeply (nested objects, arrays), but changes are
|
|
36
|
+
* reported per top-level field with the full old/new value. Firestore value
|
|
37
|
+
* types are compared via their own isEqual(). undefined, null and missing
|
|
38
|
+
* keys are treated as the same "not set" state.
|
|
39
|
+
*
|
|
40
|
+
* @param before - Previous state; undefined means "object did not exist yet"
|
|
41
|
+
* @param after - New state
|
|
42
|
+
* @param options - Optional ignore list for noisy fields (e.g. "lastEdit")
|
|
43
|
+
* @returns The changed fields — or undefined if nothing changed, so
|
|
44
|
+
* "did anything change?" is a truthiness check on the result
|
|
45
|
+
*/
|
|
52
46
|
function computeChanges(before, after, options) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
return Object.keys(changes).length > 0 ? changes : void 0;
|
|
47
|
+
const ignore = new Set(options?.ignoreFields ?? []);
|
|
48
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(before ?? {}), ...Object.keys(after)]);
|
|
49
|
+
const changes = {};
|
|
50
|
+
for (const key of keys) {
|
|
51
|
+
if (ignore.has(key)) continue;
|
|
52
|
+
const oldValue = before?.[key];
|
|
53
|
+
const newValue = after[key];
|
|
54
|
+
if (!isEqualValue(oldValue, newValue)) changes[key] = {
|
|
55
|
+
old: oldValue ?? null,
|
|
56
|
+
new: newValue ?? null
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return Object.keys(changes).length > 0 ? changes : void 0;
|
|
67
60
|
}
|
|
68
|
-
|
|
61
|
+
//#endregion
|
|
69
62
|
export { computeChanges };
|
package/dist/counter.js
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
import { getDb } from
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { getDb } from "./firestore.js";
|
|
2
|
+
//#region src/counter.ts
|
|
3
|
+
var COUNTERS_COLLECTION = "counters";
|
|
4
|
+
/**
|
|
5
|
+
* Get next counter value atomically
|
|
6
|
+
* Uses Firestore transaction to prevent race conditions
|
|
7
|
+
*/
|
|
4
8
|
async function getNextCounter(counterName, databaseId) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return next;
|
|
17
|
-
});
|
|
9
|
+
const db = getDb(databaseId);
|
|
10
|
+
const counterRef = db.collection(COUNTERS_COLLECTION).doc(counterName);
|
|
11
|
+
return db.runTransaction(async (transaction) => {
|
|
12
|
+
const doc = await transaction.get(counterRef);
|
|
13
|
+
const next = (doc.exists ? doc.data()?.value ?? 0 : 0) + 1;
|
|
14
|
+
transaction.set(counterRef, {
|
|
15
|
+
value: next,
|
|
16
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
17
|
+
}, { merge: true });
|
|
18
|
+
return next;
|
|
19
|
+
});
|
|
18
20
|
}
|
|
19
|
-
|
|
21
|
+
//#endregion
|
|
20
22
|
export { getNextCounter };
|
package/dist/errors.js
CHANGED
|
@@ -1,41 +1,42 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
1
|
+
//#region src/errors.ts
|
|
2
|
+
var SC_EMAIL_ALREADY_USED = -160;
|
|
3
|
+
var AppError = class extends Error {
|
|
4
|
+
constructor(message, code, statusCode) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.code = code;
|
|
7
|
+
this.statusCode = statusCode;
|
|
8
|
+
this.name = this.constructor.name;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
var ValidationError = class extends AppError {
|
|
12
|
+
constructor(message) {
|
|
13
|
+
super(message, "VALIDATION_ERROR", 400);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
var UnauthorizedError = class extends AppError {
|
|
17
|
+
constructor(message = "Authentication required") {
|
|
18
|
+
super(message, "UNAUTHORIZED", 401);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var ForbiddenError = class extends AppError {
|
|
22
|
+
constructor(message = "Access denied") {
|
|
23
|
+
super(message, "FORBIDDEN", 403);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var NotFoundError = class extends AppError {
|
|
27
|
+
constructor(message) {
|
|
28
|
+
super(message, "NOT_FOUND", 404);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
var ConflictError = class extends AppError {
|
|
32
|
+
constructor(message, code = "CONFLICT") {
|
|
33
|
+
super(message, code, 409);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
var EmailAlreadyUsedError = class extends AppError {
|
|
37
|
+
constructor() {
|
|
38
|
+
super("Email already used", "EMAIL_ALREADY_USED", SC_EMAIL_ALREADY_USED);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
//#endregion
|
|
41
42
|
export { AppError, ConflictError, EmailAlreadyUsedError, ForbiddenError, NotFoundError, SC_EMAIL_ALREADY_USED, UnauthorizedError, ValidationError };
|
package/dist/firestore.js
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
|
-
import { getFirestore } from
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { getFirestore } from "firebase-admin/firestore";
|
|
2
|
+
//#region src/firestore.ts
|
|
3
|
+
var dbCache = /* @__PURE__ */ new Map();
|
|
4
|
+
/**
|
|
5
|
+
* Get Firestore instance (cached)
|
|
6
|
+
*
|
|
7
|
+
* Uses the default Firebase app - consumer must call initializeApp() first.
|
|
8
|
+
* @param databaseId Optional named database
|
|
9
|
+
*/
|
|
4
10
|
function getDb(databaseId) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
const cacheKey = databaseId ?? "default";
|
|
12
|
+
if (!dbCache.has(cacheKey)) {
|
|
13
|
+
const db = databaseId ? getFirestore(databaseId) : getFirestore();
|
|
14
|
+
db.settings({ ignoreUndefinedProperties: true });
|
|
15
|
+
dbCache.set(cacheKey, db);
|
|
16
|
+
}
|
|
17
|
+
return dbCache.get(cacheKey);
|
|
12
18
|
}
|
|
13
|
-
|
|
19
|
+
//#endregion
|
|
14
20
|
export { getDb };
|