@legendapp/state 3.0.0-beta.3 → 3.0.0-beta.31
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/.DS_Store +0 -0
- package/config/enableReactComponents.js +3 -1
- package/config/enableReactComponents.mjs +3 -1
- package/config/enableReactTracking.d.mts +2 -1
- package/config/enableReactTracking.d.ts +2 -1
- package/config/enableReactTracking.js +32 -13
- package/config/enableReactTracking.mjs +32 -13
- package/index.d.mts +38 -5
- package/index.d.ts +38 -5
- package/index.js +202 -31
- package/index.mjs +202 -31
- package/package.json +35 -1
- package/persist-plugins/async-storage.js +17 -9
- package/persist-plugins/async-storage.mjs +17 -9
- package/persist-plugins/expo-sqlite.d.mts +19 -0
- package/persist-plugins/expo-sqlite.d.ts +19 -0
- package/persist-plugins/expo-sqlite.js +72 -0
- package/persist-plugins/expo-sqlite.mjs +69 -0
- package/react-native.d.mts +4 -0
- package/react-native.d.ts +4 -0
- package/react-native.js +53 -0
- package/react-native.mjs +40 -0
- package/react-reactive/Components.d.mts +19 -0
- package/react-reactive/Components.d.ts +19 -0
- package/react-reactive/Components.js +53 -0
- package/react-reactive/Components.mjs +40 -0
- package/react-reactive/enableReactComponents.d.mts +3 -2
- package/react-reactive/enableReactComponents.d.ts +3 -2
- package/react-reactive/enableReactComponents.js +10 -3
- package/react-reactive/enableReactComponents.mjs +10 -3
- package/react-reactive/enableReactNativeComponents.d.mts +3 -20
- package/react-reactive/enableReactNativeComponents.d.ts +3 -20
- package/react-reactive/enableReactNativeComponents.js +8 -3
- package/react-reactive/enableReactNativeComponents.mjs +8 -3
- package/react-reactive/enableReactive.js +10 -3
- package/react-reactive/enableReactive.mjs +10 -3
- package/react-reactive/enableReactive.native.js +8 -3
- package/react-reactive/enableReactive.native.mjs +8 -3
- package/react-reactive/enableReactive.web.js +8 -3
- package/react-reactive/enableReactive.web.mjs +8 -3
- package/react-web.d.mts +6 -0
- package/react-web.d.ts +6 -0
- package/react-web.js +39 -0
- package/react-web.mjs +37 -0
- package/react.d.mts +41 -21
- package/react.d.ts +41 -21
- package/react.js +86 -63
- package/react.mjs +87 -65
- package/sync-plugins/crud.d.mts +24 -9
- package/sync-plugins/crud.d.ts +24 -9
- package/sync-plugins/crud.js +250 -116
- package/sync-plugins/crud.mjs +251 -117
- package/sync-plugins/firebase.d.mts +7 -3
- package/sync-plugins/firebase.d.ts +7 -3
- package/sync-plugins/firebase.js +4 -2
- package/sync-plugins/firebase.mjs +4 -2
- package/sync-plugins/keel.d.mts +12 -13
- package/sync-plugins/keel.d.ts +12 -13
- package/sync-plugins/keel.js +60 -52
- package/sync-plugins/keel.mjs +61 -48
- package/sync-plugins/supabase.d.mts +7 -3
- package/sync-plugins/supabase.d.ts +7 -3
- package/sync-plugins/supabase.js +90 -33
- package/sync-plugins/supabase.mjs +91 -34
- package/sync-plugins/tanstack-query.d.mts +3 -3
- package/sync-plugins/tanstack-query.d.ts +3 -3
- package/sync.d.mts +16 -8
- package/sync.d.ts +16 -8
- package/sync.js +324 -215
- package/sync.mjs +323 -215
- package/trace.js +5 -6
- package/trace.mjs +5 -6
- package/types/reactive-native.d.ts +19 -0
- package/types/reactive-web.d.ts +7 -0
package/sync-plugins/crud.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { isPromise,
|
|
1
|
+
import { isPromise, isNullOrUndefined, applyChanges, setAtPath, symbolDelete, isArray, internal, getNodeValue } from '@legendapp/state';
|
|
2
2
|
import { synced, deepEqual, internal as internal$1, diffObjects } from '@legendapp/state/sync';
|
|
3
3
|
|
|
4
4
|
// src/sync-plugins/crud.ts
|
|
5
|
-
var { clone } = internal;
|
|
6
|
-
var { waitForSet } = internal$1;
|
|
5
|
+
var { clone, getKeys } = internal;
|
|
6
|
+
var { waitForSet, runWithRetry } = internal$1;
|
|
7
7
|
function transformOut(data, transform) {
|
|
8
8
|
return transform ? transform(clone(data)) : data;
|
|
9
9
|
}
|
|
@@ -23,6 +23,47 @@ function computeLastSync(data, fieldUpdatedAt, fieldCreatedAt) {
|
|
|
23
23
|
}
|
|
24
24
|
return newLastSync;
|
|
25
25
|
}
|
|
26
|
+
function arrayToRecord(arr, keyField) {
|
|
27
|
+
const record = {};
|
|
28
|
+
if (arr == null ? void 0 : arr.length) {
|
|
29
|
+
for (let i = 0; i < arr.length; i++) {
|
|
30
|
+
const v = arr[i];
|
|
31
|
+
const key = v[keyField];
|
|
32
|
+
record[key] = v;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return record;
|
|
36
|
+
}
|
|
37
|
+
function retrySet(params, retry, action, itemKey, itemValue, change, queuedRetries, itemValueFull, actionFn, saveResult) {
|
|
38
|
+
if (action === "delete") {
|
|
39
|
+
if (queuedRetries.create.has(itemKey)) {
|
|
40
|
+
queuedRetries.create.delete(itemKey);
|
|
41
|
+
}
|
|
42
|
+
if (queuedRetries.update.has(itemKey)) {
|
|
43
|
+
queuedRetries.update.delete(itemKey);
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
if (queuedRetries.delete.has(itemKey)) {
|
|
47
|
+
queuedRetries.delete.delete(itemKey);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const queuedRetry = queuedRetries[action].get(itemKey);
|
|
51
|
+
if (queuedRetry) {
|
|
52
|
+
itemValue = Object.assign(queuedRetry, itemValue);
|
|
53
|
+
}
|
|
54
|
+
queuedRetries[action].set(itemKey, itemValue);
|
|
55
|
+
const clonedValue = clone(itemValueFull);
|
|
56
|
+
const paramsWithChanges = { ...params, changes: [change] };
|
|
57
|
+
return runWithRetry(
|
|
58
|
+
paramsWithChanges,
|
|
59
|
+
retry,
|
|
60
|
+
"create_" + itemKey,
|
|
61
|
+
() => actionFn(itemValue, paramsWithChanges).then((result) => {
|
|
62
|
+
queuedRetries[action].delete(itemKey);
|
|
63
|
+
return saveResult(itemKey, clonedValue, result, true, change);
|
|
64
|
+
})
|
|
65
|
+
);
|
|
66
|
+
}
|
|
26
67
|
function syncedCrud(props) {
|
|
27
68
|
const {
|
|
28
69
|
get: getFn,
|
|
@@ -43,10 +84,16 @@ function syncedCrud(props) {
|
|
|
43
84
|
changesSince,
|
|
44
85
|
generateId,
|
|
45
86
|
waitForSet: waitForSetParam,
|
|
87
|
+
retry,
|
|
46
88
|
...rest
|
|
47
89
|
} = props;
|
|
48
90
|
const fieldId = fieldIdProp || "id";
|
|
49
91
|
const pendingCreates = /* @__PURE__ */ new Set();
|
|
92
|
+
const queuedRetries = {
|
|
93
|
+
create: /* @__PURE__ */ new Map(),
|
|
94
|
+
update: /* @__PURE__ */ new Map(),
|
|
95
|
+
delete: /* @__PURE__ */ new Map()
|
|
96
|
+
};
|
|
50
97
|
let asType = props.as;
|
|
51
98
|
if (!asType) {
|
|
52
99
|
asType = getFn ? "value" : "object";
|
|
@@ -75,69 +122,76 @@ function syncedCrud(props) {
|
|
|
75
122
|
return out;
|
|
76
123
|
};
|
|
77
124
|
const transformRows = (data) => {
|
|
78
|
-
return Promise.all(
|
|
125
|
+
return data.length ? Promise.all(
|
|
79
126
|
data.map(
|
|
80
127
|
(value) => (
|
|
81
128
|
// Skip transforming any children with symbolDelete or fieldDeleted because they'll get deleted by resultsToOutType
|
|
82
129
|
value[symbolDelete] || fieldDeleted && value[fieldDeleted] || fieldDeletedList && value[fieldDeletedList] ? value : transform.load(value, "get")
|
|
83
130
|
)
|
|
84
131
|
)
|
|
85
|
-
);
|
|
132
|
+
) : [];
|
|
86
133
|
};
|
|
87
134
|
const get = getFn || listFn ? (getParams) => {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const listPromise = listFn(getParams);
|
|
95
|
-
const toOut = (transformed) => {
|
|
96
|
-
var _a;
|
|
97
|
-
if (asType === "value") {
|
|
98
|
-
return transformed.length > 0 ? transformed[0] : (_a = (isLastSyncMode && lastSync || fieldDeleted) && value) != null ? _a : null;
|
|
99
|
-
} else {
|
|
100
|
-
return resultsToOutType(transformed);
|
|
135
|
+
return runWithRetry(getParams, retry, getFn || listFn, () => {
|
|
136
|
+
const { updateLastSync, lastSync, value } = getParams;
|
|
137
|
+
if (listFn) {
|
|
138
|
+
const isLastSyncMode = changesSince === "last-sync";
|
|
139
|
+
if (isLastSyncMode && lastSync) {
|
|
140
|
+
getParams.mode = modeParam || (asType === "array" ? "append" : asType === "value" ? "set" : "assign");
|
|
101
141
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
142
|
+
const listPromise = listFn(getParams);
|
|
143
|
+
const toOut = (transformed) => {
|
|
144
|
+
if (asType === "value") {
|
|
145
|
+
if (transformed.length > 0) {
|
|
146
|
+
return transformed[0];
|
|
147
|
+
} else {
|
|
148
|
+
return value ? void 0 : null;
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
return resultsToOutType(transformed);
|
|
109
152
|
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
} else if (getFn) {
|
|
119
|
-
const dataPromise = getFn(getParams);
|
|
120
|
-
const processData = (data) => {
|
|
121
|
-
let transformed = data;
|
|
122
|
-
if (data) {
|
|
123
|
-
const newLastSync = data[fieldUpdatedAt] || data[fieldCreatedAt];
|
|
124
|
-
if (newLastSync && newLastSync !== lastSync) {
|
|
125
|
-
updateLastSync(newLastSync);
|
|
153
|
+
};
|
|
154
|
+
const processResults = (data) => {
|
|
155
|
+
data || (data = []);
|
|
156
|
+
if (fieldUpdatedAt) {
|
|
157
|
+
const newLastSync = computeLastSync(data, fieldUpdatedAt, fieldCreatedAt);
|
|
158
|
+
if (newLastSync && newLastSync !== lastSync) {
|
|
159
|
+
updateLastSync(newLastSync);
|
|
160
|
+
}
|
|
126
161
|
}
|
|
162
|
+
let transformed = data;
|
|
127
163
|
if (transform == null ? void 0 : transform.load) {
|
|
128
|
-
transformed =
|
|
164
|
+
transformed = transformRows(data);
|
|
129
165
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
166
|
+
return isPromise(transformed) ? transformed.then(toOut) : toOut(transformed);
|
|
167
|
+
};
|
|
168
|
+
return isPromise(listPromise) ? listPromise.then(processResults) : processResults(listPromise);
|
|
169
|
+
} else if (getFn) {
|
|
170
|
+
const dataPromise = getFn(getParams);
|
|
171
|
+
const processData = (data) => {
|
|
172
|
+
let transformed = data;
|
|
173
|
+
if (data) {
|
|
174
|
+
const newLastSync = data[fieldUpdatedAt] || data[fieldCreatedAt];
|
|
175
|
+
if (newLastSync && newLastSync !== lastSync) {
|
|
176
|
+
updateLastSync(newLastSync);
|
|
177
|
+
}
|
|
178
|
+
if (transform == null ? void 0 : transform.load) {
|
|
179
|
+
transformed = transform.load(data, "get");
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return transformed;
|
|
183
|
+
};
|
|
184
|
+
return isPromise(dataPromise) ? dataPromise.then(processData) : processData(dataPromise);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
135
187
|
} : void 0;
|
|
136
188
|
const set = createFn || updateFn || deleteFn ? async (params) => {
|
|
137
189
|
const { value, changes, update, retryAsCreate, node } = params;
|
|
138
190
|
const creates = /* @__PURE__ */ new Map();
|
|
139
191
|
const updates = /* @__PURE__ */ new Map();
|
|
192
|
+
const updateFullValues = /* @__PURE__ */ new Map();
|
|
140
193
|
const deletes = /* @__PURE__ */ new Set();
|
|
194
|
+
const changesById = /* @__PURE__ */ new Map();
|
|
141
195
|
const getUpdateValue = (itemValue, prev) => {
|
|
142
196
|
return updatePartial ? Object.assign(
|
|
143
197
|
diffObjects(
|
|
@@ -146,19 +200,21 @@ function syncedCrud(props) {
|
|
|
146
200
|
/*deep*/
|
|
147
201
|
true
|
|
148
202
|
),
|
|
149
|
-
itemValue[fieldId] ? { [fieldId]: itemValue[fieldId] } : {}
|
|
203
|
+
!isNullOrUndefined(itemValue[fieldId]) ? { [fieldId]: itemValue[fieldId] } : {}
|
|
150
204
|
) : itemValue;
|
|
151
205
|
};
|
|
152
206
|
changes.forEach((change) => {
|
|
207
|
+
var _a, _b;
|
|
153
208
|
const { path, prevAtPath, valueAtPath, pathTypes } = change;
|
|
154
209
|
if (asType === "value") {
|
|
155
210
|
if (value) {
|
|
156
211
|
let id = value == null ? void 0 : value[fieldId];
|
|
157
212
|
let isCreate = fieldCreatedAt ? !value[fieldCreatedAt] : !prevAtPath;
|
|
158
|
-
if (
|
|
213
|
+
if (isNullOrUndefined(id) && generateId) {
|
|
159
214
|
id = ensureId(value, fieldId, generateId);
|
|
160
215
|
}
|
|
161
|
-
if (id) {
|
|
216
|
+
if (!isNullOrUndefined(id)) {
|
|
217
|
+
changesById.set(id, change);
|
|
162
218
|
if (pendingCreates.has(id)) {
|
|
163
219
|
isCreate = false;
|
|
164
220
|
}
|
|
@@ -171,6 +227,7 @@ function syncedCrud(props) {
|
|
|
171
227
|
} else if (path.length === 0) {
|
|
172
228
|
if (valueAtPath) {
|
|
173
229
|
updates.set(id, getUpdateValue(valueAtPath, prevAtPath));
|
|
230
|
+
updateFullValues.set(id, valueAtPath);
|
|
174
231
|
} else if (prevAtPath) {
|
|
175
232
|
deletes.add(prevAtPath);
|
|
176
233
|
}
|
|
@@ -182,27 +239,42 @@ function syncedCrud(props) {
|
|
|
182
239
|
true
|
|
183
240
|
);
|
|
184
241
|
updates.set(id, getUpdateValue(value, previous));
|
|
242
|
+
updateFullValues.set(id, value);
|
|
185
243
|
}
|
|
186
244
|
} else {
|
|
187
245
|
console.error("[legend-state]: added synced item without an id");
|
|
188
246
|
}
|
|
189
247
|
} else if (path.length === 0) {
|
|
190
248
|
deletes.add(prevAtPath);
|
|
249
|
+
changesById.set(prevAtPath[fieldId], change);
|
|
191
250
|
}
|
|
192
251
|
} else {
|
|
193
252
|
let itemsChanged = [];
|
|
194
253
|
if (path.length === 0) {
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
254
|
+
const valueAsObject = asArray ? arrayToRecord(valueAtPath, fieldId) : valueAtPath;
|
|
255
|
+
const prevAsObject = asArray ? arrayToRecord(prevAtPath, fieldId) : prevAtPath;
|
|
256
|
+
const keys = getKeys(valueAsObject, false, asMap, false);
|
|
257
|
+
const keysPrev = getKeys(prevAsObject, false, asMap, false);
|
|
258
|
+
const keysSet = new Set(keys);
|
|
259
|
+
const length = ((_a = keys || valueAsObject) == null ? void 0 : _a.length) || 0;
|
|
260
|
+
const lengthPrev = ((_b = keysPrev || prevAsObject) == null ? void 0 : _b.length) || 0;
|
|
261
|
+
for (let i = 0; i < lengthPrev; i++) {
|
|
262
|
+
const key = keysPrev[i];
|
|
263
|
+
if (!keysSet.has(key)) {
|
|
264
|
+
deletes.add(prevAsObject[key]);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
for (let i = 0; i < length; i++) {
|
|
268
|
+
const key = keys[i];
|
|
269
|
+
const value2 = asMap ? valueAsObject.get(key) : valueAsObject[key];
|
|
270
|
+
const prev = prevAsObject ? asMap ? prevAsObject.get(key) : prevAsObject[key] : void 0;
|
|
199
271
|
if (isNullOrUndefined(value2) && !isNullOrUndefined(prev)) {
|
|
200
272
|
deletes.add(prev);
|
|
201
273
|
return false;
|
|
202
274
|
} else {
|
|
203
|
-
const isDiff = !
|
|
275
|
+
const isDiff = !prevAsObject || !deepEqual(value2, prev);
|
|
204
276
|
if (isDiff) {
|
|
205
|
-
itemsChanged.push([getUpdateValue(value2, prev), prev]);
|
|
277
|
+
itemsChanged.push([getUpdateValue(value2, prev), prev, value2]);
|
|
206
278
|
}
|
|
207
279
|
}
|
|
208
280
|
}
|
|
@@ -212,6 +284,7 @@ function syncedCrud(props) {
|
|
|
212
284
|
if (!itemValue) {
|
|
213
285
|
if (path.length === 1 && prevAtPath) {
|
|
214
286
|
deletes.add(prevAtPath);
|
|
287
|
+
changesById.set(prevAtPath[fieldId], change);
|
|
215
288
|
}
|
|
216
289
|
} else {
|
|
217
290
|
const previous = setAtPath(
|
|
@@ -220,10 +293,10 @@ function syncedCrud(props) {
|
|
|
220
293
|
pathTypes.slice(1),
|
|
221
294
|
prevAtPath
|
|
222
295
|
);
|
|
223
|
-
itemsChanged = [[getUpdateValue(itemValue, previous), previous]];
|
|
296
|
+
itemsChanged = [[getUpdateValue(itemValue, previous), previous, itemValue]];
|
|
224
297
|
}
|
|
225
298
|
}
|
|
226
|
-
itemsChanged == null ? void 0 : itemsChanged.forEach(([item, prev]) => {
|
|
299
|
+
itemsChanged == null ? void 0 : itemsChanged.forEach(([item, prev, fullValue]) => {
|
|
227
300
|
const isCreate = !pendingCreates.has(item[fieldId]) && (fieldCreatedAt ? !item[fieldCreatedAt] && !(prev == null ? void 0 : prev[fieldCreatedAt]) : fieldUpdatedAt ? !item[fieldUpdatedAt] && !(prev == null ? void 0 : prev[fieldCreatedAt]) : isNullOrUndefined(prev));
|
|
228
301
|
if (isCreate) {
|
|
229
302
|
if (generateId) {
|
|
@@ -233,16 +306,21 @@ function syncedCrud(props) {
|
|
|
233
306
|
console.error("[legend-state]: added item without an id");
|
|
234
307
|
}
|
|
235
308
|
if (createFn) {
|
|
236
|
-
|
|
237
|
-
|
|
309
|
+
const id = item[fieldId];
|
|
310
|
+
changesById.set(id, change);
|
|
311
|
+
pendingCreates.add(id);
|
|
312
|
+
creates.set(id, item);
|
|
238
313
|
} else {
|
|
239
314
|
console.warn("[legend-state] missing create function");
|
|
240
315
|
}
|
|
241
316
|
} else {
|
|
242
317
|
if (updateFn) {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
318
|
+
const id = item[fieldId];
|
|
319
|
+
changesById.set(id, change);
|
|
320
|
+
updates.set(id, updates.has(id) ? Object.assign(updates.get(id), item) : item);
|
|
321
|
+
updateFullValues.set(
|
|
322
|
+
id,
|
|
323
|
+
updateFullValues.has(id) ? Object.assign(updateFullValues.get(id), fullValue) : fullValue
|
|
246
324
|
);
|
|
247
325
|
} else {
|
|
248
326
|
console.warn("[legend-state] missing update function");
|
|
@@ -251,93 +329,149 @@ function syncedCrud(props) {
|
|
|
251
329
|
});
|
|
252
330
|
}
|
|
253
331
|
});
|
|
254
|
-
const saveResult = async (itemKey, input, data, isCreate) => {
|
|
332
|
+
const saveResult = async (itemKey, input, data, isCreate, change) => {
|
|
255
333
|
var _a;
|
|
256
334
|
if (data) {
|
|
257
|
-
|
|
335
|
+
let saved = (transform == null ? void 0 : transform.load) ? await transform.load(data, "set") : data;
|
|
258
336
|
const isChild = itemKey !== "undefined" && asType !== "value";
|
|
259
337
|
const currentPeeked = getNodeValue(node);
|
|
260
|
-
const currentValue = isChild ? (_a = asType === "array" && isArray(currentPeeked) ? currentPeeked.find((v) => v[fieldId] === itemKey) : void 0) != null ? _a : currentPeeked[itemKey] : currentPeeked;
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
338
|
+
const currentValue = isChild ? (_a = asType === "array" && isArray(currentPeeked) ? currentPeeked.find((v) => v[fieldId] === itemKey) : void 0) != null ? _a : asType === "Map" ? currentPeeked.get(itemKey) : currentPeeked[itemKey] : currentPeeked;
|
|
339
|
+
if (saved && !isNullOrUndefined(currentValue)) {
|
|
340
|
+
if (onSaved) {
|
|
341
|
+
const ret = onSaved({
|
|
342
|
+
saved,
|
|
343
|
+
input,
|
|
344
|
+
currentValue,
|
|
345
|
+
isCreate,
|
|
346
|
+
props
|
|
347
|
+
});
|
|
348
|
+
if (ret) {
|
|
349
|
+
saved = ret;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
saved = clone(saved);
|
|
353
|
+
Object.keys(saved).forEach((key) => {
|
|
272
354
|
const i = input[key];
|
|
273
355
|
const c = currentValue[key];
|
|
274
356
|
if (
|
|
275
357
|
// value is already the new value, can ignore
|
|
276
|
-
|
|
277
|
-
key !==
|
|
358
|
+
saved[key] === c || // user has changed local value
|
|
359
|
+
key !== fieldId && i !== void 0 && i !== c
|
|
278
360
|
) {
|
|
279
|
-
delete
|
|
361
|
+
delete saved[key];
|
|
280
362
|
}
|
|
281
363
|
});
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
364
|
+
let value2;
|
|
365
|
+
if (asType === "array") {
|
|
366
|
+
const index = currentPeeked.findIndex(
|
|
367
|
+
(cur) => cur[fieldId] === itemKey
|
|
368
|
+
);
|
|
369
|
+
if (index < 0) {
|
|
370
|
+
console.warn("[legend-state] Item saved that does not exist in array", saved);
|
|
371
|
+
} else {
|
|
372
|
+
value2 = { [index < 0 ? 0 : index]: saved };
|
|
286
373
|
}
|
|
374
|
+
} else {
|
|
375
|
+
value2 = itemKey !== "undefined" && asType !== "value" ? { [itemKey]: saved } : saved;
|
|
376
|
+
}
|
|
377
|
+
if (value2 !== void 0) {
|
|
378
|
+
update({
|
|
379
|
+
value: value2,
|
|
380
|
+
mode: "merge",
|
|
381
|
+
changes: [change]
|
|
382
|
+
});
|
|
287
383
|
}
|
|
288
|
-
const createdAt = fieldCreatedAt ? savedOut[fieldCreatedAt] : void 0;
|
|
289
|
-
const updatedAt = fieldUpdatedAt ? savedOut[fieldUpdatedAt] : void 0;
|
|
290
|
-
const value2 = itemKey !== "undefined" && asType !== "value" ? { [itemKey]: savedOut } : savedOut;
|
|
291
|
-
update({
|
|
292
|
-
value: value2,
|
|
293
|
-
lastSync: updatedAt || createdAt ? +new Date(updatedAt || createdAt) : void 0,
|
|
294
|
-
mode: "merge"
|
|
295
|
-
});
|
|
296
384
|
}
|
|
297
385
|
}
|
|
298
386
|
};
|
|
299
387
|
return Promise.all([
|
|
388
|
+
// Handle creates
|
|
300
389
|
...Array.from(creates).map(async ([itemKey, itemValue]) => {
|
|
301
390
|
if (waitForSetParam) {
|
|
302
391
|
await waitForSet(waitForSetParam, changes, itemValue, { type: "create" });
|
|
303
392
|
}
|
|
304
393
|
const createObj = await transformOut(itemValue, transform == null ? void 0 : transform.save);
|
|
305
|
-
return
|
|
306
|
-
|
|
307
|
-
|
|
394
|
+
return retrySet(
|
|
395
|
+
params,
|
|
396
|
+
retry,
|
|
397
|
+
"create",
|
|
398
|
+
itemKey,
|
|
399
|
+
createObj,
|
|
400
|
+
changesById.get(itemKey),
|
|
401
|
+
queuedRetries,
|
|
402
|
+
createObj,
|
|
403
|
+
createFn,
|
|
404
|
+
saveResult
|
|
405
|
+
).then(() => {
|
|
308
406
|
pendingCreates.delete(itemKey);
|
|
309
407
|
});
|
|
310
408
|
}),
|
|
409
|
+
// Handle updates
|
|
311
410
|
...Array.from(updates).map(async ([itemKey, itemValue]) => {
|
|
411
|
+
const fullValue = updateFullValues.get(itemKey);
|
|
312
412
|
if (waitForSetParam) {
|
|
313
|
-
await waitForSet(waitForSetParam, changes,
|
|
413
|
+
await waitForSet(waitForSetParam, changes, fullValue, { type: "update" });
|
|
314
414
|
}
|
|
315
|
-
const
|
|
316
|
-
const
|
|
415
|
+
const changed = await transformOut(itemValue, transform == null ? void 0 : transform.save);
|
|
416
|
+
const fullValueTransformed = await transformOut(
|
|
417
|
+
fullValue,
|
|
418
|
+
transform == null ? void 0 : transform.save
|
|
419
|
+
);
|
|
317
420
|
if (Object.keys(changed).length > 0) {
|
|
318
|
-
return
|
|
319
|
-
|
|
421
|
+
return retrySet(
|
|
422
|
+
params,
|
|
423
|
+
retry,
|
|
424
|
+
"update",
|
|
425
|
+
itemKey,
|
|
426
|
+
changed,
|
|
427
|
+
changesById.get(itemKey),
|
|
428
|
+
queuedRetries,
|
|
429
|
+
fullValueTransformed,
|
|
430
|
+
updateFn,
|
|
431
|
+
saveResult
|
|
320
432
|
);
|
|
321
433
|
}
|
|
322
434
|
}),
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
435
|
+
// Handle deletes
|
|
436
|
+
...Array.from(deletes).filter((val) => val !== symbolDelete).map(async (valuePrevious) => {
|
|
437
|
+
if (waitForSetParam) {
|
|
438
|
+
await waitForSet(waitForSetParam, changes, valuePrevious, { type: "delete" });
|
|
439
|
+
}
|
|
440
|
+
const itemKey = valuePrevious[fieldId];
|
|
441
|
+
if (!itemKey) {
|
|
442
|
+
console.error("[legend-state]: deleting item without an id");
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
if (deleteFn) {
|
|
446
|
+
return retrySet(
|
|
447
|
+
params,
|
|
448
|
+
retry,
|
|
449
|
+
"delete",
|
|
450
|
+
itemKey,
|
|
451
|
+
valuePrevious,
|
|
452
|
+
changesById.get(itemKey),
|
|
453
|
+
queuedRetries,
|
|
454
|
+
valuePrevious,
|
|
455
|
+
deleteFn,
|
|
456
|
+
saveResult
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
if (fieldDeleted && updateFn) {
|
|
460
|
+
const value2 = { [fieldId]: itemKey, [fieldDeleted]: true };
|
|
461
|
+
return retrySet(
|
|
462
|
+
params,
|
|
463
|
+
retry,
|
|
464
|
+
"delete",
|
|
465
|
+
itemKey,
|
|
466
|
+
value2,
|
|
467
|
+
changesById.get(itemKey),
|
|
468
|
+
queuedRetries,
|
|
469
|
+
value2,
|
|
470
|
+
updateFn,
|
|
471
|
+
saveResult
|
|
472
|
+
);
|
|
340
473
|
}
|
|
474
|
+
console.warn("[legend-state] missing delete function");
|
|
341
475
|
})
|
|
342
476
|
]);
|
|
343
477
|
} : void 0;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FieldTransforms } from '@legendapp/state/sync';
|
|
1
|
+
import { FieldTransforms, SyncedErrorParams } from '@legendapp/state/sync';
|
|
2
2
|
export { FieldTransforms } from '@legendapp/state/sync';
|
|
3
3
|
import { CrudAsOption, SyncedCrudPropsMany, SyncedCrudPropsBase, SyncedCrudReturnType } from '@legendapp/state/sync-plugins/crud';
|
|
4
4
|
import { DatabaseReference, Query } from 'firebase/database';
|
|
@@ -6,11 +6,12 @@ import { DatabaseReference, Query } from 'firebase/database';
|
|
|
6
6
|
declare function transformObjectFields(dataIn: Record<string, any>, map: Record<string, any>): any;
|
|
7
7
|
declare function invertFieldMap(obj: Record<string, any>): any;
|
|
8
8
|
|
|
9
|
-
interface SyncedFirebaseProps<TRemote extends object, TLocal, TAs extends CrudAsOption = 'value'> extends Omit<SyncedCrudPropsMany<TRemote, TLocal, TAs>, 'list' | 'retry'>, SyncedCrudPropsBase<TRemote, TLocal> {
|
|
9
|
+
interface SyncedFirebaseProps<TRemote extends object, TLocal, TAs extends CrudAsOption = 'value'> extends Omit<SyncedCrudPropsMany<TRemote, TLocal, TAs>, 'list' | 'retry'>, Omit<SyncedCrudPropsBase<TRemote, TLocal>, 'onError'> {
|
|
10
10
|
refPath: (uid: string | undefined) => string;
|
|
11
11
|
query?: (ref: DatabaseReference) => DatabaseReference | Query;
|
|
12
12
|
fieldId?: string;
|
|
13
13
|
fieldTransforms?: FieldTransforms<TRemote>;
|
|
14
|
+
onError?: (error: Error, params: FirebaseErrorParams) => void;
|
|
14
15
|
realtime?: boolean;
|
|
15
16
|
requireAuth?: boolean;
|
|
16
17
|
readonly?: boolean;
|
|
@@ -22,6 +23,9 @@ interface SyncedFirebaseConfiguration {
|
|
|
22
23
|
enabled?: boolean;
|
|
23
24
|
}
|
|
24
25
|
declare function configureSyncedFirebase(config: SyncedFirebaseConfiguration): void;
|
|
26
|
+
interface FirebaseErrorParams extends Omit<SyncedErrorParams, 'source'> {
|
|
27
|
+
source: 'list' | 'get' | 'create' | 'update' | 'delete';
|
|
28
|
+
}
|
|
25
29
|
declare function syncedFirebase<TRemote extends object, TLocal = TRemote, TAs extends CrudAsOption = 'object'>(props: SyncedFirebaseProps<TRemote, TLocal, TAs>): SyncedCrudReturnType<TLocal, TAs>;
|
|
26
30
|
|
|
27
|
-
export { type SyncedFirebaseProps, configureSyncedFirebase, invertFieldMap, syncedFirebase, transformObjectFields };
|
|
31
|
+
export { type FirebaseErrorParams, type SyncedFirebaseProps, configureSyncedFirebase, invertFieldMap, syncedFirebase, transformObjectFields };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FieldTransforms } from '@legendapp/state/sync';
|
|
1
|
+
import { FieldTransforms, SyncedErrorParams } from '@legendapp/state/sync';
|
|
2
2
|
export { FieldTransforms } from '@legendapp/state/sync';
|
|
3
3
|
import { CrudAsOption, SyncedCrudPropsMany, SyncedCrudPropsBase, SyncedCrudReturnType } from '@legendapp/state/sync-plugins/crud';
|
|
4
4
|
import { DatabaseReference, Query } from 'firebase/database';
|
|
@@ -6,11 +6,12 @@ import { DatabaseReference, Query } from 'firebase/database';
|
|
|
6
6
|
declare function transformObjectFields(dataIn: Record<string, any>, map: Record<string, any>): any;
|
|
7
7
|
declare function invertFieldMap(obj: Record<string, any>): any;
|
|
8
8
|
|
|
9
|
-
interface SyncedFirebaseProps<TRemote extends object, TLocal, TAs extends CrudAsOption = 'value'> extends Omit<SyncedCrudPropsMany<TRemote, TLocal, TAs>, 'list' | 'retry'>, SyncedCrudPropsBase<TRemote, TLocal> {
|
|
9
|
+
interface SyncedFirebaseProps<TRemote extends object, TLocal, TAs extends CrudAsOption = 'value'> extends Omit<SyncedCrudPropsMany<TRemote, TLocal, TAs>, 'list' | 'retry'>, Omit<SyncedCrudPropsBase<TRemote, TLocal>, 'onError'> {
|
|
10
10
|
refPath: (uid: string | undefined) => string;
|
|
11
11
|
query?: (ref: DatabaseReference) => DatabaseReference | Query;
|
|
12
12
|
fieldId?: string;
|
|
13
13
|
fieldTransforms?: FieldTransforms<TRemote>;
|
|
14
|
+
onError?: (error: Error, params: FirebaseErrorParams) => void;
|
|
14
15
|
realtime?: boolean;
|
|
15
16
|
requireAuth?: boolean;
|
|
16
17
|
readonly?: boolean;
|
|
@@ -22,6 +23,9 @@ interface SyncedFirebaseConfiguration {
|
|
|
22
23
|
enabled?: boolean;
|
|
23
24
|
}
|
|
24
25
|
declare function configureSyncedFirebase(config: SyncedFirebaseConfiguration): void;
|
|
26
|
+
interface FirebaseErrorParams extends Omit<SyncedErrorParams, 'source'> {
|
|
27
|
+
source: 'list' | 'get' | 'create' | 'update' | 'delete';
|
|
28
|
+
}
|
|
25
29
|
declare function syncedFirebase<TRemote extends object, TLocal = TRemote, TAs extends CrudAsOption = 'object'>(props: SyncedFirebaseProps<TRemote, TLocal, TAs>): SyncedCrudReturnType<TLocal, TAs>;
|
|
26
30
|
|
|
27
|
-
export { type SyncedFirebaseProps, configureSyncedFirebase, invertFieldMap, syncedFirebase, transformObjectFields };
|
|
31
|
+
export { type FirebaseErrorParams, type SyncedFirebaseProps, configureSyncedFirebase, invertFieldMap, syncedFirebase, transformObjectFields };
|
package/sync-plugins/firebase.js
CHANGED
|
@@ -185,7 +185,8 @@ function syncedFirebase(props) {
|
|
|
185
185
|
}
|
|
186
186
|
return ref;
|
|
187
187
|
};
|
|
188
|
-
const list = async (
|
|
188
|
+
const list = async (getParams) => {
|
|
189
|
+
const { lastSync, onError } = getParams;
|
|
189
190
|
const ref = computeRef(lastSync);
|
|
190
191
|
return new Promise((resolve) => {
|
|
191
192
|
fns.once(
|
|
@@ -204,7 +205,7 @@ function syncedFirebase(props) {
|
|
|
204
205
|
didList = true;
|
|
205
206
|
resolve(values);
|
|
206
207
|
},
|
|
207
|
-
onError
|
|
208
|
+
(error) => onError(error, { source: "list", type: "get", retry: getParams })
|
|
208
209
|
);
|
|
209
210
|
});
|
|
210
211
|
};
|
|
@@ -354,6 +355,7 @@ function syncedFirebase(props) {
|
|
|
354
355
|
}
|
|
355
356
|
return crud.syncedCrud({
|
|
356
357
|
...rest,
|
|
358
|
+
// Workaround for type errors
|
|
357
359
|
list,
|
|
358
360
|
subscribe,
|
|
359
361
|
create,
|
|
@@ -183,7 +183,8 @@ function syncedFirebase(props) {
|
|
|
183
183
|
}
|
|
184
184
|
return ref;
|
|
185
185
|
};
|
|
186
|
-
const list = async (
|
|
186
|
+
const list = async (getParams) => {
|
|
187
|
+
const { lastSync, onError } = getParams;
|
|
187
188
|
const ref = computeRef(lastSync);
|
|
188
189
|
return new Promise((resolve) => {
|
|
189
190
|
fns.once(
|
|
@@ -202,7 +203,7 @@ function syncedFirebase(props) {
|
|
|
202
203
|
didList = true;
|
|
203
204
|
resolve(values);
|
|
204
205
|
},
|
|
205
|
-
onError
|
|
206
|
+
(error) => onError(error, { source: "list", type: "get", retry: getParams })
|
|
206
207
|
);
|
|
207
208
|
});
|
|
208
209
|
};
|
|
@@ -352,6 +353,7 @@ function syncedFirebase(props) {
|
|
|
352
353
|
}
|
|
353
354
|
return syncedCrud({
|
|
354
355
|
...rest,
|
|
356
|
+
// Workaround for type errors
|
|
355
357
|
list,
|
|
356
358
|
subscribe,
|
|
357
359
|
create,
|