nexabase-console 2.0.8 → 2.1.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.
@@ -57,6 +57,8 @@ export declare class NexaApp {
57
57
  action: 'set' | 'patch' | 'delete';
58
58
  serverDocument?: any;
59
59
  updateTime?: string;
60
+ mutationData?: any;
61
+ merge?: boolean;
60
62
  }): Promise<{
61
63
  data: any | null;
62
64
  hasPendingWrites: boolean;
@@ -93,7 +93,8 @@ class NexaApp {
93
93
  }
94
94
  }
95
95
  async _setCache(path, data) {
96
- await this.localStore.set(path, data);
96
+ const revived = (0, QueryUtils_1.reviveNexaData)(data);
97
+ await this.localStore.set(path, revived);
97
98
  }
98
99
  async _deleteCache(path) {
99
100
  await this.localStore.delete(path);
@@ -165,13 +166,30 @@ class NexaApp {
165
166
  const db = this.indexedDB.getRawDB();
166
167
  const queue = this.mutationQueue.inMemoryQueue;
167
168
  const jobIndex = queue.findIndex((j) => j.id === mutationId);
168
- if (jobIndex !== -1)
169
+ let jobData = null;
170
+ if (jobIndex !== -1) {
171
+ jobData = queue[jobIndex];
169
172
  queue.splice(jobIndex, 1);
173
+ }
170
174
  if (options.action === 'delete') {
171
175
  this.localStore.getServerBaseCache()[path] = null;
172
176
  }
173
177
  else if (serverDocument && serverDocument.fields) {
174
- this.localStore.getServerBaseCache()[path] = serverDocument.fields;
178
+ this.localStore.getServerBaseCache()[path] = (0, QueryUtils_1.reviveNexaData)(serverDocument.fields);
179
+ }
180
+ else {
181
+ // PROMOTION: If server returned success: true without serverDocument.fields (lightweight ACK),
182
+ // promote the local mutation payload to Server Base Cache so the document does not revert to null!
183
+ const rawData = (jobData ? jobData.data : options.mutationData) || {};
184
+ const isMerge = jobData ? jobData.merge : options.merge;
185
+ let currentBase = this.localStore.getServerBaseCache()[path];
186
+ currentBase = currentBase !== undefined && currentBase !== null ? (0, QueryUtils_1.cloneNexaData)(currentBase) : currentBase;
187
+ if (options.action === 'set' && !isMerge) {
188
+ this.localStore.getServerBaseCache()[path] = (0, QueryUtils_1.reviveNexaData)((0, helpers_1.applyDataTransforms)({}, rawData));
189
+ }
190
+ else {
191
+ this.localStore.getServerBaseCache()[path] = (0, QueryUtils_1.reviveNexaData)((0, helpers_1.applyDataTransforms)(currentBase || {}, rawData));
192
+ }
175
193
  }
176
194
  const view = this._calculateLocalView(path);
177
195
  const rebasedData = view.data;
@@ -258,7 +276,7 @@ class NexaApp {
258
276
  for (const doc of serverDocs) {
259
277
  const docPath = `${collectionPath}/${doc.id}`;
260
278
  serverIds.add(docPath);
261
- let data = doc.fields;
279
+ let data = (0, QueryUtils_1.reviveNexaData)(doc.fields);
262
280
  const jobs = pendingMutations.get(docPath);
263
281
  if (jobs) {
264
282
  for (const job of jobs) {
@@ -1,4 +1,5 @@
1
1
  export declare function isDirectChildDocument(collectionPath: string, documentPath: string): boolean;
2
+ export declare function reviveNexaData(data: any): any;
2
3
  export declare function cloneNexaData(data: any): any;
3
4
  export declare function compareNexaValues(a: any, b: any): number;
4
5
  export declare function serializeConstraint(c: any): any;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isDirectChildDocument = isDirectChildDocument;
4
+ exports.reviveNexaData = reviveNexaData;
4
5
  exports.cloneNexaData = cloneNexaData;
5
6
  exports.compareNexaValues = compareNexaValues;
6
7
  exports.serializeConstraint = serializeConstraint;
@@ -10,6 +11,31 @@ function isDirectChildDocument(collectionPath, documentPath) {
10
11
  return false;
11
12
  return documentPath.split('/').length === collectionPath.split('/').length + 1;
12
13
  }
14
+ function reviveNexaData(data) {
15
+ if (data === null || data === undefined)
16
+ return data;
17
+ if (data instanceof Timestamp_1.Timestamp)
18
+ return new Timestamp_1.Timestamp(data.seconds, data.nanoseconds);
19
+ if (Array.isArray(data))
20
+ return data.map(reviveNexaData);
21
+ if (typeof data === 'object') {
22
+ if (typeof data.isEqual === 'function' && typeof data.toMillis === 'function') {
23
+ return data;
24
+ }
25
+ // Revive timestamp
26
+ if (typeof data.seconds === 'number' && typeof data.nanoseconds === 'number' && Object.keys(data).length <= 2) {
27
+ return new Timestamp_1.Timestamp(data.seconds, data.nanoseconds);
28
+ }
29
+ const cloned = {};
30
+ for (const k in data) {
31
+ if (Object.prototype.hasOwnProperty.call(data, k)) {
32
+ cloned[k] = reviveNexaData(data[k]);
33
+ }
34
+ }
35
+ return cloned;
36
+ }
37
+ return data;
38
+ }
13
39
  function cloneNexaData(data) {
14
40
  if (data === null || data === undefined)
15
41
  return data;
@@ -105,6 +105,7 @@ const executeWriteMutation = async (docRef, action, data, options) => {
105
105
  res = await db.wsClient.send('firestore_write', {
106
106
  action: action === 'patch' ? 'update' : action,
107
107
  docPath: docRef.path,
108
+ projectId: db.projectId,
108
109
  data,
109
110
  merge: options?.merge,
110
111
  idempotencyKey: key,
@@ -158,9 +159,7 @@ const executeWriteMutation = async (docRef, action, data, options) => {
158
159
  }
159
160
  }
160
161
  // Phase 4: ACK Validation
161
- const isValidAck = res && res.success &&
162
- (action === 'delete' || (res.document && res.document.fields)) &&
163
- (action !== 'delete' ? res.document.path === docRef.path : true);
162
+ const isValidAck = res && res.success;
164
163
  if (!isValidAck) {
165
164
  console.error('[NexaBase] Protocol error: Invalid server ACK:', res);
166
165
  db.unmarkInflight(docRef.path, mutationId);
@@ -174,7 +173,9 @@ const executeWriteMutation = async (docRef, action, data, options) => {
174
173
  path: docRef.path,
175
174
  action,
176
175
  serverDocument: res.document,
177
- updateTime: res.document?.updateTime
176
+ updateTime: res.document?.updateTime,
177
+ mutationData: data,
178
+ merge: options?.merge
178
179
  });
179
180
  }
180
181
  catch (ackError) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexabase-console",
3
- "version": "2.0.8",
3
+ "version": "2.1.0",
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",