pocket-state 0.0.2

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/package.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "pocket-state",
3
+ "version": "0.0.2",
4
+ "description": "tiny global store",
5
+ "main": "src/index",
6
+ "codegenConfig": {
7
+ "name": "TinystoreSpec",
8
+ "type": "modules",
9
+ "jsSrcsDir": "src"
10
+ },
11
+ "author": " <@kayda69> (nhh.tcp@gmail.com)",
12
+ "license": "ISC",
13
+ "homepage": "#readme"
14
+ }
@@ -0,0 +1,81 @@
1
+ // event.ts
2
+ import {IEventEmitter, Listener} from './type';
3
+
4
+ export class EventEmitter implements IEventEmitter {
5
+ private events = new Map<string, Set<Listener<any>>>();
6
+ private onceWrappers = new Map<string, Map<Listener<any>, Listener<any>>>();
7
+
8
+ on<T>(event: string, listener: Listener<T>): void {
9
+ let set = this.events.get(event);
10
+ if (!set) {
11
+ set = new Set();
12
+ this.events.set(event, set);
13
+ }
14
+ set.add(listener as unknown as Listener<any>);
15
+ }
16
+
17
+ once<T>(event: string, listener: Listener<T>): void {
18
+ const wrapper: Listener<T> = payload => {
19
+ this.off(event, wrapper);
20
+ this.onceWrappers
21
+ .get(event)
22
+ ?.delete(listener as unknown as Listener<any>);
23
+ listener(payload);
24
+ };
25
+ if (!this.onceWrappers.has(event)) {
26
+ this.onceWrappers.set(event, new Map());
27
+ }
28
+ this.onceWrappers
29
+ .get(event)!
30
+ .set(
31
+ listener as unknown as Listener<any>,
32
+ wrapper as unknown as Listener<any>,
33
+ );
34
+ this.on(event, wrapper);
35
+ }
36
+
37
+ emit<T>(event: string, payload: T): void {
38
+ const listeners = this.events.get(event);
39
+ if (!listeners || listeners.size === 0) return;
40
+ for (const l of listeners) {
41
+ try {
42
+ l(payload);
43
+ } catch (error) {
44
+ console.warn(`Error in listener for '${event}':`, error);
45
+ }
46
+ }
47
+ }
48
+
49
+ off<T>(event: string, listener?: Listener<T>): void {
50
+ const set = this.events.get(event);
51
+ if (!set) return;
52
+
53
+ if (listener) {
54
+ const wrapped = this.onceWrappers
55
+ .get(event)
56
+ ?.get(listener as unknown as Listener<any>);
57
+ if (wrapped) {
58
+ set.delete(wrapped as unknown as Listener<any>);
59
+ this.onceWrappers
60
+ .get(event)!
61
+ .delete(listener as unknown as Listener<any>);
62
+ if (this.onceWrappers.get(event)!.size === 0) {
63
+ this.onceWrappers.delete(event);
64
+ }
65
+ } else {
66
+ set.delete(listener as unknown as Listener<any>);
67
+ }
68
+ if (set.size === 0) {
69
+ this.events.delete(event);
70
+ }
71
+ return;
72
+ }
73
+ this.events.delete(event);
74
+ this.onceWrappers.delete(event);
75
+ }
76
+
77
+ clear(): void {
78
+ this.events.clear();
79
+ this.onceWrappers.clear();
80
+ }
81
+ }
@@ -0,0 +1,26 @@
1
+ // useStore.ts
2
+ import {useCallback} from 'react';
3
+ import {useSyncExternalStore} from 'react';
4
+ import type {Store} from './type';
5
+
6
+ export function useStore<T>(store: Store<T>): T;
7
+ export function useStore<T, S>(store: Store<T>, selector: (state: T) => S): S;
8
+
9
+ export function useStore<T, S = T>(
10
+ store: Store<T>,
11
+ selector?: (state: T) => S,
12
+ ): T | S {
13
+ const subscribe = useCallback(
14
+ (onChange: () => void) =>
15
+ selector
16
+ ? store.subscribe(selector, () => onChange())
17
+ : store.subscribe(() => onChange()),
18
+ [store, selector],
19
+ );
20
+ const getSnapshot = useCallback(() => {
21
+ const s = store.getValue();
22
+ return selector ? selector(s) : (s as T);
23
+ }, [store, selector]);
24
+
25
+ return useSyncExternalStore(subscribe, getSnapshot, getSnapshot) as T | S;
26
+ }
@@ -0,0 +1,74 @@
1
+ const isIterable = (obj: object): obj is Iterable<unknown> =>
2
+ Symbol.iterator in obj;
3
+
4
+ const hasIterableEntries = (
5
+ value: Iterable<unknown>,
6
+ ): value is Iterable<unknown> & {
7
+ entries(): Iterable<[unknown, unknown]>;
8
+ } =>
9
+ // HACK: avoid checking entries type
10
+ 'entries' in value;
11
+
12
+ const compareEntries = (
13
+ valueA: {entries(): Iterable<[unknown, unknown]>},
14
+ valueB: {entries(): Iterable<[unknown, unknown]>},
15
+ ) => {
16
+ const mapA = valueA instanceof Map ? valueA : new Map(valueA.entries());
17
+ const mapB = valueB instanceof Map ? valueB : new Map(valueB.entries());
18
+ if (mapA.size !== mapB.size) {
19
+ return false;
20
+ }
21
+ for (const [key, value] of mapA) {
22
+ if (!Object.is(value, mapB.get(key))) {
23
+ return false;
24
+ }
25
+ }
26
+ return true;
27
+ };
28
+
29
+ // Ordered iterables
30
+ const compareIterables = (
31
+ valueA: Iterable<unknown>,
32
+ valueB: Iterable<unknown>,
33
+ ) => {
34
+ const iteratorA = valueA[Symbol.iterator]();
35
+ const iteratorB = valueB[Symbol.iterator]();
36
+ let nextA = iteratorA.next();
37
+ let nextB = iteratorB.next();
38
+ while (!nextA.done && !nextB.done) {
39
+ if (!Object.is(nextA.value, nextB.value)) {
40
+ return false;
41
+ }
42
+ nextA = iteratorA.next();
43
+ nextB = iteratorB.next();
44
+ }
45
+ return !!nextA.done && !!nextB.done;
46
+ };
47
+
48
+ export function shallow<T>(valueA: T, valueB: T): boolean {
49
+ if (Object.is(valueA, valueB)) {
50
+ return true;
51
+ }
52
+ if (
53
+ typeof valueA !== 'object' ||
54
+ valueA === null ||
55
+ typeof valueB !== 'object' ||
56
+ valueB === null
57
+ ) {
58
+ return false;
59
+ }
60
+ if (Object.getPrototypeOf(valueA) !== Object.getPrototypeOf(valueB)) {
61
+ return false;
62
+ }
63
+ if (isIterable(valueA) && isIterable(valueB)) {
64
+ if (hasIterableEntries(valueA) && hasIterableEntries(valueB)) {
65
+ return compareEntries(valueA, valueB);
66
+ }
67
+ return compareIterables(valueA, valueB);
68
+ }
69
+ // assume plain objects
70
+ return compareEntries(
71
+ {entries: () => Object.entries(valueA)},
72
+ {entries: () => Object.entries(valueB)},
73
+ );
74
+ }
@@ -0,0 +1,198 @@
1
+ // store.ts
2
+ // import deepEqual from 'fast-deep-equal';
3
+ import {IEventEmitter, Listener, Middleware, Store, UseStoreGet} from './type';
4
+ import {EventEmitter} from './event';
5
+ import {Draft, produce} from 'immer';
6
+ // import {shallow} from './shallowEqual';
7
+ import deepEqual from 'fast-deep-equal';
8
+ export function createStore<T>(
9
+ initialState: T,
10
+ middlewares: Middleware<T>[] = [],
11
+ ): Store<T> {
12
+ const emitter: IEventEmitter = new EventEmitter();
13
+ let state = initialState;
14
+
15
+ // Coalesce emits trong cùng 1 microtask
16
+ let emitScheduled = false;
17
+ const emitState = () => {
18
+ if (emitScheduled) return;
19
+ emitScheduled = true;
20
+ queueMicrotask(() => {
21
+ emitScheduled = false;
22
+ emitter.emit('state', state);
23
+ });
24
+ };
25
+
26
+ function baseSet(delta: Partial<T>) {
27
+ const nextState = Array.isArray(state)
28
+ ? (delta as unknown as T) // với array: replace
29
+ : {...state, ...delta}; // với object: shallow merge
30
+
31
+ if (!deepEqual(state, nextState)) {
32
+ state = nextState;
33
+
34
+ // Dev guard: phát hiện mutate ngoài store
35
+ if (process.env.NODE_ENV !== 'production') {
36
+ try {
37
+ Object.freeze(state as any);
38
+ } catch {}
39
+ }
40
+
41
+ emitState();
42
+ }
43
+ }
44
+
45
+ const setFn = middlewares.reduceRight(
46
+ (next, mw) => mw(next, () => state),
47
+ baseSet as (patch: Partial<T>) => void,
48
+ );
49
+
50
+ const getValue = ((key?: keyof T | (keyof T)[]) => {
51
+ if (key === undefined) return state;
52
+ if (Array.isArray(key)) {
53
+ const out = {} as Pick<T, (typeof key)[number]>;
54
+ for (const k of key) (out as any)[k] = (state as any)[k];
55
+ return out;
56
+ }
57
+ return (state as any)[key];
58
+ }) as UseStoreGet<T>;
59
+
60
+ function subscribe(selectorOrListener: any, maybeListener?: any) {
61
+ let wrapped: Listener<any>;
62
+
63
+ if (typeof maybeListener === 'function') {
64
+ // subscribe(selector, listener)
65
+ const selector: (s: T) => any = selectorOrListener;
66
+ let prevSlice = selector(state);
67
+ wrapped = (next: T) => {
68
+ const slice = selector(next);
69
+ if (!deepEqual(slice, prevSlice)) {
70
+ prevSlice = slice;
71
+ maybeListener(slice);
72
+ }
73
+ };
74
+ } else {
75
+ // subscribe(listener)
76
+ const listener: Listener<T> = selectorOrListener;
77
+ let prev = state;
78
+ wrapped = (next: T) => {
79
+ if (!deepEqual(next, prev)) {
80
+ prev = next;
81
+ listener(next);
82
+ }
83
+ };
84
+ }
85
+
86
+ emitter.on('state', wrapped);
87
+
88
+ // Lưu ý: KHÔNG gọi listener ngay khi subscribe
89
+ // (để tương thích useSyncExternalStore: initial snapshot lấy qua getSnapshot)
90
+
91
+ return () => emitter.off('state', wrapped);
92
+ }
93
+
94
+ function setValue(
95
+ patch: Partial<T> | ((state: T) => Partial<T> | Promise<Partial<T>>),
96
+ ): void {
97
+ (async () => {
98
+ try {
99
+ const resolved =
100
+ typeof patch === 'function' ? await (patch as any)(state) : patch;
101
+
102
+ if (resolved && typeof resolved === 'object') {
103
+ setFn(resolved as Partial<T>);
104
+ }
105
+ } catch (error) {
106
+ console.warn('[store.setValue] patch error:', error);
107
+ }
108
+ })();
109
+ }
110
+
111
+ function setImmer(updater: (draft: Draft<T>) => void): void {
112
+ try {
113
+ const nextState = produce(state, updater);
114
+ if (deepEqual(state, nextState)) return;
115
+
116
+ if (Array.isArray(state)) {
117
+ setFn(nextState as unknown as Partial<T>);
118
+ return;
119
+ }
120
+ const delta = {} as Partial<T>;
121
+ let changed = false;
122
+ for (const k in nextState as any) {
123
+ const nv = (nextState as any)[k];
124
+ const ov = (state as any)[k];
125
+ if (nv !== ov) {
126
+ (delta as any)[k] = nv;
127
+ changed = true;
128
+ }
129
+ }
130
+ for (const k in state as any) {
131
+ if (!(k in (nextState as any))) {
132
+ (delta as any)[k] = undefined;
133
+ changed = true;
134
+ }
135
+ }
136
+ if (changed) setFn(delta);
137
+ } catch (e) {
138
+ console.warn('[store.setImmer] error:', e);
139
+ }
140
+ }
141
+
142
+ function reset(): void;
143
+ function reset(initialValue?: T | Partial<T>): void;
144
+ function reset(initialValue?: T | Partial<T>) {
145
+ const isObj = (
146
+ v: unknown,
147
+ ): v is Record<string | symbol | number, unknown> =>
148
+ typeof v === 'object' && v !== null;
149
+
150
+ const cloneShallow = <U>(src: U): U => {
151
+ if (Array.isArray(src)) return (src as any).slice();
152
+ if (isObj(src)) return {...(src as any)} as U;
153
+ return src;
154
+ };
155
+
156
+ let next = cloneShallow(initialState) as T;
157
+ if (initialValue !== undefined) {
158
+ if (Array.isArray(initialValue)) {
159
+ next = (initialValue as any).slice();
160
+ } else if (isObj(initialValue)) {
161
+ Object.assign(next as any, initialValue);
162
+ } else {
163
+ const current = getValue();
164
+ if (!Object.is(current as any, initialValue as any)) {
165
+ setFn(initialValue as unknown as Partial<T>);
166
+ }
167
+ return;
168
+ }
169
+ }
170
+ const current = getValue();
171
+ if (!deepEqual(current, next)) {
172
+ setFn(next as unknown as Partial<T>);
173
+ }
174
+ }
175
+
176
+ function getInitialValue(): T {
177
+ if (Array.isArray(state)) {
178
+ return (state as any).slice();
179
+ }
180
+ if (state && typeof state === 'object') {
181
+ return {...(state as any)};
182
+ }
183
+ return state;
184
+ }
185
+
186
+ function isDirty() {
187
+ return !deepEqual(state, initialState);
188
+ }
189
+ return {
190
+ getValue,
191
+ getInitialValue,
192
+ setValue,
193
+ setImmer,
194
+ reset,
195
+ subscribe,
196
+ isDirty,
197
+ };
198
+ }
@@ -0,0 +1,58 @@
1
+ // ---- Path utilities (zero-deps, RHF-like) ----
2
+ type Primitive =
3
+ | string
4
+ | number
5
+ | boolean
6
+ | bigint
7
+ | symbol
8
+ | null
9
+ | undefined
10
+ | Date
11
+ | RegExp
12
+ | Function;
13
+
14
+ type IsTuple<A extends readonly unknown[]> = number extends A['length']
15
+ ? false
16
+ : true;
17
+
18
+ type IndexKeys<T> = Extract<keyof T, string>;
19
+
20
+ /** All dot/bracket-style paths into T (e.g. "user.name", "items.0.qty") */
21
+ export type Path<T> = T extends Primitive
22
+ ? never
23
+ : T extends readonly (infer V)[]
24
+ ? IsTuple<T> extends true
25
+ ? {
26
+ [I in Extract<keyof T, `${number}`>]: `${I}` | `${I}.${Path<V>}`;
27
+ }[Extract<keyof T, `${number}`>]
28
+ : `${number}` | `${number}.${Path<V>}`
29
+ : {
30
+ [K in IndexKeys<T>]: T[K] extends Primitive
31
+ ? `${K}`
32
+ : `${K}` | `${K}.${Path<T[K]>}`;
33
+ }[IndexKeys<T>];
34
+
35
+ /** Value type at path P */
36
+ export type PathValue<
37
+ T,
38
+ P extends string,
39
+ > = P extends `${infer K}.${infer Rest}`
40
+ ? K extends keyof T
41
+ ? PathValue<T[K], Rest>
42
+ : K extends `${number}`
43
+ ? T extends readonly (infer V)[]
44
+ ? PathValue<V, Rest>
45
+ : never
46
+ : never
47
+ : P extends keyof T
48
+ ? T[P]
49
+ : P extends `${number}`
50
+ ? T extends readonly (infer V)[]
51
+ ? V
52
+ : never
53
+ : never;
54
+
55
+ /** Tuple of values for a tuple of paths */
56
+ export type PathValues<T, PS extends readonly string[]> = {
57
+ [I in keyof PS]: PS[I] extends string ? PathValue<T, PS[I]> : never;
58
+ };
@@ -0,0 +1,219 @@
1
+ import {Draft} from 'immer';
2
+
3
+ /**
4
+ * A callback invoked when an event is emitted with a payload of type `T`.
5
+ * Keep listeners pure and fast. Long-running side effects should live in
6
+ * middleware/effects instead of listeners.
7
+ */
8
+ export interface Listener<T = any> {
9
+ (payload: T): void;
10
+ }
11
+
12
+ /**
13
+ * Immer-style mutation function used for "mutable-looking" updates.
14
+ *
15
+ * - Receives a `draft` (a Proxy of your state).
16
+ * - You can mutate the draft; Immer will produce the next immutable state.
17
+ * - You may return a new value instead of mutating the draft (less common).
18
+ * - Can be async, but it's recommended to await first, then mutate, to avoid races.
19
+ */
20
+ export type MutateFn<T> = (draft: Draft<T>) => void | T | Promise<void | T>;
21
+
22
+ /**
23
+ * Store getter API.
24
+ *
25
+ * Usage:
26
+ * ```ts
27
+ * const all = getValues(); // → T (entire state)
28
+ * const count = getValues('count'); // → T['count'] (one key)
29
+ * ```
30
+ *
31
+ * Notes:
32
+ * - Results are expected to be reference-stable when state hasn't changed,
33
+ * which helps React avoid unnecessary renders.
34
+ * - If you want to support reading multiple keys at once, extend the type.
35
+ */
36
+ export type UseStoreGet<T> = {
37
+ (): T;
38
+ <K extends keyof T>(key: K): T[K];
39
+ };
40
+ /**
41
+ * Store setter API:
42
+ * - Accepts a `patch` (partial) to shallow-merge into current state,
43
+ * or a function that receives the current state and returns a partial.
44
+ * The function may be async.
45
+ *
46
+ * Examples:
47
+ * ```ts
48
+ * setValue({ flag: true });
49
+ * setValue(s => ({ count: s.count + 1 }));
50
+ * setValue(async s => {
51
+ * const user = await fetchUser();
52
+ * return { user };
53
+ * });
54
+ * ```
55
+ *
56
+ * Notes:
57
+ * - The store is responsible for equality checks and only emits on real changes.
58
+ * - Multiple updates in the same tick may be coalesced (implementation-dependent).
59
+ *
60
+ * `immer()` (if implemented) is a convenience to enable Immer-style updates.
61
+ * This type does not define its runtime behavior; see your implementation.
62
+ */
63
+ export type UseStoreSet<T> = {
64
+ (patch: Partial<T> | ((state: T) => Partial<T> | Promise<Partial<T>>)): void;
65
+ immer(): void;
66
+ };
67
+
68
+ /**
69
+ * Minimal pub/sub event emitter contract.
70
+ *
71
+ * Expected behavior:
72
+ * - `on` registers a listener for an event name.
73
+ * - `emit` broadcasts a payload to all listeners of that event.
74
+ * - `off` removes a specific listener or all listeners for an event.
75
+ * - `once` registers a listener that runs exactly once, then unregisters itself.
76
+ * - `clear` removes listeners for all events.
77
+ *
78
+ * Implementation guidance:
79
+ * - Snapshot listeners before emitting to stay safe if `on/off` happens during emit.
80
+ * - `off(event, original)` should remove a `once` listener even if it's wrapped.
81
+ */
82
+ export interface IEventEmitter {
83
+ /** Register a listener for an event name. */
84
+ on<T = any>(event: string, listener: Listener<T>): void;
85
+
86
+ /** Emit an event with a payload. */
87
+ emit<T = any>(event: string, payload: T): void;
88
+
89
+ /**
90
+ * Remove a listener or all listeners for an event.
91
+ * Omit `listener` to remove all listeners for the event.
92
+ */
93
+ off<T = any>(event: string, listener?: Listener<T>): void;
94
+
95
+ /** Register a one-time listener that auto-unregisters after the first emit. */
96
+ once<T>(event: string, listener: Listener<T>): void;
97
+
98
+ /** Remove all listeners for all events. */
99
+ clear(): void;
100
+ }
101
+
102
+ /**
103
+ * Reactive key-value store interface.
104
+ * Supports:
105
+ * - Reading current state (`getValues`)
106
+ * - Updating via partials or functions (`setValue`)
107
+ * - Immer-style updates (`setImmer`) when available
108
+ * - Reset to the initial value (`reset`)
109
+ * - Subscribing to the whole state or to a slice via a selector
110
+ *
111
+ * Important notes:
112
+ * - Listeners are called only when the relevant data actually changes.
113
+ * - `subscribe` returns an unsubscribe function — call it on unmount to avoid leaks.
114
+ * - `subscribe` does **not** auto-invoke the listener initially (fits `useSyncExternalStore`);
115
+ * if you need an initial call, read the snapshot and invoke it yourself at the call site.
116
+ */
117
+ export interface Store<T> {
118
+ /**
119
+ * Read the full state or a specific property by key.
120
+ * @param key Optional key within the state.
121
+ * @returns Without `key` → the full state `T`.
122
+ * With `key` → the value `T[K]`.
123
+ */
124
+ getValue: UseStoreGet<T>;
125
+
126
+ /**
127
+ * Update state by shallow-merging `patch`, or by running a function
128
+ * that returns a `patch`. The function may be async.
129
+ */
130
+ setValue(
131
+ patch: Partial<T> | ((state: T) => Partial<T> | Promise<Partial<T>>),
132
+ ): void;
133
+
134
+ /**
135
+ * Returns the store's initial state value.
136
+ *
137
+ * - For arrays and objects → returns a shallow clone to avoid external mutations.
138
+ * - For primitive types → returns the value as-is.
139
+ * - The returned value represents the original initial state, not the current state.
140
+ */
141
+ getInitialValue(): T;
142
+
143
+ /**
144
+ * Update state in Immer style.
145
+ * @example
146
+ * ```ts
147
+ * store.setImmer(draft => {
148
+ * draft.user.name = 'Hiep';
149
+ * draft.items.push({ id: 'x' });
150
+ * });
151
+ * ```
152
+ */
153
+ setImmer(updater: (draft: Draft<T>) => void): void;
154
+
155
+ /**
156
+ * Resets the state to the initial value (`initialState`) with a new reference (shallow clone).
157
+ *
158
+ * - If no argument is provided → the state is reset to `initialState` (new reference).
159
+ * - If `initialValue` is provided:
160
+ * - If it's an object/array → shallow-merge it into a clone of `initialState`.
161
+ * - If it's a primitive → replace the state entirely with that value.
162
+ * - Always creates a new reference; only updates if the result is not shallow-equal to the current state.
163
+ */
164
+ reset(initialValue?: T | Partial<T>): void;
165
+
166
+ /**
167
+ * Subscribe to the entire state.
168
+ * The listener is invoked **after commit** whenever state changes.
169
+ * @returns Unsubscribe function.
170
+ */
171
+ subscribe(listener: Listener<T>): () => void;
172
+
173
+ /**
174
+ * Subscribe to a derived slice of the state.
175
+ * The listener fires only when the selector's result changes.
176
+ * @returns Unsubscribe function.
177
+ */
178
+ subscribe<S>(selector: (state: T) => S, listener: Listener<S>): () => void;
179
+
180
+ /**
181
+ * Checks whether the current state differs from the initial state.
182
+ *
183
+ * - For primitive types → compared using strict equality (`===`).
184
+ * - For objects/arrays → compared using deep equality.
185
+ * - Returns `true` if the state is modified, otherwise `false`.
186
+ *
187
+ * @example
188
+ * ```ts
189
+ * const store = createStore({ count: 0 });
190
+ * store.isDirty(); // false
191
+ *
192
+ * store.setValue({ count: 1 });
193
+ * store.isDirty(); // true
194
+ * ```
195
+ */
196
+ isDirty(): boolean;
197
+ }
198
+
199
+ /**
200
+ * Middleware that intercepts and transforms a `patch` before it is applied.
201
+ *
202
+ * Contract:
203
+ * - Must call `next(patch)` to forward the update (similar to Redux middleware).
204
+ * - Can read the current state via `getState()`.
205
+ * - Useful for logging, validation, mapping, batching, devtools bridges, persistence, etc.
206
+ *
207
+ * @example Logging middleware:
208
+ * ```ts
209
+ * const logger: Middleware<State> = (next, get) => patch => {
210
+ * console.log('Before:', get());
211
+ * next(patch);
212
+ * console.log('After:', get());
213
+ * };
214
+ * ```
215
+ */
216
+ export type Middleware<T> = (
217
+ next: (patch: Partial<T>) => void,
218
+ getState: () => T,
219
+ ) => (patch: Partial<T>) => void;
package/src/index.tsx ADDED
@@ -0,0 +1,22 @@
1
+ import {createStore} from './globalState/store';
2
+ import {useStore} from './globalState/hooks';
3
+ import type {
4
+ IEventEmitter,
5
+ Listener,
6
+ Middleware,
7
+ MutateFn,
8
+ UseStoreGet,
9
+ UseStoreSet,
10
+ Store,
11
+ } from './globalState/type';
12
+
13
+ export {createStore, useStore};
14
+ export type {
15
+ IEventEmitter,
16
+ Listener,
17
+ Middleware,
18
+ MutateFn,
19
+ UseStoreGet,
20
+ UseStoreSet,
21
+ Store,
22
+ };