@esportsplus/web-storage 0.3.5 → 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 +248 -0
- package/build/constants.d.ts +3 -1
- package/build/constants.js +2 -0
- package/build/drivers/localstorage.d.ts +1 -0
- package/build/drivers/localstorage.js +10 -2
- package/build/drivers/memory.d.ts +16 -0
- package/build/drivers/memory.js +64 -0
- package/build/drivers/sessionstorage.d.ts +20 -0
- package/build/drivers/sessionstorage.js +102 -0
- package/build/index.d.ts +12 -2
- package/build/index.js +271 -31
- package/build/lz.d.ts +3 -0
- package/build/lz.js +134 -0
- package/build/types.d.ts +16 -2
- package/package.json +6 -2
- package/src/constants.ts +3 -1
- package/src/drivers/localstorage.ts +13 -2
- package/src/drivers/memory.ts +92 -0
- package/src/drivers/sessionstorage.ts +142 -0
- package/src/index.ts +420 -39
- package/src/lz.ts +192 -0
- package/src/types.ts +23 -2
- package/storage/test-audit-web-storage.md +74 -0
- package/tests/drivers/indexeddb.ts +297 -0
- package/tests/drivers/localstorage.ts +376 -0
- package/tests/drivers/memory.ts +257 -0
- package/tests/drivers/sessionstorage.ts +375 -0
- package/tests/index.ts +1871 -0
- package/tests/lz.ts +324 -0
- package/vitest.config.ts +16 -0
package/README.md
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# @esportsplus/web-storage
|
|
2
|
+
|
|
3
|
+
Typed async storage with multiple backends, TTL, encryption, compression, subscriptions, and migrations.
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import storage, { DriverType } from '@esportsplus/web-storage';
|
|
7
|
+
|
|
8
|
+
type UserData = { name: string; preferences: { theme: string } };
|
|
9
|
+
|
|
10
|
+
let store = storage<UserData>({ name: 'app', version: 1 });
|
|
11
|
+
|
|
12
|
+
await store.set('name', 'alice');
|
|
13
|
+
await store.get('name'); // 'alice'
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pnpm add @esportsplus/web-storage
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
## Drivers
|
|
25
|
+
|
|
26
|
+
| Driver | Persistence | Compression | Use Case |
|
|
27
|
+
|--------|------------|-------------|----------|
|
|
28
|
+
| IndexedDB | Permanent | No | Default. Large data, no quota pressure |
|
|
29
|
+
| localStorage | Permanent | Yes (LZ) | Small data, 5MB limit |
|
|
30
|
+
| sessionStorage | Per-tab | Yes (LZ) | Tab-scoped state |
|
|
31
|
+
| Memory | None | No | Testing, SSR, fallback |
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
// IndexedDB (default)
|
|
35
|
+
let store = storage<T>({ name: 'app', version: 1 });
|
|
36
|
+
|
|
37
|
+
// localStorage
|
|
38
|
+
let store = storage<T>({ driver: DriverType.LocalStorage, name: 'app', version: 1 });
|
|
39
|
+
|
|
40
|
+
// sessionStorage
|
|
41
|
+
let store = storage<T>({ driver: DriverType.SessionStorage, name: 'app', version: 1 });
|
|
42
|
+
|
|
43
|
+
// Memory (non-persistent)
|
|
44
|
+
let store = storage<T>({ driver: DriverType.Memory, name: 'app', version: 1 });
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
## API
|
|
49
|
+
|
|
50
|
+
All methods are async and fully typed via `Local<T>`.
|
|
51
|
+
|
|
52
|
+
### Core CRUD
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// Set a value
|
|
56
|
+
await store.set('name', 'alice');
|
|
57
|
+
|
|
58
|
+
// Get a value
|
|
59
|
+
let name = await store.get('name'); // string | undefined
|
|
60
|
+
|
|
61
|
+
// Get with factory (lazy init — never returns undefined)
|
|
62
|
+
let name = await store.get('name', () => 'default');
|
|
63
|
+
let user = await store.get('name', async () => await fetchUser());
|
|
64
|
+
|
|
65
|
+
// Delete keys
|
|
66
|
+
await store.delete('name', 'preferences');
|
|
67
|
+
|
|
68
|
+
// Replace multiple values
|
|
69
|
+
let failed = await store.replace({ name: 'bob', preferences: { theme: 'dark' } });
|
|
70
|
+
|
|
71
|
+
// Get all entries
|
|
72
|
+
let all = await store.all();
|
|
73
|
+
|
|
74
|
+
// Get specific keys
|
|
75
|
+
let subset = await store.only('name', 'preferences');
|
|
76
|
+
|
|
77
|
+
// Count entries
|
|
78
|
+
let count = await store.count();
|
|
79
|
+
|
|
80
|
+
// List keys
|
|
81
|
+
let keys = await store.keys();
|
|
82
|
+
|
|
83
|
+
// Clear everything
|
|
84
|
+
await store.clear();
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Iteration
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
// Map over all entries
|
|
91
|
+
await store.map((value, key, i) => {
|
|
92
|
+
console.log(key, value);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Filter entries (with early stop)
|
|
96
|
+
let result = await store.filter(({ key, value, stop }) => {
|
|
97
|
+
if (key === 'name') {
|
|
98
|
+
stop(); // halt iteration
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return typeof value === 'string';
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
## TTL / Expiration
|
|
107
|
+
|
|
108
|
+
Per-key time-to-live in milliseconds. Expired entries return `undefined` and are lazily deleted.
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
// Set with 1 hour TTL
|
|
112
|
+
await store.set('session', token, { ttl: 3600000 });
|
|
113
|
+
|
|
114
|
+
// Check remaining time (-1 if no TTL or expired)
|
|
115
|
+
await store.ttl('session'); // ms remaining
|
|
116
|
+
|
|
117
|
+
// Remove TTL (make permanent)
|
|
118
|
+
await store.persist('session');
|
|
119
|
+
|
|
120
|
+
// Proactively sweep all expired entries
|
|
121
|
+
await store.cleanup();
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
## Encryption
|
|
126
|
+
|
|
127
|
+
Optional AES-GCM encryption via a secret string.
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
let store = storage<T>({ name: 'secure', version: 1 }, 'my-secret-key');
|
|
131
|
+
|
|
132
|
+
await store.set('token', 'sensitive-data'); // encrypted at rest
|
|
133
|
+
await store.get('token'); // 'sensitive-data' (decrypted)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
## Change Subscriptions
|
|
138
|
+
|
|
139
|
+
Subscribe to value changes. Returns an unsubscribe function.
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
// Per-key subscription
|
|
143
|
+
let unsubscribe = store.subscribe('name', (newValue, oldValue) => {
|
|
144
|
+
console.log(`name: ${oldValue} -> ${newValue}`);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Global subscription (all keys)
|
|
148
|
+
let unsubscribe = store.subscribe((key, newValue, oldValue) => {
|
|
149
|
+
console.log(`${String(key)} changed`);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Stop listening
|
|
153
|
+
unsubscribe();
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Fires after: `set`, `delete`, `replace`, `clear`, `cleanup`.
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
## Migrations
|
|
160
|
+
|
|
161
|
+
Run transform functions when the version number changes.
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
type V1 = { name: string };
|
|
165
|
+
type V2 = { displayName: string; name: string };
|
|
166
|
+
|
|
167
|
+
let store = storage<V2>({
|
|
168
|
+
name: 'app',
|
|
169
|
+
version: 2,
|
|
170
|
+
migrations: {
|
|
171
|
+
2: async (old) => {
|
|
172
|
+
let data = await old.all();
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
...data,
|
|
176
|
+
displayName: (data.name as string) || 'Anonymous'
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Migrations run sequentially. Version 1 to 3 runs migration 2 then migration 3. Each migration receives the current store data and returns the transformed data.
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
## Compression
|
|
187
|
+
|
|
188
|
+
localStorage and sessionStorage drivers automatically compress values >= 100 bytes using an inlined LZW compressor. No configuration needed.
|
|
189
|
+
|
|
190
|
+
- Values < 100 bytes: stored as JSON (LZ overhead not worth it)
|
|
191
|
+
- Values >= 100 bytes: LZ compressed (2-10x capacity gain on JSON)
|
|
192
|
+
- Backward compatible: existing uncompressed values read normally
|
|
193
|
+
- Runs before encryption on write, after decryption on read
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
## Factory Pattern (`get` with default)
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
// Sync factory
|
|
200
|
+
let count = await store.get('count', () => 0);
|
|
201
|
+
|
|
202
|
+
// Async factory
|
|
203
|
+
let user = await store.get('user', async () => {
|
|
204
|
+
return await fetchUser(id);
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
The factory is called only when the key is missing or expired. The produced value is persisted via a fire-and-forget `set` (caller isn't blocked by the write).
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
## Types
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
import type { Local } from '@esportsplus/web-storage';
|
|
215
|
+
import { DriverType } from '@esportsplus/web-storage';
|
|
216
|
+
|
|
217
|
+
type Options = {
|
|
218
|
+
driver?: DriverType;
|
|
219
|
+
migrations?: Record<number, MigrationFn>;
|
|
220
|
+
name: string;
|
|
221
|
+
version: number;
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
type SetOptions = {
|
|
225
|
+
ttl?: number;
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
type MigrationFn = (old: {
|
|
229
|
+
all(): Promise<Record<string, unknown>>;
|
|
230
|
+
}) => Promise<Record<string, unknown>>;
|
|
231
|
+
|
|
232
|
+
// Subscription callbacks
|
|
233
|
+
type KeyCallback<T, K extends keyof T> = (
|
|
234
|
+
newValue: T[K] | undefined,
|
|
235
|
+
oldValue: T[K] | undefined
|
|
236
|
+
) => void;
|
|
237
|
+
|
|
238
|
+
type GlobalCallback<T> = (
|
|
239
|
+
key: keyof T,
|
|
240
|
+
newValue: T[keyof T] | undefined,
|
|
241
|
+
oldValue: T[keyof T] | undefined
|
|
242
|
+
) => void;
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
## License
|
|
247
|
+
|
|
248
|
+
MIT
|
package/build/constants.d.ts
CHANGED
package/build/constants.js
CHANGED
|
@@ -2,5 +2,7 @@ var DriverType;
|
|
|
2
2
|
(function (DriverType) {
|
|
3
3
|
DriverType[DriverType["IndexedDB"] = 0] = "IndexedDB";
|
|
4
4
|
DriverType[DriverType["LocalStorage"] = 1] = "LocalStorage";
|
|
5
|
+
DriverType[DriverType["Memory"] = 2] = "Memory";
|
|
6
|
+
DriverType[DriverType["SessionStorage"] = 3] = "SessionStorage";
|
|
5
7
|
})(DriverType || (DriverType = {}));
|
|
6
8
|
export { DriverType };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { compress, decompress } from '../lz.js';
|
|
1
2
|
class LocalStorageDriver {
|
|
2
3
|
prefix;
|
|
3
4
|
constructor(name, version) {
|
|
@@ -21,12 +22,19 @@ class LocalStorageDriver {
|
|
|
21
22
|
return undefined;
|
|
22
23
|
}
|
|
23
24
|
try {
|
|
25
|
+
if (value.charCodeAt(0) === 1) {
|
|
26
|
+
return JSON.parse(decompress(value.slice(1)));
|
|
27
|
+
}
|
|
24
28
|
return JSON.parse(value);
|
|
25
29
|
}
|
|
26
30
|
catch {
|
|
27
31
|
return undefined;
|
|
28
32
|
}
|
|
29
33
|
}
|
|
34
|
+
serialize(value) {
|
|
35
|
+
let json = JSON.stringify(value);
|
|
36
|
+
return json.length >= 100 ? '\x01' + compress(json) : json;
|
|
37
|
+
}
|
|
30
38
|
async all() {
|
|
31
39
|
let keys = this.getKeys(), result = {};
|
|
32
40
|
for (let i = 0, n = keys.length; i < n; i++) {
|
|
@@ -78,12 +86,12 @@ class LocalStorageDriver {
|
|
|
78
86
|
}
|
|
79
87
|
async replace(entries) {
|
|
80
88
|
for (let i = 0, n = entries.length; i < n; i++) {
|
|
81
|
-
localStorage.setItem(this.key(entries[i][0]),
|
|
89
|
+
localStorage.setItem(this.key(entries[i][0]), this.serialize(entries[i][1]));
|
|
82
90
|
}
|
|
83
91
|
}
|
|
84
92
|
async set(key, value) {
|
|
85
93
|
try {
|
|
86
|
-
localStorage.setItem(this.key(key),
|
|
94
|
+
localStorage.setItem(this.key(key), this.serialize(value));
|
|
87
95
|
return true;
|
|
88
96
|
}
|
|
89
97
|
catch {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Driver } from '../types.js';
|
|
2
|
+
declare class MemoryDriver<T> implements Driver<T> {
|
|
3
|
+
private store;
|
|
4
|
+
constructor(name: string, _version: number);
|
|
5
|
+
all(): Promise<T>;
|
|
6
|
+
clear(): Promise<void>;
|
|
7
|
+
count(): Promise<number>;
|
|
8
|
+
delete(keys: (keyof T)[]): Promise<void>;
|
|
9
|
+
get(key: keyof T): Promise<T[keyof T] | undefined>;
|
|
10
|
+
keys(): Promise<(keyof T)[]>;
|
|
11
|
+
map(fn: (value: T[keyof T], key: keyof T, i: number) => void | Promise<void>): Promise<void>;
|
|
12
|
+
only(keys: (keyof T)[]): Promise<Map<keyof T, T[keyof T]>>;
|
|
13
|
+
replace(entries: [keyof T, T[keyof T]][]): Promise<void>;
|
|
14
|
+
set(key: keyof T, value: T[keyof T]): Promise<boolean>;
|
|
15
|
+
}
|
|
16
|
+
export { MemoryDriver };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
let stores = new Map();
|
|
2
|
+
class MemoryDriver {
|
|
3
|
+
store;
|
|
4
|
+
constructor(name, _version) {
|
|
5
|
+
let existing = stores.get(name);
|
|
6
|
+
if (existing) {
|
|
7
|
+
this.store = existing;
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
this.store = new Map();
|
|
11
|
+
stores.set(name, this.store);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
async all() {
|
|
15
|
+
let result = {};
|
|
16
|
+
for (let [key, value] of this.store) {
|
|
17
|
+
result[key] = value;
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
async clear() {
|
|
22
|
+
this.store.clear();
|
|
23
|
+
}
|
|
24
|
+
async count() {
|
|
25
|
+
return this.store.size;
|
|
26
|
+
}
|
|
27
|
+
async delete(keys) {
|
|
28
|
+
for (let i = 0, n = keys.length; i < n; i++) {
|
|
29
|
+
this.store.delete(keys[i]);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async get(key) {
|
|
33
|
+
return this.store.get(key);
|
|
34
|
+
}
|
|
35
|
+
async keys() {
|
|
36
|
+
return [...this.store.keys()];
|
|
37
|
+
}
|
|
38
|
+
async map(fn) {
|
|
39
|
+
let i = 0;
|
|
40
|
+
for (let [key, value] of this.store) {
|
|
41
|
+
await fn(value, key, i++);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async only(keys) {
|
|
45
|
+
let results = new Map();
|
|
46
|
+
for (let i = 0, n = keys.length; i < n; i++) {
|
|
47
|
+
let value = this.store.get(keys[i]);
|
|
48
|
+
if (value !== undefined) {
|
|
49
|
+
results.set(keys[i], value);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return results;
|
|
53
|
+
}
|
|
54
|
+
async replace(entries) {
|
|
55
|
+
for (let i = 0, n = entries.length; i < n; i++) {
|
|
56
|
+
this.store.set(entries[i][0], entries[i][1]);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async set(key, value) {
|
|
60
|
+
this.store.set(key, value);
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export { MemoryDriver };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Driver } from '../types.js';
|
|
2
|
+
declare class SessionStorageDriver<T> implements Driver<T> {
|
|
3
|
+
private prefix;
|
|
4
|
+
constructor(name: string, version: number);
|
|
5
|
+
private getKeys;
|
|
6
|
+
private key;
|
|
7
|
+
private parse;
|
|
8
|
+
private serialize;
|
|
9
|
+
all(): Promise<T>;
|
|
10
|
+
clear(): Promise<void>;
|
|
11
|
+
count(): Promise<number>;
|
|
12
|
+
delete(keys: (keyof T)[]): Promise<void>;
|
|
13
|
+
get(key: keyof T): Promise<T[keyof T] | undefined>;
|
|
14
|
+
keys(): Promise<(keyof T)[]>;
|
|
15
|
+
map(fn: (value: T[keyof T], key: keyof T, i: number) => void | Promise<void>): Promise<void>;
|
|
16
|
+
only(keys: (keyof T)[]): Promise<Map<keyof T, T[keyof T]>>;
|
|
17
|
+
replace(entries: [keyof T, T[keyof T]][]): Promise<void>;
|
|
18
|
+
set(key: keyof T, value: T[keyof T]): Promise<boolean>;
|
|
19
|
+
}
|
|
20
|
+
export { SessionStorageDriver };
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { compress, decompress } from '../lz.js';
|
|
2
|
+
class SessionStorageDriver {
|
|
3
|
+
prefix;
|
|
4
|
+
constructor(name, version) {
|
|
5
|
+
this.prefix = `${name}:${version}:`;
|
|
6
|
+
}
|
|
7
|
+
getKeys() {
|
|
8
|
+
let keys = [];
|
|
9
|
+
for (let i = 0, n = sessionStorage.length; i < n; i++) {
|
|
10
|
+
let key = sessionStorage.key(i);
|
|
11
|
+
if (key && key.startsWith(this.prefix)) {
|
|
12
|
+
keys.push(key.slice(this.prefix.length));
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return keys;
|
|
16
|
+
}
|
|
17
|
+
key(key) {
|
|
18
|
+
return this.prefix + String(key);
|
|
19
|
+
}
|
|
20
|
+
parse(value) {
|
|
21
|
+
if (value === null) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
if (value.charCodeAt(0) === 1) {
|
|
26
|
+
return JSON.parse(decompress(value.slice(1)));
|
|
27
|
+
}
|
|
28
|
+
return JSON.parse(value);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
serialize(value) {
|
|
35
|
+
let json = JSON.stringify(value);
|
|
36
|
+
return json.length >= 100 ? '\x01' + compress(json) : json;
|
|
37
|
+
}
|
|
38
|
+
async all() {
|
|
39
|
+
let keys = this.getKeys(), result = {};
|
|
40
|
+
for (let i = 0, n = keys.length; i < n; i++) {
|
|
41
|
+
let value = this.parse(sessionStorage.getItem(this.prefix + keys[i]));
|
|
42
|
+
if (value !== undefined) {
|
|
43
|
+
result[keys[i]] = value;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
async clear() {
|
|
49
|
+
let keys = this.getKeys();
|
|
50
|
+
for (let i = 0, n = keys.length; i < n; i++) {
|
|
51
|
+
sessionStorage.removeItem(this.prefix + keys[i]);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async count() {
|
|
55
|
+
return this.getKeys().length;
|
|
56
|
+
}
|
|
57
|
+
async delete(keys) {
|
|
58
|
+
for (let i = 0, n = keys.length; i < n; i++) {
|
|
59
|
+
sessionStorage.removeItem(this.key(keys[i]));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async get(key) {
|
|
63
|
+
return this.parse(sessionStorage.getItem(this.key(key)));
|
|
64
|
+
}
|
|
65
|
+
async keys() {
|
|
66
|
+
return this.getKeys();
|
|
67
|
+
}
|
|
68
|
+
async map(fn) {
|
|
69
|
+
let keys = this.getKeys();
|
|
70
|
+
for (let i = 0, n = keys.length; i < n; i++) {
|
|
71
|
+
let value = this.parse(sessionStorage.getItem(this.prefix + keys[i]));
|
|
72
|
+
if (value !== undefined) {
|
|
73
|
+
await fn(value, keys[i], i);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async only(keys) {
|
|
78
|
+
let results = new Map();
|
|
79
|
+
for (let i = 0, n = keys.length; i < n; i++) {
|
|
80
|
+
let value = this.parse(sessionStorage.getItem(this.key(keys[i])));
|
|
81
|
+
if (value !== undefined) {
|
|
82
|
+
results.set(keys[i], value);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return results;
|
|
86
|
+
}
|
|
87
|
+
async replace(entries) {
|
|
88
|
+
for (let i = 0, n = entries.length; i < n; i++) {
|
|
89
|
+
sessionStorage.setItem(this.key(entries[i][0]), this.serialize(entries[i][1]));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async set(key, value) {
|
|
93
|
+
try {
|
|
94
|
+
sessionStorage.setItem(this.key(key), this.serialize(value));
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export { SessionStorageDriver };
|
package/build/index.d.ts
CHANGED
|
@@ -1,20 +1,30 @@
|
|
|
1
|
-
import type { Filter, Options } from './types.js';
|
|
1
|
+
import type { Filter, GlobalCallback, KeyCallback, Options, SetOptions } from './types.js';
|
|
2
2
|
declare class Local<T> {
|
|
3
3
|
private driver;
|
|
4
|
+
private globals;
|
|
5
|
+
private listeners;
|
|
6
|
+
private ready;
|
|
4
7
|
private secret;
|
|
8
|
+
private version;
|
|
5
9
|
constructor(options: Options, secret?: string);
|
|
6
10
|
all(): Promise<T>;
|
|
7
11
|
clear(): Promise<void>;
|
|
12
|
+
cleanup(): Promise<void>;
|
|
8
13
|
count(): Promise<number>;
|
|
9
14
|
delete(...keys: (keyof T)[]): Promise<void>;
|
|
10
15
|
filter(fn: Filter<T>): Promise<T>;
|
|
11
16
|
get(key: keyof T): Promise<T[keyof T] | undefined>;
|
|
17
|
+
get(key: keyof T, factory: () => T[keyof T] | Promise<T[keyof T]>): Promise<T[keyof T]>;
|
|
12
18
|
keys(): Promise<(keyof T)[]>;
|
|
13
19
|
length(): Promise<number>;
|
|
14
20
|
map(fn: (value: T[keyof T], key: keyof T, i: number) => void | Promise<void>): Promise<void>;
|
|
15
21
|
only(...keys: (keyof T)[]): Promise<T>;
|
|
22
|
+
persist(key: keyof T): Promise<boolean>;
|
|
16
23
|
replace(values: Partial<T>): Promise<string[]>;
|
|
17
|
-
set(key: keyof T, value: T[keyof T]): Promise<boolean>;
|
|
24
|
+
set(key: keyof T, value: T[keyof T], options?: SetOptions): Promise<boolean>;
|
|
25
|
+
subscribe(callback: GlobalCallback<T>): () => void;
|
|
26
|
+
subscribe<K extends keyof T>(key: K, callback: KeyCallback<T, K>): () => void;
|
|
27
|
+
ttl(key: keyof T): Promise<number>;
|
|
18
28
|
}
|
|
19
29
|
declare const _default: <T>(options: Options, secret?: string) => Local<T>;
|
|
20
30
|
export default _default;
|