@legendapp/state 3.0.0-beta.14 → 3.0.0-beta.16

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/index.d.mts CHANGED
@@ -248,6 +248,7 @@ interface UpdateFnParams<T = any> {
248
248
  value: T;
249
249
  mode?: GetMode;
250
250
  lastSync?: number | undefined;
251
+ changes?: Change[];
251
252
  }
252
253
  interface UpdateSetFnParams<T = any> extends UpdateFnParams<T> {
253
254
  lastSync?: never;
package/index.d.ts CHANGED
@@ -248,6 +248,7 @@ interface UpdateFnParams<T = any> {
248
248
  value: T;
249
249
  mode?: GetMode;
250
250
  lastSync?: number | undefined;
251
+ changes?: Change[];
251
252
  }
252
253
  interface UpdateSetFnParams<T = any> extends UpdateFnParams<T> {
253
254
  lastSync?: never;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/state",
3
- "version": "3.0.0-beta.14",
3
+ "version": "3.0.0-beta.16",
4
4
  "description": "legend-state",
5
5
  "sideEffects": false,
6
6
  "private": false,
@@ -30,7 +30,7 @@ var queuedRetries = {
30
30
  update: /* @__PURE__ */ new Map(),
31
31
  delete: /* @__PURE__ */ new Map()
32
32
  };
33
- function retrySet(params, retry, action, itemKey, itemValue, actionFn, saveResult) {
33
+ function retrySet(params, retry, action, itemKey, itemValue, change, actionFn, saveResult) {
34
34
  if (action === "delete") {
35
35
  if (queuedRetries.create.has(itemKey)) {
36
36
  queuedRetries.create.delete(itemKey);
@@ -48,13 +48,14 @@ function retrySet(params, retry, action, itemKey, itemValue, actionFn, saveResul
48
48
  itemValue = Object.assign(queuedRetry, itemValue);
49
49
  }
50
50
  queuedRetries[action].set(itemKey, itemValue);
51
+ const paramsWithChanges = { ...params, changes: [change] };
51
52
  return runWithRetry(
52
- params,
53
+ paramsWithChanges,
53
54
  retry,
54
55
  "create_" + itemKey,
55
- () => actionFn(itemValue, params).then((result) => {
56
+ () => actionFn(itemValue, paramsWithChanges).then((result) => {
56
57
  queuedRetries[action].delete(itemKey);
57
- return saveResult(itemKey, itemValue, result, true);
58
+ return saveResult(itemKey, itemValue, result, true, change);
58
59
  })
59
60
  );
60
61
  }
@@ -179,6 +180,7 @@ function syncedCrud(props) {
179
180
  const creates = /* @__PURE__ */ new Map();
180
181
  const updates = /* @__PURE__ */ new Map();
181
182
  const deletes = /* @__PURE__ */ new Set();
183
+ const changesById = /* @__PURE__ */ new Map();
182
184
  const getUpdateValue = (itemValue, prev) => {
183
185
  return updatePartial ? Object.assign(
184
186
  sync.diffObjects(
@@ -200,6 +202,7 @@ function syncedCrud(props) {
200
202
  id = ensureId(value, fieldId, generateId);
201
203
  }
202
204
  if (id) {
205
+ changesById.set(id, change);
203
206
  if (pendingCreates.has(id)) {
204
207
  isCreate = false;
205
208
  }
@@ -229,6 +232,7 @@ function syncedCrud(props) {
229
232
  }
230
233
  } else if (path.length === 0) {
231
234
  deletes.add(prevAtPath);
235
+ changesById.set(prevAtPath[fieldId], change);
232
236
  }
233
237
  } else {
234
238
  let itemsChanged = [];
@@ -253,6 +257,7 @@ function syncedCrud(props) {
253
257
  if (!itemValue) {
254
258
  if (path.length === 1 && prevAtPath) {
255
259
  deletes.add(prevAtPath);
260
+ changesById.set(prevAtPath[fieldId], change);
256
261
  }
257
262
  } else {
258
263
  const previous = state.setAtPath(
@@ -274,17 +279,18 @@ function syncedCrud(props) {
274
279
  console.error("[legend-state]: added item without an id");
275
280
  }
276
281
  if (createFn) {
277
- pendingCreates.add(item[fieldId]);
278
- creates.set(item[fieldId], item);
282
+ const id = item[fieldId];
283
+ changesById.set(id, change);
284
+ pendingCreates.add(id);
285
+ creates.set(id, item);
279
286
  } else {
280
287
  console.warn("[legend-state] missing create function");
281
288
  }
282
289
  } else {
283
290
  if (updateFn) {
284
- updates.set(
285
- item[fieldId],
286
- updates.has(item[fieldId]) ? Object.assign(updates.get(item[fieldId]), item) : item
287
- );
291
+ const id = item[fieldId];
292
+ changesById.set(id, change);
293
+ updates.set(id, updates.has(id) ? Object.assign(updates.get(id), item) : item);
288
294
  } else {
289
295
  console.warn("[legend-state] missing update function");
290
296
  }
@@ -292,7 +298,7 @@ function syncedCrud(props) {
292
298
  });
293
299
  }
294
300
  });
295
- const saveResult = async (itemKey, input, data, isCreate) => {
301
+ const saveResult = async (itemKey, input, data, isCreate, change) => {
296
302
  var _a;
297
303
  if (data) {
298
304
  let saved = (transform == null ? void 0 : transform.load) ? await transform.load(data, "set") : data;
@@ -319,7 +325,7 @@ function syncedCrud(props) {
319
325
  if (
320
326
  // value is already the new value, can ignore
321
327
  saved[key] === c || // user has changed local value
322
- key !== fieldId && i !== c
328
+ key !== fieldId && i !== void 0 && i !== c
323
329
  ) {
324
330
  delete saved[key];
325
331
  }
@@ -340,7 +346,8 @@ function syncedCrud(props) {
340
346
  if (value2 !== void 0) {
341
347
  update({
342
348
  value: value2,
343
- mode: "merge"
349
+ mode: "merge",
350
+ changes: [change]
344
351
  });
345
352
  }
346
353
  }
@@ -353,11 +360,18 @@ function syncedCrud(props) {
353
360
  await waitForSet(waitForSetParam, changes, itemValue, { type: "create" });
354
361
  }
355
362
  const createObj = await transformOut(itemValue, transform == null ? void 0 : transform.save);
356
- return retrySet(params, retry, "create", itemKey, createObj, createFn, saveResult).then(
357
- () => {
358
- pendingCreates.delete(itemKey);
359
- }
360
- );
363
+ return retrySet(
364
+ params,
365
+ retry,
366
+ "create",
367
+ itemKey,
368
+ createObj,
369
+ changesById.get(itemKey),
370
+ createFn,
371
+ saveResult
372
+ ).then(() => {
373
+ pendingCreates.delete(itemKey);
374
+ });
361
375
  }),
362
376
  // Handle updates
363
377
  ...Array.from(updates).map(async ([itemKey, itemValue]) => {
@@ -366,7 +380,16 @@ function syncedCrud(props) {
366
380
  }
367
381
  const changed = await transformOut(itemValue, transform == null ? void 0 : transform.save);
368
382
  if (Object.keys(changed).length > 0) {
369
- return retrySet(params, retry, "update", itemKey, changed, updateFn, saveResult);
383
+ return retrySet(
384
+ params,
385
+ retry,
386
+ "update",
387
+ itemKey,
388
+ changed,
389
+ changesById.get(itemKey),
390
+ updateFn,
391
+ saveResult
392
+ );
370
393
  }
371
394
  }),
372
395
  // Handle deletes
@@ -374,8 +397,8 @@ function syncedCrud(props) {
374
397
  if (waitForSetParam) {
375
398
  await waitForSet(waitForSetParam, changes, valuePrevious, { type: "delete" });
376
399
  }
377
- const valueId = valuePrevious[fieldId];
378
- if (!valueId) {
400
+ const itemKey = valuePrevious[fieldId];
401
+ if (!itemKey) {
379
402
  console.error("[legend-state]: deleting item without an id");
380
403
  return;
381
404
  }
@@ -384,8 +407,9 @@ function syncedCrud(props) {
384
407
  params,
385
408
  retry,
386
409
  "delete",
387
- valueId,
410
+ itemKey,
388
411
  valuePrevious,
412
+ changesById.get(itemKey),
389
413
  deleteFn,
390
414
  saveResult
391
415
  );
@@ -395,8 +419,9 @@ function syncedCrud(props) {
395
419
  params,
396
420
  retry,
397
421
  "delete",
398
- valueId,
399
- { [fieldId]: valueId, [fieldDeleted]: true },
422
+ itemKey,
423
+ { [fieldId]: itemKey, [fieldDeleted]: true },
424
+ changesById.get(itemKey),
400
425
  updateFn,
401
426
  saveResult
402
427
  );
@@ -28,7 +28,7 @@ var queuedRetries = {
28
28
  update: /* @__PURE__ */ new Map(),
29
29
  delete: /* @__PURE__ */ new Map()
30
30
  };
31
- function retrySet(params, retry, action, itemKey, itemValue, actionFn, saveResult) {
31
+ function retrySet(params, retry, action, itemKey, itemValue, change, actionFn, saveResult) {
32
32
  if (action === "delete") {
33
33
  if (queuedRetries.create.has(itemKey)) {
34
34
  queuedRetries.create.delete(itemKey);
@@ -46,13 +46,14 @@ function retrySet(params, retry, action, itemKey, itemValue, actionFn, saveResul
46
46
  itemValue = Object.assign(queuedRetry, itemValue);
47
47
  }
48
48
  queuedRetries[action].set(itemKey, itemValue);
49
+ const paramsWithChanges = { ...params, changes: [change] };
49
50
  return runWithRetry(
50
- params,
51
+ paramsWithChanges,
51
52
  retry,
52
53
  "create_" + itemKey,
53
- () => actionFn(itemValue, params).then((result) => {
54
+ () => actionFn(itemValue, paramsWithChanges).then((result) => {
54
55
  queuedRetries[action].delete(itemKey);
55
- return saveResult(itemKey, itemValue, result, true);
56
+ return saveResult(itemKey, itemValue, result, true, change);
56
57
  })
57
58
  );
58
59
  }
@@ -177,6 +178,7 @@ function syncedCrud(props) {
177
178
  const creates = /* @__PURE__ */ new Map();
178
179
  const updates = /* @__PURE__ */ new Map();
179
180
  const deletes = /* @__PURE__ */ new Set();
181
+ const changesById = /* @__PURE__ */ new Map();
180
182
  const getUpdateValue = (itemValue, prev) => {
181
183
  return updatePartial ? Object.assign(
182
184
  diffObjects(
@@ -198,6 +200,7 @@ function syncedCrud(props) {
198
200
  id = ensureId(value, fieldId, generateId);
199
201
  }
200
202
  if (id) {
203
+ changesById.set(id, change);
201
204
  if (pendingCreates.has(id)) {
202
205
  isCreate = false;
203
206
  }
@@ -227,6 +230,7 @@ function syncedCrud(props) {
227
230
  }
228
231
  } else if (path.length === 0) {
229
232
  deletes.add(prevAtPath);
233
+ changesById.set(prevAtPath[fieldId], change);
230
234
  }
231
235
  } else {
232
236
  let itemsChanged = [];
@@ -251,6 +255,7 @@ function syncedCrud(props) {
251
255
  if (!itemValue) {
252
256
  if (path.length === 1 && prevAtPath) {
253
257
  deletes.add(prevAtPath);
258
+ changesById.set(prevAtPath[fieldId], change);
254
259
  }
255
260
  } else {
256
261
  const previous = setAtPath(
@@ -272,17 +277,18 @@ function syncedCrud(props) {
272
277
  console.error("[legend-state]: added item without an id");
273
278
  }
274
279
  if (createFn) {
275
- pendingCreates.add(item[fieldId]);
276
- creates.set(item[fieldId], item);
280
+ const id = item[fieldId];
281
+ changesById.set(id, change);
282
+ pendingCreates.add(id);
283
+ creates.set(id, item);
277
284
  } else {
278
285
  console.warn("[legend-state] missing create function");
279
286
  }
280
287
  } else {
281
288
  if (updateFn) {
282
- updates.set(
283
- item[fieldId],
284
- updates.has(item[fieldId]) ? Object.assign(updates.get(item[fieldId]), item) : item
285
- );
289
+ const id = item[fieldId];
290
+ changesById.set(id, change);
291
+ updates.set(id, updates.has(id) ? Object.assign(updates.get(id), item) : item);
286
292
  } else {
287
293
  console.warn("[legend-state] missing update function");
288
294
  }
@@ -290,7 +296,7 @@ function syncedCrud(props) {
290
296
  });
291
297
  }
292
298
  });
293
- const saveResult = async (itemKey, input, data, isCreate) => {
299
+ const saveResult = async (itemKey, input, data, isCreate, change) => {
294
300
  var _a;
295
301
  if (data) {
296
302
  let saved = (transform == null ? void 0 : transform.load) ? await transform.load(data, "set") : data;
@@ -317,7 +323,7 @@ function syncedCrud(props) {
317
323
  if (
318
324
  // value is already the new value, can ignore
319
325
  saved[key] === c || // user has changed local value
320
- key !== fieldId && i !== c
326
+ key !== fieldId && i !== void 0 && i !== c
321
327
  ) {
322
328
  delete saved[key];
323
329
  }
@@ -338,7 +344,8 @@ function syncedCrud(props) {
338
344
  if (value2 !== void 0) {
339
345
  update({
340
346
  value: value2,
341
- mode: "merge"
347
+ mode: "merge",
348
+ changes: [change]
342
349
  });
343
350
  }
344
351
  }
@@ -351,11 +358,18 @@ function syncedCrud(props) {
351
358
  await waitForSet(waitForSetParam, changes, itemValue, { type: "create" });
352
359
  }
353
360
  const createObj = await transformOut(itemValue, transform == null ? void 0 : transform.save);
354
- return retrySet(params, retry, "create", itemKey, createObj, createFn, saveResult).then(
355
- () => {
356
- pendingCreates.delete(itemKey);
357
- }
358
- );
361
+ return retrySet(
362
+ params,
363
+ retry,
364
+ "create",
365
+ itemKey,
366
+ createObj,
367
+ changesById.get(itemKey),
368
+ createFn,
369
+ saveResult
370
+ ).then(() => {
371
+ pendingCreates.delete(itemKey);
372
+ });
359
373
  }),
360
374
  // Handle updates
361
375
  ...Array.from(updates).map(async ([itemKey, itemValue]) => {
@@ -364,7 +378,16 @@ function syncedCrud(props) {
364
378
  }
365
379
  const changed = await transformOut(itemValue, transform == null ? void 0 : transform.save);
366
380
  if (Object.keys(changed).length > 0) {
367
- return retrySet(params, retry, "update", itemKey, changed, updateFn, saveResult);
381
+ return retrySet(
382
+ params,
383
+ retry,
384
+ "update",
385
+ itemKey,
386
+ changed,
387
+ changesById.get(itemKey),
388
+ updateFn,
389
+ saveResult
390
+ );
368
391
  }
369
392
  }),
370
393
  // Handle deletes
@@ -372,8 +395,8 @@ function syncedCrud(props) {
372
395
  if (waitForSetParam) {
373
396
  await waitForSet(waitForSetParam, changes, valuePrevious, { type: "delete" });
374
397
  }
375
- const valueId = valuePrevious[fieldId];
376
- if (!valueId) {
398
+ const itemKey = valuePrevious[fieldId];
399
+ if (!itemKey) {
377
400
  console.error("[legend-state]: deleting item without an id");
378
401
  return;
379
402
  }
@@ -382,8 +405,9 @@ function syncedCrud(props) {
382
405
  params,
383
406
  retry,
384
407
  "delete",
385
- valueId,
408
+ itemKey,
386
409
  valuePrevious,
410
+ changesById.get(itemKey),
387
411
  deleteFn,
388
412
  saveResult
389
413
  );
@@ -393,8 +417,9 @@ function syncedCrud(props) {
393
417
  params,
394
418
  retry,
395
419
  "delete",
396
- valueId,
397
- { [fieldId]: valueId, [fieldDeleted]: true },
420
+ itemKey,
421
+ { [fieldId]: itemKey, [fieldDeleted]: true },
422
+ changesById.get(itemKey),
398
423
  updateFn,
399
424
  saveResult
400
425
  );
@@ -13,6 +13,7 @@ type APIError = {
13
13
  type: string;
14
14
  message: string;
15
15
  requestId?: string;
16
+ error?: Error;
16
17
  };
17
18
  type APIResult<T> = Result<T, APIError>;
18
19
  type Data<T> = {
@@ -13,6 +13,7 @@ type APIError = {
13
13
  type: string;
14
14
  message: string;
15
15
  requestId?: string;
16
+ error?: Error;
16
17
  };
17
18
  type APIResult<T> = Result<T, APIError>;
18
19
  type Data<T> = {
@@ -54,11 +54,14 @@ async function ensureAuthToken(props, force) {
54
54
  return isAuthed;
55
55
  }
56
56
  async function handleApiError(props, error) {
57
+ var _a;
57
58
  if (error.type === "unauthorized" || error.type === "forbidden") {
58
59
  console.warn("Keel token expired, refreshing...");
59
60
  isAuthed$.set(false);
60
61
  await ensureAuthToken(props);
61
62
  return true;
63
+ } else if (((_a = error.error) == null ? void 0 : _a.message) === "Failed to fetch") {
64
+ throw error.error;
62
65
  }
63
66
  return false;
64
67
  }
@@ -48,11 +48,14 @@ async function ensureAuthToken(props, force) {
48
48
  return isAuthed;
49
49
  }
50
50
  async function handleApiError(props, error) {
51
+ var _a;
51
52
  if (error.type === "unauthorized" || error.type === "forbidden") {
52
53
  console.warn("Keel token expired, refreshing...");
53
54
  isAuthed$.set(false);
54
55
  await ensureAuthToken(props);
55
56
  return true;
57
+ } else if (((_a = error.error) == null ? void 0 : _a.message) === "Failed to fetch") {
58
+ throw error.error;
56
59
  }
57
60
  return false;
58
61
  }
@@ -33,6 +33,14 @@ function wrapSupabaseFn(fn, source) {
33
33
  return data;
34
34
  };
35
35
  }
36
+ function handleSupabaseError(error, onError, params) {
37
+ var _a;
38
+ if ((_a = error.message) == null ? void 0 : _a.includes("Failed to fetch")) {
39
+ throw error;
40
+ } else {
41
+ onError(new Error(error.message), params);
42
+ }
43
+ }
36
44
  function syncedSupabase(props) {
37
45
  props = { ...supabaseConfig, ...props };
38
46
  const {
@@ -87,7 +95,7 @@ function syncedSupabase(props) {
87
95
  if (data) {
88
96
  return data || [];
89
97
  } else if (error) {
90
- onError(new Error(error.message), {
98
+ handleSupabaseError(error, onError, {
91
99
  getParams: params,
92
100
  source: "list",
93
101
  type: "get",
@@ -104,7 +112,7 @@ function syncedSupabase(props) {
104
112
  const created = data[0];
105
113
  return created;
106
114
  } else if (error) {
107
- onError(new Error(error.message), {
115
+ handleSupabaseError(error, onError, {
108
116
  setParams: params,
109
117
  source: "create",
110
118
  type: "set",
@@ -122,7 +130,7 @@ function syncedSupabase(props) {
122
130
  const created = data[0];
123
131
  return created;
124
132
  } else if (error) {
125
- onError(new Error(error.message), {
133
+ handleSupabaseError(error, onError, {
126
134
  setParams: params,
127
135
  source: "update",
128
136
  type: "set",
@@ -141,7 +149,7 @@ function syncedSupabase(props) {
141
149
  const created = data[0];
142
150
  return created;
143
151
  } else if (error) {
144
- onError(new Error(error.message), {
152
+ handleSupabaseError(error, onError, {
145
153
  setParams: params,
146
154
  source: "delete",
147
155
  type: "set",
@@ -31,6 +31,14 @@ function wrapSupabaseFn(fn, source) {
31
31
  return data;
32
32
  };
33
33
  }
34
+ function handleSupabaseError(error, onError, params) {
35
+ var _a;
36
+ if ((_a = error.message) == null ? void 0 : _a.includes("Failed to fetch")) {
37
+ throw error;
38
+ } else {
39
+ onError(new Error(error.message), params);
40
+ }
41
+ }
34
42
  function syncedSupabase(props) {
35
43
  props = { ...supabaseConfig, ...props };
36
44
  const {
@@ -85,7 +93,7 @@ function syncedSupabase(props) {
85
93
  if (data) {
86
94
  return data || [];
87
95
  } else if (error) {
88
- onError(new Error(error.message), {
96
+ handleSupabaseError(error, onError, {
89
97
  getParams: params,
90
98
  source: "list",
91
99
  type: "get",
@@ -102,7 +110,7 @@ function syncedSupabase(props) {
102
110
  const created = data[0];
103
111
  return created;
104
112
  } else if (error) {
105
- onError(new Error(error.message), {
113
+ handleSupabaseError(error, onError, {
106
114
  setParams: params,
107
115
  source: "create",
108
116
  type: "set",
@@ -120,7 +128,7 @@ function syncedSupabase(props) {
120
128
  const created = data[0];
121
129
  return created;
122
130
  } else if (error) {
123
- onError(new Error(error.message), {
131
+ handleSupabaseError(error, onError, {
124
132
  setParams: params,
125
133
  source: "update",
126
134
  type: "set",
@@ -139,7 +147,7 @@ function syncedSupabase(props) {
139
147
  const created = data[0];
140
148
  return created;
141
149
  } else if (error) {
142
- onError(new Error(error.message), {
150
+ handleSupabaseError(error, onError, {
143
151
  setParams: params,
144
152
  source: "delete",
145
153
  type: "set",
package/sync.js CHANGED
@@ -287,10 +287,10 @@ function updateMetadata(value$, localState, syncState2, syncOptions, newMetadata
287
287
  if (localState.timeoutSaveMetadata) {
288
288
  clearTimeout(localState.timeoutSaveMetadata);
289
289
  }
290
- localState.timeoutSaveMetadata = setTimeout(
291
- () => updateMetadataImmediate(value$, localState, syncState2, syncOptions, newMetadata),
292
- 0
293
- );
290
+ metadatas.set(value$, { ...metadatas.get(value$) || {}, ...newMetadata });
291
+ localState.timeoutSaveMetadata = setTimeout(() => {
292
+ updateMetadataImmediate(value$, localState, syncState2, syncOptions, metadatas.get(value$));
293
+ }, 0);
294
294
  }
295
295
  var _queuedChanges = [];
296
296
  var _queuedRemoteChanges = /* @__PURE__ */ new Map();
@@ -635,10 +635,11 @@ async function doChangeRemote(changeInfo) {
635
635
  onError: onSetError,
636
636
  update: (params) => {
637
637
  if (updateResult) {
638
- const { value: value2, mode } = params;
638
+ const { value: value2, mode, changes } = params;
639
639
  updateResult = {
640
640
  value: deepMerge(updateResult.value, value2),
641
- mode
641
+ mode,
642
+ changes: changes ? [...updateResult.changes || [], ...changes] : updateResult.changes
642
643
  };
643
644
  } else {
644
645
  updateResult = params;
@@ -660,9 +661,11 @@ async function doChangeRemote(changeInfo) {
660
661
  }
661
662
  });
662
663
  }
663
- if (!didError) {
664
- const pathStrs = Array.from(new Set(changesRemote.map((change) => change.pathStr)));
665
- const { value: changes } = updateResult || {};
664
+ if (!didError || (updateResult == null ? void 0 : updateResult.changes)) {
665
+ const { value: updateValue, changes: updateChanges = changesRemote } = updateResult || {};
666
+ const pathStrs = Array.from(
667
+ new Set(updateChanges.map((change) => change.pathStr))
668
+ );
666
669
  if (pathStrs.length > 0) {
667
670
  let transformedChanges = void 0;
668
671
  const metadata = {};
@@ -680,8 +683,8 @@ async function doChangeRemote(changeInfo) {
680
683
  }
681
684
  }
682
685
  }
683
- if (changes && !state.isEmpty(changes)) {
684
- transformedChanges = transformLoadData(changes, syncOptions, false, "set");
686
+ if (updateValue && !state.isEmpty(updateValue)) {
687
+ transformedChanges = transformLoadData(updateValue, syncOptions, false, "set");
685
688
  }
686
689
  if (transformedChanges !== void 0) {
687
690
  if (state.isPromise(transformedChanges)) {
package/sync.mjs CHANGED
@@ -285,10 +285,10 @@ function updateMetadata(value$, localState, syncState2, syncOptions, newMetadata
285
285
  if (localState.timeoutSaveMetadata) {
286
286
  clearTimeout(localState.timeoutSaveMetadata);
287
287
  }
288
- localState.timeoutSaveMetadata = setTimeout(
289
- () => updateMetadataImmediate(value$, localState, syncState2, syncOptions, newMetadata),
290
- 0
291
- );
288
+ metadatas.set(value$, { ...metadatas.get(value$) || {}, ...newMetadata });
289
+ localState.timeoutSaveMetadata = setTimeout(() => {
290
+ updateMetadataImmediate(value$, localState, syncState2, syncOptions, metadatas.get(value$));
291
+ }, 0);
292
292
  }
293
293
  var _queuedChanges = [];
294
294
  var _queuedRemoteChanges = /* @__PURE__ */ new Map();
@@ -633,10 +633,11 @@ async function doChangeRemote(changeInfo) {
633
633
  onError: onSetError,
634
634
  update: (params) => {
635
635
  if (updateResult) {
636
- const { value: value2, mode } = params;
636
+ const { value: value2, mode, changes } = params;
637
637
  updateResult = {
638
638
  value: deepMerge(updateResult.value, value2),
639
- mode
639
+ mode,
640
+ changes: changes ? [...updateResult.changes || [], ...changes] : updateResult.changes
640
641
  };
641
642
  } else {
642
643
  updateResult = params;
@@ -658,9 +659,11 @@ async function doChangeRemote(changeInfo) {
658
659
  }
659
660
  });
660
661
  }
661
- if (!didError) {
662
- const pathStrs = Array.from(new Set(changesRemote.map((change) => change.pathStr)));
663
- const { value: changes } = updateResult || {};
662
+ if (!didError || (updateResult == null ? void 0 : updateResult.changes)) {
663
+ const { value: updateValue, changes: updateChanges = changesRemote } = updateResult || {};
664
+ const pathStrs = Array.from(
665
+ new Set(updateChanges.map((change) => change.pathStr))
666
+ );
664
667
  if (pathStrs.length > 0) {
665
668
  let transformedChanges = void 0;
666
669
  const metadata = {};
@@ -678,8 +681,8 @@ async function doChangeRemote(changeInfo) {
678
681
  }
679
682
  }
680
683
  }
681
- if (changes && !isEmpty(changes)) {
682
- transformedChanges = transformLoadData(changes, syncOptions, false, "set");
684
+ if (updateValue && !isEmpty(updateValue)) {
685
+ transformedChanges = transformLoadData(updateValue, syncOptions, false, "set");
683
686
  }
684
687
  if (transformedChanges !== void 0) {
685
688
  if (isPromise$1(transformedChanges)) {