coaction 2.1.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/README.md +28 -4
- package/adapter.d.ts +1 -0
- package/adapter.js +3 -0
- package/dist/adapter.d.mts +512 -0
- package/dist/adapter.d.ts +512 -0
- package/dist/adapter.js +686 -0
- package/dist/adapter.mjs +640 -0
- package/dist/index.d.mts +36 -216
- package/dist/index.d.ts +36 -216
- package/dist/index.js +1350 -1025
- package/dist/index.mjs +1353 -991
- package/dist/local.d.mts +344 -0
- package/dist/local.d.ts +344 -0
- package/dist/local.js +1421 -0
- package/dist/local.mjs +1352 -0
- package/dist/shared.d.mts +446 -0
- package/dist/shared.d.ts +446 -0
- package/dist/shared.js +2190 -0
- package/dist/shared.mjs +2114 -0
- package/local.d.ts +1 -0
- package/local.js +3 -0
- package/package.json +41 -2
- package/shared.d.ts +1 -0
- package/shared.js +3 -0
package/dist/index.mjs
CHANGED
|
@@ -1,34 +1,64 @@
|
|
|
1
|
-
import { apply, create as create$1, isDraft } from "mutative";
|
|
2
1
|
import { createTransport } from "data-transport";
|
|
3
|
-
import { computed, computed as computed$1, effect, effectScope, endBatch, endBatch as endBatch$1, isComputed, isEffect, isEffectScope, isSignal,
|
|
4
|
-
import
|
|
5
|
-
//#region packages/core/src/
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
if (typeof window !== "undefined") _global = window;
|
|
9
|
-
else if (typeof global !== "undefined") _global = global;
|
|
10
|
-
else if (typeof self !== "undefined") _global = self;
|
|
11
|
-
else _global = {};
|
|
12
|
-
return _global;
|
|
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
|
+
import { apply, create as create$1, isDraft } from "mutative";
|
|
4
|
+
//#region packages/core/src/lifecycle.ts
|
|
5
|
+
const reportLifecycleError = (error) => {
|
|
6
|
+
if (process.env.NODE_ENV === "development") console.error(error);
|
|
13
7
|
};
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
8
|
+
const tryDestroyStore = (store) => {
|
|
9
|
+
try {
|
|
10
|
+
store.destroy?.();
|
|
11
|
+
} catch (error) {
|
|
12
|
+
reportLifecycleError(error);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const failStoreSetup = (store, error) => {
|
|
16
|
+
tryDestroyStore(store);
|
|
17
|
+
throw error;
|
|
18
|
+
};
|
|
19
|
+
const failTransportInitialization = (transport, error) => {
|
|
20
|
+
try {
|
|
21
|
+
transport?.dispose?.();
|
|
22
|
+
} catch (disposeError) {
|
|
23
|
+
reportLifecycleError(disposeError);
|
|
24
|
+
}
|
|
25
|
+
throw error;
|
|
26
|
+
};
|
|
27
|
+
const storeReadyRuntimeSymbol = Symbol.for("coaction.lifecycle.ready");
|
|
28
|
+
const getStoreReadyRuntime = (store, create = false) => {
|
|
29
|
+
const target = store;
|
|
30
|
+
const existing = target[storeReadyRuntimeSymbol];
|
|
31
|
+
if (existing || !create) return existing;
|
|
32
|
+
const runtime = {
|
|
33
|
+
callbacks: /* @__PURE__ */ new Set(),
|
|
34
|
+
ready: false
|
|
35
|
+
};
|
|
36
|
+
Object.defineProperty(target, storeReadyRuntimeSymbol, {
|
|
37
|
+
configurable: true,
|
|
38
|
+
enumerable: true,
|
|
39
|
+
value: runtime,
|
|
40
|
+
writable: true
|
|
41
|
+
});
|
|
42
|
+
return runtime;
|
|
43
|
+
};
|
|
44
|
+
const onStoreReady = (store, callback) => {
|
|
45
|
+
const runtime = getStoreReadyRuntime(store, true);
|
|
46
|
+
if (runtime.ready) {
|
|
47
|
+
callback();
|
|
48
|
+
return () => void 0;
|
|
49
|
+
}
|
|
50
|
+
runtime.callbacks.add(callback);
|
|
51
|
+
return () => {
|
|
52
|
+
runtime.callbacks.delete(callback);
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
const markStoreReady = (store) => {
|
|
56
|
+
const runtime = getStoreReadyRuntime(store, true);
|
|
57
|
+
if (runtime.ready) return;
|
|
58
|
+
runtime.ready = true;
|
|
59
|
+
const callbacks = [...runtime.callbacks];
|
|
60
|
+
runtime.callbacks.clear();
|
|
61
|
+
callbacks.forEach((callback) => callback());
|
|
32
62
|
};
|
|
33
63
|
//#endregion
|
|
34
64
|
//#region packages/core/src/utils.ts
|
|
@@ -63,9 +93,10 @@ const warnDroppedUnsafePatches = (unsafePatches, source) => {
|
|
|
63
93
|
};
|
|
64
94
|
const sanitizePatches = (patches, options = {}) => {
|
|
65
95
|
if (options.warnOnDropped) warnDroppedUnsafePatches(getUnsafePatchPaths(patches), options.source ?? "patches");
|
|
96
|
+
const seen = /* @__PURE__ */ new WeakMap();
|
|
66
97
|
return patches?.filter((patch) => !hasUnsafePatchPath(patch.path)).map((patch) => Object.prototype.hasOwnProperty.call(patch, "value") ? {
|
|
67
98
|
...patch,
|
|
68
|
-
value: sanitizeReplacementState(patch.value)
|
|
99
|
+
value: sanitizeReplacementState(patch.value, seen)
|
|
69
100
|
} : patch);
|
|
70
101
|
};
|
|
71
102
|
const sanitizeCheckedPatches = (patches, source) => {
|
|
@@ -120,47 +151,6 @@ const createRootReplacementPatches = (currentState, nextState) => {
|
|
|
120
151
|
inversePatches
|
|
121
152
|
};
|
|
122
153
|
};
|
|
123
|
-
const createRootStateFromPatches = (currentState, patches) => {
|
|
124
|
-
const nextState = sanitizeReplacementState(currentState);
|
|
125
|
-
const seen = /* @__PURE__ */ new WeakMap();
|
|
126
|
-
for (const patch of patches) {
|
|
127
|
-
if (!Array.isArray(patch.path) || patch.path.length !== 1 || ![
|
|
128
|
-
"add",
|
|
129
|
-
"remove",
|
|
130
|
-
"replace"
|
|
131
|
-
].includes(patch.op)) return;
|
|
132
|
-
const key = patch.path[0];
|
|
133
|
-
if (patch.op === "remove") {
|
|
134
|
-
delete nextState[key];
|
|
135
|
-
continue;
|
|
136
|
-
}
|
|
137
|
-
nextState[key] = sanitizeReplacementState(patch.value, seen);
|
|
138
|
-
}
|
|
139
|
-
return nextState;
|
|
140
|
-
};
|
|
141
|
-
const applyRootReplacementWithPatches = (store, nextState, options = {}) => {
|
|
142
|
-
const { patches, inversePatches } = createRootReplacementPatches(store.getPureState(), nextState);
|
|
143
|
-
const finalPatches = store.patch ? store.patch({
|
|
144
|
-
patches,
|
|
145
|
-
inversePatches
|
|
146
|
-
}) : {
|
|
147
|
-
patches,
|
|
148
|
-
inversePatches
|
|
149
|
-
};
|
|
150
|
-
const safePatches = sanitizeCheckedPatches(finalPatches.patches, "store.patch()");
|
|
151
|
-
const safeInversePatches = sanitizeCheckedPatches(finalPatches.inversePatches, "store.patch() inverse patches");
|
|
152
|
-
if (safePatches.length) {
|
|
153
|
-
const applyExactReplacement = options.applyExactReplacement;
|
|
154
|
-
const exactReplacementState = applyExactReplacement ? createRootStateFromPatches(store.getPureState(), safePatches) : void 0;
|
|
155
|
-
if (applyExactReplacement && exactReplacementState) applyExactReplacement(exactReplacementState);
|
|
156
|
-
else store.apply(store.getPureState(), safePatches);
|
|
157
|
-
}
|
|
158
|
-
return [
|
|
159
|
-
store.getPureState(),
|
|
160
|
-
safePatches,
|
|
161
|
-
safeInversePatches
|
|
162
|
-
];
|
|
163
|
-
};
|
|
164
154
|
const setOwnEnumerable = (target, key, value) => {
|
|
165
155
|
if (typeof key === "string" && isUnsafeKey(key)) return;
|
|
166
156
|
target[key] = value;
|
|
@@ -221,7 +211,7 @@ const assertKnownStateShape = (source, rootState, schema, isSliceStore, options
|
|
|
221
211
|
for (const sliceKey of getOwnEnumerableKeys(slice)) assertKnownSchemaKey(knownSliceKeys, sliceKey, [key]);
|
|
222
212
|
}
|
|
223
213
|
};
|
|
224
|
-
const isArrayIndexKey
|
|
214
|
+
const isArrayIndexKey = (key) => {
|
|
225
215
|
if (typeof key !== "string") return false;
|
|
226
216
|
const index = Number(key);
|
|
227
217
|
return Number.isInteger(index) && index >= 0 && index < 2 ** 32 - 1 && String(index) === key;
|
|
@@ -230,20 +220,6 @@ const assignOwnEnumerable = (target, source, seen = /* @__PURE__ */ new WeakMap(
|
|
|
230
220
|
if (!seen.has(source)) seen.set(source, target);
|
|
231
221
|
for (const key of getOwnEnumerableKeys(source)) setOwnEnumerable(target, key, sanitizeReplacementState(source[key], seen));
|
|
232
222
|
};
|
|
233
|
-
const replaceOwnEnumerable = (target, source) => {
|
|
234
|
-
const seen = /* @__PURE__ */ new WeakMap();
|
|
235
|
-
seen.set(source, target);
|
|
236
|
-
const nextKeys = /* @__PURE__ */ new Set();
|
|
237
|
-
for (const key of getOwnEnumerableKeys(source)) {
|
|
238
|
-
if (typeof key === "string" && isUnsafeKey(key)) continue;
|
|
239
|
-
if (typeof source[key] === "function") continue;
|
|
240
|
-
nextKeys.add(key);
|
|
241
|
-
}
|
|
242
|
-
for (const key of getOwnEnumerableKeys(target)) if (!nextKeys.has(key)) delete target[key];
|
|
243
|
-
nextKeys.forEach((key) => {
|
|
244
|
-
setOwnEnumerable(target, key, sanitizeReplacementState(source[key], seen));
|
|
245
|
-
});
|
|
246
|
-
};
|
|
247
223
|
const cloneOwnEnumerable = (source) => {
|
|
248
224
|
const target = {};
|
|
249
225
|
assignOwnEnumerable(target, source);
|
|
@@ -259,7 +235,7 @@ const sanitizeReplacementState = (source, seen = /* @__PURE__ */ new WeakMap())
|
|
|
259
235
|
seen.set(source, target);
|
|
260
236
|
for (let index = 0; index < source.length; index += 1) if (Object.prototype.hasOwnProperty.call(source, index)) target[index] = sanitizeReplacementState(source[index], seen);
|
|
261
237
|
for (const key of getOwnEnumerableKeys(source)) {
|
|
262
|
-
if (isArrayIndexKey
|
|
238
|
+
if (isArrayIndexKey(key) || typeof key === "string" && isUnsafeKey(key)) continue;
|
|
263
239
|
const value = source[key];
|
|
264
240
|
if (typeof value === "function") continue;
|
|
265
241
|
setOwnEnumerable(target, key, sanitizeReplacementState(value, seen));
|
|
@@ -288,7 +264,7 @@ const sanitizeInitialStateValue = (source, seen = /* @__PURE__ */ new WeakMap())
|
|
|
288
264
|
seen.set(source, target);
|
|
289
265
|
for (let index = 0; index < source.length; index += 1) if (Object.prototype.hasOwnProperty.call(source, index)) target[index] = sanitizeInitialStateValue(source[index], seen);
|
|
290
266
|
for (const key of getOwnEnumerableKeys(source)) {
|
|
291
|
-
if (isArrayIndexKey
|
|
267
|
+
if (isArrayIndexKey(key) || typeof key === "string" && isUnsafeKey(key)) continue;
|
|
292
268
|
setOwnEnumerable(target, key, sanitizeInitialStateValue(source[key], seen));
|
|
293
269
|
}
|
|
294
270
|
return target;
|
|
@@ -333,320 +309,628 @@ const uuid = () => {
|
|
|
333
309
|
});
|
|
334
310
|
};
|
|
335
311
|
//#endregion
|
|
312
|
+
//#region packages/core/src/computed.ts
|
|
313
|
+
const isObjectLike = (value) => typeof value === "object" && value !== null;
|
|
314
|
+
const runComputedRead = (internal, read) => {
|
|
315
|
+
internal.computedReadDepth = (internal.computedReadDepth ?? 0) + 1;
|
|
316
|
+
try {
|
|
317
|
+
return read();
|
|
318
|
+
} finally {
|
|
319
|
+
internal.computedReadDepth -= 1;
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
var Computed = class {
|
|
323
|
+
deps;
|
|
324
|
+
fn;
|
|
325
|
+
constructor(deps, fn) {
|
|
326
|
+
this.deps = deps;
|
|
327
|
+
this.fn = fn;
|
|
328
|
+
}
|
|
329
|
+
createGetter({ internal }) {
|
|
330
|
+
const memoByReceiver = /* @__PURE__ */ new WeakMap();
|
|
331
|
+
const lastArgs = /* @__PURE__ */ new WeakMap();
|
|
332
|
+
const lastResult = /* @__PURE__ */ new WeakMap();
|
|
333
|
+
const fallbackReceiver = {};
|
|
334
|
+
const evaluate = (receiver) => {
|
|
335
|
+
const args = this.deps(internal.module);
|
|
336
|
+
if (!lastArgs.has(receiver) || !areShallowEqualWithArray(lastArgs.get(receiver), args)) lastResult.set(receiver, this.fn.apply(receiver, args));
|
|
337
|
+
lastArgs.set(receiver, args);
|
|
338
|
+
return lastResult.get(receiver);
|
|
339
|
+
};
|
|
340
|
+
return function() {
|
|
341
|
+
const receiver = typeof this === "object" && this !== null ? this : fallbackReceiver;
|
|
342
|
+
if (internal.isBatching) return evaluate(receiver);
|
|
343
|
+
let accessor = memoByReceiver.get(receiver);
|
|
344
|
+
if (!accessor) {
|
|
345
|
+
accessor = computed$1(() => runComputedRead(internal, () => evaluate(receiver)));
|
|
346
|
+
memoByReceiver.set(receiver, accessor);
|
|
347
|
+
}
|
|
348
|
+
return accessor();
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
const createCachedGetter = (internal, getter) => {
|
|
353
|
+
const accessors = /* @__PURE__ */ new WeakMap();
|
|
354
|
+
const fallbackReceiver = {};
|
|
355
|
+
return function() {
|
|
356
|
+
const receiver = typeof this === "object" && this !== null ? this : fallbackReceiver;
|
|
357
|
+
if (internal.isBatching) return getter.call(receiver);
|
|
358
|
+
let accessor = accessors.get(receiver);
|
|
359
|
+
if (!accessor) {
|
|
360
|
+
accessor = computed$1(() => runComputedRead(internal, () => getter.call(receiver)));
|
|
361
|
+
accessors.set(receiver, accessor);
|
|
362
|
+
}
|
|
363
|
+
return accessor();
|
|
364
|
+
};
|
|
365
|
+
};
|
|
366
|
+
const createTrackedStateReader = (internal, read, initialValue) => {
|
|
367
|
+
const slotSignal = signal$1(initialValue);
|
|
368
|
+
const slotVersionSignal = signal$1(0);
|
|
369
|
+
let slotVersion = 0;
|
|
370
|
+
(internal.signalSlots ??= /* @__PURE__ */ new Set()).add({ refresh: () => {
|
|
371
|
+
const nextValue = read();
|
|
372
|
+
slotSignal(nextValue);
|
|
373
|
+
if (internal.mutableInstance && isObjectLike(nextValue)) {
|
|
374
|
+
slotVersion += 1;
|
|
375
|
+
slotVersionSignal(slotVersion);
|
|
376
|
+
}
|
|
377
|
+
} });
|
|
378
|
+
return () => {
|
|
379
|
+
const currentValue = slotSignal();
|
|
380
|
+
if (internal.mutableInstance && isObjectLike(currentValue)) slotVersionSignal();
|
|
381
|
+
return read();
|
|
382
|
+
};
|
|
383
|
+
};
|
|
384
|
+
const refreshSignalSlots = (internal) => {
|
|
385
|
+
if (!internal.signalSlots?.size) return;
|
|
386
|
+
startBatch$1();
|
|
387
|
+
try {
|
|
388
|
+
internal.signalSlots.forEach((slot) => slot.refresh());
|
|
389
|
+
} finally {
|
|
390
|
+
endBatch$1();
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
//#endregion
|
|
336
394
|
//#region packages/core/src/sharedState.ts
|
|
337
|
-
const
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
|
|
395
|
+
const formatPath = (path) => path.length ? path.map((key) => String(key)).join(".") : "<root>";
|
|
396
|
+
const unsupported = (label, path) => {
|
|
397
|
+
throw new TypeError(`${label} is not supported in shared store mode because transport synchronization uses JSON. Found unsupported value at ${formatPath(path)}.`);
|
|
398
|
+
};
|
|
399
|
+
const getDescriptors = (value, path) => {
|
|
400
|
+
try {
|
|
401
|
+
return Object.getOwnPropertyDescriptors(value);
|
|
402
|
+
} catch {
|
|
403
|
+
return unsupported("Uninspectable state", path);
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
const getPrototype = (value, path) => {
|
|
407
|
+
try {
|
|
408
|
+
return Object.getPrototypeOf(value);
|
|
409
|
+
} catch {
|
|
410
|
+
return unsupported("Uninspectable state prototype", path);
|
|
411
|
+
}
|
|
341
412
|
};
|
|
342
|
-
const
|
|
343
|
-
|
|
413
|
+
const assertNoInheritedToJson = (prototype, path) => {
|
|
414
|
+
let current = prototype;
|
|
415
|
+
while (current) {
|
|
416
|
+
let descriptor;
|
|
417
|
+
try {
|
|
418
|
+
descriptor = Object.getOwnPropertyDescriptor(current, "toJSON");
|
|
419
|
+
} catch {
|
|
420
|
+
unsupported("Uninspectable inherited toJSON state", path);
|
|
421
|
+
}
|
|
422
|
+
if (descriptor) {
|
|
423
|
+
if (!Object.prototype.hasOwnProperty.call(descriptor, "value") || typeof descriptor.value === "function") unsupported("Inherited toJSON state", path);
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
current = getPrototype(current, path);
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
const isArrayIndex = (key, length) => {
|
|
344
430
|
const index = Number(key);
|
|
345
|
-
return Number.
|
|
346
|
-
};
|
|
347
|
-
const
|
|
348
|
-
|
|
349
|
-
if (
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
431
|
+
return key !== "" && Number.isSafeInteger(index) && index >= 0 && index < length && String(index) === key;
|
|
432
|
+
};
|
|
433
|
+
const pushDataProperty = (work, descriptor, key, path, actionRoot = false) => {
|
|
434
|
+
const nextPath = [...path, key];
|
|
435
|
+
if (!descriptor) return unsupported("Sparse array state", nextPath);
|
|
436
|
+
if (!descriptor.enumerable) return unsupported("Non-enumerable data state", nextPath);
|
|
437
|
+
if (!Object.prototype.hasOwnProperty.call(descriptor, "value")) return unsupported("Accessor-backed state", nextPath);
|
|
438
|
+
work.push({
|
|
439
|
+
actionRoot,
|
|
440
|
+
path: nextPath,
|
|
441
|
+
value: descriptor.value
|
|
442
|
+
});
|
|
443
|
+
};
|
|
444
|
+
const assertSharedJsonWork = (work, isSliceStore = false) => {
|
|
445
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
446
|
+
while (work.length) {
|
|
447
|
+
const { actionRoot = false, path, value } = work.pop();
|
|
448
|
+
if (value === null) continue;
|
|
449
|
+
switch (typeof value) {
|
|
450
|
+
case "string":
|
|
451
|
+
case "boolean": continue;
|
|
452
|
+
case "number":
|
|
453
|
+
if (!Number.isFinite(value)) unsupported("NaN or infinite number state", path);
|
|
454
|
+
if (Object.is(value, -0)) unsupported("Negative zero state", path);
|
|
455
|
+
continue;
|
|
456
|
+
case "bigint": unsupported("BigInt-valued state", path);
|
|
457
|
+
case "undefined": unsupported("Undefined-valued state", path);
|
|
458
|
+
case "function": unsupported("Function-valued state", path);
|
|
459
|
+
case "symbol": throw new TypeError(`Symbol-valued state is not supported in shared store mode because transport synchronization uses JSON. Found symbol value at ${formatPath(path)}.`);
|
|
460
|
+
default: break;
|
|
461
|
+
}
|
|
462
|
+
const object = value;
|
|
463
|
+
if (seen.has(object)) unsupported("Repeated state reference", path);
|
|
464
|
+
seen.add(object);
|
|
465
|
+
const descriptors = getDescriptors(object, path);
|
|
466
|
+
if (Array.isArray(object)) {
|
|
467
|
+
const prototype = getPrototype(object, path);
|
|
468
|
+
if (prototype !== Array.prototype) unsupported("Non-plain array state", path);
|
|
469
|
+
assertNoInheritedToJson(prototype, path);
|
|
470
|
+
const length = descriptors.length?.value;
|
|
471
|
+
if (!Number.isSafeInteger(length) || length < 0) unsupported("Invalid array state", path);
|
|
472
|
+
for (const key of Reflect.ownKeys(descriptors)) {
|
|
473
|
+
if (key === "length") continue;
|
|
474
|
+
if (typeof key === "symbol") throw new TypeError(`Symbol-keyed state is not supported in shared store mode because transport synchronization uses JSON and string action paths. Found symbol key at ${formatPath([...path, key])}.`);
|
|
475
|
+
if (!isArrayIndex(key, length)) unsupported("Non-index array property state", [...path, key]);
|
|
476
|
+
}
|
|
477
|
+
for (let index = 0; index < length; index += 1) pushDataProperty(work, descriptors[index], index, path);
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
const prototype = getPrototype(object, path);
|
|
481
|
+
if (prototype !== Object.prototype && prototype !== null) unsupported("Non-plain object state", path);
|
|
482
|
+
assertNoInheritedToJson(prototype, path);
|
|
483
|
+
for (const key of Reflect.ownKeys(descriptors)) {
|
|
484
|
+
if (typeof key === "symbol") throw new TypeError(`Symbol-keyed state is not supported in shared store mode because transport synchronization uses JSON and string action paths. Found symbol key at ${formatPath([...path, key])}.`);
|
|
485
|
+
if (isUnsafeKey(key)) unsupported("Unsafe-keyed state", [...path, key]);
|
|
486
|
+
const descriptor = descriptors[key];
|
|
487
|
+
if (actionRoot && descriptor) {
|
|
488
|
+
const isDataProperty = Object.prototype.hasOwnProperty.call(descriptor, "value");
|
|
489
|
+
if (isDataProperty && typeof descriptor.value === "function") continue;
|
|
490
|
+
if (actionRoot === "initial" && (!isDataProperty || descriptor.value instanceof Computed)) continue;
|
|
491
|
+
}
|
|
492
|
+
pushDataProperty(work, descriptor, key, path, isSliceStore && path.length === 0 ? "initial" : false);
|
|
362
493
|
}
|
|
363
494
|
}
|
|
364
495
|
};
|
|
365
|
-
const
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
496
|
+
const assertSharedJsonValue = (root) => {
|
|
497
|
+
assertSharedJsonWork([{
|
|
498
|
+
path: [],
|
|
499
|
+
value: root
|
|
500
|
+
}]);
|
|
501
|
+
};
|
|
502
|
+
const validateSharedInitialState = (root, isSliceStore = false) => {
|
|
503
|
+
assertSharedJsonWork([{
|
|
504
|
+
actionRoot: isSliceStore ? false : "initial",
|
|
505
|
+
path: [],
|
|
506
|
+
value: root
|
|
507
|
+
}], isSliceStore);
|
|
508
|
+
};
|
|
509
|
+
const validateSharedReplacementSource = (root) => {
|
|
510
|
+
if (typeof root !== "object" || root === null || Array.isArray(root)) unsupported("Non-record replacement state", []);
|
|
511
|
+
assertSharedJsonWork([{
|
|
512
|
+
actionRoot: "replacement",
|
|
513
|
+
path: [],
|
|
514
|
+
value: root
|
|
515
|
+
}]);
|
|
516
|
+
};
|
|
517
|
+
const encodeSharedJson = (value) => {
|
|
518
|
+
assertSharedJsonValue(value);
|
|
519
|
+
const encoded = JSON.stringify(value);
|
|
520
|
+
if (typeof encoded !== "string") throw new TypeError("Shared transport value could not be encoded as JSON.");
|
|
521
|
+
return encoded;
|
|
522
|
+
};
|
|
523
|
+
const decodeSharedJson = (encoded) => {
|
|
524
|
+
if (typeof encoded !== "string") throw new TypeError("Shared transport payload must be a JSON string.");
|
|
525
|
+
let value;
|
|
526
|
+
try {
|
|
527
|
+
value = JSON.parse(encoded);
|
|
528
|
+
} catch {
|
|
529
|
+
throw new TypeError("Shared transport payload is not valid JSON.");
|
|
388
530
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
if (
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
531
|
+
assertSharedJsonValue(value);
|
|
532
|
+
return value;
|
|
533
|
+
};
|
|
534
|
+
const validateSharedActionPaths = (state, isSliceStore = false) => {
|
|
535
|
+
const actions = /* @__PURE__ */ new Set();
|
|
536
|
+
const work = [{
|
|
537
|
+
actionRoot: !isSliceStore,
|
|
538
|
+
path: [],
|
|
539
|
+
value: state
|
|
540
|
+
}];
|
|
541
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
542
|
+
while (work.length) {
|
|
543
|
+
const { actionRoot, path, value } = work.pop();
|
|
544
|
+
if (typeof value !== "object" || value === null || seen.has(value)) continue;
|
|
545
|
+
seen.add(value);
|
|
546
|
+
const descriptors = getDescriptors(value, path);
|
|
547
|
+
for (const key of Reflect.ownKeys(descriptors)) {
|
|
548
|
+
if (typeof key === "symbol") throw new TypeError(`Symbol-keyed state is not supported in shared store mode because transport synchronization uses JSON and string action paths. Found symbol key at ${formatPath([...path, key])}.`);
|
|
549
|
+
const descriptor = descriptors[key];
|
|
550
|
+
if (descriptor && Object.prototype.hasOwnProperty.call(descriptor, "value")) {
|
|
551
|
+
const nextPath = [...path, key];
|
|
552
|
+
if (actionRoot && typeof descriptor.value === "function") {
|
|
553
|
+
actions.add(JSON.stringify(nextPath));
|
|
554
|
+
continue;
|
|
555
|
+
}
|
|
556
|
+
work.push({
|
|
557
|
+
actionRoot: isSliceStore && path.length === 0,
|
|
558
|
+
path: nextPath,
|
|
559
|
+
value: descriptor.value
|
|
560
|
+
});
|
|
561
|
+
}
|
|
412
562
|
}
|
|
413
|
-
ancestors.delete(value);
|
|
414
|
-
return;
|
|
415
563
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
564
|
+
return actions;
|
|
565
|
+
};
|
|
566
|
+
const validateSharedStateSerializable = assertSharedJsonValue;
|
|
567
|
+
const hasOwn = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
568
|
+
const asRecord = (value, message) => {
|
|
569
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new TypeError(message);
|
|
570
|
+
return value;
|
|
571
|
+
};
|
|
572
|
+
const decodeMessage = (encoded, type) => {
|
|
573
|
+
const message = asRecord(decodeSharedJson(encoded), "Invalid transport message");
|
|
574
|
+
if (message.v !== 1 || message.type !== type) throw new TypeError("Invalid transport message");
|
|
575
|
+
return message;
|
|
576
|
+
};
|
|
577
|
+
const readEpoch = (message) => {
|
|
578
|
+
if (typeof message.epoch !== "string" || message.epoch.length === 0) throw new TypeError("Invalid transport epoch");
|
|
579
|
+
return message.epoch;
|
|
580
|
+
};
|
|
581
|
+
const readSequence = (message) => {
|
|
582
|
+
if (typeof message.sequence !== "number" || !Number.isSafeInteger(message.sequence) || message.sequence < 0) throw new TypeError("Invalid transport sequence");
|
|
583
|
+
return message.sequence;
|
|
584
|
+
};
|
|
585
|
+
const readAction = (value) => {
|
|
586
|
+
if (!Array.isArray(value) || value.length === 0 || value.some((key) => typeof key !== "string" || isUnsafePathSegment(key))) throw new TypeError("Invalid transport action");
|
|
587
|
+
return [...value];
|
|
588
|
+
};
|
|
589
|
+
const readPath = (value, { allowUnsafe = false } = {}) => {
|
|
590
|
+
if (!Array.isArray(value) || value.length === 0) throw new TypeError("Invalid transport patch path");
|
|
591
|
+
const path = [];
|
|
592
|
+
for (const segment of value) {
|
|
593
|
+
if (typeof segment !== "string" && (typeof segment !== "number" || !Number.isSafeInteger(segment) || segment < 0) || !allowUnsafe && isUnsafePathSegment(segment)) throw new TypeError("Invalid transport patch path");
|
|
594
|
+
path.push(segment);
|
|
595
|
+
}
|
|
596
|
+
return path;
|
|
597
|
+
};
|
|
598
|
+
const readPatches = (value, options = {}) => {
|
|
599
|
+
if (!Array.isArray(value)) throw new TypeError("Invalid transport patches");
|
|
600
|
+
return value.map((candidate) => {
|
|
601
|
+
const patch = asRecord(candidate, "Invalid transport patch");
|
|
602
|
+
const path = readPath(patch.path, { allowUnsafe: options.allowUnsafePaths });
|
|
603
|
+
if (patch.op === "remove") {
|
|
604
|
+
if (hasOwn(patch, "value")) throw new TypeError("Invalid remove patch");
|
|
605
|
+
return {
|
|
606
|
+
op: "remove",
|
|
607
|
+
path
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
if (patch.op !== "add" && patch.op !== "replace" || !hasOwn(patch, "value")) throw new TypeError("Invalid transport patch");
|
|
611
|
+
return {
|
|
612
|
+
op: patch.op,
|
|
613
|
+
path,
|
|
614
|
+
value: patch.value
|
|
615
|
+
};
|
|
616
|
+
});
|
|
617
|
+
};
|
|
618
|
+
const validateUpdatePatches = (patches) => {
|
|
619
|
+
assertSharedJsonValue(patches);
|
|
620
|
+
readPatches(patches, { allowUnsafePaths: true });
|
|
621
|
+
};
|
|
622
|
+
const encodeExecuteRequest = (action, args) => encodeSharedJson({
|
|
623
|
+
action: readAction([...action]),
|
|
624
|
+
args,
|
|
625
|
+
type: "execute",
|
|
626
|
+
v: 1
|
|
627
|
+
});
|
|
628
|
+
const decodeExecuteRequest = (encoded) => {
|
|
629
|
+
const message = decodeMessage(encoded, "execute");
|
|
630
|
+
if (!Array.isArray(message.args)) throw new TypeError("Invalid transport arguments");
|
|
631
|
+
return {
|
|
632
|
+
action: readAction(message.action),
|
|
633
|
+
args: [...message.args]
|
|
419
634
|
};
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
635
|
+
};
|
|
636
|
+
const encodeExecuteResponse = (response) => encodeSharedJson({
|
|
637
|
+
...response,
|
|
638
|
+
type: "execute-result",
|
|
639
|
+
v: 1
|
|
640
|
+
});
|
|
641
|
+
const decodeExecuteResponse = (encoded) => {
|
|
642
|
+
const message = decodeMessage(encoded, "execute-result");
|
|
643
|
+
const base = {
|
|
644
|
+
epoch: readEpoch(message),
|
|
645
|
+
sequence: readSequence(message)
|
|
646
|
+
};
|
|
647
|
+
if (message.ok === true) return hasOwn(message, "value") ? {
|
|
648
|
+
...base,
|
|
649
|
+
ok: true,
|
|
650
|
+
value: message.value
|
|
651
|
+
} : {
|
|
652
|
+
...base,
|
|
653
|
+
ok: true
|
|
654
|
+
};
|
|
655
|
+
if (message.ok !== false || typeof message.error !== "string" || message.error.length === 0) throw new TypeError("Invalid execute response");
|
|
656
|
+
return {
|
|
657
|
+
...base,
|
|
658
|
+
error: message.error,
|
|
659
|
+
ok: false
|
|
660
|
+
};
|
|
661
|
+
};
|
|
662
|
+
const encodeFullSyncRequest = () => encodeSharedJson({
|
|
663
|
+
type: "full-sync",
|
|
664
|
+
v: 1
|
|
665
|
+
});
|
|
666
|
+
const decodeFullSyncRequest = (encoded) => {
|
|
667
|
+
decodeMessage(encoded, "full-sync");
|
|
668
|
+
};
|
|
669
|
+
const encodeFullSyncResponse = (response) => encodeSharedJson({
|
|
670
|
+
...response,
|
|
671
|
+
type: "full-sync-result",
|
|
672
|
+
v: 1
|
|
673
|
+
});
|
|
674
|
+
const decodeFullSyncResponse = (encoded) => {
|
|
675
|
+
const message = decodeMessage(encoded, "full-sync-result");
|
|
676
|
+
return {
|
|
677
|
+
epoch: readEpoch(message),
|
|
678
|
+
sequence: readSequence(message),
|
|
679
|
+
state: asRecord(message.state, "Invalid fullSync state")
|
|
423
680
|
};
|
|
424
|
-
ancestors.add(value);
|
|
425
|
-
for (const key of getOwnEnumerableKeys(value)) {
|
|
426
|
-
const nextPath = [...path, key];
|
|
427
|
-
if (typeof key === "symbol") return {
|
|
428
|
-
type: "symbol-key",
|
|
429
|
-
path: nextPath
|
|
430
|
-
};
|
|
431
|
-
const child = value[key];
|
|
432
|
-
const violation = findJsonViolation(child, nextPath, ancestors);
|
|
433
|
-
if (violation) return violation;
|
|
434
|
-
}
|
|
435
|
-
ancestors.delete(value);
|
|
436
|
-
};
|
|
437
|
-
const getViolationLabel = (violation) => {
|
|
438
|
-
switch (violation.type) {
|
|
439
|
-
case "bigint": return "BigInt-valued state";
|
|
440
|
-
case "undefined": return "Undefined-valued state";
|
|
441
|
-
case "function": return "Function-valued state";
|
|
442
|
-
case "non-finite-number": return "NaN or infinite number state";
|
|
443
|
-
case "non-plain-object": return "Non-plain object state";
|
|
444
|
-
case "circular-reference": return "Circular state reference";
|
|
445
|
-
case "array-hole": return "Sparse array state";
|
|
446
|
-
case "array-property": return "Non-index array property state";
|
|
447
|
-
case "to-json": return "Custom toJSON state";
|
|
448
|
-
default: return;
|
|
449
|
-
}
|
|
450
681
|
};
|
|
451
|
-
const
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
682
|
+
const encodeUpdateMessage = (epoch, sequence, patches) => {
|
|
683
|
+
return encodeSharedJson({
|
|
684
|
+
epoch,
|
|
685
|
+
patches: readPatches(patches.map((patch) => patch.op === "remove" ? {
|
|
686
|
+
op: patch.op,
|
|
687
|
+
path: patch.path
|
|
688
|
+
} : {
|
|
689
|
+
op: patch.op,
|
|
690
|
+
path: patch.path,
|
|
691
|
+
value: patch.value
|
|
692
|
+
})),
|
|
693
|
+
sequence,
|
|
694
|
+
type: "update",
|
|
695
|
+
v: 1
|
|
696
|
+
});
|
|
455
697
|
};
|
|
456
|
-
const
|
|
457
|
-
const
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
698
|
+
const decodeUpdateMessage = (encoded) => {
|
|
699
|
+
const message = decodeMessage(encoded, "update");
|
|
700
|
+
return {
|
|
701
|
+
epoch: readEpoch(message),
|
|
702
|
+
patches: readPatches(message.patches),
|
|
703
|
+
sequence: readSequence(message)
|
|
704
|
+
};
|
|
462
705
|
};
|
|
463
706
|
//#endregion
|
|
464
|
-
//#region packages/core/src/
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
707
|
+
//#region packages/core/src/wrapStore.ts
|
|
708
|
+
/**
|
|
709
|
+
* Convert a store object into Coaction's callable store shape.
|
|
710
|
+
*
|
|
711
|
+
* @remarks
|
|
712
|
+
* Framework bindings use this to attach selector-aware readers while
|
|
713
|
+
* preserving the underlying store API on the returned function object. Most
|
|
714
|
+
* applications should use a public `create` entry instead of calling
|
|
715
|
+
* `wrapStore()` directly. Framework authors import this helper from
|
|
716
|
+
* `coaction/local` or `coaction/adapter`.
|
|
717
|
+
*/
|
|
718
|
+
const wrapStore = (store, getState = () => store.getState()) => {
|
|
719
|
+
const { name, ..._store } = store;
|
|
720
|
+
return Object.assign({ [name]: (...args) => getState(...args) }[name], _store);
|
|
469
721
|
};
|
|
722
|
+
//#endregion
|
|
723
|
+
//#region packages/core/src/asyncClientStore.ts
|
|
470
724
|
const clientApplyErrorMessage = "apply() cannot be called in the client store. Client stores are mirrors; use a store method to update the main store instead.";
|
|
471
|
-
const createAsyncClientStore = (createStore,
|
|
472
|
-
|
|
473
|
-
|
|
725
|
+
const createAsyncClientStore = (createStore, options) => {
|
|
726
|
+
let createdStore;
|
|
727
|
+
try {
|
|
728
|
+
createdStore = createStore({ share: "client" });
|
|
729
|
+
} catch (error) {
|
|
730
|
+
return failTransportInitialization(options.clientTransport, error);
|
|
731
|
+
}
|
|
732
|
+
const { store, internal } = createdStore;
|
|
733
|
+
let canApplyClientState = false;
|
|
474
734
|
const previousAssertMutationAllowed = internal.assertMutationAllowed;
|
|
475
735
|
internal.assertMutationAllowed = (operation) => {
|
|
476
|
-
if (operation === "apply"
|
|
736
|
+
if (operation === "apply") {
|
|
737
|
+
if (!canApplyClientState) throw new Error(clientApplyErrorMessage);
|
|
738
|
+
canApplyClientState = false;
|
|
739
|
+
}
|
|
477
740
|
previousAssertMutationAllowed?.(operation);
|
|
478
741
|
};
|
|
479
|
-
const baseApply =
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
return baseApply(state, patches);
|
|
742
|
+
const baseApply = store.apply.bind(store);
|
|
743
|
+
store.apply = () => {
|
|
744
|
+
throw new Error(clientApplyErrorMessage);
|
|
483
745
|
};
|
|
484
746
|
internal.applyClientState = (...args) => {
|
|
485
|
-
|
|
747
|
+
canApplyClientState = true;
|
|
486
748
|
try {
|
|
487
749
|
baseApply(...args);
|
|
488
750
|
} finally {
|
|
489
|
-
|
|
751
|
+
canApplyClientState = false;
|
|
490
752
|
}
|
|
491
753
|
};
|
|
492
|
-
const isSharedWorker = typeof SharedWorker !== "undefined" &&
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
syncingPromise = null;
|
|
514
|
-
});
|
|
515
|
-
return syncingPromise;
|
|
516
|
-
};
|
|
517
|
-
if (typeof transport.onConnect !== "function") throw new Error("transport.onConnect is required");
|
|
518
|
-
transport.onConnect?.(() => {
|
|
519
|
-
awaitingReconnectSync = true;
|
|
520
|
-
reconnectSequenceBaseline = internal.sequence;
|
|
521
|
-
fullSync(true).catch((error) => {
|
|
522
|
-
if (process.env.NODE_ENV === "development") console.error(error);
|
|
523
|
-
});
|
|
754
|
+
const isSharedWorker = typeof SharedWorker !== "undefined" && options.worker instanceof SharedWorker;
|
|
755
|
+
let transport;
|
|
756
|
+
try {
|
|
757
|
+
transport = options.worker ? createTransport(isSharedWorker ? "SharedWorkerClient" : "WebWorkerClient", {
|
|
758
|
+
worker: options.worker,
|
|
759
|
+
prefix: store.name
|
|
760
|
+
}) : options.clientTransport;
|
|
761
|
+
} catch (error) {
|
|
762
|
+
return failStoreSetup(store, error);
|
|
763
|
+
}
|
|
764
|
+
if (!transport) return failStoreSetup(store, /* @__PURE__ */ new Error("transport is required"));
|
|
765
|
+
try {
|
|
766
|
+
store.transport = transport;
|
|
767
|
+
if (typeof transport.onConnect !== "function") throw new Error("transport.onConnect is required");
|
|
768
|
+
} catch (error) {
|
|
769
|
+
return failStoreSetup(store, error);
|
|
770
|
+
}
|
|
771
|
+
const destroyedMarker = Symbol("destroyed client transport");
|
|
772
|
+
let resolveDestroyed;
|
|
773
|
+
const destroyedSignal = new Promise((resolve) => {
|
|
774
|
+
resolveDestroyed = () => resolve(destroyedMarker);
|
|
524
775
|
});
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
internal.sequence = options.sequence;
|
|
543
|
-
awaitingReconnectSync = false;
|
|
544
|
-
reconnectSequenceBaseline = null;
|
|
545
|
-
return;
|
|
546
|
-
} else {
|
|
547
|
-
shouldFullSync = true;
|
|
548
|
-
allowLowerSequence = awaitingReconnectSync;
|
|
549
|
-
}
|
|
550
|
-
if (shouldFullSync) await fullSync(allowLowerSequence);
|
|
776
|
+
const disposers = /* @__PURE__ */ new Set();
|
|
777
|
+
let destroyed = false;
|
|
778
|
+
let connectGeneration = 0;
|
|
779
|
+
let connectSync = null;
|
|
780
|
+
let syncTail = Promise.resolve();
|
|
781
|
+
const registerDisposer = (value) => {
|
|
782
|
+
if (typeof value === "function") disposers.add(value);
|
|
783
|
+
};
|
|
784
|
+
const cleanup = () => {
|
|
785
|
+
if (destroyed) return;
|
|
786
|
+
destroyed = true;
|
|
787
|
+
connectGeneration += 1;
|
|
788
|
+
resolveDestroyed();
|
|
789
|
+
const callbacks = [...disposers];
|
|
790
|
+
disposers.clear();
|
|
791
|
+
for (const dispose of callbacks) try {
|
|
792
|
+
dispose();
|
|
551
793
|
} catch (error) {
|
|
552
|
-
|
|
553
|
-
await fullSync(awaitingReconnectSync);
|
|
554
|
-
} catch (syncError) {
|
|
555
|
-
if (process.env.NODE_ENV === "development") console.error(syncError);
|
|
556
|
-
}
|
|
557
|
-
if (process.env.NODE_ENV === "development") console.error(error);
|
|
794
|
+
reportLifecycleError(error);
|
|
558
795
|
}
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
internal.
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
796
|
+
};
|
|
797
|
+
const awaitActive = async (value) => {
|
|
798
|
+
const result = await Promise.race([Promise.resolve(value), destroyedSignal]);
|
|
799
|
+
if (result === destroyedMarker) throw new Error("Client transport was destroyed");
|
|
800
|
+
return result;
|
|
801
|
+
};
|
|
802
|
+
internal.awaitClientTransport = awaitActive;
|
|
803
|
+
const applyFullSync = (state, epoch, sequence) => {
|
|
804
|
+
const previousEpoch = internal.transportEpoch;
|
|
805
|
+
const previousSequence = internal.sequence;
|
|
806
|
+
internal.transportEpoch = epoch;
|
|
807
|
+
internal.sequence = sequence;
|
|
808
|
+
try {
|
|
809
|
+
internal.applyClientState(state);
|
|
810
|
+
} catch (error) {
|
|
811
|
+
internal.transportEpoch = previousEpoch;
|
|
812
|
+
internal.sequence = previousSequence;
|
|
813
|
+
throw error;
|
|
814
|
+
}
|
|
815
|
+
};
|
|
816
|
+
const fullSync = (expectedEpoch, minimumSequence = 0, generation = connectGeneration) => {
|
|
817
|
+
const execute = async () => {
|
|
818
|
+
if (destroyed || generation !== connectGeneration) return;
|
|
819
|
+
const encoded = await awaitActive(transport.emit("fullSync", encodeFullSyncRequest()));
|
|
820
|
+
if (destroyed || generation !== connectGeneration) return;
|
|
821
|
+
const snapshot = decodeFullSyncResponse(encoded);
|
|
822
|
+
if (expectedEpoch && snapshot.epoch !== expectedEpoch) throw new Error("Mismatched fullSync epoch");
|
|
823
|
+
if (snapshot.sequence < minimumSequence) throw new Error("Stale fullSync sequence");
|
|
824
|
+
if (snapshot.epoch === internal.transportEpoch && snapshot.sequence < internal.sequence) return;
|
|
825
|
+
applyFullSync(snapshot.state, snapshot.epoch, snapshot.sequence);
|
|
826
|
+
};
|
|
827
|
+
const run = syncTail.then(execute, execute);
|
|
828
|
+
syncTail = run.then(() => void 0, () => void 0);
|
|
829
|
+
return run;
|
|
830
|
+
};
|
|
831
|
+
internal.syncClientState = (expectedEpoch, minimumSequence) => fullSync(expectedEpoch, minimumSequence);
|
|
832
|
+
const applyUpdate = (update) => {
|
|
833
|
+
const previousEpoch = internal.transportEpoch;
|
|
834
|
+
const previousSequence = internal.sequence;
|
|
835
|
+
internal.transportEpoch = update.epoch;
|
|
836
|
+
internal.sequence = update.sequence;
|
|
837
|
+
try {
|
|
838
|
+
internal.applyClientState(void 0, update.patches);
|
|
839
|
+
} catch (error) {
|
|
840
|
+
internal.transportEpoch = previousEpoch;
|
|
841
|
+
internal.sequence = previousSequence;
|
|
842
|
+
throw error;
|
|
843
|
+
}
|
|
844
|
+
};
|
|
845
|
+
const handleUpdate = async (encoded) => {
|
|
846
|
+
if (destroyed) return;
|
|
847
|
+
const generation = connectGeneration;
|
|
848
|
+
const update = decodeUpdateMessage(encoded);
|
|
849
|
+
if (connectSync) await connectSync;
|
|
850
|
+
if (destroyed || generation !== connectGeneration) return;
|
|
851
|
+
if (update.epoch !== internal.transportEpoch) await fullSync(update.epoch, 0, generation);
|
|
852
|
+
if (destroyed || generation !== connectGeneration) return;
|
|
853
|
+
if (update.epoch !== internal.transportEpoch) throw new Error("Mismatched update epoch");
|
|
854
|
+
if (update.sequence <= internal.sequence) return;
|
|
855
|
+
if (update.sequence === internal.sequence + 1) {
|
|
856
|
+
applyUpdate(update);
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
await fullSync(update.epoch, update.sequence, generation);
|
|
860
|
+
};
|
|
861
|
+
internal.destroyCallbacks?.add(cleanup);
|
|
862
|
+
try {
|
|
863
|
+
registerDisposer(transport.listen("update", async (encoded) => {
|
|
864
|
+
try {
|
|
865
|
+
await handleUpdate(encoded);
|
|
866
|
+
} catch (error) {
|
|
867
|
+
if (!destroyed) {
|
|
868
|
+
try {
|
|
869
|
+
await fullSync();
|
|
870
|
+
} catch (syncError) {
|
|
871
|
+
reportLifecycleError(syncError);
|
|
872
|
+
}
|
|
873
|
+
reportLifecycleError(error);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}));
|
|
877
|
+
registerDisposer(transport.onConnect(() => {
|
|
878
|
+
const pending = fullSync(void 0, 0, ++connectGeneration).finally(() => {
|
|
879
|
+
if (connectSync === pending) connectSync = null;
|
|
880
|
+
});
|
|
881
|
+
connectSync = pending;
|
|
882
|
+
pending.catch(reportLifecycleError);
|
|
883
|
+
return pending;
|
|
884
|
+
}));
|
|
885
|
+
markStoreReady(store);
|
|
886
|
+
internal.assertAlive?.("store initialization");
|
|
887
|
+
} catch (error) {
|
|
888
|
+
return failStoreSetup(store, error);
|
|
577
889
|
}
|
|
890
|
+
return wrapStore(store, () => store.getState());
|
|
578
891
|
};
|
|
579
|
-
const
|
|
580
|
-
|
|
581
|
-
const
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
emit(store, internal, safePatches);
|
|
892
|
+
const emit = (store, internal, patches) => {
|
|
893
|
+
if (!store.transport || !patches?.length || !internal.transportEpoch) return;
|
|
894
|
+
const sequence = internal.sequence + 1;
|
|
895
|
+
const encoded = encodeUpdateMessage(internal.transportEpoch, sequence, patches);
|
|
896
|
+
internal.sequence = sequence;
|
|
897
|
+
try {
|
|
898
|
+
const pending = store.transport.emit({
|
|
899
|
+
name: "update",
|
|
900
|
+
respond: false
|
|
901
|
+
}, encoded);
|
|
902
|
+
Promise.resolve(pending).catch(reportLifecycleError);
|
|
903
|
+
} catch (error) {
|
|
904
|
+
reportLifecycleError(error);
|
|
593
905
|
}
|
|
594
906
|
};
|
|
595
907
|
//#endregion
|
|
596
|
-
//#region packages/core/src/
|
|
597
|
-
const
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
let state;
|
|
605
|
-
if (isStateFactory(stateOrFn)) state = stateOrFn(store.setState, store.getState, store);
|
|
606
|
-
else if (isObject(stateOrFn)) state = stateOrFn;
|
|
607
|
-
else {
|
|
608
|
-
if (process.env.NODE_ENV !== "production") throw new Error(formatInvalidStateMessage("value", stateOrFn, key));
|
|
609
|
-
return {};
|
|
610
|
-
}
|
|
611
|
-
if (hasGetState(state)) state = state.getState();
|
|
612
|
-
else if (typeof state === "function") state = state();
|
|
613
|
-
if (hasBindState(state)) {
|
|
614
|
-
if (store.isSliceStore) throw new Error("Third-party state binding does not support Slices mode. Please inject a whole store instead.");
|
|
615
|
-
const binder = state[bindSymbol];
|
|
616
|
-
const rawState = binder.bind(state);
|
|
617
|
-
binder.handleStore(store, rawState, state, internal, key);
|
|
618
|
-
delete state[bindSymbol];
|
|
619
|
-
return rawState;
|
|
620
|
-
}
|
|
621
|
-
if (!isObject(state)) {
|
|
622
|
-
if (process.env.NODE_ENV !== "production") throw new Error(formatInvalidStateMessage("result", state, key));
|
|
623
|
-
return {};
|
|
624
|
-
}
|
|
625
|
-
return state;
|
|
626
|
-
};
|
|
627
|
-
if (!store.isSliceStore) return makeState(createState);
|
|
628
|
-
return getOwnEnumerableKeys(createState).reduce((stateTree, key) => {
|
|
629
|
-
if (typeof key === "string" && isUnsafeKey(key)) return stateTree;
|
|
630
|
-
setOwnEnumerable(stateTree, key, makeState(createState[key], key));
|
|
631
|
-
return stateTree;
|
|
632
|
-
}, {});
|
|
908
|
+
//#region packages/core/src/global.ts
|
|
909
|
+
const getGlobal = () => {
|
|
910
|
+
let _global;
|
|
911
|
+
if (typeof window !== "undefined") _global = window;
|
|
912
|
+
else if (typeof global !== "undefined") _global = global;
|
|
913
|
+
else if (typeof self !== "undefined") _global = self;
|
|
914
|
+
else _global = {};
|
|
915
|
+
return _global;
|
|
633
916
|
};
|
|
634
917
|
//#endregion
|
|
918
|
+
//#region packages/core/src/constant.ts
|
|
919
|
+
const WorkerType = getGlobal().SharedWorkerGlobalScope ? "SharedWorkerInternal" : globalThis.WorkerGlobalScope ? "WebWorkerInternal" : null;
|
|
920
|
+
const bindSymbol = Symbol("bind");
|
|
921
|
+
//#endregion
|
|
635
922
|
//#region packages/core/src/getRawStateClientAction.ts
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
if (typeof value !== "object" || value === null) return false;
|
|
648
|
-
const candidate = value;
|
|
649
|
-
return typeof candidate.$$Error === "string" && candidate.$$Error.length > 0 && Object.keys(candidate).length === 1;
|
|
923
|
+
/**
|
|
924
|
+
* The authority changed while a remote action was in flight, so its side-effect
|
|
925
|
+
* outcome cannot be determined safely from the current client mirror.
|
|
926
|
+
*/
|
|
927
|
+
var ActionAuthorityChangedError = class extends Error {
|
|
928
|
+
code = "COACTION_ACTION_AUTHORITY_CHANGED";
|
|
929
|
+
outcome = "unknown";
|
|
930
|
+
constructor(action) {
|
|
931
|
+
super(`The authority changed while action '${action}' was in flight. The action may have completed on the previous authority; retry only if it is idempotent.`);
|
|
932
|
+
this.name = "ActionAuthorityChangedError";
|
|
933
|
+
}
|
|
650
934
|
};
|
|
651
935
|
const createClientAction = ({ clientExecuteSyncTimeoutMs, internal, key, store, sliceKey }) => {
|
|
652
936
|
return (...args) => {
|
|
@@ -688,58 +972,309 @@ const createClientAction = ({ clientExecuteSyncTimeoutMs, internal, key, store,
|
|
|
688
972
|
}
|
|
689
973
|
};
|
|
690
974
|
if (typeof sliceKey === "symbol") throw new Error("Symbol-keyed slice actions are not supported in client store mode.");
|
|
691
|
-
const
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
const
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
store.transport.emit("fullSync").then((latest) => {
|
|
722
|
-
if (typeof latest !== "object" || latest === null) throw new Error("Invalid fullSync payload");
|
|
723
|
-
const next = latest;
|
|
724
|
-
if (typeof next.state !== "string" || typeof next.sequence !== "number") throw new Error("Invalid fullSync payload");
|
|
725
|
-
if (next.sequence >= sequence) {
|
|
726
|
-
(internal.applyClientState ?? store.apply.bind(store))(parseFullSyncState(next.state));
|
|
727
|
-
internal.sequence = next.sequence;
|
|
728
|
-
finishResolve();
|
|
729
|
-
return;
|
|
730
|
-
}
|
|
731
|
-
finishReject(/* @__PURE__ */ new Error(`Stale fullSync sequence: expected >= ${sequence}, got ${next.sequence}`));
|
|
732
|
-
}).catch((error) => {
|
|
733
|
-
finishReject(error);
|
|
975
|
+
const encoded = encodeExecuteRequest(typeof sliceKey === "undefined" ? [key] : [String(sliceKey), key], args);
|
|
976
|
+
const requestEpoch = internal.transportEpoch;
|
|
977
|
+
return traceAction(() => {
|
|
978
|
+
const emitted = store.transport.emit("execute", encoded);
|
|
979
|
+
return (internal.awaitClientTransport ? internal.awaitClientTransport(emitted) : emitted).then(async (payload) => {
|
|
980
|
+
const response = decodeExecuteResponse(payload);
|
|
981
|
+
internal.assertAlive?.(`action ${key}`);
|
|
982
|
+
const syncClientState = internal.syncClientState;
|
|
983
|
+
if (!syncClientState) throw new Error("Client fullSync is not available");
|
|
984
|
+
if (internal.transportEpoch !== requestEpoch && response.epoch !== internal.transportEpoch) throw new ActionAuthorityChangedError(key);
|
|
985
|
+
if (response.epoch !== internal.transportEpoch) {
|
|
986
|
+
await syncClientState(response.epoch, response.sequence);
|
|
987
|
+
internal.assertAlive?.(`action ${key}`);
|
|
988
|
+
} else if (response.sequence > internal.sequence) {
|
|
989
|
+
await new Promise((resolve, reject) => {
|
|
990
|
+
let settled = false;
|
|
991
|
+
let unsubscribe = () => {};
|
|
992
|
+
let timeout;
|
|
993
|
+
const cancel = () => finish(/* @__PURE__ */ new Error("Client transport was destroyed"));
|
|
994
|
+
const finish = (error) => {
|
|
995
|
+
if (settled) return;
|
|
996
|
+
settled = true;
|
|
997
|
+
unsubscribe();
|
|
998
|
+
internal.destroyCallbacks?.delete(cancel);
|
|
999
|
+
if (timeout) clearTimeout(timeout);
|
|
1000
|
+
if (typeof error === "undefined") resolve();
|
|
1001
|
+
else reject(error);
|
|
1002
|
+
};
|
|
1003
|
+
unsubscribe = store.subscribe(() => {
|
|
1004
|
+
if (internal.transportEpoch === response.epoch && internal.sequence >= response.sequence) finish();
|
|
734
1005
|
});
|
|
735
|
-
|
|
1006
|
+
internal.destroyCallbacks?.add(cancel);
|
|
1007
|
+
timeout = setTimeout(() => {
|
|
1008
|
+
syncClientState(response.epoch, response.sequence).then(() => finish(), (error) => finish(error));
|
|
1009
|
+
}, clientExecuteSyncTimeoutMs);
|
|
1010
|
+
if (internal.transportEpoch === response.epoch && internal.sequence >= response.sequence) finish();
|
|
1011
|
+
});
|
|
1012
|
+
internal.assertAlive?.(`action ${key}`);
|
|
1013
|
+
}
|
|
1014
|
+
if (!response.ok) throw new Error(response.error);
|
|
1015
|
+
return response.value;
|
|
1016
|
+
});
|
|
1017
|
+
});
|
|
1018
|
+
};
|
|
1019
|
+
};
|
|
1020
|
+
//#endregion
|
|
1021
|
+
//#region packages/core/src/handleMainTransport.ts
|
|
1022
|
+
const publicErrorMessages = /* @__PURE__ */ new Set([
|
|
1023
|
+
"Remote action is not allowed",
|
|
1024
|
+
"The function is not found",
|
|
1025
|
+
"Transport request is not authorized",
|
|
1026
|
+
"Transport request was cancelled after store destroy"
|
|
1027
|
+
]);
|
|
1028
|
+
const getErrorMessage = async (error, request, policy) => {
|
|
1029
|
+
if (error instanceof Error && publicErrorMessages.has(error.message)) return error.message;
|
|
1030
|
+
if (request && policy?.mapError) try {
|
|
1031
|
+
const message = await policy.mapError(error, request);
|
|
1032
|
+
if (typeof message === "string" && message) return message;
|
|
1033
|
+
} catch (mapError) {
|
|
1034
|
+
if (process.env.NODE_ENV === "development") console.error(mapError);
|
|
1035
|
+
}
|
|
1036
|
+
return "Remote action failed";
|
|
1037
|
+
};
|
|
1038
|
+
const handleMainTransport = (store, internal, storeTransport, workerType, checkEnablePatches, policy) => {
|
|
1039
|
+
const transport = storeTransport ?? (workerType === "SharedWorkerInternal" || workerType === "WebWorkerInternal" ? createTransport(workerType, { prefix: store.name }) : void 0);
|
|
1040
|
+
if (!transport) return;
|
|
1041
|
+
if (checkEnablePatches) throw new Error("enablePatches: true is required for the transport");
|
|
1042
|
+
const epoch = uuid();
|
|
1043
|
+
internal.transportEpoch = epoch;
|
|
1044
|
+
let destroyed = false;
|
|
1045
|
+
const disposers = /* @__PURE__ */ new Set();
|
|
1046
|
+
const registerDisposer = (value) => {
|
|
1047
|
+
if (typeof value === "function") disposers.add(value);
|
|
1048
|
+
};
|
|
1049
|
+
const cleanup = () => {
|
|
1050
|
+
if (destroyed) return;
|
|
1051
|
+
destroyed = true;
|
|
1052
|
+
const callbacks = [...disposers];
|
|
1053
|
+
disposers.clear();
|
|
1054
|
+
for (const dispose of callbacks) try {
|
|
1055
|
+
dispose();
|
|
1056
|
+
} catch (error) {
|
|
1057
|
+
if (process.env.NODE_ENV === "development") console.error(error);
|
|
1058
|
+
}
|
|
1059
|
+
};
|
|
1060
|
+
const assertActive = () => {
|
|
1061
|
+
if (destroyed) throw new Error("Transport request was cancelled after store destroy");
|
|
1062
|
+
};
|
|
1063
|
+
store.transport = transport;
|
|
1064
|
+
internal.emitPatches = (patches) => emit(store, internal, patches);
|
|
1065
|
+
internal.destroyCallbacks?.add(cleanup);
|
|
1066
|
+
try {
|
|
1067
|
+
registerDisposer(transport.listen("execute", async (encoded) => {
|
|
1068
|
+
let policyRequest;
|
|
1069
|
+
try {
|
|
1070
|
+
assertActive();
|
|
1071
|
+
const request = decodeExecuteRequest(encoded);
|
|
1072
|
+
if (!internal.sharedActionPaths?.has(JSON.stringify(request.action))) throw new Error("Remote action is not allowed");
|
|
1073
|
+
if (policy?.allowedActions && !policy.allowedActions.some((allowed) => allowed.length === request.action.length && allowed.every((key, index) => key === request.action[index]))) throw new Error("Remote action is not allowed");
|
|
1074
|
+
policyRequest = {
|
|
1075
|
+
...request,
|
|
1076
|
+
type: "execute"
|
|
1077
|
+
};
|
|
1078
|
+
if (policy?.authorize && await policy.authorize(policyRequest) !== true) throw new Error("Transport request is not authorized");
|
|
1079
|
+
assertActive();
|
|
1080
|
+
let action = store.getState();
|
|
1081
|
+
let receiver;
|
|
1082
|
+
for (const key of request.action) {
|
|
1083
|
+
if (isUnsafePathSegment(key) || typeof action !== "object" && typeof action !== "function" || action === null || !Object.prototype.hasOwnProperty.call(action, key)) throw new Error("The function is not found");
|
|
1084
|
+
receiver = action;
|
|
1085
|
+
action = action[key];
|
|
1086
|
+
}
|
|
1087
|
+
if (typeof action !== "function") throw new Error("The function is not found");
|
|
1088
|
+
const value = await Reflect.apply(action, receiver, request.args);
|
|
1089
|
+
assertActive();
|
|
1090
|
+
return encodeExecuteResponse({
|
|
1091
|
+
epoch,
|
|
1092
|
+
ok: true,
|
|
1093
|
+
sequence: internal.sequence,
|
|
1094
|
+
...typeof value === "undefined" ? {} : { value }
|
|
1095
|
+
});
|
|
1096
|
+
} catch (error) {
|
|
1097
|
+
if (process.env.NODE_ENV === "development") console.error(error);
|
|
1098
|
+
return encodeExecuteResponse({
|
|
1099
|
+
epoch,
|
|
1100
|
+
error: await getErrorMessage(error, policyRequest, policy),
|
|
1101
|
+
ok: false,
|
|
1102
|
+
sequence: internal.sequence
|
|
736
1103
|
});
|
|
737
1104
|
}
|
|
738
|
-
if (isTransportErrorEnvelope(result)) throw new Error(result.message);
|
|
739
|
-
if (isLegacyTransportErrorEnvelope(result)) throw new Error(result.$$Error);
|
|
740
|
-
return result;
|
|
741
1105
|
}));
|
|
1106
|
+
registerDisposer(transport.listen("fullSync", async (encoded) => {
|
|
1107
|
+
assertActive();
|
|
1108
|
+
decodeFullSyncRequest(encoded);
|
|
1109
|
+
if (policy?.authorize && await policy.authorize({ type: "fullSync" }) !== true) throw new Error("Transport request is not authorized");
|
|
1110
|
+
assertActive();
|
|
1111
|
+
const state = internal.getTransportState?.() ?? internal.rootState;
|
|
1112
|
+
validateSharedStateSerializable(state);
|
|
1113
|
+
if (typeof state !== "object" || state === null || Array.isArray(state)) throw new TypeError("Shared store state must be a JSON object");
|
|
1114
|
+
return encodeFullSyncResponse({
|
|
1115
|
+
epoch,
|
|
1116
|
+
sequence: internal.sequence,
|
|
1117
|
+
state
|
|
1118
|
+
});
|
|
1119
|
+
}));
|
|
1120
|
+
} catch (error) {
|
|
1121
|
+
internal.destroyCallbacks?.delete(cleanup);
|
|
1122
|
+
cleanup();
|
|
1123
|
+
store.transport = void 0;
|
|
1124
|
+
try {
|
|
1125
|
+
transport.dispose?.();
|
|
1126
|
+
} catch (disposeError) {
|
|
1127
|
+
if (process.env.NODE_ENV === "development") console.error(disposeError);
|
|
1128
|
+
}
|
|
1129
|
+
throw error;
|
|
1130
|
+
}
|
|
1131
|
+
};
|
|
1132
|
+
//#endregion
|
|
1133
|
+
//#region packages/core/src/applyMiddlewares.ts
|
|
1134
|
+
const isStoreLike = (value) => {
|
|
1135
|
+
if (!value || typeof value !== "object") return false;
|
|
1136
|
+
const candidate = value;
|
|
1137
|
+
return typeof candidate.setState === "function" && typeof candidate.getState === "function" && typeof candidate.subscribe === "function" && typeof candidate.destroy === "function" && typeof candidate.apply === "function" && typeof candidate.getPureState === "function";
|
|
1138
|
+
};
|
|
1139
|
+
const applyMiddlewares = (store, middlewares) => {
|
|
1140
|
+
return middlewares.reduce((store, middleware, index) => {
|
|
1141
|
+
if (process.env.NODE_ENV === "development") {
|
|
1142
|
+
if (typeof middleware !== "function") throw new Error(`middlewares[${index}] should be a function`);
|
|
1143
|
+
}
|
|
1144
|
+
const nextStore = middleware(store);
|
|
1145
|
+
if (process.env.NODE_ENV === "development") {
|
|
1146
|
+
if (!isStoreLike(nextStore)) throw new Error(`middlewares[${index}] should return a store-like object`);
|
|
1147
|
+
}
|
|
1148
|
+
return nextStore;
|
|
1149
|
+
}, store);
|
|
1150
|
+
};
|
|
1151
|
+
//#endregion
|
|
1152
|
+
//#region packages/core/src/getInitialState.ts
|
|
1153
|
+
const isObject = (value) => typeof value === "object" && value !== null;
|
|
1154
|
+
const isStateFactory = (value) => typeof value === "function";
|
|
1155
|
+
const hasGetState = (value) => (typeof value === "object" || typeof value === "function") && value !== null && typeof value.getState === "function";
|
|
1156
|
+
const hasBindState = (value) => isObject(value) && !!value[bindSymbol];
|
|
1157
|
+
const formatInvalidStateMessage = (type, stateOrFn, key) => `Invalid state ${type} encountered in makeState: ${typeof key !== "undefined" ? `for key ${String(key)}, ` : ""}${typeof stateOrFn}`;
|
|
1158
|
+
const getInitialState = (store, createState, internal) => {
|
|
1159
|
+
const makeState = (stateOrFn, key) => {
|
|
1160
|
+
let state;
|
|
1161
|
+
if (isStateFactory(stateOrFn)) state = stateOrFn(store.setState, store.getState, store);
|
|
1162
|
+
else if (isObject(stateOrFn)) state = stateOrFn;
|
|
1163
|
+
else {
|
|
1164
|
+
if (process.env.NODE_ENV !== "production") throw new Error(formatInvalidStateMessage("value", stateOrFn, key));
|
|
1165
|
+
return {};
|
|
1166
|
+
}
|
|
1167
|
+
if (hasGetState(state)) state = state.getState();
|
|
1168
|
+
else if (typeof state === "function") state = state();
|
|
1169
|
+
if (hasBindState(state)) {
|
|
1170
|
+
if (store.isSliceStore) throw new Error("Third-party state binding does not support Slices mode. Please inject a whole store instead.");
|
|
1171
|
+
const binder = state[bindSymbol];
|
|
1172
|
+
const rawState = binder.bind(state);
|
|
1173
|
+
binder.handleStore(store, rawState, state, internal, key);
|
|
1174
|
+
delete state[bindSymbol];
|
|
1175
|
+
return rawState;
|
|
1176
|
+
}
|
|
1177
|
+
if (!isObject(state)) {
|
|
1178
|
+
if (process.env.NODE_ENV !== "production") throw new Error(formatInvalidStateMessage("result", state, key));
|
|
1179
|
+
return {};
|
|
1180
|
+
}
|
|
1181
|
+
return state;
|
|
1182
|
+
};
|
|
1183
|
+
if (!store.isSliceStore) return makeState(createState);
|
|
1184
|
+
return getOwnEnumerableKeys(createState).reduce((stateTree, key) => {
|
|
1185
|
+
if (typeof key === "string" && isUnsafeKey(key)) return stateTree;
|
|
1186
|
+
setOwnEnumerable(stateTree, key, makeState(createState[key], key));
|
|
1187
|
+
return stateTree;
|
|
1188
|
+
}, {});
|
|
1189
|
+
};
|
|
1190
|
+
//#endregion
|
|
1191
|
+
//#region packages/core/src/storeCommit.ts
|
|
1192
|
+
const storeCommitRuntimeSymbol = Symbol.for("coaction.storeCommit.runtime");
|
|
1193
|
+
const getStoreCommitRuntime = (store, create = false) => {
|
|
1194
|
+
const target = store;
|
|
1195
|
+
const existing = target[storeCommitRuntimeSymbol];
|
|
1196
|
+
if (existing || !create) return existing;
|
|
1197
|
+
const runtime = {
|
|
1198
|
+
disposed: false,
|
|
1199
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
1200
|
+
prepareListeners: /* @__PURE__ */ new Set()
|
|
1201
|
+
};
|
|
1202
|
+
Object.defineProperty(target, storeCommitRuntimeSymbol, {
|
|
1203
|
+
configurable: true,
|
|
1204
|
+
enumerable: true,
|
|
1205
|
+
value: runtime,
|
|
1206
|
+
writable: true
|
|
1207
|
+
});
|
|
1208
|
+
return runtime;
|
|
1209
|
+
};
|
|
1210
|
+
/** @internal */
|
|
1211
|
+
const hasStoreCommitListeners = (store) => Boolean(getStoreCommitRuntime(store)?.listeners.size);
|
|
1212
|
+
/** @internal */
|
|
1213
|
+
const publishStoreCommit = (store, commit) => {
|
|
1214
|
+
const runtime = getStoreCommitRuntime(store);
|
|
1215
|
+
if (!runtime || runtime.disposed || !runtime.listeners.size) return;
|
|
1216
|
+
for (const listener of [...runtime.listeners]) listener(commit);
|
|
1217
|
+
};
|
|
1218
|
+
/** @internal */
|
|
1219
|
+
const prepareStoreCommit = (store, commit) => {
|
|
1220
|
+
const runtime = getStoreCommitRuntime(store);
|
|
1221
|
+
if (!runtime || runtime.disposed || !runtime.prepareListeners.size) return false;
|
|
1222
|
+
let replace = false;
|
|
1223
|
+
for (const listener of runtime.prepareListeners) replace = listener(commit) === true || replace;
|
|
1224
|
+
return replace;
|
|
1225
|
+
};
|
|
1226
|
+
/** @internal */
|
|
1227
|
+
const getStoreCommitSource = (store, fallback) => getStoreCommitRuntime(store)?.source ?? fallback;
|
|
1228
|
+
/** @internal */
|
|
1229
|
+
const runWithStoreCommitSource = (store, source, callback) => {
|
|
1230
|
+
const runtime = getStoreCommitRuntime(store, true);
|
|
1231
|
+
const previousSource = runtime.source;
|
|
1232
|
+
runtime.source = source;
|
|
1233
|
+
try {
|
|
1234
|
+
return callback();
|
|
1235
|
+
} finally {
|
|
1236
|
+
runtime.source = previousSource;
|
|
1237
|
+
}
|
|
1238
|
+
};
|
|
1239
|
+
/** @internal */
|
|
1240
|
+
const registerStorePatchReplayer = (store, replay) => {
|
|
1241
|
+
const runtime = getStoreCommitRuntime(store, true);
|
|
1242
|
+
runtime.replay = replay;
|
|
1243
|
+
};
|
|
1244
|
+
/** @internal */
|
|
1245
|
+
const disposeStoreCommitRuntime = (store) => {
|
|
1246
|
+
const runtime = getStoreCommitRuntime(store);
|
|
1247
|
+
if (!runtime) return;
|
|
1248
|
+
runtime.disposed = true;
|
|
1249
|
+
runtime.listeners.clear();
|
|
1250
|
+
runtime.prepareListeners.clear();
|
|
1251
|
+
runtime.source = void 0;
|
|
1252
|
+
runtime.replay = void 0;
|
|
1253
|
+
};
|
|
1254
|
+
//#endregion
|
|
1255
|
+
//#region packages/core/src/handleDraft.ts
|
|
1256
|
+
const handleDraft = (store, internal) => {
|
|
1257
|
+
internal.rootState = internal.backupState;
|
|
1258
|
+
const [, patches, inversePatches] = internal.finalizeDraft();
|
|
1259
|
+
const finalPatches = store.patch ? store.patch({
|
|
1260
|
+
patches,
|
|
1261
|
+
inversePatches
|
|
1262
|
+
}) : {
|
|
1263
|
+
patches,
|
|
1264
|
+
inversePatches
|
|
742
1265
|
};
|
|
1266
|
+
const safePatches = sanitizeCheckedPatches(finalPatches.patches, "store.patch()");
|
|
1267
|
+
const safeInversePatches = sanitizeCheckedPatches(finalPatches.inversePatches, "store.patch() inverse patches");
|
|
1268
|
+
if (safePatches.length) {
|
|
1269
|
+
store.apply(internal.rootState, safePatches);
|
|
1270
|
+
internal.emitPatches?.(safePatches);
|
|
1271
|
+
publishStoreCommit(store, {
|
|
1272
|
+
state: internal.rootState,
|
|
1273
|
+
patches: safePatches,
|
|
1274
|
+
inversePatches: safeInversePatches,
|
|
1275
|
+
source: "mutableAction"
|
|
1276
|
+
});
|
|
1277
|
+
}
|
|
743
1278
|
};
|
|
744
1279
|
//#endregion
|
|
745
1280
|
//#region packages/core/src/getRawStateLocalAction.ts
|
|
@@ -785,7 +1320,7 @@ const createLocalAction = ({ fn, internal, key, options, store, sliceKey }) => {
|
|
|
785
1320
|
throw error;
|
|
786
1321
|
}
|
|
787
1322
|
};
|
|
788
|
-
const enablePatches = store.transport ?? options.enablePatches;
|
|
1323
|
+
const enablePatches = Boolean(store.transport ?? options.enablePatches) || hasStoreCommitListeners(store);
|
|
789
1324
|
return traceAction(() => {
|
|
790
1325
|
if (internal.mutableInstance && !internal.isBatching && enablePatches) {
|
|
791
1326
|
let result;
|
|
@@ -827,78 +1362,64 @@ const createLocalAction = ({ fn, internal, key, options, store, sliceKey }) => {
|
|
|
827
1362
|
});
|
|
828
1363
|
};
|
|
829
1364
|
};
|
|
830
|
-
//#endregion
|
|
831
|
-
//#region packages/core/src/
|
|
832
|
-
const
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
};
|
|
863
|
-
const createCachedGetter = (internal, getter) => {
|
|
864
|
-
const accessors = /* @__PURE__ */ new WeakMap();
|
|
865
|
-
const fallbackReceiver = {};
|
|
866
|
-
return function() {
|
|
867
|
-
const receiver = typeof this === "object" && this !== null ? this : fallbackReceiver;
|
|
868
|
-
if (internal.isBatching) return getter.call(receiver);
|
|
869
|
-
let accessor = accessors.get(receiver);
|
|
870
|
-
if (!accessor) {
|
|
871
|
-
accessor = computed$1(() => getter.call(receiver));
|
|
872
|
-
accessors.set(receiver, accessor);
|
|
873
|
-
}
|
|
874
|
-
return accessor();
|
|
875
|
-
};
|
|
876
|
-
};
|
|
877
|
-
const createTrackedStateReader = (internal, read, initialValue) => {
|
|
878
|
-
const slotSignal = signal$1(initialValue);
|
|
879
|
-
const slotVersionSignal = signal$1(0);
|
|
880
|
-
let slotVersion = 0;
|
|
881
|
-
(internal.signalSlots ??= /* @__PURE__ */ new Set()).add({ refresh: () => {
|
|
882
|
-
const nextValue = read();
|
|
883
|
-
slotSignal(nextValue);
|
|
884
|
-
if (internal.mutableInstance && isObjectLike(nextValue)) {
|
|
885
|
-
slotVersion += 1;
|
|
886
|
-
slotVersionSignal(slotVersion);
|
|
1365
|
+
//#endregion
|
|
1366
|
+
//#region packages/core/src/immutableState.ts
|
|
1367
|
+
const isImmutableStateObject = (value) => {
|
|
1368
|
+
if (typeof value !== "object" || value === null) return false;
|
|
1369
|
+
if (Array.isArray(value)) return true;
|
|
1370
|
+
const prototype = Object.getPrototypeOf(value);
|
|
1371
|
+
return prototype === Object.prototype || prototype === null;
|
|
1372
|
+
};
|
|
1373
|
+
const getImmutableStateSnapshot = (value, cache) => {
|
|
1374
|
+
if (!isImmutableStateObject(value)) return value;
|
|
1375
|
+
const cached = cache.get(value);
|
|
1376
|
+
if (cached) return cached;
|
|
1377
|
+
const isArray = Array.isArray(value);
|
|
1378
|
+
const snapshot = isArray ? new Array(value.length) : Object.create(Object.getPrototypeOf(value));
|
|
1379
|
+
cache.set(value, snapshot);
|
|
1380
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
1381
|
+
if (isArray && key === "length") continue;
|
|
1382
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
1383
|
+
if (Object.prototype.hasOwnProperty.call(descriptor, "value")) descriptor.value = getImmutableStateSnapshot(descriptor.value, cache);
|
|
1384
|
+
Object.defineProperty(snapshot, key, descriptor);
|
|
1385
|
+
}
|
|
1386
|
+
return Object.freeze(snapshot);
|
|
1387
|
+
};
|
|
1388
|
+
const createImmutableSnapshotPatches = (patches, cache) => patches.map((patch) => Object.prototype.hasOwnProperty.call(patch, "value") ? {
|
|
1389
|
+
...patch,
|
|
1390
|
+
value: getImmutableStateSnapshot(patch.value, cache)
|
|
1391
|
+
} : patch);
|
|
1392
|
+
const finalizeImmutableStateSnapshot = (state, snapshot, patches, cache, sources) => {
|
|
1393
|
+
const mapPair = (value, snapshotValue) => {
|
|
1394
|
+
if (isImmutableStateObject(value) && isImmutableStateObject(snapshotValue)) {
|
|
1395
|
+
cache.set(value, snapshotValue);
|
|
1396
|
+
sources?.set(snapshotValue, value);
|
|
887
1397
|
}
|
|
888
|
-
} });
|
|
889
|
-
return () => {
|
|
890
|
-
const currentValue = slotSignal();
|
|
891
|
-
if (internal.mutableInstance && isObjectLike(currentValue)) slotVersionSignal();
|
|
892
|
-
return read();
|
|
893
1398
|
};
|
|
1399
|
+
mapPair(state, snapshot);
|
|
1400
|
+
for (const patch of patches) {
|
|
1401
|
+
let value = state;
|
|
1402
|
+
let snapshotValue = snapshot;
|
|
1403
|
+
const ancestors = [];
|
|
1404
|
+
if (isImmutableStateObject(snapshotValue)) ancestors.push(snapshotValue);
|
|
1405
|
+
for (const key of patch.path) {
|
|
1406
|
+
if (!isImmutableStateObject(value) || !isImmutableStateObject(snapshotValue)) break;
|
|
1407
|
+
value = value[key];
|
|
1408
|
+
snapshotValue = snapshotValue[key];
|
|
1409
|
+
mapPair(value, snapshotValue);
|
|
1410
|
+
if (isImmutableStateObject(snapshotValue)) ancestors.push(snapshotValue);
|
|
1411
|
+
}
|
|
1412
|
+
for (let index = ancestors.length - 1; index >= 0; index -= 1) if (!Object.isFrozen(ancestors[index])) Object.freeze(ancestors[index]);
|
|
1413
|
+
}
|
|
894
1414
|
};
|
|
895
|
-
const
|
|
896
|
-
if (!
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
1415
|
+
const indexImmutableStateSnapshot = (state, snapshot, sources, seen = /* @__PURE__ */ new WeakSet()) => {
|
|
1416
|
+
if (!isImmutableStateObject(state) || !isImmutableStateObject(snapshot) || seen.has(snapshot)) return;
|
|
1417
|
+
seen.add(snapshot);
|
|
1418
|
+
sources.set(snapshot, state);
|
|
1419
|
+
for (const key of Reflect.ownKeys(state)) {
|
|
1420
|
+
const stateDescriptor = Object.getOwnPropertyDescriptor(state, key);
|
|
1421
|
+
const snapshotDescriptor = Object.getOwnPropertyDescriptor(snapshot, key);
|
|
1422
|
+
if (stateDescriptor && snapshotDescriptor && Object.prototype.hasOwnProperty.call(stateDescriptor, "value") && Object.prototype.hasOwnProperty.call(snapshotDescriptor, "value")) indexImmutableStateSnapshot(stateDescriptor.value, snapshotDescriptor.value, sources, seen);
|
|
902
1423
|
}
|
|
903
1424
|
};
|
|
904
1425
|
//#endregion
|
|
@@ -908,12 +1429,6 @@ const assertImmutableStateMutationAllowed = (internal) => {
|
|
|
908
1429
|
throw new Error("Direct state mutation is not allowed in immutable Coaction stores. Wrap mutations in set(() => { ... }).");
|
|
909
1430
|
};
|
|
910
1431
|
const readonlyProxyCache = /* @__PURE__ */ new WeakMap();
|
|
911
|
-
const isReadonlyProxyable = (value) => {
|
|
912
|
-
if (typeof value !== "object" || value === null) return false;
|
|
913
|
-
if (Array.isArray(value)) return true;
|
|
914
|
-
const prototype = Object.getPrototypeOf(value);
|
|
915
|
-
return prototype === Object.prototype || prototype === null;
|
|
916
|
-
};
|
|
917
1432
|
const getReadonlyProxyCache = (internal) => {
|
|
918
1433
|
let cache = readonlyProxyCache.get(internal);
|
|
919
1434
|
if (!cache) {
|
|
@@ -930,7 +1445,12 @@ const getPublicStateObject = (internal, value, sliceKey) => {
|
|
|
930
1445
|
if (rootState[sliceKey] === value) return module[sliceKey];
|
|
931
1446
|
};
|
|
932
1447
|
const toReadonlyStateValue = (internal, value, sliceKey) => {
|
|
933
|
-
if (internal.mutableInstance || internal.isBatching || !
|
|
1448
|
+
if (internal.mutableInstance || internal.isBatching || !isImmutableStateObject(value)) return value;
|
|
1449
|
+
if (internal.computedReadDepth) {
|
|
1450
|
+
const cache = internal.computedSnapshotCache ??= /* @__PURE__ */ new WeakMap();
|
|
1451
|
+
if (isImmutableStateObject(internal.rootState) && !cache.has(internal.rootState)) getImmutableStateSnapshot(internal.rootState, cache);
|
|
1452
|
+
return getImmutableStateSnapshot(value, cache);
|
|
1453
|
+
}
|
|
934
1454
|
const publicValue = getPublicStateObject(internal, value, sliceKey);
|
|
935
1455
|
if (publicValue) return publicValue;
|
|
936
1456
|
const cache = getReadonlyProxyCache(internal);
|
|
@@ -960,6 +1480,18 @@ const toReadonlyStateValue = (internal, value, sliceKey) => {
|
|
|
960
1480
|
cache.set(value, proxy);
|
|
961
1481
|
return proxy;
|
|
962
1482
|
};
|
|
1483
|
+
const toPublicComputedValue = (internal, value, sliceKey) => {
|
|
1484
|
+
if (!isImmutableStateObject(value)) return value;
|
|
1485
|
+
const rootSnapshot = internal.computedSnapshotCache?.get(internal.rootState);
|
|
1486
|
+
const sources = internal.computedSnapshotSources ??= /* @__PURE__ */ new WeakMap();
|
|
1487
|
+
let source = sources.get(value);
|
|
1488
|
+
if (!source && Object.isFrozen(value) && rootSnapshot) {
|
|
1489
|
+
indexImmutableStateSnapshot(internal.rootState, rootSnapshot, sources);
|
|
1490
|
+
source = sources.get(value);
|
|
1491
|
+
}
|
|
1492
|
+
if (source) internal.computedIdentityRequired = true;
|
|
1493
|
+
return source ? toReadonlyStateValue(internal, source, sliceKey) : value;
|
|
1494
|
+
};
|
|
963
1495
|
const prepareStateDescriptor = ({ descriptor, initialStateSeen, internal, key, rawState, sliceKey }) => {
|
|
964
1496
|
const isComputed = descriptor.value instanceof Computed;
|
|
965
1497
|
const readStateValue = () => typeof sliceKey !== "undefined" ? internal.rootState[sliceKey][key] : internal.rootState[key];
|
|
@@ -980,7 +1512,10 @@ const prepareStateDescriptor = ({ descriptor, initialStateSeen, internal, key, r
|
|
|
980
1512
|
});
|
|
981
1513
|
if (isComputed) {
|
|
982
1514
|
if (internal.mutableInstance) throw new Error("Computed is not supported with mutable instance");
|
|
983
|
-
|
|
1515
|
+
const getComputed = descriptor.value.createGetter({ internal });
|
|
1516
|
+
descriptor.get = function() {
|
|
1517
|
+
return toPublicComputedValue(internal, getComputed.call(this), sliceKey);
|
|
1518
|
+
};
|
|
984
1519
|
} else if (typeof sliceKey !== "undefined") {
|
|
985
1520
|
const read = createTrackedStateReader(internal, readStateValue, initialValue);
|
|
986
1521
|
descriptor.get = () => toReadonlyStateValue(internal, read(), sliceKey);
|
|
@@ -999,9 +1534,12 @@ const prepareStateDescriptor = ({ descriptor, initialStateSeen, internal, key, r
|
|
|
999
1534
|
delete descriptor.value;
|
|
1000
1535
|
delete descriptor.writable;
|
|
1001
1536
|
};
|
|
1002
|
-
const prepareAccessorDescriptor = ({ descriptor, internal }) => {
|
|
1537
|
+
const prepareAccessorDescriptor = ({ descriptor, internal, sliceKey }) => {
|
|
1003
1538
|
if (internal.mutableInstance || typeof descriptor.get !== "function") return;
|
|
1004
|
-
|
|
1539
|
+
const getComputed = createCachedGetter(internal, descriptor.get);
|
|
1540
|
+
descriptor.get = function() {
|
|
1541
|
+
return toPublicComputedValue(internal, getComputed.call(this), sliceKey);
|
|
1542
|
+
};
|
|
1005
1543
|
};
|
|
1006
1544
|
//#endregion
|
|
1007
1545
|
//#region packages/core/src/getRawState.ts
|
|
@@ -1016,7 +1554,7 @@ const getClientExecuteSyncTimeoutMs = (options) => {
|
|
|
1016
1554
|
if (!Number.isFinite(timeout) || timeout < 0) throw new Error("executeSyncTimeoutMs must be a finite number greater than or equal to 0");
|
|
1017
1555
|
return timeout;
|
|
1018
1556
|
};
|
|
1019
|
-
const getRawState = (store, internal, initialState, options) => {
|
|
1557
|
+
const getRawState = (store, internal, initialState, options, createClientAction) => {
|
|
1020
1558
|
const clientExecuteSyncTimeoutMs = getClientExecuteSyncTimeoutMs(options);
|
|
1021
1559
|
const rawState = {};
|
|
1022
1560
|
const handle = (_rawState, _initialState, sliceKey) => {
|
|
@@ -1035,7 +1573,8 @@ const getRawState = (store, internal, initialState, options) => {
|
|
|
1035
1573
|
if (!Object.prototype.hasOwnProperty.call(descriptor, "value")) {
|
|
1036
1574
|
prepareAccessorDescriptor({
|
|
1037
1575
|
descriptor,
|
|
1038
|
-
internal
|
|
1576
|
+
internal,
|
|
1577
|
+
sliceKey
|
|
1039
1578
|
});
|
|
1040
1579
|
return;
|
|
1041
1580
|
}
|
|
@@ -1053,6 +1592,7 @@ const getRawState = (store, internal, initialState, options) => {
|
|
|
1053
1592
|
}
|
|
1054
1593
|
if (store.share === "client") {
|
|
1055
1594
|
if (typeof key !== "string") return;
|
|
1595
|
+
if (!createClientAction) throw new Error("Client action runtime is not configured");
|
|
1056
1596
|
descriptor.value = createClientAction({
|
|
1057
1597
|
clientExecuteSyncTimeoutMs,
|
|
1058
1598
|
internal,
|
|
@@ -1087,8 +1627,13 @@ const getRawState = (store, internal, initialState, options) => {
|
|
|
1087
1627
|
//#endregion
|
|
1088
1628
|
//#region packages/core/src/handleState.ts
|
|
1089
1629
|
const handleState = (store, internal, options) => {
|
|
1630
|
+
let defaultResultValidated = false;
|
|
1631
|
+
let pendingCommitSource;
|
|
1090
1632
|
const defaultUpdater = (next) => {
|
|
1633
|
+
defaultResultValidated = false;
|
|
1634
|
+
let producedState;
|
|
1091
1635
|
const merge = (_next = next) => {
|
|
1636
|
+
if (_next !== next) internal.validateState?.(_next);
|
|
1092
1637
|
assertKnownStateShape(_next, internal.rootState, internal.stateSchema, store.isSliceStore);
|
|
1093
1638
|
mergeObject(internal.rootState, _next, store.isSliceStore);
|
|
1094
1639
|
};
|
|
@@ -1100,14 +1645,16 @@ const handleState = (store, internal, options) => {
|
|
|
1100
1645
|
}
|
|
1101
1646
|
if (typeof returnValue === "object" && returnValue !== null) merge(returnValue);
|
|
1102
1647
|
} : merge;
|
|
1103
|
-
if (!(store.transport ?? options.enablePatches) && internal.mutableInstance) {
|
|
1648
|
+
if (!(Boolean(store.transport ?? options.enablePatches) || hasStoreCommitListeners(store)) && internal.mutableInstance) {
|
|
1104
1649
|
if (internal.actMutable) {
|
|
1105
1650
|
internal.actMutable(() => {
|
|
1106
1651
|
fn.apply(null);
|
|
1107
1652
|
});
|
|
1653
|
+
defaultResultValidated = true;
|
|
1108
1654
|
return [];
|
|
1109
1655
|
}
|
|
1110
1656
|
fn.apply(null);
|
|
1657
|
+
defaultResultValidated = true;
|
|
1111
1658
|
return [];
|
|
1112
1659
|
}
|
|
1113
1660
|
internal.backupState = internal.rootState;
|
|
@@ -1119,22 +1666,40 @@ const handleState = (store, internal, options) => {
|
|
|
1119
1666
|
return fn.apply(null);
|
|
1120
1667
|
}, { enablePatches: true });
|
|
1121
1668
|
assertKnownStateShape(result[0], internal.backupState, internal.stateSchema, store.isSliceStore, { requireSliceRoots: true });
|
|
1122
|
-
|
|
1669
|
+
internal.validateState?.(internal.getTransportState?.() ?? result[0]);
|
|
1670
|
+
producedState = result[0];
|
|
1123
1671
|
patches = result[1];
|
|
1124
1672
|
inversePatches = result[2];
|
|
1125
1673
|
} finally {
|
|
1126
1674
|
internal.rootState = internal.backupState;
|
|
1127
1675
|
}
|
|
1128
|
-
const
|
|
1676
|
+
const patch = store.patch;
|
|
1677
|
+
const finalPatches = patch ? patch({
|
|
1129
1678
|
patches,
|
|
1130
1679
|
inversePatches
|
|
1131
1680
|
}) : {
|
|
1132
1681
|
patches,
|
|
1133
1682
|
inversePatches
|
|
1134
1683
|
};
|
|
1684
|
+
if (!patch) internal.validatePatches?.(finalPatches.patches);
|
|
1135
1685
|
const safePatches = sanitizeCheckedPatches(finalPatches.patches, "store.patch()");
|
|
1136
1686
|
const safeInversePatches = sanitizeCheckedPatches(finalPatches.inversePatches, "store.patch() inverse patches");
|
|
1137
|
-
if (safePatches.
|
|
1687
|
+
if (producedState && safePatches.some((patch) => typeof patch.value === "object" && patch.value !== null) && prepareStoreCommit(store, {
|
|
1688
|
+
state: producedState,
|
|
1689
|
+
patches: safePatches,
|
|
1690
|
+
inversePatches: safeInversePatches,
|
|
1691
|
+
source: "setState"
|
|
1692
|
+
})) {
|
|
1693
|
+
runWithStoreCommitSource(store, "setState", () => {
|
|
1694
|
+
store.apply(producedState);
|
|
1695
|
+
});
|
|
1696
|
+
defaultResultValidated = true;
|
|
1697
|
+
return [];
|
|
1698
|
+
}
|
|
1699
|
+
if (safePatches.length) {
|
|
1700
|
+
defaultResultValidated = internal.applyValidatedPatches?.(internal.rootState, safePatches, !patch) ?? false;
|
|
1701
|
+
if (!internal.applyValidatedPatches) store.apply(internal.rootState, safePatches);
|
|
1702
|
+
} else defaultResultValidated = true;
|
|
1138
1703
|
return [
|
|
1139
1704
|
internal.rootState,
|
|
1140
1705
|
safePatches,
|
|
@@ -1142,17 +1707,26 @@ const handleState = (store, internal, options) => {
|
|
|
1142
1707
|
];
|
|
1143
1708
|
};
|
|
1144
1709
|
const setState = (next, updater = defaultUpdater) => {
|
|
1710
|
+
const commitSource = pendingCommitSource ?? "setState";
|
|
1711
|
+
pendingCommitSource = void 0;
|
|
1145
1712
|
internal.assertAlive?.("setState");
|
|
1146
1713
|
internal.assertMutationAllowed?.("setState");
|
|
1147
1714
|
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.`);
|
|
1148
1715
|
if (internal.isBatching) throw new Error("setState cannot be called within the updater");
|
|
1149
1716
|
if (next === null) return [];
|
|
1150
|
-
if (typeof next === "object")
|
|
1717
|
+
if (typeof next === "object") {
|
|
1718
|
+
internal.validateState?.(next);
|
|
1719
|
+
assertKnownStateShape(next, internal.rootState, internal.stateSchema, store.isSliceStore);
|
|
1720
|
+
}
|
|
1151
1721
|
internal.isBatching = true;
|
|
1152
|
-
if (!store.share && !options.enablePatches && !internal.mutableInstance && updater === defaultUpdater) try {
|
|
1722
|
+
if (!store.share && !options.enablePatches && !hasStoreCommitListeners(store) && !internal.mutableInstance && updater === defaultUpdater) try {
|
|
1153
1723
|
if (typeof next === "function") try {
|
|
1154
1724
|
internal.backupState = internal.rootState;
|
|
1155
|
-
const
|
|
1725
|
+
const snapshotCache = internal.computedSnapshotCache;
|
|
1726
|
+
const snapshotSources = internal.computedIdentityRequired ? internal.computedSnapshotSources : void 0;
|
|
1727
|
+
const snapshot = snapshotCache?.get(internal.rootState);
|
|
1728
|
+
const updateSnapshot = Boolean(snapshot && snapshotCache);
|
|
1729
|
+
const produced = create$1(internal.rootState, (draft) => {
|
|
1156
1730
|
internal.rootState = draft;
|
|
1157
1731
|
const returnValue = next(internal.module);
|
|
1158
1732
|
if (returnValue instanceof Promise) {
|
|
@@ -1163,8 +1737,13 @@ const handleState = (store, internal, options) => {
|
|
|
1163
1737
|
assertKnownStateShape(returnValue, internal.rootState, internal.stateSchema, store.isSliceStore);
|
|
1164
1738
|
mergeObject(internal.rootState, returnValue, store.isSliceStore);
|
|
1165
1739
|
}
|
|
1166
|
-
});
|
|
1740
|
+
}, { enablePatches: updateSnapshot });
|
|
1741
|
+
const nextState = updateSnapshot ? produced[0] : produced;
|
|
1167
1742
|
assertKnownStateShape(nextState, internal.backupState, internal.stateSchema, store.isSliceStore, { requireSliceRoots: true });
|
|
1743
|
+
if (updateSnapshot) {
|
|
1744
|
+
const patches = produced[1];
|
|
1745
|
+
finalizeImmutableStateSnapshot(nextState, apply(snapshot, createImmutableSnapshotPatches(patches, snapshotCache)), patches, snapshotCache, snapshotSources);
|
|
1746
|
+
}
|
|
1168
1747
|
internal.rootState = nextState;
|
|
1169
1748
|
} catch (error) {
|
|
1170
1749
|
internal.rootState = internal.backupState;
|
|
@@ -1202,7 +1781,7 @@ const handleState = (store, internal, options) => {
|
|
|
1202
1781
|
if (isDrafted) handleDraft(store, internal);
|
|
1203
1782
|
result = updater(next);
|
|
1204
1783
|
if (internal.mutableInstance) assertKnownStateShape(internal.rootState, internal.backupState ?? internal.rootState, internal.stateSchema, store.isSliceStore, { requireSliceRoots: true });
|
|
1205
|
-
if (
|
|
1784
|
+
if (!(updater === defaultUpdater && defaultResultValidated)) internal.validateState?.(internal.getTransportState?.() ?? internal.rootState);
|
|
1206
1785
|
if (isDrafted) {
|
|
1207
1786
|
internal.backupState = internal.rootState;
|
|
1208
1787
|
const [draft, finalize] = create$1(internal.rootState, { enablePatches: true });
|
|
@@ -1212,110 +1791,267 @@ const handleState = (store, internal, options) => {
|
|
|
1212
1791
|
} finally {
|
|
1213
1792
|
internal.isBatching = false;
|
|
1214
1793
|
}
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1794
|
+
const trustedDefaultResult = updater === defaultUpdater && defaultResultValidated;
|
|
1795
|
+
if (result?.length && !trustedDefaultResult) {
|
|
1796
|
+
internal.validatePatches?.(result[1]);
|
|
1797
|
+
result = [
|
|
1798
|
+
result[0],
|
|
1799
|
+
sanitizeCheckedPatches(result[1], "setState updater result"),
|
|
1800
|
+
sanitizeCheckedPatches(result[2], "setState updater inverse result")
|
|
1801
|
+
];
|
|
1802
|
+
}
|
|
1803
|
+
if (result?.length === 3) {
|
|
1804
|
+
const [, patches, inversePatches] = result;
|
|
1805
|
+
internal.emitPatches?.(patches);
|
|
1806
|
+
if (patches.length || inversePatches.length) publishStoreCommit(store, {
|
|
1807
|
+
state: internal.rootState,
|
|
1808
|
+
patches,
|
|
1809
|
+
inversePatches,
|
|
1810
|
+
source: commitSource
|
|
1811
|
+
});
|
|
1812
|
+
}
|
|
1221
1813
|
return result;
|
|
1222
1814
|
};
|
|
1815
|
+
const replayPatches = ({ patches, inversePatches }, replaySetState = setState) => {
|
|
1816
|
+
const previousSource = pendingCommitSource;
|
|
1817
|
+
pendingCommitSource = "replay";
|
|
1818
|
+
try {
|
|
1819
|
+
replaySetState(internal.rootState, () => {
|
|
1820
|
+
const inputPatches = patches.map((patch) => ({
|
|
1821
|
+
...patch,
|
|
1822
|
+
path: Array.isArray(patch.path) ? [...patch.path] : patch.path
|
|
1823
|
+
}));
|
|
1824
|
+
const inputInversePatches = inversePatches.map((patch) => ({
|
|
1825
|
+
...patch,
|
|
1826
|
+
path: Array.isArray(patch.path) ? [...patch.path] : patch.path
|
|
1827
|
+
}));
|
|
1828
|
+
const finalPatches = store.patch ? store.patch({
|
|
1829
|
+
patches: inputPatches,
|
|
1830
|
+
inversePatches: inputInversePatches
|
|
1831
|
+
}) : {
|
|
1832
|
+
patches: inputPatches,
|
|
1833
|
+
inversePatches: inputInversePatches
|
|
1834
|
+
};
|
|
1835
|
+
const safePatches = sanitizeCheckedPatches(finalPatches.patches, "store.patch()");
|
|
1836
|
+
const safeInversePatches = sanitizeCheckedPatches(finalPatches.inversePatches, "store.patch() inverse patches");
|
|
1837
|
+
if (safePatches.length) {
|
|
1838
|
+
internal.applyValidatedPatches?.(internal.rootState, safePatches, false);
|
|
1839
|
+
if (!internal.applyValidatedPatches) store.apply(internal.rootState, safePatches);
|
|
1840
|
+
}
|
|
1841
|
+
return [
|
|
1842
|
+
internal.rootState,
|
|
1843
|
+
safePatches,
|
|
1844
|
+
safeInversePatches
|
|
1845
|
+
];
|
|
1846
|
+
});
|
|
1847
|
+
return internal.rootState;
|
|
1848
|
+
} finally {
|
|
1849
|
+
pendingCommitSource = previousSource;
|
|
1850
|
+
}
|
|
1851
|
+
};
|
|
1223
1852
|
const getState = (deps, selector) => deps && selector ? new Computed(deps, selector) : internal.module;
|
|
1224
1853
|
return {
|
|
1225
1854
|
setState,
|
|
1226
|
-
getState
|
|
1855
|
+
getState,
|
|
1856
|
+
replayPatches
|
|
1227
1857
|
};
|
|
1228
1858
|
};
|
|
1229
1859
|
//#endregion
|
|
1230
|
-
//#region packages/core/src/
|
|
1231
|
-
const
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
}
|
|
1241
|
-
|
|
1242
|
-
if (process.env.NODE_ENV === "development") {
|
|
1243
|
-
if (!isStoreLike(nextStore)) throw new Error(`middlewares[${index}] should return a store-like object`);
|
|
1244
|
-
}
|
|
1245
|
-
return nextStore;
|
|
1246
|
-
}, store);
|
|
1247
|
-
};
|
|
1248
|
-
//#endregion
|
|
1249
|
-
//#region packages/core/src/handleMainTransport.ts
|
|
1250
|
-
const getErrorMessage = (error) => {
|
|
1251
|
-
if (error instanceof Error) return error.message;
|
|
1252
|
-
return String(error);
|
|
1860
|
+
//#region packages/core/src/storeFactory.ts
|
|
1861
|
+
const namespaceMap = /* @__PURE__ */ new Map();
|
|
1862
|
+
let hasWarnedAmbiguousFunctionMap = false;
|
|
1863
|
+
const warnAmbiguousFunctionMap = () => {
|
|
1864
|
+
if (hasWarnedAmbiguousFunctionMap || process.env.NODE_ENV === "production" || process.env.NODE_ENV === "test") return;
|
|
1865
|
+
hasWarnedAmbiguousFunctionMap = true;
|
|
1866
|
+
console.warn([
|
|
1867
|
+
`sliceMode: 'auto' inferred slices from an object of functions.`,
|
|
1868
|
+
`This shape is ambiguous with a single store that only contains methods.`,
|
|
1869
|
+
`Use create({ ping() {} }, { sliceMode: 'single' }) for a plain method store,`,
|
|
1870
|
+
`or create({ counter: (set) => ({ count: 0 }) }, { sliceMode: 'slices' }) for slices.`
|
|
1871
|
+
].join(" "));
|
|
1253
1872
|
};
|
|
1254
|
-
const
|
|
1255
|
-
const
|
|
1256
|
-
const
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1873
|
+
const createStore = (createState, options, runtime = {}) => {
|
|
1874
|
+
const { share, validatePatches, validateReplacementSource, validateState } = runtime;
|
|
1875
|
+
const store = {};
|
|
1876
|
+
const internal = {
|
|
1877
|
+
sequence: 0,
|
|
1878
|
+
isBatching: false,
|
|
1879
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
1880
|
+
destroyCallbacks: /* @__PURE__ */ new Set(),
|
|
1881
|
+
validatePatches,
|
|
1882
|
+
validateReplacementSource,
|
|
1883
|
+
validateState
|
|
1884
|
+
};
|
|
1885
|
+
internal.notifyStateChange = () => {
|
|
1886
|
+
refreshSignalSlots(internal);
|
|
1887
|
+
internal.listeners.forEach((listener) => listener());
|
|
1888
|
+
};
|
|
1889
|
+
const name = options.name ?? "default";
|
|
1890
|
+
const shouldTrackName = share === "main" && process.env.NODE_ENV !== "test";
|
|
1891
|
+
const releaseStoreName = () => {
|
|
1892
|
+
if (shouldTrackName) namespaceMap.delete(name);
|
|
1893
|
+
};
|
|
1894
|
+
if (shouldTrackName) {
|
|
1895
|
+
if (namespaceMap.get(name)) throw new Error(`Store name '${name}' is not unique.`);
|
|
1896
|
+
namespaceMap.set(name, true);
|
|
1897
|
+
}
|
|
1898
|
+
try {
|
|
1899
|
+
const { setState, getState, replayPatches } = handleState(store, internal, options);
|
|
1900
|
+
const subscribe = (listener) => {
|
|
1901
|
+
internal.assertAlive?.("subscribe");
|
|
1902
|
+
internal.listeners.add(listener);
|
|
1903
|
+
return () => internal.listeners.delete(listener);
|
|
1904
|
+
};
|
|
1905
|
+
let isDestroyed = false;
|
|
1906
|
+
internal.assertAlive = (operation) => {
|
|
1907
|
+
if (isDestroyed) throw new Error(`${operation} cannot be called after store.destroy().`);
|
|
1908
|
+
};
|
|
1909
|
+
const destroy = () => {
|
|
1910
|
+
if (isDestroyed) return;
|
|
1911
|
+
isDestroyed = true;
|
|
1912
|
+
let firstError;
|
|
1913
|
+
const callbacks = [...internal.destroyCallbacks ?? []];
|
|
1914
|
+
internal.destroyCallbacks?.clear();
|
|
1915
|
+
for (const callback of callbacks) try {
|
|
1916
|
+
callback();
|
|
1917
|
+
} catch (error) {
|
|
1918
|
+
firstError ??= error;
|
|
1268
1919
|
}
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1920
|
+
internal.listeners.clear();
|
|
1921
|
+
disposeStoreCommitRuntime(store);
|
|
1922
|
+
try {
|
|
1923
|
+
store.transport?.dispose();
|
|
1924
|
+
} catch (error) {
|
|
1925
|
+
firstError ??= error;
|
|
1926
|
+
} finally {
|
|
1927
|
+
releaseStoreName();
|
|
1928
|
+
}
|
|
1929
|
+
if (firstError) throw firstError;
|
|
1930
|
+
};
|
|
1931
|
+
const applyState = (state, patches, prepared = false, skipFinalValidation = false) => {
|
|
1932
|
+
internal.assertAlive?.("apply");
|
|
1933
|
+
internal.assertMutationAllowed?.("apply");
|
|
1934
|
+
if (patches && !prepared) validatePatches?.(patches);
|
|
1935
|
+
if (!prepared) assertSafePatches(patches, "store.apply()");
|
|
1936
|
+
const safePatches = prepared ? patches : sanitizePatches(patches);
|
|
1937
|
+
const baseState = state === internal.module ? internal.rootState : state;
|
|
1938
|
+
if (baseState !== internal.rootState) validateReplacementSource?.(baseState);
|
|
1939
|
+
const appliedState = safePatches ? apply(baseState, safePatches) : baseState;
|
|
1940
|
+
const nextState = prepared ? appliedState : sanitizeReplacementState(appliedState);
|
|
1941
|
+
if (!skipFinalValidation) {
|
|
1942
|
+
assertKnownStateShape(nextState, internal.rootState, internal.stateSchema, store.isSliceStore, { requireSliceRoots: true });
|
|
1943
|
+
validateState?.(internal.getTransportState?.() ?? nextState);
|
|
1944
|
+
}
|
|
1945
|
+
internal.rootState = nextState;
|
|
1946
|
+
refreshSignalSlots(internal);
|
|
1947
|
+
if (internal.updateImmutable) internal.updateImmutable(internal.rootState);
|
|
1948
|
+
else internal.listeners.forEach((listener) => listener());
|
|
1949
|
+
};
|
|
1950
|
+
const apply$1 = (state = internal.rootState, patches) => {
|
|
1951
|
+
const observeReplacement = patches === void 0 && hasStoreCommitListeners(store);
|
|
1952
|
+
const previousState = internal.rootState;
|
|
1953
|
+
applyState(state, patches);
|
|
1954
|
+
if (!observeReplacement) return;
|
|
1955
|
+
const replacement = createRootReplacementPatches(previousState, internal.rootState);
|
|
1956
|
+
const safePatches = sanitizeCheckedPatches(replacement.patches, "store.apply() replacement");
|
|
1957
|
+
const safeInversePatches = sanitizeCheckedPatches(replacement.inversePatches, "store.apply() replacement inverse patches");
|
|
1958
|
+
if (!safePatches.length && !safeInversePatches.length) return;
|
|
1959
|
+
internal.emitPatches?.(safePatches);
|
|
1960
|
+
publishStoreCommit(store, {
|
|
1961
|
+
state: internal.rootState,
|
|
1962
|
+
patches: safePatches,
|
|
1963
|
+
inversePatches: safeInversePatches,
|
|
1964
|
+
source: getStoreCommitSource(store, "external")
|
|
1965
|
+
});
|
|
1966
|
+
};
|
|
1967
|
+
internal.applyValidatedPatches = (state, patches, skipFinalValidation) => {
|
|
1968
|
+
if (store.apply !== apply$1) {
|
|
1969
|
+
store.apply(state, patches);
|
|
1970
|
+
return false;
|
|
1971
|
+
}
|
|
1972
|
+
applyState(state, patches, true, skipFinalValidation);
|
|
1973
|
+
return true;
|
|
1974
|
+
};
|
|
1975
|
+
const getPureState = () => internal.rootState;
|
|
1976
|
+
const isFunctionMapObject = () => {
|
|
1977
|
+
if (typeof createState !== "object" || createState === null) return false;
|
|
1978
|
+
const values = getOwnEnumerableKeys(createState).map((key) => createState[key]);
|
|
1979
|
+
return values.length > 0 && values.every((value) => typeof value === "function");
|
|
1980
|
+
};
|
|
1981
|
+
const getIsSliceStore = () => {
|
|
1982
|
+
const sliceMode = options.sliceMode ?? "auto";
|
|
1983
|
+
if (sliceMode === "single") return false;
|
|
1984
|
+
if (sliceMode === "slices") {
|
|
1985
|
+
if (!isFunctionMapObject()) throw new Error(`sliceMode: 'slices' requires createState to be an object of slice functions.`);
|
|
1986
|
+
return true;
|
|
1987
|
+
}
|
|
1988
|
+
if (isFunctionMapObject()) {
|
|
1989
|
+
warnAmbiguousFunctionMap();
|
|
1990
|
+
return true;
|
|
1991
|
+
}
|
|
1992
|
+
return false;
|
|
1993
|
+
};
|
|
1994
|
+
const isSliceStore = getIsSliceStore();
|
|
1995
|
+
Object.assign(store, {
|
|
1996
|
+
name,
|
|
1997
|
+
share: share ?? false,
|
|
1998
|
+
setState,
|
|
1999
|
+
getState,
|
|
2000
|
+
subscribe,
|
|
2001
|
+
destroy,
|
|
2002
|
+
apply: apply$1,
|
|
2003
|
+
isSliceStore,
|
|
2004
|
+
getPureState
|
|
2005
|
+
});
|
|
2006
|
+
const middlewareStore = applyMiddlewares(store, options.middlewares ?? []);
|
|
2007
|
+
if (middlewareStore !== store) Object.assign(store, middlewareStore);
|
|
2008
|
+
registerStorePatchReplayer(store, replayPatches);
|
|
2009
|
+
internal.assertAlive?.("store initialization");
|
|
2010
|
+
if (validatePatches && store.patch) {
|
|
2011
|
+
const patch = store.patch.bind(store);
|
|
2012
|
+
store.patch = (options) => {
|
|
2013
|
+
const result = patch(options);
|
|
2014
|
+
validatePatches(result.patches);
|
|
2015
|
+
return result;
|
|
2016
|
+
};
|
|
1277
2017
|
}
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
2018
|
+
const initialState = getInitialState(store, createState, internal);
|
|
2019
|
+
internal.assertAlive?.("store initialization");
|
|
2020
|
+
internal.sharedActionPaths = runtime.collectActionPaths?.(initialState, store.isSliceStore);
|
|
2021
|
+
if (!internal.getTransportState) runtime.validateInitialState?.(initialState, store.isSliceStore);
|
|
2022
|
+
store.getInitialState = () => initialState;
|
|
2023
|
+
internal.rootState = getRawState(store, internal, initialState, options, runtime.clientAction);
|
|
2024
|
+
if (validatePatches && store.apply !== apply$1) {
|
|
2025
|
+
const applyWithAdapter = store.apply.bind(store);
|
|
2026
|
+
store.apply = (state, patches) => {
|
|
2027
|
+
internal.assertAlive?.("apply");
|
|
2028
|
+
internal.assertMutationAllowed?.("apply");
|
|
2029
|
+
if (typeof state !== "undefined" && state !== internal.rootState && state !== internal.module) validateReplacementSource?.(state);
|
|
2030
|
+
if (patches) {
|
|
2031
|
+
validatePatches(patches);
|
|
2032
|
+
assertSafePatches(patches, "store.apply()");
|
|
2033
|
+
}
|
|
2034
|
+
applyWithAdapter(state, patches);
|
|
2035
|
+
};
|
|
2036
|
+
}
|
|
2037
|
+
internal.stateSchema = createStateSchema(internal.rootState, store.isSliceStore);
|
|
2038
|
+
validateState?.(internal.getTransportState?.() ?? internal.rootState);
|
|
1281
2039
|
return {
|
|
1282
|
-
|
|
1283
|
-
|
|
2040
|
+
store,
|
|
2041
|
+
internal
|
|
1284
2042
|
};
|
|
1285
|
-
})
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
if (readyStores.has(store)) {
|
|
1294
|
-
callback();
|
|
1295
|
-
return () => void 0;
|
|
1296
|
-
}
|
|
1297
|
-
let callbacks = readyCallbacks.get(store);
|
|
1298
|
-
if (!callbacks) {
|
|
1299
|
-
callbacks = /* @__PURE__ */ new Set();
|
|
1300
|
-
readyCallbacks.set(store, callbacks);
|
|
2043
|
+
} catch (error) {
|
|
2044
|
+
try {
|
|
2045
|
+
store.destroy?.();
|
|
2046
|
+
} catch (destroyError) {
|
|
2047
|
+
if (process.env.NODE_ENV === "development") console.error(destroyError);
|
|
2048
|
+
}
|
|
2049
|
+
releaseStoreName();
|
|
2050
|
+
throw error;
|
|
1301
2051
|
}
|
|
1302
|
-
callbacks.add(callback);
|
|
1303
|
-
return () => {
|
|
1304
|
-
callbacks?.delete(callback);
|
|
1305
|
-
};
|
|
1306
|
-
};
|
|
1307
|
-
const markStoreReady = (store) => {
|
|
1308
|
-
readyStores.add(store);
|
|
1309
|
-
const callbacks = readyCallbacks.get(store);
|
|
1310
|
-
if (!callbacks) return;
|
|
1311
|
-
readyCallbacks.delete(store);
|
|
1312
|
-
callbacks.forEach((callback) => callback());
|
|
1313
|
-
callbacks.clear();
|
|
1314
2052
|
};
|
|
1315
2053
|
//#endregion
|
|
1316
2054
|
//#region packages/core/src/create.ts
|
|
1317
|
-
const namespaceMap = /* @__PURE__ */ new Map();
|
|
1318
|
-
let hasWarnedAmbiguousFunctionMap = false;
|
|
1319
2055
|
const isMainWorkerType = (workerType) => workerType === "SharedWorkerInternal" || workerType === "WebWorkerInternal";
|
|
1320
2056
|
const isClientWorkerType = (workerType) => workerType === "SharedWorkerClient" || workerType === "WebWorkerClient";
|
|
1321
2057
|
const validateCreateModeOptions = (options) => {
|
|
@@ -1329,424 +2065,50 @@ const validateCreateModeOptions = (options) => {
|
|
|
1329
2065
|
if (isMainWorkerType(explicitWorkerType) && (clientTransport || worker)) throw new Error("main workerType cannot be combined with client transport settings.");
|
|
1330
2066
|
if (isClientWorkerType(explicitWorkerType) && storeTransport) throw new Error("client workerType cannot be combined with transport.");
|
|
1331
2067
|
};
|
|
1332
|
-
const warnAmbiguousFunctionMap = () => {
|
|
1333
|
-
if (hasWarnedAmbiguousFunctionMap || process.env.NODE_ENV === "production" || process.env.NODE_ENV === "test") return;
|
|
1334
|
-
hasWarnedAmbiguousFunctionMap = true;
|
|
1335
|
-
console.warn([
|
|
1336
|
-
`sliceMode: 'auto' inferred slices from an object of functions.`,
|
|
1337
|
-
`This shape is ambiguous with a single store that only contains methods.`,
|
|
1338
|
-
`Use create({ ping() {} }, { sliceMode: 'single' }) for a plain method store,`,
|
|
1339
|
-
`or create({ counter: (set) => ({ count: 0 }) }, { sliceMode: 'slices' }) for slices.`
|
|
1340
|
-
].join(" "));
|
|
1341
|
-
};
|
|
1342
2068
|
/**
|
|
1343
2069
|
* Create a local store, the main side of a shared store, or a client mirror of
|
|
1344
2070
|
* a shared store.
|
|
1345
2071
|
*
|
|
1346
2072
|
* @remarks
|
|
1347
|
-
*
|
|
1348
|
-
*
|
|
1349
|
-
*
|
|
1350
|
-
* to avoid ambiguous inference.
|
|
1351
|
-
* - When `clientTransport` or `worker` is provided, returned store methods
|
|
1352
|
-
* become promise-returning methods because execution happens on the main
|
|
1353
|
-
* shared store.
|
|
1354
|
-
* - New semantics should prefer explicit helpers or variants over adding more
|
|
1355
|
-
* ambiguous `create()` input forms.
|
|
2073
|
+
* Prefer the static `coaction/local` entry when transport support is not
|
|
2074
|
+
* required. It excludes the JSON protocol and reconnect runtime from the
|
|
2075
|
+
* consumer dependency graph.
|
|
1356
2076
|
*/
|
|
1357
2077
|
const create = (createState, options = {}) => {
|
|
1358
2078
|
const checkEnablePatches = Object.hasOwnProperty.call(options, "enablePatches") && !options.enablePatches;
|
|
1359
2079
|
validateCreateModeOptions(options);
|
|
1360
2080
|
const workerType = options.workerType ?? WorkerType;
|
|
1361
2081
|
const storeTransport = options.transport;
|
|
1362
|
-
const share = workerType
|
|
1363
|
-
const
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
refreshSignalSlots(internal);
|
|
1372
|
-
internal.listeners.forEach((listener) => listener());
|
|
1373
|
-
};
|
|
1374
|
-
const name = options.name ?? "default";
|
|
1375
|
-
const shouldTrackName = share === "main" && process.env.NODE_ENV !== "test";
|
|
1376
|
-
const releaseStoreName = () => {
|
|
1377
|
-
if (shouldTrackName) namespaceMap.delete(name);
|
|
1378
|
-
};
|
|
1379
|
-
if (shouldTrackName) {
|
|
1380
|
-
if (namespaceMap.get(name)) throw new Error(`Store name '${name}' is not unique.`);
|
|
1381
|
-
namespaceMap.set(name, true);
|
|
1382
|
-
}
|
|
1383
|
-
try {
|
|
1384
|
-
const { setState, getState } = handleState(store, internal, options);
|
|
1385
|
-
const subscribe = (listener) => {
|
|
1386
|
-
internal.assertAlive?.("subscribe");
|
|
1387
|
-
internal.listeners.add(listener);
|
|
1388
|
-
return () => internal.listeners.delete(listener);
|
|
1389
|
-
};
|
|
1390
|
-
let isDestroyed = false;
|
|
1391
|
-
internal.assertAlive = (operation) => {
|
|
1392
|
-
if (isDestroyed) throw new Error(`${operation} cannot be called after store.destroy().`);
|
|
1393
|
-
};
|
|
1394
|
-
const destroy = () => {
|
|
1395
|
-
if (isDestroyed) return;
|
|
1396
|
-
isDestroyed = true;
|
|
1397
|
-
internal.listeners.clear();
|
|
1398
|
-
store.transport?.dispose();
|
|
1399
|
-
releaseStoreName();
|
|
1400
|
-
};
|
|
1401
|
-
const apply$1 = (state = internal.rootState, patches) => {
|
|
1402
|
-
internal.assertAlive?.("apply");
|
|
1403
|
-
internal.assertMutationAllowed?.("apply");
|
|
1404
|
-
assertSafePatches(patches, "store.apply()");
|
|
1405
|
-
const safePatches = sanitizePatches(patches);
|
|
1406
|
-
const baseState = state === internal.module ? internal.rootState : state;
|
|
1407
|
-
const nextState = sanitizeReplacementState(safePatches ? apply(baseState, safePatches) : baseState);
|
|
1408
|
-
assertKnownStateShape(nextState, internal.rootState, internal.stateSchema, store.isSliceStore, { requireSliceRoots: true });
|
|
1409
|
-
if (store.share === "main") validateSharedStateSerializable(nextState);
|
|
1410
|
-
internal.rootState = nextState;
|
|
1411
|
-
refreshSignalSlots(internal);
|
|
1412
|
-
if (internal.updateImmutable) internal.updateImmutable(internal.rootState);
|
|
1413
|
-
else internal.listeners.forEach((listener) => listener());
|
|
1414
|
-
};
|
|
1415
|
-
const getPureState = () => internal.rootState;
|
|
1416
|
-
const isFunctionMapObject = () => {
|
|
1417
|
-
if (typeof createState === "object" && createState !== null) {
|
|
1418
|
-
const values = getOwnEnumerableKeys(createState).map((key) => createState[key]);
|
|
1419
|
-
return values.length > 0 && values.every((value) => typeof value === "function");
|
|
1420
|
-
}
|
|
1421
|
-
return false;
|
|
1422
|
-
};
|
|
1423
|
-
const getIsSliceStore = () => {
|
|
1424
|
-
const sliceMode = options.sliceMode ?? "auto";
|
|
1425
|
-
if (sliceMode === "single") return false;
|
|
1426
|
-
if (sliceMode === "slices") {
|
|
1427
|
-
if (!isFunctionMapObject()) throw new Error(`sliceMode: 'slices' requires createState to be an object of slice functions.`);
|
|
1428
|
-
return true;
|
|
1429
|
-
}
|
|
1430
|
-
if (isFunctionMapObject()) {
|
|
1431
|
-
warnAmbiguousFunctionMap();
|
|
1432
|
-
return true;
|
|
1433
|
-
}
|
|
1434
|
-
return false;
|
|
1435
|
-
};
|
|
1436
|
-
const isSliceStore = getIsSliceStore();
|
|
1437
|
-
Object.assign(store, {
|
|
1438
|
-
name,
|
|
1439
|
-
share: share ?? false,
|
|
1440
|
-
setState,
|
|
1441
|
-
getState,
|
|
1442
|
-
subscribe,
|
|
1443
|
-
destroy,
|
|
1444
|
-
apply: apply$1,
|
|
1445
|
-
isSliceStore,
|
|
1446
|
-
getPureState
|
|
1447
|
-
});
|
|
1448
|
-
const middlewareStore = applyMiddlewares(store, options.middlewares ?? []);
|
|
1449
|
-
if (middlewareStore !== store) Object.assign(store, middlewareStore);
|
|
1450
|
-
const initialState = getInitialState(store, createState, internal);
|
|
1451
|
-
if (share) validateSharedActionPaths(initialState);
|
|
1452
|
-
store.getInitialState = () => initialState;
|
|
1453
|
-
internal.rootState = getRawState(store, internal, initialState, options);
|
|
1454
|
-
internal.stateSchema = createStateSchema(internal.rootState, store.isSliceStore);
|
|
1455
|
-
if (share) validateSharedStateSerializable(internal.rootState);
|
|
1456
|
-
markStoreReady(store);
|
|
1457
|
-
return {
|
|
1458
|
-
store,
|
|
1459
|
-
internal
|
|
1460
|
-
};
|
|
1461
|
-
} catch (error) {
|
|
1462
|
-
releaseStoreName();
|
|
1463
|
-
throw error;
|
|
1464
|
-
}
|
|
1465
|
-
};
|
|
1466
|
-
if (options.clientTransport || options.worker || options.workerType === "WebWorkerClient" || options.workerType === "SharedWorkerClient") {
|
|
1467
|
-
if (checkEnablePatches) throw new Error(`enablePatches: true is required for the async store`);
|
|
1468
|
-
return wrapStore(createAsyncClientStore(createStore, options));
|
|
1469
|
-
}
|
|
1470
|
-
const { store, internal } = createStore({ share });
|
|
1471
|
-
handleMainTransport(store, internal, storeTransport, workerType, checkEnablePatches);
|
|
1472
|
-
return wrapStore(store);
|
|
1473
|
-
};
|
|
1474
|
-
//#endregion
|
|
1475
|
-
//#region packages/core/src/binder.ts
|
|
1476
|
-
const createExternalStoreAdapter = ({ handleState, handleStore }) => ((state) => {
|
|
1477
|
-
const { copyState, key, bind } = handleState(state);
|
|
1478
|
-
const value = typeof key !== "undefined" ? copyState[key] : copyState;
|
|
1479
|
-
Object.defineProperty(value, bindSymbol, {
|
|
1480
|
-
configurable: true,
|
|
1481
|
-
enumerable: typeof key !== "undefined",
|
|
1482
|
-
value: {
|
|
1483
|
-
handleStore,
|
|
1484
|
-
bind
|
|
1485
|
-
}
|
|
1486
|
-
});
|
|
1487
|
-
return copyState;
|
|
1488
|
-
});
|
|
1489
|
-
/**
|
|
1490
|
-
* Build an adapter helper for bridging an external store implementation into
|
|
1491
|
-
* Coaction.
|
|
1492
|
-
*
|
|
1493
|
-
* @remarks
|
|
1494
|
-
* Official bindings use this to integrate stores such as Redux, Jotai, Pinia,
|
|
1495
|
-
* Zustand, MobX, and Valtio. Binder-backed integrations are whole-store
|
|
1496
|
-
* adapters; they are not compatible with Coaction slices mode.
|
|
1497
|
-
*/
|
|
1498
|
-
function createBinder({ handleState, handleStore }) {
|
|
1499
|
-
return createExternalStoreAdapter({
|
|
1500
|
-
handleState,
|
|
1501
|
-
handleStore
|
|
2082
|
+
const share = isMainWorkerType(workerType) || storeTransport ? "main" : void 0;
|
|
2083
|
+
const buildStore = ({ share }) => createStore(createState, options, {
|
|
2084
|
+
share,
|
|
2085
|
+
clientAction: share === "client" ? createClientAction : void 0,
|
|
2086
|
+
collectActionPaths: share === "main" ? validateSharedActionPaths : void 0,
|
|
2087
|
+
validateInitialState: share ? validateSharedInitialState : void 0,
|
|
2088
|
+
validatePatches: share === "main" ? validateUpdatePatches : void 0,
|
|
2089
|
+
validateReplacementSource: share ? validateSharedReplacementSource : void 0,
|
|
2090
|
+
validateState: share ? validateSharedStateSerializable : void 0
|
|
1502
2091
|
});
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
* Coaction.
|
|
1507
|
-
*
|
|
1508
|
-
* @remarks
|
|
1509
|
-
* This is the stable 2.x name for adapter authors. `createBinder()` remains as
|
|
1510
|
-
* a compatibility alias for existing official and community integrations.
|
|
1511
|
-
*/
|
|
1512
|
-
function defineExternalStoreAdapter(options) {
|
|
1513
|
-
return createExternalStoreAdapter(options);
|
|
1514
|
-
}
|
|
1515
|
-
//#endregion
|
|
1516
|
-
//#region packages/core/src/reactiveTracker.ts
|
|
1517
|
-
const ReactiveFlags = alienSignalsSystem.ReactiveFlags;
|
|
1518
|
-
const unwatch = (node) => {
|
|
1519
|
-
if (!(node.flags & ReactiveFlags.Mutable)) {
|
|
1520
|
-
node.depsTail = void 0;
|
|
1521
|
-
node.flags = 0;
|
|
1522
|
-
purgeDeps(node);
|
|
1523
|
-
const sub = node.subs;
|
|
1524
|
-
if (sub !== void 0) unlink(sub);
|
|
1525
|
-
return;
|
|
1526
|
-
}
|
|
1527
|
-
if (node.depsTail !== void 0) {
|
|
1528
|
-
node.depsTail = void 0;
|
|
1529
|
-
node.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty;
|
|
1530
|
-
purgeDeps(node);
|
|
2092
|
+
if (options.clientTransport || options.worker || isClientWorkerType(options.workerType)) {
|
|
2093
|
+
if (checkEnablePatches) throw new Error("enablePatches: true is required for the async store");
|
|
2094
|
+
return wrapStore(createAsyncClientStore(buildStore, options));
|
|
1531
2095
|
}
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
const dep = link.dep;
|
|
1535
|
-
const prevDep = link.prevDep;
|
|
1536
|
-
const nextDep = link.nextDep;
|
|
1537
|
-
const nextSub = link.nextSub;
|
|
1538
|
-
const prevSub = link.prevSub;
|
|
1539
|
-
if (nextDep !== void 0) nextDep.prevDep = prevDep;
|
|
1540
|
-
else sub.depsTail = prevDep;
|
|
1541
|
-
if (prevDep !== void 0) prevDep.nextDep = nextDep;
|
|
1542
|
-
else sub.deps = nextDep;
|
|
1543
|
-
if (nextSub !== void 0) nextSub.prevSub = prevSub;
|
|
1544
|
-
else dep.subsTail = prevSub;
|
|
1545
|
-
if (prevSub !== void 0) prevSub.nextSub = nextSub;
|
|
1546
|
-
else if ((dep.subs = nextSub) === void 0) unwatch(dep);
|
|
1547
|
-
return nextDep;
|
|
1548
|
-
};
|
|
1549
|
-
const purgeDeps = (sub) => {
|
|
1550
|
-
const depsTail = sub.depsTail;
|
|
1551
|
-
let dep = depsTail !== void 0 ? depsTail.nextDep : sub.deps;
|
|
1552
|
-
while (dep !== void 0) dep = unlink(dep, sub);
|
|
1553
|
-
};
|
|
1554
|
-
const createReactiveTracker = () => {
|
|
1555
|
-
let version = 0;
|
|
1556
|
-
let disposed = false;
|
|
1557
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
1558
|
-
const node = {
|
|
1559
|
-
deps: void 0,
|
|
1560
|
-
depsTail: void 0,
|
|
1561
|
-
subs: void 0,
|
|
1562
|
-
subsTail: void 0,
|
|
1563
|
-
flags: ReactiveFlags.Watching,
|
|
1564
|
-
fn: () => {
|
|
1565
|
-
if (disposed) return;
|
|
1566
|
-
version += 1;
|
|
1567
|
-
listeners.forEach((listener) => listener());
|
|
1568
|
-
}
|
|
1569
|
-
};
|
|
1570
|
-
const dispose = () => {
|
|
1571
|
-
if (disposed) return;
|
|
1572
|
-
disposed = true;
|
|
1573
|
-
listeners.clear();
|
|
1574
|
-
node.depsTail = void 0;
|
|
1575
|
-
purgeDeps(node);
|
|
1576
|
-
node.flags = 0;
|
|
1577
|
-
};
|
|
1578
|
-
return {
|
|
1579
|
-
getSnapshot: () => version,
|
|
1580
|
-
subscribe(listener) {
|
|
1581
|
-
if (disposed) return () => void 0;
|
|
1582
|
-
listeners.add(listener);
|
|
1583
|
-
return () => {
|
|
1584
|
-
listeners.delete(listener);
|
|
1585
|
-
};
|
|
1586
|
-
},
|
|
1587
|
-
track(fn) {
|
|
1588
|
-
if (disposed) return fn();
|
|
1589
|
-
node.depsTail = void 0;
|
|
1590
|
-
node.flags = ReactiveFlags.Watching | ReactiveFlags.RecursedCheck;
|
|
1591
|
-
const prevSub = setActiveSub(node);
|
|
1592
|
-
try {
|
|
1593
|
-
return fn();
|
|
1594
|
-
} finally {
|
|
1595
|
-
setActiveSub(prevSub);
|
|
1596
|
-
node.flags &= ~ReactiveFlags.RecursedCheck;
|
|
1597
|
-
purgeDeps(node);
|
|
1598
|
-
}
|
|
1599
|
-
},
|
|
1600
|
-
dispose
|
|
1601
|
-
};
|
|
1602
|
-
};
|
|
1603
|
-
//#endregion
|
|
1604
|
-
//#region packages/core/src/replaceExternalStoreState.ts
|
|
1605
|
-
const replaceExternalStoreState = (store, internal, source, { syncImmutable = true } = {}) => {
|
|
1606
|
-
const [, patches, inversePatches] = create$1(internal.rootState, (draft) => {
|
|
1607
|
-
replaceOwnEnumerable(draft, source);
|
|
1608
|
-
}, { enablePatches: true });
|
|
1609
|
-
const safePatches = sanitizeCheckedPatches((store.patch ? store.patch({
|
|
1610
|
-
patches,
|
|
1611
|
-
inversePatches
|
|
1612
|
-
}) : {
|
|
1613
|
-
patches,
|
|
1614
|
-
inversePatches
|
|
1615
|
-
}).patches, "store.patch()");
|
|
1616
|
-
if (!safePatches.length) return;
|
|
1617
|
-
const updateImmutable = internal.updateImmutable;
|
|
1618
|
-
if (!syncImmutable) internal.updateImmutable = void 0;
|
|
2096
|
+
if (share === "main" && checkEnablePatches) throw new Error("enablePatches: true is required for the transport");
|
|
2097
|
+
let builtStore;
|
|
1619
2098
|
try {
|
|
1620
|
-
|
|
1621
|
-
}
|
|
1622
|
-
|
|
1623
|
-
}
|
|
1624
|
-
emit(store, internal, safePatches);
|
|
1625
|
-
};
|
|
1626
|
-
//#endregion
|
|
1627
|
-
//#region packages/core/src/externalMutableAdapterUtils.ts
|
|
1628
|
-
const getMutableAdapterOwnEnumerableKeys = (value) => Reflect.ownKeys(value).filter((key) => Object.prototype.propertyIsEnumerable.call(value, key));
|
|
1629
|
-
const isMutableAdapterUnsafeKey = (key) => typeof key === "string" && isUnsafeKey(key);
|
|
1630
|
-
const isArrayIndexKey = (key) => {
|
|
1631
|
-
if (typeof key !== "string") return false;
|
|
1632
|
-
const index = Number(key);
|
|
1633
|
-
return Number.isInteger(index) && index >= 0 && index < 2 ** 32 - 1 && String(index) === key;
|
|
1634
|
-
};
|
|
1635
|
-
const isObjectRecord = (value) => Object.prototype.toString.call(value) === "[object Object]";
|
|
1636
|
-
const assertCanSetMutableAdapterPublicStateKey = (publicState, key) => {
|
|
1637
|
-
if (Object.prototype.hasOwnProperty.call(publicState, key)) return;
|
|
1638
|
-
if (Object.isExtensible(publicState)) return;
|
|
1639
|
-
throw new StateSchemaError(`Unknown state key '${String(key)}' cannot be added after store initialization. Coaction state schema is fixed.`);
|
|
1640
|
-
};
|
|
1641
|
-
const ensureMutableAdapterRawDescriptor = (rawState, mutableState, publicState, key) => {
|
|
1642
|
-
if (rawState === mutableState) return;
|
|
1643
|
-
const rawDescriptor = Object.getOwnPropertyDescriptor(rawState, key);
|
|
1644
|
-
if (rawDescriptor?.get && rawDescriptor.set) return;
|
|
1645
|
-
const publicDescriptor = Object.getOwnPropertyDescriptor(publicState, key);
|
|
1646
|
-
if (!publicDescriptor || rawDescriptor?.configurable === false) return;
|
|
1647
|
-
Object.defineProperty(rawState, key, {
|
|
1648
|
-
get: () => mutableState[key],
|
|
1649
|
-
set: (value) => {
|
|
1650
|
-
mutableState[key] = value;
|
|
1651
|
-
},
|
|
1652
|
-
configurable: true,
|
|
1653
|
-
enumerable: publicDescriptor.enumerable
|
|
1654
|
-
});
|
|
1655
|
-
};
|
|
1656
|
-
const replaceMutableAdapterState = (rawState, mutableState, publicState, source) => {
|
|
1657
|
-
const nextKeys = /* @__PURE__ */ new Set();
|
|
1658
|
-
for (const key of getMutableAdapterOwnEnumerableKeys(source)) {
|
|
1659
|
-
if (isMutableAdapterUnsafeKey(key)) continue;
|
|
1660
|
-
if (typeof source[key] === "function") continue;
|
|
1661
|
-
nextKeys.add(key);
|
|
2099
|
+
builtStore = buildStore({ share });
|
|
2100
|
+
} catch (error) {
|
|
2101
|
+
return failTransportInitialization(storeTransport, error);
|
|
1662
2102
|
}
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
continue;
|
|
1671
|
-
}
|
|
1672
|
-
if (typeof rawState[key] === "function") continue;
|
|
1673
|
-
if (!nextKeys.has(key)) {
|
|
1674
|
-
delete rawState[key];
|
|
1675
|
-
delete mutableState[key];
|
|
1676
|
-
}
|
|
1677
|
-
}
|
|
1678
|
-
const rawSeen = /* @__PURE__ */ new WeakMap();
|
|
1679
|
-
const mutableSeen = /* @__PURE__ */ new WeakMap();
|
|
1680
|
-
const publicSeen = /* @__PURE__ */ new WeakMap();
|
|
1681
|
-
rawSeen.set(source, rawState);
|
|
1682
|
-
mutableSeen.set(source, mutableState);
|
|
1683
|
-
publicSeen.set(source, publicState);
|
|
1684
|
-
nextKeys.forEach((key) => {
|
|
1685
|
-
ensureMutableAdapterRawDescriptor(rawState, mutableState, publicState, key);
|
|
1686
|
-
rawState[key] = sanitizeReplacementState(source[key], rawSeen);
|
|
1687
|
-
mutableState[key] = sanitizeReplacementState(source[key], mutableSeen);
|
|
1688
|
-
publicState[key] = sanitizeReplacementState(source[key], publicSeen);
|
|
1689
|
-
});
|
|
1690
|
-
};
|
|
1691
|
-
const applyMutableAdapterPatches = (baseState, patches, rawState, mutableState, publicState) => {
|
|
1692
|
-
assertSafePatches(patches, "mutable adapter apply()");
|
|
1693
|
-
replaceMutableAdapterState(rawState, mutableState, publicState, apply(toMutableAdapterSnapshot(baseState === publicState ? rawState : baseState), patches));
|
|
1694
|
-
};
|
|
1695
|
-
const toMutableAdapterSnapshot = (value, visited = /* @__PURE__ */ new WeakMap()) => {
|
|
1696
|
-
if (Array.isArray(value)) {
|
|
1697
|
-
if (visited.has(value)) return visited.get(value);
|
|
1698
|
-
const next = [];
|
|
1699
|
-
next.length = value.length;
|
|
1700
|
-
visited.set(value, next);
|
|
1701
|
-
for (let index = 0; index < value.length; index += 1) if (Object.prototype.hasOwnProperty.call(value, index)) next[index] = toMutableAdapterSnapshot(value[index], visited);
|
|
1702
|
-
const source = value;
|
|
1703
|
-
const target = next;
|
|
1704
|
-
for (const key of getMutableAdapterOwnEnumerableKeys(value)) {
|
|
1705
|
-
if (isArrayIndexKey(key) || isMutableAdapterUnsafeKey(key)) continue;
|
|
1706
|
-
const child = source[key];
|
|
1707
|
-
if (typeof child !== "function") target[key] = toMutableAdapterSnapshot(child, visited);
|
|
1708
|
-
}
|
|
1709
|
-
return next;
|
|
1710
|
-
}
|
|
1711
|
-
if (typeof value === "object" && value !== null) {
|
|
1712
|
-
if (!isObjectRecord(value)) return value;
|
|
1713
|
-
if (visited.has(value)) return visited.get(value);
|
|
1714
|
-
const next = {};
|
|
1715
|
-
visited.set(value, next);
|
|
1716
|
-
for (const key of getMutableAdapterOwnEnumerableKeys(value)) {
|
|
1717
|
-
if (isMutableAdapterUnsafeKey(key)) continue;
|
|
1718
|
-
const child = value[key];
|
|
1719
|
-
if (typeof child !== "function") next[key] = toMutableAdapterSnapshot(child, visited);
|
|
1720
|
-
}
|
|
1721
|
-
return next;
|
|
1722
|
-
}
|
|
1723
|
-
return value;
|
|
1724
|
-
};
|
|
1725
|
-
const snapshotMutableAdapterPureState = (store) => toMutableAdapterSnapshot(store.getPureState());
|
|
1726
|
-
const isEqualMutableAdapterSnapshot = (left, right, visited = /* @__PURE__ */ new WeakMap()) => {
|
|
1727
|
-
if (Object.is(left, right)) return true;
|
|
1728
|
-
if (typeof left !== "object" || left === null || typeof right !== "object" || right === null) return false;
|
|
1729
|
-
const leftIsArray = Array.isArray(left);
|
|
1730
|
-
const rightIsArray = Array.isArray(right);
|
|
1731
|
-
if (leftIsArray || rightIsArray) {
|
|
1732
|
-
if (!leftIsArray || !rightIsArray || left.length !== right.length) return false;
|
|
1733
|
-
} else if (!isObjectRecord(left) || !isObjectRecord(right)) return false;
|
|
1734
|
-
let seenTargets = visited.get(left);
|
|
1735
|
-
if (!seenTargets) {
|
|
1736
|
-
seenTargets = /* @__PURE__ */ new WeakSet();
|
|
1737
|
-
visited.set(left, seenTargets);
|
|
1738
|
-
} else if (seenTargets.has(right)) return true;
|
|
1739
|
-
seenTargets.add(right);
|
|
1740
|
-
const leftRecord = left;
|
|
1741
|
-
const rightRecord = right;
|
|
1742
|
-
const leftKeys = getMutableAdapterOwnEnumerableKeys(left);
|
|
1743
|
-
const rightKeys = getMutableAdapterOwnEnumerableKeys(right);
|
|
1744
|
-
if (leftKeys.length !== rightKeys.length) return false;
|
|
1745
|
-
for (const key of leftKeys) {
|
|
1746
|
-
if (!Object.prototype.hasOwnProperty.call(rightRecord, key)) return false;
|
|
1747
|
-
if (!isEqualMutableAdapterSnapshot(leftRecord[key], rightRecord[key], visited)) return false;
|
|
2103
|
+
const { store, internal } = builtStore;
|
|
2104
|
+
try {
|
|
2105
|
+
handleMainTransport(store, internal, storeTransport, workerType, checkEnablePatches, options.transportPolicy);
|
|
2106
|
+
markStoreReady(store);
|
|
2107
|
+
internal.assertAlive?.("store initialization");
|
|
2108
|
+
} catch (error) {
|
|
2109
|
+
return failStoreSetup(store, error);
|
|
1748
2110
|
}
|
|
1749
|
-
return
|
|
2111
|
+
return wrapStore(store);
|
|
1750
2112
|
};
|
|
1751
2113
|
//#endregion
|
|
1752
|
-
export { StateSchemaError, UnsafePatchPathError,
|
|
2114
|
+
export { ActionAuthorityChangedError, StateSchemaError, UnsafePatchPathError, assertSafePatches, computed, create, effect, effectScope, endBatch, isComputed, isEffect, isEffectScope, isSignal, isStateSchemaError, onStoreReady, sanitizeInitialStateValue, sanitizePatches, sanitizeReplacementState, signal, startBatch, trigger };
|