nexabase-console 2.1.1 → 2.1.3
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/app/NexaApp.d.ts +3 -0
- package/dist/app/NexaApp.js +40 -11
- package/dist/firestore/CollectionReference.d.ts +2 -2
- package/dist/firestore/CollectionReference.js +41 -2
- package/dist/firestore/DocumentReference.d.ts +1 -1
- package/dist/firestore/DocumentReference.js +41 -11
- package/dist/firestore/FieldPath.d.ts +2 -1
- package/dist/firestore/FieldPath.js +31 -4
- package/dist/firestore/FieldValue.d.ts +8 -4
- package/dist/firestore/FieldValue.js +59 -7
- package/dist/firestore/Firestore.js +16 -4
- package/dist/firestore/GeoPoint.d.ts +1 -0
- package/dist/firestore/GeoPoint.js +13 -6
- package/dist/firestore/Query.d.ts +5 -0
- package/dist/firestore/Query.js +190 -56
- package/dist/firestore/QueryUtils.d.ts +19 -2
- package/dist/firestore/QueryUtils.js +296 -58
- package/dist/firestore/Snapshot.js +62 -17
- package/dist/firestore/SnapshotManager.js +27 -12
- package/dist/firestore/Timestamp.d.ts +1 -0
- package/dist/firestore/Timestamp.js +28 -2
- package/dist/firestore/batch.js +89 -36
- package/dist/firestore/pathValidation.d.ts +17 -0
- package/dist/firestore/pathValidation.js +61 -0
- package/dist/firestore/queryConstraints.d.ts +4 -4
- package/dist/firestore/queryConstraints.js +69 -8
- package/dist/firestore/transaction.js +72 -18
- package/dist/firestore/writes.d.ts +1 -1
- package/dist/firestore/writes.js +32 -14
- package/dist/transport/WebSocketClient.d.ts +341 -9
- package/dist/transport/WebSocketClient.js +1895 -131
- package/dist/transport/WebSocketClient.test.d.ts +1 -0
- package/dist/transport/WebSocketClient.test.js +454 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -1
package/dist/app/NexaApp.d.ts
CHANGED
|
@@ -32,6 +32,8 @@ export declare class NexaApp {
|
|
|
32
32
|
_firestoreListening: boolean;
|
|
33
33
|
_firestoreUnsubscribes: (() => void)[];
|
|
34
34
|
_initPromise: Promise<void> | null;
|
|
35
|
+
_initialized: boolean;
|
|
36
|
+
_activeQueryTimestamps: Map<string, number>;
|
|
35
37
|
constructor(config: NexaConfig);
|
|
36
38
|
get _firestoreCache(): Record<string, any>;
|
|
37
39
|
private _setupCrossTabSync;
|
|
@@ -85,6 +87,7 @@ export declare class NexaApp {
|
|
|
85
87
|
revision?: string;
|
|
86
88
|
}): Promise<void>;
|
|
87
89
|
_syncOfflineQueue(): Promise<void>;
|
|
90
|
+
_handleServerFirestoreChange(payload: any): void;
|
|
88
91
|
_ensureFirestoreSSE(): void;
|
|
89
92
|
_ensureFirestoreWebSocket(): void;
|
|
90
93
|
_closeFirestoreSSEIfIdle(): void;
|
package/dist/app/NexaApp.js
CHANGED
|
@@ -22,6 +22,8 @@ class NexaApp {
|
|
|
22
22
|
this._firestoreListening = false;
|
|
23
23
|
this._firestoreUnsubscribes = [];
|
|
24
24
|
this._initPromise = null;
|
|
25
|
+
this._initialized = false;
|
|
26
|
+
this._activeQueryTimestamps = new Map();
|
|
25
27
|
this.projectId = config.projectId;
|
|
26
28
|
this.token = config.apiKey || null;
|
|
27
29
|
this.enablePersistence = config.enablePersistence !== false;
|
|
@@ -82,8 +84,10 @@ class NexaApp {
|
|
|
82
84
|
this.mutationQueue.unmarkInflight(path, mutationId);
|
|
83
85
|
}
|
|
84
86
|
async _initFirestoreState() {
|
|
85
|
-
if (!this.enablePersistence)
|
|
87
|
+
if (!this.enablePersistence) {
|
|
88
|
+
this._initialized = true;
|
|
86
89
|
return;
|
|
90
|
+
}
|
|
87
91
|
try {
|
|
88
92
|
await this.indexedDB.init();
|
|
89
93
|
await this.localStore.loadAll();
|
|
@@ -97,6 +101,9 @@ class NexaApp {
|
|
|
97
101
|
catch (err) {
|
|
98
102
|
console.warn('[NexaApp] Failed to initialize IndexedDB offline cache:', err);
|
|
99
103
|
}
|
|
104
|
+
finally {
|
|
105
|
+
this._initialized = true;
|
|
106
|
+
}
|
|
100
107
|
}
|
|
101
108
|
async _setCache(path, data) {
|
|
102
109
|
const revived = (0, QueryUtils_1.reviveNexaData)(data);
|
|
@@ -348,23 +355,43 @@ class NexaApp {
|
|
|
348
355
|
async _syncOfflineQueue() {
|
|
349
356
|
await this.syncEngine.syncOfflineMutations();
|
|
350
357
|
}
|
|
358
|
+
_handleServerFirestoreChange(payload) {
|
|
359
|
+
if (!payload)
|
|
360
|
+
return;
|
|
361
|
+
if (Array.isArray(payload)) {
|
|
362
|
+
payload.forEach((item) => this._handleServerFirestoreChange(item));
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
const { type, docPath, collectionPath, data, path: rawPath, action } = payload;
|
|
366
|
+
const targetDocPath = docPath || rawPath;
|
|
367
|
+
const isDelete = type === 'document_deleted' || action === 'delete' || type === 'delete';
|
|
368
|
+
if (targetDocPath && typeof targetDocPath === 'string') {
|
|
369
|
+
if (isDelete) {
|
|
370
|
+
this._deleteCache(targetDocPath);
|
|
371
|
+
}
|
|
372
|
+
else if (data) {
|
|
373
|
+
this._setCache(targetDocPath, data);
|
|
374
|
+
}
|
|
375
|
+
const parts = targetDocPath.split('/');
|
|
376
|
+
const colPath = parts.length > 1 ? parts.slice(0, -1).join('/') : '';
|
|
377
|
+
this._notifySnapshotCallbacks(targetDocPath, isDelete ? 'document_deleted' : 'document_written', data);
|
|
378
|
+
if (colPath) {
|
|
379
|
+
this._notifySnapshotCallbacks(colPath, isDelete ? 'document_deleted' : 'document_written', data);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
else if (collectionPath && typeof collectionPath === 'string') {
|
|
383
|
+
this._notifySnapshotCallbacks(collectionPath, 'server_update', data);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
351
386
|
_ensureFirestoreSSE() {
|
|
352
387
|
if (this._firestoreListening)
|
|
353
388
|
return;
|
|
354
389
|
this._firestoreListening = true;
|
|
355
390
|
const unsub1 = this.wsClient.addListener('data_changed', (payload) => {
|
|
356
|
-
|
|
357
|
-
if (payload.action === 'delete') {
|
|
358
|
-
this._deleteCache(payload.path);
|
|
359
|
-
}
|
|
360
|
-
else if (payload.data) {
|
|
361
|
-
this._setCache(payload.path, payload.data);
|
|
362
|
-
}
|
|
363
|
-
this._notifySnapshotCallbacks(payload.path, payload.action === 'delete' ? 'document_deleted' : 'document_written', payload.data);
|
|
364
|
-
}
|
|
391
|
+
this._handleServerFirestoreChange(payload);
|
|
365
392
|
});
|
|
366
393
|
const unsub2 = this.wsClient.addListener('firestore_changed', (payload) => {
|
|
367
|
-
this.
|
|
394
|
+
this._handleServerFirestoreChange(payload);
|
|
368
395
|
});
|
|
369
396
|
this._firestoreUnsubscribes.push(unsub1, unsub2);
|
|
370
397
|
}
|
|
@@ -382,6 +409,8 @@ class NexaApp {
|
|
|
382
409
|
this._closeFirestoreSSEIfIdle();
|
|
383
410
|
}
|
|
384
411
|
_notifySnapshotCallbacks(path, actionType, payload) {
|
|
412
|
+
if (!path || typeof path !== 'string')
|
|
413
|
+
return;
|
|
385
414
|
Object.keys(this._snapshotCallbacks).forEach((cbKey) => {
|
|
386
415
|
const parts = cbKey.split('_');
|
|
387
416
|
const targetPath = parts.slice(2).join('_');
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { NexaApp } from '../app/NexaApp';
|
|
2
|
-
import { CollectionReference } from '../types/index';
|
|
3
|
-
export declare const collection: <T = any>(
|
|
2
|
+
import { CollectionReference, DocumentReference } from '../types/index';
|
|
3
|
+
export declare const collection: <T = any>(dbOrRef: NexaApp | DocumentReference<any> | CollectionReference<any>, ...pathSegments: string[]) => CollectionReference<T>;
|
|
@@ -1,7 +1,46 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.collection = void 0;
|
|
4
|
-
const
|
|
5
|
-
|
|
4
|
+
const NexaError_1 = require("../errors/NexaError");
|
|
5
|
+
const pathValidation_1 = require("./pathValidation");
|
|
6
|
+
const collection = (dbOrRef, ...pathSegments) => {
|
|
7
|
+
if (!dbOrRef || typeof dbOrRef !== 'object') {
|
|
8
|
+
throw new NexaError_1.NexaError('invalid-argument', 'First argument to collection() must be a valid NexaApp, DocumentReference, or CollectionReference.');
|
|
9
|
+
}
|
|
10
|
+
if ('type' in dbOrRef && dbOrRef.type === 'document') {
|
|
11
|
+
if (pathSegments.length === 0) {
|
|
12
|
+
throw new NexaError_1.NexaError('invalid-argument', 'collection() called with DocumentReference requires path segments.');
|
|
13
|
+
}
|
|
14
|
+
const joined = pathSegments.join('/');
|
|
15
|
+
const finalPath = (0, pathValidation_1.validateCollectionPath)(`${dbOrRef.path}/${joined}`);
|
|
16
|
+
return {
|
|
17
|
+
type: 'collection',
|
|
18
|
+
path: finalPath,
|
|
19
|
+
db: dbOrRef.db
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
if ('type' in dbOrRef && dbOrRef.type === 'collection') {
|
|
23
|
+
if (pathSegments.length === 0) {
|
|
24
|
+
return dbOrRef;
|
|
25
|
+
}
|
|
26
|
+
const joined = pathSegments.join('/');
|
|
27
|
+
const finalPath = (0, pathValidation_1.validateCollectionPath)(`${dbOrRef.path}/${joined}`);
|
|
28
|
+
return {
|
|
29
|
+
type: 'collection',
|
|
30
|
+
path: finalPath,
|
|
31
|
+
db: dbOrRef.db
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// dbOrRef is NexaApp
|
|
35
|
+
if (pathSegments.length === 0) {
|
|
36
|
+
throw new NexaError_1.NexaError('invalid-argument', 'collection() called with database reference requires a path.');
|
|
37
|
+
}
|
|
38
|
+
const joined = pathSegments.join('/');
|
|
39
|
+
const finalPath = (0, pathValidation_1.validateCollectionPath)(joined);
|
|
40
|
+
return {
|
|
41
|
+
type: 'collection',
|
|
42
|
+
path: finalPath,
|
|
43
|
+
db: dbOrRef
|
|
44
|
+
};
|
|
6
45
|
};
|
|
7
46
|
exports.collection = collection;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { NexaApp } from '../app/NexaApp';
|
|
2
2
|
import { CollectionReference, DocumentReference } from '../types/index';
|
|
3
|
-
export declare const doc: <T = any>(
|
|
3
|
+
export declare const doc: <T = any>(dbOrRef: NexaApp | CollectionReference<any> | DocumentReference<any>, ...pathSegments: string[]) => DocumentReference<T>;
|
|
@@ -1,22 +1,52 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.doc = void 0;
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
const NexaError_1 = require("../errors/NexaError");
|
|
5
|
+
const pathValidation_1 = require("./pathValidation");
|
|
6
|
+
const doc = (dbOrRef, ...pathSegments) => {
|
|
7
|
+
if (!dbOrRef || typeof dbOrRef !== 'object') {
|
|
8
|
+
throw new NexaError_1.NexaError('invalid-argument', 'First argument to doc() must be a valid NexaApp, CollectionReference, or DocumentReference.');
|
|
9
|
+
}
|
|
10
|
+
if ('type' in dbOrRef && dbOrRef.type === 'collection') {
|
|
11
|
+
if (pathSegments.length === 0) {
|
|
12
|
+
const autoId = (0, pathValidation_1.generateAutoId)();
|
|
13
|
+
const finalPath = (0, pathValidation_1.validateDocumentPath)(`${dbOrRef.path}/${autoId}`);
|
|
14
|
+
return {
|
|
15
|
+
type: 'document',
|
|
16
|
+
path: finalPath,
|
|
17
|
+
db: dbOrRef.db
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const joined = pathSegments.join('/');
|
|
21
|
+
const finalPath = (0, pathValidation_1.validateDocumentPath)(`${dbOrRef.path}/${joined}`);
|
|
22
|
+
return {
|
|
8
23
|
type: 'document',
|
|
9
|
-
path:
|
|
10
|
-
db:
|
|
24
|
+
path: finalPath,
|
|
25
|
+
db: dbOrRef.db
|
|
11
26
|
};
|
|
12
27
|
}
|
|
13
|
-
|
|
14
|
-
|
|
28
|
+
if ('type' in dbOrRef && dbOrRef.type === 'document') {
|
|
29
|
+
if (pathSegments.length === 0) {
|
|
30
|
+
return dbOrRef;
|
|
31
|
+
}
|
|
32
|
+
const joined = pathSegments.join('/');
|
|
33
|
+
const finalPath = (0, pathValidation_1.validateDocumentPath)(`${dbOrRef.path}/${joined}`);
|
|
34
|
+
return {
|
|
15
35
|
type: 'document',
|
|
16
|
-
path:
|
|
17
|
-
db:
|
|
36
|
+
path: finalPath,
|
|
37
|
+
db: dbOrRef.db
|
|
18
38
|
};
|
|
19
39
|
}
|
|
20
|
-
|
|
40
|
+
// dbOrRef is NexaApp instance
|
|
41
|
+
if (pathSegments.length === 0) {
|
|
42
|
+
throw new NexaError_1.NexaError('invalid-argument', 'doc() called with database reference requires at least one path segment.');
|
|
43
|
+
}
|
|
44
|
+
const joined = pathSegments.join('/');
|
|
45
|
+
const finalPath = (0, pathValidation_1.validateDocumentPath)(joined);
|
|
46
|
+
return {
|
|
47
|
+
type: 'document',
|
|
48
|
+
path: finalPath,
|
|
49
|
+
db: dbOrRef
|
|
50
|
+
};
|
|
21
51
|
};
|
|
22
52
|
exports.doc = doc;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export declare class FieldPath {
|
|
2
|
-
|
|
2
|
+
readonly segments: readonly string[];
|
|
3
3
|
constructor(...fieldNames: string[]);
|
|
4
4
|
static documentId(): FieldPath;
|
|
5
5
|
getPathString(): string;
|
|
6
6
|
isEqual(other: FieldPath): boolean;
|
|
7
|
+
toString(): string;
|
|
7
8
|
}
|
|
@@ -1,23 +1,50 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FieldPath = void 0;
|
|
4
|
+
const NexaError_1 = require("../errors/NexaError");
|
|
5
|
+
const CONTROL_CHARS_REGEX = /[\x00-\x1F\x7F]/;
|
|
6
|
+
const SIMPLE_FIELD_NAME_REGEX = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
4
7
|
class FieldPath {
|
|
5
8
|
constructor(...fieldNames) {
|
|
6
|
-
if (fieldNames.length === 0) {
|
|
7
|
-
throw new
|
|
9
|
+
if (!fieldNames || fieldNames.length === 0) {
|
|
10
|
+
throw new NexaError_1.NexaError('invalid-argument', 'FieldPath must contain at least one field name.');
|
|
8
11
|
}
|
|
9
|
-
|
|
12
|
+
for (let i = 0; i < fieldNames.length; i++) {
|
|
13
|
+
const name = fieldNames[i];
|
|
14
|
+
if (typeof name !== 'string' || name.length === 0) {
|
|
15
|
+
throw new NexaError_1.NexaError('invalid-argument', `Invalid field path segment at index ${i}. Provided field name must be a non-empty string.`);
|
|
16
|
+
}
|
|
17
|
+
if (CONTROL_CHARS_REGEX.test(name)) {
|
|
18
|
+
throw new NexaError_1.NexaError('invalid-argument', `FieldPath segment "${name}" contains invalid control characters.`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
this.segments = Object.freeze([...fieldNames]);
|
|
22
|
+
Object.freeze(this);
|
|
10
23
|
}
|
|
11
24
|
static documentId() {
|
|
12
25
|
return new FieldPath('__name__');
|
|
13
26
|
}
|
|
14
27
|
getPathString() {
|
|
15
|
-
return this.segments
|
|
28
|
+
return this.segments
|
|
29
|
+
.map((seg) => {
|
|
30
|
+
if (SIMPLE_FIELD_NAME_REGEX.test(seg)) {
|
|
31
|
+
return seg;
|
|
32
|
+
}
|
|
33
|
+
// Escape backslashes and backticks, then wrap in backticks
|
|
34
|
+
const escaped = seg.replace(/\\/g, '\\\\').replace(/`/g, '\\`');
|
|
35
|
+
return `\`${escaped}\``;
|
|
36
|
+
})
|
|
37
|
+
.join('.');
|
|
16
38
|
}
|
|
17
39
|
isEqual(other) {
|
|
40
|
+
if (!(other instanceof FieldPath))
|
|
41
|
+
return false;
|
|
18
42
|
if (this.segments.length !== other.segments.length)
|
|
19
43
|
return false;
|
|
20
44
|
return this.segments.every((seg, idx) => seg === other.segments[idx]);
|
|
21
45
|
}
|
|
46
|
+
toString() {
|
|
47
|
+
return this.getPathString();
|
|
48
|
+
}
|
|
22
49
|
}
|
|
23
50
|
exports.FieldPath = FieldPath;
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
export declare const FIELD_VALUE_BRAND: unique symbol;
|
|
2
|
+
export type FieldValueMethod = 'serverTimestamp' | 'increment' | 'arrayUnion' | 'arrayRemove' | 'deleteField';
|
|
1
3
|
export declare class FieldValue {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
constructor(method:
|
|
4
|
+
readonly [FIELD_VALUE_BRAND] = true;
|
|
5
|
+
readonly method: FieldValueMethod;
|
|
6
|
+
readonly value?: any;
|
|
7
|
+
constructor(method: FieldValueMethod, value?: any);
|
|
8
|
+
static isFieldValue(val: any): val is FieldValue;
|
|
9
|
+
isEqual(other: any): boolean;
|
|
6
10
|
}
|
|
7
11
|
export declare const serverTimestamp: () => FieldValue;
|
|
8
12
|
export declare const increment: (n: number) => FieldValue;
|
|
@@ -1,26 +1,78 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var _a;
|
|
2
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.atomicDecrement = exports.atomicIncrement = exports.deleteField = exports.arrayRemove = exports.arrayUnion = exports.increment = exports.serverTimestamp = exports.FieldValue = void 0;
|
|
4
|
+
exports.atomicDecrement = exports.atomicIncrement = exports.deleteField = exports.arrayRemove = exports.arrayUnion = exports.increment = exports.serverTimestamp = exports.FieldValue = exports.FIELD_VALUE_BRAND = void 0;
|
|
5
|
+
const NexaError_1 = require("../errors/NexaError");
|
|
6
|
+
exports.FIELD_VALUE_BRAND = Symbol.for('nexabase.fieldValue');
|
|
4
7
|
class FieldValue {
|
|
5
8
|
constructor(method, value) {
|
|
9
|
+
this[_a] = true;
|
|
6
10
|
this.method = method;
|
|
7
11
|
this.value = value;
|
|
8
|
-
this
|
|
12
|
+
Object.freeze(this);
|
|
13
|
+
}
|
|
14
|
+
static isFieldValue(val) {
|
|
15
|
+
return (val !== null &&
|
|
16
|
+
typeof val === 'object' &&
|
|
17
|
+
(val instanceof FieldValue || val[exports.FIELD_VALUE_BRAND] === true));
|
|
18
|
+
}
|
|
19
|
+
isEqual(other) {
|
|
20
|
+
if (!FieldValue.isFieldValue(other))
|
|
21
|
+
return false;
|
|
22
|
+
if (this.method !== other.method)
|
|
23
|
+
return false;
|
|
24
|
+
if (this.value === other.value)
|
|
25
|
+
return true;
|
|
26
|
+
if (Array.isArray(this.value) && Array.isArray(other.value)) {
|
|
27
|
+
return (this.value.length === other.value.length &&
|
|
28
|
+
this.value.every((v, i) => v === other.value[i]));
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
9
31
|
}
|
|
10
32
|
}
|
|
11
33
|
exports.FieldValue = FieldValue;
|
|
34
|
+
_a = exports.FIELD_VALUE_BRAND;
|
|
12
35
|
const serverTimestamp = () => new FieldValue('serverTimestamp');
|
|
13
36
|
exports.serverTimestamp = serverTimestamp;
|
|
14
|
-
const increment = (n) =>
|
|
37
|
+
const increment = (n) => {
|
|
38
|
+
if (typeof n !== 'number' || !Number.isFinite(n)) {
|
|
39
|
+
throw new NexaError_1.NexaError('invalid-argument', 'FieldValue.increment() value must be a finite number.');
|
|
40
|
+
}
|
|
41
|
+
return new FieldValue('increment', n);
|
|
42
|
+
};
|
|
15
43
|
exports.increment = increment;
|
|
16
|
-
const arrayUnion = (...elements) =>
|
|
44
|
+
const arrayUnion = (...elements) => {
|
|
45
|
+
for (let i = 0; i < elements.length; i++) {
|
|
46
|
+
if (FieldValue.isFieldValue(elements[i])) {
|
|
47
|
+
throw new NexaError_1.NexaError('invalid-argument', 'FieldValue.arrayUnion() elements cannot contain nested FieldValues.');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return new FieldValue('arrayUnion', Object.freeze([...elements]));
|
|
51
|
+
};
|
|
17
52
|
exports.arrayUnion = arrayUnion;
|
|
18
|
-
const arrayRemove = (...elements) =>
|
|
53
|
+
const arrayRemove = (...elements) => {
|
|
54
|
+
for (let i = 0; i < elements.length; i++) {
|
|
55
|
+
if (FieldValue.isFieldValue(elements[i])) {
|
|
56
|
+
throw new NexaError_1.NexaError('invalid-argument', 'FieldValue.arrayRemove() elements cannot contain nested FieldValues.');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return new FieldValue('arrayRemove', Object.freeze([...elements]));
|
|
60
|
+
};
|
|
19
61
|
exports.arrayRemove = arrayRemove;
|
|
20
62
|
const deleteField = () => new FieldValue('deleteField');
|
|
21
63
|
exports.deleteField = deleteField;
|
|
22
64
|
// Helper methods for Offline-First operations (e.g. POS/Inventory systems)
|
|
23
|
-
const atomicIncrement = (n) =>
|
|
65
|
+
const atomicIncrement = (n) => {
|
|
66
|
+
if (typeof n !== 'number' || !Number.isFinite(n)) {
|
|
67
|
+
throw new NexaError_1.NexaError('invalid-argument', 'atomicIncrement() value must be a finite number.');
|
|
68
|
+
}
|
|
69
|
+
return new FieldValue('increment', Math.abs(n));
|
|
70
|
+
};
|
|
24
71
|
exports.atomicIncrement = atomicIncrement;
|
|
25
|
-
const atomicDecrement = (n) =>
|
|
72
|
+
const atomicDecrement = (n) => {
|
|
73
|
+
if (typeof n !== 'number' || !Number.isFinite(n)) {
|
|
74
|
+
throw new NexaError_1.NexaError('invalid-argument', 'atomicDecrement() value must be a finite number.');
|
|
75
|
+
}
|
|
76
|
+
return new FieldValue('increment', -Math.abs(n));
|
|
77
|
+
};
|
|
26
78
|
exports.atomicDecrement = atomicDecrement;
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.enableOfflinePersistence = exports.enableIndexedDbPersistence = exports.Firestore = void 0;
|
|
4
|
+
const NexaError_1 = require("../errors/NexaError");
|
|
4
5
|
class Firestore {
|
|
5
6
|
constructor(app) {
|
|
7
|
+
if (!app) {
|
|
8
|
+
throw new NexaError_1.NexaError('invalid-argument', 'Firestore constructor requires a valid NexaApp instance.');
|
|
9
|
+
}
|
|
6
10
|
this.app = app;
|
|
7
11
|
}
|
|
8
12
|
getApp() {
|
|
@@ -11,14 +15,22 @@ class Firestore {
|
|
|
11
15
|
}
|
|
12
16
|
exports.Firestore = Firestore;
|
|
13
17
|
const enableIndexedDbPersistence = async (db) => {
|
|
18
|
+
if (!db) {
|
|
19
|
+
throw new NexaError_1.NexaError('invalid-argument', 'enableIndexedDbPersistence requires a valid NexaApp database instance.');
|
|
20
|
+
}
|
|
21
|
+
if (typeof window !== 'undefined' && typeof window.indexedDB === 'undefined' && typeof indexedDB === 'undefined') {
|
|
22
|
+
throw new NexaError_1.NexaError('unimplemented', 'IndexedDB is not supported in the current runtime environment.');
|
|
23
|
+
}
|
|
24
|
+
if (db._initialized && !db.enablePersistence) {
|
|
25
|
+
throw new NexaError_1.NexaError('failed-precondition', 'Firestore persistence must be enabled before any other Firestore operations are executed.');
|
|
26
|
+
}
|
|
14
27
|
db.enablePersistence = true;
|
|
15
|
-
if (db._initPromise)
|
|
28
|
+
if (db._initPromise) {
|
|
16
29
|
await db._initPromise;
|
|
30
|
+
}
|
|
17
31
|
};
|
|
18
32
|
exports.enableIndexedDbPersistence = enableIndexedDbPersistence;
|
|
19
33
|
const enableOfflinePersistence = async (db) => {
|
|
20
|
-
|
|
21
|
-
if (db._initPromise)
|
|
22
|
-
await db._initPromise;
|
|
34
|
+
return (0, exports.enableIndexedDbPersistence)(db);
|
|
23
35
|
};
|
|
24
36
|
exports.enableOfflinePersistence = enableOfflinePersistence;
|
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.GeoPoint = void 0;
|
|
4
|
+
const NexaError_1 = require("../errors/NexaError");
|
|
4
5
|
class GeoPoint {
|
|
5
6
|
constructor(latitude, longitude) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
if (isNaN(latitude) || latitude < -90 || latitude > 90) {
|
|
9
|
-
throw new Error(`Latitude must be a number between -90 and 90, but got ${latitude}`);
|
|
7
|
+
if (typeof latitude !== 'number' || !Number.isFinite(latitude) || latitude < -90 || latitude > 90) {
|
|
8
|
+
throw new NexaError_1.NexaError('invalid-argument', `Latitude must be a finite number between -90 and 90, but got ${latitude}`);
|
|
10
9
|
}
|
|
11
|
-
if (
|
|
12
|
-
throw new
|
|
10
|
+
if (typeof longitude !== 'number' || !Number.isFinite(longitude) || longitude < -180 || longitude > 180) {
|
|
11
|
+
throw new NexaError_1.NexaError('invalid-argument', `Longitude must be a finite number between -180 and 180, but got ${longitude}`);
|
|
13
12
|
}
|
|
13
|
+
this.latitude = latitude;
|
|
14
|
+
this.longitude = longitude;
|
|
15
|
+
Object.freeze(this);
|
|
14
16
|
}
|
|
15
17
|
isEqual(other) {
|
|
18
|
+
if (!(other instanceof GeoPoint))
|
|
19
|
+
return false;
|
|
16
20
|
return this.latitude === other.latitude && this.longitude === other.longitude;
|
|
17
21
|
}
|
|
22
|
+
toString() {
|
|
23
|
+
return `GeoPoint(latitude=${this.latitude}, longitude=${this.longitude})`;
|
|
24
|
+
}
|
|
18
25
|
toJSON() {
|
|
19
26
|
return { latitude: this.latitude, longitude: this.longitude };
|
|
20
27
|
}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { FieldPath } from './FieldPath';
|
|
2
2
|
import { CollectionReference, Query, QueryConstraint, QuerySnapshot, AggregateField, AggregateSpec, AggregateSpecData, AggregateQuerySnapshot } from '../types/index';
|
|
3
|
+
export declare function getCanonicalQueryKey(collectionPath: string, constraints: QueryConstraint[]): string;
|
|
4
|
+
export declare function validateAndDeduplicateServerDocs(docs: any[]): Array<{
|
|
5
|
+
id: string;
|
|
6
|
+
fields: any;
|
|
7
|
+
}>;
|
|
3
8
|
export declare const query: <T = any>(queryObject: Query<T> | CollectionReference<T>, ...queryConstraints: QueryConstraint[]) => Query<T>;
|
|
4
9
|
export declare const getCachedDocs: <T = any>(queryOrCollection: Query<T> | CollectionReference<T>, fromCache?: boolean) => QuerySnapshot<T>;
|
|
5
10
|
export declare const getDocs: <T = any>(queryOrCollection: Query<T> | CollectionReference<T>) => Promise<QuerySnapshot<T>>;
|