coaction 2.0.0 → 2.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 +25 -19
- package/dist/index.d.mts +52 -1
- package/dist/index.d.ts +52 -1
- package/dist/index.js +433 -29
- package/dist/index.mjs +420 -30
- package/package.json +9 -4
package/README.md
CHANGED
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
# coaction
|
|
2
2
|
|
|
3
|
-

|
|
4
|
-
[](https://www.npmjs.com/package/coaction)
|
|
5
|
-

|
|
3
|
+
 [](https://www.npmjs.com/package/coaction) 
|
|
6
4
|
|
|
7
5
|
An efficient and flexible state management library for building high-performance, multithreading web applications.
|
|
8
6
|
|
|
9
|
-
Coaction
|
|
10
|
-
React selector reactivity, and adapter-facing subscriptions. The core package
|
|
11
|
-
also re-exports the signal primitives for advanced integrations.
|
|
7
|
+
Coaction uses `alien-signals` internally for cached getter/computed state, React selector reactivity, and adapter-facing subscriptions. The core package also re-exports the signal primitives for advanced integrations.
|
|
12
8
|
|
|
13
9
|
## Installation
|
|
14
10
|
|
|
15
|
-
|
|
11
|
+
Install it with pnpm:
|
|
16
12
|
|
|
17
13
|
```sh
|
|
18
|
-
|
|
14
|
+
pnpm add coaction
|
|
19
15
|
```
|
|
20
16
|
|
|
21
17
|
## Usage
|
|
@@ -36,8 +32,13 @@ const store = create((set) => ({
|
|
|
36
32
|
}));
|
|
37
33
|
```
|
|
38
34
|
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
Core stores are immutable by default. Getters and methods can read through `this`, but writes to Coaction-owned state must happen inside `set()` or `set((draft) => ...)`. Direct writes such as `this.count += 1` in a store method throw because they bypass the commit path that notifies subscribers, produces patches when enabled, and synchronizes worker/client mirrors in shared mode.
|
|
36
|
+
|
|
37
|
+
Coaction fixes the public state schema after initialization. A single store cannot add new top-level state keys later, and a slices store cannot add new slice keys or new top-level fields inside a slice. Replacement-style APIs such as `apply()` may omit a known single-store root key; the public getter remains present and reads as `undefined`, but no unknown key is promoted into the public module. Slice root keys are stricter and cannot be removed or replaced with non-object values. Keep dynamic data inside an existing object or array field.
|
|
38
|
+
|
|
39
|
+
Mutable adapters such as MobX, Pinia, and Valtio keep Coaction raw state, public state, and the external mutable runtime synchronized for known schema keys. Coaction still treats its raw/public schema as authoritative: out-of-band unknown properties written directly onto a third-party mutable runtime are not promoted into Coaction state, and adapter-specific docs define whether that external runtime property is pruned, restored, or left to the underlying library.
|
|
40
|
+
|
|
41
|
+
Accessor getters are cached automatically through the built-in signal runtime. Use `get(deps, selector)` when you want to declare dependencies manually:
|
|
41
42
|
|
|
42
43
|
```ts
|
|
43
44
|
const store = create((set, get) => ({
|
|
@@ -54,15 +55,24 @@ const store = create((set, get) => ({
|
|
|
54
55
|
}));
|
|
55
56
|
```
|
|
56
57
|
|
|
57
|
-
Advanced integrations can import the native signal primitives and adapter helper
|
|
58
|
-
directly from `coaction`:
|
|
58
|
+
Advanced integrations can import the native signal primitives and adapter helper directly from `coaction`:
|
|
59
59
|
|
|
60
60
|
```ts
|
|
61
61
|
import { computed, defineExternalStoreAdapter, effect, signal } from 'coaction';
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
### Adapter and Middleware Utilities
|
|
65
|
+
|
|
66
|
+
`coaction` also exports utilities for adapter and middleware authors. These are not needed for normal application state updates, but they are part of the supported integration surface used by the official packages:
|
|
67
|
+
|
|
68
|
+
- Mutable adapter helpers: `applyMutableAdapterPatches`, `replaceMutableAdapterState`, `toMutableAdapterSnapshot`, `snapshotMutableAdapterPureState`, `isEqualMutableAdapterSnapshot`, `getMutableAdapterOwnEnumerableKeys`, `isMutableAdapterUnsafeKey`.
|
|
69
|
+
- Root replacement helpers: `createRootReplacementPatches`, `applyRootReplacementWithPatches`.
|
|
70
|
+
- Patch safety helpers: `assertSafePatches`, `sanitizePatches`, `UnsafePatchPathError`.
|
|
71
|
+
- State shape helpers: `StateSchemaError`, `isStateSchemaError`, `sanitizeReplacementState`, `sanitizeInitialStateValue`, `replaceOwnEnumerable`.
|
|
72
|
+
|
|
73
|
+
Runtime mutation paths reject unsafe patch paths before applying state changes. If a `store.patch()` hook returns a path containing `__proto__`, `prototype`, or `constructor`, Coaction throws `UnsafePatchPathError` instead of silently dropping that patch and applying the rest.
|
|
74
|
+
|
|
75
|
+
Store methods using `this` are rebound to the latest state when invoked from `getState()`, so destructuring remains safe:
|
|
66
76
|
|
|
67
77
|
```ts
|
|
68
78
|
const store = create((set) => ({
|
|
@@ -85,11 +95,7 @@ increment();
|
|
|
85
95
|
|
|
86
96
|
### Store Shape Mode (`sliceMode`)
|
|
87
97
|
|
|
88
|
-
`create()` uses `sliceMode: 'auto'` by default. For backward compatibility,
|
|
89
|
-
`auto` still treats a non-empty object whose enumerable values are all
|
|
90
|
-
functions as slices. That shape is ambiguous with a plain store that only
|
|
91
|
-
contains methods, so development builds warn and you should set `sliceMode`
|
|
92
|
-
explicitly.
|
|
98
|
+
`create()` uses `sliceMode: 'auto'` by default. For backward compatibility, `auto` still treats a non-empty object whose enumerable values are all functions as slices. That shape is ambiguous with a plain store that only contains methods, so development builds warn and you should set `sliceMode` explicitly.
|
|
93
99
|
|
|
94
100
|
You can force behavior explicitly:
|
|
95
101
|
|
package/dist/index.d.mts
CHANGED
|
@@ -393,9 +393,14 @@ declare const create: Creator;
|
|
|
393
393
|
//#endregion
|
|
394
394
|
//#region packages/core/src/internal.d.ts
|
|
395
395
|
type MutationOperation = 'setState' | 'apply';
|
|
396
|
+
type StoreOperation = MutationOperation | 'subscribe' | `action ${string}`;
|
|
396
397
|
type SignalSlot = {
|
|
397
398
|
refresh: () => void;
|
|
398
399
|
};
|
|
400
|
+
type StateSchema = {
|
|
401
|
+
rootKeys: Set<PropertyKey>;
|
|
402
|
+
sliceKeys?: Map<PropertyKey, Set<PropertyKey>>;
|
|
403
|
+
};
|
|
399
404
|
interface Internal<T extends CreateState = CreateState> {
|
|
400
405
|
/**
|
|
401
406
|
* The store module.
|
|
@@ -438,6 +443,10 @@ interface Internal<T extends CreateState = CreateState> {
|
|
|
438
443
|
* Reactive state slots used by computed getters/selectors.
|
|
439
444
|
*/
|
|
440
445
|
signalSlots?: Set<SignalSlot>;
|
|
446
|
+
/**
|
|
447
|
+
* State keys that are allowed after initialization.
|
|
448
|
+
*/
|
|
449
|
+
stateSchema?: StateSchema;
|
|
441
450
|
/**
|
|
442
451
|
* The act is used to run the function in the action for mutable state.
|
|
443
452
|
*/
|
|
@@ -454,6 +463,10 @@ interface Internal<T extends CreateState = CreateState> {
|
|
|
454
463
|
* Adapter-level authority check for low-level mutations.
|
|
455
464
|
*/
|
|
456
465
|
assertMutationAllowed?: (operation: MutationOperation) => void;
|
|
466
|
+
/**
|
|
467
|
+
* Store lifecycle guard.
|
|
468
|
+
*/
|
|
469
|
+
assertAlive?: (operation: StoreOperation) => void;
|
|
457
470
|
/**
|
|
458
471
|
* Authorized client-mirror state application used by transports.
|
|
459
472
|
*/
|
|
@@ -555,7 +568,45 @@ declare const replaceExternalStoreState: <T extends CreateState>(store: Middlewa
|
|
|
555
568
|
syncImmutable
|
|
556
569
|
}?: ReplaceExternalStoreStateOptions) => void;
|
|
557
570
|
//#endregion
|
|
571
|
+
//#region packages/core/src/externalMutableAdapterUtils.d.ts
|
|
572
|
+
declare const getMutableAdapterOwnEnumerableKeys: (value: object) => (string | symbol)[];
|
|
573
|
+
declare const isMutableAdapterUnsafeKey: (key: PropertyKey) => key is "__proto__" | "prototype" | "constructor";
|
|
574
|
+
declare const replaceMutableAdapterState: (rawState: Record<PropertyKey, unknown>, mutableState: Record<PropertyKey, unknown>, publicState: Record<PropertyKey, unknown>, source: Record<PropertyKey, unknown>) => void;
|
|
575
|
+
declare const applyMutableAdapterPatches: (baseState: unknown, patches: Patches, rawState: Record<PropertyKey, unknown>, mutableState: Record<PropertyKey, unknown>, publicState: Record<PropertyKey, unknown>) => void;
|
|
576
|
+
declare const toMutableAdapterSnapshot: (value: unknown, visited?: WeakMap<object, unknown>) => unknown;
|
|
577
|
+
declare const snapshotMutableAdapterPureState: (store: Store<object>) => Record<PropertyKey, unknown>;
|
|
578
|
+
declare const isEqualMutableAdapterSnapshot: (left: unknown, right: unknown, visited?: WeakMap<object, WeakSet<object>>) => boolean;
|
|
579
|
+
//#endregion
|
|
558
580
|
//#region packages/core/src/utils.d.ts
|
|
581
|
+
declare class UnsafePatchPathError extends Error {
|
|
582
|
+
name: string;
|
|
583
|
+
}
|
|
584
|
+
declare class StateSchemaError extends Error {
|
|
585
|
+
name: string;
|
|
586
|
+
}
|
|
587
|
+
declare const isStateSchemaError: (error: unknown) => error is StateSchemaError;
|
|
588
|
+
declare const assertSafePatches: <T extends {
|
|
589
|
+
path: unknown;
|
|
590
|
+
}>(patches: T[] | undefined, source?: string) => void;
|
|
591
|
+
declare const sanitizePatches: <T extends {
|
|
592
|
+
path: unknown;
|
|
593
|
+
value?: unknown;
|
|
594
|
+
}>(patches: T[] | undefined, options?: {
|
|
595
|
+
source?: string;
|
|
596
|
+
warnOnDropped?: boolean;
|
|
597
|
+
}) => T[] | undefined;
|
|
598
|
+
type RootReplacementPatch = {
|
|
599
|
+
op: 'add' | 'remove' | 'replace';
|
|
600
|
+
path: PropertyKey[];
|
|
601
|
+
value?: unknown;
|
|
602
|
+
};
|
|
603
|
+
declare const createRootReplacementPatches: (currentState: Record<PropertyKey, unknown>, nextState: Record<PropertyKey, unknown>) => {
|
|
604
|
+
patches: RootReplacementPatch[];
|
|
605
|
+
inversePatches: RootReplacementPatch[];
|
|
606
|
+
};
|
|
607
|
+
declare const applyRootReplacementWithPatches: <T extends object>(store: MiddlewareStore<T>, nextState: Record<PropertyKey, unknown>, options?: {
|
|
608
|
+
applyExactReplacement?: (state: T) => void;
|
|
609
|
+
}) => [T, Patches, Patches];
|
|
559
610
|
declare const replaceOwnEnumerable: (target: Record<PropertyKey, unknown>, source: Record<PropertyKey, unknown>) => void;
|
|
560
611
|
declare const sanitizeReplacementState: <T>(source: T, seen?: WeakMap<object, unknown>) => T;
|
|
561
612
|
declare const sanitizeInitialStateValue: <T>(source: T, seen?: WeakMap<object, unknown>) => T;
|
|
@@ -572,4 +623,4 @@ declare const sanitizeInitialStateValue: <T>(source: T, seen?: WeakMap<object, u
|
|
|
572
623
|
*/
|
|
573
624
|
declare const wrapStore: <T extends object>(store: Store<T>, getState?: (...args: unknown[]) => T) => StoreReturn<T>;
|
|
574
625
|
//#endregion
|
|
575
|
-
export { type StoreWithAsyncFunction as AsyncStore, type Asyncify, type ClientStoreOptions, type ExternalStoreAdapterOptions, type ISlices, type Middleware, type MiddlewareStore, type PatchTransform, type ReactiveTracker, type Slice, type SliceState, type Slices, type Store, type StoreOptions, type StoreTraceEvent, computed, create, createBinder, createReactiveTracker, defineExternalStoreAdapter, effect, effectScope, endBatch, isComputed, isEffect, isEffectScope, isSignal, onStoreReady, replaceExternalStoreState, replaceOwnEnumerable, sanitizeInitialStateValue, sanitizeReplacementState, signal, startBatch, trigger, wrapStore };
|
|
626
|
+
export { type StoreWithAsyncFunction as AsyncStore, type Asyncify, type ClientStoreOptions, type ExternalStoreAdapterOptions, type ISlices, type Middleware, type MiddlewareStore, type PatchTransform, type ReactiveTracker, type Slice, type SliceState, type Slices, StateSchemaError, type Store, type StoreOptions, type StoreTraceEvent, UnsafePatchPathError, applyMutableAdapterPatches, applyRootReplacementWithPatches, assertSafePatches, computed, create, createBinder, createReactiveTracker, createRootReplacementPatches, defineExternalStoreAdapter, effect, effectScope, endBatch, getMutableAdapterOwnEnumerableKeys, isComputed, isEffect, isEffectScope, isEqualMutableAdapterSnapshot, isMutableAdapterUnsafeKey, isSignal, isStateSchemaError, onStoreReady, replaceExternalStoreState, replaceMutableAdapterState, replaceOwnEnumerable, sanitizeInitialStateValue, sanitizePatches, sanitizeReplacementState, signal, snapshotMutableAdapterPureState, startBatch, toMutableAdapterSnapshot, trigger, wrapStore };
|
package/dist/index.d.ts
CHANGED
|
@@ -393,9 +393,14 @@ declare const create: Creator;
|
|
|
393
393
|
//#endregion
|
|
394
394
|
//#region packages/core/src/internal.d.ts
|
|
395
395
|
type MutationOperation = 'setState' | 'apply';
|
|
396
|
+
type StoreOperation = MutationOperation | 'subscribe' | `action ${string}`;
|
|
396
397
|
type SignalSlot = {
|
|
397
398
|
refresh: () => void;
|
|
398
399
|
};
|
|
400
|
+
type StateSchema = {
|
|
401
|
+
rootKeys: Set<PropertyKey>;
|
|
402
|
+
sliceKeys?: Map<PropertyKey, Set<PropertyKey>>;
|
|
403
|
+
};
|
|
399
404
|
interface Internal<T extends CreateState = CreateState> {
|
|
400
405
|
/**
|
|
401
406
|
* The store module.
|
|
@@ -438,6 +443,10 @@ interface Internal<T extends CreateState = CreateState> {
|
|
|
438
443
|
* Reactive state slots used by computed getters/selectors.
|
|
439
444
|
*/
|
|
440
445
|
signalSlots?: Set<SignalSlot>;
|
|
446
|
+
/**
|
|
447
|
+
* State keys that are allowed after initialization.
|
|
448
|
+
*/
|
|
449
|
+
stateSchema?: StateSchema;
|
|
441
450
|
/**
|
|
442
451
|
* The act is used to run the function in the action for mutable state.
|
|
443
452
|
*/
|
|
@@ -454,6 +463,10 @@ interface Internal<T extends CreateState = CreateState> {
|
|
|
454
463
|
* Adapter-level authority check for low-level mutations.
|
|
455
464
|
*/
|
|
456
465
|
assertMutationAllowed?: (operation: MutationOperation) => void;
|
|
466
|
+
/**
|
|
467
|
+
* Store lifecycle guard.
|
|
468
|
+
*/
|
|
469
|
+
assertAlive?: (operation: StoreOperation) => void;
|
|
457
470
|
/**
|
|
458
471
|
* Authorized client-mirror state application used by transports.
|
|
459
472
|
*/
|
|
@@ -555,7 +568,45 @@ declare const replaceExternalStoreState: <T extends CreateState>(store: Middlewa
|
|
|
555
568
|
syncImmutable
|
|
556
569
|
}?: ReplaceExternalStoreStateOptions) => void;
|
|
557
570
|
//#endregion
|
|
571
|
+
//#region packages/core/src/externalMutableAdapterUtils.d.ts
|
|
572
|
+
declare const getMutableAdapterOwnEnumerableKeys: (value: object) => (string | symbol)[];
|
|
573
|
+
declare const isMutableAdapterUnsafeKey: (key: PropertyKey) => key is "__proto__" | "prototype" | "constructor";
|
|
574
|
+
declare const replaceMutableAdapterState: (rawState: Record<PropertyKey, unknown>, mutableState: Record<PropertyKey, unknown>, publicState: Record<PropertyKey, unknown>, source: Record<PropertyKey, unknown>) => void;
|
|
575
|
+
declare const applyMutableAdapterPatches: (baseState: unknown, patches: Patches, rawState: Record<PropertyKey, unknown>, mutableState: Record<PropertyKey, unknown>, publicState: Record<PropertyKey, unknown>) => void;
|
|
576
|
+
declare const toMutableAdapterSnapshot: (value: unknown, visited?: WeakMap<object, unknown>) => unknown;
|
|
577
|
+
declare const snapshotMutableAdapterPureState: (store: Store<object>) => Record<PropertyKey, unknown>;
|
|
578
|
+
declare const isEqualMutableAdapterSnapshot: (left: unknown, right: unknown, visited?: WeakMap<object, WeakSet<object>>) => boolean;
|
|
579
|
+
//#endregion
|
|
558
580
|
//#region packages/core/src/utils.d.ts
|
|
581
|
+
declare class UnsafePatchPathError extends Error {
|
|
582
|
+
name: string;
|
|
583
|
+
}
|
|
584
|
+
declare class StateSchemaError extends Error {
|
|
585
|
+
name: string;
|
|
586
|
+
}
|
|
587
|
+
declare const isStateSchemaError: (error: unknown) => error is StateSchemaError;
|
|
588
|
+
declare const assertSafePatches: <T extends {
|
|
589
|
+
path: unknown;
|
|
590
|
+
}>(patches: T[] | undefined, source?: string) => void;
|
|
591
|
+
declare const sanitizePatches: <T extends {
|
|
592
|
+
path: unknown;
|
|
593
|
+
value?: unknown;
|
|
594
|
+
}>(patches: T[] | undefined, options?: {
|
|
595
|
+
source?: string;
|
|
596
|
+
warnOnDropped?: boolean;
|
|
597
|
+
}) => T[] | undefined;
|
|
598
|
+
type RootReplacementPatch = {
|
|
599
|
+
op: 'add' | 'remove' | 'replace';
|
|
600
|
+
path: PropertyKey[];
|
|
601
|
+
value?: unknown;
|
|
602
|
+
};
|
|
603
|
+
declare const createRootReplacementPatches: (currentState: Record<PropertyKey, unknown>, nextState: Record<PropertyKey, unknown>) => {
|
|
604
|
+
patches: RootReplacementPatch[];
|
|
605
|
+
inversePatches: RootReplacementPatch[];
|
|
606
|
+
};
|
|
607
|
+
declare const applyRootReplacementWithPatches: <T extends object>(store: MiddlewareStore<T>, nextState: Record<PropertyKey, unknown>, options?: {
|
|
608
|
+
applyExactReplacement?: (state: T) => void;
|
|
609
|
+
}) => [T, Patches, Patches];
|
|
559
610
|
declare const replaceOwnEnumerable: (target: Record<PropertyKey, unknown>, source: Record<PropertyKey, unknown>) => void;
|
|
560
611
|
declare const sanitizeReplacementState: <T>(source: T, seen?: WeakMap<object, unknown>) => T;
|
|
561
612
|
declare const sanitizeInitialStateValue: <T>(source: T, seen?: WeakMap<object, unknown>) => T;
|
|
@@ -572,4 +623,4 @@ declare const sanitizeInitialStateValue: <T>(source: T, seen?: WeakMap<object, u
|
|
|
572
623
|
*/
|
|
573
624
|
declare const wrapStore: <T extends object>(store: Store<T>, getState?: (...args: unknown[]) => T) => StoreReturn<T>;
|
|
574
625
|
//#endregion
|
|
575
|
-
export { type StoreWithAsyncFunction as AsyncStore, type Asyncify, type ClientStoreOptions, type ExternalStoreAdapterOptions, type ISlices, type Middleware, type MiddlewareStore, type PatchTransform, type ReactiveTracker, type Slice, type SliceState, type Slices, type Store, type StoreOptions, type StoreTraceEvent, computed, create, createBinder, createReactiveTracker, defineExternalStoreAdapter, effect, effectScope, endBatch, isComputed, isEffect, isEffectScope, isSignal, onStoreReady, replaceExternalStoreState, replaceOwnEnumerable, sanitizeInitialStateValue, sanitizeReplacementState, signal, startBatch, trigger, wrapStore };
|
|
626
|
+
export { type StoreWithAsyncFunction as AsyncStore, type Asyncify, type ClientStoreOptions, type ExternalStoreAdapterOptions, type ISlices, type Middleware, type MiddlewareStore, type PatchTransform, type ReactiveTracker, type Slice, type SliceState, type Slices, StateSchemaError, type Store, type StoreOptions, type StoreTraceEvent, UnsafePatchPathError, applyMutableAdapterPatches, applyRootReplacementWithPatches, assertSafePatches, computed, create, createBinder, createReactiveTracker, createRootReplacementPatches, defineExternalStoreAdapter, effect, effectScope, endBatch, getMutableAdapterOwnEnumerableKeys, isComputed, isEffect, isEffectScope, isEqualMutableAdapterSnapshot, isMutableAdapterUnsafeKey, isSignal, isStateSchemaError, onStoreReady, replaceExternalStoreState, replaceMutableAdapterState, replaceOwnEnumerable, sanitizeInitialStateValue, sanitizePatches, sanitizeReplacementState, signal, snapshotMutableAdapterPureState, startBatch, toMutableAdapterSnapshot, trigger, wrapStore };
|