nexabase-console 2.1.3 → 2.1.4
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
CHANGED
|
@@ -92,7 +92,7 @@ export declare class NexaApp {
|
|
|
92
92
|
_ensureFirestoreWebSocket(): void;
|
|
93
93
|
_closeFirestoreSSEIfIdle(): void;
|
|
94
94
|
_closeFirestoreWebSocketIfIdle(): void;
|
|
95
|
-
_notifySnapshotCallbacks(path: string, actionType: string, payload
|
|
95
|
+
_notifySnapshotCallbacks(path: string, actionType: string, payload?: any): void;
|
|
96
96
|
signInWithEmailAndPassword(email: string, password: string): Promise<AuthSession>;
|
|
97
97
|
createUserWithEmailAndPassword(email: string, password: string, name?: string): Promise<AuthSession>;
|
|
98
98
|
sendOtp(email: string): Promise<{
|
package/dist/app/NexaApp.js
CHANGED
|
@@ -46,7 +46,7 @@ class NexaApp {
|
|
|
46
46
|
this.mutationQueue = new MutationQueue_1.MutationQueue(this.projectId, this.indexedDB, this.client);
|
|
47
47
|
this.syncEngine = new SyncEngine_1.SyncEngine(this.projectId, this.mutationQueue, this.sseClient);
|
|
48
48
|
// Realtime & Storage
|
|
49
|
-
const realtimeConn = new RealtimeConnection_1.RealtimeConnection(this.sseClient);
|
|
49
|
+
const realtimeConn = new RealtimeConnection_1.RealtimeConnection(this.sseClient, this.wsClient);
|
|
50
50
|
this.realtimeDatabase = new RealtimeDatabase_1.RealtimeDatabase(this.projectId, this.client, realtimeConn);
|
|
51
51
|
this.storage = new Storage_1.Storage(this.projectId, this.client);
|
|
52
52
|
this._setupCrossTabSync();
|
|
@@ -366,34 +366,44 @@ class NexaApp {
|
|
|
366
366
|
const targetDocPath = docPath || rawPath;
|
|
367
367
|
const isDelete = type === 'document_deleted' || action === 'delete' || type === 'delete';
|
|
368
368
|
if (targetDocPath && typeof targetDocPath === 'string') {
|
|
369
|
+
const cleanDocPath = targetDocPath.replace(/^\/+|\/+$/g, '');
|
|
369
370
|
if (isDelete) {
|
|
370
|
-
this._deleteCache(
|
|
371
|
+
this._deleteCache(cleanDocPath);
|
|
371
372
|
}
|
|
372
|
-
else if (data) {
|
|
373
|
-
this._setCache(
|
|
373
|
+
else if (data !== undefined && data !== null) {
|
|
374
|
+
this._setCache(cleanDocPath, data);
|
|
374
375
|
}
|
|
375
|
-
const parts =
|
|
376
|
+
const parts = cleanDocPath.split('/');
|
|
376
377
|
const colPath = parts.length > 1 ? parts.slice(0, -1).join('/') : '';
|
|
377
|
-
this._notifySnapshotCallbacks(
|
|
378
|
+
this._notifySnapshotCallbacks(cleanDocPath, isDelete ? 'document_deleted' : 'document_written', data);
|
|
378
379
|
if (colPath) {
|
|
379
380
|
this._notifySnapshotCallbacks(colPath, isDelete ? 'document_deleted' : 'document_written', data);
|
|
380
381
|
}
|
|
381
382
|
}
|
|
382
383
|
else if (collectionPath && typeof collectionPath === 'string') {
|
|
383
|
-
|
|
384
|
+
const cleanColPath = collectionPath.replace(/^\/+|\/+$/g, '');
|
|
385
|
+
this._notifySnapshotCallbacks(cleanColPath, 'server_update', data);
|
|
384
386
|
}
|
|
385
387
|
}
|
|
386
388
|
_ensureFirestoreSSE() {
|
|
387
389
|
if (this._firestoreListening)
|
|
388
390
|
return;
|
|
389
391
|
this._firestoreListening = true;
|
|
392
|
+
// Listen to WebSocketClient
|
|
390
393
|
const unsub1 = this.wsClient.addListener('data_changed', (payload) => {
|
|
391
394
|
this._handleServerFirestoreChange(payload);
|
|
392
395
|
});
|
|
393
396
|
const unsub2 = this.wsClient.addListener('firestore_changed', (payload) => {
|
|
394
397
|
this._handleServerFirestoreChange(payload);
|
|
395
398
|
});
|
|
396
|
-
|
|
399
|
+
// Also listen to SSEClient
|
|
400
|
+
const unsub3 = this.sseClient.addListener('data_changed', (payload) => {
|
|
401
|
+
this._handleServerFirestoreChange(payload);
|
|
402
|
+
});
|
|
403
|
+
const unsub4 = this.sseClient.addListener('firestore_changed', (payload) => {
|
|
404
|
+
this._handleServerFirestoreChange(payload);
|
|
405
|
+
});
|
|
406
|
+
this._firestoreUnsubscribes.push(unsub1, unsub2, unsub3, unsub4);
|
|
397
407
|
}
|
|
398
408
|
_ensureFirestoreWebSocket() {
|
|
399
409
|
this._ensureFirestoreSSE();
|
|
@@ -411,14 +421,28 @@ class NexaApp {
|
|
|
411
421
|
_notifySnapshotCallbacks(path, actionType, payload) {
|
|
412
422
|
if (!path || typeof path !== 'string')
|
|
413
423
|
return;
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
424
|
+
const cleanPath = path.replace(/^\/+|\/+$/g, '');
|
|
425
|
+
Object.entries(this._snapshotCallbacks).forEach(([cbKey, callback]) => {
|
|
426
|
+
let type = '';
|
|
427
|
+
let targetPath = '';
|
|
428
|
+
if (cbKey.includes('::')) {
|
|
429
|
+
const parts = cbKey.split('::');
|
|
430
|
+
type = parts[0];
|
|
431
|
+
targetPath = parts.slice(2).join('::');
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
const firstUnderscore = cbKey.indexOf('_');
|
|
435
|
+
const lastUnderscore = cbKey.lastIndexOf('_');
|
|
436
|
+
type = cbKey.substring(0, firstUnderscore);
|
|
437
|
+
targetPath = cbKey.substring(lastUnderscore + 1);
|
|
438
|
+
}
|
|
439
|
+
const cleanTargetPath = (targetPath || '').replace(/^\/+|\/+$/g, '');
|
|
440
|
+
if (type === 'document' && cleanTargetPath === cleanPath) {
|
|
441
|
+
callback(payload);
|
|
419
442
|
}
|
|
420
|
-
else if ((
|
|
421
|
-
|
|
443
|
+
else if ((type === 'collection' || type === 'query') &&
|
|
444
|
+
(cleanPath === cleanTargetPath || cleanPath.startsWith(cleanTargetPath + '/'))) {
|
|
445
|
+
callback(payload);
|
|
422
446
|
}
|
|
423
447
|
});
|
|
424
448
|
}
|
|
@@ -79,9 +79,9 @@ const onSnapshot = (ref, callback) => {
|
|
|
79
79
|
}
|
|
80
80
|
const db = ref.db;
|
|
81
81
|
let active = true;
|
|
82
|
-
const pathKey = ref.path;
|
|
82
|
+
const pathKey = ref.path.replace(/^\/+|\/+$/g, '');
|
|
83
83
|
const listenerId = `${Date.now()}_${Math.random().toString(36).slice(2)}_${++listenerSequence}`;
|
|
84
|
-
const keyToClean = `${ref.type}
|
|
84
|
+
const keyToClean = `${ref.type}::${listenerId}::${pathKey}`;
|
|
85
85
|
let isInitial = true;
|
|
86
86
|
let lastData = undefined;
|
|
87
87
|
let lastDocsForChanges = [];
|
|
@@ -115,13 +115,11 @@ const onSnapshot = (ref, callback) => {
|
|
|
115
115
|
};
|
|
116
116
|
db._snapshotCallbacks[keyToClean] = triggerCallback;
|
|
117
117
|
triggerCallback();
|
|
118
|
-
// Unified transport coordination:
|
|
118
|
+
// Unified transport coordination: Always ensure listening on change events & subscribe path
|
|
119
|
+
db._ensureFirestoreWebSocket();
|
|
119
120
|
if (db.wsClient && typeof db.wsClient.subscribe === 'function') {
|
|
120
121
|
db.wsClient.subscribe(ref.path);
|
|
121
122
|
}
|
|
122
|
-
else {
|
|
123
|
-
db._ensureFirestoreSSE();
|
|
124
|
-
}
|
|
125
123
|
(async () => {
|
|
126
124
|
if (db._initPromise)
|
|
127
125
|
await db._initPromise;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { SSEClient } from '../transport/SSEClient';
|
|
1
|
+
import { SSEClient, WebSocketClient } from '../transport/SSEClient';
|
|
2
2
|
export declare class RealtimeConnection {
|
|
3
3
|
private sseClient;
|
|
4
|
-
|
|
4
|
+
private wsClient?;
|
|
5
|
+
constructor(sseClient: SSEClient, wsClient?: WebSocketClient);
|
|
5
6
|
subscribeToPath(path: string, callback: (value: any) => void): () => void;
|
|
6
7
|
close(): void;
|
|
7
8
|
}
|
|
@@ -2,15 +2,40 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RealtimeConnection = void 0;
|
|
4
4
|
class RealtimeConnection {
|
|
5
|
-
constructor(sseClient) {
|
|
5
|
+
constructor(sseClient, wsClient) {
|
|
6
6
|
this.sseClient = sseClient;
|
|
7
|
+
this.wsClient = wsClient;
|
|
7
8
|
}
|
|
8
9
|
subscribeToPath(path, callback) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
const cleanPath = (path || '').replace(/^\/+|\/+$/g, '');
|
|
11
|
+
if (this.wsClient && typeof this.wsClient.subscribe === 'function') {
|
|
12
|
+
this.wsClient.subscribe(cleanPath);
|
|
13
|
+
}
|
|
14
|
+
const unsubWS = this.wsClient
|
|
15
|
+
? this.wsClient.addListener('data_changed', (payload) => {
|
|
16
|
+
if (payload) {
|
|
17
|
+
const p = (payload.path || payload.docPath || '').replace(/^\/+|\/+$/g, '');
|
|
18
|
+
if (p === cleanPath) {
|
|
19
|
+
callback(payload.value !== undefined ? payload.value : payload.data);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
: () => { };
|
|
24
|
+
const unsubSSE = this.sseClient.addListener('data_changed', (payload) => {
|
|
25
|
+
if (payload) {
|
|
26
|
+
const p = (payload.path || payload.docPath || '').replace(/^\/+|\/+$/g, '');
|
|
27
|
+
if (p === cleanPath) {
|
|
28
|
+
callback(payload.value !== undefined ? payload.value : payload.data);
|
|
29
|
+
}
|
|
12
30
|
}
|
|
13
31
|
});
|
|
32
|
+
return () => {
|
|
33
|
+
unsubWS();
|
|
34
|
+
unsubSSE();
|
|
35
|
+
if (this.wsClient && typeof this.wsClient.unsubscribe === 'function') {
|
|
36
|
+
this.wsClient.unsubscribe(cleanPath);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
14
39
|
}
|
|
15
40
|
close() {
|
|
16
41
|
this.sseClient.close();
|
package/package.json
CHANGED