coaction 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter.d.mts +45 -1
- package/dist/adapter.d.ts +45 -1
- package/dist/adapter.js +108 -13
- package/dist/adapter.mjs +106 -14
- package/dist/index.js +239 -25
- package/dist/index.mjs +239 -25
- package/dist/local.js +239 -25
- package/dist/local.mjs +239 -25
- package/dist/shared.js +239 -25
- package/dist/shared.mjs +239 -25
- package/package.json +1 -1
package/dist/local.mjs
CHANGED
|
@@ -1,30 +1,41 @@
|
|
|
1
1
|
import { apply, create, isDraft } from "mutative";
|
|
2
2
|
import { computed, computed as computed$1, effect, effectScope, endBatch, endBatch as endBatch$1, isComputed, isEffect, isEffectScope, isSignal, signal, signal as signal$1, startBatch, startBatch as startBatch$1, trigger } from "alien-signals";
|
|
3
3
|
//#region packages/core/src/lifecycle.ts
|
|
4
|
-
const
|
|
5
|
-
const
|
|
4
|
+
const storeReadyRuntimeSymbol = Symbol.for("coaction.lifecycle.ready");
|
|
5
|
+
const getStoreReadyRuntime = (store, create = false) => {
|
|
6
|
+
const target = store;
|
|
7
|
+
const existing = target[storeReadyRuntimeSymbol];
|
|
8
|
+
if (existing || !create) return existing;
|
|
9
|
+
const runtime = {
|
|
10
|
+
callbacks: /* @__PURE__ */ new Set(),
|
|
11
|
+
ready: false
|
|
12
|
+
};
|
|
13
|
+
Object.defineProperty(target, storeReadyRuntimeSymbol, {
|
|
14
|
+
configurable: true,
|
|
15
|
+
enumerable: true,
|
|
16
|
+
value: runtime,
|
|
17
|
+
writable: true
|
|
18
|
+
});
|
|
19
|
+
return runtime;
|
|
20
|
+
};
|
|
6
21
|
const onStoreReady = (store, callback) => {
|
|
7
|
-
|
|
22
|
+
const runtime = getStoreReadyRuntime(store, true);
|
|
23
|
+
if (runtime.ready) {
|
|
8
24
|
callback();
|
|
9
25
|
return () => void 0;
|
|
10
26
|
}
|
|
11
|
-
|
|
12
|
-
if (!callbacks) {
|
|
13
|
-
callbacks = /* @__PURE__ */ new Set();
|
|
14
|
-
readyCallbacks.set(store, callbacks);
|
|
15
|
-
}
|
|
16
|
-
callbacks.add(callback);
|
|
27
|
+
runtime.callbacks.add(callback);
|
|
17
28
|
return () => {
|
|
18
|
-
callbacks
|
|
29
|
+
runtime.callbacks.delete(callback);
|
|
19
30
|
};
|
|
20
31
|
};
|
|
21
32
|
const markStoreReady = (store) => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
33
|
+
const runtime = getStoreReadyRuntime(store, true);
|
|
34
|
+
if (runtime.ready) return;
|
|
35
|
+
runtime.ready = true;
|
|
36
|
+
const callbacks = [...runtime.callbacks];
|
|
37
|
+
runtime.callbacks.clear();
|
|
26
38
|
callbacks.forEach((callback) => callback());
|
|
27
|
-
callbacks.clear();
|
|
28
39
|
};
|
|
29
40
|
//#endregion
|
|
30
41
|
//#region packages/core/src/applyMiddlewares.ts
|
|
@@ -77,15 +88,64 @@ const warnDroppedUnsafePatches = (unsafePatches, source) => {
|
|
|
77
88
|
};
|
|
78
89
|
const sanitizePatches = (patches, options = {}) => {
|
|
79
90
|
if (options.warnOnDropped) warnDroppedUnsafePatches(getUnsafePatchPaths(patches), options.source ?? "patches");
|
|
91
|
+
const seen = /* @__PURE__ */ new WeakMap();
|
|
80
92
|
return patches?.filter((patch) => !hasUnsafePatchPath(patch.path)).map((patch) => Object.prototype.hasOwnProperty.call(patch, "value") ? {
|
|
81
93
|
...patch,
|
|
82
|
-
value: sanitizeReplacementState(patch.value)
|
|
94
|
+
value: sanitizeReplacementState(patch.value, seen)
|
|
83
95
|
} : patch);
|
|
84
96
|
};
|
|
85
97
|
const sanitizeCheckedPatches = (patches, source) => {
|
|
86
98
|
assertSafePatches(patches, source);
|
|
87
99
|
return sanitizePatches(patches) ?? [];
|
|
88
100
|
};
|
|
101
|
+
const createRootReplacementPatches = (currentState, nextState) => {
|
|
102
|
+
const patches = [];
|
|
103
|
+
const inversePatches = [];
|
|
104
|
+
const nextKeys = new Set(getOwnEnumerableKeys(nextState));
|
|
105
|
+
for (const key of getOwnEnumerableKeys(currentState)) {
|
|
106
|
+
if (typeof key === "string" && isUnsafeKey(key)) continue;
|
|
107
|
+
if (nextKeys.has(key)) continue;
|
|
108
|
+
patches.push({
|
|
109
|
+
op: "remove",
|
|
110
|
+
path: [key]
|
|
111
|
+
});
|
|
112
|
+
inversePatches.push({
|
|
113
|
+
op: "add",
|
|
114
|
+
path: [key],
|
|
115
|
+
value: currentState[key]
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
for (const key of nextKeys) {
|
|
119
|
+
if (typeof key === "string" && isUnsafeKey(key)) continue;
|
|
120
|
+
if (!Object.prototype.hasOwnProperty.call(currentState, key)) {
|
|
121
|
+
patches.push({
|
|
122
|
+
op: "add",
|
|
123
|
+
path: [key],
|
|
124
|
+
value: nextState[key]
|
|
125
|
+
});
|
|
126
|
+
inversePatches.push({
|
|
127
|
+
op: "remove",
|
|
128
|
+
path: [key]
|
|
129
|
+
});
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (Object.is(currentState[key], nextState[key])) continue;
|
|
133
|
+
patches.push({
|
|
134
|
+
op: "replace",
|
|
135
|
+
path: [key],
|
|
136
|
+
value: nextState[key]
|
|
137
|
+
});
|
|
138
|
+
inversePatches.push({
|
|
139
|
+
op: "replace",
|
|
140
|
+
path: [key],
|
|
141
|
+
value: currentState[key]
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
patches,
|
|
146
|
+
inversePatches
|
|
147
|
+
};
|
|
148
|
+
};
|
|
89
149
|
const setOwnEnumerable = (target, key, value) => {
|
|
90
150
|
if (typeof key === "string" && isUnsafeKey(key)) return;
|
|
91
151
|
target[key] = value;
|
|
@@ -377,20 +437,92 @@ const getInitialState = (store, createState, internal) => {
|
|
|
377
437
|
}, {});
|
|
378
438
|
};
|
|
379
439
|
//#endregion
|
|
440
|
+
//#region packages/core/src/storeCommit.ts
|
|
441
|
+
const storeCommitRuntimeSymbol = Symbol.for("coaction.storeCommit.runtime");
|
|
442
|
+
const getStoreCommitRuntime = (store, create = false) => {
|
|
443
|
+
const target = store;
|
|
444
|
+
const existing = target[storeCommitRuntimeSymbol];
|
|
445
|
+
if (existing || !create) return existing;
|
|
446
|
+
const runtime = {
|
|
447
|
+
disposed: false,
|
|
448
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
449
|
+
prepareListeners: /* @__PURE__ */ new Set()
|
|
450
|
+
};
|
|
451
|
+
Object.defineProperty(target, storeCommitRuntimeSymbol, {
|
|
452
|
+
configurable: true,
|
|
453
|
+
enumerable: true,
|
|
454
|
+
value: runtime,
|
|
455
|
+
writable: true
|
|
456
|
+
});
|
|
457
|
+
return runtime;
|
|
458
|
+
};
|
|
459
|
+
/** @internal */
|
|
460
|
+
const hasStoreCommitListeners = (store) => Boolean(getStoreCommitRuntime(store)?.listeners.size);
|
|
461
|
+
/** @internal */
|
|
462
|
+
const publishStoreCommit = (store, commit) => {
|
|
463
|
+
const runtime = getStoreCommitRuntime(store);
|
|
464
|
+
if (!runtime || runtime.disposed || !runtime.listeners.size) return;
|
|
465
|
+
for (const listener of [...runtime.listeners]) listener(commit);
|
|
466
|
+
};
|
|
467
|
+
/** @internal */
|
|
468
|
+
const prepareStoreCommit = (store, commit) => {
|
|
469
|
+
const runtime = getStoreCommitRuntime(store);
|
|
470
|
+
if (!runtime || runtime.disposed || !runtime.prepareListeners.size) return false;
|
|
471
|
+
let replace = false;
|
|
472
|
+
for (const listener of runtime.prepareListeners) replace = listener(commit) === true || replace;
|
|
473
|
+
return replace;
|
|
474
|
+
};
|
|
475
|
+
/** @internal */
|
|
476
|
+
const getStoreCommitSource = (store, fallback) => getStoreCommitRuntime(store)?.source ?? fallback;
|
|
477
|
+
/** @internal */
|
|
478
|
+
const runWithStoreCommitSource = (store, source, callback) => {
|
|
479
|
+
const runtime = getStoreCommitRuntime(store, true);
|
|
480
|
+
const previousSource = runtime.source;
|
|
481
|
+
runtime.source = source;
|
|
482
|
+
try {
|
|
483
|
+
return callback();
|
|
484
|
+
} finally {
|
|
485
|
+
runtime.source = previousSource;
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
/** @internal */
|
|
489
|
+
const registerStorePatchReplayer = (store, replay) => {
|
|
490
|
+
const runtime = getStoreCommitRuntime(store, true);
|
|
491
|
+
runtime.replay = replay;
|
|
492
|
+
};
|
|
493
|
+
/** @internal */
|
|
494
|
+
const disposeStoreCommitRuntime = (store) => {
|
|
495
|
+
const runtime = getStoreCommitRuntime(store);
|
|
496
|
+
if (!runtime) return;
|
|
497
|
+
runtime.disposed = true;
|
|
498
|
+
runtime.listeners.clear();
|
|
499
|
+
runtime.prepareListeners.clear();
|
|
500
|
+
runtime.source = void 0;
|
|
501
|
+
runtime.replay = void 0;
|
|
502
|
+
};
|
|
503
|
+
//#endregion
|
|
380
504
|
//#region packages/core/src/handleDraft.ts
|
|
381
505
|
const handleDraft = (store, internal) => {
|
|
382
506
|
internal.rootState = internal.backupState;
|
|
383
507
|
const [, patches, inversePatches] = internal.finalizeDraft();
|
|
384
|
-
const
|
|
508
|
+
const finalPatches = store.patch ? store.patch({
|
|
385
509
|
patches,
|
|
386
510
|
inversePatches
|
|
387
511
|
}) : {
|
|
388
512
|
patches,
|
|
389
513
|
inversePatches
|
|
390
|
-
}
|
|
514
|
+
};
|
|
515
|
+
const safePatches = sanitizeCheckedPatches(finalPatches.patches, "store.patch()");
|
|
516
|
+
const safeInversePatches = sanitizeCheckedPatches(finalPatches.inversePatches, "store.patch() inverse patches");
|
|
391
517
|
if (safePatches.length) {
|
|
392
518
|
store.apply(internal.rootState, safePatches);
|
|
393
519
|
internal.emitPatches?.(safePatches);
|
|
520
|
+
publishStoreCommit(store, {
|
|
521
|
+
state: internal.rootState,
|
|
522
|
+
patches: safePatches,
|
|
523
|
+
inversePatches: safeInversePatches,
|
|
524
|
+
source: "mutableAction"
|
|
525
|
+
});
|
|
394
526
|
}
|
|
395
527
|
};
|
|
396
528
|
//#endregion
|
|
@@ -437,7 +569,7 @@ const createLocalAction = ({ fn, internal, key, options, store, sliceKey }) => {
|
|
|
437
569
|
throw error;
|
|
438
570
|
}
|
|
439
571
|
};
|
|
440
|
-
const enablePatches = store.transport ?? options.enablePatches;
|
|
572
|
+
const enablePatches = Boolean(store.transport ?? options.enablePatches) || hasStoreCommitListeners(store);
|
|
441
573
|
return traceAction(() => {
|
|
442
574
|
if (internal.mutableInstance && !internal.isBatching && enablePatches) {
|
|
443
575
|
let result;
|
|
@@ -745,8 +877,10 @@ const getRawState = (store, internal, initialState, options, createClientAction)
|
|
|
745
877
|
//#region packages/core/src/handleState.ts
|
|
746
878
|
const handleState = (store, internal, options) => {
|
|
747
879
|
let defaultResultValidated = false;
|
|
880
|
+
let pendingCommitSource;
|
|
748
881
|
const defaultUpdater = (next) => {
|
|
749
882
|
defaultResultValidated = false;
|
|
883
|
+
let producedState;
|
|
750
884
|
const merge = (_next = next) => {
|
|
751
885
|
if (_next !== next) internal.validateState?.(_next);
|
|
752
886
|
assertKnownStateShape(_next, internal.rootState, internal.stateSchema, store.isSliceStore);
|
|
@@ -760,7 +894,7 @@ const handleState = (store, internal, options) => {
|
|
|
760
894
|
}
|
|
761
895
|
if (typeof returnValue === "object" && returnValue !== null) merge(returnValue);
|
|
762
896
|
} : merge;
|
|
763
|
-
if (!(store.transport ?? options.enablePatches) && internal.mutableInstance) {
|
|
897
|
+
if (!(Boolean(store.transport ?? options.enablePatches) || hasStoreCommitListeners(store)) && internal.mutableInstance) {
|
|
764
898
|
if (internal.actMutable) {
|
|
765
899
|
internal.actMutable(() => {
|
|
766
900
|
fn.apply(null);
|
|
@@ -782,6 +916,7 @@ const handleState = (store, internal, options) => {
|
|
|
782
916
|
}, { enablePatches: true });
|
|
783
917
|
assertKnownStateShape(result[0], internal.backupState, internal.stateSchema, store.isSliceStore, { requireSliceRoots: true });
|
|
784
918
|
internal.validateState?.(internal.getTransportState?.() ?? result[0]);
|
|
919
|
+
producedState = result[0];
|
|
785
920
|
patches = result[1];
|
|
786
921
|
inversePatches = result[2];
|
|
787
922
|
} finally {
|
|
@@ -798,6 +933,18 @@ const handleState = (store, internal, options) => {
|
|
|
798
933
|
if (!patch) internal.validatePatches?.(finalPatches.patches);
|
|
799
934
|
const safePatches = sanitizeCheckedPatches(finalPatches.patches, "store.patch()");
|
|
800
935
|
const safeInversePatches = sanitizeCheckedPatches(finalPatches.inversePatches, "store.patch() inverse patches");
|
|
936
|
+
if (producedState && safePatches.some((patch) => typeof patch.value === "object" && patch.value !== null) && prepareStoreCommit(store, {
|
|
937
|
+
state: producedState,
|
|
938
|
+
patches: safePatches,
|
|
939
|
+
inversePatches: safeInversePatches,
|
|
940
|
+
source: "setState"
|
|
941
|
+
})) {
|
|
942
|
+
runWithStoreCommitSource(store, "setState", () => {
|
|
943
|
+
store.apply(producedState);
|
|
944
|
+
});
|
|
945
|
+
defaultResultValidated = true;
|
|
946
|
+
return [];
|
|
947
|
+
}
|
|
801
948
|
if (safePatches.length) {
|
|
802
949
|
defaultResultValidated = internal.applyValidatedPatches?.(internal.rootState, safePatches, !patch) ?? false;
|
|
803
950
|
if (!internal.applyValidatedPatches) store.apply(internal.rootState, safePatches);
|
|
@@ -809,6 +956,8 @@ const handleState = (store, internal, options) => {
|
|
|
809
956
|
];
|
|
810
957
|
};
|
|
811
958
|
const setState = (next, updater = defaultUpdater) => {
|
|
959
|
+
const commitSource = pendingCommitSource ?? "setState";
|
|
960
|
+
pendingCommitSource = void 0;
|
|
812
961
|
internal.assertAlive?.("setState");
|
|
813
962
|
internal.assertMutationAllowed?.("setState");
|
|
814
963
|
if (store.share === "client") throw new Error(`setState() cannot be called in the client store. To update the state, please trigger a store method with setState() instead.`);
|
|
@@ -819,7 +968,7 @@ const handleState = (store, internal, options) => {
|
|
|
819
968
|
assertKnownStateShape(next, internal.rootState, internal.stateSchema, store.isSliceStore);
|
|
820
969
|
}
|
|
821
970
|
internal.isBatching = true;
|
|
822
|
-
if (!store.share && !options.enablePatches && !internal.mutableInstance && updater === defaultUpdater) try {
|
|
971
|
+
if (!store.share && !options.enablePatches && !hasStoreCommitListeners(store) && !internal.mutableInstance && updater === defaultUpdater) try {
|
|
823
972
|
if (typeof next === "function") try {
|
|
824
973
|
internal.backupState = internal.rootState;
|
|
825
974
|
const snapshotCache = internal.computedSnapshotCache;
|
|
@@ -900,13 +1049,60 @@ const handleState = (store, internal, options) => {
|
|
|
900
1049
|
sanitizeCheckedPatches(result[2], "setState updater inverse result")
|
|
901
1050
|
];
|
|
902
1051
|
}
|
|
903
|
-
if (result?.
|
|
1052
|
+
if (result?.length === 3) {
|
|
1053
|
+
const [, patches, inversePatches] = result;
|
|
1054
|
+
internal.emitPatches?.(patches);
|
|
1055
|
+
if (patches.length || inversePatches.length) publishStoreCommit(store, {
|
|
1056
|
+
state: internal.rootState,
|
|
1057
|
+
patches,
|
|
1058
|
+
inversePatches,
|
|
1059
|
+
source: commitSource
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
904
1062
|
return result;
|
|
905
1063
|
};
|
|
1064
|
+
const replayPatches = ({ patches, inversePatches }, replaySetState = setState) => {
|
|
1065
|
+
const previousSource = pendingCommitSource;
|
|
1066
|
+
pendingCommitSource = "replay";
|
|
1067
|
+
try {
|
|
1068
|
+
replaySetState(internal.rootState, () => {
|
|
1069
|
+
const inputPatches = patches.map((patch) => ({
|
|
1070
|
+
...patch,
|
|
1071
|
+
path: Array.isArray(patch.path) ? [...patch.path] : patch.path
|
|
1072
|
+
}));
|
|
1073
|
+
const inputInversePatches = inversePatches.map((patch) => ({
|
|
1074
|
+
...patch,
|
|
1075
|
+
path: Array.isArray(patch.path) ? [...patch.path] : patch.path
|
|
1076
|
+
}));
|
|
1077
|
+
const finalPatches = store.patch ? store.patch({
|
|
1078
|
+
patches: inputPatches,
|
|
1079
|
+
inversePatches: inputInversePatches
|
|
1080
|
+
}) : {
|
|
1081
|
+
patches: inputPatches,
|
|
1082
|
+
inversePatches: inputInversePatches
|
|
1083
|
+
};
|
|
1084
|
+
const safePatches = sanitizeCheckedPatches(finalPatches.patches, "store.patch()");
|
|
1085
|
+
const safeInversePatches = sanitizeCheckedPatches(finalPatches.inversePatches, "store.patch() inverse patches");
|
|
1086
|
+
if (safePatches.length) {
|
|
1087
|
+
internal.applyValidatedPatches?.(internal.rootState, safePatches, false);
|
|
1088
|
+
if (!internal.applyValidatedPatches) store.apply(internal.rootState, safePatches);
|
|
1089
|
+
}
|
|
1090
|
+
return [
|
|
1091
|
+
internal.rootState,
|
|
1092
|
+
safePatches,
|
|
1093
|
+
safeInversePatches
|
|
1094
|
+
];
|
|
1095
|
+
});
|
|
1096
|
+
return internal.rootState;
|
|
1097
|
+
} finally {
|
|
1098
|
+
pendingCommitSource = previousSource;
|
|
1099
|
+
}
|
|
1100
|
+
};
|
|
906
1101
|
const getState = (deps, selector) => deps && selector ? new Computed(deps, selector) : internal.module;
|
|
907
1102
|
return {
|
|
908
1103
|
setState,
|
|
909
|
-
getState
|
|
1104
|
+
getState,
|
|
1105
|
+
replayPatches
|
|
910
1106
|
};
|
|
911
1107
|
};
|
|
912
1108
|
//#endregion
|
|
@@ -949,7 +1145,7 @@ const createStore = (createState, options, runtime = {}) => {
|
|
|
949
1145
|
namespaceMap.set(name, true);
|
|
950
1146
|
}
|
|
951
1147
|
try {
|
|
952
|
-
const { setState, getState } = handleState(store, internal, options);
|
|
1148
|
+
const { setState, getState, replayPatches } = handleState(store, internal, options);
|
|
953
1149
|
const subscribe = (listener) => {
|
|
954
1150
|
internal.assertAlive?.("subscribe");
|
|
955
1151
|
internal.listeners.add(listener);
|
|
@@ -971,6 +1167,7 @@ const createStore = (createState, options, runtime = {}) => {
|
|
|
971
1167
|
firstError ??= error;
|
|
972
1168
|
}
|
|
973
1169
|
internal.listeners.clear();
|
|
1170
|
+
disposeStoreCommitRuntime(store);
|
|
974
1171
|
try {
|
|
975
1172
|
store.transport?.dispose();
|
|
976
1173
|
} catch (error) {
|
|
@@ -999,7 +1196,23 @@ const createStore = (createState, options, runtime = {}) => {
|
|
|
999
1196
|
if (internal.updateImmutable) internal.updateImmutable(internal.rootState);
|
|
1000
1197
|
else internal.listeners.forEach((listener) => listener());
|
|
1001
1198
|
};
|
|
1002
|
-
const apply$1 = (state = internal.rootState, patches) =>
|
|
1199
|
+
const apply$1 = (state = internal.rootState, patches) => {
|
|
1200
|
+
const observeReplacement = patches === void 0 && hasStoreCommitListeners(store);
|
|
1201
|
+
const previousState = internal.rootState;
|
|
1202
|
+
applyState(state, patches);
|
|
1203
|
+
if (!observeReplacement) return;
|
|
1204
|
+
const replacement = createRootReplacementPatches(previousState, internal.rootState);
|
|
1205
|
+
const safePatches = sanitizeCheckedPatches(replacement.patches, "store.apply() replacement");
|
|
1206
|
+
const safeInversePatches = sanitizeCheckedPatches(replacement.inversePatches, "store.apply() replacement inverse patches");
|
|
1207
|
+
if (!safePatches.length && !safeInversePatches.length) return;
|
|
1208
|
+
internal.emitPatches?.(safePatches);
|
|
1209
|
+
publishStoreCommit(store, {
|
|
1210
|
+
state: internal.rootState,
|
|
1211
|
+
patches: safePatches,
|
|
1212
|
+
inversePatches: safeInversePatches,
|
|
1213
|
+
source: getStoreCommitSource(store, "external")
|
|
1214
|
+
});
|
|
1215
|
+
};
|
|
1003
1216
|
internal.applyValidatedPatches = (state, patches, skipFinalValidation) => {
|
|
1004
1217
|
if (store.apply !== apply$1) {
|
|
1005
1218
|
store.apply(state, patches);
|
|
@@ -1041,6 +1254,7 @@ const createStore = (createState, options, runtime = {}) => {
|
|
|
1041
1254
|
});
|
|
1042
1255
|
const middlewareStore = applyMiddlewares(store, options.middlewares ?? []);
|
|
1043
1256
|
if (middlewareStore !== store) Object.assign(store, middlewareStore);
|
|
1257
|
+
registerStorePatchReplayer(store, replayPatches);
|
|
1044
1258
|
internal.assertAlive?.("store initialization");
|
|
1045
1259
|
if (validatePatches && store.patch) {
|
|
1046
1260
|
const patch = store.patch.bind(store);
|