coaction 0.1.4 → 0.2.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Michael Lin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -19,12 +19,24 @@ npm install coaction
19
19
  ```jsx
20
20
  import { create } from 'coaction';
21
21
 
22
- const useStore = create((set, get) => ({
22
+ const useStore = create((set) => ({
23
23
  count: 0,
24
24
  increment: () => set((state) => state.count++)
25
25
  }));
26
26
  ```
27
27
 
28
+ ### Store Shape Mode (`sliceMode`)
29
+
30
+ `create()` uses `sliceMode: 'auto'` by default. You can force behavior explicitly:
31
+
32
+ - `sliceMode: 'single'`: treat object input as a single store.
33
+ - `sliceMode: 'slices'`: require object-of-slice-functions input.
34
+
35
+ ```ts
36
+ create({ ping: () => 'pong' }, { sliceMode: 'single' });
37
+ create({ counter: (set) => ({ count: 0 }) }, { sliceMode: 'slices' });
38
+ ```
39
+
28
40
  ## Documentation
29
41
 
30
42
  You can find the documentation [here](https://github.com/unadlib/coaction).
@@ -1,11 +1,12 @@
1
- import type { Transport } from 'data-transport';
2
- import type { Draft, Patches } from 'mutative';
3
- export type ISlices<T = any> = Record<string, T>;
4
- export type DeepPartial<T> = {
1
+ import { Transport } from 'data-transport';
2
+ import { Draft, Patches } from 'mutative';
3
+
4
+ type ISlices<T = any> = Record<string, T>;
5
+ type DeepPartial<T> = {
5
6
  [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
6
7
  };
7
- export type Listener = () => void;
8
- export interface Store<T extends ISlices = ISlices> {
8
+ type Listener = () => void;
9
+ interface Store<T extends ISlices = ISlices> {
9
10
  /**
10
11
  * The name of the store.
11
12
  */
@@ -27,7 +28,7 @@ export interface Store<T extends ISlices = ISlices> {
27
28
  */
28
29
  getState: () => T;
29
30
  /**
30
- * Subscribe to the state changes.
31
+ * Subscribe to the state changes, and return the unsubscribe function.
31
32
  */
32
33
  subscribe: (listener: Listener) => () => void;
33
34
  /**
@@ -58,10 +59,6 @@ export interface Store<T extends ISlices = ISlices> {
58
59
  * Get the initial state.
59
60
  */
60
61
  getInitialState: () => T;
61
- /**
62
- * Get the raw instance via the initial state.
63
- */
64
- toRaw?: (key: any) => any;
65
62
  /**
66
63
  * The patch is used to update the state.
67
64
  */
@@ -72,10 +69,6 @@ export interface Store<T extends ISlices = ISlices> {
72
69
  patches: Patches;
73
70
  inversePatches: Patches;
74
71
  };
75
- /**
76
- * The act is used to run the function in the action.
77
- */
78
- act?: <T extends () => any>(fn: T) => ReturnType<T>;
79
72
  /**
80
73
  * The trace is used to trace the action
81
74
  */
@@ -102,39 +95,11 @@ export interface Store<T extends ISlices = ISlices> {
102
95
  result?: any;
103
96
  }) => void;
104
97
  }
105
- export type InternalEvents = {
106
- /**
107
- * Update the state in the worker or shared worker.
108
- */
109
- update(options: {
110
- /**
111
- * The patches is used to update the state.
112
- */
113
- patches: Patches;
114
- /**
115
- * The sequence is used to ensure the sequence of the state.
116
- */
117
- sequence: number;
118
- }): Promise<void>;
119
- };
120
- export type ExternalEvents = {
121
- /**
122
- * Execute the function in the worker or shared worker.
123
- */
124
- execute(keys: string[], args: any[]): Promise<any>;
125
- /**
126
- * Full sync the state with the worker or shared worker.
127
- */
128
- fullSync(): Promise<{
129
- state: string;
130
- sequence: number;
131
- }>;
132
- };
133
98
  interface Getter<T extends ISlices> {
134
99
  <P extends any[], R>(getDeps: (store: T) => readonly [...P] | [...P], selector: (...args: P) => R): R;
135
100
  (): T;
136
101
  }
137
- export type Slice<T extends ISlices> = (
102
+ type Slice<T extends ISlices> = (
138
103
  /**
139
104
  * The setState is used to update the state.
140
105
  */
@@ -147,7 +112,7 @@ get: Getter<T>,
147
112
  * The store is used to store the state.
148
113
  */
149
114
  store: Store<T>) => T;
150
- export type Slices<T extends ISlices, K extends keyof T> = (
115
+ type Slices<T extends ISlices, K extends keyof T> = (
151
116
  /**
152
117
  * The setState is used to update the state.
153
118
  */
@@ -160,11 +125,11 @@ get: Getter<T>,
160
125
  * The store is used to store the state.
161
126
  */
162
127
  store: Store<T>) => T[K];
163
- export type Middleware<T extends CreateState> = (store: Store<T>) => Store<T>;
164
- export type SliceState<T extends Record<string, Slice<any>>> = {
128
+ type Middleware<T extends CreateState> = (store: Store<T>) => Store<T>;
129
+ type SliceState<T extends Record<string, Slice<any>>> = {
165
130
  [K in keyof T]: ReturnType<T[K]>;
166
131
  };
167
- export type StoreOptions<T extends CreateState> = {
132
+ type StoreOptions<T extends CreateState> = {
168
133
  /**
169
134
  * The name of the store.
170
135
  */
@@ -176,49 +141,150 @@ export type StoreOptions<T extends CreateState> = {
176
141
  * enable patches
177
142
  */
178
143
  enablePatches?: boolean;
144
+ /**
145
+ * control how createState should be interpreted.
146
+ * - auto: infer from createState shape.
147
+ * - slices: force slices mode.
148
+ * - single: force single-store mode.
149
+ */
150
+ sliceMode?: 'auto' | 'slices' | 'single';
179
151
  };
180
- export type ClientStoreOptions<T extends CreateState> = {
152
+ type ClientStoreOptions<T extends CreateState> = {
181
153
  /**
182
154
  * The name of the store.
183
155
  */
184
156
  name?: string;
185
157
  middlewares?: Middleware<T>[];
158
+ /**
159
+ * control how createState should be interpreted.
160
+ * - auto: infer from createState shape.
161
+ * - slices: force slices mode.
162
+ * - single: force single-store mode.
163
+ */
164
+ sliceMode?: 'auto' | 'slices' | 'single';
186
165
  } & ClientTransportOptions;
187
- export interface ClientTransportOptions {
166
+ interface ClientTransportOptions {
188
167
  workerType?: 'WebWorkerClient' | 'SharedWorkerClient';
189
168
  clientTransport?: Transport<any>;
190
169
  worker?: SharedWorker | Worker;
191
170
  }
192
- export type Asyncify<T extends object, D extends true | false> = {
171
+ type Asyncify<T extends object, D extends true | false> = {
193
172
  [K in keyof T]: T[K] extends (...args: any[]) => any ? (...args: Parameters<T[K]>) => Promise<ReturnType<T[K]>> : D extends false ? T[K] : {
194
173
  [P in keyof T[K]]: T[K][P] extends (...args: any[]) => any ? (...args: Parameters<T[K][P]>) => Promise<ReturnType<T[K][P]>> : T[K][P];
195
174
  };
196
175
  };
197
- export type StoreWithAsyncFunction<T extends object, D extends true | false = false> = Store<Asyncify<T, D>> & (() => Asyncify<T, D>);
198
- export type StoreReturn<T extends object> = Store<T> & ((...args: any[]) => T);
199
- export type CreateState = ISlices | Record<string, Slice<any>>;
200
- export type Creator = {
176
+ type StoreWithAsyncFunction<T extends object, D extends true | false = false> = Store<Asyncify<T, D>> & (() => Asyncify<T, D>);
177
+ type StoreReturn<T extends object> = Store<T> & ((...args: any[]) => T);
178
+ type CreateState = ISlices | Record<string, Slice<any>>;
179
+ type Creator = {
201
180
  <T extends Record<string, Slice<any>>>(createState: T, options?: StoreOptions<T>): StoreReturn<SliceState<T>>;
202
181
  <T extends ISlices>(createState: Slice<T>, options?: StoreOptions<T>): StoreReturn<T>;
203
182
  <T extends Record<string, Slice<any>>>(createState: T, options?: ClientStoreOptions<T>): StoreWithAsyncFunction<SliceState<T>, true>;
204
183
  <T extends ISlices>(createState: Slice<T>, options?: ClientStoreOptions<T>): StoreWithAsyncFunction<T>;
205
184
  };
206
- export type ClientTransport = (Transport<{
207
- listen: InternalEvents;
208
- emit: ExternalEvents;
209
- }> & {
185
+
186
+ /**
187
+ * Create a simple store or a shared store. The shared store can be used in a worker or another thread.
188
+ */
189
+ declare const create: Creator;
190
+
191
+ interface Internal<T extends CreateState = CreateState> {
192
+ /**
193
+ * The store module.
194
+ */
195
+ module: T;
210
196
  /**
211
- * onConnect is called when the transport is connected.
197
+ * The root state.
212
198
  */
213
- onConnect?: (fn: () => void) => void;
214
- }) | undefined;
215
- export type StoreTransport = (Transport<{
216
- listen: ExternalEvents;
217
- emit: InternalEvents;
218
- }> & {
199
+ rootState: T | Draft<T>;
219
200
  /**
220
- * onConnect is called when the transport is connected.
201
+ * The backup state.
221
202
  */
222
- onConnect?: (fn: () => void) => void;
223
- }) | undefined;
224
- export {};
203
+ backupState: T | Draft<T>;
204
+ /**
205
+ * Finalize the draft.
206
+ */
207
+ finalizeDraft: () => [T, Patches, Patches];
208
+ /**
209
+ * The mutable instance.
210
+ */
211
+ mutableInstance: any;
212
+ /**
213
+ * The sequence number.
214
+ */
215
+ sequence: number;
216
+ /**
217
+ * Whether the batch is running.
218
+ */
219
+ isBatching: boolean;
220
+ /**
221
+ * The listeners.
222
+ */
223
+ listeners: Set<Listener>;
224
+ /**
225
+ * The act is used to run the function in the action for mutable state.
226
+ */
227
+ actMutable?: <T extends () => any>(fn: T) => ReturnType<T>;
228
+ /**
229
+ * Get the mutable raw instance via the initial state.
230
+ */
231
+ toMutableRaw?: (key: any) => any;
232
+ /**
233
+ * The update immutable function.
234
+ */
235
+ updateImmutable?: (state: T) => void;
236
+ }
237
+
238
+ /**
239
+ * createBinder is a function to create a binder for the 3rd party store.
240
+ */
241
+ declare function createBinder<F = (...args: any[]) => any>({ handleState, handleStore }: {
242
+ /**
243
+ * handleState is a function to handle the state object.
244
+ */
245
+ handleState: <T extends object = object>(state: T) => {
246
+ /**
247
+ * copyState is a copy of the state object.
248
+ */
249
+ copyState: T;
250
+ /**
251
+ * key is the key of the state object.
252
+ */
253
+ key?: keyof T;
254
+ /**
255
+ * bind is a function to bind the state object.
256
+ */
257
+ bind: (state: T) => T;
258
+ };
259
+ /**
260
+ * handleStore is a function to handle the store object.
261
+ */
262
+ handleStore: (
263
+ /**
264
+ * Coaction store
265
+ */
266
+ store: Store<object>,
267
+ /**
268
+ * The raw state object from 3rd party library.
269
+ */
270
+ rawState: object,
271
+ /**
272
+ * 3rd party library state object to Coaction state object.
273
+ */
274
+ state: object,
275
+ /**
276
+ * internal Coaction API.
277
+ */
278
+ internal: Internal<object>,
279
+ /**
280
+ * the key of the slice state object.
281
+ */
282
+ key?: string) => void;
283
+ }): F;
284
+
285
+ /**
286
+ * wrapStore is a function to wrap the store and return function to get the state with store.
287
+ */
288
+ declare const wrapStore: <T extends object>(store: Store<T>, getState?: (...args: unknown[]) => T) => StoreReturn<T>;
289
+
290
+ export { type StoreWithAsyncFunction as AsyncStore, type Asyncify, type ClientStoreOptions, type ISlices, type Middleware, type Slice, type SliceState, type Slices, type Store, type StoreOptions, create, createBinder, wrapStore };
@@ -0,0 +1,290 @@
1
+ import { Transport } from 'data-transport';
2
+ import { Draft, Patches } from 'mutative';
3
+
4
+ type ISlices<T = any> = Record<string, T>;
5
+ type DeepPartial<T> = {
6
+ [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
7
+ };
8
+ type Listener = () => void;
9
+ interface Store<T extends ISlices = ISlices> {
10
+ /**
11
+ * The name of the store.
12
+ */
13
+ name: string;
14
+ /**
15
+ * Set the next state.
16
+ */
17
+ setState: (
18
+ /**
19
+ * The next state.
20
+ */
21
+ next: DeepPartial<T> | ((draft: Draft<T>) => any) | null,
22
+ /**
23
+ * The updater is used to update the state.
24
+ */
25
+ updater?: (next: DeepPartial<T> | ((draft: Draft<T>) => any) | null) => [] | [T, Patches, Patches]) => void;
26
+ /**
27
+ * Get the current state.
28
+ */
29
+ getState: () => T;
30
+ /**
31
+ * Subscribe to the state changes, and return the unsubscribe function.
32
+ */
33
+ subscribe: (listener: Listener) => () => void;
34
+ /**
35
+ * Unsubscribe all listeners and dispose the transport.
36
+ */
37
+ destroy: () => void;
38
+ /**
39
+ * The store is shared in the web worker, shared worker, or other process.
40
+ */
41
+ share?: 'main' | 'client' | false;
42
+ /**
43
+ * The transport is used to communicate between the main thread and the worker or shared worker.
44
+ */
45
+ transport?: Transport;
46
+ /**
47
+ * The store is a slices.
48
+ */
49
+ isSliceStore: boolean;
50
+ /**
51
+ * apply the patches to the state.
52
+ */
53
+ apply: (state?: T, patches?: Patches) => void;
54
+ /**
55
+ * the pure state is used to get the state without the methods and getters.
56
+ */
57
+ getPureState: () => T;
58
+ /**
59
+ * Get the initial state.
60
+ */
61
+ getInitialState: () => T;
62
+ /**
63
+ * The patch is used to update the state.
64
+ */
65
+ patch?: (option: {
66
+ patches: Patches;
67
+ inversePatches: Patches;
68
+ }) => {
69
+ patches: Patches;
70
+ inversePatches: Patches;
71
+ };
72
+ /**
73
+ * The trace is used to trace the action
74
+ */
75
+ trace?: (options: {
76
+ /**
77
+ * The id of the method.
78
+ */
79
+ id: string;
80
+ /**
81
+ * The method name.
82
+ */
83
+ method: string;
84
+ /**
85
+ * The slice key.
86
+ */
87
+ sliceKey?: string;
88
+ /**
89
+ * The parameters of the method.
90
+ */
91
+ parameters?: any[];
92
+ /**
93
+ * The result of the method.
94
+ */
95
+ result?: any;
96
+ }) => void;
97
+ }
98
+ interface Getter<T extends ISlices> {
99
+ <P extends any[], R>(getDeps: (store: T) => readonly [...P] | [...P], selector: (...args: P) => R): R;
100
+ (): T;
101
+ }
102
+ type Slice<T extends ISlices> = (
103
+ /**
104
+ * The setState is used to update the state.
105
+ */
106
+ set: Store<T>['setState'],
107
+ /**
108
+ * The getState is used to get the state.
109
+ */
110
+ get: Getter<T>,
111
+ /**
112
+ * The store is used to store the state.
113
+ */
114
+ store: Store<T>) => T;
115
+ type Slices<T extends ISlices, K extends keyof T> = (
116
+ /**
117
+ * The setState is used to update the state.
118
+ */
119
+ set: Store<T>['setState'],
120
+ /**
121
+ * The getState is used to get the state.
122
+ */
123
+ get: Getter<T>,
124
+ /**
125
+ * The store is used to store the state.
126
+ */
127
+ store: Store<T>) => T[K];
128
+ type Middleware<T extends CreateState> = (store: Store<T>) => Store<T>;
129
+ type SliceState<T extends Record<string, Slice<any>>> = {
130
+ [K in keyof T]: ReturnType<T[K]>;
131
+ };
132
+ type StoreOptions<T extends CreateState> = {
133
+ /**
134
+ * The name of the store.
135
+ */
136
+ name?: string;
137
+ transport?: Transport;
138
+ workerType?: 'SharedWorkerInternal' | 'WebWorkerInternal';
139
+ middlewares?: Middleware<T>[];
140
+ /**
141
+ * enable patches
142
+ */
143
+ enablePatches?: boolean;
144
+ /**
145
+ * control how createState should be interpreted.
146
+ * - auto: infer from createState shape.
147
+ * - slices: force slices mode.
148
+ * - single: force single-store mode.
149
+ */
150
+ sliceMode?: 'auto' | 'slices' | 'single';
151
+ };
152
+ type ClientStoreOptions<T extends CreateState> = {
153
+ /**
154
+ * The name of the store.
155
+ */
156
+ name?: string;
157
+ middlewares?: Middleware<T>[];
158
+ /**
159
+ * control how createState should be interpreted.
160
+ * - auto: infer from createState shape.
161
+ * - slices: force slices mode.
162
+ * - single: force single-store mode.
163
+ */
164
+ sliceMode?: 'auto' | 'slices' | 'single';
165
+ } & ClientTransportOptions;
166
+ interface ClientTransportOptions {
167
+ workerType?: 'WebWorkerClient' | 'SharedWorkerClient';
168
+ clientTransport?: Transport<any>;
169
+ worker?: SharedWorker | Worker;
170
+ }
171
+ type Asyncify<T extends object, D extends true | false> = {
172
+ [K in keyof T]: T[K] extends (...args: any[]) => any ? (...args: Parameters<T[K]>) => Promise<ReturnType<T[K]>> : D extends false ? T[K] : {
173
+ [P in keyof T[K]]: T[K][P] extends (...args: any[]) => any ? (...args: Parameters<T[K][P]>) => Promise<ReturnType<T[K][P]>> : T[K][P];
174
+ };
175
+ };
176
+ type StoreWithAsyncFunction<T extends object, D extends true | false = false> = Store<Asyncify<T, D>> & (() => Asyncify<T, D>);
177
+ type StoreReturn<T extends object> = Store<T> & ((...args: any[]) => T);
178
+ type CreateState = ISlices | Record<string, Slice<any>>;
179
+ type Creator = {
180
+ <T extends Record<string, Slice<any>>>(createState: T, options?: StoreOptions<T>): StoreReturn<SliceState<T>>;
181
+ <T extends ISlices>(createState: Slice<T>, options?: StoreOptions<T>): StoreReturn<T>;
182
+ <T extends Record<string, Slice<any>>>(createState: T, options?: ClientStoreOptions<T>): StoreWithAsyncFunction<SliceState<T>, true>;
183
+ <T extends ISlices>(createState: Slice<T>, options?: ClientStoreOptions<T>): StoreWithAsyncFunction<T>;
184
+ };
185
+
186
+ /**
187
+ * Create a simple store or a shared store. The shared store can be used in a worker or another thread.
188
+ */
189
+ declare const create: Creator;
190
+
191
+ interface Internal<T extends CreateState = CreateState> {
192
+ /**
193
+ * The store module.
194
+ */
195
+ module: T;
196
+ /**
197
+ * The root state.
198
+ */
199
+ rootState: T | Draft<T>;
200
+ /**
201
+ * The backup state.
202
+ */
203
+ backupState: T | Draft<T>;
204
+ /**
205
+ * Finalize the draft.
206
+ */
207
+ finalizeDraft: () => [T, Patches, Patches];
208
+ /**
209
+ * The mutable instance.
210
+ */
211
+ mutableInstance: any;
212
+ /**
213
+ * The sequence number.
214
+ */
215
+ sequence: number;
216
+ /**
217
+ * Whether the batch is running.
218
+ */
219
+ isBatching: boolean;
220
+ /**
221
+ * The listeners.
222
+ */
223
+ listeners: Set<Listener>;
224
+ /**
225
+ * The act is used to run the function in the action for mutable state.
226
+ */
227
+ actMutable?: <T extends () => any>(fn: T) => ReturnType<T>;
228
+ /**
229
+ * Get the mutable raw instance via the initial state.
230
+ */
231
+ toMutableRaw?: (key: any) => any;
232
+ /**
233
+ * The update immutable function.
234
+ */
235
+ updateImmutable?: (state: T) => void;
236
+ }
237
+
238
+ /**
239
+ * createBinder is a function to create a binder for the 3rd party store.
240
+ */
241
+ declare function createBinder<F = (...args: any[]) => any>({ handleState, handleStore }: {
242
+ /**
243
+ * handleState is a function to handle the state object.
244
+ */
245
+ handleState: <T extends object = object>(state: T) => {
246
+ /**
247
+ * copyState is a copy of the state object.
248
+ */
249
+ copyState: T;
250
+ /**
251
+ * key is the key of the state object.
252
+ */
253
+ key?: keyof T;
254
+ /**
255
+ * bind is a function to bind the state object.
256
+ */
257
+ bind: (state: T) => T;
258
+ };
259
+ /**
260
+ * handleStore is a function to handle the store object.
261
+ */
262
+ handleStore: (
263
+ /**
264
+ * Coaction store
265
+ */
266
+ store: Store<object>,
267
+ /**
268
+ * The raw state object from 3rd party library.
269
+ */
270
+ rawState: object,
271
+ /**
272
+ * 3rd party library state object to Coaction state object.
273
+ */
274
+ state: object,
275
+ /**
276
+ * internal Coaction API.
277
+ */
278
+ internal: Internal<object>,
279
+ /**
280
+ * the key of the slice state object.
281
+ */
282
+ key?: string) => void;
283
+ }): F;
284
+
285
+ /**
286
+ * wrapStore is a function to wrap the store and return function to get the state with store.
287
+ */
288
+ declare const wrapStore: <T extends object>(store: Store<T>, getState?: (...args: unknown[]) => T) => StoreReturn<T>;
289
+
290
+ export { type StoreWithAsyncFunction as AsyncStore, type Asyncify, type ClientStoreOptions, type ISlices, type Middleware, type Slice, type SliceState, type Slices, type Store, type StoreOptions, create, createBinder, wrapStore };