nexabase-console 2.1.4 → 2.1.5

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.
@@ -36,6 +36,7 @@ export declare class NexaApp {
36
36
  _activeQueryTimestamps: Map<string, number>;
37
37
  constructor(config: NexaConfig);
38
38
  get _firestoreCache(): Record<string, any>;
39
+ private _setupVisibilityResync;
39
40
  private _setupCrossTabSync;
40
41
  _broadcastLocalMutation(path: string, action: string, data?: any): void;
41
42
  getPendingWritesCount(): number;
@@ -50,19 +50,47 @@ class NexaApp {
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();
53
+ this._setupVisibilityResync();
53
54
  }
54
55
  get _firestoreCache() {
55
56
  return this.localStore.getMemoryCache();
56
57
  }
58
+ _setupVisibilityResync() {
59
+ if (typeof document !== 'undefined' && typeof document.addEventListener === 'function') {
60
+ document.addEventListener('visibilitychange', () => {
61
+ if (document.visibilityState === 'visible') {
62
+ // Re-ensure SSE and WS when coming back from background
63
+ if (this._firestoreListening) {
64
+ if (this.wsClient && typeof this.wsClient.ensureConnected === 'function') {
65
+ this.wsClient.ensureConnected();
66
+ }
67
+ if (this.sseClient && typeof this.sseClient.ensureConnected === 'function') {
68
+ this.sseClient.ensureConnected();
69
+ }
70
+ // Notify server that we need latest changes by simulating subscribe again for each path?
71
+ // wsClient handles this on resync event.
72
+ }
73
+ // Optionally sync offline queue
74
+ this._syncOfflineQueue().catch(console.error);
75
+ }
76
+ });
77
+ }
78
+ }
57
79
  _setupCrossTabSync() {
58
80
  this.syncEngine.listenCrossTab((path, action, data) => {
81
+ const cleanPath = path.replace(/^\/+|\/+$/g, '');
59
82
  if (action === 'delete') {
60
- this.localStore.delete(path);
83
+ this.localStore.delete(cleanPath);
61
84
  }
62
85
  else if (data) {
63
- this.localStore.set(path, data);
86
+ this.localStore.set(cleanPath, data);
87
+ }
88
+ this._notifySnapshotCallbacks(cleanPath, action === 'delete' ? 'document_deleted' : 'document_written', data);
89
+ const parts = cleanPath.split('/');
90
+ const colPath = parts.length > 1 ? parts.slice(0, -1).join('/') : '';
91
+ if (colPath) {
92
+ this._notifySnapshotCallbacks(colPath, action === 'delete' ? 'document_deleted' : 'document_written', data);
64
93
  }
65
- this._notifySnapshotCallbacks(path, action === 'delete' ? 'document_deleted' : 'document_written', data);
66
94
  });
67
95
  }
68
96
  _broadcastLocalMutation(path, action, data) {
@@ -48,14 +48,20 @@ const normalizeError = (error) => {
48
48
  };
49
49
  };
50
50
  const safelyNotifyMutation = (db, path, action, data, metadata) => {
51
+ const cleanPath = path.replace(/^\/+|\/+$/g, '');
51
52
  try {
52
- db._broadcastLocalMutation(path, action, data, metadata);
53
+ db._broadcastLocalMutation(cleanPath, action, data, metadata);
53
54
  }
54
55
  catch (e) {
55
56
  console.error('[NexaBase] Listener error:', e);
56
57
  }
57
58
  try {
58
- db._notifySnapshotCallbacks(path, action === 'delete' ? 'document_deleted' : 'document_written', data, metadata);
59
+ db._notifySnapshotCallbacks(cleanPath, action === 'delete' ? 'document_deleted' : 'document_written', data, metadata);
60
+ const parts = cleanPath.split('/');
61
+ const colPath = parts.length > 1 ? parts.slice(0, -1).join('/') : '';
62
+ if (colPath) {
63
+ db._notifySnapshotCallbacks(colPath, action === 'delete' ? 'document_deleted' : 'document_written', data, metadata);
64
+ }
59
65
  }
60
66
  catch (e) {
61
67
  console.error('[NexaBase] Listener error:', e);
@@ -1882,6 +1882,7 @@ class WebSocketClient {
1882
1882
  return;
1883
1883
  }
1884
1884
  if (document.visibilityState === 'visible') {
1885
+ this.dispatch('resync', { reason: 'visibility_change' });
1885
1886
  if (!this.isLeader && this._coordinationMode === 'shared') {
1886
1887
  this.postBroadcast('follower_heartbeat', {
1887
1888
  globalListenersCount: this.getGlobalListenersCount(),
@@ -1893,6 +1894,9 @@ class WebSocketClient {
1893
1894
  });
1894
1895
  this.postBroadcast('follower_sync_request');
1895
1896
  }
1897
+ if (this.isLeader && this._socket && !this._socket.connected) {
1898
+ this._socket.connect();
1899
+ }
1896
1900
  if (this.hasLocalNeeds() && this._state === 'idle') {
1897
1901
  this.ensureConnected();
1898
1902
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexabase-console",
3
- "version": "2.1.4",
3
+ "version": "2.1.5",
4
4
  "description": "SDK Client resmi untuk NexaBase: Platform Sinkronisasi NoSQL, Realtime, File Storage, & Autentikasi Offline-First.",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",