@oxog/state 1.0.0 → 1.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/dist/index.d.ts CHANGED
@@ -478,6 +478,741 @@ declare function useCreateStore<TState>(initialState: TState): Store<TState>;
478
478
  * ```
479
479
  */
480
480
  declare function useAction<TState, TAction extends (...args: any[]) => any>(store: Store<TState>, actionName: string): TAction;
481
+ /**
482
+ * Create a shallow equality wrapper for selectors.
483
+ *
484
+ * Use this hook to wrap selectors that return objects or arrays
485
+ * and you want to avoid re-renders when the content hasn't changed.
486
+ *
487
+ * @param selector - The selector function to wrap
488
+ * @returns A wrapped selector with shallow equality
489
+ *
490
+ * @example
491
+ * ```typescript
492
+ * import { useStore, useShallow } from '@oxog/state';
493
+ *
494
+ * function UserInfo() {
495
+ * // Without useShallow - re-renders on every state change
496
+ * const { name, email } = useStore(store, s => ({ name: s.name, email: s.email }));
497
+ *
498
+ * // With useShallow - only re-renders when name or email actually changes
499
+ * const { name, email } = useStore(
500
+ * store,
501
+ * useShallow(s => ({ name: s.name, email: s.email }))
502
+ * );
503
+ * }
504
+ * ```
505
+ */
506
+ declare function useShallow<TState, TSelected extends object>(selector: Selector<TState, TSelected>): Selector<TState, TSelected>;
507
+ /**
508
+ * Hook for selecting multiple actions from a store.
509
+ *
510
+ * Returns stable references to actions that don't change between renders.
511
+ *
512
+ * @param store - The store instance
513
+ * @param actionNames - Names of actions to select
514
+ * @returns An object with the selected actions
515
+ *
516
+ * @example
517
+ * ```typescript
518
+ * import { useStoreActions } from '@oxog/state';
519
+ *
520
+ * function Counter() {
521
+ * const { increment, decrement, reset } = useStoreActions(
522
+ * store,
523
+ * 'increment',
524
+ * 'decrement',
525
+ * 'reset'
526
+ * );
527
+ *
528
+ * return (
529
+ * <>
530
+ * <button onClick={decrement}>-</button>
531
+ * <button onClick={increment}>+</button>
532
+ * <button onClick={reset}>Reset</button>
533
+ * </>
534
+ * );
535
+ * }
536
+ * ```
537
+ */
538
+ declare function useStoreActions<TState, TKeys extends string[]>(store: Store<TState>, ...actionNames: TKeys): {
539
+ [K in TKeys[number]]: (...args: any[]) => any;
540
+ };
541
+ /**
542
+ * Hook for selecting multiple values with independent selectors.
543
+ *
544
+ * Each selector is tracked independently, so the component only
545
+ * re-renders when a selector's output actually changes.
546
+ *
547
+ * @param store - The store instance
548
+ * @param selectors - Object of named selectors
549
+ * @returns An object with selected values
550
+ *
551
+ * @example
552
+ * ```typescript
553
+ * import { useStoreSelector } from '@oxog/state';
554
+ *
555
+ * function Dashboard() {
556
+ * const { userCount, activeUsers, totalRevenue } = useStoreSelector(store, {
557
+ * userCount: s => s.users.length,
558
+ * activeUsers: s => s.users.filter(u => u.active).length,
559
+ * totalRevenue: s => s.orders.reduce((sum, o) => sum + o.total, 0),
560
+ * });
561
+ *
562
+ * return (
563
+ * <div>
564
+ * <p>Users: {userCount} ({activeUsers} active)</p>
565
+ * <p>Revenue: ${totalRevenue}</p>
566
+ * </div>
567
+ * );
568
+ * }
569
+ * ```
570
+ */
571
+ declare function useStoreSelector<TState, TSelectors extends Record<string, Selector<TState, any>>>(store: Store<TState>, selectors: TSelectors): {
572
+ [K in keyof TSelectors]: ReturnType<TSelectors[K]>;
573
+ };
574
+ /**
575
+ * Hook for transient updates - subscribe without causing re-renders.
576
+ *
577
+ * Use this for side effects that don't need to update the UI.
578
+ *
579
+ * @param store - The store instance
580
+ * @param selector - Selector function
581
+ * @param callback - Callback to run on changes
582
+ *
583
+ * @example
584
+ * ```typescript
585
+ * import { useTransientSubscribe } from '@oxog/state';
586
+ *
587
+ * function Analytics() {
588
+ * // Track page views without re-rendering
589
+ * useTransientSubscribe(
590
+ * store,
591
+ * s => s.currentPage,
592
+ * (page) => analytics.track('pageview', { page })
593
+ * );
594
+ *
595
+ * return <div>...</div>;
596
+ * }
597
+ * ```
598
+ */
599
+ declare function useTransientSubscribe<TState, TSelected>(store: Store<TState>, selector: Selector<TState, TSelected>, callback: (value: TSelected, prevValue: TSelected) => void, equalityFn?: EqualityFn<TSelected>): void;
600
+ /**
601
+ * Hook that returns the store's setState function with stable reference.
602
+ *
603
+ * @param store - The store instance
604
+ * @returns The setState function
605
+ *
606
+ * @example
607
+ * ```typescript
608
+ * function Form() {
609
+ * const setState = useSetState(store);
610
+ *
611
+ * const handleChange = (e) => {
612
+ * setState({ [e.target.name]: e.target.value });
613
+ * };
614
+ *
615
+ * return <input onChange={handleChange} />;
616
+ * }
617
+ * ```
618
+ */
619
+ declare function useSetState<TState>(store: Store<TState>): (partial: Partial<TState> | ((state: TState) => Partial<TState>)) => void;
620
+
621
+ /**
622
+ * Enhanced subscription system with advanced options.
623
+ *
624
+ * @module subscribe
625
+ */
626
+
627
+ /**
628
+ * Options for enhanced subscriptions.
629
+ *
630
+ * @typeParam T - The store state type
631
+ * @typeParam U - The selected value type
632
+ *
633
+ * @example
634
+ * ```typescript
635
+ * const options: SubscribeOptions<State, number> = {
636
+ * debounce: 100,
637
+ * fireImmediately: true,
638
+ * when: (state) => state.isReady
639
+ * };
640
+ * ```
641
+ */
642
+ interface SubscribeOptions<T, U = T> {
643
+ /** Custom equality function for comparing selected values */
644
+ equalityFn?: EqualityFn<U>;
645
+ /** Fire callback immediately with current state */
646
+ fireImmediately?: boolean;
647
+ /** Debounce notifications (ms) */
648
+ debounce?: number;
649
+ /** Throttle notifications (ms) */
650
+ throttle?: number;
651
+ /** Only fire when condition is met */
652
+ when?: (state: T, prevState: T) => boolean;
653
+ }
654
+ /**
655
+ * Enhanced subscribe function with advanced options.
656
+ *
657
+ * @param store - The store to subscribe to
658
+ * @param selectorOrListener - Selector function or direct listener
659
+ * @param listenerOrOptions - Listener function or options (if no selector)
660
+ * @param options - Subscription options
661
+ * @returns Unsubscribe function
662
+ *
663
+ * @example
664
+ * ```typescript
665
+ * // With debounce
666
+ * const unsubscribe = subscribeWithOptions(
667
+ * store,
668
+ * (state) => state.searchQuery,
669
+ * (query) => performSearch(query),
670
+ * { debounce: 300 }
671
+ * );
672
+ *
673
+ * // With throttle and condition
674
+ * const unsubscribe = subscribeWithOptions(
675
+ * store,
676
+ * (state) => state.scrollPosition,
677
+ * (pos) => updateUI(pos),
678
+ * { throttle: 16, when: (state) => state.isVisible }
679
+ * );
680
+ *
681
+ * // Fire immediately
682
+ * const unsubscribe = subscribeWithOptions(
683
+ * store,
684
+ * (state) => state.user,
685
+ * (user) => console.log('User:', user),
686
+ * { fireImmediately: true }
687
+ * );
688
+ * ```
689
+ */
690
+ declare function subscribeWithOptions<TState, TSelected>(store: Store<TState>, selector: Selector<TState, TSelected>, listener: Listener<TSelected>, options?: SubscribeOptions<TState, TSelected>): () => void;
691
+ /**
692
+ * Create a subscription factory with preset options.
693
+ *
694
+ * @param defaultOptions - Default options for all subscriptions
695
+ * @returns A subscribe function with preset options
696
+ *
697
+ * @example
698
+ * ```typescript
699
+ * const debouncedSubscribe = createSubscriber({ debounce: 100 });
700
+ *
701
+ * const unsubscribe = debouncedSubscribe(
702
+ * store,
703
+ * (state) => state.input,
704
+ * (input) => validate(input)
705
+ * );
706
+ * ```
707
+ */
708
+ declare function createSubscriber<TState>(defaultOptions?: SubscribeOptions<TState, any>): <TSelected>(store: Store<TState>, selector: Selector<TState, TSelected>, listener: Listener<TSelected>, options?: SubscribeOptions<TState, TSelected>) => () => void;
709
+ /**
710
+ * Subscribe to multiple selectors with a single listener.
711
+ *
712
+ * @param store - The store to subscribe to
713
+ * @param selectors - Object of named selectors
714
+ * @param listener - Listener called when any selector value changes
715
+ * @param options - Subscription options
716
+ * @returns Unsubscribe function
717
+ *
718
+ * @example
719
+ * ```typescript
720
+ * const unsubscribe = subscribeToMany(
721
+ * store,
722
+ * {
723
+ * count: (s) => s.count,
724
+ * name: (s) => s.name,
725
+ * },
726
+ * ({ count, name }) => console.log(`${name}: ${count}`)
727
+ * );
728
+ * ```
729
+ */
730
+ declare function subscribeToMany<TState, TSelectors extends Record<string, Selector<TState, any>>>(store: Store<TState>, selectors: TSelectors, listener: (values: {
731
+ [K in keyof TSelectors]: ReturnType<TSelectors[K]>;
732
+ }) => void, options?: Omit<SubscribeOptions<TState, any>, 'equalityFn'>): () => void;
733
+ /**
734
+ * Subscribe only once - automatically unsubscribes after first call.
735
+ *
736
+ * @param store - The store to subscribe to
737
+ * @param selector - Selector function
738
+ * @param listener - Listener called once when value changes
739
+ * @param options - Subscription options
740
+ * @returns Unsubscribe function (can be called to cancel before trigger)
741
+ *
742
+ * @example
743
+ * ```typescript
744
+ * // Wait for user to be loaded
745
+ * subscribeOnce(
746
+ * store,
747
+ * (state) => state.user,
748
+ * (user) => console.log('User loaded:', user),
749
+ * { when: (state) => state.user !== null }
750
+ * );
751
+ * ```
752
+ */
753
+ declare function subscribeOnce<TState, TSelected>(store: Store<TState>, selector: Selector<TState, TSelected>, listener: Listener<TSelected>, options?: SubscribeOptions<TState, TSelected>): () => void;
754
+
755
+ /**
756
+ * Computed values (derived state) with memoization.
757
+ *
758
+ * @module computed
759
+ */
760
+
761
+ /**
762
+ * Options for computed values.
763
+ *
764
+ * @typeParam T - The store state type
765
+ * @typeParam U - The computed value type
766
+ */
767
+ interface ComputedOptions<T, U> {
768
+ /** Custom equality for caching */
769
+ equals?: EqualityFn<U>;
770
+ /** Lazy evaluation (only compute when accessed) */
771
+ lazy?: boolean;
772
+ /** Keep last N values in cache for time-travel debugging */
773
+ cacheSize?: number;
774
+ }
775
+ /**
776
+ * Computed value interface with getter and utilities.
777
+ */
778
+ interface Computed<U> {
779
+ /** Get the computed value */
780
+ (): U;
781
+ /** Get value (alias) */
782
+ get(): U;
783
+ /** Force recomputation */
784
+ invalidate(): void;
785
+ /** Subscribe to value changes */
786
+ subscribe(listener: (value: U, prevValue: U) => void): () => void;
787
+ /** Get cache history (if cacheSize > 1) */
788
+ getHistory(): U[];
789
+ /** Destroy and cleanup */
790
+ destroy(): void;
791
+ }
792
+ /**
793
+ * Create a computed (derived) value from store state.
794
+ *
795
+ * Computed values are memoized and only recompute when dependencies change.
796
+ *
797
+ * @param store - The store to derive from
798
+ * @param selector - Function to compute the derived value
799
+ * @param options - Computed options
800
+ * @returns A computed value accessor
801
+ *
802
+ * @example
803
+ * ```typescript
804
+ * const store = createStore({ items: [], filter: 'all' });
805
+ *
806
+ * // Simple computed
807
+ * const filteredItems = computed(store, (state) => {
808
+ * if (state.filter === 'all') return state.items;
809
+ * return state.items.filter(item => item.status === state.filter);
810
+ * });
811
+ *
812
+ * console.log(filteredItems()); // Get computed value
813
+ *
814
+ * // With caching for debugging
815
+ * const total = computed(
816
+ * store,
817
+ * (state) => state.items.reduce((sum, item) => sum + item.price, 0),
818
+ * { cacheSize: 10 }
819
+ * );
820
+ *
821
+ * console.log(total.getHistory()); // See past values
822
+ * ```
823
+ */
824
+ declare function computed<TState, TComputed>(store: Store<TState>, selector: Selector<TState, TComputed>, options?: ComputedOptions<TState, TComputed>): Computed<TComputed>;
825
+ /**
826
+ * Create a computed value that depends on other computed values.
827
+ *
828
+ * @param computeds - Array of computed values to depend on
829
+ * @param combiner - Function to combine the computed values
830
+ * @param options - Computed options
831
+ * @returns A combined computed value
832
+ *
833
+ * @example
834
+ * ```typescript
835
+ * const subtotal = computed(store, (s) => s.items.reduce((sum, i) => sum + i.price, 0));
836
+ * const tax = computed(store, (s) => s.taxRate);
837
+ *
838
+ * const total = combineComputed(
839
+ * [subtotal, tax],
840
+ * ([subtotalVal, taxVal]) => subtotalVal * (1 + taxVal)
841
+ * );
842
+ *
843
+ * console.log(total()); // Subtotal + tax
844
+ * ```
845
+ */
846
+ declare function combineComputed<TInputs extends Computed<any>[], TOutput>(computeds: [...TInputs], combiner: (values: {
847
+ [K in keyof TInputs]: TInputs[K] extends Computed<infer U> ? U : never;
848
+ }) => TOutput, options?: Omit<ComputedOptions<any, TOutput>, 'lazy'>): Computed<TOutput>;
849
+ /**
850
+ * Create a memoized selector for use with store.subscribe.
851
+ *
852
+ * @param selector - The selector function to memoize
853
+ * @param equals - Custom equality function
854
+ * @returns A memoized selector
855
+ *
856
+ * @example
857
+ * ```typescript
858
+ * const selectExpensiveComputation = memoizeSelector(
859
+ * (state: State) => expensiveOperation(state.data)
860
+ * );
861
+ *
862
+ * store.subscribe(selectExpensiveComputation, (result) => {
863
+ * console.log('Result:', result);
864
+ * });
865
+ * ```
866
+ */
867
+ declare function memoizeSelector<TState, TSelected>(selector: Selector<TState, TSelected>, equals?: EqualityFn<TSelected>): Selector<TState, TSelected>;
868
+
869
+ /**
870
+ * Slices pattern for modular store composition.
871
+ *
872
+ * @module slices
873
+ */
874
+
875
+ /**
876
+ * SetSlice function type for updating slice state.
877
+ */
878
+ type SetSlice<TState> = {
879
+ (partial: Partial<TState>): void;
880
+ (updater: (state: TState) => Partial<TState>): void;
881
+ };
882
+ /**
883
+ * GetSlice function type for getting current state.
884
+ */
885
+ type GetSlice<TState> = () => TState;
886
+ /**
887
+ * Slice creator function signature.
888
+ *
889
+ * @typeParam TState - The full store state type
890
+ * @typeParam TSlice - The slice state type
891
+ */
892
+ type SliceCreator<TState, TSlice extends Partial<TState>> = (set: SetSlice<TState>, get: GetSlice<TState>, store: Store<TState>) => TSlice;
893
+ /**
894
+ * Slice definition with state and actions.
895
+ */
896
+ interface SliceDefinition<TState, TSlice extends Partial<TState>> {
897
+ /** Slice name for debugging */
898
+ name: string;
899
+ /** Slice creator function */
900
+ creator: SliceCreator<TState, TSlice>;
901
+ }
902
+ /**
903
+ * Create a slice definition for use with combineSlices.
904
+ *
905
+ * Slices are modular pieces of state and actions that can be combined
906
+ * to create a complete store.
907
+ *
908
+ * @param name - Slice name for debugging
909
+ * @param creator - Slice creator function
910
+ * @returns A slice definition
911
+ *
912
+ * @example
913
+ * ```typescript
914
+ * // Define a counter slice
915
+ * const counterSlice = createSlice('counter', (set, get) => ({
916
+ * count: 0,
917
+ * increment: () => set((s) => ({ count: s.count + 1 })),
918
+ * decrement: () => set((s) => ({ count: s.count - 1 })),
919
+ * reset: () => set({ count: 0 }),
920
+ * }));
921
+ *
922
+ * // Define a user slice
923
+ * const userSlice = createSlice('user', (set, get) => ({
924
+ * user: null as User | null,
925
+ * setUser: (user: User) => set({ user }),
926
+ * logout: () => set({ user: null }),
927
+ * }));
928
+ *
929
+ * // Combine slices into a store
930
+ * const store = combineSlices(counterSlice, userSlice);
931
+ *
932
+ * // Use the store
933
+ * store.increment();
934
+ * store.setUser({ name: 'John' });
935
+ * ```
936
+ */
937
+ declare function createSlice<TState, TSlice extends Partial<TState>>(name: string, creator: SliceCreator<TState, TSlice>): SliceDefinition<TState, TSlice>;
938
+ /**
939
+ * Internal slice creator type for type inference.
940
+ */
941
+ type InferSlice<T> = T extends SliceDefinition<any, infer S> ? S : never;
942
+ /**
943
+ * Combined state type from multiple slices.
944
+ */
945
+ type CombinedState<TSlices extends SliceDefinition<any, any>[]> = {
946
+ [K in keyof TSlices]: InferSlice<TSlices[K]>;
947
+ }[number] extends infer U ? U extends object ? {
948
+ [K in keyof U as U extends Record<K, any> ? K : never]: U[K];
949
+ } : never : never;
950
+ /**
951
+ * Combine multiple slices into a single store.
952
+ *
953
+ * @param slices - Slice definitions to combine
954
+ * @returns A store with combined state and actions
955
+ *
956
+ * @example
957
+ * ```typescript
958
+ * const counterSlice = createSlice('counter', (set) => ({
959
+ * count: 0,
960
+ * increment: () => set((s) => ({ count: s.count + 1 })),
961
+ * }));
962
+ *
963
+ * const userSlice = createSlice('user', (set) => ({
964
+ * user: null,
965
+ * setUser: (user) => set({ user }),
966
+ * }));
967
+ *
968
+ * const store = combineSlices(counterSlice, userSlice);
969
+ *
970
+ * // Type-safe access to all slice methods
971
+ * store.increment();
972
+ * store.setUser({ name: 'John' });
973
+ * ```
974
+ */
975
+ declare function combineSlices<TSlices extends SliceDefinition<any, any>[]>(...slices: TSlices): Store<CombinedState<TSlices>> & CombinedState<TSlices>;
976
+ /**
977
+ * Create a namespaced slice that prefixes all state keys.
978
+ *
979
+ * @param namespace - The namespace prefix
980
+ * @param creator - Slice creator function
981
+ * @returns A namespaced slice definition
982
+ *
983
+ * @example
984
+ * ```typescript
985
+ * const settingsSlice = createNamespacedSlice('settings', (set) => ({
986
+ * theme: 'dark',
987
+ * language: 'en',
988
+ * setTheme: (theme) => set({ theme }),
989
+ * }));
990
+ *
991
+ * // State will be: { settings: { theme: 'dark', language: 'en' } }
992
+ * // Actions will be: setTheme
993
+ * ```
994
+ */
995
+ declare function createNamespacedSlice<TSlice extends Record<string, any>>(namespace: string, creator: (set: (partial: Partial<TSlice>) => void, get: () => TSlice) => TSlice): SliceDefinition<Record<string, any>, Record<string, any>>;
996
+ /**
997
+ * Extend an existing store with additional slices.
998
+ *
999
+ * @param store - The existing store
1000
+ * @param slices - Additional slices to add
1001
+ * @returns The extended store
1002
+ *
1003
+ * @example
1004
+ * ```typescript
1005
+ * const baseStore = createStore({ count: 0 });
1006
+ *
1007
+ * const extendedStore = extendStore(
1008
+ * baseStore,
1009
+ * createSlice('user', (set) => ({
1010
+ * user: null,
1011
+ * setUser: (user) => set({ user }),
1012
+ * }))
1013
+ * );
1014
+ * ```
1015
+ */
1016
+ declare function extendStore<TState, TSlices extends SliceDefinition<TState & any, any>[]>(store: Store<TState>, ...slices: TSlices): Store<TState & CombinedState<TSlices>> & CombinedState<TSlices>;
1017
+ /**
1018
+ * Reset specific slices to their initial state.
1019
+ *
1020
+ * @param store - The store
1021
+ * @param sliceNames - Names of slices to reset
1022
+ *
1023
+ * @example
1024
+ * ```typescript
1025
+ * // Reset only the user slice
1026
+ * resetSlices(store, 'user');
1027
+ *
1028
+ * // Reset multiple slices
1029
+ * resetSlices(store, 'user', 'cart');
1030
+ * ```
1031
+ */
1032
+ declare function resetSlices<TState>(store: Store<TState>, ...sliceNames: string[]): void;
1033
+
1034
+ /**
1035
+ * Store Federation - Multi-store coordination and communication.
1036
+ *
1037
+ * Enables coordinated updates across multiple stores with
1038
+ * atomic transactions and unified state access.
1039
+ *
1040
+ * @module federation
1041
+ */
1042
+
1043
+ /**
1044
+ * Extract state type from a Store.
1045
+ */
1046
+ type StoreState<S> = S extends Store<infer T> ? T : never;
1047
+ /**
1048
+ * Map of store names to their state types.
1049
+ */
1050
+ type FederatedState<Stores extends Record<string, Store<any>>> = {
1051
+ [K in keyof Stores]: StoreState<Stores[K]>;
1052
+ };
1053
+ /**
1054
+ * Federation listener callback.
1055
+ */
1056
+ type FederationListener<Stores extends Record<string, Store<any>>> = (state: FederatedState<Stores>, prevState: FederatedState<Stores>, changedStore: keyof Stores) => void;
1057
+ /**
1058
+ * Federation transaction function.
1059
+ */
1060
+ type TransactionFn<Stores extends Record<string, Store<any>>> = (stores: Stores) => void | Promise<void>;
1061
+ /**
1062
+ * Federation options.
1063
+ */
1064
+ interface FederationOptions {
1065
+ /** Name for debugging */
1066
+ name?: string;
1067
+ /** Enable transaction logging */
1068
+ debug?: boolean;
1069
+ }
1070
+ /**
1071
+ * Federation interface for coordinating multiple stores.
1072
+ */
1073
+ interface Federation<Stores extends Record<string, Store<any>>> {
1074
+ /** Access to individual stores */
1075
+ readonly stores: Stores;
1076
+ /** Get combined state from all stores */
1077
+ getState(): FederatedState<Stores>;
1078
+ /** Subscribe to any store change */
1079
+ subscribe(listener: FederationListener<Stores>): () => void;
1080
+ /** Atomic multi-store update (synchronous) */
1081
+ transaction(fn: TransactionFn<Stores>): void;
1082
+ /** Async transaction with rollback on error */
1083
+ transactionAsync(fn: TransactionFn<Stores>): Promise<void>;
1084
+ /** Get a specific store */
1085
+ getStore<K extends keyof Stores>(name: K): Stores[K];
1086
+ /** Destroy federation and unsubscribe from all stores */
1087
+ destroy(): void;
1088
+ }
1089
+ /**
1090
+ * Create a federation of multiple stores.
1091
+ *
1092
+ * @param stores - Object containing named stores
1093
+ * @param options - Federation options
1094
+ * @returns A federation instance
1095
+ *
1096
+ * @example
1097
+ * ```typescript
1098
+ * import { createStore, createFederation } from '@oxog/state';
1099
+ *
1100
+ * // Create individual stores
1101
+ * const userStore = createStore({
1102
+ * user: null,
1103
+ * setUser: (state, user) => ({ user }),
1104
+ * });
1105
+ *
1106
+ * const cartStore = createStore({
1107
+ * items: [],
1108
+ * addItem: (state, item) => ({ items: [...state.items, item] }),
1109
+ * clear: () => ({ items: [] }),
1110
+ * });
1111
+ *
1112
+ * const settingsStore = createStore({
1113
+ * theme: 'light',
1114
+ * setTheme: (state, theme) => ({ theme }),
1115
+ * });
1116
+ *
1117
+ * // Create federation
1118
+ * const federation = createFederation({
1119
+ * user: userStore,
1120
+ * cart: cartStore,
1121
+ * settings: settingsStore,
1122
+ * });
1123
+ *
1124
+ * // Get combined state
1125
+ * const state = federation.getState();
1126
+ * // { user: { user: null, ... }, cart: { items: [], ... }, settings: { theme: 'light', ... } }
1127
+ *
1128
+ * // Subscribe to any store change
1129
+ * federation.subscribe((state, prevState, changedStore) => {
1130
+ * console.log(`${changedStore} changed:`, state[changedStore]);
1131
+ * });
1132
+ *
1133
+ * // Atomic cross-store transaction
1134
+ * federation.transaction(({ user, cart }) => {
1135
+ * cart.setState({ items: [] });
1136
+ * user.setState({ user: null });
1137
+ * });
1138
+ * ```
1139
+ */
1140
+ declare function createFederation<Stores extends Record<string, Store<any>>>(stores: Stores, options?: FederationOptions): Federation<Stores>;
1141
+ /**
1142
+ * Create a selector that combines state from multiple stores.
1143
+ *
1144
+ * @param federation - The federation instance
1145
+ * @param selector - Selector function
1146
+ * @returns A function that returns the selected value
1147
+ *
1148
+ * @example
1149
+ * ```typescript
1150
+ * const getCartTotal = createFederatedSelector(
1151
+ * federation,
1152
+ * (state) => {
1153
+ * const items = state.cart.items;
1154
+ * const discount = state.user.user?.discount || 0;
1155
+ * const total = items.reduce((sum, item) => sum + item.price, 0);
1156
+ * return total * (1 - discount);
1157
+ * }
1158
+ * );
1159
+ *
1160
+ * const total = getCartTotal();
1161
+ * ```
1162
+ */
1163
+ declare function createFederatedSelector<Stores extends Record<string, Store<any>>, R>(federation: Federation<Stores>, selector: (state: FederatedState<Stores>) => R): () => R;
1164
+ /**
1165
+ * Create a computed value from federated state.
1166
+ *
1167
+ * @param federation - The federation instance
1168
+ * @param selector - Selector function
1169
+ * @param equalityFn - Optional equality function for caching
1170
+ * @returns Object with get() and subscribe() methods
1171
+ *
1172
+ * @example
1173
+ * ```typescript
1174
+ * const isLoggedIn = createFederatedComputed(
1175
+ * federation,
1176
+ * (state) => state.user.user !== null
1177
+ * );
1178
+ *
1179
+ * // Get current value
1180
+ * if (isLoggedIn.get()) {
1181
+ * showDashboard();
1182
+ * }
1183
+ *
1184
+ * // Subscribe to changes
1185
+ * isLoggedIn.subscribe((value) => {
1186
+ * console.log('Login status:', value);
1187
+ * });
1188
+ * ```
1189
+ */
1190
+ declare function createFederatedComputed<Stores extends Record<string, Store<any>>, R>(federation: Federation<Stores>, selector: (state: FederatedState<Stores>) => R, equalityFn?: (a: R, b: R) => boolean): {
1191
+ get(): R;
1192
+ subscribe(listener: (value: R, prevValue: R) => void): () => void;
1193
+ };
1194
+ /**
1195
+ * Wait for a condition across federated stores.
1196
+ *
1197
+ * @param federation - The federation instance
1198
+ * @param predicate - Condition to wait for
1199
+ * @param timeout - Optional timeout in ms
1200
+ * @returns Promise that resolves when condition is met
1201
+ *
1202
+ * @example
1203
+ * ```typescript
1204
+ * // Wait for user to be logged in and cart to have items
1205
+ * await waitForFederated(
1206
+ * federation,
1207
+ * (state) => state.user.user !== null && state.cart.items.length > 0,
1208
+ * 5000 // 5 second timeout
1209
+ * );
1210
+ *
1211
+ * // Now proceed with checkout
1212
+ * checkout();
1213
+ * ```
1214
+ */
1215
+ declare function waitForFederated<Stores extends Record<string, Store<any>>>(federation: Federation<Stores>, predicate: (state: FederatedState<Stores>) => boolean, timeout?: number): Promise<FederatedState<Stores>>;
481
1216
 
482
1217
  /**
483
1218
  * Plugin-specific types and interfaces.
@@ -495,6 +1230,30 @@ interface PersistOptions<TState> {
495
1230
  whitelist?: Array<keyof TState>;
496
1231
  /** List of state keys to exclude (blacklist) */
497
1232
  blacklist?: Array<keyof TState>;
1233
+ /** Custom function to select which parts of state to persist */
1234
+ partialize?: (state: TState) => Partial<TState>;
1235
+ /** Custom merge strategy for hydration */
1236
+ merge?: (persistedState: Partial<TState>, currentState: TState) => TState;
1237
+ /** Version for migration support */
1238
+ version?: number;
1239
+ /** Migration function between versions */
1240
+ migrate?: (persistedState: unknown, version: number) => TState;
1241
+ /** Custom serialization */
1242
+ serialize?: (state: Partial<TState>) => string;
1243
+ /** Custom deserialization */
1244
+ deserialize?: (str: string) => Partial<TState>;
1245
+ /** Encryption function */
1246
+ encrypt?: (data: string) => string;
1247
+ /** Decryption function */
1248
+ decrypt?: (data: string) => string;
1249
+ /** Debounce writes to storage (ms) */
1250
+ writeDebounce?: number;
1251
+ /** Called when hydration starts */
1252
+ onRehydrateStorage?: (state: TState | undefined) => void;
1253
+ /** Called when hydration completes */
1254
+ onHydrationComplete?: (state: TState) => void;
1255
+ /** Called on persistence error */
1256
+ onPersistError?: (error: Error) => void;
498
1257
  }
499
1258
  /**
500
1259
  * Storage interface for persistence.
@@ -596,9 +1355,25 @@ declare const sessionStorage: StorageLike;
596
1355
  * const store = createStore({ count: 0, temp: '' })
597
1356
  * .use(persist({ key: 'app', whitelist: ['count'] }));
598
1357
  *
599
- * // With blacklist
600
- * const store = createStore({ count: 0, temp: '' })
601
- * .use(persist({ key: 'app', blacklist: ['temp'] }));
1358
+ * // With encryption
1359
+ * const store = createStore({ secret: 'data' })
1360
+ * .use(persist({
1361
+ * key: 'secure',
1362
+ * encrypt: (data) => btoa(data),
1363
+ * decrypt: (data) => atob(data),
1364
+ * }));
1365
+ *
1366
+ * // With debounce and migration
1367
+ * const store = createStore({ count: 0 })
1368
+ * .use(persist({
1369
+ * key: 'app',
1370
+ * writeDebounce: 1000,
1371
+ * version: 2,
1372
+ * migrate: (state, version) => {
1373
+ * if (version < 2) return { ...state, newField: 'default' };
1374
+ * return state;
1375
+ * },
1376
+ * }));
602
1377
  * ```
603
1378
  */
604
1379
  declare function persist<TState>(options: PersistOptions<TState>): Plugin<TState>;
@@ -807,92 +1582,611 @@ declare function triggerSync<TState>(store: Store<TState>, channel?: string): vo
807
1582
  * ```typescript
808
1583
  * import { produce } from '@oxog/state';
809
1584
  *
810
- * const state = { users: [{ name: 'John', age: 30 }] };
811
- * const newState = produce(state, (draft) => {
812
- * draft.users[0].age = 31;
813
- * });
1585
+ * const state = { users: [{ name: 'John', age: 30 }] };
1586
+ * const newState = produce(state, (draft) => {
1587
+ * draft.users[0].age = 31;
1588
+ * });
1589
+ * ```
1590
+ */
1591
+ declare function produce<T>(base: T, recipe: (draft: T) => void): T;
1592
+ /**
1593
+ * Create an immer plugin.
1594
+ *
1595
+ * @returns An immer plugin
1596
+ *
1597
+ * @example
1598
+ * ```typescript
1599
+ * import { createStore, immer } from '@oxog/state';
1600
+ *
1601
+ * const store = createStore({
1602
+ * items: [{ id: 1, name: 'Item 1' }]
1603
+ * }).use(immer());
1604
+ *
1605
+ * // Now setState can accept a mutable recipe function
1606
+ * store.setState((draft) => {
1607
+ * draft.items[0].name = 'Updated Item';
1608
+ * draft.items.push({ id: 2, name: 'Item 2' });
1609
+ * });
1610
+ * ```
1611
+ */
1612
+ declare function immer<TState>(): Plugin<TState>;
1613
+
1614
+ /**
1615
+ * Selector plugin - Computed/derived values.
1616
+ *
1617
+ * Define computed values that automatically update when dependencies change.
1618
+ *
1619
+ * @example
1620
+ * ```typescript
1621
+ * import { createStore, selector } from '@oxog/state';
1622
+ *
1623
+ * const store = createStore({
1624
+ * items: [],
1625
+ * filter: 'all',
1626
+ * })
1627
+ * .use(selector({
1628
+ * // Computed: filtered items
1629
+ * filteredItems: (state) => {
1630
+ * if (state.filter === 'all') return state.items;
1631
+ * return state.items.filter((item: any) => item.status === state.filter);
1632
+ * },
1633
+ * // Computed: item count
1634
+ * itemCount: (state) => state.items.length,
1635
+ * }));
1636
+ *
1637
+ * // Access computed values
1638
+ * const state = store.getState();
1639
+ * console.log(state.filteredItems); // Computed value
1640
+ * ```
1641
+ */
1642
+
1643
+ /**
1644
+ * Create a selector plugin for computed values.
1645
+ *
1646
+ * @param options - Plugin options with selectors
1647
+ * @returns A selector plugin
1648
+ *
1649
+ * @example
1650
+ * ```typescript
1651
+ * import { selector } from '@oxog/state';
1652
+ *
1653
+ * const store = createStore({
1654
+ * items: [{ price: 10 }, { price: 20 }],
1655
+ * taxRate: 0.1,
1656
+ * })
1657
+ * .use(selector({
1658
+ * // Computed total
1659
+ * total: (state) =>
1660
+ * state.items.reduce((sum: number, item: any) => sum + item.price, 0),
1661
+ *
1662
+ * // Computed total with tax
1663
+ * totalWithTax: (state) => {
1664
+ * const total = state.items.reduce((sum: number, item: any) => sum + item.price, 0);
1665
+ * return total * (1 + state.taxRate);
1666
+ * },
1667
+ * }));
1668
+ * ```
1669
+ */
1670
+ declare function selector<TState>(options: SelectorOptions<TState>): Plugin<TState>;
1671
+
1672
+ /**
1673
+ * Logger plugin for console logging state changes.
1674
+ *
1675
+ * @module plugins/logger
1676
+ */
1677
+
1678
+ /**
1679
+ * Log level for filtering messages.
1680
+ */
1681
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
1682
+ /**
1683
+ * Logger options.
1684
+ */
1685
+ interface LoggerOptions<TState = unknown> {
1686
+ /** Log level filter (default: 'debug') */
1687
+ level?: LogLevel;
1688
+ /** Custom logger (default: console) */
1689
+ logger?: Console;
1690
+ /** Use collapsed console groups (default: true) */
1691
+ collapsed?: boolean;
1692
+ /** Show state diff (default: true) */
1693
+ diff?: boolean;
1694
+ /** Colorize output (default: true in browsers) */
1695
+ colors?: boolean;
1696
+ /** Show timestamp (default: true) */
1697
+ timestamp?: boolean;
1698
+ /** Filter function to skip certain changes */
1699
+ filter?: (state: TState, prevState: TState) => boolean;
1700
+ /** Transform state before logging */
1701
+ stateTransformer?: (state: TState) => unknown;
1702
+ /** Custom action name (default: 'STATE_CHANGE') */
1703
+ actionName?: string | ((state: TState, prevState: TState) => string);
1704
+ /** Name for this logger instance */
1705
+ name?: string;
1706
+ /** Enabled flag (default: true) */
1707
+ enabled?: boolean;
1708
+ }
1709
+ /**
1710
+ * Create a logger plugin.
1711
+ *
1712
+ * @param options - Logger options
1713
+ * @returns A logger plugin
1714
+ *
1715
+ * @example
1716
+ * ```typescript
1717
+ * import { createStore, logger } from '@oxog/state';
1718
+ *
1719
+ * // Basic usage
1720
+ * const store = createStore({ count: 0 })
1721
+ * .use(logger());
1722
+ *
1723
+ * // With options
1724
+ * const store = createStore({ count: 0 })
1725
+ * .use(logger({
1726
+ * level: 'info',
1727
+ * collapsed: false,
1728
+ * diff: true,
1729
+ * name: 'CounterStore',
1730
+ * }));
1731
+ *
1732
+ * // Disabled in production
1733
+ * const store = createStore({ count: 0 })
1734
+ * .use(logger({
1735
+ * enabled: process.env.NODE_ENV !== 'production',
1736
+ * }));
1737
+ * ```
1738
+ */
1739
+ declare function logger<TState = unknown>(options?: LoggerOptions<TState>): Plugin<TState>;
1740
+ /**
1741
+ * Create a logger with preset options.
1742
+ *
1743
+ * @param defaultOptions - Default options
1744
+ * @returns A logger factory function
1745
+ *
1746
+ * @example
1747
+ * ```typescript
1748
+ * const devLogger = createLogger({
1749
+ * enabled: process.env.NODE_ENV === 'development',
1750
+ * collapsed: true,
1751
+ * });
1752
+ *
1753
+ * const store = createStore({ count: 0 })
1754
+ * .use(devLogger({ name: 'Counter' }));
1755
+ * ```
1756
+ */
1757
+ declare function createLogger<TState = unknown>(defaultOptions?: LoggerOptions<TState>): (options?: LoggerOptions<TState>) => Plugin<TState>;
1758
+
1759
+ /**
1760
+ * Effects plugin for managing side effects.
1761
+ *
1762
+ * Provides a declarative way to handle async operations,
1763
+ * API calls, and other side effects in response to state changes.
1764
+ *
1765
+ * @module plugins/effects
1766
+ */
1767
+
1768
+ /**
1769
+ * Effect cleanup function.
1770
+ */
1771
+ type EffectCleanup = () => void;
1772
+ /**
1773
+ * Effect function that runs when dependencies change.
1774
+ */
1775
+ type EffectFn<T> = (value: T, prevValue: T, utils: EffectUtils) => void | EffectCleanup | Promise<void | EffectCleanup>;
1776
+ /**
1777
+ * Utilities available to effects.
1778
+ */
1779
+ interface EffectUtils {
1780
+ /** Get current store state */
1781
+ getState: () => unknown;
1782
+ /** Set store state */
1783
+ setState: (partial: any) => void;
1784
+ /** Check if effect is still active (not cancelled) */
1785
+ isActive: () => boolean;
1786
+ /** Cancel this effect */
1787
+ cancel: () => void;
1788
+ /** Run a callback only if effect is active */
1789
+ onlyIfActive: <T>(fn: () => T) => T | undefined;
1790
+ }
1791
+ /**
1792
+ * Effect definition for the effects plugin.
1793
+ */
1794
+ interface EffectDefinition<TState, TSelected = TState> {
1795
+ /** Selector to watch */
1796
+ selector: Selector<TState, TSelected>;
1797
+ /** Effect function */
1798
+ effect: EffectFn<TSelected>;
1799
+ /** Custom equality function */
1800
+ equalityFn?: EqualityFn<TSelected>;
1801
+ /** Fire effect immediately with current value */
1802
+ fireImmediately?: boolean;
1803
+ /** Debounce effect (ms) */
1804
+ debounce?: number;
1805
+ /** Effect name for debugging */
1806
+ name?: string;
1807
+ }
1808
+ /**
1809
+ * Options for the effects plugin.
1810
+ */
1811
+ interface EffectsOptions<TState> {
1812
+ /** Array of effect definitions */
1813
+ effects: EffectDefinition<TState, any>[];
1814
+ /** Error handler for effect errors */
1815
+ onError?: (error: Error, effectName?: string) => void;
1816
+ }
1817
+ /**
1818
+ * Create an effects plugin.
1819
+ *
1820
+ * @param options - Effects configuration
1821
+ * @returns An effects plugin
1822
+ *
1823
+ * @example
1824
+ * ```typescript
1825
+ * import { createStore, effects } from '@oxog/state';
1826
+ *
1827
+ * const store = createStore({
1828
+ * userId: null,
1829
+ * user: null,
1830
+ * loading: false,
1831
+ * }).use(effects({
1832
+ * effects: [
1833
+ * {
1834
+ * name: 'fetchUser',
1835
+ * selector: (s) => s.userId,
1836
+ * effect: async (userId, _prev, { setState, isActive }) => {
1837
+ * if (!userId) return;
1838
+ *
1839
+ * setState({ loading: true });
1840
+ * try {
1841
+ * const user = await fetchUser(userId);
1842
+ * if (isActive()) {
1843
+ * setState({ user, loading: false });
1844
+ * }
1845
+ * } catch (error) {
1846
+ * if (isActive()) {
1847
+ * setState({ user: null, loading: false });
1848
+ * }
1849
+ * }
1850
+ * },
1851
+ * },
1852
+ * ],
1853
+ * }));
1854
+ * ```
1855
+ */
1856
+ declare function effects<TState>(options: EffectsOptions<TState>): Plugin<TState>;
1857
+ /**
1858
+ * Create an effect definition helper.
1859
+ *
1860
+ * @param name - Effect name
1861
+ * @param selector - Selector to watch
1862
+ * @param effect - Effect function
1863
+ * @param options - Additional options
1864
+ * @returns Effect definition
1865
+ *
1866
+ * @example
1867
+ * ```typescript
1868
+ * const fetchUserEffect = createEffect(
1869
+ * 'fetchUser',
1870
+ * (s) => s.userId,
1871
+ * async (userId, _prev, { setState }) => {
1872
+ * const user = await api.getUser(userId);
1873
+ * setState({ user });
1874
+ * },
1875
+ * { fireImmediately: true }
1876
+ * );
1877
+ *
1878
+ * const store = createStore({ userId: null, user: null })
1879
+ * .use(effects({ effects: [fetchUserEffect] }));
1880
+ * ```
1881
+ */
1882
+ declare function createEffect<TState, TSelected>(name: string, selector: Selector<TState, TSelected>, effect: EffectFn<TSelected>, options?: Omit<EffectDefinition<TState, TSelected>, 'name' | 'selector' | 'effect'>): EffectDefinition<TState, TSelected>;
1883
+ /**
1884
+ * Create a simple effect that runs on any state change.
1885
+ *
1886
+ * @param effect - Effect function
1887
+ * @param options - Effect options
1888
+ * @returns Effect definition
1889
+ *
1890
+ * @example
1891
+ * ```typescript
1892
+ * const logEffect = createSimpleEffect(
1893
+ * (state, prevState) => {
1894
+ * console.log('State changed:', state);
1895
+ * }
1896
+ * );
1897
+ * ```
1898
+ */
1899
+ declare function createSimpleEffect<TState>(effect: (state: TState, prevState: TState, utils: EffectUtils) => void | EffectCleanup, options?: Omit<EffectDefinition<TState, TState>, 'selector' | 'effect'>): EffectDefinition<TState, TState>;
1900
+ /**
1901
+ * Combine multiple effect definitions.
1902
+ *
1903
+ * @param effectDefs - Effect definitions to combine
1904
+ * @returns Combined effects options
1905
+ *
1906
+ * @example
1907
+ * ```typescript
1908
+ * const store = createStore({ ... })
1909
+ * .use(effects(combineEffects(
1910
+ * fetchUserEffect,
1911
+ * saveToStorageEffect,
1912
+ * analyticsEffect,
1913
+ * )));
1914
+ * ```
1915
+ */
1916
+ declare function combineEffects<TState>(...effectDefs: EffectDefinition<TState, any>[]): EffectsOptions<TState>;
1917
+ /**
1918
+ * Create a debounced effect that only fires after a delay.
1919
+ *
1920
+ * @param delay - Debounce delay in ms
1921
+ * @param selector - Selector to watch
1922
+ * @param effect - Effect function
1923
+ * @returns Effect definition
1924
+ *
1925
+ * @example
1926
+ * ```typescript
1927
+ * const searchEffect = createDebouncedEffect(
1928
+ * 300,
1929
+ * (s) => s.searchQuery,
1930
+ * async (query, _prev, { setState }) => {
1931
+ * const results = await api.search(query);
1932
+ * setState({ searchResults: results });
1933
+ * }
1934
+ * );
1935
+ * ```
1936
+ */
1937
+ declare function createDebouncedEffect<TState, TSelected>(delay: number, selector: Selector<TState, TSelected>, effect: EffectFn<TSelected>, options?: Omit<EffectDefinition<TState, TSelected>, 'selector' | 'effect' | 'debounce'>): EffectDefinition<TState, TSelected>;
1938
+
1939
+ /**
1940
+ * Validation plugin for state schema validation.
1941
+ *
1942
+ * Provides schema-agnostic validation with support for Zod, Yup,
1943
+ * or custom validation functions.
1944
+ *
1945
+ * @module plugins/validate
1946
+ */
1947
+
1948
+ /**
1949
+ * Validation error type.
1950
+ */
1951
+ interface ValidationError {
1952
+ /** Path to the invalid field */
1953
+ path: string[];
1954
+ /** Error message */
1955
+ message: string;
1956
+ /** Validation rule that failed */
1957
+ rule?: string;
1958
+ /** The invalid value */
1959
+ value?: unknown;
1960
+ }
1961
+ /**
1962
+ * Validation result.
1963
+ */
1964
+ interface ValidationResult {
1965
+ /** Whether validation passed */
1966
+ valid: boolean;
1967
+ /** List of validation errors */
1968
+ errors: ValidationError[];
1969
+ }
1970
+ /**
1971
+ * Custom validator function type.
1972
+ */
1973
+ type ValidatorFn<T> = (state: T) => boolean | ValidationResult | ValidationError[];
1974
+ /**
1975
+ * Zod-like schema interface.
1976
+ */
1977
+ interface ZodLikeSchema<T> {
1978
+ safeParse(data: unknown): {
1979
+ success: boolean;
1980
+ error?: {
1981
+ issues: Array<{
1982
+ path: (string | number)[];
1983
+ message: string;
1984
+ code?: string;
1985
+ }>;
1986
+ };
1987
+ data?: T;
1988
+ };
1989
+ }
1990
+ /**
1991
+ * Yup-like schema interface.
1992
+ */
1993
+ interface YupLikeSchema<T> {
1994
+ validateSync(data: unknown, options?: {
1995
+ abortEarly?: boolean;
1996
+ }): T;
1997
+ validate(data: unknown, options?: {
1998
+ abortEarly?: boolean;
1999
+ }): Promise<T>;
2000
+ }
2001
+ /**
2002
+ * Schema type - supports Zod, Yup, or custom validators.
2003
+ */
2004
+ type Schema<T> = ZodLikeSchema<T> | YupLikeSchema<T> | ValidatorFn<T>;
2005
+ /**
2006
+ * Validation timing options.
2007
+ */
2008
+ type ValidationTiming = 'change' | 'commit' | 'manual';
2009
+ /**
2010
+ * Validation plugin options.
2011
+ */
2012
+ interface ValidateOptions<T> {
2013
+ /** Schema to validate against (Zod, Yup, or custom function) */
2014
+ schema: Schema<T>;
2015
+ /** When to validate: 'change' (every setState), 'commit' (on batch commit), 'manual' (only when validate() called) */
2016
+ on?: ValidationTiming;
2017
+ /** Callback when validation fails */
2018
+ onError?: (errors: ValidationError[]) => void;
2019
+ /** Throw error on validation failure */
2020
+ throwOnError?: boolean;
2021
+ /** Only validate these paths (keys of state) */
2022
+ paths?: Array<keyof T>;
2023
+ /** Name for debugging */
2024
+ name?: string;
2025
+ }
2026
+ /**
2027
+ * Validation API added to store.
2028
+ */
2029
+ interface ValidationAPI {
2030
+ /** Manually trigger validation */
2031
+ validate(): ValidationResult;
2032
+ /** Check if current state is valid */
2033
+ isValid(): boolean;
2034
+ /** Get current validation errors */
2035
+ getErrors(): ValidationError[];
2036
+ /** Clear validation errors */
2037
+ clearErrors(): void;
2038
+ }
2039
+ /**
2040
+ * Create a validation plugin.
2041
+ *
2042
+ * @param options - Validation options
2043
+ * @returns A validation plugin
2044
+ *
2045
+ * @example
2046
+ * ```typescript
2047
+ * import { createStore, validate } from '@oxog/state';
2048
+ * import { z } from 'zod';
2049
+ *
2050
+ * // With Zod schema
2051
+ * const userSchema = z.object({
2052
+ * name: z.string().min(1),
2053
+ * age: z.number().min(0),
2054
+ * email: z.string().email(),
2055
+ * });
2056
+ *
2057
+ * const store = createStore({ name: '', age: 0, email: '' })
2058
+ * .use(validate({
2059
+ * schema: userSchema,
2060
+ * on: 'change',
2061
+ * onError: (errors) => console.log('Validation errors:', errors),
2062
+ * }));
2063
+ *
2064
+ * // Manual validation
2065
+ * const result = store.validate();
2066
+ * if (!result.valid) {
2067
+ * console.log(result.errors);
2068
+ * }
2069
+ *
2070
+ * // Check if valid
2071
+ * if (store.isValid()) {
2072
+ * submitForm();
2073
+ * }
2074
+ * ```
2075
+ *
2076
+ * @example
2077
+ * ```typescript
2078
+ * // With custom validator function
2079
+ * const store = createStore({ password: '', confirmPassword: '' })
2080
+ * .use(validate({
2081
+ * schema: (state) => {
2082
+ * const errors = [];
2083
+ * if (state.password.length < 8) {
2084
+ * errors.push({
2085
+ * path: ['password'],
2086
+ * message: 'Password must be at least 8 characters',
2087
+ * });
2088
+ * }
2089
+ * if (state.password !== state.confirmPassword) {
2090
+ * errors.push({
2091
+ * path: ['confirmPassword'],
2092
+ * message: 'Passwords must match',
2093
+ * });
2094
+ * }
2095
+ * return errors;
2096
+ * },
2097
+ * on: 'change',
2098
+ * }));
2099
+ * ```
2100
+ *
2101
+ * @example
2102
+ * ```typescript
2103
+ * // With partial validation
2104
+ * const store = createStore({ name: '', age: 0, temp: '' })
2105
+ * .use(validate({
2106
+ * schema: userSchema,
2107
+ * paths: ['name', 'age'], // Only validate these fields
2108
+ * }));
2109
+ * ```
2110
+ */
2111
+ declare function validate<TState>(options: ValidateOptions<TState>): Plugin<TState>;
2112
+ /**
2113
+ * Create a simple boolean validator.
2114
+ *
2115
+ * @param predicate - Validation predicate function
2116
+ * @param message - Error message when validation fails
2117
+ * @returns A validator function
2118
+ *
2119
+ * @example
2120
+ * ```typescript
2121
+ * const isPositive = createValidator(
2122
+ * (state) => state.count >= 0,
2123
+ * 'Count must be positive'
2124
+ * );
2125
+ *
2126
+ * const store = createStore({ count: 0 })
2127
+ * .use(validate({ schema: isPositive }));
814
2128
  * ```
815
2129
  */
816
- declare function produce<T>(base: T, recipe: (draft: T) => void): T;
2130
+ declare function createValidator<T>(predicate: (state: T) => boolean, message: string): ValidatorFn<T>;
817
2131
  /**
818
- * Create an immer plugin.
2132
+ * Combine multiple validators into one.
819
2133
  *
820
- * @returns An immer plugin
2134
+ * @param validators - Array of validator functions
2135
+ * @returns Combined validator function
821
2136
  *
822
2137
  * @example
823
2138
  * ```typescript
824
- * import { createStore, immer } from '@oxog/state';
825
- *
826
- * const store = createStore({
827
- * items: [{ id: 1, name: 'Item 1' }]
828
- * }).use(immer());
2139
+ * const combinedValidator = combineValidators(
2140
+ * createValidator((s) => s.name.length > 0, 'Name required'),
2141
+ * createValidator((s) => s.age >= 18, 'Must be 18+'),
2142
+ * );
829
2143
  *
830
- * // Now setState can accept a mutable recipe function
831
- * store.setState((draft) => {
832
- * draft.items[0].name = 'Updated Item';
833
- * draft.items.push({ id: 2, name: 'Item 2' });
834
- * });
2144
+ * const store = createStore({ name: '', age: 0 })
2145
+ * .use(validate({ schema: combinedValidator }));
835
2146
  * ```
836
2147
  */
837
- declare function immer<TState>(): Plugin<TState>;
838
-
2148
+ declare function combineValidators<T>(...validators: ValidatorFn<T>[]): ValidatorFn<T>;
839
2149
  /**
840
- * Selector plugin - Computed/derived values.
2150
+ * Create a field-level validator.
841
2151
  *
842
- * Define computed values that automatically update when dependencies change.
2152
+ * @param field - Field name to validate
2153
+ * @param predicate - Validation predicate for field value
2154
+ * @param message - Error message when validation fails
2155
+ * @returns A validator function
843
2156
  *
844
2157
  * @example
845
2158
  * ```typescript
846
- * import { createStore, selector } from '@oxog/state';
847
- *
848
- * const store = createStore({
849
- * items: [],
850
- * filter: 'all',
851
- * })
852
- * .use(selector({
853
- * // Computed: filtered items
854
- * filteredItems: (state) => {
855
- * if (state.filter === 'all') return state.items;
856
- * return state.items.filter((item: any) => item.status === state.filter);
857
- * },
858
- * // Computed: item count
859
- * itemCount: (state) => state.items.length,
860
- * }));
2159
+ * const emailValidator = createFieldValidator(
2160
+ * 'email',
2161
+ * (email) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email),
2162
+ * 'Invalid email format'
2163
+ * );
861
2164
  *
862
- * // Access computed values
863
- * const state = store.getState();
864
- * console.log(state.filteredItems); // Computed value
2165
+ * const store = createStore({ email: '' })
2166
+ * .use(validate({ schema: emailValidator }));
865
2167
  * ```
866
2168
  */
867
-
2169
+ declare function createFieldValidator<T, K extends keyof T>(field: K, predicate: (value: T[K], state: T) => boolean, message: string): ValidatorFn<T>;
868
2170
  /**
869
- * Create a selector plugin for computed values.
2171
+ * Create an async validator (for server-side validation).
870
2172
  *
871
- * @param options - Plugin options with selectors
872
- * @returns A selector plugin
2173
+ * @param validator - Async validation function
2174
+ * @returns A promise that resolves to validation result
873
2175
  *
874
2176
  * @example
875
2177
  * ```typescript
876
- * import { selector } from '@oxog/state';
877
- *
878
- * const store = createStore({
879
- * items: [{ price: 10 }, { price: 20 }],
880
- * taxRate: 0.1,
881
- * })
882
- * .use(selector({
883
- * // Computed total
884
- * total: (state) =>
885
- * state.items.reduce((sum: number, item: any) => sum + item.price, 0),
2178
+ * const checkUsername = createAsyncValidator(async (state) => {
2179
+ * const exists = await api.checkUsername(state.username);
2180
+ * return exists
2181
+ * ? [{ path: ['username'], message: 'Username already taken' }]
2182
+ * : [];
2183
+ * });
886
2184
  *
887
- * // Computed total with tax
888
- * totalWithTax: (state) => {
889
- * const total = state.items.reduce((sum: number, item: any) => sum + item.price, 0);
890
- * return total * (1 + state.taxRate);
891
- * },
892
- * }));
2185
+ * // Manual validation
2186
+ * const result = await checkUsername(store.getState());
893
2187
  * ```
894
2188
  */
895
- declare function selector<TState>(options: SelectorOptions<TState>): Plugin<TState>;
2189
+ declare function createAsyncValidator<T>(validator: (state: T) => Promise<ValidationError[]>): (state: T) => Promise<ValidationResult>;
896
2190
 
897
2191
  /**
898
2192
  * Deep clone a value, creating copies of nested objects and arrays.
@@ -1058,4 +2352,430 @@ declare function omit<T extends object, K extends keyof T>(obj: T, keys: readonl
1058
2352
  */
1059
2353
  declare function identity<T>(value: T): T;
1060
2354
 
1061
- export { type Action, type Actions, type DeepPartial, type DevtoolsOptions, type EqualityFn, type HistoryOptions, type HistoryStore, type Listener, type PersistOptions, type Plugin, type Selector, type SelectorOptions, type StorageLike$1 as StorageLike, type Store, type StoreBuilder, StoreError, StoreError as StoreErrorClass, StoreErrorCode, type StoreOptions, type SyncOptions, batch, createStorage, createStore, deepClone, deepEqual, deepMerge, devtools, hasHistory, history, identity, immer, isFunction, omit, persist, pick, produce, selector, sessionStorage, shallowEqual, sync, triggerSync, useAction, useCreateStore, useStore };
2355
+ /**
2356
+ * Testing utilities for @oxog/state.
2357
+ *
2358
+ * Provides helpers for testing stores, state changes,
2359
+ * and async effects in unit tests.
2360
+ *
2361
+ * @module testing
2362
+ */
2363
+
2364
+ /**
2365
+ * Mock storage for testing persist plugin.
2366
+ */
2367
+ interface MockStorage {
2368
+ getItem(key: string): string | null;
2369
+ setItem(key: string, value: string): void;
2370
+ removeItem(key: string): void;
2371
+ clear(): void;
2372
+ getAll(): Record<string, string>;
2373
+ }
2374
+ /**
2375
+ * Create a mock storage for testing.
2376
+ *
2377
+ * @returns A mock storage implementation
2378
+ *
2379
+ * @example
2380
+ * ```typescript
2381
+ * import { createMockStorage, persist } from '@oxog/state';
2382
+ *
2383
+ * const mockStorage = createMockStorage();
2384
+ *
2385
+ * const store = createStore({ count: 0 })
2386
+ * .use(persist({ key: 'test', storage: mockStorage }));
2387
+ *
2388
+ * store.setState({ count: 5 });
2389
+ * expect(mockStorage.getItem('test')).toBe('{"count":5}');
2390
+ * ```
2391
+ */
2392
+ declare function createMockStorage(): MockStorage;
2393
+ /**
2394
+ * State change record for tracking.
2395
+ */
2396
+ interface StateChange<TState> {
2397
+ state: TState;
2398
+ prevState: TState;
2399
+ timestamp: number;
2400
+ }
2401
+ /**
2402
+ * Store spy for testing state changes.
2403
+ */
2404
+ interface StoreSpy<TState> {
2405
+ /** All recorded state changes */
2406
+ changes: StateChange<TState>[];
2407
+ /** Get the last state change */
2408
+ lastChange: () => StateChange<TState> | undefined;
2409
+ /** Get the last state */
2410
+ lastState: () => TState | undefined;
2411
+ /** Reset recorded changes */
2412
+ reset: () => void;
2413
+ /** Unsubscribe from store */
2414
+ unsubscribe: () => void;
2415
+ /** Wait for a specific state condition */
2416
+ waitFor: (predicate: (state: TState) => boolean, timeout?: number) => Promise<TState>;
2417
+ /** Wait for a specific number of changes */
2418
+ waitForChanges: (count: number, timeout?: number) => Promise<StateChange<TState>[]>;
2419
+ }
2420
+ /**
2421
+ * Create a spy to track store state changes.
2422
+ *
2423
+ * @param store - The store to spy on
2424
+ * @returns A store spy object
2425
+ *
2426
+ * @example
2427
+ * ```typescript
2428
+ * import { createStore, spyOnStore } from '@oxog/state';
2429
+ *
2430
+ * const store = createStore({ count: 0 });
2431
+ * const spy = spyOnStore(store);
2432
+ *
2433
+ * store.setState({ count: 1 });
2434
+ * store.setState({ count: 2 });
2435
+ *
2436
+ * expect(spy.changes).toHaveLength(2);
2437
+ * expect(spy.lastState()?.count).toBe(2);
2438
+ * ```
2439
+ */
2440
+ declare function spyOnStore<TState>(store: Store<TState>): StoreSpy<TState>;
2441
+ /**
2442
+ * Test helper for asserting state values.
2443
+ */
2444
+ interface StateAssertion<TState> {
2445
+ /** Assert the current state equals expected */
2446
+ toEqual: (expected: Partial<TState>) => void;
2447
+ /** Assert a selector value equals expected */
2448
+ toHaveSelected: <T>(selector: Selector<TState, T>, expected: T) => void;
2449
+ /** Assert state matches a predicate */
2450
+ toMatch: (predicate: (state: TState) => boolean) => void;
2451
+ }
2452
+ /**
2453
+ * Create assertions for a store's state.
2454
+ *
2455
+ * @param store - The store to assert on
2456
+ * @returns State assertion helpers
2457
+ *
2458
+ * @example
2459
+ * ```typescript
2460
+ * import { createStore, assertState } from '@oxog/state';
2461
+ *
2462
+ * const store = createStore({ count: 0, name: 'test' });
2463
+ * const assert = assertState(store);
2464
+ *
2465
+ * assert.toEqual({ count: 0 });
2466
+ * assert.toHaveSelected(s => s.name, 'test');
2467
+ * assert.toMatch(s => s.count >= 0);
2468
+ * ```
2469
+ */
2470
+ declare function assertState<TState>(store: Store<TState>): StateAssertion<TState>;
2471
+ /**
2472
+ * Options for test store creation.
2473
+ */
2474
+ interface TestStoreOptions<TState> {
2475
+ /** Initial state */
2476
+ initialState: TState;
2477
+ /** Whether to enable spy automatically */
2478
+ spy?: boolean;
2479
+ }
2480
+ /**
2481
+ * Test store wrapper with built-in utilities.
2482
+ */
2483
+ interface TestStore<TState> {
2484
+ /** The underlying store */
2485
+ store: Store<TState>;
2486
+ /** State spy (if enabled) */
2487
+ spy?: StoreSpy<TState>;
2488
+ /** State assertions */
2489
+ assert: StateAssertion<TState>;
2490
+ /** Reset store to initial state */
2491
+ reset: () => void;
2492
+ /** Destroy store and cleanup */
2493
+ destroy: () => void;
2494
+ }
2495
+ /**
2496
+ * Create a test store with built-in utilities.
2497
+ *
2498
+ * @param options - Test store options
2499
+ * @returns A test store wrapper
2500
+ *
2501
+ * @example
2502
+ * ```typescript
2503
+ * import { createTestStore } from '@oxog/state';
2504
+ *
2505
+ * describe('Counter', () => {
2506
+ * let testStore: TestStore<{ count: number }>;
2507
+ *
2508
+ * beforeEach(() => {
2509
+ * testStore = createTestStore({ initialState: { count: 0 }, spy: true });
2510
+ * });
2511
+ *
2512
+ * afterEach(() => {
2513
+ * testStore.destroy();
2514
+ * });
2515
+ *
2516
+ * it('should increment count', () => {
2517
+ * testStore.store.setState({ count: 1 });
2518
+ * testStore.assert.toEqual({ count: 1 });
2519
+ * expect(testStore.spy?.changes).toHaveLength(1);
2520
+ * });
2521
+ * });
2522
+ * ```
2523
+ */
2524
+ declare function createTestStore<TState>(options: TestStoreOptions<TState>): TestStore<TState>;
2525
+ /**
2526
+ * Wait for a specified amount of time.
2527
+ *
2528
+ * @param ms - Milliseconds to wait
2529
+ * @returns A promise that resolves after the delay
2530
+ *
2531
+ * @example
2532
+ * ```typescript
2533
+ * await delay(100);
2534
+ * ```
2535
+ */
2536
+ declare function delay(ms: number): Promise<void>;
2537
+ /**
2538
+ * Run a function and wait for all pending microtasks.
2539
+ *
2540
+ * @param fn - Function to run
2541
+ * @returns A promise that resolves after microtasks complete
2542
+ *
2543
+ * @example
2544
+ * ```typescript
2545
+ * await flushMicrotasks(() => {
2546
+ * store.setState({ count: 1 });
2547
+ * });
2548
+ * ```
2549
+ */
2550
+ declare function flushMicrotasks(fn?: () => void): Promise<void>;
2551
+ /**
2552
+ * Wrap a store action for testing with call tracking.
2553
+ */
2554
+ interface MockedAction<TArgs extends any[], TReturn> {
2555
+ /** Call the action */
2556
+ (...args: TArgs): TReturn;
2557
+ /** Number of times called */
2558
+ callCount: number;
2559
+ /** Arguments from each call */
2560
+ calls: TArgs[];
2561
+ /** Reset call tracking */
2562
+ reset: () => void;
2563
+ }
2564
+ /**
2565
+ * Create a mocked action for testing.
2566
+ *
2567
+ * @param fn - The original function
2568
+ * @returns A mocked action with call tracking
2569
+ *
2570
+ * @example
2571
+ * ```typescript
2572
+ * const mockIncrement = mockAction((amount: number) => {
2573
+ * store.setState(s => ({ count: s.count + amount }));
2574
+ * });
2575
+ *
2576
+ * mockIncrement(5);
2577
+ * mockIncrement(3);
2578
+ *
2579
+ * expect(mockIncrement.callCount).toBe(2);
2580
+ * expect(mockIncrement.calls).toEqual([[5], [3]]);
2581
+ * ```
2582
+ */
2583
+ declare function mockAction<TArgs extends any[], TReturn>(fn: (...args: TArgs) => TReturn): MockedAction<TArgs, TReturn>;
2584
+ /**
2585
+ * Create a snapshot of the current store state.
2586
+ *
2587
+ * @param store - The store to snapshot
2588
+ * @returns A deep clone of the current state
2589
+ *
2590
+ * @example
2591
+ * ```typescript
2592
+ * const before = snapshot(store);
2593
+ * store.setState({ count: 5 });
2594
+ * const after = snapshot(store);
2595
+ *
2596
+ * expect(before.count).toBe(0);
2597
+ * expect(after.count).toBe(5);
2598
+ * ```
2599
+ */
2600
+ declare function snapshot<TState>(store: Store<TState>): TState;
2601
+ /**
2602
+ * Compare two state snapshots and return differences.
2603
+ *
2604
+ * @param before - State before changes
2605
+ * @param after - State after changes
2606
+ * @returns Object containing changed keys and their values
2607
+ *
2608
+ * @example
2609
+ * ```typescript
2610
+ * const before = { count: 0, name: 'test' };
2611
+ * const after = { count: 5, name: 'test' };
2612
+ *
2613
+ * const diff = stateDiff(before, after);
2614
+ * // { count: { before: 0, after: 5 } }
2615
+ * ```
2616
+ */
2617
+ declare function stateDiff<TState extends Record<string, any>>(before: TState, after: TState): Record<string, {
2618
+ before: any;
2619
+ after: any;
2620
+ }>;
2621
+
2622
+ /**
2623
+ * Middleware Compatibility Layer
2624
+ *
2625
+ * Provides a generic middleware pattern for state management,
2626
+ * enabling compatibility with various middleware ecosystems.
2627
+ *
2628
+ * @module compat/middleware
2629
+ */
2630
+
2631
+ /**
2632
+ * Middleware-style SetState function.
2633
+ */
2634
+ type MiddlewareSetState<T> = {
2635
+ (partial: Partial<T> | ((state: T) => Partial<T>), replace?: boolean): void;
2636
+ };
2637
+ /**
2638
+ * Middleware-style GetState function.
2639
+ */
2640
+ type MiddlewareGetState<T> = () => T;
2641
+ /**
2642
+ * Middleware-style Subscribe function.
2643
+ */
2644
+ type MiddlewareSubscribe<T> = (listener: (state: T, prevState: T) => void) => () => void;
2645
+ /**
2646
+ * Generic StoreApi for middleware compatibility.
2647
+ */
2648
+ interface MiddlewareStoreApi<T> {
2649
+ setState: MiddlewareSetState<T>;
2650
+ getState: MiddlewareGetState<T>;
2651
+ subscribe: MiddlewareSubscribe<T>;
2652
+ destroy?: () => void;
2653
+ }
2654
+ /**
2655
+ * State creator function for middleware pattern.
2656
+ */
2657
+ type StateCreatorFn<T, Mps extends unknown[] = [], Mcs extends unknown[] = []> = (set: MiddlewareSetState<T>, get: MiddlewareGetState<T>, api: MiddlewareStoreApi<T>) => T;
2658
+ /**
2659
+ * Generic Middleware type.
2660
+ */
2661
+ type MiddlewareFn<T, Mps extends unknown[] = [], Mcs extends unknown[] = []> = (creator: StateCreatorFn<T, Mps, Mcs>) => StateCreatorFn<T, Mps, Mcs>;
2662
+ /**
2663
+ * Convert an @oxog/state store to middleware-compatible API.
2664
+ *
2665
+ * @param store - An @oxog/state store
2666
+ * @returns A middleware-compatible store API
2667
+ *
2668
+ * @example
2669
+ * ```typescript
2670
+ * import { createStore, toMiddlewareApi } from '@oxog/state';
2671
+ *
2672
+ * const store = createStore({ count: 0 });
2673
+ * const api = toMiddlewareApi(store);
2674
+ *
2675
+ * // Use middleware-style API
2676
+ * api.setState({ count: 1 });
2677
+ * api.setState((state) => ({ count: state.count + 1 }));
2678
+ * console.log(api.getState()); // { count: 2 }
2679
+ * ```
2680
+ */
2681
+ declare function toMiddlewareApi<T>(store: Store<T>): MiddlewareStoreApi<T>;
2682
+ /**
2683
+ * Wrap a middleware to work as an @oxog/state plugin.
2684
+ *
2685
+ * @param middleware - A middleware function
2686
+ * @param options - Optional middleware options
2687
+ * @returns An @oxog/state plugin
2688
+ *
2689
+ * @example
2690
+ * ```typescript
2691
+ * import { createStore, middlewareCompat } from '@oxog/state';
2692
+ *
2693
+ * // Use external middleware with @oxog/state
2694
+ * const store = createStore({ count: 0 })
2695
+ * .use(middlewareCompat(someMiddleware, { name: 'MyStore' }));
2696
+ * ```
2697
+ */
2698
+ declare function middlewareCompat<T>(middleware: MiddlewareFn<T>, options?: Record<string, unknown>): Plugin<T>;
2699
+ /**
2700
+ * Create a store using middleware-style state creator.
2701
+ *
2702
+ * @param creator - Middleware-style state creator function
2703
+ * @returns A store API
2704
+ *
2705
+ * @example
2706
+ * ```typescript
2707
+ * import { createWithMiddleware } from '@oxog/state';
2708
+ *
2709
+ * const store = createWithMiddleware((set, get) => ({
2710
+ * count: 0,
2711
+ * increment: () => set((state) => ({ count: state.count + 1 })),
2712
+ * decrement: () => set((state) => ({ count: state.count - 1 })),
2713
+ * reset: () => set({ count: 0 }),
2714
+ * getDoubled: () => get().count * 2,
2715
+ * }));
2716
+ *
2717
+ * store.getState().increment();
2718
+ * console.log(store.getState().count); // 1
2719
+ * ```
2720
+ */
2721
+ declare function createWithMiddleware<T extends object>(creator: StateCreatorFn<T>): MiddlewareStoreApi<T> & {
2722
+ use: <U>(plugin: Plugin<T>) => MiddlewareStoreApi<T>;
2723
+ };
2724
+ /**
2725
+ * Create a simple middleware.
2726
+ *
2727
+ * @param name - Middleware name
2728
+ * @param enhancer - Function that enhances the state creator
2729
+ * @returns A middleware function
2730
+ *
2731
+ * @example
2732
+ * ```typescript
2733
+ * const loggerMiddleware = createSimpleMiddleware('logger', (creator) => (set, get, api) => {
2734
+ * const loggedSet: typeof set = (partial, replace) => {
2735
+ * console.log('Before:', get());
2736
+ * set(partial, replace);
2737
+ * console.log('After:', get());
2738
+ * };
2739
+ * return creator(loggedSet, get, api);
2740
+ * });
2741
+ *
2742
+ * const store = createStore({ count: 0 })
2743
+ * .use(middlewareCompat(loggerMiddleware));
2744
+ * ```
2745
+ */
2746
+ declare function createSimpleMiddleware<T>(name: string, enhancer: (creator: StateCreatorFn<T>) => StateCreatorFn<T>): MiddlewareFn<T>;
2747
+ /**
2748
+ * Compose multiple middlewares.
2749
+ *
2750
+ * @param middlewares - Array of middlewares
2751
+ * @returns A single composed middleware
2752
+ *
2753
+ * @example
2754
+ * ```typescript
2755
+ * import { compose, middlewareCompat } from '@oxog/state';
2756
+ *
2757
+ * const composedMiddleware = compose(
2758
+ * loggerMiddleware,
2759
+ * devtoolsMiddleware,
2760
+ * persistMiddleware,
2761
+ * );
2762
+ *
2763
+ * const store = createStore({ count: 0 })
2764
+ * .use(middlewareCompat(composedMiddleware));
2765
+ * ```
2766
+ */
2767
+ declare function compose<T>(...middlewares: MiddlewareFn<T>[]): MiddlewareFn<T>;
2768
+ /**
2769
+ * Type helper for extracting state type from a store API.
2770
+ */
2771
+ type ExtractStateType<S> = S extends MiddlewareStoreApi<infer T> ? T : never;
2772
+ /**
2773
+ * Type helper for selector function.
2774
+ */
2775
+ type SelectorFn<T, U> = (state: T) => U;
2776
+ /**
2777
+ * Type helper for equality function.
2778
+ */
2779
+ type EqualityCheck<T> = (a: T, b: T) => boolean;
2780
+
2781
+ export { type Action, type Actions, type Computed, type ComputedOptions, type DeepPartial, type DevtoolsOptions, type EffectCleanup, type EffectDefinition, type EffectFn, type EffectUtils, type EffectsOptions, type EqualityCheck, type EqualityFn, type ExtractStateType, type FederatedState, type Federation, type FederationListener, type FederationOptions, type GetSlice, type HistoryOptions, type HistoryStore, type Listener, type LogLevel, type LoggerOptions, type MiddlewareFn, type MiddlewareGetState, type MiddlewareSetState, type MiddlewareStoreApi, type MiddlewareSubscribe, type MockStorage, type MockedAction, type PersistOptions, type Plugin, type Selector, type SelectorFn, type SelectorOptions, type SetSlice, type SliceCreator, type SliceDefinition, type StateAssertion, type StateChange, type StateCreatorFn, type StorageLike$1 as StorageLike, type Store, type StoreBuilder, StoreError, StoreError as StoreErrorClass, StoreErrorCode, type StoreOptions, type StoreSpy, type StoreState, type SubscribeOptions, type SyncOptions, type TestStore, type TestStoreOptions, type TransactionFn, type ValidateOptions, type ValidationAPI, type ValidationError, type ValidationResult, type ValidationTiming, type ValidatorFn, assertState, batch, combineComputed, combineEffects, combineSlices, combineValidators, compose, computed, createAsyncValidator, createDebouncedEffect, createEffect, createFederatedComputed, createFederatedSelector, createFederation, createFieldValidator, createLogger, createMockStorage, createNamespacedSlice, createSimpleEffect, createSimpleMiddleware, createSlice, createStorage, createStore, createSubscriber, createTestStore, createValidator, createWithMiddleware, deepClone, deepEqual, deepMerge, delay, devtools, effects, extendStore, flushMicrotasks, hasHistory, history, identity, immer, isFunction, logger, memoizeSelector, middlewareCompat, mockAction, omit, persist, pick, produce, resetSlices, selector, sessionStorage, shallowEqual, snapshot, spyOnStore, stateDiff, subscribeOnce, subscribeToMany, subscribeWithOptions, sync, toMiddlewareApi, triggerSync, useAction, useCreateStore, useSetState, useShallow, useStore, useStoreActions, useStoreSelector, useTransientSubscribe, validate, waitForFederated };