coaction 2.0.0 → 3.0.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/README.md +51 -21
- package/adapter.d.ts +1 -0
- package/adapter.js +3 -0
- package/dist/adapter.d.mts +468 -0
- package/dist/adapter.d.ts +468 -0
- package/dist/adapter.js +591 -0
- package/dist/adapter.mjs +548 -0
- package/dist/index.d.mts +53 -182
- package/dist/index.d.ts +53 -182
- package/dist/index.js +1353 -838
- package/dist/index.mjs +1349 -811
- package/dist/local.d.mts +344 -0
- package/dist/local.d.ts +344 -0
- package/dist/local.js +1207 -0
- package/dist/local.mjs +1138 -0
- package/dist/shared.d.mts +446 -0
- package/dist/shared.d.ts +446 -0
- package/dist/shared.js +1976 -0
- package/dist/shared.mjs +1900 -0
- package/local.d.ts +1 -0
- package/local.js +3 -0
- package/package.json +49 -5
- package/shared.d.ts +1 -0
- package/shared.js +3 -0
package/dist/adapter.mjs
ADDED
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
import { apply, create } from "mutative";
|
|
2
|
+
import { setActiveSub } from "alien-signals";
|
|
3
|
+
import * as alienSignalsSystem from "alien-signals/system";
|
|
4
|
+
//#region packages/core/src/global.ts
|
|
5
|
+
const getGlobal = () => {
|
|
6
|
+
let _global;
|
|
7
|
+
if (typeof window !== "undefined") _global = window;
|
|
8
|
+
else if (typeof global !== "undefined") _global = global;
|
|
9
|
+
else if (typeof self !== "undefined") _global = self;
|
|
10
|
+
else _global = {};
|
|
11
|
+
return _global;
|
|
12
|
+
};
|
|
13
|
+
getGlobal().SharedWorkerGlobalScope || globalThis.WorkerGlobalScope;
|
|
14
|
+
const bindSymbol = Symbol("bind");
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region packages/core/src/binder.ts
|
|
17
|
+
const createExternalStoreAdapter = ({ handleState, handleStore }) => ((state) => {
|
|
18
|
+
const { copyState, key, bind } = handleState(state);
|
|
19
|
+
const value = typeof key !== "undefined" ? copyState[key] : copyState;
|
|
20
|
+
Object.defineProperty(value, bindSymbol, {
|
|
21
|
+
configurable: true,
|
|
22
|
+
enumerable: typeof key !== "undefined",
|
|
23
|
+
value: {
|
|
24
|
+
handleStore,
|
|
25
|
+
bind
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
return copyState;
|
|
29
|
+
});
|
|
30
|
+
/**
|
|
31
|
+
* Build an adapter helper for bridging an external store implementation into
|
|
32
|
+
* Coaction.
|
|
33
|
+
*
|
|
34
|
+
* @remarks
|
|
35
|
+
* Import this compatibility helper from `coaction/adapter`.
|
|
36
|
+
*
|
|
37
|
+
* Official bindings use this to integrate stores such as Redux, Jotai, Pinia,
|
|
38
|
+
* Zustand, MobX, and Valtio. Binder-backed integrations are whole-store
|
|
39
|
+
* adapters; they are not compatible with Coaction slices mode.
|
|
40
|
+
*/
|
|
41
|
+
function createBinder({ handleState, handleStore }) {
|
|
42
|
+
return createExternalStoreAdapter({
|
|
43
|
+
handleState,
|
|
44
|
+
handleStore
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Define a whole-store adapter for integrating an external state runtime with
|
|
49
|
+
* Coaction.
|
|
50
|
+
*
|
|
51
|
+
* @remarks
|
|
52
|
+
* Import this helper from `coaction/adapter`. `createBinder()` remains as a
|
|
53
|
+
* compatibility alias for existing official and community integrations.
|
|
54
|
+
*/
|
|
55
|
+
function defineExternalStoreAdapter(options) {
|
|
56
|
+
return createExternalStoreAdapter(options);
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region packages/core/src/utils.ts
|
|
60
|
+
const isUnsafeKey = (key) => key === "__proto__" || key === "prototype" || key === "constructor";
|
|
61
|
+
const isUnsafePathSegment = (segment) => typeof segment === "string" && isUnsafeKey(segment);
|
|
62
|
+
var UnsafePatchPathError = class extends Error {
|
|
63
|
+
name = "UnsafePatchPathError";
|
|
64
|
+
};
|
|
65
|
+
var StateSchemaError = class extends Error {
|
|
66
|
+
name = "StateSchemaError";
|
|
67
|
+
};
|
|
68
|
+
const isStateSchemaError = (error) => error instanceof StateSchemaError || error instanceof Error && error.name === "StateSchemaError";
|
|
69
|
+
const hasUnsafePatchPath = (path) => {
|
|
70
|
+
return (Array.isArray(path) ? path : typeof path === "string" ? path.split("/").filter(Boolean).map((segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~")) : []).some(isUnsafePathSegment);
|
|
71
|
+
};
|
|
72
|
+
const formatPatchPath = (path) => Array.isArray(path) ? path.map((segment) => String(segment)).join(".") : String(path);
|
|
73
|
+
const getUnsafePatchPaths = (patches) => patches?.filter((patch) => hasUnsafePatchPath(patch.path)) ?? [];
|
|
74
|
+
const assertSafePatches = (patches, source = "patches") => {
|
|
75
|
+
const unsafePatches = getUnsafePatchPaths(patches);
|
|
76
|
+
if (!unsafePatches.length) return;
|
|
77
|
+
const paths = unsafePatches.map((patch) => `'${formatPatchPath(patch.path)}'`).join(", ");
|
|
78
|
+
throw new UnsafePatchPathError(`Unsafe patch path${unsafePatches.length > 1 ? "s" : ""} ${paths} cannot be applied from ${source}.`);
|
|
79
|
+
};
|
|
80
|
+
const warnDroppedUnsafePatches = (unsafePatches, source) => {
|
|
81
|
+
if (process.env.NODE_ENV !== "development" || !unsafePatches.length) return;
|
|
82
|
+
const paths = unsafePatches.map((patch) => `'${formatPatchPath(patch.path)}'`).join(", ");
|
|
83
|
+
console.warn(`Coaction dropped unsafe patch path${unsafePatches.length > 1 ? "s" : ""} ${paths} from ${source}.`);
|
|
84
|
+
};
|
|
85
|
+
const sanitizePatches = (patches, options = {}) => {
|
|
86
|
+
if (options.warnOnDropped) warnDroppedUnsafePatches(getUnsafePatchPaths(patches), options.source ?? "patches");
|
|
87
|
+
return patches?.filter((patch) => !hasUnsafePatchPath(patch.path)).map((patch) => Object.prototype.hasOwnProperty.call(patch, "value") ? {
|
|
88
|
+
...patch,
|
|
89
|
+
value: sanitizeReplacementState(patch.value)
|
|
90
|
+
} : patch);
|
|
91
|
+
};
|
|
92
|
+
const sanitizeCheckedPatches = (patches, source) => {
|
|
93
|
+
assertSafePatches(patches, source);
|
|
94
|
+
return sanitizePatches(patches) ?? [];
|
|
95
|
+
};
|
|
96
|
+
const createRootReplacementPatches = (currentState, nextState) => {
|
|
97
|
+
const patches = [];
|
|
98
|
+
const inversePatches = [];
|
|
99
|
+
const nextKeys = new Set(getOwnEnumerableKeys(nextState));
|
|
100
|
+
for (const key of getOwnEnumerableKeys(currentState)) {
|
|
101
|
+
if (typeof key === "string" && isUnsafeKey(key)) continue;
|
|
102
|
+
if (nextKeys.has(key)) continue;
|
|
103
|
+
patches.push({
|
|
104
|
+
op: "remove",
|
|
105
|
+
path: [key]
|
|
106
|
+
});
|
|
107
|
+
inversePatches.push({
|
|
108
|
+
op: "add",
|
|
109
|
+
path: [key],
|
|
110
|
+
value: currentState[key]
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
for (const key of nextKeys) {
|
|
114
|
+
if (typeof key === "string" && isUnsafeKey(key)) continue;
|
|
115
|
+
if (!Object.prototype.hasOwnProperty.call(currentState, key)) {
|
|
116
|
+
patches.push({
|
|
117
|
+
op: "add",
|
|
118
|
+
path: [key],
|
|
119
|
+
value: nextState[key]
|
|
120
|
+
});
|
|
121
|
+
inversePatches.push({
|
|
122
|
+
op: "remove",
|
|
123
|
+
path: [key]
|
|
124
|
+
});
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (Object.is(currentState[key], nextState[key])) continue;
|
|
128
|
+
patches.push({
|
|
129
|
+
op: "replace",
|
|
130
|
+
path: [key],
|
|
131
|
+
value: nextState[key]
|
|
132
|
+
});
|
|
133
|
+
inversePatches.push({
|
|
134
|
+
op: "replace",
|
|
135
|
+
path: [key],
|
|
136
|
+
value: currentState[key]
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
patches,
|
|
141
|
+
inversePatches
|
|
142
|
+
};
|
|
143
|
+
};
|
|
144
|
+
const createRootStateFromPatches = (currentState, patches) => {
|
|
145
|
+
const nextState = sanitizeReplacementState(currentState);
|
|
146
|
+
const seen = /* @__PURE__ */ new WeakMap();
|
|
147
|
+
for (const patch of patches) {
|
|
148
|
+
if (!Array.isArray(patch.path) || patch.path.length !== 1 || ![
|
|
149
|
+
"add",
|
|
150
|
+
"remove",
|
|
151
|
+
"replace"
|
|
152
|
+
].includes(patch.op)) return;
|
|
153
|
+
const key = patch.path[0];
|
|
154
|
+
if (patch.op === "remove") {
|
|
155
|
+
delete nextState[key];
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
nextState[key] = sanitizeReplacementState(patch.value, seen);
|
|
159
|
+
}
|
|
160
|
+
return nextState;
|
|
161
|
+
};
|
|
162
|
+
const applyRootReplacementWithPatches = (store, nextState, options = {}) => {
|
|
163
|
+
const { patches, inversePatches } = createRootReplacementPatches(store.getPureState(), nextState);
|
|
164
|
+
const finalPatches = store.patch ? store.patch({
|
|
165
|
+
patches,
|
|
166
|
+
inversePatches
|
|
167
|
+
}) : {
|
|
168
|
+
patches,
|
|
169
|
+
inversePatches
|
|
170
|
+
};
|
|
171
|
+
const safePatches = sanitizeCheckedPatches(finalPatches.patches, "store.patch()");
|
|
172
|
+
const safeInversePatches = sanitizeCheckedPatches(finalPatches.inversePatches, "store.patch() inverse patches");
|
|
173
|
+
if (safePatches.length) {
|
|
174
|
+
const applyExactReplacement = options.applyExactReplacement;
|
|
175
|
+
const exactReplacementState = applyExactReplacement ? createRootStateFromPatches(store.getPureState(), safePatches) : void 0;
|
|
176
|
+
if (applyExactReplacement && exactReplacementState) applyExactReplacement(exactReplacementState);
|
|
177
|
+
else store.apply(store.getPureState(), safePatches);
|
|
178
|
+
}
|
|
179
|
+
return [
|
|
180
|
+
store.getPureState(),
|
|
181
|
+
safePatches,
|
|
182
|
+
safeInversePatches
|
|
183
|
+
];
|
|
184
|
+
};
|
|
185
|
+
const setOwnEnumerable = (target, key, value) => {
|
|
186
|
+
if (typeof key === "string" && isUnsafeKey(key)) return;
|
|
187
|
+
target[key] = value;
|
|
188
|
+
};
|
|
189
|
+
const getOwnEnumerableKeys = (source) => {
|
|
190
|
+
if (typeof source !== "object" || source === null) return [];
|
|
191
|
+
return Reflect.ownKeys(source).filter((key) => Object.prototype.propertyIsEnumerable.call(source, key));
|
|
192
|
+
};
|
|
193
|
+
const isArrayIndexKey$1 = (key) => {
|
|
194
|
+
if (typeof key !== "string") return false;
|
|
195
|
+
const index = Number(key);
|
|
196
|
+
return Number.isInteger(index) && index >= 0 && index < 2 ** 32 - 1 && String(index) === key;
|
|
197
|
+
};
|
|
198
|
+
const replaceOwnEnumerable = (target, source) => {
|
|
199
|
+
const seen = /* @__PURE__ */ new WeakMap();
|
|
200
|
+
seen.set(source, target);
|
|
201
|
+
const nextKeys = /* @__PURE__ */ new Set();
|
|
202
|
+
for (const key of getOwnEnumerableKeys(source)) {
|
|
203
|
+
if (typeof key === "string" && isUnsafeKey(key)) continue;
|
|
204
|
+
if (typeof source[key] === "function") continue;
|
|
205
|
+
nextKeys.add(key);
|
|
206
|
+
}
|
|
207
|
+
for (const key of getOwnEnumerableKeys(target)) if (!nextKeys.has(key)) delete target[key];
|
|
208
|
+
nextKeys.forEach((key) => {
|
|
209
|
+
setOwnEnumerable(target, key, sanitizeReplacementState(source[key], seen));
|
|
210
|
+
});
|
|
211
|
+
};
|
|
212
|
+
const sanitizeReplacementState = (source, seen = /* @__PURE__ */ new WeakMap()) => {
|
|
213
|
+
if (typeof source !== "object" || source === null) return source;
|
|
214
|
+
const cached = seen.get(source);
|
|
215
|
+
if (cached) return cached;
|
|
216
|
+
if (Array.isArray(source)) {
|
|
217
|
+
const target = [];
|
|
218
|
+
target.length = source.length;
|
|
219
|
+
seen.set(source, target);
|
|
220
|
+
for (let index = 0; index < source.length; index += 1) if (Object.prototype.hasOwnProperty.call(source, index)) target[index] = sanitizeReplacementState(source[index], seen);
|
|
221
|
+
for (const key of getOwnEnumerableKeys(source)) {
|
|
222
|
+
if (isArrayIndexKey$1(key) || typeof key === "string" && isUnsafeKey(key)) continue;
|
|
223
|
+
const value = source[key];
|
|
224
|
+
if (typeof value === "function") continue;
|
|
225
|
+
setOwnEnumerable(target, key, sanitizeReplacementState(value, seen));
|
|
226
|
+
}
|
|
227
|
+
return target;
|
|
228
|
+
}
|
|
229
|
+
const prototype = Object.getPrototypeOf(source);
|
|
230
|
+
if (prototype !== Object.prototype && prototype !== null) return source;
|
|
231
|
+
const target = Object.create(prototype);
|
|
232
|
+
seen.set(source, target);
|
|
233
|
+
for (const key of getOwnEnumerableKeys(source)) {
|
|
234
|
+
if (typeof key === "string" && isUnsafeKey(key)) continue;
|
|
235
|
+
const value = source[key];
|
|
236
|
+
if (typeof value === "function") continue;
|
|
237
|
+
setOwnEnumerable(target, key, sanitizeReplacementState(value, seen));
|
|
238
|
+
}
|
|
239
|
+
return target;
|
|
240
|
+
};
|
|
241
|
+
const sanitizeInitialStateValue = (source, seen = /* @__PURE__ */ new WeakMap()) => {
|
|
242
|
+
if (typeof source !== "object" || source === null) return source;
|
|
243
|
+
const cached = seen.get(source);
|
|
244
|
+
if (cached) return cached;
|
|
245
|
+
if (Array.isArray(source)) {
|
|
246
|
+
const target = [];
|
|
247
|
+
target.length = source.length;
|
|
248
|
+
seen.set(source, target);
|
|
249
|
+
for (let index = 0; index < source.length; index += 1) if (Object.prototype.hasOwnProperty.call(source, index)) target[index] = sanitizeInitialStateValue(source[index], seen);
|
|
250
|
+
for (const key of getOwnEnumerableKeys(source)) {
|
|
251
|
+
if (isArrayIndexKey$1(key) || typeof key === "string" && isUnsafeKey(key)) continue;
|
|
252
|
+
setOwnEnumerable(target, key, sanitizeInitialStateValue(source[key], seen));
|
|
253
|
+
}
|
|
254
|
+
return target;
|
|
255
|
+
}
|
|
256
|
+
const prototype = Object.getPrototypeOf(source);
|
|
257
|
+
if (prototype !== Object.prototype && prototype !== null) return source;
|
|
258
|
+
const target = Object.create(prototype);
|
|
259
|
+
seen.set(source, target);
|
|
260
|
+
for (const key of getOwnEnumerableKeys(source)) {
|
|
261
|
+
if (typeof key === "string" && isUnsafeKey(key)) continue;
|
|
262
|
+
setOwnEnumerable(target, key, sanitizeInitialStateValue(source[key], seen));
|
|
263
|
+
}
|
|
264
|
+
return target;
|
|
265
|
+
};
|
|
266
|
+
//#endregion
|
|
267
|
+
//#region packages/core/src/externalMutableAdapterUtils.ts
|
|
268
|
+
const getMutableAdapterOwnEnumerableKeys = (value) => Reflect.ownKeys(value).filter((key) => Object.prototype.propertyIsEnumerable.call(value, key));
|
|
269
|
+
const isMutableAdapterUnsafeKey = (key) => typeof key === "string" && isUnsafeKey(key);
|
|
270
|
+
const isArrayIndexKey = (key) => {
|
|
271
|
+
if (typeof key !== "string") return false;
|
|
272
|
+
const index = Number(key);
|
|
273
|
+
return Number.isInteger(index) && index >= 0 && index < 2 ** 32 - 1 && String(index) === key;
|
|
274
|
+
};
|
|
275
|
+
const isObjectRecord = (value) => Object.prototype.toString.call(value) === "[object Object]";
|
|
276
|
+
const assertCanSetMutableAdapterPublicStateKey = (publicState, key) => {
|
|
277
|
+
if (Object.prototype.hasOwnProperty.call(publicState, key)) return;
|
|
278
|
+
if (Object.isExtensible(publicState)) return;
|
|
279
|
+
throw new StateSchemaError(`Unknown state key '${String(key)}' cannot be added after store initialization. Coaction state schema is fixed.`);
|
|
280
|
+
};
|
|
281
|
+
const ensureMutableAdapterRawDescriptor = (rawState, mutableState, publicState, key) => {
|
|
282
|
+
if (rawState === mutableState) return;
|
|
283
|
+
const rawDescriptor = Object.getOwnPropertyDescriptor(rawState, key);
|
|
284
|
+
if (rawDescriptor?.get && rawDescriptor.set) return;
|
|
285
|
+
const publicDescriptor = Object.getOwnPropertyDescriptor(publicState, key);
|
|
286
|
+
if (!publicDescriptor || rawDescriptor?.configurable === false) return;
|
|
287
|
+
Object.defineProperty(rawState, key, {
|
|
288
|
+
get: () => mutableState[key],
|
|
289
|
+
set: (value) => {
|
|
290
|
+
mutableState[key] = value;
|
|
291
|
+
},
|
|
292
|
+
configurable: true,
|
|
293
|
+
enumerable: publicDescriptor.enumerable
|
|
294
|
+
});
|
|
295
|
+
};
|
|
296
|
+
const replaceMutableAdapterState = (rawState, mutableState, publicState, source) => {
|
|
297
|
+
const nextKeys = /* @__PURE__ */ new Set();
|
|
298
|
+
for (const key of getMutableAdapterOwnEnumerableKeys(source)) {
|
|
299
|
+
if (isMutableAdapterUnsafeKey(key)) continue;
|
|
300
|
+
if (typeof source[key] === "function") continue;
|
|
301
|
+
nextKeys.add(key);
|
|
302
|
+
}
|
|
303
|
+
nextKeys.forEach((key) => {
|
|
304
|
+
assertCanSetMutableAdapterPublicStateKey(publicState, key);
|
|
305
|
+
});
|
|
306
|
+
for (const key of getMutableAdapterOwnEnumerableKeys(rawState)) {
|
|
307
|
+
if (isMutableAdapterUnsafeKey(key)) {
|
|
308
|
+
delete rawState[key];
|
|
309
|
+
delete mutableState[key];
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
if (typeof rawState[key] === "function") continue;
|
|
313
|
+
if (!nextKeys.has(key)) {
|
|
314
|
+
delete rawState[key];
|
|
315
|
+
delete mutableState[key];
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
const rawSeen = /* @__PURE__ */ new WeakMap();
|
|
319
|
+
const mutableSeen = /* @__PURE__ */ new WeakMap();
|
|
320
|
+
const publicSeen = /* @__PURE__ */ new WeakMap();
|
|
321
|
+
rawSeen.set(source, rawState);
|
|
322
|
+
mutableSeen.set(source, mutableState);
|
|
323
|
+
publicSeen.set(source, publicState);
|
|
324
|
+
nextKeys.forEach((key) => {
|
|
325
|
+
ensureMutableAdapterRawDescriptor(rawState, mutableState, publicState, key);
|
|
326
|
+
rawState[key] = sanitizeReplacementState(source[key], rawSeen);
|
|
327
|
+
mutableState[key] = sanitizeReplacementState(source[key], mutableSeen);
|
|
328
|
+
publicState[key] = sanitizeReplacementState(source[key], publicSeen);
|
|
329
|
+
});
|
|
330
|
+
};
|
|
331
|
+
const applyMutableAdapterPatches = (baseState, patches, rawState, mutableState, publicState, validateState) => {
|
|
332
|
+
assertSafePatches(patches, "mutable adapter apply()");
|
|
333
|
+
const nextState = apply(toMutableAdapterSnapshot(baseState === publicState ? rawState : baseState), patches);
|
|
334
|
+
validateState?.(nextState);
|
|
335
|
+
replaceMutableAdapterState(rawState, mutableState, publicState, nextState);
|
|
336
|
+
};
|
|
337
|
+
const toMutableAdapterSnapshot = (value, visited = /* @__PURE__ */ new WeakMap()) => {
|
|
338
|
+
if (Array.isArray(value)) {
|
|
339
|
+
if (visited.has(value)) return visited.get(value);
|
|
340
|
+
const next = [];
|
|
341
|
+
next.length = value.length;
|
|
342
|
+
visited.set(value, next);
|
|
343
|
+
for (let index = 0; index < value.length; index += 1) if (Object.prototype.hasOwnProperty.call(value, index)) next[index] = toMutableAdapterSnapshot(value[index], visited);
|
|
344
|
+
const source = value;
|
|
345
|
+
const target = next;
|
|
346
|
+
for (const key of getMutableAdapterOwnEnumerableKeys(value)) {
|
|
347
|
+
if (isArrayIndexKey(key) || isMutableAdapterUnsafeKey(key)) continue;
|
|
348
|
+
const child = source[key];
|
|
349
|
+
if (typeof child !== "function") target[key] = toMutableAdapterSnapshot(child, visited);
|
|
350
|
+
}
|
|
351
|
+
return next;
|
|
352
|
+
}
|
|
353
|
+
if (typeof value === "object" && value !== null) {
|
|
354
|
+
if (!isObjectRecord(value)) return value;
|
|
355
|
+
if (visited.has(value)) return visited.get(value);
|
|
356
|
+
const next = {};
|
|
357
|
+
visited.set(value, next);
|
|
358
|
+
for (const key of getMutableAdapterOwnEnumerableKeys(value)) {
|
|
359
|
+
if (isMutableAdapterUnsafeKey(key)) continue;
|
|
360
|
+
const child = value[key];
|
|
361
|
+
if (typeof child !== "function") next[key] = toMutableAdapterSnapshot(child, visited);
|
|
362
|
+
}
|
|
363
|
+
return next;
|
|
364
|
+
}
|
|
365
|
+
return value;
|
|
366
|
+
};
|
|
367
|
+
const snapshotMutableAdapterPureState = (store) => toMutableAdapterSnapshot(store.getPureState());
|
|
368
|
+
const isEqualMutableAdapterSnapshot = (left, right, visited = /* @__PURE__ */ new WeakMap()) => {
|
|
369
|
+
if (Object.is(left, right)) return true;
|
|
370
|
+
if (typeof left !== "object" || left === null || typeof right !== "object" || right === null) return false;
|
|
371
|
+
const leftIsArray = Array.isArray(left);
|
|
372
|
+
const rightIsArray = Array.isArray(right);
|
|
373
|
+
if (leftIsArray || rightIsArray) {
|
|
374
|
+
if (!leftIsArray || !rightIsArray || left.length !== right.length) return false;
|
|
375
|
+
} else if (!isObjectRecord(left) || !isObjectRecord(right)) return false;
|
|
376
|
+
let seenTargets = visited.get(left);
|
|
377
|
+
if (!seenTargets) {
|
|
378
|
+
seenTargets = /* @__PURE__ */ new WeakSet();
|
|
379
|
+
visited.set(left, seenTargets);
|
|
380
|
+
} else if (seenTargets.has(right)) return true;
|
|
381
|
+
seenTargets.add(right);
|
|
382
|
+
const leftRecord = left;
|
|
383
|
+
const rightRecord = right;
|
|
384
|
+
const leftKeys = getMutableAdapterOwnEnumerableKeys(left);
|
|
385
|
+
const rightKeys = getMutableAdapterOwnEnumerableKeys(right);
|
|
386
|
+
if (leftKeys.length !== rightKeys.length) return false;
|
|
387
|
+
for (const key of leftKeys) {
|
|
388
|
+
if (!Object.prototype.hasOwnProperty.call(rightRecord, key)) return false;
|
|
389
|
+
if (!isEqualMutableAdapterSnapshot(leftRecord[key], rightRecord[key], visited)) return false;
|
|
390
|
+
}
|
|
391
|
+
return true;
|
|
392
|
+
};
|
|
393
|
+
//#endregion
|
|
394
|
+
//#region packages/core/src/reactiveTracker.ts
|
|
395
|
+
const ReactiveFlags = alienSignalsSystem.ReactiveFlags;
|
|
396
|
+
const unwatch = (node) => {
|
|
397
|
+
if (!(node.flags & ReactiveFlags.Mutable)) {
|
|
398
|
+
node.depsTail = void 0;
|
|
399
|
+
node.flags = 0;
|
|
400
|
+
purgeDeps(node);
|
|
401
|
+
const sub = node.subs;
|
|
402
|
+
if (sub !== void 0) unlink(sub);
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
if (node.depsTail !== void 0) {
|
|
406
|
+
node.depsTail = void 0;
|
|
407
|
+
node.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty;
|
|
408
|
+
purgeDeps(node);
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
const unlink = (link, sub = link.sub) => {
|
|
412
|
+
const dep = link.dep;
|
|
413
|
+
const prevDep = link.prevDep;
|
|
414
|
+
const nextDep = link.nextDep;
|
|
415
|
+
const nextSub = link.nextSub;
|
|
416
|
+
const prevSub = link.prevSub;
|
|
417
|
+
if (nextDep !== void 0) nextDep.prevDep = prevDep;
|
|
418
|
+
else sub.depsTail = prevDep;
|
|
419
|
+
if (prevDep !== void 0) prevDep.nextDep = nextDep;
|
|
420
|
+
else sub.deps = nextDep;
|
|
421
|
+
if (nextSub !== void 0) nextSub.prevSub = prevSub;
|
|
422
|
+
else dep.subsTail = prevSub;
|
|
423
|
+
if (prevSub !== void 0) prevSub.nextSub = nextSub;
|
|
424
|
+
else if ((dep.subs = nextSub) === void 0) unwatch(dep);
|
|
425
|
+
return nextDep;
|
|
426
|
+
};
|
|
427
|
+
const purgeDeps = (sub) => {
|
|
428
|
+
const depsTail = sub.depsTail;
|
|
429
|
+
let dep = depsTail !== void 0 ? depsTail.nextDep : sub.deps;
|
|
430
|
+
while (dep !== void 0) dep = unlink(dep, sub);
|
|
431
|
+
};
|
|
432
|
+
/**
|
|
433
|
+
* Create a low-level signal dependency tracker for framework adapters.
|
|
434
|
+
*
|
|
435
|
+
* @remarks
|
|
436
|
+
* Adapter and framework authors import this helper from `coaction/adapter`.
|
|
437
|
+
*/
|
|
438
|
+
const createReactiveTracker = () => {
|
|
439
|
+
let version = 0;
|
|
440
|
+
let disposed = false;
|
|
441
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
442
|
+
const node = {
|
|
443
|
+
deps: void 0,
|
|
444
|
+
depsTail: void 0,
|
|
445
|
+
subs: void 0,
|
|
446
|
+
subsTail: void 0,
|
|
447
|
+
flags: ReactiveFlags.Watching,
|
|
448
|
+
fn: () => {
|
|
449
|
+
if (disposed) return;
|
|
450
|
+
version += 1;
|
|
451
|
+
listeners.forEach((listener) => listener());
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
const dispose = () => {
|
|
455
|
+
if (disposed) return;
|
|
456
|
+
disposed = true;
|
|
457
|
+
listeners.clear();
|
|
458
|
+
node.depsTail = void 0;
|
|
459
|
+
purgeDeps(node);
|
|
460
|
+
node.flags = 0;
|
|
461
|
+
};
|
|
462
|
+
return {
|
|
463
|
+
getSnapshot: () => version,
|
|
464
|
+
subscribe(listener) {
|
|
465
|
+
if (disposed) return () => void 0;
|
|
466
|
+
listeners.add(listener);
|
|
467
|
+
return () => {
|
|
468
|
+
listeners.delete(listener);
|
|
469
|
+
};
|
|
470
|
+
},
|
|
471
|
+
track(fn) {
|
|
472
|
+
if (disposed) return fn();
|
|
473
|
+
node.depsTail = void 0;
|
|
474
|
+
node.flags = ReactiveFlags.Watching | ReactiveFlags.RecursedCheck;
|
|
475
|
+
const prevSub = setActiveSub(node);
|
|
476
|
+
try {
|
|
477
|
+
return fn();
|
|
478
|
+
} finally {
|
|
479
|
+
setActiveSub(prevSub);
|
|
480
|
+
node.flags &= ~ReactiveFlags.RecursedCheck;
|
|
481
|
+
purgeDeps(node);
|
|
482
|
+
}
|
|
483
|
+
},
|
|
484
|
+
dispose
|
|
485
|
+
};
|
|
486
|
+
};
|
|
487
|
+
//#endregion
|
|
488
|
+
//#region packages/core/src/lifecycle.ts
|
|
489
|
+
const readyStores = /* @__PURE__ */ new WeakSet();
|
|
490
|
+
const readyCallbacks = /* @__PURE__ */ new WeakMap();
|
|
491
|
+
const onStoreReady = (store, callback) => {
|
|
492
|
+
if (readyStores.has(store)) {
|
|
493
|
+
callback();
|
|
494
|
+
return () => void 0;
|
|
495
|
+
}
|
|
496
|
+
let callbacks = readyCallbacks.get(store);
|
|
497
|
+
if (!callbacks) {
|
|
498
|
+
callbacks = /* @__PURE__ */ new Set();
|
|
499
|
+
readyCallbacks.set(store, callbacks);
|
|
500
|
+
}
|
|
501
|
+
callbacks.add(callback);
|
|
502
|
+
return () => {
|
|
503
|
+
callbacks?.delete(callback);
|
|
504
|
+
};
|
|
505
|
+
};
|
|
506
|
+
//#endregion
|
|
507
|
+
//#region packages/core/src/replaceExternalStoreState.ts
|
|
508
|
+
const replaceExternalStoreState = (store, internal, source, { syncImmutable = true } = {}) => {
|
|
509
|
+
internal.validateReplacementSource?.(source);
|
|
510
|
+
const [nextState, patches, inversePatches] = create(internal.rootState, (draft) => {
|
|
511
|
+
replaceOwnEnumerable(draft, source);
|
|
512
|
+
}, { enablePatches: true });
|
|
513
|
+
internal.validateState?.(nextState);
|
|
514
|
+
const safePatches = sanitizeCheckedPatches((store.patch ? store.patch({
|
|
515
|
+
patches,
|
|
516
|
+
inversePatches
|
|
517
|
+
}) : {
|
|
518
|
+
patches,
|
|
519
|
+
inversePatches
|
|
520
|
+
}).patches, "store.patch()");
|
|
521
|
+
if (!safePatches.length) return;
|
|
522
|
+
const updateImmutable = internal.updateImmutable;
|
|
523
|
+
if (!syncImmutable) internal.updateImmutable = void 0;
|
|
524
|
+
try {
|
|
525
|
+
store.apply(internal.rootState, safePatches);
|
|
526
|
+
} finally {
|
|
527
|
+
internal.updateImmutable = updateImmutable;
|
|
528
|
+
}
|
|
529
|
+
internal.emitPatches?.(safePatches);
|
|
530
|
+
};
|
|
531
|
+
//#endregion
|
|
532
|
+
//#region packages/core/src/wrapStore.ts
|
|
533
|
+
/**
|
|
534
|
+
* Convert a store object into Coaction's callable store shape.
|
|
535
|
+
*
|
|
536
|
+
* @remarks
|
|
537
|
+
* Framework bindings use this to attach selector-aware readers while
|
|
538
|
+
* preserving the underlying store API on the returned function object. Most
|
|
539
|
+
* applications should use a public `create` entry instead of calling
|
|
540
|
+
* `wrapStore()` directly. Framework authors import this helper from
|
|
541
|
+
* `coaction/local` or `coaction/adapter`.
|
|
542
|
+
*/
|
|
543
|
+
const wrapStore = (store, getState = () => store.getState()) => {
|
|
544
|
+
const { name, ..._store } = store;
|
|
545
|
+
return Object.assign({ [name]: (...args) => getState(...args) }[name], _store);
|
|
546
|
+
};
|
|
547
|
+
//#endregion
|
|
548
|
+
export { StateSchemaError, applyMutableAdapterPatches, applyRootReplacementWithPatches, createBinder, createReactiveTracker, createRootReplacementPatches, defineExternalStoreAdapter, getMutableAdapterOwnEnumerableKeys, isEqualMutableAdapterSnapshot, isMutableAdapterUnsafeKey, isStateSchemaError, onStoreReady, replaceExternalStoreState, replaceMutableAdapterState, replaceOwnEnumerable, sanitizeInitialStateValue, sanitizeReplacementState, snapshotMutableAdapterPureState, toMutableAdapterSnapshot, wrapStore };
|