@legendapp/state 3.0.0-beta.46 → 3.0.0-beta.48
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/README.md +2 -1
- package/config/enableReactNativeComponents.js +2 -4
- package/config/enableReactNativeComponents.mjs +3 -5
- package/helpers/undoRedo.js +1 -2
- package/helpers/undoRedo.mjs +1 -2
- package/index.d.mts +2 -0
- package/index.d.ts +2 -0
- package/index.js +42 -10
- package/index.mjs +42 -10
- package/package.json +1 -1
- package/react-hooks/createObservableHook.js +15 -4
- package/react-hooks/createObservableHook.mjs +15 -4
- package/react-native.js +2 -4
- package/react-native.mjs +3 -5
- package/react-reactive/Components.js +2 -4
- package/react-reactive/Components.mjs +3 -5
- package/react-reactive/enableReactNativeComponents.js +2 -5
- package/react-reactive/enableReactNativeComponents.mjs +2 -5
- package/react-reactive/enableReactive.native.js +2 -5
- package/react-reactive/enableReactive.native.mjs +2 -5
- package/react-reactive/enableReactive.web.js +2 -5
- package/react-reactive/enableReactive.web.mjs +2 -5
- package/react.js +102 -60
- package/react.mjs +103 -61
- package/sync-plugins/crud.js +237 -52
- package/sync-plugins/crud.mjs +237 -52
- package/sync.js +17 -4
- package/sync.mjs +17 -4
- package/.DS_Store +0 -0
package/sync-plugins/crud.mjs
CHANGED
|
@@ -7,6 +7,11 @@ var { waitForSet, runWithRetry } = internal$1;
|
|
|
7
7
|
function transformOut(data, transform) {
|
|
8
8
|
return transform ? transform(clone(data)) : data;
|
|
9
9
|
}
|
|
10
|
+
function warnMissingId(value) {
|
|
11
|
+
if (process.env.NODE_ENV === "development") {
|
|
12
|
+
console.warn("[legend-state] syncedCrud received an item without an id", value);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
10
15
|
function ensureId(obj, fieldId, generateId, node) {
|
|
11
16
|
if (!obj[fieldId]) {
|
|
12
17
|
obj[fieldId] = generateId();
|
|
@@ -41,40 +46,89 @@ function arrayToRecord(arr, keyField) {
|
|
|
41
46
|
for (let i = 0; i < arr.length; i++) {
|
|
42
47
|
const v = arr[i];
|
|
43
48
|
const key = v[keyField];
|
|
44
|
-
|
|
49
|
+
if (isNullOrUndefined(key)) {
|
|
50
|
+
warnMissingId(v);
|
|
51
|
+
} else {
|
|
52
|
+
record[key] = v;
|
|
53
|
+
}
|
|
45
54
|
}
|
|
46
55
|
}
|
|
47
56
|
return record;
|
|
48
57
|
}
|
|
49
|
-
function
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
function mergeQueuedRetryValue(currentValue, nextValue) {
|
|
59
|
+
if (currentValue && nextValue && typeof currentValue === "object" && typeof nextValue === "object") {
|
|
60
|
+
Object.assign(currentValue, nextValue);
|
|
61
|
+
return currentValue;
|
|
62
|
+
}
|
|
63
|
+
return nextValue;
|
|
64
|
+
}
|
|
65
|
+
function queueRetryValue(queuedRetries, itemKey, itemValue, itemValueFull) {
|
|
66
|
+
const queuedRetry = queuedRetries.get(itemKey);
|
|
67
|
+
if (queuedRetry) {
|
|
68
|
+
queuedRetry.value = mergeQueuedRetryValue(queuedRetry.value, itemValue);
|
|
69
|
+
queuedRetry.fullValue = mergeQueuedRetryValue(queuedRetry.fullValue, itemValueFull);
|
|
70
|
+
return queuedRetry;
|
|
61
71
|
}
|
|
62
|
-
const
|
|
72
|
+
const nextQueuedRetry = {
|
|
73
|
+
value: itemValue,
|
|
74
|
+
fullValue: itemValueFull
|
|
75
|
+
};
|
|
76
|
+
queuedRetries.set(itemKey, nextQueuedRetry);
|
|
77
|
+
return nextQueuedRetry;
|
|
78
|
+
}
|
|
79
|
+
function cancelQueuedRetry(queuedRetries, itemKey) {
|
|
80
|
+
const queuedRetry = queuedRetries.get(itemKey);
|
|
63
81
|
if (queuedRetry) {
|
|
64
|
-
|
|
82
|
+
queuedRetry.cancelled = true;
|
|
83
|
+
queuedRetries.delete(itemKey);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function retrySet(params, retry, action, itemKey, itemValue, change, queuedRetries, itemValueFull, actionFn, saveResult, options) {
|
|
87
|
+
if (action === "delete") {
|
|
88
|
+
cancelQueuedRetry(queuedRetries.create, itemKey);
|
|
89
|
+
cancelQueuedRetry(queuedRetries.update, itemKey);
|
|
90
|
+
} else {
|
|
91
|
+
cancelQueuedRetry(queuedRetries.delete, itemKey);
|
|
65
92
|
}
|
|
66
|
-
queuedRetries[action]
|
|
67
|
-
const clonedValue = clone(itemValueFull);
|
|
93
|
+
const queuedRetry = queueRetryValue(queuedRetries[action], itemKey, itemValue, itemValueFull);
|
|
68
94
|
const paramsWithChanges = { ...params, changes: [change] };
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
95
|
+
const runAttempt = () => {
|
|
96
|
+
var _a;
|
|
97
|
+
if (queuedRetry.cancelled) {
|
|
98
|
+
return Promise.resolve(void 0);
|
|
99
|
+
}
|
|
100
|
+
const refreshed = (_a = options == null ? void 0 : options.refreshValue) == null ? void 0 : _a.call(options);
|
|
101
|
+
const runWithRefreshedValue = (retryValue) => {
|
|
102
|
+
if (retryValue === false || queuedRetry.cancelled) {
|
|
103
|
+
queuedRetry.cancelled = true;
|
|
104
|
+
queuedRetries[action].delete(itemKey);
|
|
105
|
+
return Promise.resolve(void 0);
|
|
106
|
+
}
|
|
107
|
+
if (retryValue) {
|
|
108
|
+
queuedRetry.value = retryValue.value;
|
|
109
|
+
queuedRetry.fullValue = retryValue.fullValue;
|
|
110
|
+
}
|
|
111
|
+
const attemptValue = queuedRetry.value;
|
|
112
|
+
const attemptFullValue = clone(queuedRetry.fullValue);
|
|
113
|
+
return actionFn(attemptValue, paramsWithChanges).catch((error) => {
|
|
114
|
+
var _a2;
|
|
115
|
+
(_a2 = options == null ? void 0 : options.onAttemptFailure) == null ? void 0 : _a2.call(options);
|
|
116
|
+
throw error;
|
|
117
|
+
}).then(async (result) => {
|
|
118
|
+
queuedRetries[action].delete(itemKey);
|
|
119
|
+
if (queuedRetry.cancelled) {
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
await saveResult(itemKey, attemptFullValue, result, true, change);
|
|
123
|
+
return result;
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
return isPromise(refreshed) ? refreshed.then(runWithRefreshedValue) : runWithRefreshedValue(refreshed);
|
|
127
|
+
};
|
|
128
|
+
return runWithRetry(paramsWithChanges, retry, action + "_" + itemKey, runAttempt).catch((error) => {
|
|
129
|
+
params.update({ value: {}, failedChanges: [change] });
|
|
130
|
+
throw error;
|
|
131
|
+
});
|
|
78
132
|
}
|
|
79
133
|
function syncedCrud(props) {
|
|
80
134
|
const {
|
|
@@ -100,12 +154,53 @@ function syncedCrud(props) {
|
|
|
100
154
|
...rest
|
|
101
155
|
} = props;
|
|
102
156
|
const fieldId = fieldIdProp || "id";
|
|
103
|
-
const pendingCreates = /* @__PURE__ */ new
|
|
157
|
+
const pendingCreates = /* @__PURE__ */ new Map();
|
|
104
158
|
const queuedRetries = {
|
|
105
159
|
create: /* @__PURE__ */ new Map(),
|
|
106
160
|
update: /* @__PURE__ */ new Map(),
|
|
107
161
|
delete: /* @__PURE__ */ new Map()
|
|
108
162
|
};
|
|
163
|
+
const beginPendingCreate = (id, change) => {
|
|
164
|
+
const pendingCreate = pendingCreates.get(id) || { hasFailed: false };
|
|
165
|
+
pendingCreate.hasFailed = false;
|
|
166
|
+
pendingCreate.change || (pendingCreate.change = change);
|
|
167
|
+
pendingCreates.set(id, pendingCreate);
|
|
168
|
+
return pendingCreate;
|
|
169
|
+
};
|
|
170
|
+
const clearPendingCreate = (id) => {
|
|
171
|
+
if (!isNullOrUndefined(id)) {
|
|
172
|
+
pendingCreates.delete(id);
|
|
173
|
+
cancelQueuedRetry(queuedRetries.create, id);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
const cancelFailedPendingCreate = (id) => {
|
|
177
|
+
var _a;
|
|
178
|
+
if (!isNullOrUndefined(id) && ((_a = pendingCreates.get(id)) == null ? void 0 : _a.hasFailed)) {
|
|
179
|
+
clearPendingCreate(id);
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
return false;
|
|
183
|
+
};
|
|
184
|
+
const clearPendingCreateForValue = (value) => {
|
|
185
|
+
if (value && typeof value === "object") {
|
|
186
|
+
clearPendingCreate(value[fieldId]);
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
const clearPendingCreatesForValues = (values) => {
|
|
190
|
+
if (values == null ? void 0 : values.length) {
|
|
191
|
+
for (let i = 0; i < values.length; i++) {
|
|
192
|
+
clearPendingCreateForValue(values[i]);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
const markPendingCreateFailed = (itemKey) => {
|
|
197
|
+
const pendingCreate = pendingCreates.get(itemKey);
|
|
198
|
+
if (pendingCreate && !pendingCreate.hasFailed) {
|
|
199
|
+
pendingCreate.hasFailed = true;
|
|
200
|
+
cancelQueuedRetry(queuedRetries.update, itemKey);
|
|
201
|
+
cancelQueuedRetry(queuedRetries.delete, itemKey);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
109
204
|
let asType = props.as;
|
|
110
205
|
if (!asType) {
|
|
111
206
|
asType = getFn ? "value" : "object";
|
|
@@ -125,9 +220,19 @@ function syncedCrud(props) {
|
|
|
125
220
|
if (asArray) {
|
|
126
221
|
out.push(result);
|
|
127
222
|
} else if (asMap) {
|
|
128
|
-
|
|
223
|
+
const key = value[fieldId];
|
|
224
|
+
if (isNullOrUndefined(key)) {
|
|
225
|
+
warnMissingId(value);
|
|
226
|
+
} else {
|
|
227
|
+
out.set(key, result);
|
|
228
|
+
}
|
|
129
229
|
} else {
|
|
130
|
-
|
|
230
|
+
const key = value[fieldId];
|
|
231
|
+
if (isNullOrUndefined(key)) {
|
|
232
|
+
warnMissingId(value);
|
|
233
|
+
} else {
|
|
234
|
+
out[key] = result;
|
|
235
|
+
}
|
|
131
236
|
}
|
|
132
237
|
}
|
|
133
238
|
}
|
|
@@ -165,6 +270,7 @@ function syncedCrud(props) {
|
|
|
165
270
|
};
|
|
166
271
|
const processResults = (data) => {
|
|
167
272
|
data || (data = []);
|
|
273
|
+
clearPendingCreatesForValues(data);
|
|
168
274
|
if (fieldUpdatedAt) {
|
|
169
275
|
const newLastSync = computeLastSync(data, fieldUpdatedAt, fieldCreatedAt);
|
|
170
276
|
if (newLastSync && newLastSync !== lastSync) {
|
|
@@ -181,6 +287,7 @@ function syncedCrud(props) {
|
|
|
181
287
|
} else if (getFn) {
|
|
182
288
|
const dataPromise = getFn(getParams);
|
|
183
289
|
const processData = (data) => {
|
|
290
|
+
clearPendingCreateForValue(data);
|
|
184
291
|
let transformed = data;
|
|
185
292
|
if (data) {
|
|
186
293
|
const newLastSync = data[fieldUpdatedAt] || data[fieldCreatedAt];
|
|
@@ -215,6 +322,32 @@ function syncedCrud(props) {
|
|
|
215
322
|
!isNullOrUndefined(itemValue[fieldId]) ? { [fieldId]: itemValue[fieldId] } : {}
|
|
216
323
|
) : itemValue;
|
|
217
324
|
};
|
|
325
|
+
const getCurrentValueAtKey = (itemKey) => {
|
|
326
|
+
const currentPeeked = getNodeValue(node);
|
|
327
|
+
if (asType === "value") {
|
|
328
|
+
return currentPeeked;
|
|
329
|
+
}
|
|
330
|
+
if (asType === "array") {
|
|
331
|
+
return isArray(currentPeeked) ? currentPeeked.find((value2) => (value2 == null ? void 0 : value2[fieldId]) === itemKey) : void 0;
|
|
332
|
+
}
|
|
333
|
+
if (asType === "Map") {
|
|
334
|
+
return currentPeeked == null ? void 0 : currentPeeked.get(itemKey);
|
|
335
|
+
}
|
|
336
|
+
return currentPeeked == null ? void 0 : currentPeeked[itemKey];
|
|
337
|
+
};
|
|
338
|
+
const isFailedCreateReadyToRetry = (itemKey) => {
|
|
339
|
+
const pendingCreate = pendingCreates.get(itemKey);
|
|
340
|
+
return !!(pendingCreate == null ? void 0 : pendingCreate.hasFailed) && !pendingCreate.promise;
|
|
341
|
+
};
|
|
342
|
+
const addCreate = (id, itemValue, change) => {
|
|
343
|
+
const existingPendingCreate = pendingCreates.get(id);
|
|
344
|
+
if ((existingPendingCreate == null ? void 0 : existingPendingCreate.hasFailed) && !existingPendingCreate.promise && change.path.length === 0) {
|
|
345
|
+
existingPendingCreate.change = change;
|
|
346
|
+
}
|
|
347
|
+
const pendingCreate = beginPendingCreate(id, change);
|
|
348
|
+
changesById.set(id, pendingCreate.change);
|
|
349
|
+
creates.set(id, itemValue);
|
|
350
|
+
};
|
|
218
351
|
changes.forEach((change) => {
|
|
219
352
|
var _a, _b;
|
|
220
353
|
const { path, prevAtPath, valueAtPath, pathTypes } = change;
|
|
@@ -227,12 +360,14 @@ function syncedCrud(props) {
|
|
|
227
360
|
const id = value[fieldId];
|
|
228
361
|
if (!isNullOrUndefined(id)) {
|
|
229
362
|
changesById.set(id, change);
|
|
230
|
-
if (
|
|
363
|
+
if (isFailedCreateReadyToRetry(id)) {
|
|
364
|
+
isCreate = true;
|
|
365
|
+
} else if (pendingCreates.has(id)) {
|
|
231
366
|
isCreate = false;
|
|
232
367
|
}
|
|
233
368
|
if (isCreate || retryAsCreate) {
|
|
234
369
|
if (createFn) {
|
|
235
|
-
|
|
370
|
+
addCreate(id, value, change);
|
|
236
371
|
} else {
|
|
237
372
|
console.warn("[legend-state] missing create function");
|
|
238
373
|
}
|
|
@@ -257,8 +392,11 @@ function syncedCrud(props) {
|
|
|
257
392
|
console.error("[legend-state]: added synced item without an id");
|
|
258
393
|
}
|
|
259
394
|
} else if (path.length === 0) {
|
|
260
|
-
|
|
261
|
-
|
|
395
|
+
const id = prevAtPath == null ? void 0 : prevAtPath[fieldId];
|
|
396
|
+
if (!cancelFailedPendingCreate(id)) {
|
|
397
|
+
deletes.add(prevAtPath);
|
|
398
|
+
changesById.set(prevAtPath[fieldId], change);
|
|
399
|
+
}
|
|
262
400
|
}
|
|
263
401
|
} else {
|
|
264
402
|
let itemsChanged = [];
|
|
@@ -281,7 +419,11 @@ function syncedCrud(props) {
|
|
|
281
419
|
for (let i = 0; i < lengthPrev; i++) {
|
|
282
420
|
const key = keysPrev[i];
|
|
283
421
|
if (!keysSet.has(key)) {
|
|
284
|
-
|
|
422
|
+
const prevValue = prevAsObject[key];
|
|
423
|
+
const id = prevValue == null ? void 0 : prevValue[fieldId];
|
|
424
|
+
if (!cancelFailedPendingCreate(id)) {
|
|
425
|
+
deletes.add(prevValue);
|
|
426
|
+
}
|
|
285
427
|
}
|
|
286
428
|
}
|
|
287
429
|
for (let i = 0; i < length; i++) {
|
|
@@ -293,7 +435,8 @@ function syncedCrud(props) {
|
|
|
293
435
|
return false;
|
|
294
436
|
} else {
|
|
295
437
|
const isDiff = !prevAsObject || !deepEqual(value2, prev);
|
|
296
|
-
|
|
438
|
+
const isFailedCreateRetry = isFailedCreateReadyToRetry(value2 == null ? void 0 : value2[fieldId]);
|
|
439
|
+
if (isDiff || isFailedCreateRetry) {
|
|
297
440
|
itemsChanged.push([getUpdateValue(value2, prev), prev, value2]);
|
|
298
441
|
}
|
|
299
442
|
}
|
|
@@ -303,8 +446,11 @@ function syncedCrud(props) {
|
|
|
303
446
|
const itemValue = asMap ? value.get(itemKey) : value[itemKey];
|
|
304
447
|
if (!itemValue) {
|
|
305
448
|
if (path.length === 1 && prevAtPath) {
|
|
306
|
-
|
|
307
|
-
|
|
449
|
+
const id = prevAtPath[fieldId];
|
|
450
|
+
if (!cancelFailedPendingCreate(id)) {
|
|
451
|
+
deletes.add(prevAtPath);
|
|
452
|
+
changesById.set(id, change);
|
|
453
|
+
}
|
|
308
454
|
}
|
|
309
455
|
} else {
|
|
310
456
|
if (generateId) {
|
|
@@ -320,27 +466,26 @@ function syncedCrud(props) {
|
|
|
320
466
|
}
|
|
321
467
|
}
|
|
322
468
|
itemsChanged == null ? void 0 : itemsChanged.forEach(([item, prev, fullValue]) => {
|
|
323
|
-
const
|
|
469
|
+
const id = item[fieldId];
|
|
470
|
+
const isFailedCreateRetry = isFailedCreateReadyToRetry(id);
|
|
471
|
+
const isCreate = isFailedCreateRetry || !pendingCreates.has(id) && (fieldCreatedAt ? !item[fieldCreatedAt] && !(prev == null ? void 0 : prev[fieldCreatedAt]) : fieldUpdatedAt ? !item[fieldUpdatedAt] && !(prev == null ? void 0 : prev[fieldCreatedAt]) : isNullOrUndefined(prev));
|
|
324
472
|
if (isCreate) {
|
|
325
|
-
if (!
|
|
473
|
+
if (!id) {
|
|
326
474
|
console.error("[legend-state]: added item without an id");
|
|
327
475
|
}
|
|
328
476
|
if (createFn) {
|
|
329
|
-
|
|
330
|
-
changesById.set(id, change);
|
|
331
|
-
pendingCreates.add(id);
|
|
332
|
-
creates.set(id, item);
|
|
477
|
+
addCreate(id, isFailedCreateRetry ? fullValue : item, change);
|
|
333
478
|
} else {
|
|
334
479
|
console.warn("[legend-state] missing create function");
|
|
335
480
|
}
|
|
336
481
|
} else {
|
|
337
482
|
if (updateFn) {
|
|
338
|
-
const
|
|
339
|
-
changesById.set(
|
|
340
|
-
updates.set(
|
|
483
|
+
const id2 = item[fieldId];
|
|
484
|
+
changesById.set(id2, change);
|
|
485
|
+
updates.set(id2, updates.has(id2) ? Object.assign(updates.get(id2), item) : item);
|
|
341
486
|
updateFullValues.set(
|
|
342
|
-
|
|
343
|
-
updateFullValues.has(
|
|
487
|
+
id2,
|
|
488
|
+
updateFullValues.has(id2) ? Object.assign(updateFullValues.get(id2), fullValue) : fullValue
|
|
344
489
|
);
|
|
345
490
|
} else {
|
|
346
491
|
console.warn("[legend-state] missing update function");
|
|
@@ -411,7 +556,28 @@ function syncedCrud(props) {
|
|
|
411
556
|
await waitForSet(waitForSetParam, changes, itemValue, { type: "create" });
|
|
412
557
|
}
|
|
413
558
|
const createObj = await transformOut(itemValue, transform == null ? void 0 : transform.save);
|
|
414
|
-
|
|
559
|
+
const pendingCreate = pendingCreates.get(itemKey) || { hasFailed: false };
|
|
560
|
+
pendingCreates.set(itemKey, pendingCreate);
|
|
561
|
+
const refreshCreateValue = async () => {
|
|
562
|
+
const currentPendingCreate = pendingCreates.get(itemKey);
|
|
563
|
+
if (!currentPendingCreate) {
|
|
564
|
+
return false;
|
|
565
|
+
}
|
|
566
|
+
if (!currentPendingCreate.hasFailed) {
|
|
567
|
+
return void 0;
|
|
568
|
+
}
|
|
569
|
+
const currentValue = getCurrentValueAtKey(itemKey);
|
|
570
|
+
if (isNullOrUndefined(currentValue)) {
|
|
571
|
+
clearPendingCreate(itemKey);
|
|
572
|
+
return false;
|
|
573
|
+
}
|
|
574
|
+
const nextCreateObj = await transformOut(
|
|
575
|
+
clone(currentValue),
|
|
576
|
+
transform == null ? void 0 : transform.save
|
|
577
|
+
);
|
|
578
|
+
return { value: nextCreateObj, fullValue: nextCreateObj };
|
|
579
|
+
};
|
|
580
|
+
const createPromise = retrySet(
|
|
415
581
|
params,
|
|
416
582
|
retry,
|
|
417
583
|
"create",
|
|
@@ -421,13 +587,31 @@ function syncedCrud(props) {
|
|
|
421
587
|
queuedRetries,
|
|
422
588
|
createObj,
|
|
423
589
|
createFn,
|
|
424
|
-
saveResult
|
|
425
|
-
|
|
426
|
-
|
|
590
|
+
saveResult,
|
|
591
|
+
{
|
|
592
|
+
onAttemptFailure: () => markPendingCreateFailed(itemKey),
|
|
593
|
+
refreshValue: refreshCreateValue
|
|
594
|
+
}
|
|
595
|
+
);
|
|
596
|
+
pendingCreate.promise = createPromise;
|
|
597
|
+
return createPromise.then((result) => {
|
|
598
|
+
if (pendingCreates.get(itemKey) === pendingCreate) {
|
|
599
|
+
pendingCreates.delete(itemKey);
|
|
600
|
+
}
|
|
601
|
+
return result;
|
|
602
|
+
}).catch((error) => {
|
|
603
|
+
if (pendingCreates.get(itemKey) === pendingCreate) {
|
|
604
|
+
pendingCreate.promise = void 0;
|
|
605
|
+
}
|
|
606
|
+
throw error;
|
|
427
607
|
});
|
|
428
608
|
}),
|
|
429
609
|
// Handle updates
|
|
430
610
|
...Array.from(updates).map(async ([itemKey, itemValue]) => {
|
|
611
|
+
const pendingCreate = pendingCreates.get(itemKey);
|
|
612
|
+
if ((pendingCreate == null ? void 0 : pendingCreate.hasFailed) && pendingCreate.promise) {
|
|
613
|
+
await pendingCreate.promise;
|
|
614
|
+
}
|
|
431
615
|
const fullValue = updateFullValues.get(itemKey);
|
|
432
616
|
if (waitForSetParam) {
|
|
433
617
|
await waitForSet(waitForSetParam, changes, fullValue, { type: "update" });
|
|
@@ -510,6 +694,7 @@ function syncedCrud(props) {
|
|
|
510
694
|
paramsForUpdate.lastSync = newLastSync;
|
|
511
695
|
}
|
|
512
696
|
const rowsTransformed = (transform == null ? void 0 : transform.load) ? await transformRows(rows) : rows;
|
|
697
|
+
clearPendingCreatesForValues(rows);
|
|
513
698
|
paramsForUpdate.value = resultsToOutType(rowsTransformed);
|
|
514
699
|
params.update(paramsForUpdate);
|
|
515
700
|
}
|
package/sync.js
CHANGED
|
@@ -249,6 +249,12 @@ function createRevertChanges(obs$, changes) {
|
|
|
249
249
|
};
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
+
// src/onChange.ts
|
|
253
|
+
function markNodeAsSynced(node) {
|
|
254
|
+
const activationState = node.activationState || (node.activationState = {});
|
|
255
|
+
activationState.synced = true;
|
|
256
|
+
}
|
|
257
|
+
|
|
252
258
|
// src/sync/syncObservable.ts
|
|
253
259
|
var {
|
|
254
260
|
clone: clone2,
|
|
@@ -715,11 +721,12 @@ async function doChangeRemote(changeInfo) {
|
|
|
715
721
|
onError: onSetError,
|
|
716
722
|
update: (params) => {
|
|
717
723
|
if (updateResult) {
|
|
718
|
-
const { value: value2, mode, changes } = params;
|
|
724
|
+
const { value: value2, mode, changes, failedChanges } = params;
|
|
719
725
|
updateResult = {
|
|
720
726
|
value: deepMerge(updateResult.value, value2),
|
|
721
727
|
mode,
|
|
722
|
-
changes: changes ? [...updateResult.changes || [], ...changes] : updateResult.changes
|
|
728
|
+
changes: changes ? [...updateResult.changes || [], ...changes] : updateResult.changes,
|
|
729
|
+
failedChanges: failedChanges ? [...updateResult.failedChanges || [], ...failedChanges] : updateResult.failedChanges
|
|
723
730
|
};
|
|
724
731
|
} else {
|
|
725
732
|
updateResult = params;
|
|
@@ -742,7 +749,11 @@ async function doChangeRemote(changeInfo) {
|
|
|
742
749
|
});
|
|
743
750
|
}
|
|
744
751
|
if (!didError || (updateResult == null ? void 0 : updateResult.changes)) {
|
|
745
|
-
const {
|
|
752
|
+
const {
|
|
753
|
+
value: updateValue,
|
|
754
|
+
changes: updateChanges = changesRemote,
|
|
755
|
+
failedChanges = []
|
|
756
|
+
} = updateResult || {};
|
|
746
757
|
const changesWithPath = updateChanges;
|
|
747
758
|
const pathStrs = Array.from(new Set(changesWithPath.map((change) => change.pathStr)));
|
|
748
759
|
if (pathStrs.length > 0) {
|
|
@@ -750,6 +761,7 @@ async function doChangeRemote(changeInfo) {
|
|
|
750
761
|
const metadata = {};
|
|
751
762
|
const pending = localState.pendingChanges;
|
|
752
763
|
const pendingToKeep = /* @__PURE__ */ new Set();
|
|
764
|
+
const failedPathStrs = new Set(failedChanges.map((change) => change.pathStr));
|
|
753
765
|
if (pending) {
|
|
754
766
|
const changesByPath = /* @__PURE__ */ new Map();
|
|
755
767
|
for (let i = 0; i < changesWithPath.length; i++) {
|
|
@@ -762,7 +774,7 @@ async function doChangeRemote(changeInfo) {
|
|
|
762
774
|
continue;
|
|
763
775
|
}
|
|
764
776
|
const change = changesByPath.get(key);
|
|
765
|
-
if (!change || !deepEqual(pendingEntry.v, change.valueAtPath)) {
|
|
777
|
+
if (failedPathStrs.has(key) || !change || !deepEqual(pendingEntry.v, change.valueAtPath)) {
|
|
766
778
|
pendingToKeep.add(key);
|
|
767
779
|
}
|
|
768
780
|
}
|
|
@@ -996,6 +1008,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
|
|
|
996
1008
|
if ((process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") && (!obs$ || !node)) {
|
|
997
1009
|
throw new Error("[legend-state] syncObservable called with undefined observable");
|
|
998
1010
|
}
|
|
1011
|
+
markNodeAsSynced(node);
|
|
999
1012
|
syncOptions = deepMerge(
|
|
1000
1013
|
{
|
|
1001
1014
|
syncMode: "auto"
|
package/sync.mjs
CHANGED
|
@@ -247,6 +247,12 @@ function createRevertChanges(obs$, changes) {
|
|
|
247
247
|
};
|
|
248
248
|
}
|
|
249
249
|
|
|
250
|
+
// src/onChange.ts
|
|
251
|
+
function markNodeAsSynced(node) {
|
|
252
|
+
const activationState = node.activationState || (node.activationState = {});
|
|
253
|
+
activationState.synced = true;
|
|
254
|
+
}
|
|
255
|
+
|
|
250
256
|
// src/sync/syncObservable.ts
|
|
251
257
|
var {
|
|
252
258
|
clone: clone2,
|
|
@@ -713,11 +719,12 @@ async function doChangeRemote(changeInfo) {
|
|
|
713
719
|
onError: onSetError,
|
|
714
720
|
update: (params) => {
|
|
715
721
|
if (updateResult) {
|
|
716
|
-
const { value: value2, mode, changes } = params;
|
|
722
|
+
const { value: value2, mode, changes, failedChanges } = params;
|
|
717
723
|
updateResult = {
|
|
718
724
|
value: deepMerge(updateResult.value, value2),
|
|
719
725
|
mode,
|
|
720
|
-
changes: changes ? [...updateResult.changes || [], ...changes] : updateResult.changes
|
|
726
|
+
changes: changes ? [...updateResult.changes || [], ...changes] : updateResult.changes,
|
|
727
|
+
failedChanges: failedChanges ? [...updateResult.failedChanges || [], ...failedChanges] : updateResult.failedChanges
|
|
721
728
|
};
|
|
722
729
|
} else {
|
|
723
730
|
updateResult = params;
|
|
@@ -740,7 +747,11 @@ async function doChangeRemote(changeInfo) {
|
|
|
740
747
|
});
|
|
741
748
|
}
|
|
742
749
|
if (!didError || (updateResult == null ? void 0 : updateResult.changes)) {
|
|
743
|
-
const {
|
|
750
|
+
const {
|
|
751
|
+
value: updateValue,
|
|
752
|
+
changes: updateChanges = changesRemote,
|
|
753
|
+
failedChanges = []
|
|
754
|
+
} = updateResult || {};
|
|
744
755
|
const changesWithPath = updateChanges;
|
|
745
756
|
const pathStrs = Array.from(new Set(changesWithPath.map((change) => change.pathStr)));
|
|
746
757
|
if (pathStrs.length > 0) {
|
|
@@ -748,6 +759,7 @@ async function doChangeRemote(changeInfo) {
|
|
|
748
759
|
const metadata = {};
|
|
749
760
|
const pending = localState.pendingChanges;
|
|
750
761
|
const pendingToKeep = /* @__PURE__ */ new Set();
|
|
762
|
+
const failedPathStrs = new Set(failedChanges.map((change) => change.pathStr));
|
|
751
763
|
if (pending) {
|
|
752
764
|
const changesByPath = /* @__PURE__ */ new Map();
|
|
753
765
|
for (let i = 0; i < changesWithPath.length; i++) {
|
|
@@ -760,7 +772,7 @@ async function doChangeRemote(changeInfo) {
|
|
|
760
772
|
continue;
|
|
761
773
|
}
|
|
762
774
|
const change = changesByPath.get(key);
|
|
763
|
-
if (!change || !deepEqual(pendingEntry.v, change.valueAtPath)) {
|
|
775
|
+
if (failedPathStrs.has(key) || !change || !deepEqual(pendingEntry.v, change.valueAtPath)) {
|
|
764
776
|
pendingToKeep.add(key);
|
|
765
777
|
}
|
|
766
778
|
}
|
|
@@ -994,6 +1006,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
|
|
|
994
1006
|
if ((process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") && (!obs$ || !node)) {
|
|
995
1007
|
throw new Error("[legend-state] syncObservable called with undefined observable");
|
|
996
1008
|
}
|
|
1009
|
+
markNodeAsSynced(node);
|
|
997
1010
|
syncOptions = deepMerge(
|
|
998
1011
|
{
|
|
999
1012
|
syncMode: "auto"
|
package/.DS_Store
DELETED
|
Binary file
|