@legendapp/state 3.0.0-beta.21 → 3.0.0-beta.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.mts CHANGED
@@ -113,6 +113,7 @@ declare function setNodeValue(node: NodeInfo, newValue: any): {
113
113
  declare function getNodeValue(node: NodeInfo): any;
114
114
  declare function ensureNodeValue(node: NodeInfo): any;
115
115
  declare function findIDKey(obj: unknown | undefined, node: NodeInfo): string | ((value: any) => string) | undefined;
116
+ declare function getKeys(obj: Record<any, any> | Array<any> | undefined, isArr: boolean, isMap: boolean, isSet: boolean): string[];
116
117
 
117
118
  type TrackingType = undefined | true | symbol;
118
119
  interface GetOptions {
@@ -397,6 +398,7 @@ declare const internal: {
397
398
  ensureNodeValue: typeof ensureNodeValue;
398
399
  findIDKey: typeof findIDKey;
399
400
  get: typeof get;
401
+ getKeys: typeof getKeys;
400
402
  getNode: typeof getNode;
401
403
  getNodeValue: typeof getNodeValue;
402
404
  getPathType: typeof getPathType;
package/index.d.ts CHANGED
@@ -113,6 +113,7 @@ declare function setNodeValue(node: NodeInfo, newValue: any): {
113
113
  declare function getNodeValue(node: NodeInfo): any;
114
114
  declare function ensureNodeValue(node: NodeInfo): any;
115
115
  declare function findIDKey(obj: unknown | undefined, node: NodeInfo): string | ((value: any) => string) | undefined;
116
+ declare function getKeys(obj: Record<any, any> | Array<any> | undefined, isArr: boolean, isMap: boolean, isSet: boolean): string[];
116
117
 
117
118
  type TrackingType = undefined | true | symbol;
118
119
  interface GetOptions {
@@ -397,6 +398,7 @@ declare const internal: {
397
398
  ensureNodeValue: typeof ensureNodeValue;
398
399
  findIDKey: typeof findIDKey;
399
400
  get: typeof get;
401
+ getKeys: typeof getKeys;
400
402
  getNode: typeof getNode;
401
403
  getNodeValue: typeof getNodeValue;
402
404
  getPathType: typeof getPathType;
package/index.js CHANGED
@@ -257,6 +257,9 @@ function extractFunction(node, key, fnOrComputed) {
257
257
  function equals(a, b) {
258
258
  return a === b || isDate(a) && isDate(b) && +a === +b;
259
259
  }
260
+ function getKeys(obj, isArr, isMap2, isSet2) {
261
+ return isArr ? void 0 : obj ? isSet2 ? Array.from(obj) : isMap2 ? Array.from(obj.keys()) : Object.keys(obj) : [];
262
+ }
260
263
 
261
264
  // src/ObservableHint.ts
262
265
  function addSymbol(value, symbol) {
@@ -593,6 +596,7 @@ function computeChangesAtNode(changesInBatch, node, isFromPersist, isFromSync, v
593
596
  if (!isArraySubset(changes[0].path, change.path)) {
594
597
  changes.push(change);
595
598
  changeInBatch.level = Math.min(changeInBatch.level, level);
599
+ changeInBatch.whenOptimizedOnlyIf || (changeInBatch.whenOptimizedOnlyIf = whenOptimizedOnlyIf);
596
600
  }
597
601
  } else {
598
602
  changesInBatch.set(node, {
@@ -1180,9 +1184,6 @@ function collectionSetter(node, target, prop, ...args) {
1180
1184
  return ret;
1181
1185
  }
1182
1186
  }
1183
- function getKeys(obj, isArr, isMap2, isSet2) {
1184
- return isArr ? void 0 : obj ? isSet2 ? Array.from(obj) : isMap2 ? Array.from(obj.keys()) : Object.keys(obj) : [];
1185
- }
1186
1187
  function updateNodes(parent, obj, prevValue) {
1187
1188
  var _a, _b, _c;
1188
1189
  if ((process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") && typeof __devUpdateNodes !== "undefined" && isObject(obj)) {
@@ -2340,6 +2341,7 @@ var internal = {
2340
2341
  ensureNodeValue,
2341
2342
  findIDKey,
2342
2343
  get,
2344
+ getKeys,
2343
2345
  getNode,
2344
2346
  getNodeValue,
2345
2347
  getPathType,
package/index.mjs CHANGED
@@ -255,6 +255,9 @@ function extractFunction(node, key, fnOrComputed) {
255
255
  function equals(a, b) {
256
256
  return a === b || isDate(a) && isDate(b) && +a === +b;
257
257
  }
258
+ function getKeys(obj, isArr, isMap2, isSet2) {
259
+ return isArr ? void 0 : obj ? isSet2 ? Array.from(obj) : isMap2 ? Array.from(obj.keys()) : Object.keys(obj) : [];
260
+ }
258
261
 
259
262
  // src/ObservableHint.ts
260
263
  function addSymbol(value, symbol) {
@@ -591,6 +594,7 @@ function computeChangesAtNode(changesInBatch, node, isFromPersist, isFromSync, v
591
594
  if (!isArraySubset(changes[0].path, change.path)) {
592
595
  changes.push(change);
593
596
  changeInBatch.level = Math.min(changeInBatch.level, level);
597
+ changeInBatch.whenOptimizedOnlyIf || (changeInBatch.whenOptimizedOnlyIf = whenOptimizedOnlyIf);
594
598
  }
595
599
  } else {
596
600
  changesInBatch.set(node, {
@@ -1178,9 +1182,6 @@ function collectionSetter(node, target, prop, ...args) {
1178
1182
  return ret;
1179
1183
  }
1180
1184
  }
1181
- function getKeys(obj, isArr, isMap2, isSet2) {
1182
- return isArr ? void 0 : obj ? isSet2 ? Array.from(obj) : isMap2 ? Array.from(obj.keys()) : Object.keys(obj) : [];
1183
- }
1184
1185
  function updateNodes(parent, obj, prevValue) {
1185
1186
  var _a, _b, _c;
1186
1187
  if ((process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") && typeof __devUpdateNodes !== "undefined" && isObject(obj)) {
@@ -2338,6 +2339,7 @@ var internal = {
2338
2339
  ensureNodeValue,
2339
2340
  findIDKey,
2340
2341
  get,
2342
+ getKeys,
2341
2343
  getNode,
2342
2344
  getNodeValue,
2343
2345
  getPathType,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/state",
3
- "version": "3.0.0-beta.21",
3
+ "version": "3.0.0-beta.23",
4
4
  "description": "legend-state",
5
5
  "sideEffects": false,
6
6
  "private": false,
@@ -4,7 +4,7 @@ var state = require('@legendapp/state');
4
4
  var sync = require('@legendapp/state/sync');
5
5
 
6
6
  // src/sync-plugins/crud.ts
7
- var { clone } = state.internal;
7
+ var { clone, getKeys } = state.internal;
8
8
  var { waitForSet, runWithRetry } = sync.internal;
9
9
  function transformOut(data, transform) {
10
10
  return transform ? transform(clone(data)) : data;
@@ -25,6 +25,17 @@ function computeLastSync(data, fieldUpdatedAt, fieldCreatedAt) {
25
25
  }
26
26
  return newLastSync;
27
27
  }
28
+ function arrayToRecord(arr, keyField) {
29
+ const record = {};
30
+ if (arr == null ? void 0 : arr.length) {
31
+ for (let i = 0; i < arr.length; i++) {
32
+ const v = arr[i];
33
+ const key = v[keyField];
34
+ record[key] = v;
35
+ }
36
+ }
37
+ return record;
38
+ }
28
39
  function retrySet(params, retry, action, itemKey, itemValue, change, queuedRetries, actionFn, saveResult) {
29
40
  if (action === "delete") {
30
41
  if (queuedRetries.create.has(itemKey)) {
@@ -179,6 +190,7 @@ function syncedCrud(props) {
179
190
  const { value, changes, update, retryAsCreate, node } = params;
180
191
  const creates = /* @__PURE__ */ new Map();
181
192
  const updates = /* @__PURE__ */ new Map();
193
+ const updateFullValues = /* @__PURE__ */ new Map();
182
194
  const deletes = /* @__PURE__ */ new Set();
183
195
  const changesById = /* @__PURE__ */ new Map();
184
196
  const getUpdateValue = (itemValue, prev) => {
@@ -193,6 +205,7 @@ function syncedCrud(props) {
193
205
  ) : itemValue;
194
206
  };
195
207
  changes.forEach((change) => {
208
+ var _a, _b;
196
209
  const { path, prevAtPath, valueAtPath, pathTypes } = change;
197
210
  if (asType === "value") {
198
211
  if (value) {
@@ -215,6 +228,7 @@ function syncedCrud(props) {
215
228
  } else if (path.length === 0) {
216
229
  if (valueAtPath) {
217
230
  updates.set(id, getUpdateValue(valueAtPath, prevAtPath));
231
+ updateFullValues.set(id, valueAtPath);
218
232
  } else if (prevAtPath) {
219
233
  deletes.add(prevAtPath);
220
234
  }
@@ -226,6 +240,7 @@ function syncedCrud(props) {
226
240
  true
227
241
  );
228
242
  updates.set(id, getUpdateValue(value, previous));
243
+ updateFullValues.set(id, value);
229
244
  }
230
245
  } else {
231
246
  console.error("[legend-state]: added synced item without an id");
@@ -237,17 +252,30 @@ function syncedCrud(props) {
237
252
  } else {
238
253
  let itemsChanged = [];
239
254
  if (path.length === 0) {
240
- const changed = asMap ? Array.from(valueAtPath.entries()) : Object.entries(valueAtPath);
241
- for (let i = 0; i < changed.length; i++) {
242
- const [key, value2] = changed[i];
243
- const prev = prevAtPath ? asMap ? prevAtPath.get(key) : prevAtPath[key] : void 0;
255
+ const valueAsObject = asArray ? arrayToRecord(valueAtPath, fieldId) : valueAtPath;
256
+ const prevAsObject = asArray ? arrayToRecord(prevAtPath, fieldId) : prevAtPath;
257
+ const keys = getKeys(valueAsObject, false, asMap, false);
258
+ const keysPrev = getKeys(prevAsObject, false, asMap, false);
259
+ const keysSet = new Set(keys);
260
+ const length = ((_a = keys || valueAsObject) == null ? void 0 : _a.length) || 0;
261
+ const lengthPrev = ((_b = keysPrev || prevAsObject) == null ? void 0 : _b.length) || 0;
262
+ for (let i = 0; i < lengthPrev; i++) {
263
+ const key = keysPrev[i];
264
+ if (!keysSet.has(key)) {
265
+ deletes.add(prevAsObject[key]);
266
+ }
267
+ }
268
+ for (let i = 0; i < length; i++) {
269
+ const key = keys[i];
270
+ const value2 = asMap ? valueAsObject.get(key) : valueAsObject[key];
271
+ const prev = prevAsObject ? asMap ? prevAsObject.get(key) : prevAsObject[key] : void 0;
244
272
  if (state.isNullOrUndefined(value2) && !state.isNullOrUndefined(prev)) {
245
273
  deletes.add(prev);
246
274
  return false;
247
275
  } else {
248
- const isDiff = !prevAtPath || !sync.deepEqual(value2, prev);
276
+ const isDiff = !prevAsObject || !sync.deepEqual(value2, prev);
249
277
  if (isDiff) {
250
- itemsChanged.push([getUpdateValue(value2, prev), prev]);
278
+ itemsChanged.push([getUpdateValue(value2, prev), prev, value2]);
251
279
  }
252
280
  }
253
281
  }
@@ -266,10 +294,10 @@ function syncedCrud(props) {
266
294
  pathTypes.slice(1),
267
295
  prevAtPath
268
296
  );
269
- itemsChanged = [[getUpdateValue(itemValue, previous), previous]];
297
+ itemsChanged = [[getUpdateValue(itemValue, previous), previous, itemValue]];
270
298
  }
271
299
  }
272
- itemsChanged == null ? void 0 : itemsChanged.forEach(([item, prev]) => {
300
+ itemsChanged == null ? void 0 : itemsChanged.forEach(([item, prev, fullValue]) => {
273
301
  const isCreate = !pendingCreates.has(item[fieldId]) && (fieldCreatedAt ? !item[fieldCreatedAt] && !(prev == null ? void 0 : prev[fieldCreatedAt]) : fieldUpdatedAt ? !item[fieldUpdatedAt] && !(prev == null ? void 0 : prev[fieldCreatedAt]) : state.isNullOrUndefined(prev));
274
302
  if (isCreate) {
275
303
  if (generateId) {
@@ -291,6 +319,10 @@ function syncedCrud(props) {
291
319
  const id = item[fieldId];
292
320
  changesById.set(id, change);
293
321
  updates.set(id, updates.has(id) ? Object.assign(updates.get(id), item) : item);
322
+ updateFullValues.set(
323
+ id,
324
+ updateFullValues.has(id) ? Object.assign(updateFullValues.get(id), fullValue) : fullValue
325
+ );
294
326
  } else {
295
327
  console.warn("[legend-state] missing update function");
296
328
  }
@@ -377,7 +409,8 @@ function syncedCrud(props) {
377
409
  // Handle updates
378
410
  ...Array.from(updates).map(async ([itemKey, itemValue]) => {
379
411
  if (waitForSetParam) {
380
- await waitForSet(waitForSetParam, changes, itemValue, { type: "update" });
412
+ const fullValue = updateFullValues.get(itemKey);
413
+ await waitForSet(waitForSetParam, changes, fullValue, { type: "update" });
381
414
  }
382
415
  const changed = await transformOut(itemValue, transform == null ? void 0 : transform.save);
383
416
  if (Object.keys(changed).length > 0) {
@@ -2,7 +2,7 @@ import { isPromise, isNullOrUndefined, applyChanges, setAtPath, symbolDelete, is
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;
5
+ var { clone, getKeys } = internal;
6
6
  var { waitForSet, runWithRetry } = internal$1;
7
7
  function transformOut(data, transform) {
8
8
  return transform ? transform(clone(data)) : data;
@@ -23,6 +23,17 @@ 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
+ }
26
37
  function retrySet(params, retry, action, itemKey, itemValue, change, queuedRetries, actionFn, saveResult) {
27
38
  if (action === "delete") {
28
39
  if (queuedRetries.create.has(itemKey)) {
@@ -177,6 +188,7 @@ function syncedCrud(props) {
177
188
  const { value, changes, update, retryAsCreate, node } = params;
178
189
  const creates = /* @__PURE__ */ new Map();
179
190
  const updates = /* @__PURE__ */ new Map();
191
+ const updateFullValues = /* @__PURE__ */ new Map();
180
192
  const deletes = /* @__PURE__ */ new Set();
181
193
  const changesById = /* @__PURE__ */ new Map();
182
194
  const getUpdateValue = (itemValue, prev) => {
@@ -191,6 +203,7 @@ function syncedCrud(props) {
191
203
  ) : itemValue;
192
204
  };
193
205
  changes.forEach((change) => {
206
+ var _a, _b;
194
207
  const { path, prevAtPath, valueAtPath, pathTypes } = change;
195
208
  if (asType === "value") {
196
209
  if (value) {
@@ -213,6 +226,7 @@ function syncedCrud(props) {
213
226
  } else if (path.length === 0) {
214
227
  if (valueAtPath) {
215
228
  updates.set(id, getUpdateValue(valueAtPath, prevAtPath));
229
+ updateFullValues.set(id, valueAtPath);
216
230
  } else if (prevAtPath) {
217
231
  deletes.add(prevAtPath);
218
232
  }
@@ -224,6 +238,7 @@ function syncedCrud(props) {
224
238
  true
225
239
  );
226
240
  updates.set(id, getUpdateValue(value, previous));
241
+ updateFullValues.set(id, value);
227
242
  }
228
243
  } else {
229
244
  console.error("[legend-state]: added synced item without an id");
@@ -235,17 +250,30 @@ function syncedCrud(props) {
235
250
  } else {
236
251
  let itemsChanged = [];
237
252
  if (path.length === 0) {
238
- const changed = asMap ? Array.from(valueAtPath.entries()) : Object.entries(valueAtPath);
239
- for (let i = 0; i < changed.length; i++) {
240
- const [key, value2] = changed[i];
241
- const prev = prevAtPath ? asMap ? prevAtPath.get(key) : prevAtPath[key] : void 0;
253
+ const valueAsObject = asArray ? arrayToRecord(valueAtPath, fieldId) : valueAtPath;
254
+ const prevAsObject = asArray ? arrayToRecord(prevAtPath, fieldId) : prevAtPath;
255
+ const keys = getKeys(valueAsObject, false, asMap, false);
256
+ const keysPrev = getKeys(prevAsObject, false, asMap, false);
257
+ const keysSet = new Set(keys);
258
+ const length = ((_a = keys || valueAsObject) == null ? void 0 : _a.length) || 0;
259
+ const lengthPrev = ((_b = keysPrev || prevAsObject) == null ? void 0 : _b.length) || 0;
260
+ for (let i = 0; i < lengthPrev; i++) {
261
+ const key = keysPrev[i];
262
+ if (!keysSet.has(key)) {
263
+ deletes.add(prevAsObject[key]);
264
+ }
265
+ }
266
+ for (let i = 0; i < length; i++) {
267
+ const key = keys[i];
268
+ const value2 = asMap ? valueAsObject.get(key) : valueAsObject[key];
269
+ const prev = prevAsObject ? asMap ? prevAsObject.get(key) : prevAsObject[key] : void 0;
242
270
  if (isNullOrUndefined(value2) && !isNullOrUndefined(prev)) {
243
271
  deletes.add(prev);
244
272
  return false;
245
273
  } else {
246
- const isDiff = !prevAtPath || !deepEqual(value2, prev);
274
+ const isDiff = !prevAsObject || !deepEqual(value2, prev);
247
275
  if (isDiff) {
248
- itemsChanged.push([getUpdateValue(value2, prev), prev]);
276
+ itemsChanged.push([getUpdateValue(value2, prev), prev, value2]);
249
277
  }
250
278
  }
251
279
  }
@@ -264,10 +292,10 @@ function syncedCrud(props) {
264
292
  pathTypes.slice(1),
265
293
  prevAtPath
266
294
  );
267
- itemsChanged = [[getUpdateValue(itemValue, previous), previous]];
295
+ itemsChanged = [[getUpdateValue(itemValue, previous), previous, itemValue]];
268
296
  }
269
297
  }
270
- itemsChanged == null ? void 0 : itemsChanged.forEach(([item, prev]) => {
298
+ itemsChanged == null ? void 0 : itemsChanged.forEach(([item, prev, fullValue]) => {
271
299
  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));
272
300
  if (isCreate) {
273
301
  if (generateId) {
@@ -289,6 +317,10 @@ function syncedCrud(props) {
289
317
  const id = item[fieldId];
290
318
  changesById.set(id, change);
291
319
  updates.set(id, updates.has(id) ? Object.assign(updates.get(id), item) : item);
320
+ updateFullValues.set(
321
+ id,
322
+ updateFullValues.has(id) ? Object.assign(updateFullValues.get(id), fullValue) : fullValue
323
+ );
292
324
  } else {
293
325
  console.warn("[legend-state] missing update function");
294
326
  }
@@ -375,7 +407,8 @@ function syncedCrud(props) {
375
407
  // Handle updates
376
408
  ...Array.from(updates).map(async ([itemKey, itemValue]) => {
377
409
  if (waitForSetParam) {
378
- await waitForSet(waitForSetParam, changes, itemValue, { type: "update" });
410
+ const fullValue = updateFullValues.get(itemKey);
411
+ await waitForSet(waitForSetParam, changes, fullValue, { type: "update" });
379
412
  }
380
413
  const changed = await transformOut(itemValue, transform == null ? void 0 : transform.save);
381
414
  if (Object.keys(changed).length > 0) {