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