@legendapp/state 3.0.0-beta.42 → 3.0.0-beta.43

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
@@ -5,9 +5,9 @@ type RemoveIndex<T> = {
5
5
  };
6
6
  type BuiltIns = String | Boolean | Number | Date | Error | RegExp | Array<any> | Function | Promise<any>;
7
7
  type IsUserDefinedObject<T> = T extends Function | BuiltIns | any[] ? false : T extends object ? true : false;
8
- type RemoveObservables<T> = T extends ImmutableObservableBase<infer t> ? t : T extends ImmutableObservableBase<infer t>[] ? t[] : IsUserDefinedObject<T> extends true ? {
8
+ type RemoveObservables<T> = T extends OpaqueObject<infer t> ? t : T extends ImmutableObservableBase<infer t> ? t : T extends ImmutableObservableBase<infer t>[] ? t[] : IsUserDefinedObject<T> extends true ? {
9
9
  [K in keyof T]: RemoveObservables<T[K]>;
10
- } : T extends ImmutableObservableBase<infer TObs> ? TObs : T extends () => infer TRet ? RemoveObservables<TRet> & T : T extends (key: infer TKey extends string | number) => infer TRet ? Record<TKey, RemoveObservables<TRet>> & T : T extends OpaqueObject<infer TObj> ? TObj : T;
10
+ } : T extends ImmutableObservableBase<infer TObs> ? TObs : T extends () => infer TRet ? RemoveObservables<TRet> & T : T extends (key: infer TKey extends string | number) => infer TRet ? Record<TKey, RemoveObservables<TRet>> & T : T;
11
11
  interface ObservableArray<T, U> extends ObservablePrimitive<T>, Pick<Array<Observable<U>>, ArrayOverrideFnNames>, Omit<RemoveIndex<Array<U>>, ArrayOverrideFnNames> {
12
12
  }
13
13
  interface ObservableObjectFns<T> {
@@ -29,7 +29,7 @@ type ObservableSet<T extends Set<any> | WeakSet<any>> = Omit<T, 'size' | 'add'>
29
29
  size: number;
30
30
  add: (value: SetValue<T>) => Observable<T>;
31
31
  };
32
- interface ObservableBoolean extends ObservablePrimitive<boolean> {
32
+ interface ObservableBoolean<T = any> extends ObservablePrimitive<T> {
33
33
  toggle(): void;
34
34
  }
35
35
  interface ObservablePrimitive<T> extends ImmutableObservableBase<T>, MutableObservableBase<T> {
@@ -87,7 +87,7 @@ type ObservableFunction<T> = T extends () => infer t ? t | (() => t) : T;
87
87
  type IsLookupFunction<T> = T extends (...args: infer P) => any ? P extends {
88
88
  length: 1;
89
89
  } ? P[0] extends string | ObservablePrimitive<string> | number | ObservablePrimitive<number> ? true : false : false : false;
90
- type ObservableNode<T, NT = NonNullable<T>> = [NT] extends [never] ? ObservablePrimitive<T> : IsStrictAny<T> extends true ? ObservableAny : [T] extends [Promise<infer t>] ? ObservableNode<t> : [T] extends [(key: infer K extends string) => infer t] ? [t] extends [ImmutableObservableBase<any>] ? IsLookupFunction<T> extends true ? Observable<Record<K, t>> : t : IsLookupFunction<T> extends true ? Observable<Record<K, t>> & T : Observable<ObservableFunction<t>> : [NT] extends [ImmutableObservableBase<any>] ? NT : [NT] extends [Primitive$1] ? [NT] extends [boolean] ? ObservableBoolean : ObservablePrimitive<T> : NT extends Map<any, any> | WeakMap<any, any> ? ObservableMap<NT> : NT extends Set<infer U> ? ObservableSet<Set<UndefinedIf<U, IsNullable<T>>>> : NT extends WeakSet<any> ? ObservableSet<NT> : NT extends Array<infer U> ? ObservableArray<T, U> & ObservableChildren<T> : ObservableObject<T> & {};
90
+ type ObservableNode<T, NT = NonNullable<T>> = [NT] extends [never] ? ObservablePrimitive<T> : IsStrictAny<T> extends true ? ObservableAny : [T] extends [Promise<infer t>] ? ObservableNode<t> : [T] extends [(key: infer K extends string) => infer t] ? [t] extends [ImmutableObservableBase<any>] ? IsLookupFunction<T> extends true ? Observable<Record<K, t>> : t : IsLookupFunction<T> extends true ? Observable<Record<K, t>> & T : Observable<ObservableFunction<t>> : [NT] extends [ImmutableObservableBase<any>] ? NT : [NT] extends [Primitive$1] ? [NT] extends [boolean] ? ObservableBoolean<T> : ObservablePrimitive<T> : NT extends Map<any, any> | WeakMap<any, any> ? ObservableMap<NT> : NT extends Set<infer U> ? ObservableSet<Set<UndefinedIf<U, IsNullable<T>>>> : NT extends WeakSet<any> ? ObservableSet<NT> : NT extends Array<infer U> ? ObservableArray<T, U> & ObservableChildren<T> : ObservableObject<T> & {};
91
91
  type Observable<T = any> = ObservableNode<T> & {};
92
92
  type ObservableParam<T = any> = ImmutableObservableSimple<T> & MutableObservableSimple;
93
93
  type FixExpanded<T> = [T] extends [boolean] ? boolean : T;
@@ -146,6 +146,9 @@ interface Change {
146
146
  valueAtPath: any;
147
147
  prevAtPath: any;
148
148
  }
149
+ interface ChangeWithPathStr extends Change {
150
+ pathStr: string;
151
+ }
149
152
  type RecordValue<T> = T extends Record<string, infer t> ? t : never;
150
153
  type ArrayValue<T> = T extends Array<infer t> ? t : never;
151
154
  type ObservableValue<T> = T extends Observable<infer t> ? t : never;
@@ -253,8 +256,13 @@ interface UpdateFnParams<T = any> {
253
256
  lastSync?: number | undefined;
254
257
  changes?: Change[];
255
258
  }
256
- interface UpdateSetFnParams<T = any> extends UpdateFnParams<T> {
259
+ type DeepPartial<T> = T extends readonly (infer U)[] ? ReadonlyArray<DeepPartial<U>> : T extends Array<infer U> ? Array<DeepPartial<U>> : T extends object ? {
260
+ [K in keyof T]?: DeepPartial<T[K]>;
261
+ } : T;
262
+ interface UpdateSetFnParams<T = any> extends Omit<UpdateFnParams<T>, 'value'> {
263
+ value: DeepPartial<T>;
257
264
  lastSync?: never;
265
+ changes?: ChangeWithPathStr[];
258
266
  }
259
267
  type UpdateFn<T = any> = (params: UpdateFnParams<T>) => void;
260
268
  type UpdateSetFn<T = any> = (params: UpdateSetFnParams<T>) => void;
@@ -464,4 +472,4 @@ declare const internal: {
464
472
  };
465
473
  };
466
474
 
467
- export { type ArrayValue, type Change, type ChildNodeInfo, type ClassConstructor, type GetMode, type GetOptions, type ImmutableObservableBase, type Linked, type LinkedOptions, type ListenerFn, type ListenerParams, type NodeInfo, type NodeListener, type NotPrimitive, type Observable, type ObservableBoolean, type ObservableEvent, ObservableHint, type ObservableListenerDispose, type ObservableMap, type ObservableObject, type ObservableObjectFns, type ObservableParam, type ObservablePrimitive, type ObservableRoot, type ObservableState, type ObservableSyncState, type ObservableSyncStateBase, type ObservableSyncStateOptions, type ObservableValue, type ObserveEvent, type ObserveEventCallback, type ObserveOptions, type OpaqueObject, type PlainObject, type Primitive, type RecordValue, type RecursiveValueOrFunction, type RemoveObservables, type RetryOptions, type RootNodeInfo, type Selector, type SetParams, type TrackingNode, type TrackingState, type TrackingType, type TypeAtPath, type UpdateFn, type UpdateFnParams, type UpdateSetFn, type UpdateSetFnParams, type WaitForSet, type WaitForSetFnParams, applyChange, applyChanges, batch, beginBatch, computeSelector, computed, constructObjectWithPath, deconstructObjectWithPath, endBatch, event, getObservableIndex, hasOwnProperty, internal, isArray, isBoolean, isDate, isEmpty, isFunction, isMap, isNullOrUndefined, isNumber, isObject, isObservable, isObservableValueReady, isObserved, isPlainObject, isPrimitive, isPromise, isSet, isString, isSymbol, linked, mergeIntoObservable, observable, observablePrimitive, observe, opaqueObject, proxy, setAtPath, setSilently, shouldIgnoreUnobserved, syncState, trackSelector, when, whenReady };
475
+ export { type ArrayValue, type Change, type ChangeWithPathStr, type ChildNodeInfo, type ClassConstructor, type GetMode, type GetOptions, type ImmutableObservableBase, type Linked, type LinkedOptions, type ListenerFn, type ListenerParams, type NodeInfo, type NodeListener, type NotPrimitive, type Observable, type ObservableBoolean, type ObservableEvent, ObservableHint, type ObservableListenerDispose, type ObservableMap, type ObservableObject, type ObservableObjectFns, type ObservableParam, type ObservablePrimitive, type ObservableRoot, type ObservableState, type ObservableSyncState, type ObservableSyncStateBase, type ObservableSyncStateOptions, type ObservableValue, type ObserveEvent, type ObserveEventCallback, type ObserveOptions, type OpaqueObject, type PlainObject, type Primitive, type RecordValue, type RecursiveValueOrFunction, type RemoveObservables, type RetryOptions, type RootNodeInfo, type Selector, type SetParams, type TrackingNode, type TrackingState, type TrackingType, type TypeAtPath, type UpdateFn, type UpdateFnParams, type UpdateSetFn, type UpdateSetFnParams, type WaitForSet, type WaitForSetFnParams, applyChange, applyChanges, batch, beginBatch, computeSelector, computed, constructObjectWithPath, deconstructObjectWithPath, endBatch, event, getObservableIndex, hasOwnProperty, internal, isArray, isBoolean, isDate, isEmpty, isFunction, isMap, isNullOrUndefined, isNumber, isObject, isObservable, isObservableValueReady, isObserved, isPlainObject, isPrimitive, isPromise, isSet, isString, isSymbol, linked, mergeIntoObservable, observable, observablePrimitive, observe, opaqueObject, proxy, setAtPath, setSilently, shouldIgnoreUnobserved, syncState, trackSelector, when, whenReady };
package/index.d.ts CHANGED
@@ -5,9 +5,9 @@ type RemoveIndex<T> = {
5
5
  };
6
6
  type BuiltIns = String | Boolean | Number | Date | Error | RegExp | Array<any> | Function | Promise<any>;
7
7
  type IsUserDefinedObject<T> = T extends Function | BuiltIns | any[] ? false : T extends object ? true : false;
8
- type RemoveObservables<T> = T extends ImmutableObservableBase<infer t> ? t : T extends ImmutableObservableBase<infer t>[] ? t[] : IsUserDefinedObject<T> extends true ? {
8
+ type RemoveObservables<T> = T extends OpaqueObject<infer t> ? t : T extends ImmutableObservableBase<infer t> ? t : T extends ImmutableObservableBase<infer t>[] ? t[] : IsUserDefinedObject<T> extends true ? {
9
9
  [K in keyof T]: RemoveObservables<T[K]>;
10
- } : T extends ImmutableObservableBase<infer TObs> ? TObs : T extends () => infer TRet ? RemoveObservables<TRet> & T : T extends (key: infer TKey extends string | number) => infer TRet ? Record<TKey, RemoveObservables<TRet>> & T : T extends OpaqueObject<infer TObj> ? TObj : T;
10
+ } : T extends ImmutableObservableBase<infer TObs> ? TObs : T extends () => infer TRet ? RemoveObservables<TRet> & T : T extends (key: infer TKey extends string | number) => infer TRet ? Record<TKey, RemoveObservables<TRet>> & T : T;
11
11
  interface ObservableArray<T, U> extends ObservablePrimitive<T>, Pick<Array<Observable<U>>, ArrayOverrideFnNames>, Omit<RemoveIndex<Array<U>>, ArrayOverrideFnNames> {
12
12
  }
13
13
  interface ObservableObjectFns<T> {
@@ -29,7 +29,7 @@ type ObservableSet<T extends Set<any> | WeakSet<any>> = Omit<T, 'size' | 'add'>
29
29
  size: number;
30
30
  add: (value: SetValue<T>) => Observable<T>;
31
31
  };
32
- interface ObservableBoolean extends ObservablePrimitive<boolean> {
32
+ interface ObservableBoolean<T = any> extends ObservablePrimitive<T> {
33
33
  toggle(): void;
34
34
  }
35
35
  interface ObservablePrimitive<T> extends ImmutableObservableBase<T>, MutableObservableBase<T> {
@@ -87,7 +87,7 @@ type ObservableFunction<T> = T extends () => infer t ? t | (() => t) : T;
87
87
  type IsLookupFunction<T> = T extends (...args: infer P) => any ? P extends {
88
88
  length: 1;
89
89
  } ? P[0] extends string | ObservablePrimitive<string> | number | ObservablePrimitive<number> ? true : false : false : false;
90
- type ObservableNode<T, NT = NonNullable<T>> = [NT] extends [never] ? ObservablePrimitive<T> : IsStrictAny<T> extends true ? ObservableAny : [T] extends [Promise<infer t>] ? ObservableNode<t> : [T] extends [(key: infer K extends string) => infer t] ? [t] extends [ImmutableObservableBase<any>] ? IsLookupFunction<T> extends true ? Observable<Record<K, t>> : t : IsLookupFunction<T> extends true ? Observable<Record<K, t>> & T : Observable<ObservableFunction<t>> : [NT] extends [ImmutableObservableBase<any>] ? NT : [NT] extends [Primitive$1] ? [NT] extends [boolean] ? ObservableBoolean : ObservablePrimitive<T> : NT extends Map<any, any> | WeakMap<any, any> ? ObservableMap<NT> : NT extends Set<infer U> ? ObservableSet<Set<UndefinedIf<U, IsNullable<T>>>> : NT extends WeakSet<any> ? ObservableSet<NT> : NT extends Array<infer U> ? ObservableArray<T, U> & ObservableChildren<T> : ObservableObject<T> & {};
90
+ type ObservableNode<T, NT = NonNullable<T>> = [NT] extends [never] ? ObservablePrimitive<T> : IsStrictAny<T> extends true ? ObservableAny : [T] extends [Promise<infer t>] ? ObservableNode<t> : [T] extends [(key: infer K extends string) => infer t] ? [t] extends [ImmutableObservableBase<any>] ? IsLookupFunction<T> extends true ? Observable<Record<K, t>> : t : IsLookupFunction<T> extends true ? Observable<Record<K, t>> & T : Observable<ObservableFunction<t>> : [NT] extends [ImmutableObservableBase<any>] ? NT : [NT] extends [Primitive$1] ? [NT] extends [boolean] ? ObservableBoolean<T> : ObservablePrimitive<T> : NT extends Map<any, any> | WeakMap<any, any> ? ObservableMap<NT> : NT extends Set<infer U> ? ObservableSet<Set<UndefinedIf<U, IsNullable<T>>>> : NT extends WeakSet<any> ? ObservableSet<NT> : NT extends Array<infer U> ? ObservableArray<T, U> & ObservableChildren<T> : ObservableObject<T> & {};
91
91
  type Observable<T = any> = ObservableNode<T> & {};
92
92
  type ObservableParam<T = any> = ImmutableObservableSimple<T> & MutableObservableSimple;
93
93
  type FixExpanded<T> = [T] extends [boolean] ? boolean : T;
@@ -146,6 +146,9 @@ interface Change {
146
146
  valueAtPath: any;
147
147
  prevAtPath: any;
148
148
  }
149
+ interface ChangeWithPathStr extends Change {
150
+ pathStr: string;
151
+ }
149
152
  type RecordValue<T> = T extends Record<string, infer t> ? t : never;
150
153
  type ArrayValue<T> = T extends Array<infer t> ? t : never;
151
154
  type ObservableValue<T> = T extends Observable<infer t> ? t : never;
@@ -253,8 +256,13 @@ interface UpdateFnParams<T = any> {
253
256
  lastSync?: number | undefined;
254
257
  changes?: Change[];
255
258
  }
256
- interface UpdateSetFnParams<T = any> extends UpdateFnParams<T> {
259
+ type DeepPartial<T> = T extends readonly (infer U)[] ? ReadonlyArray<DeepPartial<U>> : T extends Array<infer U> ? Array<DeepPartial<U>> : T extends object ? {
260
+ [K in keyof T]?: DeepPartial<T[K]>;
261
+ } : T;
262
+ interface UpdateSetFnParams<T = any> extends Omit<UpdateFnParams<T>, 'value'> {
263
+ value: DeepPartial<T>;
257
264
  lastSync?: never;
265
+ changes?: ChangeWithPathStr[];
258
266
  }
259
267
  type UpdateFn<T = any> = (params: UpdateFnParams<T>) => void;
260
268
  type UpdateSetFn<T = any> = (params: UpdateSetFnParams<T>) => void;
@@ -464,4 +472,4 @@ declare const internal: {
464
472
  };
465
473
  };
466
474
 
467
- export { type ArrayValue, type Change, type ChildNodeInfo, type ClassConstructor, type GetMode, type GetOptions, type ImmutableObservableBase, type Linked, type LinkedOptions, type ListenerFn, type ListenerParams, type NodeInfo, type NodeListener, type NotPrimitive, type Observable, type ObservableBoolean, type ObservableEvent, ObservableHint, type ObservableListenerDispose, type ObservableMap, type ObservableObject, type ObservableObjectFns, type ObservableParam, type ObservablePrimitive, type ObservableRoot, type ObservableState, type ObservableSyncState, type ObservableSyncStateBase, type ObservableSyncStateOptions, type ObservableValue, type ObserveEvent, type ObserveEventCallback, type ObserveOptions, type OpaqueObject, type PlainObject, type Primitive, type RecordValue, type RecursiveValueOrFunction, type RemoveObservables, type RetryOptions, type RootNodeInfo, type Selector, type SetParams, type TrackingNode, type TrackingState, type TrackingType, type TypeAtPath, type UpdateFn, type UpdateFnParams, type UpdateSetFn, type UpdateSetFnParams, type WaitForSet, type WaitForSetFnParams, applyChange, applyChanges, batch, beginBatch, computeSelector, computed, constructObjectWithPath, deconstructObjectWithPath, endBatch, event, getObservableIndex, hasOwnProperty, internal, isArray, isBoolean, isDate, isEmpty, isFunction, isMap, isNullOrUndefined, isNumber, isObject, isObservable, isObservableValueReady, isObserved, isPlainObject, isPrimitive, isPromise, isSet, isString, isSymbol, linked, mergeIntoObservable, observable, observablePrimitive, observe, opaqueObject, proxy, setAtPath, setSilently, shouldIgnoreUnobserved, syncState, trackSelector, when, whenReady };
475
+ export { type ArrayValue, type Change, type ChangeWithPathStr, type ChildNodeInfo, type ClassConstructor, type GetMode, type GetOptions, type ImmutableObservableBase, type Linked, type LinkedOptions, type ListenerFn, type ListenerParams, type NodeInfo, type NodeListener, type NotPrimitive, type Observable, type ObservableBoolean, type ObservableEvent, ObservableHint, type ObservableListenerDispose, type ObservableMap, type ObservableObject, type ObservableObjectFns, type ObservableParam, type ObservablePrimitive, type ObservableRoot, type ObservableState, type ObservableSyncState, type ObservableSyncStateBase, type ObservableSyncStateOptions, type ObservableValue, type ObserveEvent, type ObserveEventCallback, type ObserveOptions, type OpaqueObject, type PlainObject, type Primitive, type RecordValue, type RecursiveValueOrFunction, type RemoveObservables, type RetryOptions, type RootNodeInfo, type Selector, type SetParams, type TrackingNode, type TrackingState, type TrackingType, type TypeAtPath, type UpdateFn, type UpdateFnParams, type UpdateSetFn, type UpdateSetFnParams, type WaitForSet, type WaitForSetFnParams, applyChange, applyChanges, batch, beginBatch, computeSelector, computed, constructObjectWithPath, deconstructObjectWithPath, endBatch, event, getObservableIndex, hasOwnProperty, internal, isArray, isBoolean, isDate, isEmpty, isFunction, isMap, isNullOrUndefined, isNumber, isObject, isObservable, isObservableValueReady, isObserved, isPlainObject, isPrimitive, isPromise, isSet, isString, isSymbol, linked, mergeIntoObservable, observable, observablePrimitive, observe, opaqueObject, proxy, setAtPath, setSilently, shouldIgnoreUnobserved, syncState, trackSelector, when, whenReady };
package/index.js CHANGED
@@ -416,10 +416,19 @@ function _mergeIntoObservable(target, source, levelsDeep) {
416
416
  const isArr = !isObj && isArray(sourceValue);
417
417
  const targetChild = target[key];
418
418
  if ((isObj || isArr) && targetChild) {
419
- if (levelsDeep > 0 && isEmpty(sourceValue)) {
419
+ if (isArr) {
420
+ const sourceArr = sourceValue;
421
+ const isSparseArray = Object.keys(sourceArr).length < sourceArr.length;
422
+ if (isSparseArray) {
423
+ _mergeIntoObservable(targetChild, sourceValue, levelsDeep + 1);
424
+ } else {
425
+ targetChild.set(sourceValue);
426
+ }
427
+ } else if (levelsDeep > 0 && isEmpty(sourceValue)) {
420
428
  targetChild.set(sourceValue);
429
+ } else {
430
+ _mergeIntoObservable(targetChild, sourceValue, levelsDeep + 1);
421
431
  }
422
- _mergeIntoObservable(targetChild, sourceValue, levelsDeep + 1);
423
432
  } else {
424
433
  targetChild.set(sourceValue);
425
434
  }
@@ -1501,7 +1510,7 @@ function flushPending() {
1501
1510
  }
1502
1511
  var proxyHandler = {
1503
1512
  get(node, p, receiver) {
1504
- var _a, _b;
1513
+ var _a, _b, _c;
1505
1514
  if (p === symbolToPrimitive) {
1506
1515
  throw new Error(
1507
1516
  process.env.NODE_ENV === "development" ? "[legend-state] observable should not be used as a primitive. You may have forgotten to use .get() or .peek() to get the value of the observable." : "[legend-state] observable is not a primitive."
@@ -1516,6 +1525,10 @@ var proxyHandler = {
1516
1525
  return nodeValue[p];
1517
1526
  }
1518
1527
  }
1528
+ if (p === "constructor") {
1529
+ const ctor = (_a = peekInternal(node)) == null ? void 0 : _a.constructor;
1530
+ return typeof ctor === "function" ? ctor : Object;
1531
+ }
1519
1532
  let value = peekInternal(
1520
1533
  node,
1521
1534
  /*activateRecursive*/
@@ -1561,7 +1574,7 @@ var proxyHandler = {
1561
1574
  if (isObject(value) && isHintOpaque(value)) {
1562
1575
  return vProp;
1563
1576
  }
1564
- const fnOrComputed = (_a = node.functions) == null ? void 0 : _a.get(p);
1577
+ const fnOrComputed = (_b = node.functions) == null ? void 0 : _b.get(p);
1565
1578
  if (fnOrComputed) {
1566
1579
  if (isObservable(fnOrComputed)) {
1567
1580
  return fnOrComputed;
@@ -1614,7 +1627,7 @@ var proxyHandler = {
1614
1627
  }
1615
1628
  }
1616
1629
  extractFunctionOrComputed(node, p, vProp);
1617
- const fnOrComputed2 = (_b = node.functions) == null ? void 0 : _b.get(p);
1630
+ const fnOrComputed2 = (_c = node.functions) == null ? void 0 : _c.get(p);
1618
1631
  if (fnOrComputed2) {
1619
1632
  return getProxy(node, p, fnOrComputed2);
1620
1633
  }
@@ -1689,7 +1702,13 @@ var proxyHandler = {
1689
1702
  },
1690
1703
  has(node, prop) {
1691
1704
  const value = getNodeValue(node);
1692
- return Reflect.has(value, prop);
1705
+ if (value === void 0 || value === null) {
1706
+ return false;
1707
+ }
1708
+ if (typeof value === "object" || typeof value === "function") {
1709
+ return Reflect.has(value, prop);
1710
+ }
1711
+ return false;
1693
1712
  },
1694
1713
  apply(target, thisArg, argArray) {
1695
1714
  if (isObservable(thisArg)) {
package/index.mjs CHANGED
@@ -414,10 +414,19 @@ function _mergeIntoObservable(target, source, levelsDeep) {
414
414
  const isArr = !isObj && isArray(sourceValue);
415
415
  const targetChild = target[key];
416
416
  if ((isObj || isArr) && targetChild) {
417
- if (levelsDeep > 0 && isEmpty(sourceValue)) {
417
+ if (isArr) {
418
+ const sourceArr = sourceValue;
419
+ const isSparseArray = Object.keys(sourceArr).length < sourceArr.length;
420
+ if (isSparseArray) {
421
+ _mergeIntoObservable(targetChild, sourceValue, levelsDeep + 1);
422
+ } else {
423
+ targetChild.set(sourceValue);
424
+ }
425
+ } else if (levelsDeep > 0 && isEmpty(sourceValue)) {
418
426
  targetChild.set(sourceValue);
427
+ } else {
428
+ _mergeIntoObservable(targetChild, sourceValue, levelsDeep + 1);
419
429
  }
420
- _mergeIntoObservable(targetChild, sourceValue, levelsDeep + 1);
421
430
  } else {
422
431
  targetChild.set(sourceValue);
423
432
  }
@@ -1499,7 +1508,7 @@ function flushPending() {
1499
1508
  }
1500
1509
  var proxyHandler = {
1501
1510
  get(node, p, receiver) {
1502
- var _a, _b;
1511
+ var _a, _b, _c;
1503
1512
  if (p === symbolToPrimitive) {
1504
1513
  throw new Error(
1505
1514
  process.env.NODE_ENV === "development" ? "[legend-state] observable should not be used as a primitive. You may have forgotten to use .get() or .peek() to get the value of the observable." : "[legend-state] observable is not a primitive."
@@ -1514,6 +1523,10 @@ var proxyHandler = {
1514
1523
  return nodeValue[p];
1515
1524
  }
1516
1525
  }
1526
+ if (p === "constructor") {
1527
+ const ctor = (_a = peekInternal(node)) == null ? void 0 : _a.constructor;
1528
+ return typeof ctor === "function" ? ctor : Object;
1529
+ }
1517
1530
  let value = peekInternal(
1518
1531
  node,
1519
1532
  /*activateRecursive*/
@@ -1559,7 +1572,7 @@ var proxyHandler = {
1559
1572
  if (isObject(value) && isHintOpaque(value)) {
1560
1573
  return vProp;
1561
1574
  }
1562
- const fnOrComputed = (_a = node.functions) == null ? void 0 : _a.get(p);
1575
+ const fnOrComputed = (_b = node.functions) == null ? void 0 : _b.get(p);
1563
1576
  if (fnOrComputed) {
1564
1577
  if (isObservable(fnOrComputed)) {
1565
1578
  return fnOrComputed;
@@ -1612,7 +1625,7 @@ var proxyHandler = {
1612
1625
  }
1613
1626
  }
1614
1627
  extractFunctionOrComputed(node, p, vProp);
1615
- const fnOrComputed2 = (_b = node.functions) == null ? void 0 : _b.get(p);
1628
+ const fnOrComputed2 = (_c = node.functions) == null ? void 0 : _c.get(p);
1616
1629
  if (fnOrComputed2) {
1617
1630
  return getProxy(node, p, fnOrComputed2);
1618
1631
  }
@@ -1687,7 +1700,13 @@ var proxyHandler = {
1687
1700
  },
1688
1701
  has(node, prop) {
1689
1702
  const value = getNodeValue(node);
1690
- return Reflect.has(value, prop);
1703
+ if (value === void 0 || value === null) {
1704
+ return false;
1705
+ }
1706
+ if (typeof value === "object" || typeof value === "function") {
1707
+ return Reflect.has(value, prop);
1708
+ }
1709
+ return false;
1691
1710
  },
1692
1711
  apply(target, thisArg, argArray) {
1693
1712
  if (isObservable(thisArg)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/state",
3
- "version": "3.0.0-beta.42",
3
+ "version": "3.0.0-beta.43",
4
4
  "description": "legend-state",
5
5
  "sideEffects": false,
6
6
  "private": false,
@@ -1,12 +1,13 @@
1
1
  import { Change } from '@legendapp/state';
2
2
  import { ObservablePersistPlugin, PersistOptions, PersistMetadata } from '@legendapp/state/sync';
3
- import { MMKVConfiguration } from 'react-native-mmkv';
3
+ import * as mmkv from 'react-native-mmkv';
4
4
 
5
+ type Configuration = mmkv.Configuration;
5
6
  declare class ObservablePersistMMKV implements ObservablePersistPlugin {
6
7
  private data;
7
8
  private storages;
8
9
  private configuration;
9
- constructor(configuration: MMKVConfiguration);
10
+ constructor(configuration: Configuration);
10
11
  getTable<T = any>(table: string, init: object, config: PersistOptions): T;
11
12
  getMetadata(table: string, config: PersistOptions): PersistMetadata;
12
13
  set(table: string, changes: Change[], config: PersistOptions): void;
@@ -17,6 +18,6 @@ declare class ObservablePersistMMKV implements ObservablePersistPlugin {
17
18
  private setValue;
18
19
  private save;
19
20
  }
20
- declare function observablePersistMMKV(configuration: MMKVConfiguration): ObservablePersistMMKV;
21
+ declare function observablePersistMMKV(configuration: Configuration): ObservablePersistMMKV;
21
22
 
22
23
  export { ObservablePersistMMKV, observablePersistMMKV };
@@ -1,12 +1,13 @@
1
1
  import { Change } from '@legendapp/state';
2
2
  import { ObservablePersistPlugin, PersistOptions, PersistMetadata } from '@legendapp/state/sync';
3
- import { MMKVConfiguration } from 'react-native-mmkv';
3
+ import * as mmkv from 'react-native-mmkv';
4
4
 
5
+ type Configuration = mmkv.Configuration;
5
6
  declare class ObservablePersistMMKV implements ObservablePersistPlugin {
6
7
  private data;
7
8
  private storages;
8
9
  private configuration;
9
- constructor(configuration: MMKVConfiguration);
10
+ constructor(configuration: Configuration);
10
11
  getTable<T = any>(table: string, init: object, config: PersistOptions): T;
11
12
  getMetadata(table: string, config: PersistOptions): PersistMetadata;
12
13
  set(table: string, changes: Change[], config: PersistOptions): void;
@@ -17,6 +18,6 @@ declare class ObservablePersistMMKV implements ObservablePersistPlugin {
17
18
  private setValue;
18
19
  private save;
19
20
  }
20
- declare function observablePersistMMKV(configuration: MMKVConfiguration): ObservablePersistMMKV;
21
+ declare function observablePersistMMKV(configuration: Configuration): ObservablePersistMMKV;
21
22
 
22
23
  export { ObservablePersistMMKV, observablePersistMMKV };
@@ -1,19 +1,55 @@
1
1
  'use strict';
2
2
 
3
3
  var state = require('@legendapp/state');
4
- var reactNativeMmkv = require('react-native-mmkv');
4
+ var mmkv = require('react-native-mmkv');
5
+
6
+ function _interopNamespace(e) {
7
+ if (e && e.__esModule) return e;
8
+ var n = Object.create(null);
9
+ if (e) {
10
+ Object.keys(e).forEach(function (k) {
11
+ if (k !== 'default') {
12
+ var d = Object.getOwnPropertyDescriptor(e, k);
13
+ Object.defineProperty(n, k, d.get ? d : {
14
+ enumerable: true,
15
+ get: function () { return e[k]; }
16
+ });
17
+ }
18
+ });
19
+ }
20
+ n.default = e;
21
+ return Object.freeze(n);
22
+ }
23
+
24
+ var mmkv__namespace = /*#__PURE__*/_interopNamespace(mmkv);
5
25
 
6
26
  // src/persist-plugins/mmkv.ts
7
27
  var symbolDefault = Symbol();
8
28
  var MetadataSuffix = "__m";
9
29
  var { safeParse, safeStringify } = state.internal;
30
+ function createMMKVInstance(config) {
31
+ const hasCreateFunction = "createMMKV" in mmkv__namespace;
32
+ if (hasCreateFunction) {
33
+ return mmkv__namespace.createMMKV(config);
34
+ } else {
35
+ const { MMKV: MMKVConstructor } = mmkv__namespace;
36
+ return new MMKVConstructor(config);
37
+ }
38
+ }
39
+ function deleteFromMMKV(storage, key) {
40
+ if ("remove" in storage) {
41
+ storage.remove(key);
42
+ } else {
43
+ storage.delete(key);
44
+ }
45
+ }
10
46
  var ObservablePersistMMKV = class {
11
47
  constructor(configuration) {
12
48
  this.data = {};
13
49
  this.storages = /* @__PURE__ */ new Map([
14
50
  [
15
51
  symbolDefault,
16
- new reactNativeMmkv.MMKV({
52
+ createMMKVInstance({
17
53
  id: `obsPersist`
18
54
  })
19
55
  ]
@@ -53,7 +89,7 @@ var ObservablePersistMMKV = class {
53
89
  deleteTable(table, config) {
54
90
  const storage = this.getStorage(config);
55
91
  delete this.data[table];
56
- storage.delete(table);
92
+ deleteFromMMKV(storage, table);
57
93
  }
58
94
  deleteMetadata(table, config) {
59
95
  this.deleteTable(table + MetadataSuffix, config);
@@ -65,7 +101,7 @@ var ObservablePersistMMKV = class {
65
101
  const key = JSON.stringify(configuration);
66
102
  let storage = this.storages.get(key);
67
103
  if (!storage) {
68
- storage = new reactNativeMmkv.MMKV(configuration);
104
+ storage = createMMKVInstance(configuration);
69
105
  this.storages.set(key, storage);
70
106
  }
71
107
  return storage;
@@ -87,7 +123,7 @@ var ObservablePersistMMKV = class {
87
123
  console.error(err);
88
124
  }
89
125
  } else {
90
- storage.delete(table);
126
+ deleteFromMMKV(storage, table);
91
127
  }
92
128
  }
93
129
  };
@@ -1,17 +1,33 @@
1
1
  import { setAtPath, internal } from '@legendapp/state';
2
- import { MMKV } from 'react-native-mmkv';
2
+ import * as mmkv from 'react-native-mmkv';
3
3
 
4
4
  // src/persist-plugins/mmkv.ts
5
5
  var symbolDefault = Symbol();
6
6
  var MetadataSuffix = "__m";
7
7
  var { safeParse, safeStringify } = internal;
8
+ function createMMKVInstance(config) {
9
+ const hasCreateFunction = "createMMKV" in mmkv;
10
+ if (hasCreateFunction) {
11
+ return mmkv.createMMKV(config);
12
+ } else {
13
+ const { MMKV: MMKVConstructor } = mmkv;
14
+ return new MMKVConstructor(config);
15
+ }
16
+ }
17
+ function deleteFromMMKV(storage, key) {
18
+ if ("remove" in storage) {
19
+ storage.remove(key);
20
+ } else {
21
+ storage.delete(key);
22
+ }
23
+ }
8
24
  var ObservablePersistMMKV = class {
9
25
  constructor(configuration) {
10
26
  this.data = {};
11
27
  this.storages = /* @__PURE__ */ new Map([
12
28
  [
13
29
  symbolDefault,
14
- new MMKV({
30
+ createMMKVInstance({
15
31
  id: `obsPersist`
16
32
  })
17
33
  ]
@@ -51,7 +67,7 @@ var ObservablePersistMMKV = class {
51
67
  deleteTable(table, config) {
52
68
  const storage = this.getStorage(config);
53
69
  delete this.data[table];
54
- storage.delete(table);
70
+ deleteFromMMKV(storage, table);
55
71
  }
56
72
  deleteMetadata(table, config) {
57
73
  this.deleteTable(table + MetadataSuffix, config);
@@ -63,7 +79,7 @@ var ObservablePersistMMKV = class {
63
79
  const key = JSON.stringify(configuration);
64
80
  let storage = this.storages.get(key);
65
81
  if (!storage) {
66
- storage = new MMKV(configuration);
82
+ storage = createMMKVInstance(configuration);
67
83
  this.storages.set(key, storage);
68
84
  }
69
85
  return storage;
@@ -85,7 +101,7 @@ var ObservablePersistMMKV = class {
85
101
  console.error(err);
86
102
  }
87
103
  } else {
88
- storage.delete(table);
104
+ deleteFromMMKV(storage, table);
89
105
  }
90
106
  }
91
107
  };
package/react.d.mts CHANGED
@@ -22,8 +22,8 @@ declare function For<T, TProps>({ each, optimized: isOptimized, item, itemProps,
22
22
  declare function usePauseProvider(): {
23
23
  PauseProvider: ({ children }: {
24
24
  children: ReactNode;
25
- }) => React.FunctionComponentElement<React.ProviderProps<ObservableBoolean>>;
26
- isPaused$: ObservableBoolean;
25
+ }) => React.FunctionComponentElement<React.ProviderProps<ObservableBoolean<boolean>>>;
26
+ isPaused$: ObservableBoolean<boolean>;
27
27
  };
28
28
 
29
29
  declare const Memo: NamedExoticComponent<{
package/react.d.ts CHANGED
@@ -22,8 +22,8 @@ declare function For<T, TProps>({ each, optimized: isOptimized, item, itemProps,
22
22
  declare function usePauseProvider(): {
23
23
  PauseProvider: ({ children }: {
24
24
  children: ReactNode;
25
- }) => React.FunctionComponentElement<React.ProviderProps<ObservableBoolean>>;
26
- isPaused$: ObservableBoolean;
25
+ }) => React.FunctionComponentElement<React.ProviderProps<ObservableBoolean<boolean>>>;
26
+ isPaused$: ObservableBoolean<boolean>;
27
27
  };
28
28
 
29
29
  declare const Memo: NamedExoticComponent<{
@@ -1,4 +1,4 @@
1
- import { WaitForSetFnParams, ObservableParam, ObservableEvent } from '@legendapp/state';
1
+ import { WaitForSetFnParams, ChangeWithPathStr, ObservableParam, ObservableEvent } from '@legendapp/state';
2
2
  import { SyncedGetParams, SyncedErrorParams, SyncedOptions, SyncedSetParams, SyncedSubscribeParams } from '@legendapp/state/sync';
3
3
 
4
4
  type CrudAsOption = 'Map' | 'object' | 'value' | 'array';
@@ -28,7 +28,8 @@ interface SyncedCrudOnSavedParams<TRemote extends object, TLocal> {
28
28
  isCreate: boolean;
29
29
  props: SyncedCrudPropsBase<TRemote, TLocal>;
30
30
  }
31
- interface WaitForSetCrudFnParams<T> extends WaitForSetFnParams<T> {
31
+ interface WaitForSetCrudFnParams<T> extends Omit<WaitForSetFnParams<T>, 'changes'> {
32
+ changes: ChangeWithPathStr[];
32
33
  type: 'create' | 'update' | 'delete';
33
34
  }
34
35
  interface CrudErrorParams extends Omit<SyncedErrorParams, 'source'> {
@@ -1,4 +1,4 @@
1
- import { WaitForSetFnParams, ObservableParam, ObservableEvent } from '@legendapp/state';
1
+ import { WaitForSetFnParams, ChangeWithPathStr, ObservableParam, ObservableEvent } from '@legendapp/state';
2
2
  import { SyncedGetParams, SyncedErrorParams, SyncedOptions, SyncedSetParams, SyncedSubscribeParams } from '@legendapp/state/sync';
3
3
 
4
4
  type CrudAsOption = 'Map' | 'object' | 'value' | 'array';
@@ -28,7 +28,8 @@ interface SyncedCrudOnSavedParams<TRemote extends object, TLocal> {
28
28
  isCreate: boolean;
29
29
  props: SyncedCrudPropsBase<TRemote, TLocal>;
30
30
  }
31
- interface WaitForSetCrudFnParams<T> extends WaitForSetFnParams<T> {
31
+ interface WaitForSetCrudFnParams<T> extends Omit<WaitForSetFnParams<T>, 'changes'> {
32
+ changes: ChangeWithPathStr[];
32
33
  type: 'create' | 'update' | 'delete';
33
34
  }
34
35
  interface CrudErrorParams extends Omit<SyncedErrorParams, 'source'> {
@@ -13,7 +13,7 @@ type SupabaseSchemaOf<Client extends SupabaseClient> = Client extends SupabaseCl
13
13
  type SupabaseTableOf<Client extends SupabaseClient, SchemaName extends SchemaNameOf<Client>> = DatabaseOf<Client>[SchemaName]['Tables'];
14
14
  type SupabaseViewOf<Client extends SupabaseClient, SchemaName extends SchemaNameOf<Client>> = DatabaseOf<Client>[SchemaName]['Views'];
15
15
  type SupabaseCollectionOf<Client extends SupabaseClient, SchemaName extends SchemaNameOf<Client>> = keyof SupabaseTableOf<Client, IsUnionOfStrings<SchemaName> extends true ? 'public' : SchemaName> | keyof SupabaseViewOf<Client, IsUnionOfStrings<SchemaName> extends true ? 'public' : SchemaName>;
16
- type SupabaseRowOf<Client extends SupabaseClient, Collection extends SupabaseCollectionOf<Client, SchemaName>, SchemaName extends SchemaNameOf<Client>> = SupabaseTableOf<Client, SchemaName>[Collection]['Row'];
16
+ type SupabaseRowOf<Client extends SupabaseClient, Collection extends SupabaseCollectionOf<Client, SchemaName>, SchemaName extends SchemaNameOf<Client>> = SupabaseTableOf<Client, SchemaName>[Collection]['Row'] & SupabaseViewOf<Client, SchemaName>[Collection]['Row'];
17
17
  type SyncedSupabaseConfig<TRemote extends {
18
18
  id: string | number;
19
19
  }, TLocal> = Omit<SyncedCrudPropsBase<TRemote, TLocal>, 'create' | 'update' | 'delete'>;
@@ -44,7 +44,7 @@ interface SyncedSupabaseProps<Client extends SupabaseClient<any, any>, Collectio
44
44
  delete?: (...params: Parameters<Required<SyncedCrudPropsBase<TRemote>>['delete']>) => PromiseLike<PostgrestSingleResponse<TRemote>> | Promise<FunctionsResponse<NoInfer<TRemote>>>;
45
45
  }
46
46
  interface SyncedSupabasePropsWithSelect<Client extends SupabaseClient<any, any>, Collection extends SupabaseCollectionOf<Client, SchemaName>, SchemaName extends SchemaNameOf<Client> = 'public', TOption extends CrudAsOption = 'object', TRemote extends SupabaseRowOf<Client, Collection, SchemaName> = SupabaseRowOf<Client, Collection, SchemaName>, TLocal = TRemote> extends Omit<SyncedSupabaseProps<Client, Collection, SchemaName, TOption, TRemote, TLocal>, 'select'> {
47
- select: (query: PostgrestQueryBuilder<SupabaseSchemaOf<Client>, SupabaseTableOf<Client, SchemaName>[Collection], Collection>) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
47
+ select: (query: PostgrestQueryBuilder<SupabaseSchemaOf<Client>, SupabaseTableOf<Client, SchemaName>[Collection] & SupabaseViewOf<Client, SchemaName>[Collection], Collection>) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
48
48
  }
49
49
  declare function getSyncedSupabaseConfiguration(): SyncedSupabaseConfiguration;
50
50
  declare function configureSyncedSupabase(config: SyncedSupabaseConfiguration): void;
@@ -13,7 +13,7 @@ type SupabaseSchemaOf<Client extends SupabaseClient> = Client extends SupabaseCl
13
13
  type SupabaseTableOf<Client extends SupabaseClient, SchemaName extends SchemaNameOf<Client>> = DatabaseOf<Client>[SchemaName]['Tables'];
14
14
  type SupabaseViewOf<Client extends SupabaseClient, SchemaName extends SchemaNameOf<Client>> = DatabaseOf<Client>[SchemaName]['Views'];
15
15
  type SupabaseCollectionOf<Client extends SupabaseClient, SchemaName extends SchemaNameOf<Client>> = keyof SupabaseTableOf<Client, IsUnionOfStrings<SchemaName> extends true ? 'public' : SchemaName> | keyof SupabaseViewOf<Client, IsUnionOfStrings<SchemaName> extends true ? 'public' : SchemaName>;
16
- type SupabaseRowOf<Client extends SupabaseClient, Collection extends SupabaseCollectionOf<Client, SchemaName>, SchemaName extends SchemaNameOf<Client>> = SupabaseTableOf<Client, SchemaName>[Collection]['Row'];
16
+ type SupabaseRowOf<Client extends SupabaseClient, Collection extends SupabaseCollectionOf<Client, SchemaName>, SchemaName extends SchemaNameOf<Client>> = SupabaseTableOf<Client, SchemaName>[Collection]['Row'] & SupabaseViewOf<Client, SchemaName>[Collection]['Row'];
17
17
  type SyncedSupabaseConfig<TRemote extends {
18
18
  id: string | number;
19
19
  }, TLocal> = Omit<SyncedCrudPropsBase<TRemote, TLocal>, 'create' | 'update' | 'delete'>;
@@ -44,7 +44,7 @@ interface SyncedSupabaseProps<Client extends SupabaseClient<any, any>, Collectio
44
44
  delete?: (...params: Parameters<Required<SyncedCrudPropsBase<TRemote>>['delete']>) => PromiseLike<PostgrestSingleResponse<TRemote>> | Promise<FunctionsResponse<NoInfer<TRemote>>>;
45
45
  }
46
46
  interface SyncedSupabasePropsWithSelect<Client extends SupabaseClient<any, any>, Collection extends SupabaseCollectionOf<Client, SchemaName>, SchemaName extends SchemaNameOf<Client> = 'public', TOption extends CrudAsOption = 'object', TRemote extends SupabaseRowOf<Client, Collection, SchemaName> = SupabaseRowOf<Client, Collection, SchemaName>, TLocal = TRemote> extends Omit<SyncedSupabaseProps<Client, Collection, SchemaName, TOption, TRemote, TLocal>, 'select'> {
47
- select: (query: PostgrestQueryBuilder<SupabaseSchemaOf<Client>, SupabaseTableOf<Client, SchemaName>[Collection], Collection>) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
47
+ select: (query: PostgrestQueryBuilder<SupabaseSchemaOf<Client>, SupabaseTableOf<Client, SchemaName>[Collection] & SupabaseViewOf<Client, SchemaName>[Collection], Collection>) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
48
48
  }
49
49
  declare function getSyncedSupabaseConfiguration(): SyncedSupabaseConfiguration;
50
50
  declare function configureSyncedSupabase(config: SyncedSupabaseConfiguration): void;
package/sync.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { MMKVConfiguration } from 'react-native-mmkv';
2
2
  import { AsyncStorageStatic } from '@react-native-async-storage/async-storage';
3
- import { ClassConstructor, NodeInfo, ObservableParam, GetMode, SetParams, UpdateSetFn, UpdateFn, LinkedOptions, RetryOptions, Change, Observable, ObservableSyncState, TypeAtPath, RecordValue, ArrayValue, WaitForSet } from '@legendapp/state';
3
+ import { ClassConstructor, NodeInfo, ObservableParam, GetMode, SetParams, ChangeWithPathStr, UpdateSetFn, UpdateFn, LinkedOptions, RetryOptions, Change, Observable, ObservableSyncState, TypeAtPath, RecordValue, ArrayValue, WaitForSet } from '@legendapp/state';
4
4
  import { SyncedOptionsGlobal as SyncedOptionsGlobal$1 } from '@legendapp/state/sync';
5
5
 
6
6
  interface PersistOptions<T = any> {
@@ -35,7 +35,8 @@ interface SyncedGetParams<T> extends SyncedGetSetBaseParams<T> {
35
35
  onError: (error: Error, params: SyncedErrorParams) => void;
36
36
  options: SyncedOptions;
37
37
  }
38
- interface SyncedSetParams<T> extends Pick<SetParams<T>, 'changes' | 'value'>, SyncedGetSetBaseParams<T> {
38
+ interface SyncedSetParams<T> extends Omit<Pick<SetParams<T>, 'changes' | 'value'>, 'changes'>, SyncedGetSetBaseParams<T> {
39
+ changes: ChangeWithPathStr[];
39
40
  update: UpdateSetFn<T>;
40
41
  onError: (error: Error, params: SyncedErrorParams) => void;
41
42
  }
package/sync.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { MMKVConfiguration } from 'react-native-mmkv';
2
2
  import { AsyncStorageStatic } from '@react-native-async-storage/async-storage';
3
- import { ClassConstructor, NodeInfo, ObservableParam, GetMode, SetParams, UpdateSetFn, UpdateFn, LinkedOptions, RetryOptions, Change, Observable, ObservableSyncState, TypeAtPath, RecordValue, ArrayValue, WaitForSet } from '@legendapp/state';
3
+ import { ClassConstructor, NodeInfo, ObservableParam, GetMode, SetParams, ChangeWithPathStr, UpdateSetFn, UpdateFn, LinkedOptions, RetryOptions, Change, Observable, ObservableSyncState, TypeAtPath, RecordValue, ArrayValue, WaitForSet } from '@legendapp/state';
4
4
  import { SyncedOptionsGlobal as SyncedOptionsGlobal$1 } from '@legendapp/state/sync';
5
5
 
6
6
  interface PersistOptions<T = any> {
@@ -35,7 +35,8 @@ interface SyncedGetParams<T> extends SyncedGetSetBaseParams<T> {
35
35
  onError: (error: Error, params: SyncedErrorParams) => void;
36
36
  options: SyncedOptions;
37
37
  }
38
- interface SyncedSetParams<T> extends Pick<SetParams<T>, 'changes' | 'value'>, SyncedGetSetBaseParams<T> {
38
+ interface SyncedSetParams<T> extends Omit<Pick<SetParams<T>, 'changes' | 'value'>, 'changes'>, SyncedGetSetBaseParams<T> {
39
+ changes: ChangeWithPathStr[];
39
40
  update: UpdateSetFn<T>;
40
41
  onError: (error: Error, params: SyncedErrorParams) => void;
41
42
  }
package/sync.js CHANGED
@@ -542,7 +542,7 @@ async function prepChangeRemote(queuedChange) {
542
542
  );
543
543
  promisesTransform.push(
544
544
  doInOrder(promiseTransformRemote, ({ value: valueTransformed, path: pathTransformed }) => {
545
- var _a;
545
+ var _a, _b, _c, _d;
546
546
  if (!localState.pendingChanges) {
547
547
  localState.pendingChanges = {};
548
548
  }
@@ -559,18 +559,27 @@ async function prepChangeRemote(queuedChange) {
559
559
  pathTypesChild,
560
560
  valueAtPath
561
561
  );
562
+ if ((_b = localState.pendingClears) == null ? void 0 : _b[pathParent]) {
563
+ delete localState.pendingClears[pathParent];
564
+ }
562
565
  }
563
566
  }
564
567
  if (!found2) {
565
568
  for (const key in localState.pendingChanges) {
566
569
  if (key !== pathStr && key.startsWith(pathStr)) {
567
570
  delete localState.pendingChanges[key];
571
+ if ((_c = localState.pendingClears) == null ? void 0 : _c[key]) {
572
+ delete localState.pendingClears[key];
573
+ }
568
574
  }
569
575
  }
570
576
  if (!localState.pendingChanges[pathStr]) {
571
577
  localState.pendingChanges[pathStr] = { p: prevAtPath != null ? prevAtPath : null, t: pathTypes };
572
578
  }
573
579
  localState.pendingChanges[pathStr].v = valueAtPath;
580
+ if ((_d = localState.pendingClears) == null ? void 0 : _d[pathStr]) {
581
+ delete localState.pendingClears[pathStr];
582
+ }
574
583
  }
575
584
  changesRemote.push({
576
585
  path: pathTransformed,
@@ -634,7 +643,7 @@ async function doChangeRemote(changeInfo) {
634
643
  const shouldSaveMetadata = persist == null ? void 0 : persist.retrySync;
635
644
  const saveLocal = !!(persist == null ? void 0 : persist.name);
636
645
  if (changesRemote.length > 0) {
637
- if (!syncState2.isLoaded.peek()) {
646
+ if ((syncOptions.get || syncOptions.subscribe) && !syncState2.isLoaded.peek()) {
638
647
  await state.when(syncState2.isLoaded);
639
648
  const pending = localState.pendingChanges;
640
649
  if (pending) {
@@ -656,6 +665,12 @@ async function doChangeRemote(changeInfo) {
656
665
  if (transformSave) {
657
666
  value = transformSave(value);
658
667
  }
668
+ const setGeneration = localState.pendingSetGeneration;
669
+ const pendingSetsSinceClear = localState.pendingSetsSinceClear || 0;
670
+ const hadPendingSets = setGeneration !== void 0 ? pendingSetsSinceClear > 0 : (state$.numPendingSets.peek() || 0) > 0;
671
+ if (setGeneration !== void 0) {
672
+ localState.pendingSetsSinceClear = pendingSetsSinceClear + 1;
673
+ }
659
674
  state$.numPendingSets.set((v) => (v || 0) + 1);
660
675
  state$.isSetting.set(true);
661
676
  const beforeSetParams = {
@@ -722,26 +737,63 @@ async function doChangeRemote(changeInfo) {
722
737
  }
723
738
  if (!didError || (updateResult == null ? void 0 : updateResult.changes)) {
724
739
  const { value: updateValue, changes: updateChanges = changesRemote } = updateResult || {};
725
- const pathStrs = Array.from(
726
- new Set(updateChanges.map((change) => change.pathStr))
727
- );
740
+ const changesWithPath = updateChanges;
741
+ const pathStrs = Array.from(new Set(changesWithPath.map((change) => change.pathStr)));
728
742
  if (pathStrs.length > 0) {
729
743
  let transformedChanges = void 0;
730
744
  const metadata = {};
731
- if (saveLocal) {
732
- const pendingMetadata = (_b = pluginPersist.getMetadata(table, configLocal)) == null ? void 0 : _b.pending;
733
- const pending = localState.pendingChanges;
734
- for (let i = 0; i < pathStrs.length; i++) {
735
- const pathStr = pathStrs[i];
736
- if (pendingMetadata == null ? void 0 : pendingMetadata[pathStr]) {
737
- delete pendingMetadata[pathStr];
738
- metadata.pending = pendingMetadata;
745
+ const pending = localState.pendingChanges;
746
+ const pendingToKeep = /* @__PURE__ */ new Set();
747
+ if (pending) {
748
+ const changesByPath = /* @__PURE__ */ new Map();
749
+ for (let i = 0; i < changesWithPath.length; i++) {
750
+ const change = changesWithPath[i];
751
+ changesByPath.set(change.pathStr, change);
752
+ }
753
+ for (const key in pending) {
754
+ const pendingEntry = pending[key];
755
+ if (!pendingEntry) {
756
+ continue;
739
757
  }
740
- if (pending == null ? void 0 : pending[pathStr]) {
741
- delete pending[pathStr];
758
+ const change = changesByPath.get(key);
759
+ if (!change || !deepEqual(pendingEntry.v, change.valueAtPath)) {
760
+ pendingToKeep.add(key);
742
761
  }
743
762
  }
744
763
  }
764
+ const pendingToOverlay = new Set(pendingToKeep);
765
+ const pendingClears = localState.pendingClears;
766
+ if (pendingClears) {
767
+ for (const key in pendingClears) {
768
+ pendingToOverlay.add(key);
769
+ }
770
+ }
771
+ if (hadPendingSets) {
772
+ for (let i = 0; i < changesWithPath.length; i++) {
773
+ pendingToOverlay.add(changesWithPath[i].pathStr);
774
+ }
775
+ }
776
+ const pendingMetadata = saveLocal ? (_b = pluginPersist.getMetadata(table, configLocal)) == null ? void 0 : _b.pending : void 0;
777
+ const shouldDeferPendingClear = (state$.numPendingSets.peek() || 0) > 1;
778
+ for (let i = 0; i < pathStrs.length; i++) {
779
+ const pathStr = pathStrs[i];
780
+ if (pendingToKeep.has(pathStr)) {
781
+ continue;
782
+ }
783
+ if (shouldDeferPendingClear && (pending == null ? void 0 : pending[pathStr])) {
784
+ if (!localState.pendingClears) {
785
+ localState.pendingClears = {};
786
+ }
787
+ localState.pendingClears[pathStr] = pending[pathStr];
788
+ }
789
+ if (pendingMetadata == null ? void 0 : pendingMetadata[pathStr]) {
790
+ delete pendingMetadata[pathStr];
791
+ metadata.pending = pendingMetadata;
792
+ }
793
+ if (pending == null ? void 0 : pending[pathStr]) {
794
+ delete pending[pathStr];
795
+ }
796
+ }
745
797
  if (updateValue && !state.isEmpty(updateValue)) {
746
798
  transformedChanges = transformLoadData(updateValue, syncOptions, false, "set");
747
799
  }
@@ -749,7 +801,48 @@ async function doChangeRemote(changeInfo) {
749
801
  if (state.isPromise(transformedChanges)) {
750
802
  transformedChanges = await transformedChanges;
751
803
  }
752
- onChangeRemote2(() => state.mergeIntoObservable(obs$, transformedChanges));
804
+ if (pendingToOverlay.size === 0) {
805
+ onChangeRemote2(() => state.mergeIntoObservable(obs$, transformedChanges));
806
+ } else if (!pendingToOverlay.has("")) {
807
+ let updatePatch = transformedChanges;
808
+ if (typeof updatePatch === "object" && updatePatch !== null) {
809
+ updatePatch = clone2(updatePatch);
810
+ const currentValue = obs$.peek();
811
+ for (const pathStr of pendingToOverlay) {
812
+ if (!pathStr) {
813
+ continue;
814
+ }
815
+ const pendingEntry = (pending == null ? void 0 : pending[pathStr]) || (pendingClears == null ? void 0 : pendingClears[pathStr]);
816
+ if (!pendingEntry) {
817
+ continue;
818
+ }
819
+ const path = pathStr.split("/").filter((p) => p);
820
+ const currentAtPath = getValueAtPath(currentValue, path);
821
+ updatePatch = state.setAtPath(updatePatch, path, pendingEntry.t, currentAtPath);
822
+ }
823
+ if (hadPendingSets) {
824
+ for (let i = 0; i < changesWithPath.length; i++) {
825
+ const change = changesWithPath[i];
826
+ if (!change.pathStr || !pendingToOverlay.has(change.pathStr)) {
827
+ continue;
828
+ }
829
+ const currentAtPath = getValueAtPath(
830
+ currentValue,
831
+ change.path
832
+ );
833
+ updatePatch = state.setAtPath(
834
+ updatePatch,
835
+ change.path,
836
+ change.pathTypes,
837
+ currentAtPath
838
+ );
839
+ }
840
+ }
841
+ }
842
+ if (updatePatch !== void 0) {
843
+ onChangeRemote2(() => state.mergeIntoObservable(obs$, updatePatch));
844
+ }
845
+ }
753
846
  }
754
847
  if (saveLocal) {
755
848
  if (shouldSaveMetadata && !state.isEmpty(metadata)) {
@@ -758,7 +851,18 @@ async function doChangeRemote(changeInfo) {
758
851
  }
759
852
  }
760
853
  state$.numPendingSets.set((v) => v - 1);
761
- state$.isSetting.set(state$.numPendingSets.peek() > 0);
854
+ const remainingSets = state$.numPendingSets.peek() || 0;
855
+ if (setGeneration !== void 0 && localState.pendingSetGeneration === setGeneration) {
856
+ localState.pendingSetsSinceClear = (localState.pendingSetsSinceClear || 1) - 1;
857
+ }
858
+ if (!remainingSets) {
859
+ if (localState.pendingSetGeneration !== void 0 && !localState.pendingSetsSinceClear) {
860
+ localState.pendingSetGeneration = void 0;
861
+ localState.pendingSetsSinceClear = void 0;
862
+ }
863
+ localState.pendingClears = void 0;
864
+ }
865
+ state$.isSetting.set(remainingSets > 0);
762
866
  onAfterSet == null ? void 0 : onAfterSet();
763
867
  }
764
868
  }
@@ -893,10 +997,18 @@ function syncObservable(obs$, syncOptionsOrSynced) {
893
997
  observableSyncConfiguration,
894
998
  removeNullUndefined(syncOptions || {})
895
999
  );
896
- const localState = {};
897
- let sync;
898
1000
  const syncState$ = state.syncState(obs$);
899
1001
  const syncStateValue = getNodeValue(getNode(syncState$));
1002
+ const localState = {};
1003
+ let sync;
1004
+ const resetPendingState = () => {
1005
+ var _a;
1006
+ localState.pendingChanges = {};
1007
+ localState.pendingClears = void 0;
1008
+ const hasPendingSets = (syncStateValue.numPendingSets || 0) > 0;
1009
+ localState.pendingSetGeneration = hasPendingSets ? ((_a = localState.pendingSetGeneration) != null ? _a : 0) + 1 : void 0;
1010
+ localState.pendingSetsSinceClear = hasPendingSets ? 0 : void 0;
1011
+ };
900
1012
  allSyncStates.set(syncState$, node);
901
1013
  syncStateValue.getPendingChanges = () => localState.pendingChanges;
902
1014
  let lastErrorHandled;
@@ -1087,7 +1199,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
1087
1199
  onChange(params);
1088
1200
  if (!syncState$.isLoaded.peek()) {
1089
1201
  syncState$.assign({
1090
- isLoaded: syncStateValue.numPendingRemoteLoads < 1,
1202
+ isLoaded: (syncStateValue.numPendingRemoteLoads || 0) < 1,
1091
1203
  error: void 0,
1092
1204
  isGetting: syncStateValue.numPendingGets > 0
1093
1205
  });
@@ -1145,7 +1257,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
1145
1257
  lastSync,
1146
1258
  pendingChanges: pending && !state.isEmpty(pending) ? pending : void 0,
1147
1259
  clearPendingChanges: async () => {
1148
- localState.pendingChanges = {};
1260
+ resetPendingState();
1149
1261
  await updateMetadataImmediate(obs$, localState, syncState$, syncOptions, {
1150
1262
  pending: localState.pendingChanges
1151
1263
  });
@@ -1232,6 +1344,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
1232
1344
  if (metadata) {
1233
1345
  Object.assign(metadata, { lastSync: void 0, pending: void 0 });
1234
1346
  }
1347
+ resetPendingState();
1235
1348
  const newState = {
1236
1349
  isPersistEnabled: false,
1237
1350
  isSyncEnabled: false,
@@ -1253,7 +1366,6 @@ function syncObservable(obs$, syncOptionsOrSynced) {
1253
1366
  var _a;
1254
1367
  obs$.set((_a = syncOptions.initial) != null ? _a : void 0);
1255
1368
  });
1256
- syncState$.isLoaded.set(false);
1257
1369
  syncStateValue.isPersistEnabled = wasPersistEnabled;
1258
1370
  syncStateValue.isSyncEnabled = wasSyncEnabled;
1259
1371
  node.dirtyFn = sync;
package/sync.mjs CHANGED
@@ -540,7 +540,7 @@ async function prepChangeRemote(queuedChange) {
540
540
  );
541
541
  promisesTransform.push(
542
542
  doInOrder(promiseTransformRemote, ({ value: valueTransformed, path: pathTransformed }) => {
543
- var _a;
543
+ var _a, _b, _c, _d;
544
544
  if (!localState.pendingChanges) {
545
545
  localState.pendingChanges = {};
546
546
  }
@@ -557,18 +557,27 @@ async function prepChangeRemote(queuedChange) {
557
557
  pathTypesChild,
558
558
  valueAtPath
559
559
  );
560
+ if ((_b = localState.pendingClears) == null ? void 0 : _b[pathParent]) {
561
+ delete localState.pendingClears[pathParent];
562
+ }
560
563
  }
561
564
  }
562
565
  if (!found2) {
563
566
  for (const key in localState.pendingChanges) {
564
567
  if (key !== pathStr && key.startsWith(pathStr)) {
565
568
  delete localState.pendingChanges[key];
569
+ if ((_c = localState.pendingClears) == null ? void 0 : _c[key]) {
570
+ delete localState.pendingClears[key];
571
+ }
566
572
  }
567
573
  }
568
574
  if (!localState.pendingChanges[pathStr]) {
569
575
  localState.pendingChanges[pathStr] = { p: prevAtPath != null ? prevAtPath : null, t: pathTypes };
570
576
  }
571
577
  localState.pendingChanges[pathStr].v = valueAtPath;
578
+ if ((_d = localState.pendingClears) == null ? void 0 : _d[pathStr]) {
579
+ delete localState.pendingClears[pathStr];
580
+ }
572
581
  }
573
582
  changesRemote.push({
574
583
  path: pathTransformed,
@@ -632,7 +641,7 @@ async function doChangeRemote(changeInfo) {
632
641
  const shouldSaveMetadata = persist == null ? void 0 : persist.retrySync;
633
642
  const saveLocal = !!(persist == null ? void 0 : persist.name);
634
643
  if (changesRemote.length > 0) {
635
- if (!syncState2.isLoaded.peek()) {
644
+ if ((syncOptions.get || syncOptions.subscribe) && !syncState2.isLoaded.peek()) {
636
645
  await when(syncState2.isLoaded);
637
646
  const pending = localState.pendingChanges;
638
647
  if (pending) {
@@ -654,6 +663,12 @@ async function doChangeRemote(changeInfo) {
654
663
  if (transformSave) {
655
664
  value = transformSave(value);
656
665
  }
666
+ const setGeneration = localState.pendingSetGeneration;
667
+ const pendingSetsSinceClear = localState.pendingSetsSinceClear || 0;
668
+ const hadPendingSets = setGeneration !== void 0 ? pendingSetsSinceClear > 0 : (state$.numPendingSets.peek() || 0) > 0;
669
+ if (setGeneration !== void 0) {
670
+ localState.pendingSetsSinceClear = pendingSetsSinceClear + 1;
671
+ }
657
672
  state$.numPendingSets.set((v) => (v || 0) + 1);
658
673
  state$.isSetting.set(true);
659
674
  const beforeSetParams = {
@@ -720,26 +735,63 @@ async function doChangeRemote(changeInfo) {
720
735
  }
721
736
  if (!didError || (updateResult == null ? void 0 : updateResult.changes)) {
722
737
  const { value: updateValue, changes: updateChanges = changesRemote } = updateResult || {};
723
- const pathStrs = Array.from(
724
- new Set(updateChanges.map((change) => change.pathStr))
725
- );
738
+ const changesWithPath = updateChanges;
739
+ const pathStrs = Array.from(new Set(changesWithPath.map((change) => change.pathStr)));
726
740
  if (pathStrs.length > 0) {
727
741
  let transformedChanges = void 0;
728
742
  const metadata = {};
729
- if (saveLocal) {
730
- const pendingMetadata = (_b = pluginPersist.getMetadata(table, configLocal)) == null ? void 0 : _b.pending;
731
- const pending = localState.pendingChanges;
732
- for (let i = 0; i < pathStrs.length; i++) {
733
- const pathStr = pathStrs[i];
734
- if (pendingMetadata == null ? void 0 : pendingMetadata[pathStr]) {
735
- delete pendingMetadata[pathStr];
736
- metadata.pending = pendingMetadata;
743
+ const pending = localState.pendingChanges;
744
+ const pendingToKeep = /* @__PURE__ */ new Set();
745
+ if (pending) {
746
+ const changesByPath = /* @__PURE__ */ new Map();
747
+ for (let i = 0; i < changesWithPath.length; i++) {
748
+ const change = changesWithPath[i];
749
+ changesByPath.set(change.pathStr, change);
750
+ }
751
+ for (const key in pending) {
752
+ const pendingEntry = pending[key];
753
+ if (!pendingEntry) {
754
+ continue;
737
755
  }
738
- if (pending == null ? void 0 : pending[pathStr]) {
739
- delete pending[pathStr];
756
+ const change = changesByPath.get(key);
757
+ if (!change || !deepEqual(pendingEntry.v, change.valueAtPath)) {
758
+ pendingToKeep.add(key);
740
759
  }
741
760
  }
742
761
  }
762
+ const pendingToOverlay = new Set(pendingToKeep);
763
+ const pendingClears = localState.pendingClears;
764
+ if (pendingClears) {
765
+ for (const key in pendingClears) {
766
+ pendingToOverlay.add(key);
767
+ }
768
+ }
769
+ if (hadPendingSets) {
770
+ for (let i = 0; i < changesWithPath.length; i++) {
771
+ pendingToOverlay.add(changesWithPath[i].pathStr);
772
+ }
773
+ }
774
+ const pendingMetadata = saveLocal ? (_b = pluginPersist.getMetadata(table, configLocal)) == null ? void 0 : _b.pending : void 0;
775
+ const shouldDeferPendingClear = (state$.numPendingSets.peek() || 0) > 1;
776
+ for (let i = 0; i < pathStrs.length; i++) {
777
+ const pathStr = pathStrs[i];
778
+ if (pendingToKeep.has(pathStr)) {
779
+ continue;
780
+ }
781
+ if (shouldDeferPendingClear && (pending == null ? void 0 : pending[pathStr])) {
782
+ if (!localState.pendingClears) {
783
+ localState.pendingClears = {};
784
+ }
785
+ localState.pendingClears[pathStr] = pending[pathStr];
786
+ }
787
+ if (pendingMetadata == null ? void 0 : pendingMetadata[pathStr]) {
788
+ delete pendingMetadata[pathStr];
789
+ metadata.pending = pendingMetadata;
790
+ }
791
+ if (pending == null ? void 0 : pending[pathStr]) {
792
+ delete pending[pathStr];
793
+ }
794
+ }
743
795
  if (updateValue && !isEmpty(updateValue)) {
744
796
  transformedChanges = transformLoadData(updateValue, syncOptions, false, "set");
745
797
  }
@@ -747,7 +799,48 @@ async function doChangeRemote(changeInfo) {
747
799
  if (isPromise$1(transformedChanges)) {
748
800
  transformedChanges = await transformedChanges;
749
801
  }
750
- onChangeRemote2(() => mergeIntoObservable(obs$, transformedChanges));
802
+ if (pendingToOverlay.size === 0) {
803
+ onChangeRemote2(() => mergeIntoObservable(obs$, transformedChanges));
804
+ } else if (!pendingToOverlay.has("")) {
805
+ let updatePatch = transformedChanges;
806
+ if (typeof updatePatch === "object" && updatePatch !== null) {
807
+ updatePatch = clone2(updatePatch);
808
+ const currentValue = obs$.peek();
809
+ for (const pathStr of pendingToOverlay) {
810
+ if (!pathStr) {
811
+ continue;
812
+ }
813
+ const pendingEntry = (pending == null ? void 0 : pending[pathStr]) || (pendingClears == null ? void 0 : pendingClears[pathStr]);
814
+ if (!pendingEntry) {
815
+ continue;
816
+ }
817
+ const path = pathStr.split("/").filter((p) => p);
818
+ const currentAtPath = getValueAtPath(currentValue, path);
819
+ updatePatch = setAtPath(updatePatch, path, pendingEntry.t, currentAtPath);
820
+ }
821
+ if (hadPendingSets) {
822
+ for (let i = 0; i < changesWithPath.length; i++) {
823
+ const change = changesWithPath[i];
824
+ if (!change.pathStr || !pendingToOverlay.has(change.pathStr)) {
825
+ continue;
826
+ }
827
+ const currentAtPath = getValueAtPath(
828
+ currentValue,
829
+ change.path
830
+ );
831
+ updatePatch = setAtPath(
832
+ updatePatch,
833
+ change.path,
834
+ change.pathTypes,
835
+ currentAtPath
836
+ );
837
+ }
838
+ }
839
+ }
840
+ if (updatePatch !== void 0) {
841
+ onChangeRemote2(() => mergeIntoObservable(obs$, updatePatch));
842
+ }
843
+ }
751
844
  }
752
845
  if (saveLocal) {
753
846
  if (shouldSaveMetadata && !isEmpty(metadata)) {
@@ -756,7 +849,18 @@ async function doChangeRemote(changeInfo) {
756
849
  }
757
850
  }
758
851
  state$.numPendingSets.set((v) => v - 1);
759
- state$.isSetting.set(state$.numPendingSets.peek() > 0);
852
+ const remainingSets = state$.numPendingSets.peek() || 0;
853
+ if (setGeneration !== void 0 && localState.pendingSetGeneration === setGeneration) {
854
+ localState.pendingSetsSinceClear = (localState.pendingSetsSinceClear || 1) - 1;
855
+ }
856
+ if (!remainingSets) {
857
+ if (localState.pendingSetGeneration !== void 0 && !localState.pendingSetsSinceClear) {
858
+ localState.pendingSetGeneration = void 0;
859
+ localState.pendingSetsSinceClear = void 0;
860
+ }
861
+ localState.pendingClears = void 0;
862
+ }
863
+ state$.isSetting.set(remainingSets > 0);
760
864
  onAfterSet == null ? void 0 : onAfterSet();
761
865
  }
762
866
  }
@@ -891,10 +995,18 @@ function syncObservable(obs$, syncOptionsOrSynced) {
891
995
  observableSyncConfiguration,
892
996
  removeNullUndefined(syncOptions || {})
893
997
  );
894
- const localState = {};
895
- let sync;
896
998
  const syncState$ = syncState(obs$);
897
999
  const syncStateValue = getNodeValue(getNode(syncState$));
1000
+ const localState = {};
1001
+ let sync;
1002
+ const resetPendingState = () => {
1003
+ var _a;
1004
+ localState.pendingChanges = {};
1005
+ localState.pendingClears = void 0;
1006
+ const hasPendingSets = (syncStateValue.numPendingSets || 0) > 0;
1007
+ localState.pendingSetGeneration = hasPendingSets ? ((_a = localState.pendingSetGeneration) != null ? _a : 0) + 1 : void 0;
1008
+ localState.pendingSetsSinceClear = hasPendingSets ? 0 : void 0;
1009
+ };
898
1010
  allSyncStates.set(syncState$, node);
899
1011
  syncStateValue.getPendingChanges = () => localState.pendingChanges;
900
1012
  let lastErrorHandled;
@@ -1085,7 +1197,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
1085
1197
  onChange(params);
1086
1198
  if (!syncState$.isLoaded.peek()) {
1087
1199
  syncState$.assign({
1088
- isLoaded: syncStateValue.numPendingRemoteLoads < 1,
1200
+ isLoaded: (syncStateValue.numPendingRemoteLoads || 0) < 1,
1089
1201
  error: void 0,
1090
1202
  isGetting: syncStateValue.numPendingGets > 0
1091
1203
  });
@@ -1143,7 +1255,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
1143
1255
  lastSync,
1144
1256
  pendingChanges: pending && !isEmpty(pending) ? pending : void 0,
1145
1257
  clearPendingChanges: async () => {
1146
- localState.pendingChanges = {};
1258
+ resetPendingState();
1147
1259
  await updateMetadataImmediate(obs$, localState, syncState$, syncOptions, {
1148
1260
  pending: localState.pendingChanges
1149
1261
  });
@@ -1230,6 +1342,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
1230
1342
  if (metadata) {
1231
1343
  Object.assign(metadata, { lastSync: void 0, pending: void 0 });
1232
1344
  }
1345
+ resetPendingState();
1233
1346
  const newState = {
1234
1347
  isPersistEnabled: false,
1235
1348
  isSyncEnabled: false,
@@ -1251,7 +1364,6 @@ function syncObservable(obs$, syncOptionsOrSynced) {
1251
1364
  var _a;
1252
1365
  obs$.set((_a = syncOptions.initial) != null ? _a : void 0);
1253
1366
  });
1254
- syncState$.isLoaded.set(false);
1255
1367
  syncStateValue.isPersistEnabled = wasPersistEnabled;
1256
1368
  syncStateValue.isSyncEnabled = wasSyncEnabled;
1257
1369
  node.dirtyFn = sync;