@legendapp/state 2.2.0-next.74 → 2.2.0-next.76
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/helpers/time.d.ts +2 -2
- package/index.d.ts +1 -1
- package/index.js +82 -31
- package/index.js.map +1 -1
- package/index.mjs +81 -32
- package/index.mjs.map +1 -1
- package/package.json +16 -1
- package/persist.js +122 -129
- package/persist.js.map +1 -1
- package/persist.mjs +122 -129
- package/persist.mjs.map +1 -1
- package/react.js +5 -5
- package/react.js.map +1 -1
- package/react.mjs +6 -6
- package/react.mjs.map +1 -1
- package/src/ObservableObject.ts +34 -15
- package/src/batching.ts +9 -3
- package/src/computed.ts +4 -2
- package/src/globals.ts +17 -7
- package/src/helpers.ts +3 -3
- package/src/history/undoRedo.ts +111 -0
- package/src/is.ts +7 -0
- package/src/observableInterfaces.ts +6 -5
- package/src/observableTypes.ts +5 -0
- package/src/observe.ts +1 -1
- package/src/react/For.tsx +6 -6
- package/src/sync/activateSyncedNode.ts +9 -25
- package/src/sync/syncHelpers.ts +53 -12
- package/src/sync/syncObservable.ts +117 -101
- package/src/sync-plugins/crud.ts +384 -0
- package/src/sync-plugins/fetch.ts +57 -27
- package/src/sync-plugins/keel.ts +447 -0
- package/src/sync-plugins/supabase.ts +225 -0
- package/src/syncTypes.ts +12 -6
- package/src/when.ts +6 -1
- package/sync-plugins/crud.d.ts +40 -0
- package/sync-plugins/crud.js +275 -0
- package/sync-plugins/crud.js.map +1 -0
- package/sync-plugins/crud.mjs +271 -0
- package/sync-plugins/crud.mjs.map +1 -0
- package/sync-plugins/fetch.d.ts +8 -7
- package/sync-plugins/fetch.js +34 -12
- package/sync-plugins/fetch.js.map +1 -1
- package/sync-plugins/fetch.mjs +35 -13
- package/sync-plugins/fetch.mjs.map +1 -1
- package/sync-plugins/keel.d.ts +91 -0
- package/sync-plugins/keel.js +278 -0
- package/sync-plugins/keel.js.map +1 -0
- package/sync-plugins/keel.mjs +274 -0
- package/sync-plugins/keel.mjs.map +1 -0
- package/sync-plugins/supabase.d.ts +32 -0
- package/sync-plugins/supabase.js +134 -0
- package/sync-plugins/supabase.js.map +1 -0
- package/sync-plugins/supabase.mjs +131 -0
- package/sync-plugins/supabase.mjs.map +1 -0
- package/sync.d.ts +1 -0
- package/sync.js +157 -127
- package/sync.js.map +1 -1
- package/sync.mjs +156 -129
- package/sync.mjs.map +1 -1
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
GetMode,
|
|
3
2
|
NodeValue,
|
|
4
3
|
Observable,
|
|
5
|
-
ObservableOnChangeParams,
|
|
6
4
|
ObservablePersistState,
|
|
7
5
|
ObservableSyncFunctions,
|
|
8
6
|
ObservableSyncGetParams,
|
|
@@ -11,7 +9,7 @@ import type {
|
|
|
11
9
|
SyncedSetParams,
|
|
12
10
|
UpdateFn,
|
|
13
11
|
} from '@legendapp/state';
|
|
14
|
-
import { internal, isFunction, isPromise, mergeIntoObservable,
|
|
12
|
+
import { internal, isFunction, isPromise, mergeIntoObservable, whenReady } from '@legendapp/state';
|
|
15
13
|
import { syncObservable } from './syncObservable';
|
|
16
14
|
const { getProxy, globalState, runWithRetry, symbolLinked, setNodeValue, getNodeValue } = internal;
|
|
17
15
|
|
|
@@ -20,7 +18,7 @@ export function enableActivateSyncedNode() {
|
|
|
20
18
|
const obs$ = getProxy(node);
|
|
21
19
|
if (node.activationState) {
|
|
22
20
|
// If it is a Synced
|
|
23
|
-
const { get, initial, set
|
|
21
|
+
const { get, initial, set } = node.activationState!;
|
|
24
22
|
|
|
25
23
|
let onChange: UpdateFn | undefined = undefined;
|
|
26
24
|
const pluginRemote: ObservableSyncFunctions = {};
|
|
@@ -35,18 +33,21 @@ export function enableActivateSyncedNode() {
|
|
|
35
33
|
pluginRemote.get = (params: ObservableSyncGetParams<any>) => {
|
|
36
34
|
onChange = params.onChange;
|
|
37
35
|
const updateLastSync = (lastSync: number) => (params.lastSync = lastSync);
|
|
38
|
-
const setMode = (mode: GetMode) => (params.mode = mode);
|
|
39
36
|
|
|
40
37
|
const existingValue = getNodeValue(node);
|
|
41
38
|
const value = runWithRetry(node, { attemptNum: 0 }, () => {
|
|
42
|
-
|
|
39
|
+
const paramsToGet = {
|
|
43
40
|
value:
|
|
44
41
|
isFunction(existingValue) || existingValue?.[symbolLinked] ? undefined : existingValue,
|
|
45
42
|
lastSync: params.lastSync!,
|
|
46
43
|
updateLastSync,
|
|
47
|
-
|
|
44
|
+
mode: params.mode!,
|
|
48
45
|
refresh,
|
|
49
|
-
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const ret = get!(paramsToGet);
|
|
49
|
+
params.mode = paramsToGet.mode;
|
|
50
|
+
return ret;
|
|
50
51
|
});
|
|
51
52
|
|
|
52
53
|
promiseReturn = value;
|
|
@@ -102,23 +103,6 @@ export function enableActivateSyncedNode() {
|
|
|
102
103
|
// @ts-expect-error TODO fix these types
|
|
103
104
|
syncState = syncObservable(obs$, { ...node.activationState, ...pluginRemote });
|
|
104
105
|
|
|
105
|
-
if (subscribe) {
|
|
106
|
-
when(promiseReturn || true, () => {
|
|
107
|
-
subscribe({
|
|
108
|
-
node,
|
|
109
|
-
update: (params: ObservableOnChangeParams) => {
|
|
110
|
-
if (!onChange) {
|
|
111
|
-
// TODO: Make this message better
|
|
112
|
-
console.log('[legend-state] Cannot update immediately before the first return');
|
|
113
|
-
} else {
|
|
114
|
-
onChange(params);
|
|
115
|
-
}
|
|
116
|
-
},
|
|
117
|
-
refresh,
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
|
|
122
106
|
return { update: onChange!, value: newValue };
|
|
123
107
|
} else {
|
|
124
108
|
// If it is not a Synced
|
package/src/sync/syncHelpers.ts
CHANGED
|
@@ -1,15 +1,56 @@
|
|
|
1
|
-
import { isObject } from '@legendapp/state';
|
|
2
|
-
|
|
3
|
-
export function removeNullUndefined<T extends Record<string, any>>(
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
import { isDate, isNullOrUndefined, isObject } from '@legendapp/state';
|
|
2
|
+
|
|
3
|
+
export function removeNullUndefined<T extends Record<string, any>>(a: T, recursive?: boolean): T {
|
|
4
|
+
const out: T = {} as T;
|
|
5
|
+
Object.keys(a).forEach((key: keyof T) => {
|
|
6
|
+
if (a[key] !== null && a[key] !== undefined) {
|
|
7
|
+
out[key] = recursive && isObject(a[key]) ? removeNullUndefined(a[key]) : a[key];
|
|
8
|
+
}
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
return out;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function diffObjects<T extends Record<string, any>>(obj1: T, obj2: T, deep: boolean = false): Partial<T> {
|
|
15
|
+
const diff: Partial<T> = {};
|
|
16
|
+
if (!obj1) return obj2 || diff;
|
|
17
|
+
if (!obj2) return obj1 || diff;
|
|
18
|
+
|
|
19
|
+
const keys = new Set<keyof T>([...Object.keys(obj1), ...Object.keys(obj2)] as (keyof T)[]);
|
|
20
|
+
|
|
21
|
+
keys.forEach((key) => {
|
|
22
|
+
const o1 = obj1[key];
|
|
23
|
+
const o2 = obj2[key];
|
|
24
|
+
if (deep ? !deepEqual(o1, o2) : o1 !== o2) {
|
|
25
|
+
if (!isDate(o1) || !isDate(o2) || o1.getTime() !== o2.getTime()) {
|
|
26
|
+
diff[key] = o2;
|
|
11
27
|
}
|
|
12
|
-
}
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
return diff;
|
|
32
|
+
}
|
|
33
|
+
export function deepEqual<T extends Record<string, any> = any>(
|
|
34
|
+
a: T,
|
|
35
|
+
b: T,
|
|
36
|
+
ignoreFields?: string[],
|
|
37
|
+
nullVsUndefined?: boolean,
|
|
38
|
+
): boolean {
|
|
39
|
+
if (a === b) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
if (isNullOrUndefined(a) !== isNullOrUndefined(b)) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (nullVsUndefined) {
|
|
47
|
+
a = removeNullUndefined(a, /*recursive*/ true);
|
|
48
|
+
b = removeNullUndefined(b, /*recursive*/ true);
|
|
13
49
|
}
|
|
14
|
-
|
|
50
|
+
|
|
51
|
+
const replacer = ignoreFields
|
|
52
|
+
? (key: string, value: any) => (ignoreFields.includes(key) ? undefined : value)
|
|
53
|
+
: undefined;
|
|
54
|
+
|
|
55
|
+
return JSON.stringify(a, replacer) === JSON.stringify(b, replacer);
|
|
15
56
|
}
|
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
NodeValue,
|
|
6
6
|
Observable,
|
|
7
7
|
ObservableObject,
|
|
8
|
+
ObservableOnChangeParams,
|
|
8
9
|
ObservableParam,
|
|
9
10
|
ObservablePersistPlugin,
|
|
10
11
|
ObservableSyncClass,
|
|
@@ -15,6 +16,7 @@ import type {
|
|
|
15
16
|
Synced,
|
|
16
17
|
SyncedOptions,
|
|
17
18
|
TypeAtPath,
|
|
19
|
+
UpdateFnParams,
|
|
18
20
|
} from '@legendapp/state';
|
|
19
21
|
import {
|
|
20
22
|
beginBatch,
|
|
@@ -538,8 +540,7 @@ async function doChangeLocal(changeInfo: PreppedChangeLocal | undefined) {
|
|
|
538
540
|
|
|
539
541
|
const persist = syncOptions.persist;
|
|
540
542
|
const { table, config: configLocal } = parseLocalConfig(persist!);
|
|
541
|
-
const
|
|
542
|
-
const shouldSaveMetadata = persist && configRemote?.offlineBehavior === 'retry';
|
|
543
|
+
const shouldSaveMetadata = persist?.retrySync;
|
|
543
544
|
|
|
544
545
|
if (saveRemote && shouldSaveMetadata) {
|
|
545
546
|
// First save pending changes before saving local or remote
|
|
@@ -574,9 +575,9 @@ async function doChangeRemote(changeInfo: PreppedChangeRemote | undefined) {
|
|
|
574
575
|
|
|
575
576
|
const persist = syncOptions.persist;
|
|
576
577
|
const { table, config: configLocal } = parseLocalConfig(persist!);
|
|
577
|
-
const {
|
|
578
|
+
const { allowSetIfGetError, onBeforeSet, onSetError, waitForSet, onAfterSet } =
|
|
578
579
|
syncOptions || ({} as SyncedOptions);
|
|
579
|
-
const shouldSaveMetadata = persist
|
|
580
|
+
const shouldSaveMetadata = persist?.retrySync;
|
|
580
581
|
|
|
581
582
|
if (changesRemote.length > 0) {
|
|
582
583
|
// Wait for remote to be ready before saving
|
|
@@ -624,11 +625,11 @@ async function doChangeRemote(changeInfo: PreppedChangeRemote | undefined) {
|
|
|
624
625
|
const pathStrs = Array.from(new Set(changesRemote.map((change) => change.pathStr)));
|
|
625
626
|
const { changes, lastSync } = saved;
|
|
626
627
|
if (pathStrs.length > 0) {
|
|
628
|
+
let transformedChanges: object | undefined = undefined;
|
|
629
|
+
const metadata: PersistMetadata = {};
|
|
627
630
|
if (persist) {
|
|
628
|
-
const metadata: PersistMetadata = {};
|
|
629
631
|
const pendingMetadata = pluginPersist!.getMetadata(table, configLocal)?.pending;
|
|
630
632
|
const pending = localState.pendingChanges;
|
|
631
|
-
let transformedChanges: object | undefined = undefined;
|
|
632
633
|
|
|
633
634
|
for (let i = 0; i < pathStrs.length; i++) {
|
|
634
635
|
const pathStr = pathStrs[i];
|
|
@@ -649,37 +650,39 @@ async function doChangeRemote(changeInfo: PreppedChangeRemote | undefined) {
|
|
|
649
650
|
if (lastSync) {
|
|
650
651
|
metadata.lastSync = lastSync;
|
|
651
652
|
}
|
|
653
|
+
}
|
|
652
654
|
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
655
|
+
// Remote can optionally have data that needs to be merged back into the observable,
|
|
656
|
+
// for example Firebase may update dateModified with the server timestamp
|
|
657
|
+
if (changes && !isEmpty(changes)) {
|
|
658
|
+
transformedChanges = transformLoadData(changes, syncOptions, false);
|
|
659
|
+
}
|
|
658
660
|
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
}
|
|
664
|
-
localState.pendingSaveResults.push(transformedChanges);
|
|
661
|
+
if (localState.numSavesOutstanding > 0) {
|
|
662
|
+
if (transformedChanges) {
|
|
663
|
+
if (!localState.pendingSaveResults) {
|
|
664
|
+
localState.pendingSaveResults = [];
|
|
665
665
|
}
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
666
|
+
localState.pendingSaveResults.push(transformedChanges);
|
|
667
|
+
}
|
|
668
|
+
} else {
|
|
669
|
+
let allChanges = [...(localState.pendingSaveResults || []), transformedChanges].filter(
|
|
670
|
+
(v) => v !== undefined,
|
|
671
|
+
);
|
|
672
|
+
if (allChanges.length > 0) {
|
|
673
|
+
if (allChanges.some((change) => isPromise(change))) {
|
|
674
|
+
allChanges = await Promise.all(allChanges);
|
|
675
675
|
}
|
|
676
|
+
onChangeRemote(() => mergeIntoObservable(obs, ...allChanges));
|
|
677
|
+
}
|
|
676
678
|
|
|
679
|
+
if (persist) {
|
|
677
680
|
if (shouldSaveMetadata && !isEmpty(metadata)) {
|
|
678
681
|
updateMetadata(obs, localState, syncState, syncOptions, metadata);
|
|
679
682
|
}
|
|
680
|
-
|
|
681
|
-
localState.pendingSaveResults = [];
|
|
682
683
|
}
|
|
684
|
+
|
|
685
|
+
localState.pendingSaveResults = [];
|
|
683
686
|
}
|
|
684
687
|
onAfterSet?.();
|
|
685
688
|
}
|
|
@@ -862,6 +865,82 @@ export function syncObservable<T>(
|
|
|
862
865
|
|
|
863
866
|
if (get) {
|
|
864
867
|
const runGet = () => {
|
|
868
|
+
const onChange = async ({ value, mode, lastSync }: UpdateFnParams) => {
|
|
869
|
+
mode = mode || syncOptions.mode || 'set';
|
|
870
|
+
if (value !== undefined) {
|
|
871
|
+
value = transformLoadData(value, syncOptions, true);
|
|
872
|
+
if (isPromise(value)) {
|
|
873
|
+
value = await (value as Promise<T>);
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
const pending = localState.pendingChanges;
|
|
877
|
+
const currentValue = obs$.peek();
|
|
878
|
+
if (pending) {
|
|
879
|
+
let didChangeMetadata = false;
|
|
880
|
+
Object.keys(pending).forEach((key) => {
|
|
881
|
+
const p = key.split('/').filter((p) => p !== '');
|
|
882
|
+
const { v, t } = pending[key];
|
|
883
|
+
|
|
884
|
+
if (t.length === 0 || !value) {
|
|
885
|
+
if (isObject(value) && isObject(v)) {
|
|
886
|
+
Object.assign(value, v);
|
|
887
|
+
} else {
|
|
888
|
+
value = v;
|
|
889
|
+
}
|
|
890
|
+
} else if ((value as any)[p[0]] !== undefined) {
|
|
891
|
+
const curValue = getValueAtPath(currentValue as object, p);
|
|
892
|
+
const newValue = getValueAtPath(value as object, p);
|
|
893
|
+
if (JSON.stringify(curValue) === JSON.stringify(newValue)) {
|
|
894
|
+
delete pending[key];
|
|
895
|
+
didChangeMetadata = true;
|
|
896
|
+
} else {
|
|
897
|
+
(value as any) = setAtPath(
|
|
898
|
+
value as any,
|
|
899
|
+
p,
|
|
900
|
+
t,
|
|
901
|
+
v,
|
|
902
|
+
'merge',
|
|
903
|
+
obs$.peek(),
|
|
904
|
+
(path: string[], value: any) => {
|
|
905
|
+
delete pending[key];
|
|
906
|
+
pending[path.join('/')] = {
|
|
907
|
+
p: null,
|
|
908
|
+
v: value,
|
|
909
|
+
t: t.slice(0, path.length),
|
|
910
|
+
};
|
|
911
|
+
},
|
|
912
|
+
);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
});
|
|
916
|
+
|
|
917
|
+
if (didChangeMetadata) {
|
|
918
|
+
updateMetadata(obs$, localState, syncState, syncOptions, {
|
|
919
|
+
pending,
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
onChangeRemote(() => {
|
|
925
|
+
if (mode === 'assign' && isObject(value)) {
|
|
926
|
+
(obs$ as unknown as Observable<object>).assign(value);
|
|
927
|
+
} else if (mode === 'append' && isArray(value)) {
|
|
928
|
+
(obs$ as unknown as Observable<any[]>).push(...value);
|
|
929
|
+
} else if (mode === 'prepend' && isArray(value)) {
|
|
930
|
+
(obs$ as unknown as Observable<any[]>).splice(0, 0, ...value);
|
|
931
|
+
} else if (mode === 'merge') {
|
|
932
|
+
mergeIntoObservable(obs$, value);
|
|
933
|
+
} else {
|
|
934
|
+
obs$.set(value);
|
|
935
|
+
}
|
|
936
|
+
});
|
|
937
|
+
}
|
|
938
|
+
if (lastSync && syncOptions.persist) {
|
|
939
|
+
updateMetadata(obs$, localState, syncState, syncOptions, {
|
|
940
|
+
lastSync,
|
|
941
|
+
});
|
|
942
|
+
}
|
|
943
|
+
};
|
|
865
944
|
get({
|
|
866
945
|
state: syncState,
|
|
867
946
|
obs: obs$,
|
|
@@ -872,87 +951,24 @@ export function syncObservable<T>(
|
|
|
872
951
|
syncOptions.onGetError?.(error);
|
|
873
952
|
},
|
|
874
953
|
onGet: () => {
|
|
954
|
+
const isFirstLoad = !node.state!.isLoaded.peek();
|
|
875
955
|
node.state!.assign({
|
|
876
956
|
isLoaded: true,
|
|
877
957
|
error: undefined,
|
|
878
958
|
});
|
|
879
|
-
},
|
|
880
|
-
onChange: async ({ value, mode, lastSync }) => {
|
|
881
|
-
mode = mode || syncOptions.mode || 'set';
|
|
882
|
-
if (value !== undefined) {
|
|
883
|
-
value = transformLoadData(value, syncOptions, true);
|
|
884
|
-
if (isPromise(value)) {
|
|
885
|
-
value = await (value as Promise<T>);
|
|
886
|
-
}
|
|
887
959
|
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
if (t.length === 0 || !value) {
|
|
897
|
-
if (isObject(value) && isObject(v)) {
|
|
898
|
-
Object.assign(value, v);
|
|
899
|
-
} else {
|
|
900
|
-
value = v;
|
|
901
|
-
}
|
|
902
|
-
} else if ((value as any)[p[0]] !== undefined) {
|
|
903
|
-
const curValue = getValueAtPath(currentValue as object, p);
|
|
904
|
-
const newValue = getValueAtPath(value as object, p);
|
|
905
|
-
if (JSON.stringify(curValue) === JSON.stringify(newValue)) {
|
|
906
|
-
delete pending[key];
|
|
907
|
-
didChangeMetadata = true;
|
|
908
|
-
} else {
|
|
909
|
-
(value as any) = setAtPath(
|
|
910
|
-
value as any,
|
|
911
|
-
p,
|
|
912
|
-
t,
|
|
913
|
-
v,
|
|
914
|
-
'merge',
|
|
915
|
-
obs$.peek(),
|
|
916
|
-
(path: string[], value: any) => {
|
|
917
|
-
delete pending[key];
|
|
918
|
-
pending[path.join('/')] = {
|
|
919
|
-
p: null,
|
|
920
|
-
v: value,
|
|
921
|
-
t: t.slice(0, path.length),
|
|
922
|
-
};
|
|
923
|
-
},
|
|
924
|
-
);
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
});
|
|
928
|
-
|
|
929
|
-
if (didChangeMetadata) {
|
|
930
|
-
updateMetadata(obs$, localState, syncState, syncOptions, {
|
|
931
|
-
pending,
|
|
932
|
-
});
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
onChangeRemote(() => {
|
|
937
|
-
if (mode === 'assign' && isObject(value)) {
|
|
938
|
-
(obs$ as unknown as Observable<object>).assign(value);
|
|
939
|
-
} else if (mode === 'append' && isArray(value)) {
|
|
940
|
-
(obs$ as unknown as Observable<any[]>).push(...value);
|
|
941
|
-
} else if (mode === 'prepend' && isArray(value)) {
|
|
942
|
-
(obs$ as unknown as Observable<any[]>).splice(0, 0, ...value);
|
|
943
|
-
} else if (mode === 'merge') {
|
|
944
|
-
mergeIntoObservable(obs$, value);
|
|
945
|
-
} else {
|
|
946
|
-
obs$.set(value);
|
|
947
|
-
}
|
|
948
|
-
});
|
|
949
|
-
}
|
|
950
|
-
if (lastSync && syncOptions.persist) {
|
|
951
|
-
updateMetadata(obs$, localState, syncState, syncOptions, {
|
|
952
|
-
lastSync,
|
|
960
|
+
if (isFirstLoad && syncOptions.subscribe) {
|
|
961
|
+
syncOptions.subscribe({
|
|
962
|
+
node,
|
|
963
|
+
update: (params: ObservableOnChangeParams) => {
|
|
964
|
+
params.mode ||= syncOptions.mode || 'merge';
|
|
965
|
+
onChange(params);
|
|
966
|
+
},
|
|
967
|
+
refresh: sync,
|
|
953
968
|
});
|
|
954
969
|
}
|
|
955
970
|
},
|
|
971
|
+
onChange,
|
|
956
972
|
});
|
|
957
973
|
};
|
|
958
974
|
runGet();
|