@ahoo-wang/fetcher-storage 1.9.2 → 1.9.5
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 +10 -7
- package/README.zh-CN.md +10 -7
- package/dist/browserListenableStorage.d.ts.map +1 -1
- package/dist/inMemoryListenableStorage.d.ts.map +1 -1
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/listenableStorage.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -42,7 +42,7 @@ storage.setItem('key', 'value');
|
|
|
42
42
|
const value = storage.getItem('key');
|
|
43
43
|
|
|
44
44
|
// Listen for storage changes
|
|
45
|
-
const removeListener = storage.addListener(
|
|
45
|
+
const removeListener = storage.addListener(event => {
|
|
46
46
|
console.log('Storage changed:', event);
|
|
47
47
|
});
|
|
48
48
|
|
|
@@ -56,8 +56,8 @@ removeListener();
|
|
|
56
56
|
import { KeyStorage } from '@ahoo-wang/fetcher-storage';
|
|
57
57
|
|
|
58
58
|
// Create a storage for a specific key
|
|
59
|
-
const userStorage = new KeyStorage<{ name: string
|
|
60
|
-
key: 'user'
|
|
59
|
+
const userStorage = new KeyStorage<{ name: string; age: number }>({
|
|
60
|
+
key: 'user',
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
// Set and get values
|
|
@@ -65,7 +65,7 @@ userStorage.set({ name: 'John', age: 30 });
|
|
|
65
65
|
const user = userStorage.get(); // {name: 'John', age: 30}
|
|
66
66
|
|
|
67
67
|
// Listen for changes to this specific key
|
|
68
|
-
const removeListener = userStorage.addListener(
|
|
68
|
+
const removeListener = userStorage.addListener(event => {
|
|
69
69
|
console.log('User changed:', event.newValue);
|
|
70
70
|
});
|
|
71
71
|
```
|
|
@@ -77,7 +77,7 @@ import { KeyStorage, JsonSerializer } from '@ahoo-wang/fetcher-storage';
|
|
|
77
77
|
|
|
78
78
|
const jsonStorage = new KeyStorage<any>({
|
|
79
79
|
key: 'data',
|
|
80
|
-
serializer: new JsonSerializer()
|
|
80
|
+
serializer: new JsonSerializer(),
|
|
81
81
|
});
|
|
82
82
|
|
|
83
83
|
jsonStorage.set({ message: 'Hello World' });
|
|
@@ -87,7 +87,10 @@ const data = jsonStorage.get(); // {message: 'Hello World'}
|
|
|
87
87
|
### Environment-specific Storage
|
|
88
88
|
|
|
89
89
|
```typescript
|
|
90
|
-
import {
|
|
90
|
+
import {
|
|
91
|
+
BrowserListenableStorage,
|
|
92
|
+
InMemoryListenableStorage,
|
|
93
|
+
} from '@ahoo-wang/fetcher-storage';
|
|
91
94
|
|
|
92
95
|
// Browser storage (wraps localStorage or sessionStorage)
|
|
93
96
|
const browserStorage = new BrowserListenableStorage(localStorage);
|
|
@@ -127,4 +130,4 @@ A storage wrapper for managing a single value associated with a specific key:
|
|
|
127
130
|
|
|
128
131
|
## License
|
|
129
132
|
|
|
130
|
-
[Apache 2.0](https://github.com/Ahoo-Wang/fetcher/blob/master/LICENSE)
|
|
133
|
+
[Apache 2.0](https://github.com/Ahoo-Wang/fetcher/blob/master/LICENSE)
|
package/README.zh-CN.md
CHANGED
|
@@ -41,7 +41,7 @@ storage.setItem('key', 'value');
|
|
|
41
41
|
const value = storage.getItem('key');
|
|
42
42
|
|
|
43
43
|
// 监听存储变更
|
|
44
|
-
const removeListener = storage.addListener(
|
|
44
|
+
const removeListener = storage.addListener(event => {
|
|
45
45
|
console.log('存储变更:', event);
|
|
46
46
|
});
|
|
47
47
|
|
|
@@ -55,8 +55,8 @@ removeListener();
|
|
|
55
55
|
import { KeyStorage } from '@ahoo-wang/fetcher-storage';
|
|
56
56
|
|
|
57
57
|
// 为特定键创建存储
|
|
58
|
-
const userStorage = new KeyStorage<{ name: string
|
|
59
|
-
key: 'user'
|
|
58
|
+
const userStorage = new KeyStorage<{ name: string; age: number }>({
|
|
59
|
+
key: 'user',
|
|
60
60
|
});
|
|
61
61
|
|
|
62
62
|
// 设置和获取值
|
|
@@ -64,7 +64,7 @@ userStorage.set({ name: 'John', age: 30 });
|
|
|
64
64
|
const user = userStorage.get(); // {name: 'John', age: 30}
|
|
65
65
|
|
|
66
66
|
// 监听此特定键的变更
|
|
67
|
-
const removeListener = userStorage.addListener(
|
|
67
|
+
const removeListener = userStorage.addListener(event => {
|
|
68
68
|
console.log('用户变更:', event.newValue);
|
|
69
69
|
});
|
|
70
70
|
```
|
|
@@ -76,7 +76,7 @@ import { KeyStorage, JsonSerializer } from '@ahoo-wang/fetcher-storage';
|
|
|
76
76
|
|
|
77
77
|
const jsonStorage = new KeyStorage<any>({
|
|
78
78
|
key: 'data',
|
|
79
|
-
serializer: new JsonSerializer()
|
|
79
|
+
serializer: new JsonSerializer(),
|
|
80
80
|
});
|
|
81
81
|
|
|
82
82
|
jsonStorage.set({ message: 'Hello World' });
|
|
@@ -86,7 +86,10 @@ const data = jsonStorage.get(); // {message: 'Hello World'}
|
|
|
86
86
|
### 环境特定的存储
|
|
87
87
|
|
|
88
88
|
```typescript
|
|
89
|
-
import {
|
|
89
|
+
import {
|
|
90
|
+
BrowserListenableStorage,
|
|
91
|
+
InMemoryListenableStorage,
|
|
92
|
+
} from '@ahoo-wang/fetcher-storage';
|
|
90
93
|
|
|
91
94
|
// 浏览器存储(包装 localStorage 或 sessionStorage)
|
|
92
95
|
const browserStorage = new BrowserListenableStorage(localStorage);
|
|
@@ -126,4 +129,4 @@ const memoryStorage = new InMemoryListenableStorage();
|
|
|
126
129
|
|
|
127
130
|
## 许可证
|
|
128
131
|
|
|
129
|
-
[Apache 2.0](https://github.com/Ahoo-Wang/fetcher/blob/master/LICENSE)
|
|
132
|
+
[Apache 2.0](https://github.com/Ahoo-Wang/fetcher/blob/master/LICENSE)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browserListenableStorage.d.ts","sourceRoot":"","sources":["../src/browserListenableStorage.ts"],"names":[],"mappings":"AAaA,OAAO,
|
|
1
|
+
{"version":3,"file":"browserListenableStorage.d.ts","sourceRoot":"","sources":["../src/browserListenableStorage.ts"],"names":[],"mappings":"AAaA,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EAErB,eAAe,EAChB,MAAM,qBAAqB,CAAC;AAE7B;;;GAGG;AACH,qBAAa,wBAAyB,YAAW,iBAAiB;IAKpD,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJpC;;;OAGG;gBAC0B,OAAO,EAAE,OAAO;IAG7C;;OAEG;IACH,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED;;;;OAIG;IACH,WAAW,CAAC,QAAQ,EAAE,eAAe,GAAG,qBAAqB;IAU7D;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;;;OAIG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAInC;;;;OAIG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAIjC;;;OAGG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAI7B;;;;OAIG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;CAG1C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inMemoryListenableStorage.d.ts","sourceRoot":"","sources":["../src/inMemoryListenableStorage.ts"],"names":[],"mappings":"AAaA,OAAO,
|
|
1
|
+
{"version":3,"file":"inMemoryListenableStorage.d.ts","sourceRoot":"","sources":["../src/inMemoryListenableStorage.ts"],"names":[],"mappings":"AAaA,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,eAAe,EAChB,MAAM,qBAAqB,CAAC;AAG7B;;;GAGG;AACH,qBAAa,yBAA0B,YAAW,iBAAiB;IACjE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkC;IACxD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmC;IAE7D;;OAEG;IACH,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;;;OAIG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAKnC;;;;OAIG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAKjC;;;OAGG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAY7B;;;;OAIG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAMzC;;;;OAIG;IACH,WAAW,CAAC,QAAQ,EAAE,eAAe,GAAG,qBAAqB;IAK7D;;;OAGG;IACH,OAAO,CAAC,eAAe;CAaxB"}
|
package/dist/index.es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.es.js","sources":["../src/env.ts","../src/inMemoryListenableStorage.ts","../src/browserListenableStorage.ts","../src/listenableStorage.ts","../src/serializer.ts","../src/keyStorage.ts"],"sourcesContent":["/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined';\n}","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ListenableStorage, RemoveStorageListener, StorageListener } from './listenableStorage';\nimport { isBrowser } from './env';\n\n/**\n * An in-memory implementation of ListenableStorage that works in any environment.\n * This implementation stores data in a Map and manually fires storage events when data changes.\n */\nexport class InMemoryListenableStorage implements ListenableStorage {\n private readonly store: Map<string, string> = new Map();\n private readonly listeners: Set<StorageListener> = new Set();\n\n /**\n * Gets the number of items stored in the storage.\n */\n get length(): number {\n return this.store.size;\n }\n\n /**\n * Clears all items from the storage.\n */\n clear(): void {\n this.store.clear();\n }\n\n /**\n * Gets an item from the storage.\n * @param key - The key of the item to retrieve\n * @returns The value of the item, or null if the item does not exist\n */\n getItem(key: string): string | null {\n const value = this.store.get(key);\n return value !== undefined ? value : null;\n }\n\n /**\n * Gets the key at the specified index.\n * @param index - The index of the key to retrieve\n * @returns The key at the specified index, or null if the index is out of bounds\n */\n key(index: number): string | null {\n const keys = Array.from(this.store.keys());\n return keys[index] || null;\n }\n\n /**\n * Removes an item from the storage.\n * @param key - The key of the item to remove\n */\n removeItem(key: string): void {\n const oldValue = this.getItem(key);\n if (this.store.has(key)) {\n this.store.delete(key);\n this.notifyListeners({\n key,\n oldValue,\n newValue: null,\n });\n }\n }\n\n /**\n * Sets an item in the storage.\n * @param key - The key of the item to set\n * @param value - The value to set\n */\n setItem(key: string, value: string): void {\n const oldValue = this.getItem(key);\n this.store.set(key, value);\n this.notifyListeners({ key, oldValue, newValue: value });\n }\n\n /**\n * Adds a listener for storage changes.\n * @param listener - The listener function to be called when storage changes\n * @returns A function that can be called to remove the listener\n */\n addListener(listener: StorageListener): RemoveStorageListener {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Notifies all listeners of a storage change by creating and dispatching a StorageEvent.\n * @param eventInit - The initialization object for the StorageEvent\n */\n private notifyListeners(\n eventInit: StorageEventInit,\n ): void {\n if (isBrowser() && window.location) {\n eventInit.url = eventInit.url || window.location.href;\n }\n eventInit.storageArea = this;\n this.listeners.forEach(listener => {\n try {\n listener(eventInit);\n } catch (error) {\n console.error('Error in storage change listener:', error);\n }\n });\n }\n}","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ListenableStorage, RemoveStorageListener, STORAGE_EVENT_TYPE, StorageListener } from './listenableStorage';\n\n/**\n * A wrapper around the browser's native Storage (localStorage or sessionStorage)\n * that implements the ListenableStorage interface by using the browser's native storage events.\n */\nexport class BrowserListenableStorage implements ListenableStorage {\n\n /**\n * Creates a new BrowserListenableStorage instance.\n * @param storage - The native Storage object to wrap (e.g., localStorage or sessionStorage)\n */\n constructor(private readonly storage: Storage) {\n }\n\n /**\n * Gets the number of items stored in the storage.\n */\n get length(): number {\n return this.storage.length;\n }\n\n /**\n * Adds a listener for storage changes.\n * @param listener - The listener function to be called when storage changes\n * @returns A function that can be called to remove the listener\n */\n addListener(listener: StorageListener): RemoveStorageListener {\n const wrapper: StorageListener = (event: StorageEventInit) => {\n if (event.storageArea === this.storage) {\n listener(event);\n }\n };\n window.addEventListener(STORAGE_EVENT_TYPE, wrapper);\n return () => window.removeEventListener(STORAGE_EVENT_TYPE, wrapper);\n }\n\n /**\n * Clears all items from the storage.\n */\n clear(): void {\n this.storage.clear();\n }\n\n /**\n * Gets an item from the storage.\n * @param key - The key of the item to retrieve\n * @returns The value of the item, or null if the item does not exist\n */\n getItem(key: string): string | null {\n return this.storage.getItem(key);\n }\n\n /**\n * Gets the key at the specified index.\n * @param index - The index of the key to retrieve\n * @returns The key at the specified index, or null if the index is out of bounds\n */\n key(index: number): string | null {\n return this.storage.key(index);\n }\n\n /**\n * Removes an item from the storage.\n * @param key - The key of the item to remove\n */\n removeItem(key: string): void {\n this.storage.removeItem(key);\n }\n\n /**\n * Sets an item in the storage.\n * @param key - The key of the item to set\n * @param value - The value to set\n */\n setItem(key: string, value: string): void {\n this.storage.setItem(key, value);\n }\n}","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InMemoryListenableStorage } from './inMemoryListenableStorage';\nimport { BrowserListenableStorage } from './browserListenableStorage';\nimport { isBrowser } from './env';\n\n/**\n * The type of storage event used for listening to storage changes.\n */\nexport const STORAGE_EVENT_TYPE = 'storage';\n\n/**\n * A function that handles storage change events.\n */\nexport type StorageListener = (event: StorageEventInit) => void;\n\n/**\n * A function that removes a storage listener when called.\n */\nexport type RemoveStorageListener = () => void;\n\nexport interface StorageListenable {\n /**\n * Adds a listener for storage changes.\n * @param listener - The listener function to be called when storage changes\n * @returns A function that can be called to remove the listener\n */\n addListener(listener: StorageListener): RemoveStorageListener;\n}\n\n/**\n * An interface that extends the native Storage interface with the ability to listen for storage changes.\n */\nexport interface ListenableStorage extends Storage, StorageListenable {\n\n}\n\n/**\n * Factory function to get an appropriate ListenableStorage implementation based on the environment.\n * In a browser environment, it returns a BrowserListenableStorage wrapping localStorage.\n * In other environments, it returns an InMemoryListenableStorage.\n * @returns A ListenableStorage instance suitable for the current environment\n */\nexport const createListenableStorage = (): ListenableStorage => {\n if (isBrowser()) {\n return new BrowserListenableStorage(window.localStorage);\n }\n return new InMemoryListenableStorage();\n};","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Interface for serializing and deserializing values\n * @template Serialized The type of the serialized value\n */\n/**\n * Interface for serializing and deserializing values\n * @template Serialized The type of the serialized value\n * @template Deserialized The type of the deserialized value\n */\nexport interface Serializer<Serialized, Deserialized> {\n /**\n * Serializes a value to the specified format\n * @param value The value to serialize\n * @returns The serialized value\n */\n serialize(value: any): Serialized;\n\n /**\n * Deserializes a value from the specified format\n * @template Deserialized The type of the deserialized value\n * @param value The value to deserialize\n * @returns The deserialized value\n */\n /**\n * Deserializes a value from the specified format\n * @param value The value to deserialize\n * @returns The deserialized value\n */\n deserialize(value: Serialized): Deserialized;\n}\n\n/**\n * Implementation of Serializer that uses JSON for serialization\n */\nexport class JsonSerializer implements Serializer<string, any> {\n /**\n * Serializes a value to a JSON string\n * @param value The value to serialize\n * @returns The JSON string representation of the value\n */\n /**\n * Serializes a value to a JSON string\n * @param value The value to serialize\n * @returns The JSON string representation of the value\n */\n serialize(value: any): string {\n return JSON.stringify(value);\n }\n\n /**\n * Deserializes a JSON string to a value\n * @template V The type of the deserialized value\n * @param value The JSON string to deserialize\n * @returns The deserialized value\n */\n /**\n * Deserializes a JSON string to a value\n * @param value The JSON string to deserialize\n * @returns The deserialized value\n */\n deserialize<V>(value: string): V {\n return JSON.parse(value);\n }\n}\n\n/**\n * Implementation of Serializer that performs no actual serialization\n * @template T The type of the value to pass through\n */\nexport class IdentitySerializer<T> implements Serializer<T, T> {\n /**\n * Returns the value as-is without serialization\n * @param value The value to pass through\n * @returns The same value that was passed in\n */\n /**\n * Returns the value as-is without serialization\n * @param value The value to pass through\n * @returns The same value that was passed in\n */\n serialize(value: T): T {\n return value;\n }\n\n /**\n * Returns the value as-is without deserialization\n * @template Deserialized The type of the deserialized value\n * @param value The value to pass through\n * @returns The same value that was passed in, cast to the target type\n */\n /**\n * Returns the value as-is without deserialization\n * @param value The value to pass through\n * @returns The same value that was passed in\n */\n deserialize(value: T): T {\n return value;\n }\n}\n\n/**\n * Global instance of JsonSerializer\n */\nexport const jsonSerializer = new JsonSerializer();\n/**\n * Global instance of IdentitySerializer\n */\nexport const identitySerializer = new IdentitySerializer<any>();\n\nexport function typedIdentitySerializer<T>(): IdentitySerializer<T> {\n return identitySerializer as IdentitySerializer<T>;\n}","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createListenableStorage,\n ListenableStorage,\n RemoveStorageListener,\n StorageListenable,\n StorageListener,\n} from './listenableStorage';\nimport { Serializer, typedIdentitySerializer } from './serializer';\n\n/**\n * Options for configuring KeyStorage\n */\nexport interface KeyStorageOptions<Deserialized> {\n /**\n * The key used to store and retrieve values from storage\n */\n key: string;\n\n /**\n * Optional serializer for converting values to and from storage format\n * Defaults to IdentitySerializer if not provided\n */\n serializer?: Serializer<string, Deserialized>;\n\n /**\n * Optional storage implementation\n * Defaults to the result of createListenableStorage() if not provided\n */\n storage?: ListenableStorage;\n}\n\n/**\n * A storage wrapper that manages a single value associated with a specific key\n * Provides caching and automatic cache invalidation when the storage value changes\n * @template Deserialized The type of the value being stored\n */\nexport class KeyStorage<Deserialized> implements StorageListenable {\n private readonly key: string;\n private readonly serializer: Serializer<string, Deserialized>;\n private readonly storage: ListenableStorage;\n private cacheValue: Deserialized | null = null;\n\n /**\n * Listener for storage change events\n * Invalidates the cache when the relevant key is modified\n */\n private readonly refreshCacheListener: StorageListener = (event) => {\n this.cacheValue = null;\n if (event.newValue) {\n this.refreshCache(event.newValue);\n }\n };\n\n /**\n * Refreshes the cached value by deserializing the provided string\n * @param value The serialized value to deserialize and cache\n */\n private refreshCache(value: string) {\n this.cacheValue = this.serializer.deserialize(value);\n }\n\n /**\n * Creates a new KeyStorage instance\n * @param options Configuration options for the storage\n */\n constructor(options: KeyStorageOptions<Deserialized>) {\n this.key = options.key;\n this.serializer = options.serializer ?? typedIdentitySerializer();\n this.storage = options.storage ?? createListenableStorage();\n this.addListener(this.refreshCacheListener);\n }\n\n addListener(listener: StorageListener): RemoveStorageListener {\n const wrapper: StorageListener = (event: StorageEventInit) => {\n if (event.key !== this.key) {\n return;\n }\n listener(event);\n };\n return this.storage.addListener(wrapper);\n }\n\n /**\n * Gets the value associated with the key from storage\n * Uses cached value if available, otherwise retrieves from storage and caches it\n * @returns The deserialized value or null if no value is found\n */\n get(): Deserialized | null {\n if (this.cacheValue) {\n return this.cacheValue;\n }\n const value = this.storage.getItem(this.key);\n if (!value) {\n return null;\n }\n this.refreshCache(value);\n return this.cacheValue;\n }\n\n /**\n * Sets the value associated with the key in storage\n * Also updates the cached value\n * @param value The value to serialize and store\n */\n set(value: Deserialized): void {\n const serialized = this.serializer.serialize(value);\n this.storage.setItem(this.key, serialized);\n this.cacheValue = value;\n }\n\n /**\n * Removes the value associated with the key from storage\n * Also clears the cached value\n */\n remove(): void {\n this.storage.removeItem(this.key);\n this.cacheValue = null;\n }\n}"],"names":["isBrowser","InMemoryListenableStorage","key","value","index","oldValue","listener","eventInit","error","BrowserListenableStorage","storage","wrapper","event","STORAGE_EVENT_TYPE","createListenableStorage","JsonSerializer","IdentitySerializer","jsonSerializer","identitySerializer","typedIdentitySerializer","KeyStorage","options","serialized"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.es.js","sources":["../src/env.ts","../src/inMemoryListenableStorage.ts","../src/browserListenableStorage.ts","../src/listenableStorage.ts","../src/serializer.ts","../src/keyStorage.ts"],"sourcesContent":["/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined';\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ListenableStorage,\n RemoveStorageListener,\n StorageListener,\n} from './listenableStorage';\nimport { isBrowser } from './env';\n\n/**\n * An in-memory implementation of ListenableStorage that works in any environment.\n * This implementation stores data in a Map and manually fires storage events when data changes.\n */\nexport class InMemoryListenableStorage implements ListenableStorage {\n private readonly store: Map<string, string> = new Map();\n private readonly listeners: Set<StorageListener> = new Set();\n\n /**\n * Gets the number of items stored in the storage.\n */\n get length(): number {\n return this.store.size;\n }\n\n /**\n * Clears all items from the storage.\n */\n clear(): void {\n this.store.clear();\n }\n\n /**\n * Gets an item from the storage.\n * @param key - The key of the item to retrieve\n * @returns The value of the item, or null if the item does not exist\n */\n getItem(key: string): string | null {\n const value = this.store.get(key);\n return value !== undefined ? value : null;\n }\n\n /**\n * Gets the key at the specified index.\n * @param index - The index of the key to retrieve\n * @returns The key at the specified index, or null if the index is out of bounds\n */\n key(index: number): string | null {\n const keys = Array.from(this.store.keys());\n return keys[index] || null;\n }\n\n /**\n * Removes an item from the storage.\n * @param key - The key of the item to remove\n */\n removeItem(key: string): void {\n const oldValue = this.getItem(key);\n if (this.store.has(key)) {\n this.store.delete(key);\n this.notifyListeners({\n key,\n oldValue,\n newValue: null,\n });\n }\n }\n\n /**\n * Sets an item in the storage.\n * @param key - The key of the item to set\n * @param value - The value to set\n */\n setItem(key: string, value: string): void {\n const oldValue = this.getItem(key);\n this.store.set(key, value);\n this.notifyListeners({ key, oldValue, newValue: value });\n }\n\n /**\n * Adds a listener for storage changes.\n * @param listener - The listener function to be called when storage changes\n * @returns A function that can be called to remove the listener\n */\n addListener(listener: StorageListener): RemoveStorageListener {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Notifies all listeners of a storage change by creating and dispatching a StorageEvent.\n * @param eventInit - The initialization object for the StorageEvent\n */\n private notifyListeners(eventInit: StorageEventInit): void {\n if (isBrowser() && window.location) {\n eventInit.url = eventInit.url || window.location.href;\n }\n eventInit.storageArea = this;\n this.listeners.forEach(listener => {\n try {\n listener(eventInit);\n } catch (error) {\n console.error('Error in storage change listener:', error);\n }\n });\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ListenableStorage,\n RemoveStorageListener,\n STORAGE_EVENT_TYPE,\n StorageListener,\n} from './listenableStorage';\n\n/**\n * A wrapper around the browser's native Storage (localStorage or sessionStorage)\n * that implements the ListenableStorage interface by using the browser's native storage events.\n */\nexport class BrowserListenableStorage implements ListenableStorage {\n /**\n * Creates a new BrowserListenableStorage instance.\n * @param storage - The native Storage object to wrap (e.g., localStorage or sessionStorage)\n */\n constructor(private readonly storage: Storage) {\n }\n\n /**\n * Gets the number of items stored in the storage.\n */\n get length(): number {\n return this.storage.length;\n }\n\n /**\n * Adds a listener for storage changes.\n * @param listener - The listener function to be called when storage changes\n * @returns A function that can be called to remove the listener\n */\n addListener(listener: StorageListener): RemoveStorageListener {\n const wrapper: StorageListener = (event: StorageEventInit) => {\n if (event.storageArea === this.storage) {\n listener(event);\n }\n };\n window.addEventListener(STORAGE_EVENT_TYPE, wrapper);\n return () => window.removeEventListener(STORAGE_EVENT_TYPE, wrapper);\n }\n\n /**\n * Clears all items from the storage.\n */\n clear(): void {\n this.storage.clear();\n }\n\n /**\n * Gets an item from the storage.\n * @param key - The key of the item to retrieve\n * @returns The value of the item, or null if the item does not exist\n */\n getItem(key: string): string | null {\n return this.storage.getItem(key);\n }\n\n /**\n * Gets the key at the specified index.\n * @param index - The index of the key to retrieve\n * @returns The key at the specified index, or null if the index is out of bounds\n */\n key(index: number): string | null {\n return this.storage.key(index);\n }\n\n /**\n * Removes an item from the storage.\n * @param key - The key of the item to remove\n */\n removeItem(key: string): void {\n this.storage.removeItem(key);\n }\n\n /**\n * Sets an item in the storage.\n * @param key - The key of the item to set\n * @param value - The value to set\n */\n setItem(key: string, value: string): void {\n this.storage.setItem(key, value);\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InMemoryListenableStorage } from './inMemoryListenableStorage';\nimport { BrowserListenableStorage } from './browserListenableStorage';\nimport { isBrowser } from './env';\n\n/**\n * The type of storage event used for listening to storage changes.\n */\nexport const STORAGE_EVENT_TYPE = 'storage';\n\n/**\n * A function that handles storage change events.\n */\nexport type StorageListener = (event: StorageEventInit) => void;\n\n/**\n * A function that removes a storage listener when called.\n */\nexport type RemoveStorageListener = () => void;\n\nexport interface StorageListenable {\n /**\n * Adds a listener for storage changes.\n * @param listener - The listener function to be called when storage changes\n * @returns A function that can be called to remove the listener\n */\n addListener(listener: StorageListener): RemoveStorageListener;\n}\n\n/**\n * An interface that extends the native Storage interface with the ability to listen for storage changes.\n */\nexport interface ListenableStorage extends Storage, StorageListenable {\n}\n\n/**\n * Factory function to get an appropriate ListenableStorage implementation based on the environment.\n * In a browser environment, it returns a BrowserListenableStorage wrapping localStorage.\n * In other environments, it returns an InMemoryListenableStorage.\n * @returns A ListenableStorage instance suitable for the current environment\n */\nexport const createListenableStorage = (): ListenableStorage => {\n if (isBrowser()) {\n return new BrowserListenableStorage(window.localStorage);\n }\n return new InMemoryListenableStorage();\n};\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Interface for serializing and deserializing values\n * @template Serialized The type of the serialized value\n */\n/**\n * Interface for serializing and deserializing values\n * @template Serialized The type of the serialized value\n * @template Deserialized The type of the deserialized value\n */\nexport interface Serializer<Serialized, Deserialized> {\n /**\n * Serializes a value to the specified format\n * @param value The value to serialize\n * @returns The serialized value\n */\n serialize(value: any): Serialized;\n\n /**\n * Deserializes a value from the specified format\n * @template Deserialized The type of the deserialized value\n * @param value The value to deserialize\n * @returns The deserialized value\n */\n /**\n * Deserializes a value from the specified format\n * @param value The value to deserialize\n * @returns The deserialized value\n */\n deserialize(value: Serialized): Deserialized;\n}\n\n/**\n * Implementation of Serializer that uses JSON for serialization\n */\nexport class JsonSerializer implements Serializer<string, any> {\n /**\n * Serializes a value to a JSON string\n * @param value The value to serialize\n * @returns The JSON string representation of the value\n */\n /**\n * Serializes a value to a JSON string\n * @param value The value to serialize\n * @returns The JSON string representation of the value\n */\n serialize(value: any): string {\n return JSON.stringify(value);\n }\n\n /**\n * Deserializes a JSON string to a value\n * @template V The type of the deserialized value\n * @param value The JSON string to deserialize\n * @returns The deserialized value\n */\n /**\n * Deserializes a JSON string to a value\n * @param value The JSON string to deserialize\n * @returns The deserialized value\n */\n deserialize<V>(value: string): V {\n return JSON.parse(value);\n }\n}\n\n/**\n * Implementation of Serializer that performs no actual serialization\n * @template T The type of the value to pass through\n */\nexport class IdentitySerializer<T> implements Serializer<T, T> {\n /**\n * Returns the value as-is without serialization\n * @param value The value to pass through\n * @returns The same value that was passed in\n */\n /**\n * Returns the value as-is without serialization\n * @param value The value to pass through\n * @returns The same value that was passed in\n */\n serialize(value: T): T {\n return value;\n }\n\n /**\n * Returns the value as-is without deserialization\n * @template Deserialized The type of the deserialized value\n * @param value The value to pass through\n * @returns The same value that was passed in, cast to the target type\n */\n /**\n * Returns the value as-is without deserialization\n * @param value The value to pass through\n * @returns The same value that was passed in\n */\n deserialize(value: T): T {\n return value;\n }\n}\n\n/**\n * Global instance of JsonSerializer\n */\nexport const jsonSerializer = new JsonSerializer();\n/**\n * Global instance of IdentitySerializer\n */\nexport const identitySerializer = new IdentitySerializer<any>();\n\nexport function typedIdentitySerializer<T>(): IdentitySerializer<T> {\n return identitySerializer as IdentitySerializer<T>;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createListenableStorage,\n ListenableStorage,\n RemoveStorageListener,\n StorageListenable,\n StorageListener,\n} from './listenableStorage';\nimport { Serializer, typedIdentitySerializer } from './serializer';\n\n/**\n * Options for configuring KeyStorage\n */\nexport interface KeyStorageOptions<Deserialized> {\n /**\n * The key used to store and retrieve values from storage\n */\n key: string;\n\n /**\n * Optional serializer for converting values to and from storage format\n * Defaults to IdentitySerializer if not provided\n */\n serializer?: Serializer<string, Deserialized>;\n\n /**\n * Optional storage implementation\n * Defaults to the result of createListenableStorage() if not provided\n */\n storage?: ListenableStorage;\n}\n\n/**\n * A storage wrapper that manages a single value associated with a specific key\n * Provides caching and automatic cache invalidation when the storage value changes\n * @template Deserialized The type of the value being stored\n */\nexport class KeyStorage<Deserialized> implements StorageListenable {\n private readonly key: string;\n private readonly serializer: Serializer<string, Deserialized>;\n private readonly storage: ListenableStorage;\n private cacheValue: Deserialized | null = null;\n\n /**\n * Listener for storage change events\n * Invalidates the cache when the relevant key is modified\n */\n private readonly refreshCacheListener: StorageListener = event => {\n this.cacheValue = null;\n if (event.newValue) {\n this.refreshCache(event.newValue);\n }\n };\n\n /**\n * Refreshes the cached value by deserializing the provided string\n * @param value The serialized value to deserialize and cache\n */\n private refreshCache(value: string) {\n this.cacheValue = this.serializer.deserialize(value);\n }\n\n /**\n * Creates a new KeyStorage instance\n * @param options Configuration options for the storage\n */\n constructor(options: KeyStorageOptions<Deserialized>) {\n this.key = options.key;\n this.serializer = options.serializer ?? typedIdentitySerializer();\n this.storage = options.storage ?? createListenableStorage();\n this.addListener(this.refreshCacheListener);\n }\n\n addListener(listener: StorageListener): RemoveStorageListener {\n const wrapper: StorageListener = (event: StorageEventInit) => {\n if (event.key !== this.key) {\n return;\n }\n listener(event);\n };\n return this.storage.addListener(wrapper);\n }\n\n /**\n * Gets the value associated with the key from storage\n * Uses cached value if available, otherwise retrieves from storage and caches it\n * @returns The deserialized value or null if no value is found\n */\n get(): Deserialized | null {\n if (this.cacheValue) {\n return this.cacheValue;\n }\n const value = this.storage.getItem(this.key);\n if (!value) {\n return null;\n }\n this.refreshCache(value);\n return this.cacheValue;\n }\n\n /**\n * Sets the value associated with the key in storage\n * Also updates the cached value\n * @param value The value to serialize and store\n */\n set(value: Deserialized): void {\n const serialized = this.serializer.serialize(value);\n this.storage.setItem(this.key, serialized);\n this.cacheValue = value;\n }\n\n /**\n * Removes the value associated with the key from storage\n * Also clears the cached value\n */\n remove(): void {\n this.storage.removeItem(this.key);\n this.cacheValue = null;\n }\n}\n"],"names":["isBrowser","InMemoryListenableStorage","key","value","index","oldValue","listener","eventInit","error","BrowserListenableStorage","storage","wrapper","event","STORAGE_EVENT_TYPE","createListenableStorage","JsonSerializer","IdentitySerializer","jsonSerializer","identitySerializer","typedIdentitySerializer","KeyStorage","options","serialized"],"mappings":"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"}
|
package/dist/index.umd.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.umd.js","sources":["../src/env.ts","../src/inMemoryListenableStorage.ts","../src/browserListenableStorage.ts","../src/listenableStorage.ts","../src/serializer.ts","../src/keyStorage.ts"],"sourcesContent":["/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined';\n}","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ListenableStorage, RemoveStorageListener, StorageListener } from './listenableStorage';\nimport { isBrowser } from './env';\n\n/**\n * An in-memory implementation of ListenableStorage that works in any environment.\n * This implementation stores data in a Map and manually fires storage events when data changes.\n */\nexport class InMemoryListenableStorage implements ListenableStorage {\n private readonly store: Map<string, string> = new Map();\n private readonly listeners: Set<StorageListener> = new Set();\n\n /**\n * Gets the number of items stored in the storage.\n */\n get length(): number {\n return this.store.size;\n }\n\n /**\n * Clears all items from the storage.\n */\n clear(): void {\n this.store.clear();\n }\n\n /**\n * Gets an item from the storage.\n * @param key - The key of the item to retrieve\n * @returns The value of the item, or null if the item does not exist\n */\n getItem(key: string): string | null {\n const value = this.store.get(key);\n return value !== undefined ? value : null;\n }\n\n /**\n * Gets the key at the specified index.\n * @param index - The index of the key to retrieve\n * @returns The key at the specified index, or null if the index is out of bounds\n */\n key(index: number): string | null {\n const keys = Array.from(this.store.keys());\n return keys[index] || null;\n }\n\n /**\n * Removes an item from the storage.\n * @param key - The key of the item to remove\n */\n removeItem(key: string): void {\n const oldValue = this.getItem(key);\n if (this.store.has(key)) {\n this.store.delete(key);\n this.notifyListeners({\n key,\n oldValue,\n newValue: null,\n });\n }\n }\n\n /**\n * Sets an item in the storage.\n * @param key - The key of the item to set\n * @param value - The value to set\n */\n setItem(key: string, value: string): void {\n const oldValue = this.getItem(key);\n this.store.set(key, value);\n this.notifyListeners({ key, oldValue, newValue: value });\n }\n\n /**\n * Adds a listener for storage changes.\n * @param listener - The listener function to be called when storage changes\n * @returns A function that can be called to remove the listener\n */\n addListener(listener: StorageListener): RemoveStorageListener {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Notifies all listeners of a storage change by creating and dispatching a StorageEvent.\n * @param eventInit - The initialization object for the StorageEvent\n */\n private notifyListeners(\n eventInit: StorageEventInit,\n ): void {\n if (isBrowser() && window.location) {\n eventInit.url = eventInit.url || window.location.href;\n }\n eventInit.storageArea = this;\n this.listeners.forEach(listener => {\n try {\n listener(eventInit);\n } catch (error) {\n console.error('Error in storage change listener:', error);\n }\n });\n }\n}","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ListenableStorage, RemoveStorageListener, STORAGE_EVENT_TYPE, StorageListener } from './listenableStorage';\n\n/**\n * A wrapper around the browser's native Storage (localStorage or sessionStorage)\n * that implements the ListenableStorage interface by using the browser's native storage events.\n */\nexport class BrowserListenableStorage implements ListenableStorage {\n\n /**\n * Creates a new BrowserListenableStorage instance.\n * @param storage - The native Storage object to wrap (e.g., localStorage or sessionStorage)\n */\n constructor(private readonly storage: Storage) {\n }\n\n /**\n * Gets the number of items stored in the storage.\n */\n get length(): number {\n return this.storage.length;\n }\n\n /**\n * Adds a listener for storage changes.\n * @param listener - The listener function to be called when storage changes\n * @returns A function that can be called to remove the listener\n */\n addListener(listener: StorageListener): RemoveStorageListener {\n const wrapper: StorageListener = (event: StorageEventInit) => {\n if (event.storageArea === this.storage) {\n listener(event);\n }\n };\n window.addEventListener(STORAGE_EVENT_TYPE, wrapper);\n return () => window.removeEventListener(STORAGE_EVENT_TYPE, wrapper);\n }\n\n /**\n * Clears all items from the storage.\n */\n clear(): void {\n this.storage.clear();\n }\n\n /**\n * Gets an item from the storage.\n * @param key - The key of the item to retrieve\n * @returns The value of the item, or null if the item does not exist\n */\n getItem(key: string): string | null {\n return this.storage.getItem(key);\n }\n\n /**\n * Gets the key at the specified index.\n * @param index - The index of the key to retrieve\n * @returns The key at the specified index, or null if the index is out of bounds\n */\n key(index: number): string | null {\n return this.storage.key(index);\n }\n\n /**\n * Removes an item from the storage.\n * @param key - The key of the item to remove\n */\n removeItem(key: string): void {\n this.storage.removeItem(key);\n }\n\n /**\n * Sets an item in the storage.\n * @param key - The key of the item to set\n * @param value - The value to set\n */\n setItem(key: string, value: string): void {\n this.storage.setItem(key, value);\n }\n}","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InMemoryListenableStorage } from './inMemoryListenableStorage';\nimport { BrowserListenableStorage } from './browserListenableStorage';\nimport { isBrowser } from './env';\n\n/**\n * The type of storage event used for listening to storage changes.\n */\nexport const STORAGE_EVENT_TYPE = 'storage';\n\n/**\n * A function that handles storage change events.\n */\nexport type StorageListener = (event: StorageEventInit) => void;\n\n/**\n * A function that removes a storage listener when called.\n */\nexport type RemoveStorageListener = () => void;\n\nexport interface StorageListenable {\n /**\n * Adds a listener for storage changes.\n * @param listener - The listener function to be called when storage changes\n * @returns A function that can be called to remove the listener\n */\n addListener(listener: StorageListener): RemoveStorageListener;\n}\n\n/**\n * An interface that extends the native Storage interface with the ability to listen for storage changes.\n */\nexport interface ListenableStorage extends Storage, StorageListenable {\n\n}\n\n/**\n * Factory function to get an appropriate ListenableStorage implementation based on the environment.\n * In a browser environment, it returns a BrowserListenableStorage wrapping localStorage.\n * In other environments, it returns an InMemoryListenableStorage.\n * @returns A ListenableStorage instance suitable for the current environment\n */\nexport const createListenableStorage = (): ListenableStorage => {\n if (isBrowser()) {\n return new BrowserListenableStorage(window.localStorage);\n }\n return new InMemoryListenableStorage();\n};","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Interface for serializing and deserializing values\n * @template Serialized The type of the serialized value\n */\n/**\n * Interface for serializing and deserializing values\n * @template Serialized The type of the serialized value\n * @template Deserialized The type of the deserialized value\n */\nexport interface Serializer<Serialized, Deserialized> {\n /**\n * Serializes a value to the specified format\n * @param value The value to serialize\n * @returns The serialized value\n */\n serialize(value: any): Serialized;\n\n /**\n * Deserializes a value from the specified format\n * @template Deserialized The type of the deserialized value\n * @param value The value to deserialize\n * @returns The deserialized value\n */\n /**\n * Deserializes a value from the specified format\n * @param value The value to deserialize\n * @returns The deserialized value\n */\n deserialize(value: Serialized): Deserialized;\n}\n\n/**\n * Implementation of Serializer that uses JSON for serialization\n */\nexport class JsonSerializer implements Serializer<string, any> {\n /**\n * Serializes a value to a JSON string\n * @param value The value to serialize\n * @returns The JSON string representation of the value\n */\n /**\n * Serializes a value to a JSON string\n * @param value The value to serialize\n * @returns The JSON string representation of the value\n */\n serialize(value: any): string {\n return JSON.stringify(value);\n }\n\n /**\n * Deserializes a JSON string to a value\n * @template V The type of the deserialized value\n * @param value The JSON string to deserialize\n * @returns The deserialized value\n */\n /**\n * Deserializes a JSON string to a value\n * @param value The JSON string to deserialize\n * @returns The deserialized value\n */\n deserialize<V>(value: string): V {\n return JSON.parse(value);\n }\n}\n\n/**\n * Implementation of Serializer that performs no actual serialization\n * @template T The type of the value to pass through\n */\nexport class IdentitySerializer<T> implements Serializer<T, T> {\n /**\n * Returns the value as-is without serialization\n * @param value The value to pass through\n * @returns The same value that was passed in\n */\n /**\n * Returns the value as-is without serialization\n * @param value The value to pass through\n * @returns The same value that was passed in\n */\n serialize(value: T): T {\n return value;\n }\n\n /**\n * Returns the value as-is without deserialization\n * @template Deserialized The type of the deserialized value\n * @param value The value to pass through\n * @returns The same value that was passed in, cast to the target type\n */\n /**\n * Returns the value as-is without deserialization\n * @param value The value to pass through\n * @returns The same value that was passed in\n */\n deserialize(value: T): T {\n return value;\n }\n}\n\n/**\n * Global instance of JsonSerializer\n */\nexport const jsonSerializer = new JsonSerializer();\n/**\n * Global instance of IdentitySerializer\n */\nexport const identitySerializer = new IdentitySerializer<any>();\n\nexport function typedIdentitySerializer<T>(): IdentitySerializer<T> {\n return identitySerializer as IdentitySerializer<T>;\n}","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createListenableStorage,\n ListenableStorage,\n RemoveStorageListener,\n StorageListenable,\n StorageListener,\n} from './listenableStorage';\nimport { Serializer, typedIdentitySerializer } from './serializer';\n\n/**\n * Options for configuring KeyStorage\n */\nexport interface KeyStorageOptions<Deserialized> {\n /**\n * The key used to store and retrieve values from storage\n */\n key: string;\n\n /**\n * Optional serializer for converting values to and from storage format\n * Defaults to IdentitySerializer if not provided\n */\n serializer?: Serializer<string, Deserialized>;\n\n /**\n * Optional storage implementation\n * Defaults to the result of createListenableStorage() if not provided\n */\n storage?: ListenableStorage;\n}\n\n/**\n * A storage wrapper that manages a single value associated with a specific key\n * Provides caching and automatic cache invalidation when the storage value changes\n * @template Deserialized The type of the value being stored\n */\nexport class KeyStorage<Deserialized> implements StorageListenable {\n private readonly key: string;\n private readonly serializer: Serializer<string, Deserialized>;\n private readonly storage: ListenableStorage;\n private cacheValue: Deserialized | null = null;\n\n /**\n * Listener for storage change events\n * Invalidates the cache when the relevant key is modified\n */\n private readonly refreshCacheListener: StorageListener = (event) => {\n this.cacheValue = null;\n if (event.newValue) {\n this.refreshCache(event.newValue);\n }\n };\n\n /**\n * Refreshes the cached value by deserializing the provided string\n * @param value The serialized value to deserialize and cache\n */\n private refreshCache(value: string) {\n this.cacheValue = this.serializer.deserialize(value);\n }\n\n /**\n * Creates a new KeyStorage instance\n * @param options Configuration options for the storage\n */\n constructor(options: KeyStorageOptions<Deserialized>) {\n this.key = options.key;\n this.serializer = options.serializer ?? typedIdentitySerializer();\n this.storage = options.storage ?? createListenableStorage();\n this.addListener(this.refreshCacheListener);\n }\n\n addListener(listener: StorageListener): RemoveStorageListener {\n const wrapper: StorageListener = (event: StorageEventInit) => {\n if (event.key !== this.key) {\n return;\n }\n listener(event);\n };\n return this.storage.addListener(wrapper);\n }\n\n /**\n * Gets the value associated with the key from storage\n * Uses cached value if available, otherwise retrieves from storage and caches it\n * @returns The deserialized value or null if no value is found\n */\n get(): Deserialized | null {\n if (this.cacheValue) {\n return this.cacheValue;\n }\n const value = this.storage.getItem(this.key);\n if (!value) {\n return null;\n }\n this.refreshCache(value);\n return this.cacheValue;\n }\n\n /**\n * Sets the value associated with the key in storage\n * Also updates the cached value\n * @param value The value to serialize and store\n */\n set(value: Deserialized): void {\n const serialized = this.serializer.serialize(value);\n this.storage.setItem(this.key, serialized);\n this.cacheValue = value;\n }\n\n /**\n * Removes the value associated with the key from storage\n * Also clears the cached value\n */\n remove(): void {\n this.storage.removeItem(this.key);\n this.cacheValue = null;\n }\n}"],"names":["isBrowser","InMemoryListenableStorage","key","value","index","oldValue","listener","eventInit","error","BrowserListenableStorage","storage","wrapper","event","STORAGE_EVENT_TYPE","createListenableStorage","JsonSerializer","IdentitySerializer","jsonSerializer","identitySerializer","typedIdentitySerializer","KeyStorage","options","serialized"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.umd.js","sources":["../src/env.ts","../src/inMemoryListenableStorage.ts","../src/browserListenableStorage.ts","../src/listenableStorage.ts","../src/serializer.ts","../src/keyStorage.ts"],"sourcesContent":["/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined';\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ListenableStorage,\n RemoveStorageListener,\n StorageListener,\n} from './listenableStorage';\nimport { isBrowser } from './env';\n\n/**\n * An in-memory implementation of ListenableStorage that works in any environment.\n * This implementation stores data in a Map and manually fires storage events when data changes.\n */\nexport class InMemoryListenableStorage implements ListenableStorage {\n private readonly store: Map<string, string> = new Map();\n private readonly listeners: Set<StorageListener> = new Set();\n\n /**\n * Gets the number of items stored in the storage.\n */\n get length(): number {\n return this.store.size;\n }\n\n /**\n * Clears all items from the storage.\n */\n clear(): void {\n this.store.clear();\n }\n\n /**\n * Gets an item from the storage.\n * @param key - The key of the item to retrieve\n * @returns The value of the item, or null if the item does not exist\n */\n getItem(key: string): string | null {\n const value = this.store.get(key);\n return value !== undefined ? value : null;\n }\n\n /**\n * Gets the key at the specified index.\n * @param index - The index of the key to retrieve\n * @returns The key at the specified index, or null if the index is out of bounds\n */\n key(index: number): string | null {\n const keys = Array.from(this.store.keys());\n return keys[index] || null;\n }\n\n /**\n * Removes an item from the storage.\n * @param key - The key of the item to remove\n */\n removeItem(key: string): void {\n const oldValue = this.getItem(key);\n if (this.store.has(key)) {\n this.store.delete(key);\n this.notifyListeners({\n key,\n oldValue,\n newValue: null,\n });\n }\n }\n\n /**\n * Sets an item in the storage.\n * @param key - The key of the item to set\n * @param value - The value to set\n */\n setItem(key: string, value: string): void {\n const oldValue = this.getItem(key);\n this.store.set(key, value);\n this.notifyListeners({ key, oldValue, newValue: value });\n }\n\n /**\n * Adds a listener for storage changes.\n * @param listener - The listener function to be called when storage changes\n * @returns A function that can be called to remove the listener\n */\n addListener(listener: StorageListener): RemoveStorageListener {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Notifies all listeners of a storage change by creating and dispatching a StorageEvent.\n * @param eventInit - The initialization object for the StorageEvent\n */\n private notifyListeners(eventInit: StorageEventInit): void {\n if (isBrowser() && window.location) {\n eventInit.url = eventInit.url || window.location.href;\n }\n eventInit.storageArea = this;\n this.listeners.forEach(listener => {\n try {\n listener(eventInit);\n } catch (error) {\n console.error('Error in storage change listener:', error);\n }\n });\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ListenableStorage,\n RemoveStorageListener,\n STORAGE_EVENT_TYPE,\n StorageListener,\n} from './listenableStorage';\n\n/**\n * A wrapper around the browser's native Storage (localStorage or sessionStorage)\n * that implements the ListenableStorage interface by using the browser's native storage events.\n */\nexport class BrowserListenableStorage implements ListenableStorage {\n /**\n * Creates a new BrowserListenableStorage instance.\n * @param storage - The native Storage object to wrap (e.g., localStorage or sessionStorage)\n */\n constructor(private readonly storage: Storage) {\n }\n\n /**\n * Gets the number of items stored in the storage.\n */\n get length(): number {\n return this.storage.length;\n }\n\n /**\n * Adds a listener for storage changes.\n * @param listener - The listener function to be called when storage changes\n * @returns A function that can be called to remove the listener\n */\n addListener(listener: StorageListener): RemoveStorageListener {\n const wrapper: StorageListener = (event: StorageEventInit) => {\n if (event.storageArea === this.storage) {\n listener(event);\n }\n };\n window.addEventListener(STORAGE_EVENT_TYPE, wrapper);\n return () => window.removeEventListener(STORAGE_EVENT_TYPE, wrapper);\n }\n\n /**\n * Clears all items from the storage.\n */\n clear(): void {\n this.storage.clear();\n }\n\n /**\n * Gets an item from the storage.\n * @param key - The key of the item to retrieve\n * @returns The value of the item, or null if the item does not exist\n */\n getItem(key: string): string | null {\n return this.storage.getItem(key);\n }\n\n /**\n * Gets the key at the specified index.\n * @param index - The index of the key to retrieve\n * @returns The key at the specified index, or null if the index is out of bounds\n */\n key(index: number): string | null {\n return this.storage.key(index);\n }\n\n /**\n * Removes an item from the storage.\n * @param key - The key of the item to remove\n */\n removeItem(key: string): void {\n this.storage.removeItem(key);\n }\n\n /**\n * Sets an item in the storage.\n * @param key - The key of the item to set\n * @param value - The value to set\n */\n setItem(key: string, value: string): void {\n this.storage.setItem(key, value);\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InMemoryListenableStorage } from './inMemoryListenableStorage';\nimport { BrowserListenableStorage } from './browserListenableStorage';\nimport { isBrowser } from './env';\n\n/**\n * The type of storage event used for listening to storage changes.\n */\nexport const STORAGE_EVENT_TYPE = 'storage';\n\n/**\n * A function that handles storage change events.\n */\nexport type StorageListener = (event: StorageEventInit) => void;\n\n/**\n * A function that removes a storage listener when called.\n */\nexport type RemoveStorageListener = () => void;\n\nexport interface StorageListenable {\n /**\n * Adds a listener for storage changes.\n * @param listener - The listener function to be called when storage changes\n * @returns A function that can be called to remove the listener\n */\n addListener(listener: StorageListener): RemoveStorageListener;\n}\n\n/**\n * An interface that extends the native Storage interface with the ability to listen for storage changes.\n */\nexport interface ListenableStorage extends Storage, StorageListenable {\n}\n\n/**\n * Factory function to get an appropriate ListenableStorage implementation based on the environment.\n * In a browser environment, it returns a BrowserListenableStorage wrapping localStorage.\n * In other environments, it returns an InMemoryListenableStorage.\n * @returns A ListenableStorage instance suitable for the current environment\n */\nexport const createListenableStorage = (): ListenableStorage => {\n if (isBrowser()) {\n return new BrowserListenableStorage(window.localStorage);\n }\n return new InMemoryListenableStorage();\n};\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Interface for serializing and deserializing values\n * @template Serialized The type of the serialized value\n */\n/**\n * Interface for serializing and deserializing values\n * @template Serialized The type of the serialized value\n * @template Deserialized The type of the deserialized value\n */\nexport interface Serializer<Serialized, Deserialized> {\n /**\n * Serializes a value to the specified format\n * @param value The value to serialize\n * @returns The serialized value\n */\n serialize(value: any): Serialized;\n\n /**\n * Deserializes a value from the specified format\n * @template Deserialized The type of the deserialized value\n * @param value The value to deserialize\n * @returns The deserialized value\n */\n /**\n * Deserializes a value from the specified format\n * @param value The value to deserialize\n * @returns The deserialized value\n */\n deserialize(value: Serialized): Deserialized;\n}\n\n/**\n * Implementation of Serializer that uses JSON for serialization\n */\nexport class JsonSerializer implements Serializer<string, any> {\n /**\n * Serializes a value to a JSON string\n * @param value The value to serialize\n * @returns The JSON string representation of the value\n */\n /**\n * Serializes a value to a JSON string\n * @param value The value to serialize\n * @returns The JSON string representation of the value\n */\n serialize(value: any): string {\n return JSON.stringify(value);\n }\n\n /**\n * Deserializes a JSON string to a value\n * @template V The type of the deserialized value\n * @param value The JSON string to deserialize\n * @returns The deserialized value\n */\n /**\n * Deserializes a JSON string to a value\n * @param value The JSON string to deserialize\n * @returns The deserialized value\n */\n deserialize<V>(value: string): V {\n return JSON.parse(value);\n }\n}\n\n/**\n * Implementation of Serializer that performs no actual serialization\n * @template T The type of the value to pass through\n */\nexport class IdentitySerializer<T> implements Serializer<T, T> {\n /**\n * Returns the value as-is without serialization\n * @param value The value to pass through\n * @returns The same value that was passed in\n */\n /**\n * Returns the value as-is without serialization\n * @param value The value to pass through\n * @returns The same value that was passed in\n */\n serialize(value: T): T {\n return value;\n }\n\n /**\n * Returns the value as-is without deserialization\n * @template Deserialized The type of the deserialized value\n * @param value The value to pass through\n * @returns The same value that was passed in, cast to the target type\n */\n /**\n * Returns the value as-is without deserialization\n * @param value The value to pass through\n * @returns The same value that was passed in\n */\n deserialize(value: T): T {\n return value;\n }\n}\n\n/**\n * Global instance of JsonSerializer\n */\nexport const jsonSerializer = new JsonSerializer();\n/**\n * Global instance of IdentitySerializer\n */\nexport const identitySerializer = new IdentitySerializer<any>();\n\nexport function typedIdentitySerializer<T>(): IdentitySerializer<T> {\n return identitySerializer as IdentitySerializer<T>;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createListenableStorage,\n ListenableStorage,\n RemoveStorageListener,\n StorageListenable,\n StorageListener,\n} from './listenableStorage';\nimport { Serializer, typedIdentitySerializer } from './serializer';\n\n/**\n * Options for configuring KeyStorage\n */\nexport interface KeyStorageOptions<Deserialized> {\n /**\n * The key used to store and retrieve values from storage\n */\n key: string;\n\n /**\n * Optional serializer for converting values to and from storage format\n * Defaults to IdentitySerializer if not provided\n */\n serializer?: Serializer<string, Deserialized>;\n\n /**\n * Optional storage implementation\n * Defaults to the result of createListenableStorage() if not provided\n */\n storage?: ListenableStorage;\n}\n\n/**\n * A storage wrapper that manages a single value associated with a specific key\n * Provides caching and automatic cache invalidation when the storage value changes\n * @template Deserialized The type of the value being stored\n */\nexport class KeyStorage<Deserialized> implements StorageListenable {\n private readonly key: string;\n private readonly serializer: Serializer<string, Deserialized>;\n private readonly storage: ListenableStorage;\n private cacheValue: Deserialized | null = null;\n\n /**\n * Listener for storage change events\n * Invalidates the cache when the relevant key is modified\n */\n private readonly refreshCacheListener: StorageListener = event => {\n this.cacheValue = null;\n if (event.newValue) {\n this.refreshCache(event.newValue);\n }\n };\n\n /**\n * Refreshes the cached value by deserializing the provided string\n * @param value The serialized value to deserialize and cache\n */\n private refreshCache(value: string) {\n this.cacheValue = this.serializer.deserialize(value);\n }\n\n /**\n * Creates a new KeyStorage instance\n * @param options Configuration options for the storage\n */\n constructor(options: KeyStorageOptions<Deserialized>) {\n this.key = options.key;\n this.serializer = options.serializer ?? typedIdentitySerializer();\n this.storage = options.storage ?? createListenableStorage();\n this.addListener(this.refreshCacheListener);\n }\n\n addListener(listener: StorageListener): RemoveStorageListener {\n const wrapper: StorageListener = (event: StorageEventInit) => {\n if (event.key !== this.key) {\n return;\n }\n listener(event);\n };\n return this.storage.addListener(wrapper);\n }\n\n /**\n * Gets the value associated with the key from storage\n * Uses cached value if available, otherwise retrieves from storage and caches it\n * @returns The deserialized value or null if no value is found\n */\n get(): Deserialized | null {\n if (this.cacheValue) {\n return this.cacheValue;\n }\n const value = this.storage.getItem(this.key);\n if (!value) {\n return null;\n }\n this.refreshCache(value);\n return this.cacheValue;\n }\n\n /**\n * Sets the value associated with the key in storage\n * Also updates the cached value\n * @param value The value to serialize and store\n */\n set(value: Deserialized): void {\n const serialized = this.serializer.serialize(value);\n this.storage.setItem(this.key, serialized);\n this.cacheValue = value;\n }\n\n /**\n * Removes the value associated with the key from storage\n * Also clears the cached value\n */\n remove(): void {\n this.storage.removeItem(this.key);\n this.cacheValue = null;\n }\n}\n"],"names":["isBrowser","InMemoryListenableStorage","key","value","index","oldValue","listener","eventInit","error","BrowserListenableStorage","storage","wrapper","event","STORAGE_EVENT_TYPE","createListenableStorage","JsonSerializer","IdentitySerializer","jsonSerializer","identitySerializer","typedIdentitySerializer","KeyStorage","options","serialized"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"listenableStorage.d.ts","sourceRoot":"","sources":["../src/listenableStorage.ts"],"names":[],"mappings":"AAiBA;;GAEG;AACH,eAAO,MAAM,kBAAkB,YAAY,CAAC;AAE5C;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;AAEhE;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,IAAI,CAAC;AAE/C,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,WAAW,CAAC,QAAQ,EAAE,eAAe,GAAG,qBAAqB,CAAC;CAC/D;AAED;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,OAAO,EAAE,iBAAiB;
|
|
1
|
+
{"version":3,"file":"listenableStorage.d.ts","sourceRoot":"","sources":["../src/listenableStorage.ts"],"names":[],"mappings":"AAiBA;;GAEG;AACH,eAAO,MAAM,kBAAkB,YAAY,CAAC;AAE5C;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;AAEhE;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,IAAI,CAAC;AAE/C,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,WAAW,CAAC,QAAQ,EAAE,eAAe,GAAG,qBAAqB,CAAC;CAC/D;AAED;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,OAAO,EAAE,iBAAiB;CACpE;AAED;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,QAAO,iBAK1C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ahoo-wang/fetcher-storage",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.5",
|
|
4
4
|
"description": "A lightweight, cross-environment storage library with change event listening capabilities. Provides consistent API for browser localStorage/sessionStorage and in-memory storage with change notifications.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"storage",
|