@legendapp/state 3.0.0-beta.15 → 3.0.0-beta.17
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 +1 -0
- package/index.d.ts +1 -0
- package/package.json +1 -1
- package/sync-plugins/crud.js +58 -29
- package/sync-plugins/crud.mjs +58 -29
- package/sync-plugins/keel.d.mts +1 -1
- package/sync-plugins/keel.d.ts +1 -1
- package/sync.js +76 -36
- package/sync.mjs +76 -36
package/index.d.mts
CHANGED
package/index.d.ts
CHANGED
package/package.json
CHANGED
package/sync-plugins/crud.js
CHANGED
|
@@ -25,12 +25,7 @@ function computeLastSync(data, fieldUpdatedAt, fieldCreatedAt) {
|
|
|
25
25
|
}
|
|
26
26
|
return newLastSync;
|
|
27
27
|
}
|
|
28
|
-
|
|
29
|
-
create: /* @__PURE__ */ new Map(),
|
|
30
|
-
update: /* @__PURE__ */ new Map(),
|
|
31
|
-
delete: /* @__PURE__ */ new Map()
|
|
32
|
-
};
|
|
33
|
-
function retrySet(params, retry, action, itemKey, itemValue, actionFn, saveResult) {
|
|
28
|
+
function retrySet(params, retry, action, itemKey, itemValue, change, queuedRetries, actionFn, saveResult) {
|
|
34
29
|
if (action === "delete") {
|
|
35
30
|
if (queuedRetries.create.has(itemKey)) {
|
|
36
31
|
queuedRetries.create.delete(itemKey);
|
|
@@ -48,13 +43,14 @@ function retrySet(params, retry, action, itemKey, itemValue, actionFn, saveResul
|
|
|
48
43
|
itemValue = Object.assign(queuedRetry, itemValue);
|
|
49
44
|
}
|
|
50
45
|
queuedRetries[action].set(itemKey, itemValue);
|
|
46
|
+
const paramsWithChanges = { ...params, changes: [change] };
|
|
51
47
|
return runWithRetry(
|
|
52
|
-
|
|
48
|
+
paramsWithChanges,
|
|
53
49
|
retry,
|
|
54
50
|
"create_" + itemKey,
|
|
55
|
-
() => actionFn(itemValue,
|
|
51
|
+
() => actionFn(itemValue, paramsWithChanges).then((result) => {
|
|
56
52
|
queuedRetries[action].delete(itemKey);
|
|
57
|
-
return saveResult(itemKey, itemValue, result, true);
|
|
53
|
+
return saveResult(itemKey, itemValue, result, true, change);
|
|
58
54
|
})
|
|
59
55
|
);
|
|
60
56
|
}
|
|
@@ -83,6 +79,11 @@ function syncedCrud(props) {
|
|
|
83
79
|
} = props;
|
|
84
80
|
const fieldId = fieldIdProp || "id";
|
|
85
81
|
const pendingCreates = /* @__PURE__ */ new Set();
|
|
82
|
+
const queuedRetries = {
|
|
83
|
+
create: /* @__PURE__ */ new Map(),
|
|
84
|
+
update: /* @__PURE__ */ new Map(),
|
|
85
|
+
delete: /* @__PURE__ */ new Map()
|
|
86
|
+
};
|
|
86
87
|
let asType = props.as;
|
|
87
88
|
if (!asType) {
|
|
88
89
|
asType = getFn ? "value" : "object";
|
|
@@ -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
|
-
|
|
278
|
-
|
|
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
|
-
|
|
285
|
-
|
|
286
|
-
|
|
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,19 @@ 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(
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
363
|
+
return retrySet(
|
|
364
|
+
params,
|
|
365
|
+
retry,
|
|
366
|
+
"create",
|
|
367
|
+
itemKey,
|
|
368
|
+
createObj,
|
|
369
|
+
changesById.get(itemKey),
|
|
370
|
+
queuedRetries,
|
|
371
|
+
createFn,
|
|
372
|
+
saveResult
|
|
373
|
+
).then(() => {
|
|
374
|
+
pendingCreates.delete(itemKey);
|
|
375
|
+
});
|
|
361
376
|
}),
|
|
362
377
|
// Handle updates
|
|
363
378
|
...Array.from(updates).map(async ([itemKey, itemValue]) => {
|
|
@@ -366,7 +381,17 @@ function syncedCrud(props) {
|
|
|
366
381
|
}
|
|
367
382
|
const changed = await transformOut(itemValue, transform == null ? void 0 : transform.save);
|
|
368
383
|
if (Object.keys(changed).length > 0) {
|
|
369
|
-
return retrySet(
|
|
384
|
+
return retrySet(
|
|
385
|
+
params,
|
|
386
|
+
retry,
|
|
387
|
+
"update",
|
|
388
|
+
itemKey,
|
|
389
|
+
changed,
|
|
390
|
+
changesById.get(itemKey),
|
|
391
|
+
queuedRetries,
|
|
392
|
+
updateFn,
|
|
393
|
+
saveResult
|
|
394
|
+
);
|
|
370
395
|
}
|
|
371
396
|
}),
|
|
372
397
|
// Handle deletes
|
|
@@ -374,8 +399,8 @@ function syncedCrud(props) {
|
|
|
374
399
|
if (waitForSetParam) {
|
|
375
400
|
await waitForSet(waitForSetParam, changes, valuePrevious, { type: "delete" });
|
|
376
401
|
}
|
|
377
|
-
const
|
|
378
|
-
if (!
|
|
402
|
+
const itemKey = valuePrevious[fieldId];
|
|
403
|
+
if (!itemKey) {
|
|
379
404
|
console.error("[legend-state]: deleting item without an id");
|
|
380
405
|
return;
|
|
381
406
|
}
|
|
@@ -384,8 +409,10 @@ function syncedCrud(props) {
|
|
|
384
409
|
params,
|
|
385
410
|
retry,
|
|
386
411
|
"delete",
|
|
387
|
-
|
|
412
|
+
itemKey,
|
|
388
413
|
valuePrevious,
|
|
414
|
+
changesById.get(itemKey),
|
|
415
|
+
queuedRetries,
|
|
389
416
|
deleteFn,
|
|
390
417
|
saveResult
|
|
391
418
|
);
|
|
@@ -395,8 +422,10 @@ function syncedCrud(props) {
|
|
|
395
422
|
params,
|
|
396
423
|
retry,
|
|
397
424
|
"delete",
|
|
398
|
-
|
|
399
|
-
{ [fieldId]:
|
|
425
|
+
itemKey,
|
|
426
|
+
{ [fieldId]: itemKey, [fieldDeleted]: true },
|
|
427
|
+
changesById.get(itemKey),
|
|
428
|
+
queuedRetries,
|
|
400
429
|
updateFn,
|
|
401
430
|
saveResult
|
|
402
431
|
);
|
package/sync-plugins/crud.mjs
CHANGED
|
@@ -23,12 +23,7 @@ function computeLastSync(data, fieldUpdatedAt, fieldCreatedAt) {
|
|
|
23
23
|
}
|
|
24
24
|
return newLastSync;
|
|
25
25
|
}
|
|
26
|
-
|
|
27
|
-
create: /* @__PURE__ */ new Map(),
|
|
28
|
-
update: /* @__PURE__ */ new Map(),
|
|
29
|
-
delete: /* @__PURE__ */ new Map()
|
|
30
|
-
};
|
|
31
|
-
function retrySet(params, retry, action, itemKey, itemValue, actionFn, saveResult) {
|
|
26
|
+
function retrySet(params, retry, action, itemKey, itemValue, change, queuedRetries, actionFn, saveResult) {
|
|
32
27
|
if (action === "delete") {
|
|
33
28
|
if (queuedRetries.create.has(itemKey)) {
|
|
34
29
|
queuedRetries.create.delete(itemKey);
|
|
@@ -46,13 +41,14 @@ function retrySet(params, retry, action, itemKey, itemValue, actionFn, saveResul
|
|
|
46
41
|
itemValue = Object.assign(queuedRetry, itemValue);
|
|
47
42
|
}
|
|
48
43
|
queuedRetries[action].set(itemKey, itemValue);
|
|
44
|
+
const paramsWithChanges = { ...params, changes: [change] };
|
|
49
45
|
return runWithRetry(
|
|
50
|
-
|
|
46
|
+
paramsWithChanges,
|
|
51
47
|
retry,
|
|
52
48
|
"create_" + itemKey,
|
|
53
|
-
() => actionFn(itemValue,
|
|
49
|
+
() => actionFn(itemValue, paramsWithChanges).then((result) => {
|
|
54
50
|
queuedRetries[action].delete(itemKey);
|
|
55
|
-
return saveResult(itemKey, itemValue, result, true);
|
|
51
|
+
return saveResult(itemKey, itemValue, result, true, change);
|
|
56
52
|
})
|
|
57
53
|
);
|
|
58
54
|
}
|
|
@@ -81,6 +77,11 @@ function syncedCrud(props) {
|
|
|
81
77
|
} = props;
|
|
82
78
|
const fieldId = fieldIdProp || "id";
|
|
83
79
|
const pendingCreates = /* @__PURE__ */ new Set();
|
|
80
|
+
const queuedRetries = {
|
|
81
|
+
create: /* @__PURE__ */ new Map(),
|
|
82
|
+
update: /* @__PURE__ */ new Map(),
|
|
83
|
+
delete: /* @__PURE__ */ new Map()
|
|
84
|
+
};
|
|
84
85
|
let asType = props.as;
|
|
85
86
|
if (!asType) {
|
|
86
87
|
asType = getFn ? "value" : "object";
|
|
@@ -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
|
-
|
|
276
|
-
|
|
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
|
-
|
|
283
|
-
|
|
284
|
-
|
|
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,19 @@ 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(
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
361
|
+
return retrySet(
|
|
362
|
+
params,
|
|
363
|
+
retry,
|
|
364
|
+
"create",
|
|
365
|
+
itemKey,
|
|
366
|
+
createObj,
|
|
367
|
+
changesById.get(itemKey),
|
|
368
|
+
queuedRetries,
|
|
369
|
+
createFn,
|
|
370
|
+
saveResult
|
|
371
|
+
).then(() => {
|
|
372
|
+
pendingCreates.delete(itemKey);
|
|
373
|
+
});
|
|
359
374
|
}),
|
|
360
375
|
// Handle updates
|
|
361
376
|
...Array.from(updates).map(async ([itemKey, itemValue]) => {
|
|
@@ -364,7 +379,17 @@ function syncedCrud(props) {
|
|
|
364
379
|
}
|
|
365
380
|
const changed = await transformOut(itemValue, transform == null ? void 0 : transform.save);
|
|
366
381
|
if (Object.keys(changed).length > 0) {
|
|
367
|
-
return retrySet(
|
|
382
|
+
return retrySet(
|
|
383
|
+
params,
|
|
384
|
+
retry,
|
|
385
|
+
"update",
|
|
386
|
+
itemKey,
|
|
387
|
+
changed,
|
|
388
|
+
changesById.get(itemKey),
|
|
389
|
+
queuedRetries,
|
|
390
|
+
updateFn,
|
|
391
|
+
saveResult
|
|
392
|
+
);
|
|
368
393
|
}
|
|
369
394
|
}),
|
|
370
395
|
// Handle deletes
|
|
@@ -372,8 +397,8 @@ function syncedCrud(props) {
|
|
|
372
397
|
if (waitForSetParam) {
|
|
373
398
|
await waitForSet(waitForSetParam, changes, valuePrevious, { type: "delete" });
|
|
374
399
|
}
|
|
375
|
-
const
|
|
376
|
-
if (!
|
|
400
|
+
const itemKey = valuePrevious[fieldId];
|
|
401
|
+
if (!itemKey) {
|
|
377
402
|
console.error("[legend-state]: deleting item without an id");
|
|
378
403
|
return;
|
|
379
404
|
}
|
|
@@ -382,8 +407,10 @@ function syncedCrud(props) {
|
|
|
382
407
|
params,
|
|
383
408
|
retry,
|
|
384
409
|
"delete",
|
|
385
|
-
|
|
410
|
+
itemKey,
|
|
386
411
|
valuePrevious,
|
|
412
|
+
changesById.get(itemKey),
|
|
413
|
+
queuedRetries,
|
|
387
414
|
deleteFn,
|
|
388
415
|
saveResult
|
|
389
416
|
);
|
|
@@ -393,8 +420,10 @@ function syncedCrud(props) {
|
|
|
393
420
|
params,
|
|
394
421
|
retry,
|
|
395
422
|
"delete",
|
|
396
|
-
|
|
397
|
-
{ [fieldId]:
|
|
423
|
+
itemKey,
|
|
424
|
+
{ [fieldId]: itemKey, [fieldDeleted]: true },
|
|
425
|
+
changesById.get(itemKey),
|
|
426
|
+
queuedRetries,
|
|
398
427
|
updateFn,
|
|
399
428
|
saveResult
|
|
400
429
|
);
|
package/sync-plugins/keel.d.mts
CHANGED
package/sync-plugins/keel.d.ts
CHANGED
package/sync.js
CHANGED
|
@@ -36,12 +36,12 @@ function diffObjects(obj1, obj2, deep = false) {
|
|
|
36
36
|
return diff;
|
|
37
37
|
}
|
|
38
38
|
function deepEqual(a, b, ignoreFields, nullVsUndefined) {
|
|
39
|
-
if (a === b)
|
|
39
|
+
if (a === b)
|
|
40
40
|
return true;
|
|
41
|
-
|
|
42
|
-
if (state.isNullOrUndefined(a) !== state.isNullOrUndefined(b)) {
|
|
41
|
+
if (state.isNullOrUndefined(a) !== state.isNullOrUndefined(b))
|
|
43
42
|
return false;
|
|
44
|
-
|
|
43
|
+
if (!state.isObject(a) || !state.isObject(b))
|
|
44
|
+
return a === b;
|
|
45
45
|
if (nullVsUndefined) {
|
|
46
46
|
a = removeNullUndefined(
|
|
47
47
|
a,
|
|
@@ -54,8 +54,18 @@ function deepEqual(a, b, ignoreFields, nullVsUndefined) {
|
|
|
54
54
|
true
|
|
55
55
|
);
|
|
56
56
|
}
|
|
57
|
-
const
|
|
58
|
-
|
|
57
|
+
const keysA = Object.keys(a).filter((key) => !(ignoreFields == null ? void 0 : ignoreFields.includes(key)));
|
|
58
|
+
const keysB = Object.keys(b).filter((key) => !(ignoreFields == null ? void 0 : ignoreFields.includes(key)));
|
|
59
|
+
if (keysA.length !== keysB.length)
|
|
60
|
+
return false;
|
|
61
|
+
return keysA.every((key) => {
|
|
62
|
+
if (!Object.prototype.hasOwnProperty.call(b, key))
|
|
63
|
+
return false;
|
|
64
|
+
if (state.isDate(a[key]) && state.isDate(b[key])) {
|
|
65
|
+
return a[key].getTime() === b[key].getTime();
|
|
66
|
+
}
|
|
67
|
+
return deepEqual(a[key], b[key], ignoreFields, nullVsUndefined);
|
|
68
|
+
});
|
|
59
69
|
}
|
|
60
70
|
function combineTransforms(...transforms) {
|
|
61
71
|
return {
|
|
@@ -287,10 +297,10 @@ function updateMetadata(value$, localState, syncState2, syncOptions, newMetadata
|
|
|
287
297
|
if (localState.timeoutSaveMetadata) {
|
|
288
298
|
clearTimeout(localState.timeoutSaveMetadata);
|
|
289
299
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
);
|
|
300
|
+
metadatas.set(value$, { ...metadatas.get(value$) || {}, ...newMetadata });
|
|
301
|
+
localState.timeoutSaveMetadata = setTimeout(() => {
|
|
302
|
+
updateMetadataImmediate(value$, localState, syncState2, syncOptions, metadatas.get(value$));
|
|
303
|
+
}, 0);
|
|
294
304
|
}
|
|
295
305
|
var _queuedChanges = [];
|
|
296
306
|
var _queuedRemoteChanges = /* @__PURE__ */ new Map();
|
|
@@ -309,8 +319,25 @@ function mergeChanges(changes) {
|
|
|
309
319
|
existing.valueAtPath = change.valueAtPath;
|
|
310
320
|
}
|
|
311
321
|
} else {
|
|
312
|
-
|
|
313
|
-
|
|
322
|
+
let found = false;
|
|
323
|
+
for (let u = 0; u < change.path.length; u++) {
|
|
324
|
+
const path = change.path.slice(0, u).join("/");
|
|
325
|
+
if (changesByPath.has(path)) {
|
|
326
|
+
const remaining = change.path.slice(u);
|
|
327
|
+
state.setAtPath(
|
|
328
|
+
changesByPath.get(path).valueAtPath,
|
|
329
|
+
remaining,
|
|
330
|
+
change.pathTypes.slice(u),
|
|
331
|
+
change.valueAtPath
|
|
332
|
+
);
|
|
333
|
+
found = true;
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
if (!found) {
|
|
338
|
+
changesByPath.set(pathStr, change);
|
|
339
|
+
changesOut.push(change);
|
|
340
|
+
}
|
|
314
341
|
}
|
|
315
342
|
}
|
|
316
343
|
return changesOut;
|
|
@@ -635,10 +662,11 @@ async function doChangeRemote(changeInfo) {
|
|
|
635
662
|
onError: onSetError,
|
|
636
663
|
update: (params) => {
|
|
637
664
|
if (updateResult) {
|
|
638
|
-
const { value: value2, mode } = params;
|
|
665
|
+
const { value: value2, mode, changes } = params;
|
|
639
666
|
updateResult = {
|
|
640
667
|
value: deepMerge(updateResult.value, value2),
|
|
641
|
-
mode
|
|
668
|
+
mode,
|
|
669
|
+
changes: changes ? [...updateResult.changes || [], ...changes] : updateResult.changes
|
|
642
670
|
};
|
|
643
671
|
} else {
|
|
644
672
|
updateResult = params;
|
|
@@ -660,9 +688,11 @@ async function doChangeRemote(changeInfo) {
|
|
|
660
688
|
}
|
|
661
689
|
});
|
|
662
690
|
}
|
|
663
|
-
if (!didError) {
|
|
664
|
-
const
|
|
665
|
-
const
|
|
691
|
+
if (!didError || (updateResult == null ? void 0 : updateResult.changes)) {
|
|
692
|
+
const { value: updateValue, changes: updateChanges = changesRemote } = updateResult || {};
|
|
693
|
+
const pathStrs = Array.from(
|
|
694
|
+
new Set(updateChanges.map((change) => change.pathStr))
|
|
695
|
+
);
|
|
666
696
|
if (pathStrs.length > 0) {
|
|
667
697
|
let transformedChanges = void 0;
|
|
668
698
|
const metadata = {};
|
|
@@ -680,8 +710,8 @@ async function doChangeRemote(changeInfo) {
|
|
|
680
710
|
}
|
|
681
711
|
}
|
|
682
712
|
}
|
|
683
|
-
if (
|
|
684
|
-
transformedChanges = transformLoadData(
|
|
713
|
+
if (updateValue && !state.isEmpty(updateValue)) {
|
|
714
|
+
transformedChanges = transformLoadData(updateValue, syncOptions, false, "set");
|
|
685
715
|
}
|
|
686
716
|
if (transformedChanges !== void 0) {
|
|
687
717
|
if (state.isPromise(transformedChanges)) {
|
|
@@ -857,27 +887,33 @@ function syncObservable(obs$, syncOptionsOrSynced) {
|
|
|
857
887
|
syncState$.isLoaded.set(!syncState$.numPendingRemoteLoads.peek());
|
|
858
888
|
let isSynced = false;
|
|
859
889
|
let isSubscribed = false;
|
|
890
|
+
let isApplyingPendingAfterSync = false;
|
|
860
891
|
let unsubscribe = void 0;
|
|
861
892
|
const applyPending = (pending) => {
|
|
862
893
|
if (pending && !state.isEmpty(pending)) {
|
|
863
|
-
localState.isApplyingPending = true;
|
|
864
894
|
const keys = Object.keys(pending);
|
|
895
|
+
const value = getNodeValue(node);
|
|
865
896
|
const changes = [];
|
|
866
897
|
for (let i = 0; i < keys.length; i++) {
|
|
867
898
|
const key = keys[i];
|
|
868
899
|
const path = key.split("/").filter((p2) => p2 !== "");
|
|
869
|
-
const { p,
|
|
870
|
-
|
|
900
|
+
const { p, t, v } = pending[key];
|
|
901
|
+
const valueAtPath = getValueAtPath(value, path);
|
|
902
|
+
if (isApplyingPendingAfterSync || !deepEqual(valueAtPath, v)) {
|
|
903
|
+
changes.push({ path, valueAtPath: v, prevAtPath: p, pathTypes: t });
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
if (changes.length > 0) {
|
|
907
|
+
localState.isApplyingPending = true;
|
|
908
|
+
onObsChange(obs$, syncState$, localState, syncOptions, {
|
|
909
|
+
value,
|
|
910
|
+
isFromPersist: false,
|
|
911
|
+
isFromSync: false,
|
|
912
|
+
getPrevious: createPreviousHandler(value, changes),
|
|
913
|
+
changes
|
|
914
|
+
});
|
|
915
|
+
localState.isApplyingPending = false;
|
|
871
916
|
}
|
|
872
|
-
const value = getNodeValue(node);
|
|
873
|
-
onObsChange(obs$, syncState$, localState, syncOptions, {
|
|
874
|
-
value,
|
|
875
|
-
isFromPersist: false,
|
|
876
|
-
isFromSync: false,
|
|
877
|
-
getPrevious: createPreviousHandler(value, changes),
|
|
878
|
-
changes
|
|
879
|
-
});
|
|
880
|
-
localState.isApplyingPending = false;
|
|
881
917
|
}
|
|
882
918
|
};
|
|
883
919
|
const { get, subscribe } = syncOptions;
|
|
@@ -914,10 +950,10 @@ function syncObservable(obs$, syncOptionsOrSynced) {
|
|
|
914
950
|
const { v, t } = pending2[key];
|
|
915
951
|
if (t.length === 0 || !value) {
|
|
916
952
|
const oldValue = clone2(value);
|
|
917
|
-
pending2[key].p = oldValue;
|
|
953
|
+
pending2[key].p = key ? oldValue[key] : oldValue;
|
|
918
954
|
if (state.isObject(value) && state.isObject(v)) {
|
|
919
|
-
Object.assign(value, v);
|
|
920
|
-
} else {
|
|
955
|
+
Object.assign(value, key ? { [key]: v } : v);
|
|
956
|
+
} else if (!key) {
|
|
921
957
|
value = v;
|
|
922
958
|
}
|
|
923
959
|
} else if (value[p[0]] !== void 0) {
|
|
@@ -929,6 +965,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
|
|
|
929
965
|
} else {
|
|
930
966
|
const oldValue = clone2(value);
|
|
931
967
|
pending2[key].p = getValueAtPath(oldValue, p);
|
|
968
|
+
didChangeMetadata = true;
|
|
932
969
|
value = state.setAtPath(
|
|
933
970
|
value,
|
|
934
971
|
p,
|
|
@@ -949,7 +986,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
|
|
|
949
986
|
}
|
|
950
987
|
});
|
|
951
988
|
if (didChangeMetadata && syncOptions.persist) {
|
|
952
|
-
|
|
989
|
+
updateMetadataImmediate(obs$, localState, syncState$, syncOptions, {
|
|
953
990
|
pending: pending2
|
|
954
991
|
});
|
|
955
992
|
}
|
|
@@ -1126,14 +1163,17 @@ function syncObservable(obs$, syncOptionsOrSynced) {
|
|
|
1126
1163
|
}
|
|
1127
1164
|
if (!isSynced) {
|
|
1128
1165
|
isSynced = true;
|
|
1129
|
-
|
|
1166
|
+
isApplyingPendingAfterSync = true;
|
|
1130
1167
|
applyPending(pending);
|
|
1168
|
+
isApplyingPendingAfterSync = false;
|
|
1131
1169
|
}
|
|
1132
1170
|
};
|
|
1133
1171
|
syncStateValue.sync = sync;
|
|
1134
1172
|
} else {
|
|
1135
1173
|
if (!isSynced) {
|
|
1174
|
+
isApplyingPendingAfterSync = true;
|
|
1136
1175
|
applyPending(localState.pendingChanges);
|
|
1176
|
+
isApplyingPendingAfterSync = false;
|
|
1137
1177
|
}
|
|
1138
1178
|
}
|
|
1139
1179
|
syncStateValue.reset = async () => {
|
package/sync.mjs
CHANGED
|
@@ -34,12 +34,12 @@ function diffObjects(obj1, obj2, deep = false) {
|
|
|
34
34
|
return diff;
|
|
35
35
|
}
|
|
36
36
|
function deepEqual(a, b, ignoreFields, nullVsUndefined) {
|
|
37
|
-
if (a === b)
|
|
37
|
+
if (a === b)
|
|
38
38
|
return true;
|
|
39
|
-
|
|
40
|
-
if (isNullOrUndefined(a) !== isNullOrUndefined(b)) {
|
|
39
|
+
if (isNullOrUndefined(a) !== isNullOrUndefined(b))
|
|
41
40
|
return false;
|
|
42
|
-
|
|
41
|
+
if (!isObject(a) || !isObject(b))
|
|
42
|
+
return a === b;
|
|
43
43
|
if (nullVsUndefined) {
|
|
44
44
|
a = removeNullUndefined(
|
|
45
45
|
a,
|
|
@@ -52,8 +52,18 @@ function deepEqual(a, b, ignoreFields, nullVsUndefined) {
|
|
|
52
52
|
true
|
|
53
53
|
);
|
|
54
54
|
}
|
|
55
|
-
const
|
|
56
|
-
|
|
55
|
+
const keysA = Object.keys(a).filter((key) => !(ignoreFields == null ? void 0 : ignoreFields.includes(key)));
|
|
56
|
+
const keysB = Object.keys(b).filter((key) => !(ignoreFields == null ? void 0 : ignoreFields.includes(key)));
|
|
57
|
+
if (keysA.length !== keysB.length)
|
|
58
|
+
return false;
|
|
59
|
+
return keysA.every((key) => {
|
|
60
|
+
if (!Object.prototype.hasOwnProperty.call(b, key))
|
|
61
|
+
return false;
|
|
62
|
+
if (isDate(a[key]) && isDate(b[key])) {
|
|
63
|
+
return a[key].getTime() === b[key].getTime();
|
|
64
|
+
}
|
|
65
|
+
return deepEqual(a[key], b[key], ignoreFields, nullVsUndefined);
|
|
66
|
+
});
|
|
57
67
|
}
|
|
58
68
|
function combineTransforms(...transforms) {
|
|
59
69
|
return {
|
|
@@ -285,10 +295,10 @@ function updateMetadata(value$, localState, syncState2, syncOptions, newMetadata
|
|
|
285
295
|
if (localState.timeoutSaveMetadata) {
|
|
286
296
|
clearTimeout(localState.timeoutSaveMetadata);
|
|
287
297
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
);
|
|
298
|
+
metadatas.set(value$, { ...metadatas.get(value$) || {}, ...newMetadata });
|
|
299
|
+
localState.timeoutSaveMetadata = setTimeout(() => {
|
|
300
|
+
updateMetadataImmediate(value$, localState, syncState2, syncOptions, metadatas.get(value$));
|
|
301
|
+
}, 0);
|
|
292
302
|
}
|
|
293
303
|
var _queuedChanges = [];
|
|
294
304
|
var _queuedRemoteChanges = /* @__PURE__ */ new Map();
|
|
@@ -307,8 +317,25 @@ function mergeChanges(changes) {
|
|
|
307
317
|
existing.valueAtPath = change.valueAtPath;
|
|
308
318
|
}
|
|
309
319
|
} else {
|
|
310
|
-
|
|
311
|
-
|
|
320
|
+
let found = false;
|
|
321
|
+
for (let u = 0; u < change.path.length; u++) {
|
|
322
|
+
const path = change.path.slice(0, u).join("/");
|
|
323
|
+
if (changesByPath.has(path)) {
|
|
324
|
+
const remaining = change.path.slice(u);
|
|
325
|
+
setAtPath(
|
|
326
|
+
changesByPath.get(path).valueAtPath,
|
|
327
|
+
remaining,
|
|
328
|
+
change.pathTypes.slice(u),
|
|
329
|
+
change.valueAtPath
|
|
330
|
+
);
|
|
331
|
+
found = true;
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
if (!found) {
|
|
336
|
+
changesByPath.set(pathStr, change);
|
|
337
|
+
changesOut.push(change);
|
|
338
|
+
}
|
|
312
339
|
}
|
|
313
340
|
}
|
|
314
341
|
return changesOut;
|
|
@@ -633,10 +660,11 @@ async function doChangeRemote(changeInfo) {
|
|
|
633
660
|
onError: onSetError,
|
|
634
661
|
update: (params) => {
|
|
635
662
|
if (updateResult) {
|
|
636
|
-
const { value: value2, mode } = params;
|
|
663
|
+
const { value: value2, mode, changes } = params;
|
|
637
664
|
updateResult = {
|
|
638
665
|
value: deepMerge(updateResult.value, value2),
|
|
639
|
-
mode
|
|
666
|
+
mode,
|
|
667
|
+
changes: changes ? [...updateResult.changes || [], ...changes] : updateResult.changes
|
|
640
668
|
};
|
|
641
669
|
} else {
|
|
642
670
|
updateResult = params;
|
|
@@ -658,9 +686,11 @@ async function doChangeRemote(changeInfo) {
|
|
|
658
686
|
}
|
|
659
687
|
});
|
|
660
688
|
}
|
|
661
|
-
if (!didError) {
|
|
662
|
-
const
|
|
663
|
-
const
|
|
689
|
+
if (!didError || (updateResult == null ? void 0 : updateResult.changes)) {
|
|
690
|
+
const { value: updateValue, changes: updateChanges = changesRemote } = updateResult || {};
|
|
691
|
+
const pathStrs = Array.from(
|
|
692
|
+
new Set(updateChanges.map((change) => change.pathStr))
|
|
693
|
+
);
|
|
664
694
|
if (pathStrs.length > 0) {
|
|
665
695
|
let transformedChanges = void 0;
|
|
666
696
|
const metadata = {};
|
|
@@ -678,8 +708,8 @@ async function doChangeRemote(changeInfo) {
|
|
|
678
708
|
}
|
|
679
709
|
}
|
|
680
710
|
}
|
|
681
|
-
if (
|
|
682
|
-
transformedChanges = transformLoadData(
|
|
711
|
+
if (updateValue && !isEmpty(updateValue)) {
|
|
712
|
+
transformedChanges = transformLoadData(updateValue, syncOptions, false, "set");
|
|
683
713
|
}
|
|
684
714
|
if (transformedChanges !== void 0) {
|
|
685
715
|
if (isPromise$1(transformedChanges)) {
|
|
@@ -855,27 +885,33 @@ function syncObservable(obs$, syncOptionsOrSynced) {
|
|
|
855
885
|
syncState$.isLoaded.set(!syncState$.numPendingRemoteLoads.peek());
|
|
856
886
|
let isSynced = false;
|
|
857
887
|
let isSubscribed = false;
|
|
888
|
+
let isApplyingPendingAfterSync = false;
|
|
858
889
|
let unsubscribe = void 0;
|
|
859
890
|
const applyPending = (pending) => {
|
|
860
891
|
if (pending && !isEmpty(pending)) {
|
|
861
|
-
localState.isApplyingPending = true;
|
|
862
892
|
const keys = Object.keys(pending);
|
|
893
|
+
const value = getNodeValue(node);
|
|
863
894
|
const changes = [];
|
|
864
895
|
for (let i = 0; i < keys.length; i++) {
|
|
865
896
|
const key = keys[i];
|
|
866
897
|
const path = key.split("/").filter((p2) => p2 !== "");
|
|
867
|
-
const { p,
|
|
868
|
-
|
|
898
|
+
const { p, t, v } = pending[key];
|
|
899
|
+
const valueAtPath = getValueAtPath(value, path);
|
|
900
|
+
if (isApplyingPendingAfterSync || !deepEqual(valueAtPath, v)) {
|
|
901
|
+
changes.push({ path, valueAtPath: v, prevAtPath: p, pathTypes: t });
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
if (changes.length > 0) {
|
|
905
|
+
localState.isApplyingPending = true;
|
|
906
|
+
onObsChange(obs$, syncState$, localState, syncOptions, {
|
|
907
|
+
value,
|
|
908
|
+
isFromPersist: false,
|
|
909
|
+
isFromSync: false,
|
|
910
|
+
getPrevious: createPreviousHandler(value, changes),
|
|
911
|
+
changes
|
|
912
|
+
});
|
|
913
|
+
localState.isApplyingPending = false;
|
|
869
914
|
}
|
|
870
|
-
const value = getNodeValue(node);
|
|
871
|
-
onObsChange(obs$, syncState$, localState, syncOptions, {
|
|
872
|
-
value,
|
|
873
|
-
isFromPersist: false,
|
|
874
|
-
isFromSync: false,
|
|
875
|
-
getPrevious: createPreviousHandler(value, changes),
|
|
876
|
-
changes
|
|
877
|
-
});
|
|
878
|
-
localState.isApplyingPending = false;
|
|
879
915
|
}
|
|
880
916
|
};
|
|
881
917
|
const { get, subscribe } = syncOptions;
|
|
@@ -912,10 +948,10 @@ function syncObservable(obs$, syncOptionsOrSynced) {
|
|
|
912
948
|
const { v, t } = pending2[key];
|
|
913
949
|
if (t.length === 0 || !value) {
|
|
914
950
|
const oldValue = clone2(value);
|
|
915
|
-
pending2[key].p = oldValue;
|
|
951
|
+
pending2[key].p = key ? oldValue[key] : oldValue;
|
|
916
952
|
if (isObject(value) && isObject(v)) {
|
|
917
|
-
Object.assign(value, v);
|
|
918
|
-
} else {
|
|
953
|
+
Object.assign(value, key ? { [key]: v } : v);
|
|
954
|
+
} else if (!key) {
|
|
919
955
|
value = v;
|
|
920
956
|
}
|
|
921
957
|
} else if (value[p[0]] !== void 0) {
|
|
@@ -927,6 +963,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
|
|
|
927
963
|
} else {
|
|
928
964
|
const oldValue = clone2(value);
|
|
929
965
|
pending2[key].p = getValueAtPath(oldValue, p);
|
|
966
|
+
didChangeMetadata = true;
|
|
930
967
|
value = setAtPath(
|
|
931
968
|
value,
|
|
932
969
|
p,
|
|
@@ -947,7 +984,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
|
|
|
947
984
|
}
|
|
948
985
|
});
|
|
949
986
|
if (didChangeMetadata && syncOptions.persist) {
|
|
950
|
-
|
|
987
|
+
updateMetadataImmediate(obs$, localState, syncState$, syncOptions, {
|
|
951
988
|
pending: pending2
|
|
952
989
|
});
|
|
953
990
|
}
|
|
@@ -1124,14 +1161,17 @@ function syncObservable(obs$, syncOptionsOrSynced) {
|
|
|
1124
1161
|
}
|
|
1125
1162
|
if (!isSynced) {
|
|
1126
1163
|
isSynced = true;
|
|
1127
|
-
|
|
1164
|
+
isApplyingPendingAfterSync = true;
|
|
1128
1165
|
applyPending(pending);
|
|
1166
|
+
isApplyingPendingAfterSync = false;
|
|
1129
1167
|
}
|
|
1130
1168
|
};
|
|
1131
1169
|
syncStateValue.sync = sync;
|
|
1132
1170
|
} else {
|
|
1133
1171
|
if (!isSynced) {
|
|
1172
|
+
isApplyingPendingAfterSync = true;
|
|
1134
1173
|
applyPending(localState.pendingChanges);
|
|
1174
|
+
isApplyingPendingAfterSync = false;
|
|
1135
1175
|
}
|
|
1136
1176
|
}
|
|
1137
1177
|
syncStateValue.reset = async () => {
|