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