@knymbus/firestoredb 1.0.14 → 1.2.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/dist/cjs/FirestoreDB.d.ts +23 -8
- package/dist/cjs/FirestoreDB.d.ts.map +1 -1
- package/dist/cjs/FirestoreDB.js +136 -38
- package/dist/cjs/FirestoreQuery.d.ts +2 -1
- package/dist/cjs/FirestoreQuery.d.ts.map +1 -1
- package/dist/cjs/FirestoreQuery.js +5 -1
- package/dist/cjs/types.d.ts +15 -4
- package/dist/cjs/types.d.ts.map +1 -1
- package/dist/cjs/utils/createFirestoreDB.d.ts +1 -1
- package/dist/cjs/utils/createFirestoreDB.d.ts.map +1 -1
- package/dist/cjs/utils/createFirestoreDB.js +2 -2
- package/dist/esm/FirestoreDB.d.ts +23 -8
- package/dist/esm/FirestoreDB.d.ts.map +1 -1
- package/dist/esm/FirestoreDB.js +136 -38
- package/dist/esm/FirestoreQuery.d.ts +2 -1
- package/dist/esm/FirestoreQuery.d.ts.map +1 -1
- package/dist/esm/FirestoreQuery.js +5 -1
- package/dist/esm/types.d.ts +15 -4
- package/dist/esm/types.d.ts.map +1 -1
- package/dist/esm/utils/createFirestoreDB.d.ts +1 -1
- package/dist/esm/utils/createFirestoreDB.d.ts.map +1 -1
- package/dist/esm/utils/createFirestoreDB.js +2 -2
- package/package.json +3 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Firestore, FirestoreError, Unsubscribe } from 'firebase/firestore';
|
|
2
2
|
import { FirestoreQuery } from './FirestoreQuery';
|
|
3
|
-
import { DBOptions, DocumentInput, FirestoreSDK, QueryFilter, UpdateDocument, WithSystemFields } from './types';
|
|
3
|
+
import { DBOptions, DocumentInput, FirestoreSDK, QueryFilter, SecurityUser, UpdateDocument, WithSystemFields } from './types';
|
|
4
4
|
export declare class FirestoreDB<T> {
|
|
5
5
|
private _db;
|
|
6
6
|
private _collectionName;
|
|
@@ -8,14 +8,16 @@ export declare class FirestoreDB<T> {
|
|
|
8
8
|
private _options;
|
|
9
9
|
private _collectionRef;
|
|
10
10
|
private _isSoftDeleteEnabled;
|
|
11
|
-
private _security?;
|
|
12
11
|
private _tenantField;
|
|
12
|
+
private _userToken;
|
|
13
|
+
private _activeTenantId;
|
|
14
|
+
private _currentUser;
|
|
13
15
|
/**
|
|
14
16
|
* Initialize with Firebase DB and targeted collection Name
|
|
15
17
|
* @param db: Firebase
|
|
16
18
|
* @param collection string
|
|
17
19
|
*/
|
|
18
|
-
constructor(_db: Firestore, _collectionName: string, _sdk: FirestoreSDK, _options?: DBOptions);
|
|
20
|
+
constructor(_db: Firestore, _collectionName: string, _sdk: FirestoreSDK, _options?: DBOptions, user?: SecurityUser);
|
|
19
21
|
/**
|
|
20
22
|
* FIRESTOREDB: findOne({ age: '13' }); or findOne('id_123');
|
|
21
23
|
*/
|
|
@@ -38,7 +40,7 @@ export declare class FirestoreDB<T> {
|
|
|
38
40
|
*/
|
|
39
41
|
insertOne: (entity: Partial<T & {
|
|
40
42
|
_id?: string;
|
|
41
|
-
}>) => Promise<WithSystemFields<T
|
|
43
|
+
}>) => Promise<WithSystemFields<T> | null>;
|
|
42
44
|
/**
|
|
43
45
|
* FIRESTOREDB: insertMany(docs) - Uses Firestore Batched Writes (Limit 500 per batch)
|
|
44
46
|
*
|
|
@@ -57,9 +59,7 @@ export declare class FirestoreDB<T> {
|
|
|
57
59
|
*/
|
|
58
60
|
updateMany: <T_1>(updates: UpdateDocument<T_1>[], options?: {
|
|
59
61
|
upsert?: boolean;
|
|
60
|
-
}) => Promise<
|
|
61
|
-
_id: string;
|
|
62
|
-
}[]>;
|
|
62
|
+
}) => Promise<string[]>;
|
|
63
63
|
/**
|
|
64
64
|
* FIRESTOREDB: deleteOne('id_123')
|
|
65
65
|
*/
|
|
@@ -109,6 +109,17 @@ export declare class FirestoreDB<T> {
|
|
|
109
109
|
$count?: boolean;
|
|
110
110
|
};
|
|
111
111
|
}) => Promise<import("@firebase/firestore").AggregateSpecData<any>>;
|
|
112
|
+
/**
|
|
113
|
+
* Sets the global user and automatically syncs the Tenant ID.
|
|
114
|
+
* @param user - The SecurityUser object or null to clear.
|
|
115
|
+
*/
|
|
116
|
+
setUser(user: SecurityUser | null): this;
|
|
117
|
+
static generateToken: (raw: string) => string;
|
|
118
|
+
/**
|
|
119
|
+
* FIRESTOREDB: logout/clear context
|
|
120
|
+
* Wipes all identity and tenant data to prevent stale writes.
|
|
121
|
+
*/
|
|
122
|
+
clearUser(): void;
|
|
112
123
|
/**
|
|
113
124
|
* Public UI Helper: Check permission without executing
|
|
114
125
|
* Usage: <button disabled={!Users.can('create')}>Add User</button>
|
|
@@ -131,6 +142,10 @@ export declare class FirestoreDB<T> {
|
|
|
131
142
|
/**
|
|
132
143
|
* PRIVATE: Helper to stamp tenant info on new data
|
|
133
144
|
*/
|
|
134
|
-
|
|
145
|
+
/**
|
|
146
|
+
* THE MASTER STAMPING PIPE
|
|
147
|
+
* Processes raw entity through all enabled security and metadata layers.
|
|
148
|
+
*/
|
|
149
|
+
private _runStampingPipe;
|
|
135
150
|
}
|
|
136
151
|
//# sourceMappingURL=FirestoreDB.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FirestoreDB.d.ts","sourceRoot":"","sources":["../../src/FirestoreDB.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAmB,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAClG,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAkB,cAAc,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"FirestoreDB.d.ts","sourceRoot":"","sources":["../../src/FirestoreDB.ts"],"names":[],"mappings":"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"}
|
package/dist/cjs/FirestoreDB.js
CHANGED
|
@@ -8,6 +8,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
12
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
13
|
+
var m = o[Symbol.asyncIterator], i;
|
|
14
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
15
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
16
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
17
|
+
};
|
|
11
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
19
|
exports.FirestoreDB = void 0;
|
|
13
20
|
const FirestoreQuery_1 = require("./FirestoreQuery");
|
|
@@ -18,12 +25,15 @@ class FirestoreDB {
|
|
|
18
25
|
* @param db: Firebase
|
|
19
26
|
* @param collection string
|
|
20
27
|
*/
|
|
21
|
-
constructor(_db, _collectionName, _sdk, _options = {}) {
|
|
28
|
+
constructor(_db, _collectionName, _sdk, _options = {}, user) {
|
|
22
29
|
var _a, _b, _c;
|
|
23
30
|
this._db = _db;
|
|
24
31
|
this._collectionName = _collectionName;
|
|
25
32
|
this._sdk = _sdk;
|
|
26
33
|
this._options = _options;
|
|
34
|
+
this._userToken = null;
|
|
35
|
+
this._activeTenantId = null;
|
|
36
|
+
this._currentUser = null;
|
|
27
37
|
/**
|
|
28
38
|
* FIRESTOREDB: findOne({ age: '13' }); or findOne('id_123');
|
|
29
39
|
*/
|
|
@@ -79,20 +89,20 @@ class FirestoreDB {
|
|
|
79
89
|
* Basic implementation. For production, you'd expand the 'filter' to handle where clauses.
|
|
80
90
|
*/
|
|
81
91
|
this.find = (filter = {}) => {
|
|
82
|
-
this._checkPermission('read');
|
|
83
92
|
return new FirestoreQuery_1.FirestoreQuery(this._db, this._collectionName, this._collectionRef, filter, this._sdk, this._buildConstraints.bind(this), //Pass the private helper
|
|
84
93
|
this.countDocuments.bind(this), // pass the count helper
|
|
85
|
-
this._isSoftDeleteEnabled);
|
|
94
|
+
this._isSoftDeleteEnabled, this._checkPermission.bind(this));
|
|
86
95
|
};
|
|
87
96
|
/**
|
|
88
97
|
* FIRESTOREDB: insertOne(doc)
|
|
89
98
|
* Optimized: Uses set with merge or create
|
|
90
99
|
*/
|
|
91
100
|
this.insertOne = (entity) => __awaiter(this, void 0, void 0, function* () {
|
|
92
|
-
this._checkPermission('create', null, entity)
|
|
101
|
+
if (!this._checkPermission('create', null, entity))
|
|
102
|
+
return null;
|
|
93
103
|
const docRef = this._getDocRef(entity._id);
|
|
94
104
|
// Using 'set' with { merge: false } acts like an insert/overwrite
|
|
95
|
-
yield this._sdk.setDoc(docRef, this.
|
|
105
|
+
yield this._sdk.setDoc(docRef, this._runStampingPipe(Object.assign(Object.assign({}, entity), { _id: docRef.id }), false));
|
|
96
106
|
// 2. TRIGGER INVALIDATION: Any cached 'find' results for this
|
|
97
107
|
// collection are now potentially stale.
|
|
98
108
|
this._invalidateCache();
|
|
@@ -118,8 +128,7 @@ class FirestoreDB {
|
|
|
118
128
|
// 1. Client-side security check (if enabled)
|
|
119
129
|
this._checkPermission('create', null, entity);
|
|
120
130
|
const docRef = this._getDocRef(entity._id);
|
|
121
|
-
const finalDoc = this.
|
|
122
|
-
}));
|
|
131
|
+
const finalDoc = this._runStampingPipe(Object.assign(Object.assign({}, entity), { _id: docRef.id }), false);
|
|
123
132
|
// Add operation to the current batch
|
|
124
133
|
batch.set(docRef, finalDoc);
|
|
125
134
|
// Track the processed doc to return to the user
|
|
@@ -183,6 +192,7 @@ class FirestoreDB {
|
|
|
183
192
|
* Optimized: Chunks updates into batches of 500 to handle large datasets.
|
|
184
193
|
*/
|
|
185
194
|
this.updateMany = (updates_1, ...args_1) => __awaiter(this, [updates_1, ...args_1], void 0, function* (updates, options = { upsert: false }) {
|
|
195
|
+
var _a, e_1, _b, _c;
|
|
186
196
|
const CHUNK_SIZE = 500;
|
|
187
197
|
const batchPromises = [];
|
|
188
198
|
const results = [];
|
|
@@ -190,28 +200,50 @@ class FirestoreDB {
|
|
|
190
200
|
for (let i = 0; i < updates.length; i += CHUNK_SIZE) {
|
|
191
201
|
const batch = this._sdk.writeBatch(this._db);
|
|
192
202
|
const chunk = updates.slice(i, i + CHUNK_SIZE);
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
//
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
203
|
+
try {
|
|
204
|
+
for (var _d = true, chunk_1 = (e_1 = void 0, __asyncValues(chunk)), chunk_1_1; chunk_1_1 = yield chunk_1.next(), _a = chunk_1_1.done, !_a; _d = true) {
|
|
205
|
+
_c = chunk_1_1.value;
|
|
206
|
+
_d = false;
|
|
207
|
+
let item = _c;
|
|
208
|
+
const { docId, entity } = item;
|
|
209
|
+
const docRef = this._getDocRef(docId);
|
|
210
|
+
// Inject updatedAt into the update payload
|
|
211
|
+
let updateData = this._runStampingPipe(Object.assign({}, entity), true);
|
|
212
|
+
if (options.upsert) {
|
|
213
|
+
// UPSERT: Create if missing, merge if exists
|
|
214
|
+
// We ensure _id is included in the document for consistency
|
|
215
|
+
// For upserts, we also need to ensure createdAt is set if the doc is new
|
|
216
|
+
// Firestore's 'set' with merge doesn't know if it's new, so we
|
|
217
|
+
// usually set createdAt only on first creation via a different method
|
|
218
|
+
if (!this.exists({ _id: docRef.id })) {
|
|
219
|
+
console.log("Document: not found on update insert is true therefore we will create a new doc : ");
|
|
220
|
+
if (!this._checkPermission('create'))
|
|
221
|
+
continue;
|
|
222
|
+
updateData = this._runStampingPipe({ updateData }, false);
|
|
223
|
+
}
|
|
224
|
+
batch.set(docRef, updateData, { merge: true });
|
|
225
|
+
// Set the Id of the object so the consumer knows which id was affected
|
|
226
|
+
results.push(docRef.id);
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
// STRICT UPDATE: Fails if document doesn't exist (Standard Mongo)
|
|
230
|
+
const checkDoc = yield this.findOne({ _id: docRef.id });
|
|
231
|
+
if (!this._checkPermission('update', checkDoc, item))
|
|
232
|
+
continue;
|
|
233
|
+
updateData = this._runStampingPipe({ updateData }, true);
|
|
234
|
+
batch.update(docRef, updateData);
|
|
235
|
+
results.push(docRef.id);
|
|
236
|
+
}
|
|
209
237
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
238
|
+
}
|
|
239
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
240
|
+
finally {
|
|
241
|
+
try {
|
|
242
|
+
if (!_d && !_a && (_b = chunk_1.return)) yield _b.call(chunk_1);
|
|
213
243
|
}
|
|
214
|
-
|
|
244
|
+
finally { if (e_1) throw e_1.error; }
|
|
245
|
+
}
|
|
246
|
+
;
|
|
215
247
|
// Queue the batch commit
|
|
216
248
|
batchPromises.push(batch.commit());
|
|
217
249
|
}
|
|
@@ -220,8 +252,11 @@ class FirestoreDB {
|
|
|
220
252
|
this._invalidateCache();
|
|
221
253
|
// Run all batches in parallel
|
|
222
254
|
try {
|
|
223
|
-
|
|
224
|
-
|
|
255
|
+
if (batchPromises.length > 0) {
|
|
256
|
+
yield Promise.all(batchPromises);
|
|
257
|
+
return results;
|
|
258
|
+
}
|
|
259
|
+
return [];
|
|
225
260
|
}
|
|
226
261
|
catch (error) {
|
|
227
262
|
console.error("FirestoreDB::updateMany: Error during batched update", error);
|
|
@@ -360,8 +395,8 @@ class FirestoreDB {
|
|
|
360
395
|
}
|
|
361
396
|
this._collectionRef = this._sdk.collection(this._db, this._collectionName);
|
|
362
397
|
this._isSoftDeleteEnabled = (_a = this._options.softDelete) !== null && _a !== void 0 ? _a : false;
|
|
363
|
-
this._security = this._options.security;
|
|
364
398
|
this._tenantField = this._tenantField = ((_c = (_b = this._options) === null || _b === void 0 ? void 0 : _b.tenant) === null || _c === void 0 ? void 0 : _c.field) || 'orgId';
|
|
399
|
+
this.setUser(user || null);
|
|
365
400
|
}
|
|
366
401
|
catch (error) {
|
|
367
402
|
throw new Error(`error on init @collection: ${this._collectionName} - ` + error.message);
|
|
@@ -412,6 +447,35 @@ class FirestoreDB {
|
|
|
412
447
|
console.error("FirestoreDB::watch:Error: ", err);
|
|
413
448
|
});
|
|
414
449
|
}
|
|
450
|
+
// ****************************** Security Rules ***********************************************//
|
|
451
|
+
/**
|
|
452
|
+
* Sets the global user and automatically syncs the Tenant ID.
|
|
453
|
+
* @param user - The SecurityUser object or null to clear.
|
|
454
|
+
*/
|
|
455
|
+
setUser(user) {
|
|
456
|
+
if (!user) {
|
|
457
|
+
this.clearUser();
|
|
458
|
+
return this;
|
|
459
|
+
}
|
|
460
|
+
this._currentUser = user;
|
|
461
|
+
// 1. Auto-Sync: User's orgId becomes the active Tenant ID
|
|
462
|
+
this._activeTenantId = user.orgId;
|
|
463
|
+
// 2. Generate Deterministic Token: b64(uid:orgId)
|
|
464
|
+
const raw = `${user.uid}:${user.orgId}`;
|
|
465
|
+
this._userToken = FirestoreDB.generateToken(raw);
|
|
466
|
+
return this;
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* FIRESTOREDB: logout/clear context
|
|
470
|
+
* Wipes all identity and tenant data to prevent stale writes.
|
|
471
|
+
*/
|
|
472
|
+
clearUser() {
|
|
473
|
+
this._currentUser = null;
|
|
474
|
+
this._userToken = null;
|
|
475
|
+
this._activeTenantId = null;
|
|
476
|
+
// Optional: Log for debugging in dev environments
|
|
477
|
+
console.debug(`[FirestoreDB] Context cleared for collection: ${this._collectionName}`);
|
|
478
|
+
}
|
|
415
479
|
/**
|
|
416
480
|
* Public UI Helper: Check permission without executing
|
|
417
481
|
* Usage: <button disabled={!Users.can('create')}>Add User</button>
|
|
@@ -424,7 +488,8 @@ class FirestoreDB {
|
|
|
424
488
|
return false;
|
|
425
489
|
}
|
|
426
490
|
}
|
|
427
|
-
//
|
|
491
|
+
// ****************************** End of Security Rules ***********************************************//
|
|
492
|
+
// ****************************** PRIVATE METHODS ***********************************************//
|
|
428
493
|
_buildConstraints(filter) {
|
|
429
494
|
var _a;
|
|
430
495
|
// Inject Tenant ID (Mandatory Filter)
|
|
@@ -451,22 +516,55 @@ class FirestoreDB {
|
|
|
451
516
|
_checkPermission(action, doc, newData) {
|
|
452
517
|
if (!this._options.security)
|
|
453
518
|
return true; // Security not enabled
|
|
454
|
-
const {
|
|
519
|
+
const { rules, silent, onError } = this._options.security;
|
|
455
520
|
const rule = rules[action];
|
|
456
|
-
if (rule && !rule(
|
|
457
|
-
|
|
521
|
+
if (rule && !rule(this._currentUser, doc, newData)) {
|
|
522
|
+
const err = new Error(`Security Error: User does not have ${action} permission on ${this._collectionName}`);
|
|
523
|
+
// 1. Always trigger the global error hook if it exists (for toasts/logging)
|
|
524
|
+
if (onError)
|
|
525
|
+
onError(err);
|
|
526
|
+
// 2. Decide whether to "Hard Throw" or "Silent Fail"
|
|
527
|
+
if (silent)
|
|
528
|
+
return false;
|
|
529
|
+
throw err;
|
|
458
530
|
}
|
|
459
531
|
return true;
|
|
460
532
|
}
|
|
461
533
|
/**
|
|
462
534
|
* PRIVATE: Helper to stamp tenant info on new data
|
|
463
535
|
*/
|
|
464
|
-
|
|
536
|
+
/**
|
|
537
|
+
* THE MASTER STAMPING PIPE
|
|
538
|
+
* Processes raw entity through all enabled security and metadata layers.
|
|
539
|
+
*/
|
|
540
|
+
_runStampingPipe(entity, isUpdate = false) {
|
|
465
541
|
var _a;
|
|
466
|
-
|
|
467
|
-
|
|
542
|
+
const pipe = [];
|
|
543
|
+
// 1. Identity/Security Token Stamp (Hash of UID:OrgId)
|
|
544
|
+
if (this._userToken) {
|
|
545
|
+
pipe.push((data) => {
|
|
546
|
+
var _a, _b;
|
|
547
|
+
return (Object.assign(Object.assign({}, data), { _userToken: this._userToken, _createdBy: isUpdate && data._createdBy ? data._createdBy : (((_a = this._currentUser) === null || _a === void 0 ? void 0 : _a.uid) || 'system'), _updatedBy: ((_b = this._currentUser) === null || _b === void 0 ? void 0 : _b.uid) || 'system' }));
|
|
548
|
+
});
|
|
468
549
|
}
|
|
469
|
-
|
|
550
|
+
// 2. Multi-Tenancy Stamp
|
|
551
|
+
if (((_a = this._options.tenant) === null || _a === void 0 ? void 0 : _a.enabled) && this._activeTenantId) {
|
|
552
|
+
const field = this._options.tenant.field || 'orgId';
|
|
553
|
+
pipe.push((data) => (Object.assign(Object.assign({}, data), { [field]: this._activeTenantId })));
|
|
554
|
+
}
|
|
555
|
+
// 3. Timestamps (Firestore Server Side)
|
|
556
|
+
pipe.push((data) => (Object.assign(Object.assign(Object.assign({}, data), (isUpdate ? {} : { createdAt: this._sdk.serverTimestamp() })), { updatedAt: this._sdk.serverTimestamp() })));
|
|
557
|
+
// handle a stamp for isDeleted on all documents if this field is not present
|
|
558
|
+
pipe.push((data) => {
|
|
559
|
+
if (!Object.keys(data).includes('isDeleted'))
|
|
560
|
+
return Object.assign(Object.assign({}, data), { isDeleted: false });
|
|
561
|
+
return Object.assign({}, data);
|
|
562
|
+
});
|
|
563
|
+
// Execute the pipe: reducer patterns are perfect for this
|
|
564
|
+
return pipe.reduce((processedData, stampFn) => stampFn(processedData), entity);
|
|
470
565
|
}
|
|
471
566
|
}
|
|
472
567
|
exports.FirestoreDB = FirestoreDB;
|
|
568
|
+
FirestoreDB.generateToken = (raw) => typeof btoa !== 'undefined'
|
|
569
|
+
? btoa(raw)
|
|
570
|
+
: Buffer.from(raw).toString('base64');
|
|
@@ -18,6 +18,7 @@ export declare class FirestoreQuery<T> {
|
|
|
18
18
|
private _sdk;
|
|
19
19
|
private buildConstraints;
|
|
20
20
|
private countDocs;
|
|
21
|
+
private _checkPermission;
|
|
21
22
|
static _globalCache: LRUCache;
|
|
22
23
|
private _useCache;
|
|
23
24
|
private _ttl;
|
|
@@ -27,7 +28,7 @@ export declare class FirestoreQuery<T> {
|
|
|
27
28
|
private _sort;
|
|
28
29
|
private _cursorId?;
|
|
29
30
|
private _cursorType;
|
|
30
|
-
constructor(db: any, collectionName: string, collectionRef: any, filter: Record<string, any>, _sdk: FirestoreSDK, buildConstraints: (f: any) => QueryConstraint[], countDocs: (f: any) => Promise<number>, isSoftDeleteEnabled: boolean);
|
|
31
|
+
constructor(db: any, collectionName: string, collectionRef: any, filter: Record<string, any>, _sdk: FirestoreSDK, buildConstraints: (f: any) => QueryConstraint[], countDocs: (f: any) => Promise<number>, isSoftDeleteEnabled: boolean, _checkPermission: (action: 'read' | 'create' | 'update' | 'delete', doc?: any, newData?: any) => boolean);
|
|
31
32
|
/** Enables result caching for this query */
|
|
32
33
|
cache(ttlMs?: number): this;
|
|
33
34
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FirestoreQuery.d.ts","sourceRoot":"","sources":["../../src/FirestoreQuery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAGzD,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE1D,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,CAAA;AAC3C,MAAM,WAAW,kBAAkB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACxB;AAED,qBAAa,cAAc,CAAC,CAAC;IAgBrB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,gBAAgB;IACxB,OAAO,CAAC,SAAS;
|
|
1
|
+
{"version":3,"file":"FirestoreQuery.d.ts","sourceRoot":"","sources":["../../src/FirestoreQuery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAGzD,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE1D,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,CAAA;AAC3C,MAAM,WAAW,kBAAkB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACxB;AAED,qBAAa,cAAc,CAAC,CAAC;IAgBrB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,gBAAgB;IACxB,OAAO,CAAC,SAAS;IAEjB,OAAO,CAAC,gBAAgB;IArB5B,OAAc,YAAY,WAAkB;IAC5C,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,IAAI,CAAiB;IAC7B,OAAO,CAAC,WAAW,CAAa;IAGhC,OAAO,CAAC,WAAW,CAAuC;IAC1D,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,KAAK,CAAsC;IACnD,OAAO,CAAC,SAAS,CAAC,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAmC;gBAG1C,EAAE,EAAE,GAAG,EACP,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,GAAG,EAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,IAAI,EAAE,YAAY,EAClB,gBAAgB,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,eAAe,EAAE,EAC/C,SAAS,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC,MAAM,CAAC,EAC9C,mBAAmB,EAAE,OAAO,EACpB,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG,KAAG,OAAO;IAKlH,4CAA4C;IAC5C,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM;IAMpB;;OAEG;IACH,IAAI,CAAC,CAAC,EAAE,MAAM;IAKP,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC;IAK7C,KAAK,CAAC,CAAC,EAAE,MAAM;IAKtB,4BAA4B;IACrB,KAAK,CAAC,EAAE,EAAE,MAAM;IAMvB,gCAAgC;IACzB,MAAM,CAAC,EAAE,EAAE,MAAM;IAMxB;;;OAGG;IACH,WAAW;IAKX,WAAW;IAEX,uCAAuC;IAC1B,OAAO,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC;IActD;;;;;;;;;;;;;;;;;OAiBG;IACU,QAAQ,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC;QAAC,QAAQ,EAAE,kBAAkB,CAAA;KAAE,CAAC;IAuCxF,MAAM,IAAI,cAAc,CAAC,CAAC,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAkBpD;;;;;;;;;;OAUG;IACU,MAAM,IAAI,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YAapC,mBAAmB;IAsCjC,OAAO,CAAC,iBAAiB;IAezB;;GAED;IACC,OAAO,CAAC,eAAe;CAQ1B"}
|
|
@@ -15,7 +15,7 @@ const Hasher_1 = require("./utils/Hasher");
|
|
|
15
15
|
const utils_2 = require("./utils");
|
|
16
16
|
const FirestoreCursor_1 = require("./utils/FirestoreCursor");
|
|
17
17
|
class FirestoreQuery {
|
|
18
|
-
constructor(db, collectionName, collectionRef, filter, _sdk, buildConstraints, countDocs, isSoftDeleteEnabled) {
|
|
18
|
+
constructor(db, collectionName, collectionRef, filter, _sdk, buildConstraints, countDocs, isSoftDeleteEnabled, _checkPermission) {
|
|
19
19
|
this.db = db;
|
|
20
20
|
this.collectionName = collectionName;
|
|
21
21
|
this.collectionRef = collectionRef;
|
|
@@ -23,6 +23,7 @@ class FirestoreQuery {
|
|
|
23
23
|
this._sdk = _sdk;
|
|
24
24
|
this.buildConstraints = buildConstraints;
|
|
25
25
|
this.countDocs = countDocs;
|
|
26
|
+
this._checkPermission = _checkPermission;
|
|
26
27
|
this._useCache = false;
|
|
27
28
|
this._ttl = 60000; // Default 1 minute
|
|
28
29
|
this._pageNumber = 1; // Default to first page
|
|
@@ -78,6 +79,9 @@ class FirestoreQuery {
|
|
|
78
79
|
/** Simple execution (Returns Array) */
|
|
79
80
|
execute() {
|
|
80
81
|
return __awaiter(this, void 0, void 0, function* () {
|
|
82
|
+
// If security fails and we are in silent mode, return empty array
|
|
83
|
+
if (!this._checkPermission('read'))
|
|
84
|
+
return [];
|
|
81
85
|
let finalConstraints = yield this._prepareConstraints();
|
|
82
86
|
const q = this._sdk.query(this.collectionRef, ...finalConstraints);
|
|
83
87
|
const snapshot = yield this._sdk.getDocs(q);
|
package/dist/cjs/types.d.ts
CHANGED
|
@@ -23,14 +23,25 @@ export interface TenantOptions {
|
|
|
23
23
|
id: string | number;
|
|
24
24
|
field?: string;
|
|
25
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Internal Type for a Stamping Function
|
|
28
|
+
*/
|
|
29
|
+
export type StamperFn = (data: any) => any;
|
|
30
|
+
export interface SecurityUser {
|
|
31
|
+
uid: string;
|
|
32
|
+
orgId: string;
|
|
33
|
+
role: string;
|
|
34
|
+
[key: string]: any;
|
|
35
|
+
}
|
|
26
36
|
export interface SecurityPolicy {
|
|
27
|
-
user: any;
|
|
28
37
|
rules: {
|
|
29
38
|
read?: (user: any, doc?: any) => boolean;
|
|
30
39
|
create?: (user: any, data?: any) => boolean;
|
|
31
40
|
update?: (user: any, doc: any, newData?: any) => boolean;
|
|
32
41
|
delete?: (user: any, doc: any) => boolean;
|
|
33
42
|
};
|
|
43
|
+
silent?: boolean;
|
|
44
|
+
onError?: (err: Error) => void;
|
|
34
45
|
}
|
|
35
46
|
export type WithSystemFields<T> = T & FirestoreDBDocument;
|
|
36
47
|
export interface DBOptions {
|
|
@@ -43,9 +54,9 @@ export interface DBOptions {
|
|
|
43
54
|
*/
|
|
44
55
|
export interface FirestoreSDK {
|
|
45
56
|
collection: (db: Firestore, path: string) => CollectionReference;
|
|
46
|
-
doc: (dbOrRef: Firestore | CollectionReference, ...
|
|
47
|
-
getDoc: (ref: DocumentReference) => Promise<DocumentSnapshot
|
|
48
|
-
getDocs: (query: Query) => Promise<QuerySnapshot<unknown, DocumentData>>;
|
|
57
|
+
doc: (dbOrRef: Firestore | CollectionReference<DocumentData, DocumentData>, path?: string, ...pathSegments: string[]) => DocumentReference<DocumentData, DocumentData>;
|
|
58
|
+
getDoc: (ref: DocumentReference<DocumentData, DocumentData>) => Promise<DocumentSnapshot<DocumentData, DocumentData>>;
|
|
59
|
+
getDocs: (query: Query<DocumentData, DocumentData>) => Promise<QuerySnapshot<unknown, DocumentData>>;
|
|
49
60
|
setDoc: (ref: DocumentReference, data: any, options?: any) => Promise<void>;
|
|
50
61
|
updateDoc: (ref: DocumentReference, data: any) => Promise<void>;
|
|
51
62
|
deleteDoc: (ref: DocumentReference) => Promise<void>;
|
package/dist/cjs/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,SAAS,EAAE,mBAAmB,EAAE,iBAAiB,EACjD,eAAe,EAAE,UAAU,EAAE,KAAK,EAAE,gBAAgB,EACpD,YAAY,EACZ,cAAc,EACd,WAAW,EACX,SAAS,EACT,cAAc,EACd,aAAa,EACb,sBAAsB,EACtB,qBAAqB,EACrB,aAAa,EACb,WAAW,EACX,kBAAkB,EACrB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAC5D;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;KACxB,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG;CACvB,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAGxB,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;CACrB,CAAA;AAID,KAAK,mBAAmB,GAAG;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,IAAI,CAAA;IACf,SAAS,EAAE,IAAI,CAAA;IACf,SAAS,CAAC,EAAE,IAAI,CAAA;CACnB,CAAA;AAED,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,5 +6,5 @@ import { DBOptions, FirestoreSDK } from "../types";
|
|
|
6
6
|
*
|
|
7
7
|
* @returns Returns a generator function to create collection-specific instances.
|
|
8
8
|
*/
|
|
9
|
-
export declare const createFirestoreDB: (db: Firestore, sdk: FirestoreSDK, FirestoreOptions?: DBOptions) => (collectionName: string, options?: DBOptions) => FirestoreDB<
|
|
9
|
+
export declare const createFirestoreDB: (db: Firestore, sdk: FirestoreSDK, FirestoreOptions?: DBOptions) => <T>(collectionName: string, options?: DBOptions) => FirestoreDB<T>;
|
|
10
10
|
//# sourceMappingURL=createFirestoreDB.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createFirestoreDB.d.ts","sourceRoot":"","sources":["../../../src/utils/createFirestoreDB.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEnD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,IAAI,SAAS,EAAE,KAAK,YAAY,EAAE,mBAAkB,SAAc,MAMxF,gBAAgB,MAAM,EAAE,UAAS,
|
|
1
|
+
{"version":3,"file":"createFirestoreDB.d.ts","sourceRoot":"","sources":["../../../src/utils/createFirestoreDB.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEnD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,IAAI,SAAS,EAAE,KAAK,YAAY,EAAE,mBAAkB,SAAc,MAMxF,CAAC,EAAE,gBAAgB,MAAM,EAAE,UAAS,SAAc,mBAG7D,CAAC"}
|
|
@@ -12,8 +12,8 @@ const createFirestoreDB = (db, sdk, FirestoreOptions = {}) => {
|
|
|
12
12
|
* @param collectionName - The name of the Firestore collection
|
|
13
13
|
* @param options - Optional: { softDelete: true }
|
|
14
14
|
*/
|
|
15
|
-
return (collectionName, options =
|
|
16
|
-
return new FirestoreDB_1.FirestoreDB(db, collectionName, sdk, options);
|
|
15
|
+
return (collectionName, options = {}) => {
|
|
16
|
+
return new FirestoreDB_1.FirestoreDB(db, collectionName, sdk, Object.assign(options, FirestoreOptions));
|
|
17
17
|
};
|
|
18
18
|
};
|
|
19
19
|
exports.createFirestoreDB = createFirestoreDB;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Firestore, FirestoreError, Unsubscribe } from 'firebase/firestore';
|
|
2
2
|
import { FirestoreQuery } from './FirestoreQuery';
|
|
3
|
-
import { DBOptions, DocumentInput, FirestoreSDK, QueryFilter, UpdateDocument, WithSystemFields } from './types';
|
|
3
|
+
import { DBOptions, DocumentInput, FirestoreSDK, QueryFilter, SecurityUser, UpdateDocument, WithSystemFields } from './types';
|
|
4
4
|
export declare class FirestoreDB<T> {
|
|
5
5
|
private _db;
|
|
6
6
|
private _collectionName;
|
|
@@ -8,14 +8,16 @@ export declare class FirestoreDB<T> {
|
|
|
8
8
|
private _options;
|
|
9
9
|
private _collectionRef;
|
|
10
10
|
private _isSoftDeleteEnabled;
|
|
11
|
-
private _security?;
|
|
12
11
|
private _tenantField;
|
|
12
|
+
private _userToken;
|
|
13
|
+
private _activeTenantId;
|
|
14
|
+
private _currentUser;
|
|
13
15
|
/**
|
|
14
16
|
* Initialize with Firebase DB and targeted collection Name
|
|
15
17
|
* @param db: Firebase
|
|
16
18
|
* @param collection string
|
|
17
19
|
*/
|
|
18
|
-
constructor(_db: Firestore, _collectionName: string, _sdk: FirestoreSDK, _options?: DBOptions);
|
|
20
|
+
constructor(_db: Firestore, _collectionName: string, _sdk: FirestoreSDK, _options?: DBOptions, user?: SecurityUser);
|
|
19
21
|
/**
|
|
20
22
|
* FIRESTOREDB: findOne({ age: '13' }); or findOne('id_123');
|
|
21
23
|
*/
|
|
@@ -38,7 +40,7 @@ export declare class FirestoreDB<T> {
|
|
|
38
40
|
*/
|
|
39
41
|
insertOne: (entity: Partial<T & {
|
|
40
42
|
_id?: string;
|
|
41
|
-
}>) => Promise<WithSystemFields<T
|
|
43
|
+
}>) => Promise<WithSystemFields<T> | null>;
|
|
42
44
|
/**
|
|
43
45
|
* FIRESTOREDB: insertMany(docs) - Uses Firestore Batched Writes (Limit 500 per batch)
|
|
44
46
|
*
|
|
@@ -57,9 +59,7 @@ export declare class FirestoreDB<T> {
|
|
|
57
59
|
*/
|
|
58
60
|
updateMany: <T_1>(updates: UpdateDocument<T_1>[], options?: {
|
|
59
61
|
upsert?: boolean;
|
|
60
|
-
}) => Promise<
|
|
61
|
-
_id: string;
|
|
62
|
-
}[]>;
|
|
62
|
+
}) => Promise<string[]>;
|
|
63
63
|
/**
|
|
64
64
|
* FIRESTOREDB: deleteOne('id_123')
|
|
65
65
|
*/
|
|
@@ -109,6 +109,17 @@ export declare class FirestoreDB<T> {
|
|
|
109
109
|
$count?: boolean;
|
|
110
110
|
};
|
|
111
111
|
}) => Promise<import("@firebase/firestore").AggregateSpecData<any>>;
|
|
112
|
+
/**
|
|
113
|
+
* Sets the global user and automatically syncs the Tenant ID.
|
|
114
|
+
* @param user - The SecurityUser object or null to clear.
|
|
115
|
+
*/
|
|
116
|
+
setUser(user: SecurityUser | null): this;
|
|
117
|
+
static generateToken: (raw: string) => string;
|
|
118
|
+
/**
|
|
119
|
+
* FIRESTOREDB: logout/clear context
|
|
120
|
+
* Wipes all identity and tenant data to prevent stale writes.
|
|
121
|
+
*/
|
|
122
|
+
clearUser(): void;
|
|
112
123
|
/**
|
|
113
124
|
* Public UI Helper: Check permission without executing
|
|
114
125
|
* Usage: <button disabled={!Users.can('create')}>Add User</button>
|
|
@@ -131,6 +142,10 @@ export declare class FirestoreDB<T> {
|
|
|
131
142
|
/**
|
|
132
143
|
* PRIVATE: Helper to stamp tenant info on new data
|
|
133
144
|
*/
|
|
134
|
-
|
|
145
|
+
/**
|
|
146
|
+
* THE MASTER STAMPING PIPE
|
|
147
|
+
* Processes raw entity through all enabled security and metadata layers.
|
|
148
|
+
*/
|
|
149
|
+
private _runStampingPipe;
|
|
135
150
|
}
|
|
136
151
|
//# sourceMappingURL=FirestoreDB.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FirestoreDB.d.ts","sourceRoot":"","sources":["../../src/FirestoreDB.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAmB,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAClG,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAkB,cAAc,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"FirestoreDB.d.ts","sourceRoot":"","sources":["../../src/FirestoreDB.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/FirestoreDB.js
CHANGED
|
@@ -8,6 +8,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
12
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
13
|
+
var m = o[Symbol.asyncIterator], i;
|
|
14
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
15
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
16
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
17
|
+
};
|
|
11
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
19
|
exports.FirestoreDB = void 0;
|
|
13
20
|
const FirestoreQuery_1 = require("./FirestoreQuery");
|
|
@@ -18,12 +25,15 @@ class FirestoreDB {
|
|
|
18
25
|
* @param db: Firebase
|
|
19
26
|
* @param collection string
|
|
20
27
|
*/
|
|
21
|
-
constructor(_db, _collectionName, _sdk, _options = {}) {
|
|
28
|
+
constructor(_db, _collectionName, _sdk, _options = {}, user) {
|
|
22
29
|
var _a, _b, _c;
|
|
23
30
|
this._db = _db;
|
|
24
31
|
this._collectionName = _collectionName;
|
|
25
32
|
this._sdk = _sdk;
|
|
26
33
|
this._options = _options;
|
|
34
|
+
this._userToken = null;
|
|
35
|
+
this._activeTenantId = null;
|
|
36
|
+
this._currentUser = null;
|
|
27
37
|
/**
|
|
28
38
|
* FIRESTOREDB: findOne({ age: '13' }); or findOne('id_123');
|
|
29
39
|
*/
|
|
@@ -79,20 +89,20 @@ class FirestoreDB {
|
|
|
79
89
|
* Basic implementation. For production, you'd expand the 'filter' to handle where clauses.
|
|
80
90
|
*/
|
|
81
91
|
this.find = (filter = {}) => {
|
|
82
|
-
this._checkPermission('read');
|
|
83
92
|
return new FirestoreQuery_1.FirestoreQuery(this._db, this._collectionName, this._collectionRef, filter, this._sdk, this._buildConstraints.bind(this), //Pass the private helper
|
|
84
93
|
this.countDocuments.bind(this), // pass the count helper
|
|
85
|
-
this._isSoftDeleteEnabled);
|
|
94
|
+
this._isSoftDeleteEnabled, this._checkPermission.bind(this));
|
|
86
95
|
};
|
|
87
96
|
/**
|
|
88
97
|
* FIRESTOREDB: insertOne(doc)
|
|
89
98
|
* Optimized: Uses set with merge or create
|
|
90
99
|
*/
|
|
91
100
|
this.insertOne = (entity) => __awaiter(this, void 0, void 0, function* () {
|
|
92
|
-
this._checkPermission('create', null, entity)
|
|
101
|
+
if (!this._checkPermission('create', null, entity))
|
|
102
|
+
return null;
|
|
93
103
|
const docRef = this._getDocRef(entity._id);
|
|
94
104
|
// Using 'set' with { merge: false } acts like an insert/overwrite
|
|
95
|
-
yield this._sdk.setDoc(docRef, this.
|
|
105
|
+
yield this._sdk.setDoc(docRef, this._runStampingPipe(Object.assign(Object.assign({}, entity), { _id: docRef.id }), false));
|
|
96
106
|
// 2. TRIGGER INVALIDATION: Any cached 'find' results for this
|
|
97
107
|
// collection are now potentially stale.
|
|
98
108
|
this._invalidateCache();
|
|
@@ -118,8 +128,7 @@ class FirestoreDB {
|
|
|
118
128
|
// 1. Client-side security check (if enabled)
|
|
119
129
|
this._checkPermission('create', null, entity);
|
|
120
130
|
const docRef = this._getDocRef(entity._id);
|
|
121
|
-
const finalDoc = this.
|
|
122
|
-
}));
|
|
131
|
+
const finalDoc = this._runStampingPipe(Object.assign(Object.assign({}, entity), { _id: docRef.id }), false);
|
|
123
132
|
// Add operation to the current batch
|
|
124
133
|
batch.set(docRef, finalDoc);
|
|
125
134
|
// Track the processed doc to return to the user
|
|
@@ -183,6 +192,7 @@ class FirestoreDB {
|
|
|
183
192
|
* Optimized: Chunks updates into batches of 500 to handle large datasets.
|
|
184
193
|
*/
|
|
185
194
|
this.updateMany = (updates_1, ...args_1) => __awaiter(this, [updates_1, ...args_1], void 0, function* (updates, options = { upsert: false }) {
|
|
195
|
+
var _a, e_1, _b, _c;
|
|
186
196
|
const CHUNK_SIZE = 500;
|
|
187
197
|
const batchPromises = [];
|
|
188
198
|
const results = [];
|
|
@@ -190,28 +200,50 @@ class FirestoreDB {
|
|
|
190
200
|
for (let i = 0; i < updates.length; i += CHUNK_SIZE) {
|
|
191
201
|
const batch = this._sdk.writeBatch(this._db);
|
|
192
202
|
const chunk = updates.slice(i, i + CHUNK_SIZE);
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
//
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
203
|
+
try {
|
|
204
|
+
for (var _d = true, chunk_1 = (e_1 = void 0, __asyncValues(chunk)), chunk_1_1; chunk_1_1 = yield chunk_1.next(), _a = chunk_1_1.done, !_a; _d = true) {
|
|
205
|
+
_c = chunk_1_1.value;
|
|
206
|
+
_d = false;
|
|
207
|
+
let item = _c;
|
|
208
|
+
const { docId, entity } = item;
|
|
209
|
+
const docRef = this._getDocRef(docId);
|
|
210
|
+
// Inject updatedAt into the update payload
|
|
211
|
+
let updateData = this._runStampingPipe(Object.assign({}, entity), true);
|
|
212
|
+
if (options.upsert) {
|
|
213
|
+
// UPSERT: Create if missing, merge if exists
|
|
214
|
+
// We ensure _id is included in the document for consistency
|
|
215
|
+
// For upserts, we also need to ensure createdAt is set if the doc is new
|
|
216
|
+
// Firestore's 'set' with merge doesn't know if it's new, so we
|
|
217
|
+
// usually set createdAt only on first creation via a different method
|
|
218
|
+
if (!this.exists({ _id: docRef.id })) {
|
|
219
|
+
console.log("Document: not found on update insert is true therefore we will create a new doc : ");
|
|
220
|
+
if (!this._checkPermission('create'))
|
|
221
|
+
continue;
|
|
222
|
+
updateData = this._runStampingPipe({ updateData }, false);
|
|
223
|
+
}
|
|
224
|
+
batch.set(docRef, updateData, { merge: true });
|
|
225
|
+
// Set the Id of the object so the consumer knows which id was affected
|
|
226
|
+
results.push(docRef.id);
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
// STRICT UPDATE: Fails if document doesn't exist (Standard Mongo)
|
|
230
|
+
const checkDoc = yield this.findOne({ _id: docRef.id });
|
|
231
|
+
if (!this._checkPermission('update', checkDoc, item))
|
|
232
|
+
continue;
|
|
233
|
+
updateData = this._runStampingPipe({ updateData }, true);
|
|
234
|
+
batch.update(docRef, updateData);
|
|
235
|
+
results.push(docRef.id);
|
|
236
|
+
}
|
|
209
237
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
238
|
+
}
|
|
239
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
240
|
+
finally {
|
|
241
|
+
try {
|
|
242
|
+
if (!_d && !_a && (_b = chunk_1.return)) yield _b.call(chunk_1);
|
|
213
243
|
}
|
|
214
|
-
|
|
244
|
+
finally { if (e_1) throw e_1.error; }
|
|
245
|
+
}
|
|
246
|
+
;
|
|
215
247
|
// Queue the batch commit
|
|
216
248
|
batchPromises.push(batch.commit());
|
|
217
249
|
}
|
|
@@ -220,8 +252,11 @@ class FirestoreDB {
|
|
|
220
252
|
this._invalidateCache();
|
|
221
253
|
// Run all batches in parallel
|
|
222
254
|
try {
|
|
223
|
-
|
|
224
|
-
|
|
255
|
+
if (batchPromises.length > 0) {
|
|
256
|
+
yield Promise.all(batchPromises);
|
|
257
|
+
return results;
|
|
258
|
+
}
|
|
259
|
+
return [];
|
|
225
260
|
}
|
|
226
261
|
catch (error) {
|
|
227
262
|
console.error("FirestoreDB::updateMany: Error during batched update", error);
|
|
@@ -360,8 +395,8 @@ class FirestoreDB {
|
|
|
360
395
|
}
|
|
361
396
|
this._collectionRef = this._sdk.collection(this._db, this._collectionName);
|
|
362
397
|
this._isSoftDeleteEnabled = (_a = this._options.softDelete) !== null && _a !== void 0 ? _a : false;
|
|
363
|
-
this._security = this._options.security;
|
|
364
398
|
this._tenantField = this._tenantField = ((_c = (_b = this._options) === null || _b === void 0 ? void 0 : _b.tenant) === null || _c === void 0 ? void 0 : _c.field) || 'orgId';
|
|
399
|
+
this.setUser(user || null);
|
|
365
400
|
}
|
|
366
401
|
catch (error) {
|
|
367
402
|
throw new Error(`error on init @collection: ${this._collectionName} - ` + error.message);
|
|
@@ -412,6 +447,35 @@ class FirestoreDB {
|
|
|
412
447
|
console.error("FirestoreDB::watch:Error: ", err);
|
|
413
448
|
});
|
|
414
449
|
}
|
|
450
|
+
// ****************************** Security Rules ***********************************************//
|
|
451
|
+
/**
|
|
452
|
+
* Sets the global user and automatically syncs the Tenant ID.
|
|
453
|
+
* @param user - The SecurityUser object or null to clear.
|
|
454
|
+
*/
|
|
455
|
+
setUser(user) {
|
|
456
|
+
if (!user) {
|
|
457
|
+
this.clearUser();
|
|
458
|
+
return this;
|
|
459
|
+
}
|
|
460
|
+
this._currentUser = user;
|
|
461
|
+
// 1. Auto-Sync: User's orgId becomes the active Tenant ID
|
|
462
|
+
this._activeTenantId = user.orgId;
|
|
463
|
+
// 2. Generate Deterministic Token: b64(uid:orgId)
|
|
464
|
+
const raw = `${user.uid}:${user.orgId}`;
|
|
465
|
+
this._userToken = FirestoreDB.generateToken(raw);
|
|
466
|
+
return this;
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* FIRESTOREDB: logout/clear context
|
|
470
|
+
* Wipes all identity and tenant data to prevent stale writes.
|
|
471
|
+
*/
|
|
472
|
+
clearUser() {
|
|
473
|
+
this._currentUser = null;
|
|
474
|
+
this._userToken = null;
|
|
475
|
+
this._activeTenantId = null;
|
|
476
|
+
// Optional: Log for debugging in dev environments
|
|
477
|
+
console.debug(`[FirestoreDB] Context cleared for collection: ${this._collectionName}`);
|
|
478
|
+
}
|
|
415
479
|
/**
|
|
416
480
|
* Public UI Helper: Check permission without executing
|
|
417
481
|
* Usage: <button disabled={!Users.can('create')}>Add User</button>
|
|
@@ -424,7 +488,8 @@ class FirestoreDB {
|
|
|
424
488
|
return false;
|
|
425
489
|
}
|
|
426
490
|
}
|
|
427
|
-
//
|
|
491
|
+
// ****************************** End of Security Rules ***********************************************//
|
|
492
|
+
// ****************************** PRIVATE METHODS ***********************************************//
|
|
428
493
|
_buildConstraints(filter) {
|
|
429
494
|
var _a;
|
|
430
495
|
// Inject Tenant ID (Mandatory Filter)
|
|
@@ -451,22 +516,55 @@ class FirestoreDB {
|
|
|
451
516
|
_checkPermission(action, doc, newData) {
|
|
452
517
|
if (!this._options.security)
|
|
453
518
|
return true; // Security not enabled
|
|
454
|
-
const {
|
|
519
|
+
const { rules, silent, onError } = this._options.security;
|
|
455
520
|
const rule = rules[action];
|
|
456
|
-
if (rule && !rule(
|
|
457
|
-
|
|
521
|
+
if (rule && !rule(this._currentUser, doc, newData)) {
|
|
522
|
+
const err = new Error(`Security Error: User does not have ${action} permission on ${this._collectionName}`);
|
|
523
|
+
// 1. Always trigger the global error hook if it exists (for toasts/logging)
|
|
524
|
+
if (onError)
|
|
525
|
+
onError(err);
|
|
526
|
+
// 2. Decide whether to "Hard Throw" or "Silent Fail"
|
|
527
|
+
if (silent)
|
|
528
|
+
return false;
|
|
529
|
+
throw err;
|
|
458
530
|
}
|
|
459
531
|
return true;
|
|
460
532
|
}
|
|
461
533
|
/**
|
|
462
534
|
* PRIVATE: Helper to stamp tenant info on new data
|
|
463
535
|
*/
|
|
464
|
-
|
|
536
|
+
/**
|
|
537
|
+
* THE MASTER STAMPING PIPE
|
|
538
|
+
* Processes raw entity through all enabled security and metadata layers.
|
|
539
|
+
*/
|
|
540
|
+
_runStampingPipe(entity, isUpdate = false) {
|
|
465
541
|
var _a;
|
|
466
|
-
|
|
467
|
-
|
|
542
|
+
const pipe = [];
|
|
543
|
+
// 1. Identity/Security Token Stamp (Hash of UID:OrgId)
|
|
544
|
+
if (this._userToken) {
|
|
545
|
+
pipe.push((data) => {
|
|
546
|
+
var _a, _b;
|
|
547
|
+
return (Object.assign(Object.assign({}, data), { _userToken: this._userToken, _createdBy: isUpdate && data._createdBy ? data._createdBy : (((_a = this._currentUser) === null || _a === void 0 ? void 0 : _a.uid) || 'system'), _updatedBy: ((_b = this._currentUser) === null || _b === void 0 ? void 0 : _b.uid) || 'system' }));
|
|
548
|
+
});
|
|
468
549
|
}
|
|
469
|
-
|
|
550
|
+
// 2. Multi-Tenancy Stamp
|
|
551
|
+
if (((_a = this._options.tenant) === null || _a === void 0 ? void 0 : _a.enabled) && this._activeTenantId) {
|
|
552
|
+
const field = this._options.tenant.field || 'orgId';
|
|
553
|
+
pipe.push((data) => (Object.assign(Object.assign({}, data), { [field]: this._activeTenantId })));
|
|
554
|
+
}
|
|
555
|
+
// 3. Timestamps (Firestore Server Side)
|
|
556
|
+
pipe.push((data) => (Object.assign(Object.assign(Object.assign({}, data), (isUpdate ? {} : { createdAt: this._sdk.serverTimestamp() })), { updatedAt: this._sdk.serverTimestamp() })));
|
|
557
|
+
// handle a stamp for isDeleted on all documents if this field is not present
|
|
558
|
+
pipe.push((data) => {
|
|
559
|
+
if (!Object.keys(data).includes('isDeleted'))
|
|
560
|
+
return Object.assign(Object.assign({}, data), { isDeleted: false });
|
|
561
|
+
return Object.assign({}, data);
|
|
562
|
+
});
|
|
563
|
+
// Execute the pipe: reducer patterns are perfect for this
|
|
564
|
+
return pipe.reduce((processedData, stampFn) => stampFn(processedData), entity);
|
|
470
565
|
}
|
|
471
566
|
}
|
|
472
567
|
exports.FirestoreDB = FirestoreDB;
|
|
568
|
+
FirestoreDB.generateToken = (raw) => typeof btoa !== 'undefined'
|
|
569
|
+
? btoa(raw)
|
|
570
|
+
: Buffer.from(raw).toString('base64');
|
|
@@ -18,6 +18,7 @@ export declare class FirestoreQuery<T> {
|
|
|
18
18
|
private _sdk;
|
|
19
19
|
private buildConstraints;
|
|
20
20
|
private countDocs;
|
|
21
|
+
private _checkPermission;
|
|
21
22
|
static _globalCache: LRUCache;
|
|
22
23
|
private _useCache;
|
|
23
24
|
private _ttl;
|
|
@@ -27,7 +28,7 @@ export declare class FirestoreQuery<T> {
|
|
|
27
28
|
private _sort;
|
|
28
29
|
private _cursorId?;
|
|
29
30
|
private _cursorType;
|
|
30
|
-
constructor(db: any, collectionName: string, collectionRef: any, filter: Record<string, any>, _sdk: FirestoreSDK, buildConstraints: (f: any) => QueryConstraint[], countDocs: (f: any) => Promise<number>, isSoftDeleteEnabled: boolean);
|
|
31
|
+
constructor(db: any, collectionName: string, collectionRef: any, filter: Record<string, any>, _sdk: FirestoreSDK, buildConstraints: (f: any) => QueryConstraint[], countDocs: (f: any) => Promise<number>, isSoftDeleteEnabled: boolean, _checkPermission: (action: 'read' | 'create' | 'update' | 'delete', doc?: any, newData?: any) => boolean);
|
|
31
32
|
/** Enables result caching for this query */
|
|
32
33
|
cache(ttlMs?: number): this;
|
|
33
34
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FirestoreQuery.d.ts","sourceRoot":"","sources":["../../src/FirestoreQuery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAGzD,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE1D,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,CAAA;AAC3C,MAAM,WAAW,kBAAkB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACxB;AAED,qBAAa,cAAc,CAAC,CAAC;IAgBrB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,gBAAgB;IACxB,OAAO,CAAC,SAAS;
|
|
1
|
+
{"version":3,"file":"FirestoreQuery.d.ts","sourceRoot":"","sources":["../../src/FirestoreQuery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAGzD,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE1D,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,CAAA;AAC3C,MAAM,WAAW,kBAAkB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACxB;AAED,qBAAa,cAAc,CAAC,CAAC;IAgBrB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,gBAAgB;IACxB,OAAO,CAAC,SAAS;IAEjB,OAAO,CAAC,gBAAgB;IArB5B,OAAc,YAAY,WAAkB;IAC5C,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,IAAI,CAAiB;IAC7B,OAAO,CAAC,WAAW,CAAa;IAGhC,OAAO,CAAC,WAAW,CAAuC;IAC1D,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,KAAK,CAAsC;IACnD,OAAO,CAAC,SAAS,CAAC,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAmC;gBAG1C,EAAE,EAAE,GAAG,EACP,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,GAAG,EAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,IAAI,EAAE,YAAY,EAClB,gBAAgB,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,eAAe,EAAE,EAC/C,SAAS,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC,MAAM,CAAC,EAC9C,mBAAmB,EAAE,OAAO,EACpB,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG,KAAG,OAAO;IAKlH,4CAA4C;IAC5C,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM;IAMpB;;OAEG;IACH,IAAI,CAAC,CAAC,EAAE,MAAM;IAKP,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC;IAK7C,KAAK,CAAC,CAAC,EAAE,MAAM;IAKtB,4BAA4B;IACrB,KAAK,CAAC,EAAE,EAAE,MAAM;IAMvB,gCAAgC;IACzB,MAAM,CAAC,EAAE,EAAE,MAAM;IAMxB;;;OAGG;IACH,WAAW;IAKX,WAAW;IAEX,uCAAuC;IAC1B,OAAO,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC;IActD;;;;;;;;;;;;;;;;;OAiBG;IACU,QAAQ,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC;QAAC,QAAQ,EAAE,kBAAkB,CAAA;KAAE,CAAC;IAuCxF,MAAM,IAAI,cAAc,CAAC,CAAC,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAkBpD;;;;;;;;;;OAUG;IACU,MAAM,IAAI,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YAapC,mBAAmB;IAsCjC,OAAO,CAAC,iBAAiB;IAezB;;GAED;IACC,OAAO,CAAC,eAAe;CAQ1B"}
|
|
@@ -15,7 +15,7 @@ const Hasher_1 = require("./utils/Hasher");
|
|
|
15
15
|
const utils_2 = require("./utils");
|
|
16
16
|
const FirestoreCursor_1 = require("./utils/FirestoreCursor");
|
|
17
17
|
class FirestoreQuery {
|
|
18
|
-
constructor(db, collectionName, collectionRef, filter, _sdk, buildConstraints, countDocs, isSoftDeleteEnabled) {
|
|
18
|
+
constructor(db, collectionName, collectionRef, filter, _sdk, buildConstraints, countDocs, isSoftDeleteEnabled, _checkPermission) {
|
|
19
19
|
this.db = db;
|
|
20
20
|
this.collectionName = collectionName;
|
|
21
21
|
this.collectionRef = collectionRef;
|
|
@@ -23,6 +23,7 @@ class FirestoreQuery {
|
|
|
23
23
|
this._sdk = _sdk;
|
|
24
24
|
this.buildConstraints = buildConstraints;
|
|
25
25
|
this.countDocs = countDocs;
|
|
26
|
+
this._checkPermission = _checkPermission;
|
|
26
27
|
this._useCache = false;
|
|
27
28
|
this._ttl = 60000; // Default 1 minute
|
|
28
29
|
this._pageNumber = 1; // Default to first page
|
|
@@ -78,6 +79,9 @@ class FirestoreQuery {
|
|
|
78
79
|
/** Simple execution (Returns Array) */
|
|
79
80
|
execute() {
|
|
80
81
|
return __awaiter(this, void 0, void 0, function* () {
|
|
82
|
+
// If security fails and we are in silent mode, return empty array
|
|
83
|
+
if (!this._checkPermission('read'))
|
|
84
|
+
return [];
|
|
81
85
|
let finalConstraints = yield this._prepareConstraints();
|
|
82
86
|
const q = this._sdk.query(this.collectionRef, ...finalConstraints);
|
|
83
87
|
const snapshot = yield this._sdk.getDocs(q);
|
package/dist/esm/types.d.ts
CHANGED
|
@@ -23,14 +23,25 @@ export interface TenantOptions {
|
|
|
23
23
|
id: string | number;
|
|
24
24
|
field?: string;
|
|
25
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Internal Type for a Stamping Function
|
|
28
|
+
*/
|
|
29
|
+
export type StamperFn = (data: any) => any;
|
|
30
|
+
export interface SecurityUser {
|
|
31
|
+
uid: string;
|
|
32
|
+
orgId: string;
|
|
33
|
+
role: string;
|
|
34
|
+
[key: string]: any;
|
|
35
|
+
}
|
|
26
36
|
export interface SecurityPolicy {
|
|
27
|
-
user: any;
|
|
28
37
|
rules: {
|
|
29
38
|
read?: (user: any, doc?: any) => boolean;
|
|
30
39
|
create?: (user: any, data?: any) => boolean;
|
|
31
40
|
update?: (user: any, doc: any, newData?: any) => boolean;
|
|
32
41
|
delete?: (user: any, doc: any) => boolean;
|
|
33
42
|
};
|
|
43
|
+
silent?: boolean;
|
|
44
|
+
onError?: (err: Error) => void;
|
|
34
45
|
}
|
|
35
46
|
export type WithSystemFields<T> = T & FirestoreDBDocument;
|
|
36
47
|
export interface DBOptions {
|
|
@@ -43,9 +54,9 @@ export interface DBOptions {
|
|
|
43
54
|
*/
|
|
44
55
|
export interface FirestoreSDK {
|
|
45
56
|
collection: (db: Firestore, path: string) => CollectionReference;
|
|
46
|
-
doc: (dbOrRef: Firestore | CollectionReference, ...
|
|
47
|
-
getDoc: (ref: DocumentReference) => Promise<DocumentSnapshot
|
|
48
|
-
getDocs: (query: Query) => Promise<QuerySnapshot<unknown, DocumentData>>;
|
|
57
|
+
doc: (dbOrRef: Firestore | CollectionReference<DocumentData, DocumentData>, path?: string, ...pathSegments: string[]) => DocumentReference<DocumentData, DocumentData>;
|
|
58
|
+
getDoc: (ref: DocumentReference<DocumentData, DocumentData>) => Promise<DocumentSnapshot<DocumentData, DocumentData>>;
|
|
59
|
+
getDocs: (query: Query<DocumentData, DocumentData>) => Promise<QuerySnapshot<unknown, DocumentData>>;
|
|
49
60
|
setDoc: (ref: DocumentReference, data: any, options?: any) => Promise<void>;
|
|
50
61
|
updateDoc: (ref: DocumentReference, data: any) => Promise<void>;
|
|
51
62
|
deleteDoc: (ref: DocumentReference) => Promise<void>;
|
package/dist/esm/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,SAAS,EAAE,mBAAmB,EAAE,iBAAiB,EACjD,eAAe,EAAE,UAAU,EAAE,KAAK,EAAE,gBAAgB,EACpD,YAAY,EACZ,cAAc,EACd,WAAW,EACX,SAAS,EACT,cAAc,EACd,aAAa,EACb,sBAAsB,EACtB,qBAAqB,EACrB,aAAa,EACb,WAAW,EACX,kBAAkB,EACrB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAC5D;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;KACxB,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG;CACvB,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAGxB,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;CACrB,CAAA;AAID,KAAK,mBAAmB,GAAG;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,IAAI,CAAA;IACf,SAAS,EAAE,IAAI,CAAA;IACf,SAAS,CAAC,EAAE,IAAI,CAAA;CACnB,CAAA;AAED,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,5 +6,5 @@ import { DBOptions, FirestoreSDK } from "../types";
|
|
|
6
6
|
*
|
|
7
7
|
* @returns Returns a generator function to create collection-specific instances.
|
|
8
8
|
*/
|
|
9
|
-
export declare const createFirestoreDB: (db: Firestore, sdk: FirestoreSDK, FirestoreOptions?: DBOptions) => (collectionName: string, options?: DBOptions) => FirestoreDB<
|
|
9
|
+
export declare const createFirestoreDB: (db: Firestore, sdk: FirestoreSDK, FirestoreOptions?: DBOptions) => <T>(collectionName: string, options?: DBOptions) => FirestoreDB<T>;
|
|
10
10
|
//# sourceMappingURL=createFirestoreDB.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createFirestoreDB.d.ts","sourceRoot":"","sources":["../../../src/utils/createFirestoreDB.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEnD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,IAAI,SAAS,EAAE,KAAK,YAAY,EAAE,mBAAkB,SAAc,MAMxF,gBAAgB,MAAM,EAAE,UAAS,
|
|
1
|
+
{"version":3,"file":"createFirestoreDB.d.ts","sourceRoot":"","sources":["../../../src/utils/createFirestoreDB.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEnD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,IAAI,SAAS,EAAE,KAAK,YAAY,EAAE,mBAAkB,SAAc,MAMxF,CAAC,EAAE,gBAAgB,MAAM,EAAE,UAAS,SAAc,mBAG7D,CAAC"}
|
|
@@ -12,8 +12,8 @@ const createFirestoreDB = (db, sdk, FirestoreOptions = {}) => {
|
|
|
12
12
|
* @param collectionName - The name of the Firestore collection
|
|
13
13
|
* @param options - Optional: { softDelete: true }
|
|
14
14
|
*/
|
|
15
|
-
return (collectionName, options =
|
|
16
|
-
return new FirestoreDB_1.FirestoreDB(db, collectionName, sdk, options);
|
|
15
|
+
return (collectionName, options = {}) => {
|
|
16
|
+
return new FirestoreDB_1.FirestoreDB(db, collectionName, sdk, Object.assign(options, FirestoreOptions));
|
|
17
17
|
};
|
|
18
18
|
};
|
|
19
19
|
exports.createFirestoreDB = createFirestoreDB;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knymbus/firestoredb",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "MongoDB-style wrapper for Firestore with parallel streaming and caching.",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"test": "firebase emulators:exec --only firestore \"vitest run\"",
|
|
19
19
|
"test:watch": "firebase emulators:exec --only firestore \"vitest\"",
|
|
20
20
|
"emulator": "firebase emulators:start --only firestore",
|
|
21
|
-
"publish:patch": "npm version patch && npm publish --access public"
|
|
21
|
+
"publish:patch": "npm version patch && npm publish --access public",
|
|
22
|
+
"publish:minor": "npm version minor && npm publish --access public"
|
|
22
23
|
},
|
|
23
24
|
"keywords": [],
|
|
24
25
|
"author": "Ovel Heslop <kayheslop@gmail.com>",
|