react-wire-persisted 2.1.0 → 3.0.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
@@ -5,23 +5,13 @@
5
5
  ## Install
6
6
 
7
7
  ```shell
8
- $ pnpm add -D @forminator/react-wire react-wire-persisted
9
- ```
10
-
11
- ## Building
12
-
13
- ```shell
14
- $ pnpm build
15
- $ npm version patch # patch, minor, major
16
- $ git push
17
- $ git push --tags
18
- $ npm publish
8
+ $ pnpm add @forminator/react-wire react-wire-persisted
19
9
  ```
20
10
 
21
11
  ## Usage
22
12
 
23
- ```javascript
24
- // constants.js
13
+ ```typescript
14
+ // constants.ts
25
15
  import { key, getPrefixedKeys } from 'react-wire-persisted/lib/utils'
26
16
 
27
17
  export const NS = 'myapp'
@@ -33,36 +23,48 @@ const prefixedKeys = getPrefixedKeys(NS)
33
23
  export { prefixedKeys as keys }
34
24
  ```
35
25
 
36
- ```javascript
37
- // index.js
26
+ ```tsx
27
+ // index.tsx
38
28
  import { NS } from './constants'
39
- import * as reactWirePersisted from 'react-wire-persisted'
29
+ import * as rwp from 'react-wire-persisted'
30
+
31
+ rwp.setNamespace(NS)
40
32
 
41
- reactWirePersisted.setNamespace(NS)
33
+ rwp.setOptions({
34
+ logging: {
35
+ enabled: true,
36
+ },
37
+ storageProvider: rwp.MemoryStorageProvider,
38
+ })
42
39
 
43
40
  // Normal React init code
44
41
  ```
45
42
 
46
- ```javascript
47
- // store.js
43
+ ```typescript
44
+ // store.ts
48
45
  import { createPersistedWire } from 'react-wire-persisted'
49
46
  import { keys } from './constants'
50
47
 
51
- export const foo = createPersistedWire(keys.foo, null)
48
+ type User = {
49
+ id: number
50
+ email: string
51
+ }
52
+
53
+ export const user = createPersistedWire<User | null>(keys.foo, null)
52
54
  ```
53
55
 
54
- ```javascript
55
- // SomeComponent.js
56
+ ```tsx
57
+ // SomeComponent.tsx
56
58
  import { useWireState } from '@forminator/react-wire'
57
59
  import * as store from './store'
58
60
 
59
61
  const SomeComponent = () => {
60
- const [foo, setFoo] = useWireState(store.foo)
62
+ const [user, setUser] = useWireState(store.user)
61
63
  return (
62
64
  <div>
63
- <p>Foo: {foo}</p>
64
- <button onClick={() => setFoo('bar')}>
65
- CHANGE FOO
65
+ <p>User: {user?.email}</p>
66
+ <button onClick={() => setUser({ ...user, email: 'example@gmail.com'})}>
67
+ Change Email
66
68
  </button>
67
69
  </div>
68
70
  )
@@ -75,9 +77,100 @@ See the [demo](demo) folder for a more complete example.
75
77
 
76
78
  ## Storage Providers
77
79
 
78
- This library uses `localStorage`, and will only work in browser environments.
80
+ By default, this library uses `localStorage` via `LocalStorageProvider` in browser environments. However, you can customize the storage behavior using `setOptions`:
81
+
82
+ ```typescript
83
+ import { setOptions, createPersistedWire } from 'react-wire-persisted'
84
+ import { MemoryStorageProvider } from 'react-wire-persisted'
85
+
86
+ // Use in-memory storage (useful for testing or SSR)
87
+ setOptions({
88
+ storageProvider: MemoryStorageProvider,
89
+ })
90
+ ```
91
+
92
+ This is useful for:
93
+ - **Testing**: Avoid localStorage in unit tests
94
+ - **SSR**: Use in-memory storage during server-side rendering
95
+ - **Custom storage**: Implement your own provider by extending `RWPStorageProvider`
96
+
97
+ See [LocalStorageProvider](src/providers/LocalStorageProvider.ts) and [MemoryStorageProvider](src/providers/MemoryStorageProvider.ts) for implementation examples.
98
+
99
+ ## API
100
+
101
+ ### `createPersistedWire<T = null>(key: string, value?: T): PersistedWire<T>`
102
+
103
+ Creates a persisted Wire that automatically syncs with the configured storage provider.
104
+
105
+ ### `setNamespace(namespace: string): void`
106
+
107
+ Sets the namespace for storage keys. This prefixes all keys to avoid collisions.
108
+
109
+ ### `setOptions(options: Partial<RWPOptions>): void`
110
+
111
+ Configure library options:
112
+ - `logging.enabled`: Enable/disable logging (default: `false`)
113
+ - `storageProvider`: Custom storage provider class
114
+
115
+ ### `getOptions(): RWPOptions`
116
+
117
+ Get current options.
79
118
 
80
- See [LocalStorageProvider](src/LocalStorageProvider.js) for implementation.
119
+ ### `getNamespace(): string | null`
120
+
121
+ Get current namespace.
122
+
123
+ ### `getStorage(): RWPStorageProvider`
124
+
125
+ Get the current storage provider instance.
126
+
127
+ ### `upgradeStorage(): boolean`
128
+
129
+ Attempts to upgrade from fake storage (used during SSR) to real localStorage. Returns `true` if upgrade was successful. Call this after hydration in client-side code.
130
+
131
+ ## Building
132
+
133
+ ```shell
134
+ $ pnpm build
135
+ ```
136
+
137
+ ## Contributing
138
+
139
+ Contributions are welcome. Please feel free to submit a [GitHub Issue](https://github.com/forminator/react-wire-persisted/issues) or pull request.
140
+
141
+ ### Development
142
+
143
+ ```shell
144
+ # Install dependencies
145
+ pnpm install
146
+
147
+ # Run tests
148
+ pnpm test
149
+
150
+ # Run linter
151
+ pnpm lint
152
+ ```
153
+
154
+ ## Publishing
155
+
156
+ To publish a new version to npm:
157
+
158
+ ```shell
159
+ # Build the project
160
+ pnpm build
161
+
162
+ # Bump version (choose one)
163
+ npm version patch # bug fixes (e.g., 2.1.0 -> 2.1.1)
164
+ npm version minor # new features (e.g., 2.1.0 -> 2.2.0)
165
+ npm version major # breaking changes (e.g., 2.1.0 -> 3.0.0)
166
+
167
+ # Push changes and tags
168
+ git push
169
+ git push --tags
170
+
171
+ # Publish to npm
172
+ npm publish
173
+ ```
81
174
 
82
175
  ## Miscellaneous
83
176
 
@@ -0,0 +1,197 @@
1
+ import { ReactNode } from 'react';
2
+ import * as utils from '@/utils';
3
+ import { Wire } from '@forminator/react-wire';
4
+
5
+ declare type AnyStorage = InternalStorage | Storage;
6
+
7
+ /**
8
+ * Creates a persisted Wire using the `RWPStorageProvider` that is currently set
9
+ * Defaults to `localStorage` via `LocalStorageProvider`
10
+ *
11
+ * @param {String} key Unique key for storing this value
12
+ * @param {*} value Initial value of this Wire
13
+ * @returns A new Wire decorated with localStorage functionality
14
+ */
15
+ export declare const createPersistedWire: <T = null>(key: string, value?: T) => PersistedWire<T>;
16
+
17
+ export declare const defaultOptions: RWPOptions;
18
+
19
+ export declare const getNamespace: () => string | null;
20
+
21
+ export declare const getOptions: () => RWPOptions;
22
+
23
+ export declare const getStorage: () => RWPStorageProvider;
24
+
25
+ export declare const HydrationProvider: ({ children, onUpgrade, autoUpgrade }: HydrationProviderProps) => ReactNode;
26
+
27
+ /**
28
+ * A Next.js App Router compatible component that handles automatic storage upgrade
29
+ * after hydration. Use this in your root layout.
30
+ *
31
+ * @param {Object} props Component props
32
+ * @param {React.ReactNode} props.children Child components to render
33
+ * @param {Function} props.onUpgrade Callback called when storage is upgraded
34
+ * @param {Boolean} props.autoUpgrade Whether to automatically upgrade storage (default: true)
35
+ */
36
+ declare type HydrationProviderProps = {
37
+ children: ReactNode;
38
+ onUpgrade?: () => void;
39
+ autoUpgrade?: boolean;
40
+ };
41
+
42
+ declare interface InternalStorage {
43
+ getItem: (key: string) => string | null;
44
+ setItem: (key: string, value: string) => void;
45
+ removeItem: (key: string) => void;
46
+ }
47
+
48
+ /**
49
+ * A storage provider for `localStorage`
50
+ * @see `RWPStorageProvider.ts` for documentation
51
+ */
52
+ export declare class LocalStorageProvider extends RWPStorageProvider {
53
+ storage: AnyStorage;
54
+ private _isUsingFakeStorage;
55
+ constructor(namespace: string, registry?: Record<string, unknown>);
56
+ getStorage(): AnyStorage;
57
+ setNamespace(namespace: string): void;
58
+ getItem(key: string): any;
59
+ setItem(key: string, value: unknown): void;
60
+ removeItem(key: string, fromRegistry?: boolean): void;
61
+ getAll(): Record<string, unknown>;
62
+ _resetAll(useInitialValues?: boolean, excludedKeys?: string[], clearRegistry?: boolean): void;
63
+ resetAll(excludedKeys?: string[], clearRegistry?: boolean): void;
64
+ removeAll(excludedKeys?: string[], clearRegistry?: boolean): void;
65
+ /**
66
+ * Attempt to upgrade from fake storage to real localStorage
67
+ * This is useful for hydration scenarios
68
+ */
69
+ upgradeToRealStorage(): boolean;
70
+ /**
71
+ * Check if currently using fake storage
72
+ */
73
+ isUsingFakeStorage(): boolean;
74
+ }
75
+
76
+ export declare class MemoryStorageProvider extends LocalStorageProvider {
77
+ constructor(namespace: string, registry?: Record<string, unknown>);
78
+ getStorage(): InternalStorage;
79
+ }
80
+
81
+ declare type PersistedWire<T> = Wire<T>;
82
+
83
+ declare type RWPOptions = {
84
+ logging: {
85
+ enabled: boolean;
86
+ };
87
+ storageProvider?: typeof RWPStorageProvider;
88
+ };
89
+
90
+ /**
91
+ * Base class to allow storage access
92
+ * @see `LocalStorageProvider.ts` for an example implementation
93
+ */
94
+ /** biome-ignore-all lint/correctness/noUnusedFunctionParameters: WIP next PR will switch to TypeScript */
95
+ export declare abstract class RWPStorageProvider {
96
+ namespace: string | null;
97
+ registry: Record<string, unknown>;
98
+ /**
99
+ * Initializes the class
100
+ * @param {String} namespace Namespace to prefix all keys with. Mostly used for the logging and reset functions
101
+ * @param {Object} registry (Optional) Initialize the storage provider with an existing registry
102
+ */
103
+ protected constructor(namespace: string, registry: Record<string, unknown>);
104
+ /**
105
+ * Sets the namespace for this storage provider, and migrates
106
+ * all stored values to the new namespace
107
+ * @param {String} namespace New namespace for this storage provider
108
+ */
109
+ abstract setNamespace(namespace: string | null): void;
110
+ /**
111
+ * Registers an item with its initial value. This is used for logging, resetting, etc.
112
+ * @param {String} key InternalStorage item's key
113
+ * @param {*} initialValue InternalStorage item's initial value
114
+ */
115
+ register<T>(key: string, initialValue: T | null): void;
116
+ /**
117
+ * Reads an item from storage
118
+ * @param {String} key Key for the item to retrieve
119
+ */
120
+ abstract getItem<T>(key: string): T | null;
121
+ /**
122
+ * Stores a value
123
+ * @param {String} key Item's storage key
124
+ * @param {String} value Item's value to store
125
+ */
126
+ abstract setItem<T>(key: string, value: T | null): void;
127
+ /**
128
+ * Removes an item from storage
129
+ * @param {String} key Item's storage key
130
+ * @param {Boolean} fromRegistry (Optional) If the item should also be removed from the registry
131
+ */
132
+ abstract removeItem(key: string, fromRegistry: boolean): void;
133
+ /**
134
+ * Gets all stored keys and values
135
+ * If a `namespace` was set, only keys prefixed with the namespace will be returned
136
+ */
137
+ abstract getAll(): Record<string, unknown>;
138
+ /**
139
+ *
140
+ * @param {Boolean} useInitialValues If values should be replaced with their initial values. If false, keys are removed
141
+ * @param {String[]} excludedKeys (Optional) List of keys to exclude
142
+ * @param {Boolean} clearRegistry (Optional) If the registry should also be cleared
143
+ */
144
+ abstract _resetAll(useInitialValues: boolean, excludedKeys: string[], clearRegistry: boolean): void;
145
+ /**
146
+ * Resets all values to their initial values
147
+ * If a `namespace` is set, only keys prefixed with the namespace will be reset
148
+ * @param {String[]} excludedKeys (Optional) List of keys to exclude
149
+ */
150
+ abstract resetAll(excludedKeys: string[]): void;
151
+ /**
152
+ * Removes all items from local storage.
153
+ * If a `namespace` is set, only keys prefixed with the namespace will be removed
154
+ * @param {String[]} excludedKeys (Optional) List of keys to exclude
155
+ */
156
+ abstract removeAll(excludedKeys: string[]): void;
157
+ upgradeToRealStorage(): boolean;
158
+ isUsingFakeStorage(): boolean;
159
+ }
160
+
161
+ /**
162
+ * Sets the namespace for the storage provider
163
+ *
164
+ * @param {String} namespace The namespace for the storage provider
165
+ */
166
+ export declare const setNamespace: (namespace: string) => void;
167
+
168
+ export declare const setOptions: (value: Partial<RWPOptions>) => void;
169
+
170
+ /**
171
+ * Attempts to upgrade the storage provider from fake storage to real localStorage
172
+ * This should be called on the client side after hydration
173
+ *
174
+ * @returns true if upgrade was successful
175
+ */
176
+ export declare const upgradeStorage: () => boolean;
177
+
178
+ /**
179
+ * React hook that handles automatic storage upgrade after hydration
180
+ * This should be used in the root component of your application
181
+ *
182
+ * @param {Object} options Configuration options
183
+ * @param {Boolean} options.autoUpgrade Whether to automatically upgrade storage (default: true)
184
+ * @param {Function} options.onUpgrade Callback called when storage is upgraded
185
+ */
186
+ export declare const useHydration: (options?: UseHydrationOptions) => {
187
+ hasUpgraded: boolean;
188
+ };
189
+
190
+ export declare type UseHydrationOptions = {
191
+ autoUpgrade?: boolean;
192
+ onUpgrade?: () => void;
193
+ };
194
+
195
+ export { utils }
196
+
197
+ export { }