@esportsplus/web-storage 0.3.5 → 0.4.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.
@@ -1,5 +1,7 @@
1
1
  declare enum DriverType {
2
2
  IndexedDB = 0,
3
- LocalStorage = 1
3
+ LocalStorage = 1,
4
+ Memory = 2,
5
+ SessionStorage = 3
4
6
  }
5
7
  export { DriverType };
@@ -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 };
@@ -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,19 @@
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
+ all(): Promise<T>;
9
+ clear(): Promise<void>;
10
+ count(): Promise<number>;
11
+ delete(keys: (keyof T)[]): Promise<void>;
12
+ get(key: keyof T): Promise<T[keyof T] | undefined>;
13
+ keys(): Promise<(keyof T)[]>;
14
+ map(fn: (value: T[keyof T], key: keyof T, i: number) => void | Promise<void>): Promise<void>;
15
+ only(keys: (keyof T)[]): Promise<Map<keyof T, T[keyof T]>>;
16
+ replace(entries: [keyof T, T[keyof T]][]): Promise<void>;
17
+ set(key: keyof T, value: T[keyof T]): Promise<boolean>;
18
+ }
19
+ export { SessionStorageDriver };
@@ -0,0 +1,94 @@
1
+ class SessionStorageDriver {
2
+ prefix;
3
+ constructor(name, version) {
4
+ this.prefix = `${name}:${version}:`;
5
+ }
6
+ getKeys() {
7
+ let keys = [];
8
+ for (let i = 0, n = sessionStorage.length; i < n; i++) {
9
+ let key = sessionStorage.key(i);
10
+ if (key && key.startsWith(this.prefix)) {
11
+ keys.push(key.slice(this.prefix.length));
12
+ }
13
+ }
14
+ return keys;
15
+ }
16
+ key(key) {
17
+ return this.prefix + String(key);
18
+ }
19
+ parse(value) {
20
+ if (value === null) {
21
+ return undefined;
22
+ }
23
+ try {
24
+ return JSON.parse(value);
25
+ }
26
+ catch {
27
+ return undefined;
28
+ }
29
+ }
30
+ async all() {
31
+ let keys = this.getKeys(), result = {};
32
+ for (let i = 0, n = keys.length; i < n; i++) {
33
+ let value = this.parse(sessionStorage.getItem(this.prefix + keys[i]));
34
+ if (value !== undefined) {
35
+ result[keys[i]] = value;
36
+ }
37
+ }
38
+ return result;
39
+ }
40
+ async clear() {
41
+ let keys = this.getKeys();
42
+ for (let i = 0, n = keys.length; i < n; i++) {
43
+ sessionStorage.removeItem(this.prefix + keys[i]);
44
+ }
45
+ }
46
+ async count() {
47
+ return this.getKeys().length;
48
+ }
49
+ async delete(keys) {
50
+ for (let i = 0, n = keys.length; i < n; i++) {
51
+ sessionStorage.removeItem(this.key(keys[i]));
52
+ }
53
+ }
54
+ async get(key) {
55
+ return this.parse(sessionStorage.getItem(this.key(key)));
56
+ }
57
+ async keys() {
58
+ return this.getKeys();
59
+ }
60
+ async map(fn) {
61
+ let keys = this.getKeys();
62
+ for (let i = 0, n = keys.length; i < n; i++) {
63
+ let value = this.parse(sessionStorage.getItem(this.prefix + keys[i]));
64
+ if (value !== undefined) {
65
+ await fn(value, keys[i], i);
66
+ }
67
+ }
68
+ }
69
+ async only(keys) {
70
+ let results = new Map();
71
+ for (let i = 0, n = keys.length; i < n; i++) {
72
+ let value = this.parse(sessionStorage.getItem(this.key(keys[i])));
73
+ if (value !== undefined) {
74
+ results.set(keys[i], value);
75
+ }
76
+ }
77
+ return results;
78
+ }
79
+ async replace(entries) {
80
+ for (let i = 0, n = entries.length; i < n; i++) {
81
+ sessionStorage.setItem(this.key(entries[i][0]), JSON.stringify(entries[i][1]));
82
+ }
83
+ }
84
+ async set(key, value) {
85
+ try {
86
+ sessionStorage.setItem(this.key(key), JSON.stringify(value));
87
+ return true;
88
+ }
89
+ catch {
90
+ return false;
91
+ }
92
+ }
93
+ }
94
+ 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;
package/build/index.js CHANGED
@@ -2,6 +2,15 @@ import { decrypt, encrypt } from '@esportsplus/utilities';
2
2
  import { DriverType } from './constants.js';
3
3
  import { IndexedDBDriver } from './drivers/indexeddb.js';
4
4
  import { LocalStorageDriver } from './drivers/localstorage.js';
5
+ import { MemoryDriver } from './drivers/memory.js';
6
+ import { SessionStorageDriver } from './drivers/sessionstorage.js';
7
+ const VERSION_KEY = '__version__';
8
+ function isEnvelope(value) {
9
+ return value !== null
10
+ && typeof value === 'object'
11
+ && '__e' in value
12
+ && '__v' in value;
13
+ }
5
14
  async function deserialize(value, secret) {
6
15
  if (value === undefined || value === null) {
7
16
  return undefined;
@@ -26,84 +35,267 @@ async function serialize(value, secret) {
26
35
  }
27
36
  return value;
28
37
  }
38
+ function notify(globals, listeners, key, newValue, oldValue) {
39
+ let set = listeners.get(key);
40
+ if (set) {
41
+ for (let cb of set) {
42
+ cb(newValue, oldValue);
43
+ }
44
+ }
45
+ for (let cb of globals) {
46
+ cb(key, newValue, oldValue);
47
+ }
48
+ }
49
+ function unwrap(value) {
50
+ if (isEnvelope(value)) {
51
+ return {
52
+ expired: Date.now() > value.__e,
53
+ hasTTL: true,
54
+ value: value.__v
55
+ };
56
+ }
57
+ return { expired: false, hasTTL: false, value: value };
58
+ }
59
+ async function migrate(driver, migrations, version) {
60
+ let raw = await driver.get(VERSION_KEY), stored = typeof raw === 'number' ? raw : 0;
61
+ if (stored >= version) {
62
+ return;
63
+ }
64
+ let keys = Object.keys(migrations).map(Number).filter((v) => v > stored && v <= version).sort((a, b) => a - b);
65
+ for (let i = 0, n = keys.length; i < n; i++) {
66
+ let all = await driver.all(), data = {};
67
+ for (let key in all) {
68
+ if (key !== VERSION_KEY) {
69
+ data[key] = all[key];
70
+ }
71
+ }
72
+ let transformed = await migrations[keys[i]]({ all: () => Promise.resolve(data) });
73
+ await driver.clear();
74
+ let entries = [];
75
+ for (let key in transformed) {
76
+ entries.push([key, transformed[key]]);
77
+ }
78
+ if (entries.length > 0) {
79
+ await driver.replace(entries);
80
+ }
81
+ }
82
+ await driver.set(VERSION_KEY, version);
83
+ }
29
84
  class Local {
30
85
  driver;
86
+ globals;
87
+ listeners;
88
+ ready;
31
89
  secret;
90
+ version;
32
91
  constructor(options, secret) {
92
+ this.globals = new Set();
93
+ this.listeners = new Map();
33
94
  this.secret = secret || null;
34
- let { name, version = 1 } = options;
95
+ let { migrations, name, version = 1 } = options;
96
+ this.version = version;
35
97
  if (options.driver === DriverType.LocalStorage) {
36
98
  this.driver = new LocalStorageDriver(name, version);
37
99
  }
100
+ else if (options.driver === DriverType.Memory) {
101
+ this.driver = new MemoryDriver(name, version);
102
+ }
103
+ else if (options.driver === DriverType.SessionStorage) {
104
+ this.driver = new SessionStorageDriver(name, version);
105
+ }
38
106
  else {
39
107
  this.driver = new IndexedDBDriver(name, version);
40
108
  }
109
+ if (migrations) {
110
+ this.ready = migrate(this.driver, migrations, version);
111
+ }
112
+ else {
113
+ this.ready = Promise.resolve();
114
+ }
41
115
  }
42
116
  async all() {
43
- let raw = await this.driver.all(), result = {};
117
+ await this.ready;
118
+ let expired = [], raw = await this.driver.all(), result = {};
44
119
  for (let key in raw) {
45
- let value = await deserialize(raw[key], this.secret);
46
- if (value !== undefined) {
47
- result[key] = value;
120
+ if (key === VERSION_KEY) {
121
+ continue;
122
+ }
123
+ let deserialized = await deserialize(raw[key], this.secret), unwrapped = unwrap(deserialized);
124
+ if (deserialized === undefined) {
125
+ continue;
126
+ }
127
+ if (unwrapped.expired) {
128
+ expired.push(key);
129
+ continue;
48
130
  }
131
+ result[key] = unwrapped.value;
132
+ }
133
+ if (expired.length > 0) {
134
+ this.driver.delete(expired);
49
135
  }
50
136
  return result;
51
137
  }
52
138
  async clear() {
53
- return this.driver.clear();
139
+ await this.ready;
140
+ let allData = await this.all(), keys = Object.keys(allData);
141
+ await this.driver.clear();
142
+ await this.driver.set(VERSION_KEY, this.version);
143
+ for (let i = 0, n = keys.length; i < n; i++) {
144
+ notify(this.globals, this.listeners, keys[i], undefined, allData[keys[i]]);
145
+ }
146
+ }
147
+ async cleanup() {
148
+ await this.ready;
149
+ let expired = [], oldValues = new Map();
150
+ await this.driver.map(async (raw, key) => {
151
+ if (key === VERSION_KEY) {
152
+ return;
153
+ }
154
+ let deserialized = await deserialize(raw, this.secret), unwrapped = unwrap(deserialized);
155
+ if (deserialized !== undefined && unwrapped.expired) {
156
+ expired.push(key);
157
+ oldValues.set(key, unwrapped.value);
158
+ }
159
+ });
160
+ if (expired.length > 0) {
161
+ await this.driver.delete(expired);
162
+ for (let i = 0, n = expired.length; i < n; i++) {
163
+ notify(this.globals, this.listeners, expired[i], undefined, oldValues.get(expired[i]));
164
+ }
165
+ }
54
166
  }
55
167
  async count() {
56
- return this.driver.count();
168
+ await this.ready;
169
+ let total = await this.driver.count(), raw = await this.driver.get(VERSION_KEY);
170
+ return raw !== undefined ? total - 1 : total;
57
171
  }
58
172
  async delete(...keys) {
59
- return this.driver.delete(keys);
173
+ await this.ready;
174
+ let oldValues = new Map();
175
+ for (let i = 0, n = keys.length; i < n; i++) {
176
+ let raw = await this.driver.get(keys[i]), deserialized = await deserialize(raw, this.secret), unwrapped = unwrap(deserialized);
177
+ oldValues.set(keys[i], deserialized === undefined ? undefined : unwrapped.value);
178
+ }
179
+ await this.driver.delete(keys);
180
+ for (let i = 0, n = keys.length; i < n; i++) {
181
+ notify(this.globals, this.listeners, keys[i], undefined, oldValues.get(keys[i]));
182
+ }
60
183
  }
61
184
  async filter(fn) {
62
- let i = 0, result = {}, stop = () => { stopped = true; }, stopped = false;
185
+ await this.ready;
186
+ let expired = [], i = 0, result = {}, stop = () => { stopped = true; }, stopped = false;
63
187
  await this.driver.map(async (raw, key) => {
64
- if (stopped) {
188
+ if (stopped || key === VERSION_KEY) {
65
189
  return;
66
190
  }
67
- let value = await deserialize(raw, this.secret);
68
- if (value === undefined) {
191
+ let deserialized = await deserialize(raw, this.secret), unwrapped = unwrap(deserialized);
192
+ if (deserialized === undefined) {
69
193
  return;
70
194
  }
71
- if (await fn({ i: i++, key, stop, value })) {
72
- result[key] = value;
195
+ if (unwrapped.expired) {
196
+ expired.push(key);
197
+ return;
198
+ }
199
+ if (await fn({ i: i++, key, stop, value: unwrapped.value })) {
200
+ result[key] = unwrapped.value;
73
201
  }
74
202
  });
203
+ if (expired.length > 0) {
204
+ this.driver.delete(expired);
205
+ }
75
206
  return result;
76
207
  }
77
- async get(key) {
78
- return deserialize(await this.driver.get(key), this.secret);
208
+ async get(key, factory) {
209
+ await this.ready;
210
+ let deserialized = await deserialize(await this.driver.get(key), this.secret), missing = false, unwrapped = unwrap(deserialized);
211
+ if (deserialized === undefined) {
212
+ missing = true;
213
+ }
214
+ else if (unwrapped.expired) {
215
+ this.driver.delete([key]);
216
+ missing = true;
217
+ }
218
+ if (missing) {
219
+ if (factory) {
220
+ let value = await factory();
221
+ this.set(key, value);
222
+ return value;
223
+ }
224
+ return undefined;
225
+ }
226
+ return unwrapped.value;
79
227
  }
80
228
  async keys() {
81
- return this.driver.keys();
229
+ await this.ready;
230
+ let all = await this.driver.keys();
231
+ return all.filter((k) => k !== VERSION_KEY);
82
232
  }
83
- length() {
84
- return this.driver.count();
233
+ async length() {
234
+ await this.ready;
235
+ return this.count();
85
236
  }
86
- map(fn) {
87
- return this.driver.map(async (raw, key, i) => {
88
- let value = await deserialize(raw, this.secret);
89
- if (value !== undefined) {
90
- await fn(value, key, i);
237
+ async map(fn) {
238
+ await this.ready;
239
+ let expired = [], j = 0;
240
+ await this.driver.map(async (raw, key) => {
241
+ if (key === VERSION_KEY) {
242
+ return;
243
+ }
244
+ let deserialized = await deserialize(raw, this.secret), unwrapped = unwrap(deserialized);
245
+ if (deserialized === undefined) {
246
+ return;
247
+ }
248
+ if (unwrapped.expired) {
249
+ expired.push(key);
250
+ return;
91
251
  }
252
+ await fn(unwrapped.value, key, j++);
92
253
  });
254
+ if (expired.length > 0) {
255
+ this.driver.delete(expired);
256
+ }
93
257
  }
94
258
  async only(...keys) {
95
- let raw = await this.driver.only(keys), result = {};
259
+ await this.ready;
260
+ let expired = [], raw = await this.driver.only(keys), result = {};
96
261
  for (let [key, value] of raw) {
97
- let deserialized = await deserialize(value, this.secret);
98
- if (deserialized !== undefined) {
99
- result[key] = deserialized;
262
+ let deserialized = await deserialize(value, this.secret), unwrapped = unwrap(deserialized);
263
+ if (deserialized === undefined) {
264
+ continue;
100
265
  }
266
+ if (unwrapped.expired) {
267
+ expired.push(key);
268
+ continue;
269
+ }
270
+ result[key] = unwrapped.value;
271
+ }
272
+ if (expired.length > 0) {
273
+ this.driver.delete(expired);
101
274
  }
102
275
  return result;
103
276
  }
277
+ async persist(key) {
278
+ await this.ready;
279
+ let raw = await this.driver.get(key), deserialized = await deserialize(raw, this.secret);
280
+ if (deserialized === undefined) {
281
+ return false;
282
+ }
283
+ let unwrapped = unwrap(deserialized);
284
+ if (unwrapped.expired) {
285
+ this.driver.delete([key]);
286
+ return false;
287
+ }
288
+ if (!unwrapped.hasTTL) {
289
+ return true;
290
+ }
291
+ return this.driver.set(key, await serialize(unwrapped.value, this.secret));
292
+ }
104
293
  async replace(values) {
105
- let entries = [], failed = [];
294
+ await this.ready;
295
+ let entries = [], failed = [], oldValues = new Map();
106
296
  for (let key in values) {
297
+ let raw = await this.driver.get(key), deserialized = await deserialize(raw, this.secret), unwrapped = unwrap(deserialized);
298
+ oldValues.set(key, deserialized === undefined ? undefined : unwrapped.value);
107
299
  try {
108
300
  entries.push([
109
301
  key,
@@ -117,16 +309,64 @@ class Local {
117
309
  if (entries.length > 0) {
118
310
  await this.driver.replace(entries);
119
311
  }
312
+ for (let i = 0, n = entries.length; i < n; i++) {
313
+ let key = entries[i][0];
314
+ notify(this.globals, this.listeners, key, values[key], oldValues.get(key));
315
+ }
120
316
  return failed;
121
317
  }
122
- async set(key, value) {
318
+ async set(key, value, options) {
319
+ await this.ready;
123
320
  try {
124
- return this.driver.set(key, await serialize(value, this.secret));
321
+ let oldRaw = await this.driver.get(key), oldDeserialized = await deserialize(oldRaw, this.secret), oldUnwrapped = unwrap(oldDeserialized), oldValue = oldDeserialized === undefined ? undefined : oldUnwrapped.value, stored;
322
+ if (options?.ttl != null && options.ttl > 0) {
323
+ let envelope = {
324
+ __e: Date.now() + options.ttl,
325
+ __v: value
326
+ };
327
+ stored = await serialize(envelope, this.secret);
328
+ }
329
+ else {
330
+ stored = await serialize(value, this.secret);
331
+ }
332
+ let result = await this.driver.set(key, stored);
333
+ notify(this.globals, this.listeners, key, value, oldValue);
334
+ return result;
125
335
  }
126
336
  catch {
127
337
  return false;
128
338
  }
129
339
  }
340
+ subscribe(keyOrCallback, callback) {
341
+ if (typeof keyOrCallback === 'function') {
342
+ let cb = keyOrCallback;
343
+ this.globals.add(cb);
344
+ return () => { this.globals.delete(cb); };
345
+ }
346
+ let cb = callback, key = keyOrCallback, set = this.listeners.get(key);
347
+ if (!set) {
348
+ set = new Set();
349
+ this.listeners.set(key, set);
350
+ }
351
+ set.add(cb);
352
+ return () => { set.delete(cb); };
353
+ }
354
+ async ttl(key) {
355
+ await this.ready;
356
+ let raw = await this.driver.get(key), deserialized = await deserialize(raw, this.secret);
357
+ if (deserialized === undefined) {
358
+ return -1;
359
+ }
360
+ if (!isEnvelope(deserialized)) {
361
+ return -1;
362
+ }
363
+ let remaining = deserialized.__e - Date.now();
364
+ if (remaining <= 0) {
365
+ this.driver.delete([key]);
366
+ return -1;
367
+ }
368
+ return remaining;
369
+ }
130
370
  }
131
371
  export default (options, secret) => {
132
372
  return new Local(options, secret);
package/build/types.d.ts CHANGED
@@ -17,9 +17,23 @@ type Filter<T> = (data: {
17
17
  stop: VoidFunction;
18
18
  value: T[keyof T];
19
19
  }) => boolean | Promise<boolean>;
20
+ type MigrationContext = {
21
+ all(): Promise<Record<string, unknown>>;
22
+ };
23
+ type MigrationFn = (old: MigrationContext) => Promise<Record<string, unknown>>;
20
24
  type Options = {
21
- driver?: DriverType.IndexedDB | DriverType.LocalStorage;
25
+ driver?: DriverType.IndexedDB | DriverType.LocalStorage | DriverType.Memory | DriverType.SessionStorage;
26
+ migrations?: Record<number, MigrationFn>;
22
27
  name: string;
23
28
  version: number;
24
29
  };
25
- export type { Driver, Filter, Options };
30
+ type SetOptions = {
31
+ ttl?: number;
32
+ };
33
+ type TTLEnvelope<V> = {
34
+ __e: number;
35
+ __v: V;
36
+ };
37
+ type GlobalCallback<T> = (key: keyof T, newValue: T[keyof T] | undefined, oldValue: T[keyof T] | undefined) => void;
38
+ type KeyCallback<T, K extends keyof T = keyof T> = (newValue: T[K] | undefined, oldValue: T[K] | undefined) => void;
39
+ export type { Driver, Filter, GlobalCallback, KeyCallback, MigrationContext, MigrationFn, Options, SetOptions, TTLEnvelope };
package/package.json CHANGED
@@ -5,7 +5,10 @@
5
5
  },
6
6
  "description": "Web storage utility",
7
7
  "devDependencies": {
8
- "@esportsplus/typescript": "^0.9.2"
8
+ "@esportsplus/typescript": "^0.9.2",
9
+ "fake-indexeddb": "^6.2.5",
10
+ "happy-dom": "^20.8.8",
11
+ "vitest": "^4.1.1"
9
12
  },
10
13
  "main": "build/index.js",
11
14
  "name": "@esportsplus/web-storage",
@@ -16,9 +19,10 @@
16
19
  },
17
20
  "type": "module",
18
21
  "types": "build/index.d.ts",
19
- "version": "0.3.5",
22
+ "version": "0.4.0",
20
23
  "scripts": {
21
24
  "build": "tsc && tsc-alias",
25
+ "test": "vitest run",
22
26
  "-": "-"
23
27
  }
24
28
  }
package/src/constants.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  enum DriverType {
2
2
  IndexedDB,
3
- LocalStorage
3
+ LocalStorage,
4
+ Memory,
5
+ SessionStorage
4
6
  }
5
7
 
6
8
  export { DriverType };