@legendapp/state 3.0.0-alpha.8 → 3.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.DS_Store +0 -0
- package/config/configureLegendState.d.mts +13 -0
- package/config/configureLegendState.d.ts +13 -0
- package/config/configureLegendState.js +45 -0
- package/config/configureLegendState.mjs +43 -0
- package/config/enable$GetSet.js +2 -1
- package/config/enable$GetSet.mjs +2 -1
- package/config/enableReactTracking.js +2 -1
- package/config/enableReactTracking.mjs +2 -1
- package/config/enableReactUse.js +2 -1
- package/config/enableReactUse.mjs +2 -1
- package/config/enable_PeekAssign.js +2 -1
- package/config/enable_PeekAssign.mjs +2 -1
- package/helpers/trackHistory.js +2 -2
- package/helpers/trackHistory.mjs +2 -2
- package/index.d.mts +104 -80
- package/index.d.ts +104 -80
- package/index.js +328 -318
- package/index.mjs +325 -316
- package/package.json +36 -1
- package/persist-plugins/async-storage.d.mts +6 -3
- package/persist-plugins/async-storage.d.ts +6 -3
- package/persist-plugins/async-storage.js +8 -4
- package/persist-plugins/async-storage.mjs +8 -5
- package/persist-plugins/indexeddb.d.mts +6 -4
- package/persist-plugins/indexeddb.d.ts +6 -4
- package/persist-plugins/indexeddb.js +35 -15
- package/persist-plugins/indexeddb.mjs +35 -16
- package/persist-plugins/mmkv.d.mts +5 -1
- package/persist-plugins/mmkv.d.ts +5 -1
- package/persist-plugins/mmkv.js +10 -5
- package/persist-plugins/mmkv.mjs +10 -6
- package/react-reactive/enableReactComponents.d.mts +9 -0
- package/react-reactive/enableReactComponents.d.ts +9 -0
- package/react-reactive/enableReactComponents.js +19 -0
- package/react-reactive/enableReactComponents.mjs +17 -0
- package/react-reactive/enableReactNativeComponents.d.mts +22 -0
- package/react-reactive/enableReactNativeComponents.d.ts +22 -0
- package/react-reactive/enableReactNativeComponents.js +53 -0
- package/react-reactive/enableReactNativeComponents.mjs +51 -0
- package/react-reactive/enableReactive.d.mts +5 -0
- package/react-reactive/enableReactive.d.ts +5 -0
- package/react-reactive/enableReactive.js +24 -0
- package/react-reactive/enableReactive.mjs +22 -0
- package/react-reactive/enableReactive.native.d.mts +5 -0
- package/react-reactive/enableReactive.native.d.ts +5 -0
- package/react-reactive/enableReactive.native.js +58 -0
- package/react-reactive/enableReactive.native.mjs +56 -0
- package/react-reactive/enableReactive.web.d.mts +5 -0
- package/react-reactive/enableReactive.web.d.ts +5 -0
- package/react-reactive/enableReactive.web.js +58 -0
- package/react-reactive/enableReactive.web.mjs +56 -0
- package/react.d.mts +39 -34
- package/react.d.ts +39 -34
- package/react.js +39 -17
- package/react.mjs +39 -17
- package/sync-plugins/crud.d.mts +21 -24
- package/sync-plugins/crud.d.ts +21 -24
- package/sync-plugins/crud.js +241 -140
- package/sync-plugins/crud.mjs +243 -142
- package/sync-plugins/fetch.js +12 -8
- package/sync-plugins/fetch.mjs +13 -9
- package/sync-plugins/firebase.d.mts +27 -0
- package/sync-plugins/firebase.d.ts +27 -0
- package/sync-plugins/firebase.js +373 -0
- package/sync-plugins/firebase.mjs +368 -0
- package/sync-plugins/keel.d.mts +43 -26
- package/sync-plugins/keel.d.ts +43 -26
- package/sync-plugins/keel.js +145 -100
- package/sync-plugins/keel.mjs +147 -100
- package/sync-plugins/supabase.d.mts +19 -9
- package/sync-plugins/supabase.d.ts +19 -9
- package/sync-plugins/supabase.js +52 -22
- package/sync-plugins/supabase.mjs +53 -23
- package/sync-plugins/tanstack-query.d.mts +2 -2
- package/sync-plugins/tanstack-query.d.ts +2 -2
- package/sync-plugins/tanstack-query.js +22 -5
- package/sync-plugins/tanstack-query.mjs +22 -5
- package/sync-plugins/tanstack-react-query.d.mts +1 -1
- package/sync-plugins/tanstack-react-query.d.ts +1 -1
- package/sync-plugins/tanstack-react-query.js +8 -1
- package/sync-plugins/tanstack-react-query.mjs +8 -1
- package/sync.d.mts +74 -200
- package/sync.d.ts +74 -200
- package/sync.js +492 -293
- package/sync.mjs +498 -299
package/sync-plugins/crud.mjs
CHANGED
|
@@ -1,35 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { synced, deepEqual, diffObjects } from '@legendapp/state/sync';
|
|
1
|
+
import { isPromise, applyChanges, isNullOrUndefined, setAtPath, symbolDelete, isArray, internal, getNodeValue } from '@legendapp/state';
|
|
2
|
+
import { synced, deepEqual, internal as internal$1, diffObjects } from '@legendapp/state/sync';
|
|
3
3
|
|
|
4
4
|
// src/sync-plugins/crud.ts
|
|
5
5
|
var { clone } = internal;
|
|
6
|
+
var { waitForSet } = internal$1;
|
|
6
7
|
function transformOut(data, transform) {
|
|
7
8
|
return transform ? transform(clone(data)) : data;
|
|
8
9
|
}
|
|
9
|
-
function ensureId(obj, generateId) {
|
|
10
|
-
if (!obj
|
|
11
|
-
obj
|
|
10
|
+
function ensureId(obj, fieldId, generateId) {
|
|
11
|
+
if (!obj[fieldId]) {
|
|
12
|
+
obj[fieldId] = generateId();
|
|
12
13
|
}
|
|
13
|
-
return obj
|
|
14
|
+
return obj[fieldId];
|
|
14
15
|
}
|
|
15
|
-
function
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
});
|
|
23
|
-
} else if (mode === "createdUpdatedAt") {
|
|
24
|
-
Object.keys(saved).forEach((key) => {
|
|
25
|
-
const k = key;
|
|
26
|
-
const keyLower = key.toLowerCase();
|
|
27
|
-
if ((key === props.fieldCreatedAt || key === props.fieldUpdatedAt || keyLower.endsWith("createdat") || keyLower.endsWith("updatedat") || keyLower.endsWith("created_at") || keyLower.endsWith("updated_at")) && saved[k] instanceof Date) {
|
|
28
|
-
savedOut[k] = saved[k];
|
|
29
|
-
}
|
|
30
|
-
});
|
|
16
|
+
function computeLastSync(data, fieldUpdatedAt, fieldCreatedAt) {
|
|
17
|
+
let newLastSync = 0;
|
|
18
|
+
for (let i = 0; i < data.length; i++) {
|
|
19
|
+
const updated = (fieldUpdatedAt ? data[i][fieldUpdatedAt] : 0) || (fieldCreatedAt ? data[i][fieldCreatedAt] : 0);
|
|
20
|
+
if (updated) {
|
|
21
|
+
newLastSync = Math.max(newLastSync, +new Date(updated));
|
|
22
|
+
}
|
|
31
23
|
}
|
|
32
|
-
return
|
|
24
|
+
return newLastSync;
|
|
33
25
|
}
|
|
34
26
|
function syncedCrud(props) {
|
|
35
27
|
const {
|
|
@@ -39,168 +31,233 @@ function syncedCrud(props) {
|
|
|
39
31
|
update: updateFn,
|
|
40
32
|
delete: deleteFn,
|
|
41
33
|
transform,
|
|
34
|
+
fieldId: fieldIdProp,
|
|
42
35
|
fieldCreatedAt,
|
|
43
36
|
fieldUpdatedAt,
|
|
44
37
|
fieldDeleted,
|
|
38
|
+
fieldDeletedList,
|
|
45
39
|
updatePartial,
|
|
40
|
+
subscribe: subscribeProp,
|
|
46
41
|
onSaved,
|
|
47
|
-
onSavedUpdate,
|
|
48
42
|
mode: modeParam,
|
|
49
43
|
changesSince,
|
|
50
44
|
generateId,
|
|
45
|
+
waitForSet: waitForSetParam,
|
|
51
46
|
...rest
|
|
52
47
|
} = props;
|
|
48
|
+
const fieldId = fieldIdProp || "id";
|
|
49
|
+
const pendingCreates = /* @__PURE__ */ new Set();
|
|
53
50
|
let asType = props.as;
|
|
54
51
|
if (!asType) {
|
|
55
52
|
asType = getFn ? "value" : "object";
|
|
56
53
|
}
|
|
57
54
|
const asMap = asType === "Map";
|
|
58
55
|
const asArray = asType === "array";
|
|
59
|
-
const
|
|
56
|
+
const resultsToOutType = (results) => {
|
|
57
|
+
if (asType === "value") {
|
|
58
|
+
return results[0];
|
|
59
|
+
}
|
|
60
|
+
const out = asType === "array" ? [] : asMap ? /* @__PURE__ */ new Map() : {};
|
|
61
|
+
for (let i = 0; i < results.length; i++) {
|
|
62
|
+
let result = results[i];
|
|
63
|
+
const value = result;
|
|
64
|
+
if (value) {
|
|
65
|
+
result = fieldDeleted && result[fieldDeleted] || fieldDeletedList && result[fieldDeletedList] || result[symbolDelete] ? internal.symbolDelete : result;
|
|
66
|
+
if (asArray) {
|
|
67
|
+
out.push(result);
|
|
68
|
+
} else if (asMap) {
|
|
69
|
+
out.set(value[fieldId], result);
|
|
70
|
+
} else {
|
|
71
|
+
out[value[fieldId]] = result;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return out;
|
|
76
|
+
};
|
|
77
|
+
const transformRows = (data) => {
|
|
78
|
+
return Promise.all(
|
|
79
|
+
data.map(
|
|
80
|
+
(value) => (
|
|
81
|
+
// Skip transforming any children with symbolDelete or fieldDeleted because they'll get deleted by resultsToOutType
|
|
82
|
+
value[symbolDelete] || fieldDeleted && value[fieldDeleted] || fieldDeletedList && value[fieldDeletedList] ? value : transform.load(value, "get")
|
|
83
|
+
)
|
|
84
|
+
)
|
|
85
|
+
);
|
|
86
|
+
};
|
|
87
|
+
const get = getFn || listFn ? (getParams) => {
|
|
60
88
|
const { updateLastSync, lastSync, value } = getParams;
|
|
61
89
|
if (listFn) {
|
|
62
90
|
const isLastSyncMode = changesSince === "last-sync";
|
|
63
91
|
if (isLastSyncMode && lastSync) {
|
|
64
92
|
getParams.mode = modeParam || (asType === "array" ? "append" : asType === "value" ? "set" : "assign");
|
|
65
93
|
}
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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);
|
|
72
101
|
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
if (asType === "value") {
|
|
82
|
-
return transformed.length > 0 ? transformed[0] : isLastSyncMode && lastSync && value || null;
|
|
83
|
-
} else {
|
|
84
|
-
const results = transformed.map(
|
|
85
|
-
(result) => result[fieldDeleted] || result.__deleted ? internal.symbolDelete : result
|
|
86
|
-
);
|
|
87
|
-
const out = asType === "array" ? [] : asMap ? /* @__PURE__ */ new Map() : {};
|
|
88
|
-
for (let i = 0; i < results.length; i++) {
|
|
89
|
-
let result = results[i];
|
|
90
|
-
result = result[fieldDeleted] || result.__deleted ? internal.symbolDelete : result;
|
|
91
|
-
if (asArray) {
|
|
92
|
-
out.push(result);
|
|
93
|
-
} else if (asMap) {
|
|
94
|
-
out.set(result.id, result);
|
|
95
|
-
} else {
|
|
96
|
-
out[result.id] = result;
|
|
102
|
+
};
|
|
103
|
+
const processResults = (data) => {
|
|
104
|
+
data || (data = []);
|
|
105
|
+
if (fieldUpdatedAt) {
|
|
106
|
+
const newLastSync = computeLastSync(data, fieldUpdatedAt, fieldCreatedAt);
|
|
107
|
+
if (newLastSync && newLastSync !== lastSync) {
|
|
108
|
+
updateLastSync(newLastSync);
|
|
97
109
|
}
|
|
98
110
|
}
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
} else if (getFn) {
|
|
102
|
-
const data = await getFn(getParams);
|
|
103
|
-
let transformed = data;
|
|
104
|
-
if (data) {
|
|
105
|
-
const newLastSync = data[fieldUpdatedAt] || data[fieldCreatedAt];
|
|
106
|
-
if (newLastSync && newLastSync !== lastSync) {
|
|
107
|
-
updateLastSync(newLastSync);
|
|
108
|
-
}
|
|
111
|
+
let transformed = data;
|
|
109
112
|
if (transform == null ? void 0 : transform.load) {
|
|
110
|
-
transformed =
|
|
113
|
+
transformed = transformRows(data);
|
|
111
114
|
}
|
|
112
|
-
|
|
113
|
-
|
|
115
|
+
return isPromise(transformed) ? transformed.then(toOut) : toOut(transformed);
|
|
116
|
+
};
|
|
117
|
+
return isPromise(listPromise) ? listPromise.then(processResults) : processResults(listPromise);
|
|
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);
|
|
126
|
+
}
|
|
127
|
+
if (transform == null ? void 0 : transform.load) {
|
|
128
|
+
transformed = transform.load(data, "get");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return transformed;
|
|
132
|
+
};
|
|
133
|
+
return isPromise(dataPromise) ? dataPromise.then(processData) : processData(dataPromise);
|
|
114
134
|
}
|
|
115
135
|
} : void 0;
|
|
116
136
|
const set = createFn || updateFn || deleteFn ? async (params) => {
|
|
117
|
-
const { value, changes, update, retryAsCreate,
|
|
137
|
+
const { value, changes, update, retryAsCreate, node } = params;
|
|
118
138
|
const creates = /* @__PURE__ */ new Map();
|
|
119
139
|
const updates = /* @__PURE__ */ new Map();
|
|
120
140
|
const deletes = /* @__PURE__ */ new Set();
|
|
121
|
-
|
|
141
|
+
const getUpdateValue = (itemValue, prev) => {
|
|
142
|
+
return updatePartial ? Object.assign(
|
|
143
|
+
diffObjects(
|
|
144
|
+
prev,
|
|
145
|
+
itemValue,
|
|
146
|
+
/*deep*/
|
|
147
|
+
true
|
|
148
|
+
),
|
|
149
|
+
itemValue[fieldId] ? { [fieldId]: itemValue[fieldId] } : {}
|
|
150
|
+
) : itemValue;
|
|
151
|
+
};
|
|
152
|
+
changes.forEach((change) => {
|
|
153
|
+
const { path, prevAtPath, valueAtPath, pathTypes } = change;
|
|
122
154
|
if (asType === "value") {
|
|
123
155
|
if (value) {
|
|
124
|
-
let id = value == null ? void 0 : value
|
|
125
|
-
|
|
156
|
+
let id = value == null ? void 0 : value[fieldId];
|
|
157
|
+
let isCreate = fieldCreatedAt ? !value[fieldCreatedAt] : !prevAtPath;
|
|
126
158
|
if (!id && generateId) {
|
|
127
|
-
id = ensureId(value, generateId);
|
|
159
|
+
id = ensureId(value, fieldId, generateId);
|
|
128
160
|
}
|
|
129
161
|
if (id) {
|
|
162
|
+
if (pendingCreates.has(id)) {
|
|
163
|
+
isCreate = false;
|
|
164
|
+
}
|
|
130
165
|
if (isCreate || retryAsCreate) {
|
|
131
|
-
|
|
166
|
+
if (createFn) {
|
|
167
|
+
creates.set(id, value);
|
|
168
|
+
} else {
|
|
169
|
+
console.warn("[legend-state] missing create function");
|
|
170
|
+
}
|
|
132
171
|
} else if (path.length === 0) {
|
|
133
172
|
if (valueAtPath) {
|
|
134
|
-
updates.set(id, valueAtPath);
|
|
173
|
+
updates.set(id, getUpdateValue(valueAtPath, prevAtPath));
|
|
135
174
|
} else if (prevAtPath) {
|
|
136
|
-
deletes.add(prevAtPath
|
|
175
|
+
deletes.add(prevAtPath);
|
|
137
176
|
}
|
|
138
|
-
} else {
|
|
139
|
-
|
|
177
|
+
} else if (!updates.has(id)) {
|
|
178
|
+
const previous = applyChanges(
|
|
179
|
+
clone(value),
|
|
180
|
+
changes,
|
|
181
|
+
/*applyPrevious*/
|
|
182
|
+
true
|
|
183
|
+
);
|
|
184
|
+
updates.set(id, getUpdateValue(value, previous));
|
|
140
185
|
}
|
|
141
186
|
} else {
|
|
142
187
|
console.error("[legend-state]: added synced item without an id");
|
|
143
188
|
}
|
|
144
189
|
} else if (path.length === 0) {
|
|
145
|
-
|
|
146
|
-
if (id) {
|
|
147
|
-
deletes.add(id);
|
|
148
|
-
}
|
|
190
|
+
deletes.add(prevAtPath);
|
|
149
191
|
}
|
|
150
192
|
} else {
|
|
151
|
-
let itemsChanged =
|
|
193
|
+
let itemsChanged = [];
|
|
152
194
|
if (path.length === 0) {
|
|
153
|
-
|
|
195
|
+
const changed = asMap ? Array.from(valueAtPath.entries()) : Object.entries(valueAtPath);
|
|
196
|
+
for (let i = 0; i < changed.length; i++) {
|
|
197
|
+
const [key, value2] = changed[i];
|
|
154
198
|
const prev = asMap ? prevAtPath.get(key) : prevAtPath[key];
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
199
|
+
if (isNullOrUndefined(value2) && !isNullOrUndefined(prev)) {
|
|
200
|
+
deletes.add(prev);
|
|
201
|
+
return false;
|
|
202
|
+
} else {
|
|
203
|
+
const isDiff = !prevAtPath || !deepEqual(value2, prev);
|
|
204
|
+
if (isDiff) {
|
|
205
|
+
itemsChanged.push([getUpdateValue(value2, prev), prev]);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
158
209
|
} else {
|
|
159
210
|
const itemKey = path[0];
|
|
160
211
|
const itemValue = asMap ? value.get(itemKey) : value[itemKey];
|
|
161
212
|
if (!itemValue) {
|
|
162
213
|
if (path.length === 1 && prevAtPath) {
|
|
163
|
-
deletes.add(
|
|
214
|
+
deletes.add(prevAtPath);
|
|
164
215
|
}
|
|
165
216
|
} else {
|
|
166
|
-
|
|
217
|
+
const previous = setAtPath(
|
|
218
|
+
clone(itemValue),
|
|
219
|
+
path.slice(1),
|
|
220
|
+
pathTypes.slice(1),
|
|
221
|
+
prevAtPath
|
|
222
|
+
);
|
|
223
|
+
itemsChanged = [[getUpdateValue(itemValue, previous), previous]];
|
|
167
224
|
}
|
|
168
225
|
}
|
|
169
|
-
itemsChanged == null ? void 0 : itemsChanged.forEach(([
|
|
170
|
-
|
|
171
|
-
|
|
226
|
+
itemsChanged == null ? void 0 : itemsChanged.forEach(([item, prev]) => {
|
|
227
|
+
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
|
+
if (isCreate) {
|
|
229
|
+
if (generateId) {
|
|
230
|
+
ensureId(item, fieldId, generateId);
|
|
231
|
+
}
|
|
232
|
+
if (!item[fieldId]) {
|
|
233
|
+
console.error("[legend-state]: added item without an id");
|
|
234
|
+
}
|
|
235
|
+
if (createFn) {
|
|
236
|
+
pendingCreates.add(item[fieldId]);
|
|
237
|
+
creates.set(item[fieldId], item);
|
|
238
|
+
} else {
|
|
239
|
+
console.warn("[legend-state] missing create function");
|
|
240
|
+
}
|
|
172
241
|
} else {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
if (!item.id) {
|
|
180
|
-
console.error("[legend-state]: added item without an id");
|
|
181
|
-
}
|
|
182
|
-
if (createFn) {
|
|
183
|
-
creates.set(item.id, item);
|
|
184
|
-
} else {
|
|
185
|
-
console.log("[legend-state] missing create function");
|
|
186
|
-
}
|
|
242
|
+
if (updateFn) {
|
|
243
|
+
updates.set(
|
|
244
|
+
item[fieldId],
|
|
245
|
+
updates.has(item[fieldId]) ? Object.assign(updates.get(item[fieldId]), item) : item
|
|
246
|
+
);
|
|
187
247
|
} else {
|
|
188
|
-
|
|
189
|
-
updates.set(item.id, item);
|
|
190
|
-
} else {
|
|
191
|
-
console.log("[legend-state] missing update function");
|
|
192
|
-
}
|
|
248
|
+
console.warn("[legend-state] missing update function");
|
|
193
249
|
}
|
|
194
250
|
}
|
|
195
251
|
});
|
|
196
252
|
}
|
|
197
253
|
});
|
|
198
254
|
const saveResult = async (itemKey, input, data, isCreate) => {
|
|
199
|
-
|
|
200
|
-
|
|
255
|
+
var _a;
|
|
256
|
+
if (data) {
|
|
257
|
+
const saved = (transform == null ? void 0 : transform.load) ? await transform.load(data, "set") : data;
|
|
201
258
|
const isChild = itemKey !== "undefined" && asType !== "value";
|
|
202
259
|
const currentPeeked = getNodeValue(node);
|
|
203
|
-
const currentValue = isChild ?
|
|
260
|
+
const currentValue = isChild ? (_a = asType === "array" && isArray(currentPeeked) ? currentPeeked.find((v) => v[fieldId] === itemKey) : void 0) != null ? _a : currentPeeked[itemKey] : currentPeeked;
|
|
204
261
|
const dataOnSaved = {
|
|
205
262
|
saved,
|
|
206
263
|
input,
|
|
@@ -208,17 +265,26 @@ function syncedCrud(props) {
|
|
|
208
265
|
isCreate,
|
|
209
266
|
props
|
|
210
267
|
};
|
|
211
|
-
let savedOut =
|
|
212
|
-
if (
|
|
213
|
-
savedOut =
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
268
|
+
let savedOut = saved;
|
|
269
|
+
if (savedOut && !isNullOrUndefined(currentValue)) {
|
|
270
|
+
savedOut = clone(savedOut);
|
|
271
|
+
Object.keys(savedOut).forEach((key) => {
|
|
272
|
+
const i = input[key];
|
|
273
|
+
const c = currentValue[key];
|
|
274
|
+
if (
|
|
275
|
+
// value is already the new value, can ignore
|
|
276
|
+
savedOut[key] === c || // user has changed local value
|
|
277
|
+
key !== "id" && i !== c
|
|
278
|
+
) {
|
|
279
|
+
delete savedOut[key];
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
if (onSaved) {
|
|
283
|
+
const ret = onSaved(dataOnSaved);
|
|
284
|
+
if (ret) {
|
|
285
|
+
savedOut = ret;
|
|
286
|
+
}
|
|
219
287
|
}
|
|
220
|
-
}
|
|
221
|
-
if (savedOut) {
|
|
222
288
|
const createdAt = fieldCreatedAt ? savedOut[fieldCreatedAt] : void 0;
|
|
223
289
|
const updatedAt = fieldUpdatedAt ? savedOut[fieldUpdatedAt] : void 0;
|
|
224
290
|
const value2 = itemKey !== "undefined" && asType !== "value" ? { [itemKey]: savedOut } : savedOut;
|
|
@@ -231,38 +297,73 @@ function syncedCrud(props) {
|
|
|
231
297
|
}
|
|
232
298
|
};
|
|
233
299
|
return Promise.all([
|
|
234
|
-
...Array.from(creates).map(([itemKey, itemValue]) => {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
);
|
|
300
|
+
...Array.from(creates).map(async ([itemKey, itemValue]) => {
|
|
301
|
+
if (waitForSetParam) {
|
|
302
|
+
await waitForSet(waitForSetParam, changes, itemValue, { type: "create" });
|
|
303
|
+
}
|
|
304
|
+
const createObj = await transformOut(itemValue, transform == null ? void 0 : transform.save);
|
|
305
|
+
return createFn(createObj, params).then((result) => {
|
|
306
|
+
return saveResult(itemKey, createObj, result, true);
|
|
307
|
+
}).finally(() => {
|
|
308
|
+
pendingCreates.delete(itemKey);
|
|
309
|
+
});
|
|
239
310
|
}),
|
|
240
|
-
...Array.from(updates).map(([itemKey, itemValue]) => {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
const changed = transformOut(toSave, transform == null ? void 0 : transform.save);
|
|
311
|
+
...Array.from(updates).map(async ([itemKey, itemValue]) => {
|
|
312
|
+
if (waitForSetParam) {
|
|
313
|
+
await waitForSet(waitForSetParam, changes, itemValue, { type: "update" });
|
|
314
|
+
}
|
|
315
|
+
const toSave = itemValue;
|
|
316
|
+
const changed = await transformOut(toSave, transform == null ? void 0 : transform.save);
|
|
246
317
|
if (Object.keys(changed).length > 0) {
|
|
247
318
|
return updateFn(changed, params).then(
|
|
248
319
|
(result) => result && saveResult(itemKey, changed, result, false)
|
|
249
320
|
);
|
|
250
321
|
}
|
|
251
322
|
}),
|
|
252
|
-
...Array.from(deletes).map((
|
|
253
|
-
if (
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
323
|
+
...Array.from(deletes).map(async (valuePrevious) => {
|
|
324
|
+
if (valuePrevious !== symbolDelete) {
|
|
325
|
+
if (waitForSetParam) {
|
|
326
|
+
await waitForSet(waitForSetParam, changes, valuePrevious, { type: "delete" });
|
|
327
|
+
}
|
|
328
|
+
if (deleteFn) {
|
|
329
|
+
deleteFn(valuePrevious, params);
|
|
330
|
+
} else if (fieldDeleted && updateFn) {
|
|
331
|
+
const valueId = valuePrevious[fieldId];
|
|
332
|
+
if (valueId) {
|
|
333
|
+
updateFn({ ...{ [fieldId]: valueId }, [fieldDeleted]: true }, params);
|
|
334
|
+
} else {
|
|
335
|
+
console.error("[legend-state]: deleting item without an id");
|
|
336
|
+
}
|
|
337
|
+
} else {
|
|
338
|
+
console.warn("[legend-state] missing delete function");
|
|
339
|
+
}
|
|
259
340
|
}
|
|
260
341
|
})
|
|
261
342
|
]);
|
|
262
343
|
} : void 0;
|
|
344
|
+
const subscribe = subscribeProp ? (params) => subscribeProp({
|
|
345
|
+
...params,
|
|
346
|
+
update: async (paramsUpdate) => {
|
|
347
|
+
const paramsForUpdate = paramsUpdate;
|
|
348
|
+
const rows = paramsUpdate.value;
|
|
349
|
+
if (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") {
|
|
350
|
+
if (!isArray(rows)) {
|
|
351
|
+
console.error("[legend-state] subscribe:update expects an array of changed items");
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
const newLastSync = computeLastSync(rows, fieldUpdatedAt, fieldCreatedAt);
|
|
355
|
+
if (newLastSync) {
|
|
356
|
+
paramsForUpdate.lastSync = newLastSync;
|
|
357
|
+
}
|
|
358
|
+
const rowsTransformed = (transform == null ? void 0 : transform.load) ? await transformRows(rows) : rows;
|
|
359
|
+
paramsForUpdate.value = resultsToOutType(rowsTransformed);
|
|
360
|
+
params.update(paramsForUpdate);
|
|
361
|
+
}
|
|
362
|
+
}) : void 0;
|
|
263
363
|
return synced({
|
|
264
364
|
set,
|
|
265
365
|
get,
|
|
366
|
+
subscribe,
|
|
266
367
|
mode: modeParam,
|
|
267
368
|
...rest
|
|
268
369
|
});
|
package/sync-plugins/fetch.js
CHANGED
|
@@ -18,15 +18,19 @@ function syncedFetch(props) {
|
|
|
18
18
|
} = props;
|
|
19
19
|
const get = async () => {
|
|
20
20
|
const url = state.computeSelector(getParam);
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
if (url && state.isString(url)) {
|
|
22
|
+
const response = await fetch(url, getInit);
|
|
23
|
+
if (!response.ok) {
|
|
24
|
+
throw new Error(response.statusText);
|
|
25
|
+
}
|
|
26
|
+
let value = await response[valueType || "json"]();
|
|
27
|
+
if (transform == null ? void 0 : transform.load) {
|
|
28
|
+
value = transform == null ? void 0 : transform.load(value, "get");
|
|
29
|
+
}
|
|
30
|
+
return value;
|
|
31
|
+
} else {
|
|
32
|
+
return null;
|
|
28
33
|
}
|
|
29
|
-
return value;
|
|
30
34
|
};
|
|
31
35
|
let set = void 0;
|
|
32
36
|
if (setParam) {
|
package/sync-plugins/fetch.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { computeSelector, getNodeValue } from '@legendapp/state';
|
|
1
|
+
import { computeSelector, isString, getNodeValue } from '@legendapp/state';
|
|
2
2
|
import { synced } from '@legendapp/state/sync';
|
|
3
3
|
|
|
4
4
|
// src/sync-plugins/fetch.ts
|
|
@@ -16,15 +16,19 @@ function syncedFetch(props) {
|
|
|
16
16
|
} = props;
|
|
17
17
|
const get = async () => {
|
|
18
18
|
const url = computeSelector(getParam);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
if (url && isString(url)) {
|
|
20
|
+
const response = await fetch(url, getInit);
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
throw new Error(response.statusText);
|
|
23
|
+
}
|
|
24
|
+
let value = await response[valueType || "json"]();
|
|
25
|
+
if (transform == null ? void 0 : transform.load) {
|
|
26
|
+
value = transform == null ? void 0 : transform.load(value, "get");
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
} else {
|
|
30
|
+
return null;
|
|
26
31
|
}
|
|
27
|
-
return value;
|
|
28
32
|
};
|
|
29
33
|
let set = void 0;
|
|
30
34
|
if (setParam) {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { FieldTransforms } from '@legendapp/state/sync';
|
|
2
|
+
export { FieldTransforms } from '@legendapp/state/sync';
|
|
3
|
+
import { CrudAsOption, SyncedCrudPropsMany, SyncedCrudPropsBase, SyncedCrudReturnType } from '@legendapp/state/sync-plugins/crud';
|
|
4
|
+
import { DatabaseReference, Query } from 'firebase/database';
|
|
5
|
+
|
|
6
|
+
declare function transformObjectFields(dataIn: Record<string, any>, map: Record<string, any>): any;
|
|
7
|
+
declare function invertFieldMap(obj: Record<string, any>): any;
|
|
8
|
+
|
|
9
|
+
interface SyncedFirebaseProps<TRemote extends object, TLocal, TAs extends CrudAsOption = 'value'> extends Omit<SyncedCrudPropsMany<TRemote, TLocal, TAs>, 'list' | 'retry'>, SyncedCrudPropsBase<TRemote, TLocal> {
|
|
10
|
+
refPath: (uid: string | undefined) => string;
|
|
11
|
+
query?: (ref: DatabaseReference) => DatabaseReference | Query;
|
|
12
|
+
fieldId?: string;
|
|
13
|
+
fieldTransforms?: FieldTransforms<TRemote>;
|
|
14
|
+
realtime?: boolean;
|
|
15
|
+
requireAuth?: boolean;
|
|
16
|
+
readonly?: boolean;
|
|
17
|
+
}
|
|
18
|
+
interface SyncedFirebaseConfiguration {
|
|
19
|
+
realtime?: boolean;
|
|
20
|
+
requireAuth?: boolean;
|
|
21
|
+
readonly?: boolean;
|
|
22
|
+
enabled?: boolean;
|
|
23
|
+
}
|
|
24
|
+
declare function configureSyncedFirebase(config: SyncedFirebaseConfiguration): void;
|
|
25
|
+
declare function syncedFirebase<TRemote extends object, TLocal = TRemote, TAs extends CrudAsOption = 'object'>(props: SyncedFirebaseProps<TRemote, TLocal, TAs>): SyncedCrudReturnType<TLocal, TAs>;
|
|
26
|
+
|
|
27
|
+
export { type SyncedFirebaseProps, configureSyncedFirebase, invertFieldMap, syncedFirebase, transformObjectFields };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { FieldTransforms } from '@legendapp/state/sync';
|
|
2
|
+
export { FieldTransforms } from '@legendapp/state/sync';
|
|
3
|
+
import { CrudAsOption, SyncedCrudPropsMany, SyncedCrudPropsBase, SyncedCrudReturnType } from '@legendapp/state/sync-plugins/crud';
|
|
4
|
+
import { DatabaseReference, Query } from 'firebase/database';
|
|
5
|
+
|
|
6
|
+
declare function transformObjectFields(dataIn: Record<string, any>, map: Record<string, any>): any;
|
|
7
|
+
declare function invertFieldMap(obj: Record<string, any>): any;
|
|
8
|
+
|
|
9
|
+
interface SyncedFirebaseProps<TRemote extends object, TLocal, TAs extends CrudAsOption = 'value'> extends Omit<SyncedCrudPropsMany<TRemote, TLocal, TAs>, 'list' | 'retry'>, SyncedCrudPropsBase<TRemote, TLocal> {
|
|
10
|
+
refPath: (uid: string | undefined) => string;
|
|
11
|
+
query?: (ref: DatabaseReference) => DatabaseReference | Query;
|
|
12
|
+
fieldId?: string;
|
|
13
|
+
fieldTransforms?: FieldTransforms<TRemote>;
|
|
14
|
+
realtime?: boolean;
|
|
15
|
+
requireAuth?: boolean;
|
|
16
|
+
readonly?: boolean;
|
|
17
|
+
}
|
|
18
|
+
interface SyncedFirebaseConfiguration {
|
|
19
|
+
realtime?: boolean;
|
|
20
|
+
requireAuth?: boolean;
|
|
21
|
+
readonly?: boolean;
|
|
22
|
+
enabled?: boolean;
|
|
23
|
+
}
|
|
24
|
+
declare function configureSyncedFirebase(config: SyncedFirebaseConfiguration): void;
|
|
25
|
+
declare function syncedFirebase<TRemote extends object, TLocal = TRemote, TAs extends CrudAsOption = 'object'>(props: SyncedFirebaseProps<TRemote, TLocal, TAs>): SyncedCrudReturnType<TLocal, TAs>;
|
|
26
|
+
|
|
27
|
+
export { type SyncedFirebaseProps, configureSyncedFirebase, invertFieldMap, syncedFirebase, transformObjectFields };
|