coaction 1.3.0 → 1.4.1

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 CHANGED
@@ -25,9 +25,37 @@ const useStore = create((set) => ({
25
25
  }));
26
26
  ```
27
27
 
28
+ Store methods using `this` are rebound to the latest state when invoked from
29
+ `getState()`, so destructuring remains safe:
30
+
31
+ ```ts
32
+ const store = create((set) => ({
33
+ count: 0,
34
+ increment() {
35
+ set(() => {
36
+ this.count += 1;
37
+ });
38
+ }
39
+ }));
40
+
41
+ const { increment } = store.getState();
42
+ increment();
43
+ ```
44
+
45
+ ## API Reference
46
+
47
+ - [Generated core API index](https://github.com/unadlib/coaction/blob/main/docs/api/core/index.md)
48
+ - [Core API notes](https://github.com/unadlib/coaction/blob/main/docs/api/core/documents/core-api-notes.md)
49
+
28
50
  ### Store Shape Mode (`sliceMode`)
29
51
 
30
- `create()` uses `sliceMode: 'auto'` by default. You can force behavior explicitly:
52
+ `create()` uses `sliceMode: 'auto'` by default. For backward compatibility,
53
+ `auto` still treats a non-empty object whose enumerable values are all
54
+ functions as slices. That shape is ambiguous with a plain store that only
55
+ contains methods, so development builds warn and you should set `sliceMode`
56
+ explicitly.
57
+
58
+ You can force behavior explicitly:
31
59
 
32
60
  - `sliceMode: 'single'`: treat object input as a single store.
33
61
  - `sliceMode: 'slices'`: require object-of-slice-functions input.
package/dist/index.d.mts CHANGED
@@ -1,104 +1,177 @@
1
1
  import { Transport } from 'data-transport';
2
2
  import { Draft, Patches } from 'mutative';
3
3
 
4
+ /**
5
+ * Generic object shape used by stores and slices.
6
+ */
4
7
  type ISlices<T = any> = Record<string, T>;
8
+ /**
9
+ * Recursive partial object accepted by {@link Store.setState} when merging a
10
+ * plain object payload into the current state tree.
11
+ */
5
12
  type DeepPartial<T> = {
6
13
  [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
7
14
  };
15
+ /**
16
+ * Subscription callback invoked after the store publishes a state change.
17
+ */
8
18
  type Listener = () => void;
19
+ /**
20
+ * Patch pair exposed to middleware compatibility hooks.
21
+ */
22
+ interface PatchTransform {
23
+ patches: Patches;
24
+ inversePatches: Patches;
25
+ }
26
+ /**
27
+ * Trace envelope emitted before and after a store method executes.
28
+ */
29
+ interface StoreTraceEvent {
30
+ /**
31
+ * The id of the method.
32
+ */
33
+ id: string;
34
+ /**
35
+ * The method name.
36
+ */
37
+ method: string;
38
+ /**
39
+ * The slice key.
40
+ */
41
+ sliceKey?: string;
42
+ /**
43
+ * The parameters of the method.
44
+ */
45
+ parameters?: any[];
46
+ /**
47
+ * The result of the method.
48
+ */
49
+ result?: any;
50
+ }
51
+ /**
52
+ * Runtime store contract returned by {@link create} before framework-specific
53
+ * wrappers add selectors or reactivity helpers.
54
+ *
55
+ * @remarks
56
+ * `getState()` returns methods and getters alongside plain data. Methods
57
+ * extracted from the returned object keep the correct `this` binding when they
58
+ * are later invoked.
59
+ */
9
60
  interface Store<T extends ISlices = ISlices> {
10
61
  /**
11
62
  * The name of the store.
12
63
  */
13
64
  name: string;
14
65
  /**
15
- * Set the next state.
66
+ * Mutate the current state.
67
+ *
68
+ * @remarks
69
+ * Pass a deep-partial object to merge fields, or pass an updater to edit a
70
+ * Mutative draft. Client-side shared stores intentionally reject direct
71
+ * `setState()` calls; trigger a store method instead.
16
72
  */
17
73
  setState: (
18
74
  /**
19
- * The next state.
75
+ * The next partial state, or an updater that mutates a draft.
20
76
  */
21
77
  next: DeepPartial<T> | ((draft: Draft<T>) => any) | null,
22
78
  /**
23
- * The updater is used to update the state.
79
+ * Low-level updater hook used by transports and middleware integrations.
24
80
  */
25
81
  updater?: (next: DeepPartial<T> | ((draft: Draft<T>) => any) | null) => [] | [T, Patches, Patches]) => void;
26
82
  /**
27
- * Get the current state.
83
+ * Read the current state object.
84
+ *
85
+ * @remarks
86
+ * The returned object includes methods and getters. Methods destructured from
87
+ * this object continue to execute against the latest store state.
28
88
  */
29
89
  getState: () => T;
30
90
  /**
31
- * Subscribe to the state changes, and return the unsubscribe function.
91
+ * Subscribe to state changes.
92
+ *
93
+ * @returns A function that removes the listener.
32
94
  */
33
95
  subscribe: (listener: Listener) => () => void;
34
96
  /**
35
- * Unsubscribe all listeners and dispose the transport.
97
+ * Tear down the store.
98
+ *
99
+ * @remarks
100
+ * `destroy()` is idempotent. It clears subscriptions and disposes any
101
+ * attached transport.
36
102
  */
37
103
  destroy: () => void;
38
104
  /**
39
- * The store is shared in the web worker, shared worker, or other process.
105
+ * Indicates whether the store is local, the main shared store, or a client
106
+ * mirror of a shared store.
40
107
  */
41
108
  share?: 'main' | 'client' | false;
42
109
  /**
43
- * The transport is used to communicate between the main thread and the worker or shared worker.
110
+ * Transport used to synchronize a shared store between processes or threads.
44
111
  */
45
112
  transport?: Transport;
46
113
  /**
47
- * The store is a slices.
114
+ * Whether `createState` was interpreted as a slices object.
48
115
  */
49
116
  isSliceStore: boolean;
50
117
  /**
51
- * apply the patches to the state.
118
+ * Apply patches to the current state.
119
+ *
120
+ * @remarks
121
+ * This is a low-level hook used by transports and middleware. Application
122
+ * code should generally prefer store methods or `setState()`.
52
123
  */
53
124
  apply: (state?: T, patches?: Patches) => void;
54
125
  /**
55
- * the pure state is used to get the state without the methods and getters.
126
+ * Return the current state without methods or getters.
127
+ *
128
+ * @remarks
129
+ * Useful for serialization, inspection, or tests that only care about raw
130
+ * data.
56
131
  */
57
132
  getPureState: () => T;
58
133
  /**
59
- * Get the initial state.
134
+ * Return the state produced during initialization before later mutations.
60
135
  */
61
136
  getInitialState: () => T;
62
137
  /**
63
- * The patch is used to update the state.
138
+ * @deprecated Middleware compatibility hook. Prefer typing middleware stores
139
+ * with `MiddlewareStore`.
64
140
  */
65
- patch?: (option: {
66
- patches: Patches;
67
- inversePatches: Patches;
68
- }) => {
69
- patches: Patches;
70
- inversePatches: Patches;
71
- };
141
+ patch?: (option: PatchTransform) => PatchTransform;
72
142
  /**
73
- * The trace is used to trace the action
143
+ * @deprecated Middleware compatibility hook. Prefer typing middleware stores
144
+ * with `MiddlewareStore`.
74
145
  */
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;
146
+ trace?: (options: StoreTraceEvent) => void;
147
+ }
148
+ /**
149
+ * Semantic alias for middleware-facing stores.
150
+ *
151
+ * @remarks
152
+ * Middleware implementations should type their `store` parameter as
153
+ * `MiddlewareStore` instead of relying on deprecated `patch` or `trace` hooks.
154
+ */
155
+ interface MiddlewareStore<T extends ISlices = ISlices> extends Store<T> {
97
156
  }
157
+ /**
158
+ * Helper passed into {@link Slice} and {@link Slices} factories.
159
+ *
160
+ * @remarks
161
+ * Call it with no arguments to read the current store state. Call it with a
162
+ * dependency selector pair to define a computed value.
163
+ */
98
164
  interface Getter<T extends ISlices> {
99
165
  <P extends any[], R>(getDeps: (store: T) => readonly [...P] | [...P], selector: (...args: P) => R): R;
100
166
  (): T;
101
167
  }
168
+ /**
169
+ * Factory for a single store object.
170
+ *
171
+ * @remarks
172
+ * Return a plain object containing state, getters, and methods. Methods and
173
+ * getters may use `this` to access the live store state.
174
+ */
102
175
  type Slice<T extends ISlices> = (
103
176
  /**
104
177
  * The setState is used to update the state.
@@ -112,6 +185,14 @@ get: Getter<T>,
112
185
  * The store is used to store the state.
113
186
  */
114
187
  store: Store<T>) => T;
188
+ /**
189
+ * Factory for a named slice inside a slices store.
190
+ *
191
+ * @remarks
192
+ * The returned object becomes the value stored under the slice key. When an
193
+ * object input only contains functions, prefer explicit `sliceMode` to avoid
194
+ * ambiguity between slices and a plain method-only store.
195
+ */
115
196
  type Slices<T extends ISlices, K extends keyof T> = (
116
197
  /**
117
198
  * The setState is used to update the state.
@@ -125,57 +206,156 @@ get: Getter<T>,
125
206
  * The store is used to store the state.
126
207
  */
127
208
  store: Store<T>) => T[K];
128
- type Middleware<T extends CreateState> = (store: Store<T>) => Store<T>;
209
+ /**
210
+ * Store enhancer invoked during store creation.
211
+ *
212
+ * @remarks
213
+ * Middleware may mutate the received store in place or return a replacement
214
+ * store object, but it must preserve the {@link Store} contract.
215
+ */
216
+ type Middleware<T extends CreateState> = (store: MiddlewareStore<T>) => MiddlewareStore<T>;
217
+ /**
218
+ * Derived state object produced by mapping slice factories to their return
219
+ * types.
220
+ */
129
221
  type SliceState<T extends Record<string, Slice<any>>> = {
130
222
  [K in keyof T]: ReturnType<T[K]>;
131
223
  };
224
+ /**
225
+ * Options for creating a local store or the main side of a shared store.
226
+ */
132
227
  type StoreOptions<T extends CreateState> = {
133
228
  /**
134
229
  * The name of the store.
135
230
  */
136
231
  name?: string;
137
- transport?: Transport;
232
+ /**
233
+ * @deprecated Internal worker-mode override retained for compatibility.
234
+ * Prefer passing `transport` or letting the runtime infer the environment.
235
+ */
138
236
  workerType?: 'SharedWorkerInternal' | 'WebWorkerInternal';
237
+ /**
238
+ * Inject a pre-built transport for advanced shared-store setups.
239
+ */
240
+ transport?: Transport;
241
+ /**
242
+ * Middleware chain applied before the initial state is finalized.
243
+ */
139
244
  middlewares?: Middleware<T>[];
140
245
  /**
141
- * enable patches
246
+ * Enable patch generation.
247
+ *
248
+ * @remarks
249
+ * Required for async client stores and useful for middleware or mutable
250
+ * integrations that depend on patch streams.
142
251
  */
143
252
  enablePatches?: boolean;
144
253
  /**
145
- * control how createState should be interpreted.
146
- * - auto: infer from createState shape.
254
+ * Control how `createState` should be interpreted.
255
+ *
256
+ * @remarks
257
+ * - auto: infer from createState shape. Object maps whose values are all
258
+ * functions are ambiguous, so prefer setting `sliceMode` explicitly.
147
259
  * - slices: force slices mode.
148
260
  * - single: force single-store mode.
149
261
  */
150
262
  sliceMode?: 'auto' | 'slices' | 'single';
151
263
  };
264
+ /**
265
+ * Options for creating a client mirror of a shared store.
266
+ *
267
+ * @remarks
268
+ * Methods on the returned store become promise-returning methods because
269
+ * execution happens on the main/shared store.
270
+ */
152
271
  type ClientStoreOptions<T extends CreateState> = {
153
272
  /**
154
- * The name of the store.
273
+ * The name of the shared store to connect to.
155
274
  */
156
275
  name?: string;
276
+ /**
277
+ * Middleware chain applied to the client-side store wrapper.
278
+ */
157
279
  middlewares?: Middleware<T>[];
158
280
  /**
159
- * control how createState should be interpreted.
160
- * - auto: infer from createState shape.
281
+ * Control how `createState` should be interpreted.
282
+ *
283
+ * @remarks
284
+ * - auto: infer from createState shape. Object maps whose values are all
285
+ * functions are ambiguous, so prefer setting `sliceMode` explicitly.
161
286
  * - slices: force slices mode.
162
287
  * - single: force single-store mode.
163
288
  */
164
289
  sliceMode?: 'auto' | 'slices' | 'single';
165
290
  } & ClientTransportOptions;
291
+ /**
292
+ * Transport-related options for client/shared-store mirrors.
293
+ */
166
294
  interface ClientTransportOptions {
295
+ /**
296
+ * @deprecated Internal worker-mode override retained for compatibility.
297
+ * Prefer passing `clientTransport` or `worker`.
298
+ */
167
299
  workerType?: 'WebWorkerClient' | 'SharedWorkerClient';
300
+ /**
301
+ * How long the client should wait for sequence catch-up before falling back
302
+ * to `fullSync`.
303
+ *
304
+ * Increase this when worker-side execution can complete before the matching
305
+ * incremental `update` message arrives under heavy load.
306
+ *
307
+ * @default 1500
308
+ */
309
+ executeSyncTimeoutMs?: number;
310
+ /**
311
+ * Inject a pre-built client transport.
312
+ */
168
313
  clientTransport?: Transport<any>;
314
+ /**
315
+ * Build a client transport from a Worker or SharedWorker instance.
316
+ */
169
317
  worker?: SharedWorker | Worker;
170
318
  }
319
+ /**
320
+ * Transform store methods into promise-returning methods for client stores.
321
+ */
171
322
  type Asyncify<T extends object, D extends true | false> = {
172
323
  [K in keyof T]: T[K] extends (...args: any[]) => any ? (...args: Parameters<T[K]>) => Promise<ReturnType<T[K]>> : D extends false ? T[K] : {
173
324
  [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
325
  };
175
326
  };
327
+ /**
328
+ * Store shape returned by {@link create} when acting as a client of a shared
329
+ * store.
330
+ *
331
+ * @remarks
332
+ * Methods return promises because they execute on the main/shared store.
333
+ */
176
334
  type StoreWithAsyncFunction<T extends object, D extends true | false = false> = Store<Asyncify<T, D>> & (() => Asyncify<T, D>);
335
+ /**
336
+ * Callable store returned by {@link create} in local or main/shared mode.
337
+ */
177
338
  type StoreReturn<T extends object> = Store<T> & ((...args: any[]) => T);
339
+ /**
340
+ * Accepted `create()` input shape.
341
+ *
342
+ * @remarks
343
+ * This can be either a single store factory/object or a map of slice
344
+ * factories.
345
+ */
178
346
  type CreateState = ISlices | Record<string, Slice<any>>;
347
+ /**
348
+ * Overload set for {@link create}.
349
+ *
350
+ * @remarks
351
+ * - `Slice` + `StoreOptions` returns a synchronous local or main/shared store.
352
+ * - slice map + `StoreOptions` returns a synchronous slices store.
353
+ * - `Slice` + `ClientStoreOptions` returns an async client store.
354
+ * - slice map + `ClientStoreOptions` returns an async client slices store.
355
+ *
356
+ * For object inputs whose enumerable values are all functions, prefer explicit
357
+ * `sliceMode` to avoid ambiguous inference.
358
+ */
179
359
  type Creator = {
180
360
  <T extends Record<string, Slice<any>>>(createState: T, options?: StoreOptions<T>): StoreReturn<SliceState<T>>;
181
361
  <T extends ISlices>(createState: Slice<T>, options?: StoreOptions<T>): StoreReturn<T>;
@@ -184,7 +364,17 @@ type Creator = {
184
364
  };
185
365
 
186
366
  /**
187
- * Create a simple store or a shared store. The shared store can be used in a worker or another thread.
367
+ * Create a local store, the main side of a shared store, or a client mirror of
368
+ * a shared store.
369
+ *
370
+ * @remarks
371
+ * - Pass a {@link Slice} function for a single store.
372
+ * - Pass an object of slice factories for a slices store.
373
+ * - When an object input only contains functions, prefer explicit `sliceMode`
374
+ * to avoid ambiguous inference.
375
+ * - When `clientTransport` or `worker` is provided, returned store methods
376
+ * become promise-returning methods because execution happens on the main
377
+ * shared store.
188
378
  */
189
379
  declare const create: Creator;
190
380
 
@@ -236,55 +426,70 @@ interface Internal<T extends CreateState = CreateState> {
236
426
  }
237
427
 
238
428
  /**
239
- * createBinder is a function to create a binder for the 3rd party store.
429
+ * Build an adapter helper for bridging an external store implementation into
430
+ * Coaction.
431
+ *
432
+ * @remarks
433
+ * Official bindings use this to integrate stores such as Redux, Jotai, Pinia,
434
+ * Zustand, MobX, and Valtio. Binder-backed integrations are whole-store
435
+ * adapters; they are not compatible with Coaction slices mode.
240
436
  */
241
437
  declare function createBinder<F = (...args: any[]) => any>({ handleState, handleStore }: {
242
438
  /**
243
- * handleState is a function to handle the state object.
439
+ * Normalize a third-party store instance into a raw state object plus the
440
+ * binding hook used during initialization.
244
441
  */
245
442
  handleState: <T extends object = object>(state: T) => {
246
443
  /**
247
- * copyState is a copy of the state object.
444
+ * Copy of the incoming state object that Coaction should consume.
248
445
  */
249
446
  copyState: T;
250
447
  /**
251
- * key is the key of the state object.
448
+ * Optional nested key when the adapter exposes a single child object from
449
+ * the third-party store.
252
450
  */
253
451
  key?: keyof T;
254
452
  /**
255
- * bind is a function to bind the state object.
453
+ * Convert the external state object into the raw state shape used by
454
+ * Coaction.
256
455
  */
257
456
  bind: (state: T) => T;
258
457
  };
259
458
  /**
260
- * handleStore is a function to handle the store object.
459
+ * Wire Coaction's store lifecycle to the external store implementation.
261
460
  */
262
461
  handleStore: (
263
462
  /**
264
- * Coaction store
463
+ * Coaction store wrapper.
265
464
  */
266
465
  store: Store<object>,
267
466
  /**
268
- * The raw state object from 3rd party library.
467
+ * Raw state object returned from `bind`.
269
468
  */
270
469
  rawState: object,
271
470
  /**
272
- * 3rd party library state object to Coaction state object.
471
+ * Original external store state object.
273
472
  */
274
473
  state: object,
275
474
  /**
276
- * internal Coaction API.
475
+ * Low-level Coaction adapter hooks used by official bindings.
277
476
  */
278
477
  internal: Internal<object>,
279
478
  /**
280
- * the key of the slice state object.
479
+ * Optional nested key returned by `handleState`.
281
480
  */
282
481
  key?: string) => void;
283
482
  }): F;
284
483
 
285
484
  /**
286
- * wrapStore is a function to wrap the store and return function to get the state with store.
485
+ * Convert a store object into Coaction's callable store shape.
486
+ *
487
+ * @remarks
488
+ * Framework bindings use this to attach selector-aware readers while
489
+ * preserving the underlying store API on the returned function object. Most
490
+ * applications should call {@link create} instead of using `wrapStore()`
491
+ * directly.
287
492
  */
288
493
  declare const wrapStore: <T extends object>(store: Store<T>, getState?: (...args: unknown[]) => T) => StoreReturn<T>;
289
494
 
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 };
495
+ export { type StoreWithAsyncFunction as AsyncStore, type Asyncify, type ClientStoreOptions, type ISlices, type Middleware, type MiddlewareStore, type PatchTransform, type Slice, type SliceState, type Slices, type Store, type StoreOptions, type StoreTraceEvent, create, createBinder, wrapStore };