dharma-core 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1 +1,32 @@
1
- # Dharma Core
1
+ # dharma-core
2
+
3
+ [![Version](https://img.shields.io/npm/v/dharma-core)](https://npmjs.com/package/dharma-core)
4
+ [![Downloads](https://img.shields.io/npm/dm/dharma-core.svg)](https://npmjs.com/package/dharma-core)
5
+ [![Minzipped size](https://img.shields.io/bundlephobia/minzip/dharma-core)](https://bundlephobia.com/package/dharma-core)
6
+
7
+ A simple and lightweight state management solution for JavaScript and TypeScript applications.
8
+
9
+ ## Basic usage
10
+
11
+ ```ts
12
+ import { createStore } from "dharma-core";
13
+
14
+ const store = createStore({
15
+ initialState: { count: 0 },
16
+ defineActions: ({ set }) => ({
17
+ increment: () => set((state) => ({ count: state.count + 1 })),
18
+ decrement: () => set((state) => ({ count: state.count - 1 })),
19
+ }),
20
+ });
21
+
22
+ const { increment, decrement } = store.actions;
23
+
24
+ // Subscribe to state changes
25
+ const unsubscribe = store.subscribe((state) => console.log(state.count));
26
+ // Update the state
27
+ increment();
28
+ // { count: 1 }
29
+ decrement();
30
+ // { count: 0 }
31
+ unsubscribe();
32
+ ```
@@ -10,8 +10,8 @@ export type Serializer<T = any> = {
10
10
  };
11
11
  export type PersistentStoreConfiguration<TState extends object, TActions extends object> = StoreConfiguration<TState, TActions> & {
12
12
  key: string;
13
- /** The storage to use for persisting the state. Defaults to local storage. */
14
- storage?: StorageAPI | "local" | "session";
13
+ /** The storage to use for persisting the state. Defaults to local storage if available. */
14
+ storage?: StorageAPI;
15
15
  /** The serializer to use for storing the state. Defaults to JSON. */
16
16
  serializer?: Serializer<TState>;
17
17
  };
@@ -22,10 +22,7 @@ export type PersistentStoreConfiguration<TState extends object, TActions extends
22
22
  * **Note:** The state needs to be serializable by whatever serializer you use. (JSON by default)
23
23
  * If you need something more versatile I would recommend using a library like [superjson](https://github.com/flightcontrolhq/superjson).
24
24
  *
25
- * @param {string} key - A unique key to identify the store in storage.
26
- * @param {TState} initialState - The initial state of the store.
27
- * @param {DefineActions<TState, TActions>} [defineActions] - A function to define actions for the store.
28
- * @param {PersistentStoreConfiguration<TState>} [options] - Additional options for the persistent store.
25
+ * @param {PersistentStoreConfiguration<TState, TActions>} config - The configuration for the persistent store.
29
26
  *
30
27
  * @returns {Store<TState, TActions>} The created store.
31
28
  *
@@ -34,11 +31,15 @@ export type PersistentStoreConfiguration<TState extends object, TActions extends
34
31
  * ```ts
35
32
  * import { createPersistentStore } from "dharma-core";
36
33
  *
37
- * const store = createPersistentStore("count", { count: 0 }, ({ set }) => ({
38
- * increment: () => set((state) => ({ count: state.count + 1 })),
39
- * decrement: () => set((state) => ({ count: state.count - 1 })),
40
- * reset: () => set({ count: 0 }),
41
- * }));
34
+ * const store = createPersistentStore({
35
+ * key: "count",
36
+ * initialState: { count: 0 },
37
+ * defineActions: ({ set }) => ({
38
+ * increment: () => set((state) => ({ count: state.count + 1 })),
39
+ * decrement: () => set((state) => ({ count: state.count - 1 })),
40
+ * reset: () => set({ count: 0 }),
41
+ * }),
42
+ * });
42
43
  * ```
43
44
  * @example
44
45
  * With superjson serialization and session storage:
@@ -46,19 +47,17 @@ export type PersistentStoreConfiguration<TState extends object, TActions extends
46
47
  * import { createPersistentStore } from "dharma-core";
47
48
  * import superjson from "superjson";
48
49
  *
49
- * const store = createPersistentStore(
50
- * "count",
51
- * { count: 0 },
52
- * ({ set }) => ({
50
+ * const store = createPersistentStore({
51
+ * key: "count",
52
+ * initialState: { count: 0 },
53
+ * defineActions: ({ set }) => ({
53
54
  * increment: () => set((state) => ({ count: state.count + 1 })),
54
55
  * decrement: () => set((state) => ({ count: state.count - 1 })),
55
56
  * reset: () => set({ count: 0 }),
56
57
  * }),
57
- * {
58
- * serializer: superjson,
59
- * storage: "session",
60
- * },
61
- * );
58
+ * serializer: superjson,
59
+ * storage: sessionStorage,
60
+ * });
62
61
  * ```
63
62
  */
64
- export declare const createPersistentStore: <TState extends object, TActions extends object = Record<never, never>>(options: PersistentStoreConfiguration<TState, TActions>) => Store<TState, TActions>;
63
+ export declare const createPersistentStore: <TState extends object, TActions extends object = Record<never, never>>(config: PersistentStoreConfiguration<TState, TActions>) => Store<TState, TActions>;
@@ -9,10 +9,7 @@ var createStore = require('./createStore.js');
9
9
  * **Note:** The state needs to be serializable by whatever serializer you use. (JSON by default)
10
10
  * If you need something more versatile I would recommend using a library like [superjson](https://github.com/flightcontrolhq/superjson).
11
11
  *
12
- * @param {string} key - A unique key to identify the store in storage.
13
- * @param {TState} initialState - The initial state of the store.
14
- * @param {DefineActions<TState, TActions>} [defineActions] - A function to define actions for the store.
15
- * @param {PersistentStoreConfiguration<TState>} [options] - Additional options for the persistent store.
12
+ * @param {PersistentStoreConfiguration<TState, TActions>} config - The configuration for the persistent store.
16
13
  *
17
14
  * @returns {Store<TState, TActions>} The created store.
18
15
  *
@@ -21,11 +18,15 @@ var createStore = require('./createStore.js');
21
18
  * ```ts
22
19
  * import { createPersistentStore } from "dharma-core";
23
20
  *
24
- * const store = createPersistentStore("count", { count: 0 }, ({ set }) => ({
25
- * increment: () => set((state) => ({ count: state.count + 1 })),
26
- * decrement: () => set((state) => ({ count: state.count - 1 })),
27
- * reset: () => set({ count: 0 }),
28
- * }));
21
+ * const store = createPersistentStore({
22
+ * key: "count",
23
+ * initialState: { count: 0 },
24
+ * defineActions: ({ set }) => ({
25
+ * increment: () => set((state) => ({ count: state.count + 1 })),
26
+ * decrement: () => set((state) => ({ count: state.count - 1 })),
27
+ * reset: () => set({ count: 0 }),
28
+ * }),
29
+ * });
29
30
  * ```
30
31
  * @example
31
32
  * With superjson serialization and session storage:
@@ -33,44 +34,42 @@ var createStore = require('./createStore.js');
33
34
  * import { createPersistentStore } from "dharma-core";
34
35
  * import superjson from "superjson";
35
36
  *
36
- * const store = createPersistentStore(
37
- * "count",
38
- * { count: 0 },
39
- * ({ set }) => ({
37
+ * const store = createPersistentStore({
38
+ * key: "count",
39
+ * initialState: { count: 0 },
40
+ * defineActions: ({ set }) => ({
40
41
  * increment: () => set((state) => ({ count: state.count + 1 })),
41
42
  * decrement: () => set((state) => ({ count: state.count - 1 })),
42
43
  * reset: () => set({ count: 0 }),
43
44
  * }),
44
- * {
45
- * serializer: superjson,
46
- * storage: "session",
47
- * },
48
- * );
45
+ * serializer: superjson,
46
+ * storage: sessionStorage,
47
+ * });
49
48
  * ```
50
49
  */
51
- const createPersistentStore = (options) => {
52
- if (typeof window === "undefined") {
53
- return createStore.createStore(options);
50
+ const createPersistentStore = (config) => {
51
+ const { key, initialState, storage: customStorage, serializer = JSON, onAttach, onDetach, onChange, ...rest } = config;
52
+ const IS_BROWSER = typeof window !== "undefined";
53
+ const storage = customStorage ?? (IS_BROWSER ? localStorage : undefined);
54
+ if (!storage) {
55
+ return createStore.createStore(config);
54
56
  }
55
- const { key, initialState, storage: _storage = "local", serializer = JSON, onAttach, onDetach, onChange, ...rest } = options;
56
- const storage = getStorage(_storage);
57
- const stateKey = `store_${key}`;
58
57
  const initialStateKey = `init_${key}`;
59
58
  const initialStateSnapshot = storage.getItem(initialStateKey);
60
59
  const initialStateString = serializer.stringify(initialState);
61
60
  if (initialStateSnapshot !== initialStateString) {
62
61
  storage.setItem(initialStateKey, initialStateString);
63
- storage.removeItem(stateKey);
62
+ storage.removeItem(key);
64
63
  }
65
64
  const updateSnapshot = (newState) => {
66
- const currentSnapshot = storage.getItem(stateKey);
65
+ const currentSnapshot = storage.getItem(key);
67
66
  const newSnapshot = serializer.stringify(newState);
68
67
  if (newSnapshot !== currentSnapshot) {
69
- storage.setItem(stateKey, newSnapshot);
68
+ storage.setItem(key, newSnapshot);
70
69
  }
71
70
  };
72
71
  const updateState = () => {
73
- const currentSnapshot = storage.getItem(stateKey);
72
+ const currentSnapshot = storage.getItem(key);
74
73
  if (currentSnapshot &&
75
74
  currentSnapshot !== serializer.stringify(store.get())) {
76
75
  store.set(serializer.parse(currentSnapshot));
@@ -81,11 +80,15 @@ const createPersistentStore = (options) => {
81
80
  onAttach: (ctx) => {
82
81
  onAttach?.(ctx);
83
82
  updateState();
84
- window.addEventListener("focus", updateState);
83
+ if (IS_BROWSER) {
84
+ window.addEventListener("focus", updateState);
85
+ }
85
86
  },
86
87
  onDetach: (ctx) => {
87
88
  onDetach?.(ctx);
88
- window.removeEventListener("focus", updateState);
89
+ if (IS_BROWSER) {
90
+ window.removeEventListener("focus", updateState);
91
+ }
89
92
  },
90
93
  onChange: ({ state, ...ctx }) => {
91
94
  onChange?.({ state, ...ctx });
@@ -95,16 +98,6 @@ const createPersistentStore = (options) => {
95
98
  });
96
99
  return store;
97
100
  };
98
- const getStorage = (storage) => {
99
- switch (storage) {
100
- case "local":
101
- return localStorage;
102
- case "session":
103
- return sessionStorage;
104
- default:
105
- return storage;
106
- }
107
- };
108
101
 
109
102
  exports.createPersistentStore = createPersistentStore;
110
103
  //# sourceMappingURL=createPersistentStore.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"createPersistentStore.js","sources":["../../../src/lib/createPersistentStore.ts"],"sourcesContent":["import { createStore, Store, StoreConfiguration } from \"./createStore\";\n\nexport type StorageAPI = {\n getItem: (key: string) => string | null;\n setItem: (key: string, value: string) => void;\n removeItem: (key: string) => void;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type Serializer<T = any> = {\n stringify: (value: T) => string;\n parse: (value: string) => T;\n};\n\nexport type PersistentStoreConfiguration<\n TState extends object,\n TActions extends object,\n> = StoreConfiguration<TState, TActions> & {\n key: string;\n /** The storage to use for persisting the state. Defaults to local storage. */\n storage?: StorageAPI | \"local\" | \"session\";\n /** The serializer to use for storing the state. Defaults to JSON. */\n serializer?: Serializer<TState>;\n};\n\n/**\n * Creates a store that persists its state in local or session storage.\n * Defaults to local storage but this can be changed in the options.\n *\n * **Note:** The state needs to be serializable by whatever serializer you use. (JSON by default)\n * If you need something more versatile I would recommend using a library like [superjson](https://github.com/flightcontrolhq/superjson).\n *\n * @param {string} key - A unique key to identify the store in storage.\n * @param {TState} initialState - The initial state of the store.\n * @param {DefineActions<TState, TActions>} [defineActions] - A function to define actions for the store.\n * @param {PersistentStoreConfiguration<TState>} [options] - Additional options for the persistent store.\n *\n * @returns {Store<TState, TActions>} The created store.\n *\n * @example\n * Basic usage:\n * ```ts\n * import { createPersistentStore } from \"dharma-core\";\n *\n * const store = createPersistentStore(\"count\", { count: 0 }, ({ set }) => ({\n * increment: () => set((state) => ({ count: state.count + 1 })),\n * decrement: () => set((state) => ({ count: state.count - 1 })),\n * reset: () => set({ count: 0 }),\n * }));\n * ```\n * @example\n * With superjson serialization and session storage:\n * ```ts\n * import { createPersistentStore } from \"dharma-core\";\n * import superjson from \"superjson\";\n *\n * const store = createPersistentStore(\n * \"count\",\n * { count: 0 },\n * ({ set }) => ({\n * increment: () => set((state) => ({ count: state.count + 1 })),\n * decrement: () => set((state) => ({ count: state.count - 1 })),\n * reset: () => set({ count: 0 }),\n * }),\n * {\n * serializer: superjson,\n * storage: \"session\",\n * },\n * );\n * ```\n */\nexport const createPersistentStore = <\n TState extends object,\n TActions extends object = Record<never, never>,\n>(\n options: PersistentStoreConfiguration<TState, TActions>,\n): Store<TState, TActions> => {\n if (typeof window === \"undefined\") {\n return createStore(options);\n }\n\n const {\n key,\n initialState,\n storage: _storage = \"local\",\n serializer = JSON,\n onAttach,\n onDetach,\n onChange,\n ...rest\n } = options;\n\n const storage = getStorage(_storage);\n const stateKey = `store_${key}`;\n const initialStateKey = `init_${key}`;\n const initialStateSnapshot = storage.getItem(initialStateKey);\n const initialStateString = serializer.stringify(initialState);\n\n if (initialStateSnapshot !== initialStateString) {\n storage.setItem(initialStateKey, initialStateString);\n storage.removeItem(stateKey);\n }\n\n const updateSnapshot = (newState: TState) => {\n const currentSnapshot = storage.getItem(stateKey);\n const newSnapshot = serializer.stringify(newState);\n\n if (newSnapshot !== currentSnapshot) {\n storage.setItem(stateKey, newSnapshot);\n }\n };\n\n const updateState = () => {\n const currentSnapshot = storage.getItem(stateKey);\n\n if (\n currentSnapshot &&\n currentSnapshot !== serializer.stringify(store.get())\n ) {\n store.set(serializer.parse(currentSnapshot));\n }\n };\n\n const store = createStore({\n initialState,\n onAttach: (ctx) => {\n onAttach?.(ctx);\n updateState();\n window.addEventListener(\"focus\", updateState);\n },\n onDetach: (ctx) => {\n onDetach?.(ctx);\n window.removeEventListener(\"focus\", updateState);\n },\n onChange: ({ state, ...ctx }) => {\n onChange?.({ state, ...ctx });\n updateSnapshot(state);\n },\n ...rest,\n });\n\n return store;\n};\n\nconst getStorage = (storage: StorageAPI | \"local\" | \"session\"): StorageAPI => {\n switch (storage) {\n case \"local\":\n return localStorage;\n case \"session\":\n return sessionStorage;\n default:\n return storage;\n }\n};\n"],"names":["createStore"],"mappings":";;;;AAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CG;AACI,MAAM,qBAAqB,GAAG,CAInC,OAAuD,KAC5B;AAC3B,IAAA,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;AACjC,QAAA,OAAOA,uBAAW,CAAC,OAAO,CAAC;IAC7B;IAEA,MAAM,EACJ,GAAG,EACH,YAAY,EACZ,OAAO,EAAE,QAAQ,GAAG,OAAO,EAC3B,UAAU,GAAG,IAAI,EACjB,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,GAAG,IAAI,EACR,GAAG,OAAO;AAEX,IAAA,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC;AACpC,IAAA,MAAM,QAAQ,GAAG,CAAA,MAAA,EAAS,GAAG,EAAE;AAC/B,IAAA,MAAM,eAAe,GAAG,CAAA,KAAA,EAAQ,GAAG,EAAE;IACrC,MAAM,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC;IAC7D,MAAM,kBAAkB,GAAG,UAAU,CAAC,SAAS,CAAC,YAAY,CAAC;AAE7D,IAAA,IAAI,oBAAoB,KAAK,kBAAkB,EAAE;AAC/C,QAAA,OAAO,CAAC,OAAO,CAAC,eAAe,EAAE,kBAAkB,CAAC;AACpD,QAAA,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC;IAC9B;AAEA,IAAA,MAAM,cAAc,GAAG,CAAC,QAAgB,KAAI;QAC1C,MAAM,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;QACjD,MAAM,WAAW,GAAG,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC;AAElD,QAAA,IAAI,WAAW,KAAK,eAAe,EAAE;AACnC,YAAA,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,WAAW,CAAC;QACxC;AACF,IAAA,CAAC;IAED,MAAM,WAAW,GAAG,MAAK;QACvB,MAAM,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;AAEjD,QAAA,IACE,eAAe;YACf,eAAe,KAAK,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EACrD;YACA,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QAC9C;AACF,IAAA,CAAC;IAED,MAAM,KAAK,GAAGA,uBAAW,CAAC;QACxB,YAAY;AACZ,QAAA,QAAQ,EAAE,CAAC,GAAG,KAAI;AAChB,YAAA,QAAQ,GAAG,GAAG,CAAC;AACf,YAAA,WAAW,EAAE;AACb,YAAA,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,WAAW,CAAC;QAC/C,CAAC;AACD,QAAA,QAAQ,EAAE,CAAC,GAAG,KAAI;AAChB,YAAA,QAAQ,GAAG,GAAG,CAAC;AACf,YAAA,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,WAAW,CAAC;QAClD,CAAC;QACD,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,GAAG,EAAE,KAAI;YAC9B,QAAQ,GAAG,EAAE,KAAK,EAAE,GAAG,GAAG,EAAE,CAAC;YAC7B,cAAc,CAAC,KAAK,CAAC;QACvB,CAAC;AACD,QAAA,GAAG,IAAI;AACR,KAAA,CAAC;AAEF,IAAA,OAAO,KAAK;AACd;AAEA,MAAM,UAAU,GAAG,CAAC,OAAyC,KAAgB;IAC3E,QAAQ,OAAO;AACb,QAAA,KAAK,OAAO;AACV,YAAA,OAAO,YAAY;AACrB,QAAA,KAAK,SAAS;AACZ,YAAA,OAAO,cAAc;AACvB,QAAA;AACE,YAAA,OAAO,OAAO;;AAEpB,CAAC;;;;"}
1
+ {"version":3,"file":"createPersistentStore.js","sources":["../../../src/lib/createPersistentStore.ts"],"sourcesContent":["import { createStore, Store, StoreConfiguration } from \"./createStore\";\n\nexport type StorageAPI = {\n getItem: (key: string) => string | null;\n setItem: (key: string, value: string) => void;\n removeItem: (key: string) => void;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type Serializer<T = any> = {\n stringify: (value: T) => string;\n parse: (value: string) => T;\n};\n\nexport type PersistentStoreConfiguration<\n TState extends object,\n TActions extends object,\n> = StoreConfiguration<TState, TActions> & {\n key: string;\n /** The storage to use for persisting the state. Defaults to local storage if available. */\n storage?: StorageAPI;\n /** The serializer to use for storing the state. Defaults to JSON. */\n serializer?: Serializer<TState>;\n};\n\n/**\n * Creates a store that persists its state in local or session storage.\n * Defaults to local storage but this can be changed in the options.\n *\n * **Note:** The state needs to be serializable by whatever serializer you use. (JSON by default)\n * If you need something more versatile I would recommend using a library like [superjson](https://github.com/flightcontrolhq/superjson).\n *\n * @param {PersistentStoreConfiguration<TState, TActions>} config - The configuration for the persistent store.\n *\n * @returns {Store<TState, TActions>} The created store.\n *\n * @example\n * Basic usage:\n * ```ts\n * import { createPersistentStore } from \"dharma-core\";\n *\n * const store = createPersistentStore({\n * key: \"count\",\n * initialState: { count: 0 },\n * defineActions: ({ set }) => ({\n * increment: () => set((state) => ({ count: state.count + 1 })),\n * decrement: () => set((state) => ({ count: state.count - 1 })),\n * reset: () => set({ count: 0 }),\n * }),\n * });\n * ```\n * @example\n * With superjson serialization and session storage:\n * ```ts\n * import { createPersistentStore } from \"dharma-core\";\n * import superjson from \"superjson\";\n *\n * const store = createPersistentStore({\n * key: \"count\",\n * initialState: { count: 0 },\n * defineActions: ({ set }) => ({\n * increment: () => set((state) => ({ count: state.count + 1 })),\n * decrement: () => set((state) => ({ count: state.count - 1 })),\n * reset: () => set({ count: 0 }),\n * }),\n * serializer: superjson,\n * storage: sessionStorage,\n * });\n * ```\n */\nexport const createPersistentStore = <\n TState extends object,\n TActions extends object = Record<never, never>,\n>(\n config: PersistentStoreConfiguration<TState, TActions>,\n): Store<TState, TActions> => {\n const {\n key,\n initialState,\n storage: customStorage,\n serializer = JSON,\n onAttach,\n onDetach,\n onChange,\n ...rest\n } = config;\n\n const IS_BROWSER = typeof window !== \"undefined\";\n const storage = customStorage ?? (IS_BROWSER ? localStorage : undefined);\n\n if (!storage) {\n return createStore(config);\n }\n\n const initialStateKey = `init_${key}`;\n\n const initialStateSnapshot = storage.getItem(initialStateKey);\n const initialStateString = serializer.stringify(initialState);\n\n if (initialStateSnapshot !== initialStateString) {\n storage.setItem(initialStateKey, initialStateString);\n storage.removeItem(key);\n }\n\n const updateSnapshot = (newState: TState) => {\n const currentSnapshot = storage.getItem(key);\n const newSnapshot = serializer.stringify(newState);\n\n if (newSnapshot !== currentSnapshot) {\n storage.setItem(key, newSnapshot);\n }\n };\n\n const updateState = () => {\n const currentSnapshot = storage.getItem(key);\n\n if (\n currentSnapshot &&\n currentSnapshot !== serializer.stringify(store.get())\n ) {\n store.set(serializer.parse(currentSnapshot));\n }\n };\n\n const store = createStore({\n initialState,\n onAttach: (ctx) => {\n onAttach?.(ctx);\n updateState();\n if (IS_BROWSER) {\n window.addEventListener(\"focus\", updateState);\n }\n },\n onDetach: (ctx) => {\n onDetach?.(ctx);\n if (IS_BROWSER) {\n window.removeEventListener(\"focus\", updateState);\n }\n },\n onChange: ({ state, ...ctx }) => {\n onChange?.({ state, ...ctx });\n updateSnapshot(state);\n },\n ...rest,\n });\n\n return store;\n};\n"],"names":["createStore"],"mappings":";;;;AAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CG;AACI,MAAM,qBAAqB,GAAG,CAInC,MAAsD,KAC3B;IAC3B,MAAM,EACJ,GAAG,EACH,YAAY,EACZ,OAAO,EAAE,aAAa,EACtB,UAAU,GAAG,IAAI,EACjB,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,GAAG,IAAI,EACR,GAAG,MAAM;AAEV,IAAA,MAAM,UAAU,GAAG,OAAO,MAAM,KAAK,WAAW;AAChD,IAAA,MAAM,OAAO,GAAG,aAAa,KAAK,UAAU,GAAG,YAAY,GAAG,SAAS,CAAC;IAExE,IAAI,CAAC,OAAO,EAAE;AACZ,QAAA,OAAOA,uBAAW,CAAC,MAAM,CAAC;IAC5B;AAEA,IAAA,MAAM,eAAe,GAAG,CAAA,KAAA,EAAQ,GAAG,EAAE;IAErC,MAAM,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC;IAC7D,MAAM,kBAAkB,GAAG,UAAU,CAAC,SAAS,CAAC,YAAY,CAAC;AAE7D,IAAA,IAAI,oBAAoB,KAAK,kBAAkB,EAAE;AAC/C,QAAA,OAAO,CAAC,OAAO,CAAC,eAAe,EAAE,kBAAkB,CAAC;AACpD,QAAA,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;IACzB;AAEA,IAAA,MAAM,cAAc,GAAG,CAAC,QAAgB,KAAI;QAC1C,MAAM,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC;QAC5C,MAAM,WAAW,GAAG,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC;AAElD,QAAA,IAAI,WAAW,KAAK,eAAe,EAAE;AACnC,YAAA,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,WAAW,CAAC;QACnC;AACF,IAAA,CAAC;IAED,MAAM,WAAW,GAAG,MAAK;QACvB,MAAM,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC;AAE5C,QAAA,IACE,eAAe;YACf,eAAe,KAAK,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EACrD;YACA,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QAC9C;AACF,IAAA,CAAC;IAED,MAAM,KAAK,GAAGA,uBAAW,CAAC;QACxB,YAAY;AACZ,QAAA,QAAQ,EAAE,CAAC,GAAG,KAAI;AAChB,YAAA,QAAQ,GAAG,GAAG,CAAC;AACf,YAAA,WAAW,EAAE;YACb,IAAI,UAAU,EAAE;AACd,gBAAA,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,WAAW,CAAC;YAC/C;QACF,CAAC;AACD,QAAA,QAAQ,EAAE,CAAC,GAAG,KAAI;AAChB,YAAA,QAAQ,GAAG,GAAG,CAAC;YACf,IAAI,UAAU,EAAE;AACd,gBAAA,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,WAAW,CAAC;YAClD;QACF,CAAC;QACD,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,GAAG,EAAE,KAAI;YAC9B,QAAQ,GAAG,EAAE,KAAK,EAAE,GAAG,GAAG,EAAE,CAAC;YAC7B,cAAc,CAAC,KAAK,CAAC;QACvB,CAAC;AACD,QAAA,GAAG,IAAI;AACR,KAAA,CAAC;AAEF,IAAA,OAAO,KAAK;AACd;;;;"}
@@ -3,8 +3,8 @@ import { StateModifier } from "./createStore";
3
3
  * Merges the current state with a state modifier.
4
4
  * Useful for creating custom set functions.
5
5
  *
6
- * @param {T} stateModifier - A function or object that modifies the state.
7
- * @param {StateModifier<T>} stateModifier - The current state object.
6
+ * @param {T} currentState - The current state object.
7
+ * @param {StateModifier<T>} stateModifier - A function or object that modifies the state.
8
8
  * @returns {T} The new state object, which is a combination of the current state and the state modifier.
9
9
  *
10
10
  * @example
@@ -4,8 +4,8 @@
4
4
  * Merges the current state with a state modifier.
5
5
  * Useful for creating custom set functions.
6
6
  *
7
- * @param {T} stateModifier - A function or object that modifies the state.
8
- * @param {StateModifier<T>} stateModifier - The current state object.
7
+ * @param {T} currentState - The current state object.
8
+ * @param {StateModifier<T>} stateModifier - A function or object that modifies the state.
9
9
  * @returns {T} The new state object, which is a combination of the current state and the state modifier.
10
10
  *
11
11
  * @example
@@ -1 +1 @@
1
- {"version":3,"file":"merge.js","sources":["../../../src/lib/merge.ts"],"sourcesContent":["import { StateModifier } from \"./createStore\";\n\n/**\n * Merges the current state with a state modifier.\n * Useful for creating custom set functions.\n *\n * @param {T} stateModifier - A function or object that modifies the state.\n * @param {StateModifier<T>} stateModifier - The current state object.\n * @returns {T} The new state object, which is a combination of the current state and the state modifier.\n *\n * @example\n * ```ts\n * import { createStore, merge, StateModifier } from \"dharma-core\";\n *\n * const store = createStore({\n * initialState: {\n * counter: {\n * count: 0,\n * },\n * // ...\n * },\n * defineActions: ({ set }) => {\n * const setCounter = (counter: StateModifier<{ count: number }>) =>\n * set((state) => ({\n * counter: merge(state.counter, counter),\n * }));\n *\n * return {\n * increment: () => setCounter((state) => ({ count: state.count + 1 })),\n * decrement: () => setCounter((state) => ({ count: state.count - 1 })),\n * reset: () => setCounter({ count: 0 }),\n * // ...\n * };\n * },\n * });\n * ```\n */\nexport const merge = <T extends object>(\n currentState: T,\n stateModifier: StateModifier<T>,\n): T => {\n const newState =\n typeof stateModifier === \"function\"\n ? stateModifier(currentState)\n : stateModifier;\n return { ...currentState, ...newState };\n};\n"],"names":[],"mappings":";;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCG;MACU,KAAK,GAAG,CACnB,YAAe,EACf,aAA+B,KAC1B;AACL,IAAA,MAAM,QAAQ,GACZ,OAAO,aAAa,KAAK;AACvB,UAAE,aAAa,CAAC,YAAY;UAC1B,aAAa;AACnB,IAAA,OAAO,EAAE,GAAG,YAAY,EAAE,GAAG,QAAQ,EAAE;AACzC;;;;"}
1
+ {"version":3,"file":"merge.js","sources":["../../../src/lib/merge.ts"],"sourcesContent":["import { StateModifier } from \"./createStore\";\n\n/**\n * Merges the current state with a state modifier.\n * Useful for creating custom set functions.\n *\n * @param {T} currentState - The current state object.\n * @param {StateModifier<T>} stateModifier - A function or object that modifies the state.\n * @returns {T} The new state object, which is a combination of the current state and the state modifier.\n *\n * @example\n * ```ts\n * import { createStore, merge, StateModifier } from \"dharma-core\";\n *\n * const store = createStore({\n * initialState: {\n * counter: {\n * count: 0,\n * },\n * // ...\n * },\n * defineActions: ({ set }) => {\n * const setCounter = (counter: StateModifier<{ count: number }>) =>\n * set((state) => ({\n * counter: merge(state.counter, counter),\n * }));\n *\n * return {\n * increment: () => setCounter((state) => ({ count: state.count + 1 })),\n * decrement: () => setCounter((state) => ({ count: state.count - 1 })),\n * reset: () => setCounter({ count: 0 }),\n * // ...\n * };\n * },\n * });\n * ```\n */\nexport const merge = <T extends object>(\n currentState: T,\n stateModifier: StateModifier<T>,\n): T => {\n const newState =\n typeof stateModifier === \"function\"\n ? stateModifier(currentState)\n : stateModifier;\n return { ...currentState, ...newState };\n};\n"],"names":[],"mappings":";;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCG;MACU,KAAK,GAAG,CACnB,YAAe,EACf,aAA+B,KAC1B;AACL,IAAA,MAAM,QAAQ,GACZ,OAAO,aAAa,KAAK;AACvB,UAAE,aAAa,CAAC,YAAY;UAC1B,aAAa;AACnB,IAAA,OAAO,EAAE,GAAG,YAAY,EAAE,GAAG,QAAQ,EAAE;AACzC;;;;"}
@@ -10,8 +10,8 @@ export type Serializer<T = any> = {
10
10
  };
11
11
  export type PersistentStoreConfiguration<TState extends object, TActions extends object> = StoreConfiguration<TState, TActions> & {
12
12
  key: string;
13
- /** The storage to use for persisting the state. Defaults to local storage. */
14
- storage?: StorageAPI | "local" | "session";
13
+ /** The storage to use for persisting the state. Defaults to local storage if available. */
14
+ storage?: StorageAPI;
15
15
  /** The serializer to use for storing the state. Defaults to JSON. */
16
16
  serializer?: Serializer<TState>;
17
17
  };
@@ -22,10 +22,7 @@ export type PersistentStoreConfiguration<TState extends object, TActions extends
22
22
  * **Note:** The state needs to be serializable by whatever serializer you use. (JSON by default)
23
23
  * If you need something more versatile I would recommend using a library like [superjson](https://github.com/flightcontrolhq/superjson).
24
24
  *
25
- * @param {string} key - A unique key to identify the store in storage.
26
- * @param {TState} initialState - The initial state of the store.
27
- * @param {DefineActions<TState, TActions>} [defineActions] - A function to define actions for the store.
28
- * @param {PersistentStoreConfiguration<TState>} [options] - Additional options for the persistent store.
25
+ * @param {PersistentStoreConfiguration<TState, TActions>} config - The configuration for the persistent store.
29
26
  *
30
27
  * @returns {Store<TState, TActions>} The created store.
31
28
  *
@@ -34,11 +31,15 @@ export type PersistentStoreConfiguration<TState extends object, TActions extends
34
31
  * ```ts
35
32
  * import { createPersistentStore } from "dharma-core";
36
33
  *
37
- * const store = createPersistentStore("count", { count: 0 }, ({ set }) => ({
38
- * increment: () => set((state) => ({ count: state.count + 1 })),
39
- * decrement: () => set((state) => ({ count: state.count - 1 })),
40
- * reset: () => set({ count: 0 }),
41
- * }));
34
+ * const store = createPersistentStore({
35
+ * key: "count",
36
+ * initialState: { count: 0 },
37
+ * defineActions: ({ set }) => ({
38
+ * increment: () => set((state) => ({ count: state.count + 1 })),
39
+ * decrement: () => set((state) => ({ count: state.count - 1 })),
40
+ * reset: () => set({ count: 0 }),
41
+ * }),
42
+ * });
42
43
  * ```
43
44
  * @example
44
45
  * With superjson serialization and session storage:
@@ -46,19 +47,17 @@ export type PersistentStoreConfiguration<TState extends object, TActions extends
46
47
  * import { createPersistentStore } from "dharma-core";
47
48
  * import superjson from "superjson";
48
49
  *
49
- * const store = createPersistentStore(
50
- * "count",
51
- * { count: 0 },
52
- * ({ set }) => ({
50
+ * const store = createPersistentStore({
51
+ * key: "count",
52
+ * initialState: { count: 0 },
53
+ * defineActions: ({ set }) => ({
53
54
  * increment: () => set((state) => ({ count: state.count + 1 })),
54
55
  * decrement: () => set((state) => ({ count: state.count - 1 })),
55
56
  * reset: () => set({ count: 0 }),
56
57
  * }),
57
- * {
58
- * serializer: superjson,
59
- * storage: "session",
60
- * },
61
- * );
58
+ * serializer: superjson,
59
+ * storage: sessionStorage,
60
+ * });
62
61
  * ```
63
62
  */
64
- export declare const createPersistentStore: <TState extends object, TActions extends object = Record<never, never>>(options: PersistentStoreConfiguration<TState, TActions>) => Store<TState, TActions>;
63
+ export declare const createPersistentStore: <TState extends object, TActions extends object = Record<never, never>>(config: PersistentStoreConfiguration<TState, TActions>) => Store<TState, TActions>;
@@ -7,10 +7,7 @@ import { createStore } from './createStore.js';
7
7
  * **Note:** The state needs to be serializable by whatever serializer you use. (JSON by default)
8
8
  * If you need something more versatile I would recommend using a library like [superjson](https://github.com/flightcontrolhq/superjson).
9
9
  *
10
- * @param {string} key - A unique key to identify the store in storage.
11
- * @param {TState} initialState - The initial state of the store.
12
- * @param {DefineActions<TState, TActions>} [defineActions] - A function to define actions for the store.
13
- * @param {PersistentStoreConfiguration<TState>} [options] - Additional options for the persistent store.
10
+ * @param {PersistentStoreConfiguration<TState, TActions>} config - The configuration for the persistent store.
14
11
  *
15
12
  * @returns {Store<TState, TActions>} The created store.
16
13
  *
@@ -19,11 +16,15 @@ import { createStore } from './createStore.js';
19
16
  * ```ts
20
17
  * import { createPersistentStore } from "dharma-core";
21
18
  *
22
- * const store = createPersistentStore("count", { count: 0 }, ({ set }) => ({
23
- * increment: () => set((state) => ({ count: state.count + 1 })),
24
- * decrement: () => set((state) => ({ count: state.count - 1 })),
25
- * reset: () => set({ count: 0 }),
26
- * }));
19
+ * const store = createPersistentStore({
20
+ * key: "count",
21
+ * initialState: { count: 0 },
22
+ * defineActions: ({ set }) => ({
23
+ * increment: () => set((state) => ({ count: state.count + 1 })),
24
+ * decrement: () => set((state) => ({ count: state.count - 1 })),
25
+ * reset: () => set({ count: 0 }),
26
+ * }),
27
+ * });
27
28
  * ```
28
29
  * @example
29
30
  * With superjson serialization and session storage:
@@ -31,44 +32,42 @@ import { createStore } from './createStore.js';
31
32
  * import { createPersistentStore } from "dharma-core";
32
33
  * import superjson from "superjson";
33
34
  *
34
- * const store = createPersistentStore(
35
- * "count",
36
- * { count: 0 },
37
- * ({ set }) => ({
35
+ * const store = createPersistentStore({
36
+ * key: "count",
37
+ * initialState: { count: 0 },
38
+ * defineActions: ({ set }) => ({
38
39
  * increment: () => set((state) => ({ count: state.count + 1 })),
39
40
  * decrement: () => set((state) => ({ count: state.count - 1 })),
40
41
  * reset: () => set({ count: 0 }),
41
42
  * }),
42
- * {
43
- * serializer: superjson,
44
- * storage: "session",
45
- * },
46
- * );
43
+ * serializer: superjson,
44
+ * storage: sessionStorage,
45
+ * });
47
46
  * ```
48
47
  */
49
- const createPersistentStore = (options) => {
50
- if (typeof window === "undefined") {
51
- return createStore(options);
48
+ const createPersistentStore = (config) => {
49
+ const { key, initialState, storage: customStorage, serializer = JSON, onAttach, onDetach, onChange, ...rest } = config;
50
+ const IS_BROWSER = typeof window !== "undefined";
51
+ const storage = customStorage ?? (IS_BROWSER ? localStorage : undefined);
52
+ if (!storage) {
53
+ return createStore(config);
52
54
  }
53
- const { key, initialState, storage: _storage = "local", serializer = JSON, onAttach, onDetach, onChange, ...rest } = options;
54
- const storage = getStorage(_storage);
55
- const stateKey = `store_${key}`;
56
55
  const initialStateKey = `init_${key}`;
57
56
  const initialStateSnapshot = storage.getItem(initialStateKey);
58
57
  const initialStateString = serializer.stringify(initialState);
59
58
  if (initialStateSnapshot !== initialStateString) {
60
59
  storage.setItem(initialStateKey, initialStateString);
61
- storage.removeItem(stateKey);
60
+ storage.removeItem(key);
62
61
  }
63
62
  const updateSnapshot = (newState) => {
64
- const currentSnapshot = storage.getItem(stateKey);
63
+ const currentSnapshot = storage.getItem(key);
65
64
  const newSnapshot = serializer.stringify(newState);
66
65
  if (newSnapshot !== currentSnapshot) {
67
- storage.setItem(stateKey, newSnapshot);
66
+ storage.setItem(key, newSnapshot);
68
67
  }
69
68
  };
70
69
  const updateState = () => {
71
- const currentSnapshot = storage.getItem(stateKey);
70
+ const currentSnapshot = storage.getItem(key);
72
71
  if (currentSnapshot &&
73
72
  currentSnapshot !== serializer.stringify(store.get())) {
74
73
  store.set(serializer.parse(currentSnapshot));
@@ -79,11 +78,15 @@ const createPersistentStore = (options) => {
79
78
  onAttach: (ctx) => {
80
79
  onAttach?.(ctx);
81
80
  updateState();
82
- window.addEventListener("focus", updateState);
81
+ if (IS_BROWSER) {
82
+ window.addEventListener("focus", updateState);
83
+ }
83
84
  },
84
85
  onDetach: (ctx) => {
85
86
  onDetach?.(ctx);
86
- window.removeEventListener("focus", updateState);
87
+ if (IS_BROWSER) {
88
+ window.removeEventListener("focus", updateState);
89
+ }
87
90
  },
88
91
  onChange: ({ state, ...ctx }) => {
89
92
  onChange?.({ state, ...ctx });
@@ -93,16 +96,6 @@ const createPersistentStore = (options) => {
93
96
  });
94
97
  return store;
95
98
  };
96
- const getStorage = (storage) => {
97
- switch (storage) {
98
- case "local":
99
- return localStorage;
100
- case "session":
101
- return sessionStorage;
102
- default:
103
- return storage;
104
- }
105
- };
106
99
 
107
100
  export { createPersistentStore };
108
101
  //# sourceMappingURL=createPersistentStore.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"createPersistentStore.js","sources":["../../../src/lib/createPersistentStore.ts"],"sourcesContent":["import { createStore, Store, StoreConfiguration } from \"./createStore\";\n\nexport type StorageAPI = {\n getItem: (key: string) => string | null;\n setItem: (key: string, value: string) => void;\n removeItem: (key: string) => void;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type Serializer<T = any> = {\n stringify: (value: T) => string;\n parse: (value: string) => T;\n};\n\nexport type PersistentStoreConfiguration<\n TState extends object,\n TActions extends object,\n> = StoreConfiguration<TState, TActions> & {\n key: string;\n /** The storage to use for persisting the state. Defaults to local storage. */\n storage?: StorageAPI | \"local\" | \"session\";\n /** The serializer to use for storing the state. Defaults to JSON. */\n serializer?: Serializer<TState>;\n};\n\n/**\n * Creates a store that persists its state in local or session storage.\n * Defaults to local storage but this can be changed in the options.\n *\n * **Note:** The state needs to be serializable by whatever serializer you use. (JSON by default)\n * If you need something more versatile I would recommend using a library like [superjson](https://github.com/flightcontrolhq/superjson).\n *\n * @param {string} key - A unique key to identify the store in storage.\n * @param {TState} initialState - The initial state of the store.\n * @param {DefineActions<TState, TActions>} [defineActions] - A function to define actions for the store.\n * @param {PersistentStoreConfiguration<TState>} [options] - Additional options for the persistent store.\n *\n * @returns {Store<TState, TActions>} The created store.\n *\n * @example\n * Basic usage:\n * ```ts\n * import { createPersistentStore } from \"dharma-core\";\n *\n * const store = createPersistentStore(\"count\", { count: 0 }, ({ set }) => ({\n * increment: () => set((state) => ({ count: state.count + 1 })),\n * decrement: () => set((state) => ({ count: state.count - 1 })),\n * reset: () => set({ count: 0 }),\n * }));\n * ```\n * @example\n * With superjson serialization and session storage:\n * ```ts\n * import { createPersistentStore } from \"dharma-core\";\n * import superjson from \"superjson\";\n *\n * const store = createPersistentStore(\n * \"count\",\n * { count: 0 },\n * ({ set }) => ({\n * increment: () => set((state) => ({ count: state.count + 1 })),\n * decrement: () => set((state) => ({ count: state.count - 1 })),\n * reset: () => set({ count: 0 }),\n * }),\n * {\n * serializer: superjson,\n * storage: \"session\",\n * },\n * );\n * ```\n */\nexport const createPersistentStore = <\n TState extends object,\n TActions extends object = Record<never, never>,\n>(\n options: PersistentStoreConfiguration<TState, TActions>,\n): Store<TState, TActions> => {\n if (typeof window === \"undefined\") {\n return createStore(options);\n }\n\n const {\n key,\n initialState,\n storage: _storage = \"local\",\n serializer = JSON,\n onAttach,\n onDetach,\n onChange,\n ...rest\n } = options;\n\n const storage = getStorage(_storage);\n const stateKey = `store_${key}`;\n const initialStateKey = `init_${key}`;\n const initialStateSnapshot = storage.getItem(initialStateKey);\n const initialStateString = serializer.stringify(initialState);\n\n if (initialStateSnapshot !== initialStateString) {\n storage.setItem(initialStateKey, initialStateString);\n storage.removeItem(stateKey);\n }\n\n const updateSnapshot = (newState: TState) => {\n const currentSnapshot = storage.getItem(stateKey);\n const newSnapshot = serializer.stringify(newState);\n\n if (newSnapshot !== currentSnapshot) {\n storage.setItem(stateKey, newSnapshot);\n }\n };\n\n const updateState = () => {\n const currentSnapshot = storage.getItem(stateKey);\n\n if (\n currentSnapshot &&\n currentSnapshot !== serializer.stringify(store.get())\n ) {\n store.set(serializer.parse(currentSnapshot));\n }\n };\n\n const store = createStore({\n initialState,\n onAttach: (ctx) => {\n onAttach?.(ctx);\n updateState();\n window.addEventListener(\"focus\", updateState);\n },\n onDetach: (ctx) => {\n onDetach?.(ctx);\n window.removeEventListener(\"focus\", updateState);\n },\n onChange: ({ state, ...ctx }) => {\n onChange?.({ state, ...ctx });\n updateSnapshot(state);\n },\n ...rest,\n });\n\n return store;\n};\n\nconst getStorage = (storage: StorageAPI | \"local\" | \"session\"): StorageAPI => {\n switch (storage) {\n case \"local\":\n return localStorage;\n case \"session\":\n return sessionStorage;\n default:\n return storage;\n }\n};\n"],"names":[],"mappings":";;AAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CG;AACI,MAAM,qBAAqB,GAAG,CAInC,OAAuD,KAC5B;AAC3B,IAAA,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;AACjC,QAAA,OAAO,WAAW,CAAC,OAAO,CAAC;IAC7B;IAEA,MAAM,EACJ,GAAG,EACH,YAAY,EACZ,OAAO,EAAE,QAAQ,GAAG,OAAO,EAC3B,UAAU,GAAG,IAAI,EACjB,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,GAAG,IAAI,EACR,GAAG,OAAO;AAEX,IAAA,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC;AACpC,IAAA,MAAM,QAAQ,GAAG,CAAA,MAAA,EAAS,GAAG,EAAE;AAC/B,IAAA,MAAM,eAAe,GAAG,CAAA,KAAA,EAAQ,GAAG,EAAE;IACrC,MAAM,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC;IAC7D,MAAM,kBAAkB,GAAG,UAAU,CAAC,SAAS,CAAC,YAAY,CAAC;AAE7D,IAAA,IAAI,oBAAoB,KAAK,kBAAkB,EAAE;AAC/C,QAAA,OAAO,CAAC,OAAO,CAAC,eAAe,EAAE,kBAAkB,CAAC;AACpD,QAAA,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC;IAC9B;AAEA,IAAA,MAAM,cAAc,GAAG,CAAC,QAAgB,KAAI;QAC1C,MAAM,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;QACjD,MAAM,WAAW,GAAG,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC;AAElD,QAAA,IAAI,WAAW,KAAK,eAAe,EAAE;AACnC,YAAA,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,WAAW,CAAC;QACxC;AACF,IAAA,CAAC;IAED,MAAM,WAAW,GAAG,MAAK;QACvB,MAAM,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;AAEjD,QAAA,IACE,eAAe;YACf,eAAe,KAAK,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EACrD;YACA,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QAC9C;AACF,IAAA,CAAC;IAED,MAAM,KAAK,GAAG,WAAW,CAAC;QACxB,YAAY;AACZ,QAAA,QAAQ,EAAE,CAAC,GAAG,KAAI;AAChB,YAAA,QAAQ,GAAG,GAAG,CAAC;AACf,YAAA,WAAW,EAAE;AACb,YAAA,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,WAAW,CAAC;QAC/C,CAAC;AACD,QAAA,QAAQ,EAAE,CAAC,GAAG,KAAI;AAChB,YAAA,QAAQ,GAAG,GAAG,CAAC;AACf,YAAA,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,WAAW,CAAC;QAClD,CAAC;QACD,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,GAAG,EAAE,KAAI;YAC9B,QAAQ,GAAG,EAAE,KAAK,EAAE,GAAG,GAAG,EAAE,CAAC;YAC7B,cAAc,CAAC,KAAK,CAAC;QACvB,CAAC;AACD,QAAA,GAAG,IAAI;AACR,KAAA,CAAC;AAEF,IAAA,OAAO,KAAK;AACd;AAEA,MAAM,UAAU,GAAG,CAAC,OAAyC,KAAgB;IAC3E,QAAQ,OAAO;AACb,QAAA,KAAK,OAAO;AACV,YAAA,OAAO,YAAY;AACrB,QAAA,KAAK,SAAS;AACZ,YAAA,OAAO,cAAc;AACvB,QAAA;AACE,YAAA,OAAO,OAAO;;AAEpB,CAAC;;;;"}
1
+ {"version":3,"file":"createPersistentStore.js","sources":["../../../src/lib/createPersistentStore.ts"],"sourcesContent":["import { createStore, Store, StoreConfiguration } from \"./createStore\";\n\nexport type StorageAPI = {\n getItem: (key: string) => string | null;\n setItem: (key: string, value: string) => void;\n removeItem: (key: string) => void;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type Serializer<T = any> = {\n stringify: (value: T) => string;\n parse: (value: string) => T;\n};\n\nexport type PersistentStoreConfiguration<\n TState extends object,\n TActions extends object,\n> = StoreConfiguration<TState, TActions> & {\n key: string;\n /** The storage to use for persisting the state. Defaults to local storage if available. */\n storage?: StorageAPI;\n /** The serializer to use for storing the state. Defaults to JSON. */\n serializer?: Serializer<TState>;\n};\n\n/**\n * Creates a store that persists its state in local or session storage.\n * Defaults to local storage but this can be changed in the options.\n *\n * **Note:** The state needs to be serializable by whatever serializer you use. (JSON by default)\n * If you need something more versatile I would recommend using a library like [superjson](https://github.com/flightcontrolhq/superjson).\n *\n * @param {PersistentStoreConfiguration<TState, TActions>} config - The configuration for the persistent store.\n *\n * @returns {Store<TState, TActions>} The created store.\n *\n * @example\n * Basic usage:\n * ```ts\n * import { createPersistentStore } from \"dharma-core\";\n *\n * const store = createPersistentStore({\n * key: \"count\",\n * initialState: { count: 0 },\n * defineActions: ({ set }) => ({\n * increment: () => set((state) => ({ count: state.count + 1 })),\n * decrement: () => set((state) => ({ count: state.count - 1 })),\n * reset: () => set({ count: 0 }),\n * }),\n * });\n * ```\n * @example\n * With superjson serialization and session storage:\n * ```ts\n * import { createPersistentStore } from \"dharma-core\";\n * import superjson from \"superjson\";\n *\n * const store = createPersistentStore({\n * key: \"count\",\n * initialState: { count: 0 },\n * defineActions: ({ set }) => ({\n * increment: () => set((state) => ({ count: state.count + 1 })),\n * decrement: () => set((state) => ({ count: state.count - 1 })),\n * reset: () => set({ count: 0 }),\n * }),\n * serializer: superjson,\n * storage: sessionStorage,\n * });\n * ```\n */\nexport const createPersistentStore = <\n TState extends object,\n TActions extends object = Record<never, never>,\n>(\n config: PersistentStoreConfiguration<TState, TActions>,\n): Store<TState, TActions> => {\n const {\n key,\n initialState,\n storage: customStorage,\n serializer = JSON,\n onAttach,\n onDetach,\n onChange,\n ...rest\n } = config;\n\n const IS_BROWSER = typeof window !== \"undefined\";\n const storage = customStorage ?? (IS_BROWSER ? localStorage : undefined);\n\n if (!storage) {\n return createStore(config);\n }\n\n const initialStateKey = `init_${key}`;\n\n const initialStateSnapshot = storage.getItem(initialStateKey);\n const initialStateString = serializer.stringify(initialState);\n\n if (initialStateSnapshot !== initialStateString) {\n storage.setItem(initialStateKey, initialStateString);\n storage.removeItem(key);\n }\n\n const updateSnapshot = (newState: TState) => {\n const currentSnapshot = storage.getItem(key);\n const newSnapshot = serializer.stringify(newState);\n\n if (newSnapshot !== currentSnapshot) {\n storage.setItem(key, newSnapshot);\n }\n };\n\n const updateState = () => {\n const currentSnapshot = storage.getItem(key);\n\n if (\n currentSnapshot &&\n currentSnapshot !== serializer.stringify(store.get())\n ) {\n store.set(serializer.parse(currentSnapshot));\n }\n };\n\n const store = createStore({\n initialState,\n onAttach: (ctx) => {\n onAttach?.(ctx);\n updateState();\n if (IS_BROWSER) {\n window.addEventListener(\"focus\", updateState);\n }\n },\n onDetach: (ctx) => {\n onDetach?.(ctx);\n if (IS_BROWSER) {\n window.removeEventListener(\"focus\", updateState);\n }\n },\n onChange: ({ state, ...ctx }) => {\n onChange?.({ state, ...ctx });\n updateSnapshot(state);\n },\n ...rest,\n });\n\n return store;\n};\n"],"names":[],"mappings":";;AAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CG;AACI,MAAM,qBAAqB,GAAG,CAInC,MAAsD,KAC3B;IAC3B,MAAM,EACJ,GAAG,EACH,YAAY,EACZ,OAAO,EAAE,aAAa,EACtB,UAAU,GAAG,IAAI,EACjB,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,GAAG,IAAI,EACR,GAAG,MAAM;AAEV,IAAA,MAAM,UAAU,GAAG,OAAO,MAAM,KAAK,WAAW;AAChD,IAAA,MAAM,OAAO,GAAG,aAAa,KAAK,UAAU,GAAG,YAAY,GAAG,SAAS,CAAC;IAExE,IAAI,CAAC,OAAO,EAAE;AACZ,QAAA,OAAO,WAAW,CAAC,MAAM,CAAC;IAC5B;AAEA,IAAA,MAAM,eAAe,GAAG,CAAA,KAAA,EAAQ,GAAG,EAAE;IAErC,MAAM,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC;IAC7D,MAAM,kBAAkB,GAAG,UAAU,CAAC,SAAS,CAAC,YAAY,CAAC;AAE7D,IAAA,IAAI,oBAAoB,KAAK,kBAAkB,EAAE;AAC/C,QAAA,OAAO,CAAC,OAAO,CAAC,eAAe,EAAE,kBAAkB,CAAC;AACpD,QAAA,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;IACzB;AAEA,IAAA,MAAM,cAAc,GAAG,CAAC,QAAgB,KAAI;QAC1C,MAAM,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC;QAC5C,MAAM,WAAW,GAAG,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC;AAElD,QAAA,IAAI,WAAW,KAAK,eAAe,EAAE;AACnC,YAAA,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,WAAW,CAAC;QACnC;AACF,IAAA,CAAC;IAED,MAAM,WAAW,GAAG,MAAK;QACvB,MAAM,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC;AAE5C,QAAA,IACE,eAAe;YACf,eAAe,KAAK,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EACrD;YACA,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QAC9C;AACF,IAAA,CAAC;IAED,MAAM,KAAK,GAAG,WAAW,CAAC;QACxB,YAAY;AACZ,QAAA,QAAQ,EAAE,CAAC,GAAG,KAAI;AAChB,YAAA,QAAQ,GAAG,GAAG,CAAC;AACf,YAAA,WAAW,EAAE;YACb,IAAI,UAAU,EAAE;AACd,gBAAA,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,WAAW,CAAC;YAC/C;QACF,CAAC;AACD,QAAA,QAAQ,EAAE,CAAC,GAAG,KAAI;AAChB,YAAA,QAAQ,GAAG,GAAG,CAAC;YACf,IAAI,UAAU,EAAE;AACd,gBAAA,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,WAAW,CAAC;YAClD;QACF,CAAC;QACD,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,GAAG,EAAE,KAAI;YAC9B,QAAQ,GAAG,EAAE,KAAK,EAAE,GAAG,GAAG,EAAE,CAAC;YAC7B,cAAc,CAAC,KAAK,CAAC;QACvB,CAAC;AACD,QAAA,GAAG,IAAI;AACR,KAAA,CAAC;AAEF,IAAA,OAAO,KAAK;AACd;;;;"}
@@ -3,8 +3,8 @@ import { StateModifier } from "./createStore";
3
3
  * Merges the current state with a state modifier.
4
4
  * Useful for creating custom set functions.
5
5
  *
6
- * @param {T} stateModifier - A function or object that modifies the state.
7
- * @param {StateModifier<T>} stateModifier - The current state object.
6
+ * @param {T} currentState - The current state object.
7
+ * @param {StateModifier<T>} stateModifier - A function or object that modifies the state.
8
8
  * @returns {T} The new state object, which is a combination of the current state and the state modifier.
9
9
  *
10
10
  * @example
@@ -2,8 +2,8 @@
2
2
  * Merges the current state with a state modifier.
3
3
  * Useful for creating custom set functions.
4
4
  *
5
- * @param {T} stateModifier - A function or object that modifies the state.
6
- * @param {StateModifier<T>} stateModifier - The current state object.
5
+ * @param {T} currentState - The current state object.
6
+ * @param {StateModifier<T>} stateModifier - A function or object that modifies the state.
7
7
  * @returns {T} The new state object, which is a combination of the current state and the state modifier.
8
8
  *
9
9
  * @example
@@ -1 +1 @@
1
- {"version":3,"file":"merge.js","sources":["../../../src/lib/merge.ts"],"sourcesContent":["import { StateModifier } from \"./createStore\";\n\n/**\n * Merges the current state with a state modifier.\n * Useful for creating custom set functions.\n *\n * @param {T} stateModifier - A function or object that modifies the state.\n * @param {StateModifier<T>} stateModifier - The current state object.\n * @returns {T} The new state object, which is a combination of the current state and the state modifier.\n *\n * @example\n * ```ts\n * import { createStore, merge, StateModifier } from \"dharma-core\";\n *\n * const store = createStore({\n * initialState: {\n * counter: {\n * count: 0,\n * },\n * // ...\n * },\n * defineActions: ({ set }) => {\n * const setCounter = (counter: StateModifier<{ count: number }>) =>\n * set((state) => ({\n * counter: merge(state.counter, counter),\n * }));\n *\n * return {\n * increment: () => setCounter((state) => ({ count: state.count + 1 })),\n * decrement: () => setCounter((state) => ({ count: state.count - 1 })),\n * reset: () => setCounter({ count: 0 }),\n * // ...\n * };\n * },\n * });\n * ```\n */\nexport const merge = <T extends object>(\n currentState: T,\n stateModifier: StateModifier<T>,\n): T => {\n const newState =\n typeof stateModifier === \"function\"\n ? stateModifier(currentState)\n : stateModifier;\n return { ...currentState, ...newState };\n};\n"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCG;MACU,KAAK,GAAG,CACnB,YAAe,EACf,aAA+B,KAC1B;AACL,IAAA,MAAM,QAAQ,GACZ,OAAO,aAAa,KAAK;AACvB,UAAE,aAAa,CAAC,YAAY;UAC1B,aAAa;AACnB,IAAA,OAAO,EAAE,GAAG,YAAY,EAAE,GAAG,QAAQ,EAAE;AACzC;;;;"}
1
+ {"version":3,"file":"merge.js","sources":["../../../src/lib/merge.ts"],"sourcesContent":["import { StateModifier } from \"./createStore\";\n\n/**\n * Merges the current state with a state modifier.\n * Useful for creating custom set functions.\n *\n * @param {T} currentState - The current state object.\n * @param {StateModifier<T>} stateModifier - A function or object that modifies the state.\n * @returns {T} The new state object, which is a combination of the current state and the state modifier.\n *\n * @example\n * ```ts\n * import { createStore, merge, StateModifier } from \"dharma-core\";\n *\n * const store = createStore({\n * initialState: {\n * counter: {\n * count: 0,\n * },\n * // ...\n * },\n * defineActions: ({ set }) => {\n * const setCounter = (counter: StateModifier<{ count: number }>) =>\n * set((state) => ({\n * counter: merge(state.counter, counter),\n * }));\n *\n * return {\n * increment: () => setCounter((state) => ({ count: state.count + 1 })),\n * decrement: () => setCounter((state) => ({ count: state.count - 1 })),\n * reset: () => setCounter({ count: 0 }),\n * // ...\n * };\n * },\n * });\n * ```\n */\nexport const merge = <T extends object>(\n currentState: T,\n stateModifier: StateModifier<T>,\n): T => {\n const newState =\n typeof stateModifier === \"function\"\n ? stateModifier(currentState)\n : stateModifier;\n return { ...currentState, ...newState };\n};\n"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCG;MACU,KAAK,GAAG,CACnB,YAAe,EACf,aAA+B,KAC1B;AACL,IAAA,MAAM,QAAQ,GACZ,OAAO,aAAa,KAAK;AACvB,UAAE,aAAa,CAAC,YAAY;UAC1B,aAAa;AACnB,IAAA,OAAO,EAAE,GAAG,YAAY,EAAE,GAAG,QAAQ,EAAE;AACzC;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dharma-core",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "author": "Frans Ekman <fransedvinekman@gmail.com>",
5
5
  "license": "MIT",
6
6
  "description": "My package description",