nusm 0.1.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/LICENSE +21 -0
- package/README.md +240 -0
- package/dist/adapters/indexDbAdapter.d.ts +3 -0
- package/dist/adapters/indexDbAdapter.d.ts.map +1 -0
- package/dist/adapters/indexDbAdapter.js +53 -0
- package/dist/adapters/indexDbAdapter.js.map +1 -0
- package/dist/adapters/localStorageAdapter.d.ts +3 -0
- package/dist/adapters/localStorageAdapter.d.ts.map +1 -0
- package/dist/adapters/localStorageAdapter.js +6 -0
- package/dist/adapters/localStorageAdapter.js.map +1 -0
- package/dist/adapters/sessionStorageAdapter.d.ts +3 -0
- package/dist/adapters/sessionStorageAdapter.d.ts.map +1 -0
- package/dist/adapters/sessionStorageAdapter.js +6 -0
- package/dist/adapters/sessionStorageAdapter.js.map +1 -0
- package/dist/adapters/storageAdapter.d.ts +3 -0
- package/dist/adapters/storageAdapter.d.ts.map +1 -0
- package/dist/adapters/storageAdapter.js +62 -0
- package/dist/adapters/storageAdapter.js.map +1 -0
- package/dist/core/createNusmStore.d.ts +3 -0
- package/dist/core/createNusmStore.d.ts.map +1 -0
- package/dist/core/createNusmStore.js +491 -0
- package/dist/core/createNusmStore.js.map +1 -0
- package/dist/devtools/client.d.ts +15 -0
- package/dist/devtools/client.d.ts.map +1 -0
- package/dist/devtools/client.js +21 -0
- package/dist/devtools/client.js.map +1 -0
- package/dist/devtools/plugin.d.ts +3 -0
- package/dist/devtools/plugin.d.ts.map +1 -0
- package/dist/devtools/plugin.js +57 -0
- package/dist/devtools/plugin.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/react/index.d.ts +11 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +32 -0
- package/dist/react/index.js.map +1 -0
- package/dist/types.d.ts +112 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +30 -0
- package/dist/utils.js.map +1 -0
- package/package.json +96 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 nusm contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="./logo.svg" alt="nusm" height="100" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# nusm
|
|
6
|
+
Non Uniform State Manager (nusm) > Pronounced **noose em** (/ˈnuːs əm/)
|
|
7
|
+
is a persistence-ready wrapper around
|
|
8
|
+
[@tanstack/store](https://github.com/TanStack/store) with adapter-based storage
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- Same store semantics as @tanstack/store
|
|
13
|
+
- Optional persistence via adapters
|
|
14
|
+
- Entire-store or slice-based persistence
|
|
15
|
+
- Async hydration with deep merge
|
|
16
|
+
- Debounced persistence via @tanstack/pacer
|
|
17
|
+
- Adapter events for cross-tab or external updates
|
|
18
|
+
- React hooks (via `nusm/react`)
|
|
19
|
+
- @tanstack/devtools event support (panel coming soon)
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
bun install `nusm`
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import { createNusmStore, createLocalStorageAdapter } from 'nusm'
|
|
31
|
+
|
|
32
|
+
const store = createNusmStore(
|
|
33
|
+
{ count: 0 },
|
|
34
|
+
{
|
|
35
|
+
storeId: 'counter',
|
|
36
|
+
adapter: createLocalStorageAdapter(),
|
|
37
|
+
persist: { strategy: 'entire' },
|
|
38
|
+
},
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
await store.ready
|
|
42
|
+
store.setState((state) => ({ count: state.count + 1 }))
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## API
|
|
46
|
+
|
|
47
|
+
### `createNusmStore(initialState, options?)`
|
|
48
|
+
|
|
49
|
+
Creates a nusm-backed store.
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
import { createNusmStore } from 'nusm'
|
|
53
|
+
|
|
54
|
+
const nusm = createNusmStore(initialState, {
|
|
55
|
+
storeId: 'settings',
|
|
56
|
+
adapter,
|
|
57
|
+
persist: {
|
|
58
|
+
strategy: 'entire',
|
|
59
|
+
},
|
|
60
|
+
})
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Return value:
|
|
64
|
+
|
|
65
|
+
- A @tanstack/store instance extended with `ready` (resolves when hydration completes).
|
|
66
|
+
|
|
67
|
+
### Persistence strategies
|
|
68
|
+
|
|
69
|
+
**Entire store**
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
persist: { strategy: 'entire' }
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Slices**
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
persist: {
|
|
79
|
+
strategy: 'slices',
|
|
80
|
+
slices: [
|
|
81
|
+
{
|
|
82
|
+
key: 'todos',
|
|
83
|
+
select: (state) => state.todos,
|
|
84
|
+
apply: (state, sliceValue) => ({ ...state, todos: sliceValue }),
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Hydration configuration
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
persist: {
|
|
94
|
+
strategy: 'entire',
|
|
95
|
+
hydrate: {
|
|
96
|
+
discardPersisted: false,
|
|
97
|
+
validate: (persisted) => ({ ok: true, value: persisted }),
|
|
98
|
+
merge: ({ initial, persisted }) => ({ ...initial, ...persisted }),
|
|
99
|
+
},
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Adapters
|
|
104
|
+
|
|
105
|
+
Adapters control persistence. They define how nusm reads/writes state and how
|
|
106
|
+
external changes (for example, another tab) are observed.
|
|
107
|
+
|
|
108
|
+
### Adapter interface
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
type NusmAdapter = {
|
|
112
|
+
name: string
|
|
113
|
+
getItem(key: string): unknown | null | Promise<unknown | null>
|
|
114
|
+
setItem(key: string, value: unknown): void | Promise<void>
|
|
115
|
+
removeItem(key: string): void | Promise<void>
|
|
116
|
+
getAllKeys?(): string[] | Promise<string[]>
|
|
117
|
+
clear?(): void | Promise<void>
|
|
118
|
+
subscribe?(listener: (event: { type: 'set' | 'remove' | 'clear'; key?: string }) => void): () => void
|
|
119
|
+
resolveKey?(params: { storeId: string; sliceKey?: string; kind: 'entire' | 'slice' }): string
|
|
120
|
+
pacer?: false | { wait?: number; maxWait?: number; leading?: boolean; trailing?: boolean }
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Notes:
|
|
125
|
+
|
|
126
|
+
- `getAllKeys` enables more complete persisted snapshots.
|
|
127
|
+
- `resolveKey` lets you control key layout. When omitted, nusm uses
|
|
128
|
+
`nusm:<storeId>:entire` and `nusm:<storeId>:slice:<sliceKey>`.
|
|
129
|
+
- `subscribe` should emit adapter events for cross-tab or external updates.
|
|
130
|
+
- `pacer` controls debouncing of writes. Use `false` to write immediately.
|
|
131
|
+
|
|
132
|
+
### Creating a custom adapter
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
const memoryAdapter: NusmAdapter = {
|
|
136
|
+
name: 'memory',
|
|
137
|
+
getItem: (key) => store.get(key) ?? null,
|
|
138
|
+
setItem: (key, value) => store.set(key, value),
|
|
139
|
+
removeItem: (key) => store.delete(key),
|
|
140
|
+
getAllKeys: () => Array.from(store.keys()),
|
|
141
|
+
resolveKey: ({ storeId, kind, sliceKey }) =>
|
|
142
|
+
kind === 'entire'
|
|
143
|
+
? `nusm:${storeId}:entire`
|
|
144
|
+
: `nusm:${storeId}:slice:${sliceKey}`,
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Local Storage
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
import { createLocalStorageAdapter } from 'nusm'
|
|
152
|
+
|
|
153
|
+
const adapter = createLocalStorageAdapter()
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Options:
|
|
157
|
+
|
|
158
|
+
- `storage`: a `Storage`-like implementation (defaults to `window.localStorage`).
|
|
159
|
+
- `prefix`: key prefix (default: `nusm`).
|
|
160
|
+
- `serialize`: custom serializer (default: `superjson.stringify`).
|
|
161
|
+
- `deserialize`: custom deserializer (default: `superjson.parse`).
|
|
162
|
+
- `pacer`: persistence debouncer configuration.
|
|
163
|
+
|
|
164
|
+
### Session Storage
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
import { createSessionStorageAdapter } from 'nusm'
|
|
168
|
+
|
|
169
|
+
const adapter = createSessionStorageAdapter()
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Options:
|
|
173
|
+
|
|
174
|
+
- `storage`: a `Storage`-like implementation (defaults to `window.sessionStorage`).
|
|
175
|
+
- `prefix`: key prefix (default: `nusm`).
|
|
176
|
+
- `serialize`: custom serializer (default: `superjson.stringify`).
|
|
177
|
+
- `deserialize`: custom deserializer (default: `superjson.parse`).
|
|
178
|
+
- `pacer`: persistence debouncer configuration.
|
|
179
|
+
|
|
180
|
+
### IndexDB
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
import { createIndexDbAdapter } from 'nusm'
|
|
184
|
+
|
|
185
|
+
const adapter = createIndexDbAdapter({ dbName: 'my-db' })
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Options:
|
|
189
|
+
|
|
190
|
+
- `dbName`: database name (default: `nusm`).
|
|
191
|
+
- `storeName`: object store name (default: `nusm`).
|
|
192
|
+
- `version`: database version (default: `1`).
|
|
193
|
+
- `serialize`: custom serializer (default: `superjson.stringify`).
|
|
194
|
+
- `deserialize`: custom deserializer (default: `superjson.parse`).
|
|
195
|
+
- `pacer`: persistence debouncer configuration (default: trailing, 100ms).
|
|
196
|
+
|
|
197
|
+
## React Hooks
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
import { useStore } from 'nusm/react'
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
`useStore` uses React 19's `useSyncExternalStore` and supports selectors and
|
|
204
|
+
configurable equality checks.
|
|
205
|
+
|
|
206
|
+
### `useStore(store, selector?, options?)`
|
|
207
|
+
|
|
208
|
+
Arguments:
|
|
209
|
+
|
|
210
|
+
- `store`: a Nusm store instance returned by `createNusmStore`.
|
|
211
|
+
- `selector` (optional): function that receives the full state and returns the
|
|
212
|
+
selected slice. Defaults to identity (returns full state).
|
|
213
|
+
- `options` (optional): configuration object with:
|
|
214
|
+
- `equal`: when `true`, uses deep equality (`fast-equals` `deepEqual`). When
|
|
215
|
+
`false` or omitted, uses shallow equality (`fast-equals` `shallowEqual`).
|
|
216
|
+
|
|
217
|
+
Example:
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
const store = createNusmStore({ user: { name: 'Ada' } })
|
|
221
|
+
|
|
222
|
+
const name = useStore(store, (state) => state.user.name)
|
|
223
|
+
const user = useStore(store, (state) => state.user, { equal: true })
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Tests
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
bun test
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Build
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
bun run build
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## License
|
|
239
|
+
|
|
240
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexDbAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/indexDbAdapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AA+CnE,eAAO,MAAM,oBAAoB,GAC/B,UAAU,qBAAqB,KAC9B,WAsCF,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import superjson from "superjson";
|
|
2
|
+
const openIndexDb = (dbName, storeName, version) => {
|
|
3
|
+
return new Promise((resolve, reject) => {
|
|
4
|
+
const request = indexedDB.open(dbName, version);
|
|
5
|
+
request.onerror = () => reject(request.error);
|
|
6
|
+
request.onupgradeneeded = () => {
|
|
7
|
+
const db = request.result;
|
|
8
|
+
if (!db.objectStoreNames.contains(storeName)) {
|
|
9
|
+
db.createObjectStore(storeName);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
request.onsuccess = () => resolve(request.result);
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
const withStore = async (dbName, storeName, mode, action) => {
|
|
16
|
+
const db = await openIndexDb(dbName, storeName, 1);
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
18
|
+
const tx = db.transaction(storeName, mode);
|
|
19
|
+
const store = tx.objectStore(storeName);
|
|
20
|
+
const request = action(store);
|
|
21
|
+
request.onerror = () => reject(request.error);
|
|
22
|
+
request.onsuccess = () => resolve(request.result);
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
const defaultResolveKey = (params) => {
|
|
26
|
+
if (params.kind === "entire") {
|
|
27
|
+
return `nusm:${params.storeId}:entire`;
|
|
28
|
+
}
|
|
29
|
+
return `nusm:${params.storeId}:slice:${params.sliceKey}`;
|
|
30
|
+
};
|
|
31
|
+
export const createIndexDbAdapter = (options) => {
|
|
32
|
+
if (typeof indexedDB === "undefined") {
|
|
33
|
+
throw new Error("IndexDB adapter requires a browser environment.");
|
|
34
|
+
}
|
|
35
|
+
const dbName = options?.dbName ?? "nusm";
|
|
36
|
+
const storeName = options?.storeName ?? "nusm";
|
|
37
|
+
const serialize = options?.serialize ?? ((value) => superjson.stringify(value));
|
|
38
|
+
const deserialize = options?.deserialize ?? ((raw) => superjson.parse(raw));
|
|
39
|
+
return {
|
|
40
|
+
clear: () => withStore(dbName, storeName, "readwrite", (store) => store.clear()).then(() => undefined),
|
|
41
|
+
getAllKeys: async () => {
|
|
42
|
+
const keys = await withStore(dbName, storeName, "readonly", (store) => store.getAllKeys());
|
|
43
|
+
return keys.map((key) => String(key));
|
|
44
|
+
},
|
|
45
|
+
getItem: (key) => withStore(dbName, storeName, "readonly", (store) => store.get(key)).then((raw) => (raw == null ? null : deserialize(String(raw)))),
|
|
46
|
+
name: "indexdb",
|
|
47
|
+
pacer: options?.pacer ?? { trailing: true, wait: 100 },
|
|
48
|
+
removeItem: (key) => withStore(dbName, storeName, "readwrite", (store) => store.delete(key)).then(() => undefined),
|
|
49
|
+
resolveKey: defaultResolveKey,
|
|
50
|
+
setItem: (key, value) => withStore(dbName, storeName, "readwrite", (store) => store.put(serialize(value), key)).then(() => undefined),
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=indexDbAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexDbAdapter.js","sourceRoot":"","sources":["../../src/adapters/indexDbAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"localStorageAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/localStorageAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAGnE,eAAO,MAAM,yBAAyB,GACpC,UAAU,qBAAqB,KAC9B,WAQA,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { createStorageAdapter } from "./storageAdapter";
|
|
2
|
+
export const createLocalStorageAdapter = (options) => createStorageAdapter("localStorage", typeof window === "undefined" ? undefined : window.localStorage, {
|
|
3
|
+
pacer: { trailing: true, wait: 50 },
|
|
4
|
+
...options,
|
|
5
|
+
});
|
|
6
|
+
//# sourceMappingURL=localStorageAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"localStorageAdapter.js","sourceRoot":"","sources":["../../src/adapters/localStorageAdapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,OAA+B,EAClB,EAAE,CACf,oBAAoB,CAClB,cAAc,EACd,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,EAC/D;IACE,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE;IACnC,GAAG,OAAO;CACX,CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionStorageAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/sessionStorageAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAGnE,eAAO,MAAM,2BAA2B,GACtC,UAAU,qBAAqB,KAC9B,WAQA,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { createStorageAdapter } from "./storageAdapter";
|
|
2
|
+
export const createSessionStorageAdapter = (options) => createStorageAdapter("sessionStorage", typeof window === "undefined" ? undefined : window.sessionStorage, {
|
|
3
|
+
pacer: { trailing: true, wait: 50 },
|
|
4
|
+
...options,
|
|
5
|
+
});
|
|
6
|
+
//# sourceMappingURL=sessionStorageAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionStorageAdapter.js","sourceRoot":"","sources":["../../src/adapters/sessionStorageAdapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,CAAC,MAAM,2BAA2B,GAAG,CACzC,OAA+B,EAClB,EAAE,CACf,oBAAoB,CAClB,gBAAgB,EAChB,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,EACjE;IACE,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE;IACnC,GAAG,OAAO;CACX,CACF,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { NusmAdapter, StorageAdapterOptions, StorageLike } from "../types";
|
|
2
|
+
export declare const createStorageAdapter: (name: string, defaultStorage: StorageLike | undefined, options?: StorageAdapterOptions) => NusmAdapter;
|
|
3
|
+
//# sourceMappingURL=storageAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storageAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/storageAdapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,WAAW,EACX,qBAAqB,EACrB,WAAW,EACZ,MAAM,UAAU,CAAC;AAElB,eAAO,MAAM,oBAAoB,GAC/B,MAAM,MAAM,EACZ,gBAAgB,WAAW,GAAG,SAAS,EACvC,UAAU,qBAAqB,KAC9B,WAmEF,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import superjson from "superjson";
|
|
2
|
+
export const createStorageAdapter = (name, defaultStorage, options) => {
|
|
3
|
+
const storage = options?.storage ?? defaultStorage;
|
|
4
|
+
if (!storage) {
|
|
5
|
+
throw new Error(`${name} adapter requires a storage implementation.`);
|
|
6
|
+
}
|
|
7
|
+
const prefix = options?.prefix ?? "nusm";
|
|
8
|
+
const serialize = options?.serialize ?? ((value) => superjson.stringify(value));
|
|
9
|
+
const deserialize = options?.deserialize ?? ((raw) => superjson.parse(raw));
|
|
10
|
+
const resolveKey = (params) => {
|
|
11
|
+
if (params.kind === "entire") {
|
|
12
|
+
return `${prefix}:${params.storeId}:entire`;
|
|
13
|
+
}
|
|
14
|
+
return `${prefix}:${params.storeId}:slice:${params.sliceKey}`;
|
|
15
|
+
};
|
|
16
|
+
const getAllKeys = () => {
|
|
17
|
+
if (typeof storage.length !== "number" || !storage.key)
|
|
18
|
+
return [];
|
|
19
|
+
const keys = [];
|
|
20
|
+
for (let i = 0; i < storage.length; i += 1) {
|
|
21
|
+
const key = storage.key(i);
|
|
22
|
+
if (key)
|
|
23
|
+
keys.push(key);
|
|
24
|
+
}
|
|
25
|
+
return keys;
|
|
26
|
+
};
|
|
27
|
+
const subscribe = (listener) => {
|
|
28
|
+
if (typeof window === "undefined" || !("addEventListener" in window)) {
|
|
29
|
+
return () => undefined;
|
|
30
|
+
}
|
|
31
|
+
const handler = (event) => {
|
|
32
|
+
if (!event.key)
|
|
33
|
+
return;
|
|
34
|
+
if (!event.key.startsWith(prefix))
|
|
35
|
+
return;
|
|
36
|
+
if (event.newValue === null) {
|
|
37
|
+
listener({ key: event.key, type: "remove" });
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
listener({ key: event.key, type: "set" });
|
|
41
|
+
};
|
|
42
|
+
window.addEventListener("storage", handler);
|
|
43
|
+
return () => window.removeEventListener("storage", handler);
|
|
44
|
+
};
|
|
45
|
+
return {
|
|
46
|
+
clear: storage.clear ? () => storage.clear?.() : undefined,
|
|
47
|
+
getAllKeys,
|
|
48
|
+
getItem: (key) => {
|
|
49
|
+
const raw = storage.getItem(key);
|
|
50
|
+
return raw == null ? null : deserialize(raw);
|
|
51
|
+
},
|
|
52
|
+
name,
|
|
53
|
+
pacer: options?.pacer,
|
|
54
|
+
removeItem: (key) => storage.removeItem(key),
|
|
55
|
+
resolveKey,
|
|
56
|
+
setItem: (key, value) => {
|
|
57
|
+
storage.setItem(key, serialize(value));
|
|
58
|
+
},
|
|
59
|
+
subscribe,
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=storageAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storageAdapter.js","sourceRoot":"","sources":["../../src/adapters/storageAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createNusmStore.d.ts","sourceRoot":"","sources":["../../src/core/createNusmStore.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,sBAAsB,EAItB,SAAS,EACV,MAAM,UAAU,CAAC;AAwDlB,wBAAgB,eAAe,CAAC,MAAM,EACpC,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,sBAAsB,CAAC,MAAM,CAAC,GACvC,SAAS,CAAC,MAAM,CAAC,CAggBnB"}
|