@ahoo-wang/fetcher-storage 3.1.9 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.es.js +20 -20
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/keyStorage.d.ts +5 -0
- package/dist/keyStorage.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.es.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { nameGenerator as i, SerialTypedEventBus as
|
|
2
|
-
class
|
|
1
|
+
import { nameGenerator as i, SerialTypedEventBus as a } from "@ahoo-wang/fetcher-eventbus";
|
|
2
|
+
class n {
|
|
3
3
|
constructor() {
|
|
4
4
|
this.store = /* @__PURE__ */ new Map();
|
|
5
5
|
}
|
|
@@ -51,7 +51,7 @@ class a {
|
|
|
51
51
|
function l() {
|
|
52
52
|
return typeof window < "u";
|
|
53
53
|
}
|
|
54
|
-
const
|
|
54
|
+
const u = () => l() ? window.localStorage : new n();
|
|
55
55
|
class h {
|
|
56
56
|
/**
|
|
57
57
|
* Serializes a value to a JSON string
|
|
@@ -70,7 +70,7 @@ class h {
|
|
|
70
70
|
return JSON.parse(e);
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
-
class
|
|
73
|
+
class o {
|
|
74
74
|
/**
|
|
75
75
|
* Returns the value as-is without serialization
|
|
76
76
|
* @param value The value to pass through
|
|
@@ -88,9 +88,9 @@ class u {
|
|
|
88
88
|
return e;
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
|
-
const
|
|
92
|
-
function
|
|
93
|
-
return
|
|
91
|
+
const c = new h(), d = new o();
|
|
92
|
+
function g() {
|
|
93
|
+
return d;
|
|
94
94
|
}
|
|
95
95
|
class m {
|
|
96
96
|
/**
|
|
@@ -98,14 +98,14 @@ class m {
|
|
|
98
98
|
* @param options Configuration options for the storage
|
|
99
99
|
*/
|
|
100
100
|
constructor(e) {
|
|
101
|
-
this.cacheValue = null, this.keyStorageHandler = {
|
|
101
|
+
this.defaultValue = null, this.cacheValue = null, this.keyStorageHandler = {
|
|
102
102
|
name: i.generate("KeyStorage"),
|
|
103
103
|
handle: (t) => {
|
|
104
104
|
this.cacheValue = t.newValue ?? null;
|
|
105
105
|
}
|
|
106
|
-
}, this.key = e.key, this.serializer = e.serializer ??
|
|
106
|
+
}, this.key = e.key, this.serializer = e.serializer ?? c, this.storage = e.storage ?? u(), this.eventBus = e.eventBus ?? new a(
|
|
107
107
|
`KeyStorage:${this.key}`
|
|
108
|
-
), this.eventBus.on(this.keyStorageHandler);
|
|
108
|
+
), this.defaultValue = e.defaultValue ?? null, this.eventBus.on(this.keyStorageHandler);
|
|
109
109
|
}
|
|
110
110
|
/**
|
|
111
111
|
* Adds a listener for storage changes.
|
|
@@ -149,10 +149,10 @@ class m {
|
|
|
149
149
|
* ```
|
|
150
150
|
*/
|
|
151
151
|
get() {
|
|
152
|
-
if (this.cacheValue)
|
|
152
|
+
if (this.cacheValue !== null && this.cacheValue !== void 0)
|
|
153
153
|
return this.cacheValue;
|
|
154
154
|
const e = this.storage.getItem(this.key);
|
|
155
|
-
return e ? (this.cacheValue = this.serializer.deserialize(e), this.cacheValue)
|
|
155
|
+
return e == null ? this.defaultValue : (this.cacheValue = this.serializer.deserialize(e), this.cacheValue);
|
|
156
156
|
}
|
|
157
157
|
/**
|
|
158
158
|
* Stores a value in storage and notifies all listeners.
|
|
@@ -169,8 +169,8 @@ class m {
|
|
|
169
169
|
* ```
|
|
170
170
|
*/
|
|
171
171
|
set(e) {
|
|
172
|
-
const t = this.get(),
|
|
173
|
-
this.storage.setItem(this.key,
|
|
172
|
+
const t = this.get(), r = this.serializer.serialize(e);
|
|
173
|
+
this.storage.setItem(this.key, r), this.cacheValue = e, this.eventBus.emit({
|
|
174
174
|
newValue: e,
|
|
175
175
|
oldValue: t
|
|
176
176
|
});
|
|
@@ -213,14 +213,14 @@ class m {
|
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
215
|
export {
|
|
216
|
-
|
|
217
|
-
|
|
216
|
+
o as IdentitySerializer,
|
|
217
|
+
n as InMemoryStorage,
|
|
218
218
|
h as JsonSerializer,
|
|
219
219
|
m as KeyStorage,
|
|
220
|
-
|
|
221
|
-
|
|
220
|
+
u as getStorage,
|
|
221
|
+
d as identitySerializer,
|
|
222
222
|
l as isBrowser,
|
|
223
|
-
|
|
224
|
-
|
|
223
|
+
c as jsonSerializer,
|
|
224
|
+
g as typedIdentitySerializer
|
|
225
225
|
};
|
|
226
226
|
//# sourceMappingURL=index.es.js.map
|
package/dist/index.es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.es.js","sources":["../src/inMemoryStorage.ts","../src/env.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 class InMemoryStorage implements Storage {\n private readonly store: Map<string, string> = new Map();\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 this.store.delete(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.store.set(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 { InMemoryStorage } from './inMemoryStorage';\n\n/**\n * Checks if the current environment is a browser.\n * @returns True if running in a browser environment, false otherwise\n */\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined';\n}\n\n/**\n * Gets the appropriate storage implementation based on the environment.\n * Returns localStorage in browser environments if available, InMemoryStorage otherwise.\n * @returns A Storage-compatible object\n */\nexport const getStorage = (): Storage => {\n if (isBrowser()) {\n return window.localStorage;\n }\n return new InMemoryStorage();\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 * @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 * @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 serialize(value: any): string {\n return JSON.stringify(value);\n }\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(value: string): any {\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 serialize(value: T): T {\n return value;\n }\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 { Serializer, typedIdentitySerializer } from './serializer';\nimport {\n EventHandler,\n nameGenerator,\n SerialTypedEventBus,\n TypedEventBus,\n} from '@ahoo-wang/fetcher-eventbus';\nimport { getStorage } from './env';\n\nexport interface StorageEvent<Deserialized> {\n newValue?: Deserialized | null;\n oldValue?: Deserialized | null;\n}\n\n/**\n * A function that removes a storage listener when called.\n */\nexport type RemoveStorageListener = () => void;\n\nexport interface StorageListenable<Deserialized> {\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(\n listener: EventHandler<StorageEvent<Deserialized>>,\n ): RemoveStorageListener;\n}\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 instance. Defaults to localStorage\n */\n storage?: Storage;\n\n /**\n * Optional event bus for cross-tab communication. Defaults to SerialTypedEventBus\n */\n eventBus?: TypedEventBus<StorageEvent<Deserialized>>;\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>\n implements StorageListenable<Deserialized>\n{\n private readonly key: string;\n private readonly serializer: Serializer<string, Deserialized>;\n private readonly storage: Storage;\n public readonly eventBus: TypedEventBus<StorageEvent<Deserialized>>;\n private cacheValue: Deserialized | null = null;\n private readonly keyStorageHandler: EventHandler<StorageEvent<Deserialized>> =\n {\n name: nameGenerator.generate('KeyStorage'),\n handle: (event: StorageEvent<Deserialized>) => {\n this.cacheValue = event.newValue ?? null;\n },\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 ?? getStorage();\n this.eventBus =\n options.eventBus ??\n new SerialTypedEventBus<StorageEvent<Deserialized>>(\n `KeyStorage:${this.key}`,\n );\n this.eventBus.on(this.keyStorageHandler);\n }\n\n /**\n * Adds a listener for storage changes.\n *\n * The listener will be called whenever the storage value changes,\n * either locally or from other tabs/windows.\n *\n * @param listener - The event handler to be called when storage changes\n * @returns A function that can be called to remove the listener\n *\n * @example\n * ```typescript\n * const storage = new KeyStorage<string>({ key: 'userName' });\n * const removeListener = storage.addListener({\n * name: 'userNameChange',\n * handle: (event) => {\n * console.log('User name changed:', event.newValue);\n * }\n * });\n *\n * // Later, to remove the listener\n * removeListener();\n * ```\n */\n addListener(\n listener: EventHandler<StorageEvent<Deserialized>>,\n ): RemoveStorageListener {\n this.eventBus.on(listener);\n return () => this.eventBus.off(listener.name);\n }\n\n /**\n * Retrieves the current value from storage.\n *\n * Uses caching to avoid repeated deserialization. If the value is not in cache,\n * it retrieves it from the underlying storage and deserializes it.\n *\n * @returns The deserialized value, or null if no value exists in storage\n *\n * @example\n * ```typescript\n * const storage = new KeyStorage<string>({ key: 'userName' });\n * const userName = storage.get();\n * console.log(userName); // 'John Doe' or null\n * ```\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.cacheValue = this.serializer.deserialize(value);\n return this.cacheValue;\n }\n\n /**\n * Stores a value in storage and notifies all listeners.\n *\n * Serializes the value, stores it in the underlying storage, updates the cache,\n * and emits a change event to all registered listeners.\n *\n * @param value - The value to store (will be serialized before storage)\n *\n * @example\n * ```typescript\n * const storage = new KeyStorage<string>({ key: 'userName' });\n * storage.set('John Doe');\n * ```\n */\n set(value: Deserialized): void {\n const oldValue = this.get();\n const serialized = this.serializer.serialize(value);\n this.storage.setItem(this.key, serialized);\n this.cacheValue = value;\n this.eventBus.emit({\n newValue: value,\n oldValue: oldValue,\n });\n }\n\n /**\n * Removes the value from storage and notifies all listeners.\n *\n * Removes the item from the underlying storage, clears the cache,\n * and emits a change event indicating the value was removed.\n *\n * @example\n * ```typescript\n * const storage = new KeyStorage<string>({ key: 'userName' });\n * storage.remove(); // Removes the stored value\n * ```\n */\n remove(): void {\n const oldValue = this.get();\n this.storage.removeItem(this.key);\n this.cacheValue = null;\n this.eventBus.emit({\n oldValue: oldValue,\n newValue: null,\n });\n }\n\n /**\n * Cleans up resources used by the KeyStorage instance.\n *\n * Removes the internal event handler from the event bus.\n * Should be called when the KeyStorage instance is no longer needed\n * to prevent memory leaks.\n *\n * @example\n * ```typescript\n * const storage = new KeyStorage<string>({ key: 'userName' });\n * // ... use storage ...\n * storage.destroy(); // Clean up resources\n * ```\n */\n destroy() {\n this.eventBus.off(this.keyStorageHandler.name);\n }\n}\n"],"names":["InMemoryStorage","key","value","index","isBrowser","getStorage","JsonSerializer","IdentitySerializer","jsonSerializer","identitySerializer","typedIdentitySerializer","KeyStorage","options","nameGenerator","event","SerialTypedEventBus","listener","oldValue","serialized"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.es.js","sources":["../src/inMemoryStorage.ts","../src/env.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 class InMemoryStorage implements Storage {\n private readonly store: Map<string, string> = new Map();\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 this.store.delete(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.store.set(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 { InMemoryStorage } from './inMemoryStorage';\n\n/**\n * Checks if the current environment is a browser.\n * @returns True if running in a browser environment, false otherwise\n */\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined';\n}\n\n/**\n * Gets the appropriate storage implementation based on the environment.\n * Returns localStorage in browser environments if available, InMemoryStorage otherwise.\n * @returns A Storage-compatible object\n */\nexport const getStorage = (): Storage => {\n if (isBrowser()) {\n return window.localStorage;\n }\n return new InMemoryStorage();\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 * @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 * @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 serialize(value: any): string {\n return JSON.stringify(value);\n }\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(value: string): any {\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 serialize(value: T): T {\n return value;\n }\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 { jsonSerializer, Serializer } from './serializer';\nimport {\n EventHandler,\n nameGenerator,\n SerialTypedEventBus,\n TypedEventBus,\n} from '@ahoo-wang/fetcher-eventbus';\nimport { getStorage } from './env';\n\nexport interface StorageEvent<Deserialized> {\n newValue?: Deserialized | null;\n oldValue?: Deserialized | null;\n}\n\n/**\n * A function that removes a storage listener when called.\n */\nexport type RemoveStorageListener = () => void;\n\nexport interface StorageListenable<Deserialized> {\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(\n listener: EventHandler<StorageEvent<Deserialized>>,\n ): RemoveStorageListener;\n}\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 instance. Defaults to localStorage\n */\n storage?: Storage;\n\n /**\n * Optional event bus for cross-tab communication. Defaults to SerialTypedEventBus\n */\n eventBus?: TypedEventBus<StorageEvent<Deserialized>>;\n\n /**\n * Optional default value to return when no value exists in storage\n */\n defaultValue?: Deserialized;\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>\n implements StorageListenable<Deserialized> {\n private readonly key: string;\n private readonly serializer: Serializer<string, Deserialized>;\n private readonly storage: Storage;\n public readonly eventBus: TypedEventBus<StorageEvent<Deserialized>>;\n private readonly defaultValue: Deserialized | null = null;\n private cacheValue: Deserialized | null = null;\n private readonly keyStorageHandler: EventHandler<StorageEvent<Deserialized>> =\n {\n name: nameGenerator.generate('KeyStorage'),\n handle: (event: StorageEvent<Deserialized>) => {\n this.cacheValue = event.newValue ?? null;\n },\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 ?? jsonSerializer;\n this.storage = options.storage ?? getStorage();\n this.eventBus =\n options.eventBus ??\n new SerialTypedEventBus<StorageEvent<Deserialized>>(\n `KeyStorage:${this.key}`,\n );\n this.defaultValue = options.defaultValue ?? null;\n this.eventBus.on(this.keyStorageHandler);\n }\n\n /**\n * Adds a listener for storage changes.\n *\n * The listener will be called whenever the storage value changes,\n * either locally or from other tabs/windows.\n *\n * @param listener - The event handler to be called when storage changes\n * @returns A function that can be called to remove the listener\n *\n * @example\n * ```typescript\n * const storage = new KeyStorage<string>({ key: 'userName' });\n * const removeListener = storage.addListener({\n * name: 'userNameChange',\n * handle: (event) => {\n * console.log('User name changed:', event.newValue);\n * }\n * });\n *\n * // Later, to remove the listener\n * removeListener();\n * ```\n */\n addListener(\n listener: EventHandler<StorageEvent<Deserialized>>,\n ): RemoveStorageListener {\n this.eventBus.on(listener);\n return () => this.eventBus.off(listener.name);\n }\n\n /**\n * Retrieves the current value from storage.\n *\n * Uses caching to avoid repeated deserialization. If the value is not in cache,\n * it retrieves it from the underlying storage and deserializes it.\n *\n * @returns The deserialized value, or null if no value exists in storage\n *\n * @example\n * ```typescript\n * const storage = new KeyStorage<string>({ key: 'userName' });\n * const userName = storage.get();\n * console.log(userName); // 'John Doe' or null\n * ```\n */\n get(): Deserialized | null {\n if (this.cacheValue !== null && this.cacheValue !== undefined) {\n return this.cacheValue;\n }\n const value = this.storage.getItem(this.key);\n if (value === null || value === undefined) {\n return this.defaultValue;\n }\n this.cacheValue = this.serializer.deserialize(value);\n return this.cacheValue;\n }\n\n /**\n * Stores a value in storage and notifies all listeners.\n *\n * Serializes the value, stores it in the underlying storage, updates the cache,\n * and emits a change event to all registered listeners.\n *\n * @param value - The value to store (will be serialized before storage)\n *\n * @example\n * ```typescript\n * const storage = new KeyStorage<string>({ key: 'userName' });\n * storage.set('John Doe');\n * ```\n */\n set(value: Deserialized): void {\n const oldValue = this.get();\n const serialized = this.serializer.serialize(value);\n this.storage.setItem(this.key, serialized);\n this.cacheValue = value;\n this.eventBus.emit({\n newValue: value,\n oldValue: oldValue,\n });\n }\n\n /**\n * Removes the value from storage and notifies all listeners.\n *\n * Removes the item from the underlying storage, clears the cache,\n * and emits a change event indicating the value was removed.\n *\n * @example\n * ```typescript\n * const storage = new KeyStorage<string>({ key: 'userName' });\n * storage.remove(); // Removes the stored value\n * ```\n */\n remove(): void {\n const oldValue = this.get();\n this.storage.removeItem(this.key);\n this.cacheValue = null;\n this.eventBus.emit({\n oldValue: oldValue,\n newValue: null,\n });\n }\n\n /**\n * Cleans up resources used by the KeyStorage instance.\n *\n * Removes the internal event handler from the event bus.\n * Should be called when the KeyStorage instance is no longer needed\n * to prevent memory leaks.\n *\n * @example\n * ```typescript\n * const storage = new KeyStorage<string>({ key: 'userName' });\n * // ... use storage ...\n * storage.destroy(); // Clean up resources\n * ```\n */\n destroy() {\n this.eventBus.off(this.keyStorageHandler.name);\n }\n}\n"],"names":["InMemoryStorage","key","value","index","isBrowser","getStorage","JsonSerializer","IdentitySerializer","jsonSerializer","identitySerializer","typedIdentitySerializer","KeyStorage","options","nameGenerator","event","SerialTypedEventBus","listener","oldValue","serialized"],"mappings":"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"}
|
package/dist/index.umd.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(t,r){typeof exports=="object"&&typeof module<"u"?r(exports,require("@ahoo-wang/fetcher-eventbus")):typeof define=="function"&&define.amd?define(["exports","@ahoo-wang/fetcher-eventbus"],r):(t=typeof globalThis<"u"?globalThis:t||self,r(t.Fetcher={},t.FetcherEventBus))})(this,(function(t,r){"use strict";class n{constructor(){this.store=new Map}get length(){return this.store.size}clear(){this.store.clear()}getItem(e){const i=this.store.get(e);return i!==void 0?i:null}key(e){return Array.from(this.store.keys())[e]||null}removeItem(e){this.store.delete(e)}setItem(e,i){this.store.set(e,i)}}function a(){return typeof window<"u"}const l=()=>a()?window.localStorage:new n;class
|
|
1
|
+
(function(t,r){typeof exports=="object"&&typeof module<"u"?r(exports,require("@ahoo-wang/fetcher-eventbus")):typeof define=="function"&&define.amd?define(["exports","@ahoo-wang/fetcher-eventbus"],r):(t=typeof globalThis<"u"?globalThis:t||self,r(t.Fetcher={},t.FetcherEventBus))})(this,(function(t,r){"use strict";class n{constructor(){this.store=new Map}get length(){return this.store.size}clear(){this.store.clear()}getItem(e){const i=this.store.get(e);return i!==void 0?i:null}key(e){return Array.from(this.store.keys())[e]||null}removeItem(e){this.store.delete(e)}setItem(e,i){this.store.set(e,i)}}function a(){return typeof window<"u"}const l=()=>a()?window.localStorage:new n;class u{serialize(e){return JSON.stringify(e)}deserialize(e){return JSON.parse(e)}}class o{serialize(e){return e}deserialize(e){return e}}const h=new u,c=new o;function d(){return c}class y{constructor(e){this.defaultValue=null,this.cacheValue=null,this.keyStorageHandler={name:r.nameGenerator.generate("KeyStorage"),handle:i=>{this.cacheValue=i.newValue??null}},this.key=e.key,this.serializer=e.serializer??h,this.storage=e.storage??l(),this.eventBus=e.eventBus??new r.SerialTypedEventBus(`KeyStorage:${this.key}`),this.defaultValue=e.defaultValue??null,this.eventBus.on(this.keyStorageHandler)}addListener(e){return this.eventBus.on(e),()=>this.eventBus.off(e.name)}get(){if(this.cacheValue!==null&&this.cacheValue!==void 0)return this.cacheValue;const e=this.storage.getItem(this.key);return e==null?this.defaultValue:(this.cacheValue=this.serializer.deserialize(e),this.cacheValue)}set(e){const i=this.get(),g=this.serializer.serialize(e);this.storage.setItem(this.key,g),this.cacheValue=e,this.eventBus.emit({newValue:e,oldValue:i})}remove(){const e=this.get();this.storage.removeItem(this.key),this.cacheValue=null,this.eventBus.emit({oldValue:e,newValue:null})}destroy(){this.eventBus.off(this.keyStorageHandler.name)}}t.IdentitySerializer=o,t.InMemoryStorage=n,t.JsonSerializer=u,t.KeyStorage=y,t.getStorage=l,t.identitySerializer=c,t.isBrowser=a,t.jsonSerializer=h,t.typedIdentitySerializer=d,Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})}));
|
|
2
2
|
//# sourceMappingURL=index.umd.js.map
|
package/dist/index.umd.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.umd.js","sources":["../src/inMemoryStorage.ts","../src/env.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 class InMemoryStorage implements Storage {\n private readonly store: Map<string, string> = new Map();\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 this.store.delete(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.store.set(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 { InMemoryStorage } from './inMemoryStorage';\n\n/**\n * Checks if the current environment is a browser.\n * @returns True if running in a browser environment, false otherwise\n */\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined';\n}\n\n/**\n * Gets the appropriate storage implementation based on the environment.\n * Returns localStorage in browser environments if available, InMemoryStorage otherwise.\n * @returns A Storage-compatible object\n */\nexport const getStorage = (): Storage => {\n if (isBrowser()) {\n return window.localStorage;\n }\n return new InMemoryStorage();\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 * @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 * @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 serialize(value: any): string {\n return JSON.stringify(value);\n }\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(value: string): any {\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 serialize(value: T): T {\n return value;\n }\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 { Serializer, typedIdentitySerializer } from './serializer';\nimport {\n EventHandler,\n nameGenerator,\n SerialTypedEventBus,\n TypedEventBus,\n} from '@ahoo-wang/fetcher-eventbus';\nimport { getStorage } from './env';\n\nexport interface StorageEvent<Deserialized> {\n newValue?: Deserialized | null;\n oldValue?: Deserialized | null;\n}\n\n/**\n * A function that removes a storage listener when called.\n */\nexport type RemoveStorageListener = () => void;\n\nexport interface StorageListenable<Deserialized> {\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(\n listener: EventHandler<StorageEvent<Deserialized>>,\n ): RemoveStorageListener;\n}\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 instance. Defaults to localStorage\n */\n storage?: Storage;\n\n /**\n * Optional event bus for cross-tab communication. Defaults to SerialTypedEventBus\n */\n eventBus?: TypedEventBus<StorageEvent<Deserialized>>;\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>\n implements StorageListenable<Deserialized>\n{\n private readonly key: string;\n private readonly serializer: Serializer<string, Deserialized>;\n private readonly storage: Storage;\n public readonly eventBus: TypedEventBus<StorageEvent<Deserialized>>;\n private cacheValue: Deserialized | null = null;\n private readonly keyStorageHandler: EventHandler<StorageEvent<Deserialized>> =\n {\n name: nameGenerator.generate('KeyStorage'),\n handle: (event: StorageEvent<Deserialized>) => {\n this.cacheValue = event.newValue ?? null;\n },\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 ?? getStorage();\n this.eventBus =\n options.eventBus ??\n new SerialTypedEventBus<StorageEvent<Deserialized>>(\n `KeyStorage:${this.key}`,\n );\n this.eventBus.on(this.keyStorageHandler);\n }\n\n /**\n * Adds a listener for storage changes.\n *\n * The listener will be called whenever the storage value changes,\n * either locally or from other tabs/windows.\n *\n * @param listener - The event handler to be called when storage changes\n * @returns A function that can be called to remove the listener\n *\n * @example\n * ```typescript\n * const storage = new KeyStorage<string>({ key: 'userName' });\n * const removeListener = storage.addListener({\n * name: 'userNameChange',\n * handle: (event) => {\n * console.log('User name changed:', event.newValue);\n * }\n * });\n *\n * // Later, to remove the listener\n * removeListener();\n * ```\n */\n addListener(\n listener: EventHandler<StorageEvent<Deserialized>>,\n ): RemoveStorageListener {\n this.eventBus.on(listener);\n return () => this.eventBus.off(listener.name);\n }\n\n /**\n * Retrieves the current value from storage.\n *\n * Uses caching to avoid repeated deserialization. If the value is not in cache,\n * it retrieves it from the underlying storage and deserializes it.\n *\n * @returns The deserialized value, or null if no value exists in storage\n *\n * @example\n * ```typescript\n * const storage = new KeyStorage<string>({ key: 'userName' });\n * const userName = storage.get();\n * console.log(userName); // 'John Doe' or null\n * ```\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.cacheValue = this.serializer.deserialize(value);\n return this.cacheValue;\n }\n\n /**\n * Stores a value in storage and notifies all listeners.\n *\n * Serializes the value, stores it in the underlying storage, updates the cache,\n * and emits a change event to all registered listeners.\n *\n * @param value - The value to store (will be serialized before storage)\n *\n * @example\n * ```typescript\n * const storage = new KeyStorage<string>({ key: 'userName' });\n * storage.set('John Doe');\n * ```\n */\n set(value: Deserialized): void {\n const oldValue = this.get();\n const serialized = this.serializer.serialize(value);\n this.storage.setItem(this.key, serialized);\n this.cacheValue = value;\n this.eventBus.emit({\n newValue: value,\n oldValue: oldValue,\n });\n }\n\n /**\n * Removes the value from storage and notifies all listeners.\n *\n * Removes the item from the underlying storage, clears the cache,\n * and emits a change event indicating the value was removed.\n *\n * @example\n * ```typescript\n * const storage = new KeyStorage<string>({ key: 'userName' });\n * storage.remove(); // Removes the stored value\n * ```\n */\n remove(): void {\n const oldValue = this.get();\n this.storage.removeItem(this.key);\n this.cacheValue = null;\n this.eventBus.emit({\n oldValue: oldValue,\n newValue: null,\n });\n }\n\n /**\n * Cleans up resources used by the KeyStorage instance.\n *\n * Removes the internal event handler from the event bus.\n * Should be called when the KeyStorage instance is no longer needed\n * to prevent memory leaks.\n *\n * @example\n * ```typescript\n * const storage = new KeyStorage<string>({ key: 'userName' });\n * // ... use storage ...\n * storage.destroy(); // Clean up resources\n * ```\n */\n destroy() {\n this.eventBus.off(this.keyStorageHandler.name);\n }\n}\n"],"names":["InMemoryStorage","key","value","index","isBrowser","getStorage","JsonSerializer","IdentitySerializer","jsonSerializer","identitySerializer","typedIdentitySerializer","KeyStorage","options","nameGenerator","event","SerialTypedEventBus","listener","oldValue","serialized"],"mappings":"yTAaO,MAAMA,CAAmC,CAAzC,aAAA,CACL,KAAiB,UAAiC,GAAI,CAKtD,IAAI,QAAiB,CACnB,OAAO,KAAK,MAAM,IACpB,CAKA,OAAc,CACZ,KAAK,MAAM,MAAA,CACb,CAOA,QAAQC,EAA4B,CAClC,MAAMC,EAAQ,KAAK,MAAM,IAAID,CAAG,EAChC,OAAOC,IAAU,OAAYA,EAAQ,IACvC,CAOA,IAAIC,EAA8B,CAEhC,OADa,MAAM,KAAK,KAAK,MAAM,MAAM,EAC7BA,CAAK,GAAK,IACxB,CAMA,WAAWF,EAAmB,CAC5B,KAAK,MAAM,OAAOA,CAAG,CACvB,CAOA,QAAQA,EAAaC,EAAqB,CACxC,KAAK,MAAM,IAAID,EAAKC,CAAK,CAC3B,CACF,CC/CO,SAASE,GAAqB,CACnC,OAAO,OAAO,OAAW,GAC3B,CAOO,MAAMC,EAAa,IACpBD,IACK,OAAO,aAET,IAAIJ,ECKN,MAAMM,CAAkD,CAM7D,UAAUJ,EAAoB,CAC5B,OAAO,KAAK,UAAUA,CAAK,CAC7B,CAOA,YAAYA,EAAoB,CAC9B,OAAO,KAAK,MAAMA,CAAK,CACzB,CACF,CAMO,MAAMK,CAAkD,CAM7D,UAAUL,EAAa,CACrB,OAAOA,CACT,CAOA,YAAYA,EAAa,CACvB,OAAOA,CACT,CACF,CAKO,MAAMM,EAAiB,IAAIF,EAIrBG,EAAqB,IAAIF,EAE/B,SAASG,GAAoD,CAClE,OAAOD,CACT,CClBO,MAAME,CAEb,CAkBE,YAAYC,EAA0C,CAbtD,KAAQ,WAAkC,KAC1C,KAAiB,kBACf,CACE,KAAMC,EAAAA,cAAc,SAAS,YAAY,EACzC,OAASC,GAAsC,CAC7C,KAAK,WAAaA,EAAM,UAAY,IACtC,CAAA,EAQF,KAAK,IAAMF,EAAQ,IACnB,KAAK,WAAaA,EAAQ,YAAcF,EAAA,EACxC,KAAK,QAAUE,EAAQ,SAAWP,EAAA,EAClC,KAAK,SACHO,EAAQ,UACR,IAAIG,EAAAA,oBACF,cAAc,KAAK,GAAG,EAAA,EAE1B,KAAK,SAAS,GAAG,KAAK,iBAAiB,CACzC,CAyBA,YACEC,EACuB,CACvB,YAAK,SAAS,GAAGA,CAAQ,EAClB,IAAM,KAAK,SAAS,IAAIA,EAAS,IAAI,CAC9C,CAiBA,KAA2B,CACzB,GAAI,KAAK,WACP,OAAO,KAAK,WAEd,MAAMd,EAAQ,KAAK,QAAQ,QAAQ,KAAK,GAAG,EAC3C,OAAKA,GAGL,KAAK,WAAa,KAAK,WAAW,YAAYA,CAAK,EAC5C,KAAK,YAHH,IAIX,CAgBA,IAAIA,EAA2B,CAC7B,MAAMe,EAAW,KAAK,IAAA,EAChBC,EAAa,KAAK,WAAW,UAAUhB,CAAK,EAClD,KAAK,QAAQ,QAAQ,KAAK,IAAKgB,CAAU,EACzC,KAAK,WAAahB,EAClB,KAAK,SAAS,KAAK,CACjB,SAAUA,EACV,SAAAe,CAAA,CACD,CACH,CAcA,QAAe,CACb,MAAMA,EAAW,KAAK,IAAA,EACtB,KAAK,QAAQ,WAAW,KAAK,GAAG,EAChC,KAAK,WAAa,KAClB,KAAK,SAAS,KAAK,CACjB,SAAAA,EACA,SAAU,IAAA,CACX,CACH,CAgBA,SAAU,CACR,KAAK,SAAS,IAAI,KAAK,kBAAkB,IAAI,CAC/C,CACF"}
|
|
1
|
+
{"version":3,"file":"index.umd.js","sources":["../src/inMemoryStorage.ts","../src/env.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 class InMemoryStorage implements Storage {\n private readonly store: Map<string, string> = new Map();\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 this.store.delete(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.store.set(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 { InMemoryStorage } from './inMemoryStorage';\n\n/**\n * Checks if the current environment is a browser.\n * @returns True if running in a browser environment, false otherwise\n */\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined';\n}\n\n/**\n * Gets the appropriate storage implementation based on the environment.\n * Returns localStorage in browser environments if available, InMemoryStorage otherwise.\n * @returns A Storage-compatible object\n */\nexport const getStorage = (): Storage => {\n if (isBrowser()) {\n return window.localStorage;\n }\n return new InMemoryStorage();\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 * @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 * @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 serialize(value: any): string {\n return JSON.stringify(value);\n }\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(value: string): any {\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 serialize(value: T): T {\n return value;\n }\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 { jsonSerializer, Serializer } from './serializer';\nimport {\n EventHandler,\n nameGenerator,\n SerialTypedEventBus,\n TypedEventBus,\n} from '@ahoo-wang/fetcher-eventbus';\nimport { getStorage } from './env';\n\nexport interface StorageEvent<Deserialized> {\n newValue?: Deserialized | null;\n oldValue?: Deserialized | null;\n}\n\n/**\n * A function that removes a storage listener when called.\n */\nexport type RemoveStorageListener = () => void;\n\nexport interface StorageListenable<Deserialized> {\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(\n listener: EventHandler<StorageEvent<Deserialized>>,\n ): RemoveStorageListener;\n}\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 instance. Defaults to localStorage\n */\n storage?: Storage;\n\n /**\n * Optional event bus for cross-tab communication. Defaults to SerialTypedEventBus\n */\n eventBus?: TypedEventBus<StorageEvent<Deserialized>>;\n\n /**\n * Optional default value to return when no value exists in storage\n */\n defaultValue?: Deserialized;\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>\n implements StorageListenable<Deserialized> {\n private readonly key: string;\n private readonly serializer: Serializer<string, Deserialized>;\n private readonly storage: Storage;\n public readonly eventBus: TypedEventBus<StorageEvent<Deserialized>>;\n private readonly defaultValue: Deserialized | null = null;\n private cacheValue: Deserialized | null = null;\n private readonly keyStorageHandler: EventHandler<StorageEvent<Deserialized>> =\n {\n name: nameGenerator.generate('KeyStorage'),\n handle: (event: StorageEvent<Deserialized>) => {\n this.cacheValue = event.newValue ?? null;\n },\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 ?? jsonSerializer;\n this.storage = options.storage ?? getStorage();\n this.eventBus =\n options.eventBus ??\n new SerialTypedEventBus<StorageEvent<Deserialized>>(\n `KeyStorage:${this.key}`,\n );\n this.defaultValue = options.defaultValue ?? null;\n this.eventBus.on(this.keyStorageHandler);\n }\n\n /**\n * Adds a listener for storage changes.\n *\n * The listener will be called whenever the storage value changes,\n * either locally or from other tabs/windows.\n *\n * @param listener - The event handler to be called when storage changes\n * @returns A function that can be called to remove the listener\n *\n * @example\n * ```typescript\n * const storage = new KeyStorage<string>({ key: 'userName' });\n * const removeListener = storage.addListener({\n * name: 'userNameChange',\n * handle: (event) => {\n * console.log('User name changed:', event.newValue);\n * }\n * });\n *\n * // Later, to remove the listener\n * removeListener();\n * ```\n */\n addListener(\n listener: EventHandler<StorageEvent<Deserialized>>,\n ): RemoveStorageListener {\n this.eventBus.on(listener);\n return () => this.eventBus.off(listener.name);\n }\n\n /**\n * Retrieves the current value from storage.\n *\n * Uses caching to avoid repeated deserialization. If the value is not in cache,\n * it retrieves it from the underlying storage and deserializes it.\n *\n * @returns The deserialized value, or null if no value exists in storage\n *\n * @example\n * ```typescript\n * const storage = new KeyStorage<string>({ key: 'userName' });\n * const userName = storage.get();\n * console.log(userName); // 'John Doe' or null\n * ```\n */\n get(): Deserialized | null {\n if (this.cacheValue !== null && this.cacheValue !== undefined) {\n return this.cacheValue;\n }\n const value = this.storage.getItem(this.key);\n if (value === null || value === undefined) {\n return this.defaultValue;\n }\n this.cacheValue = this.serializer.deserialize(value);\n return this.cacheValue;\n }\n\n /**\n * Stores a value in storage and notifies all listeners.\n *\n * Serializes the value, stores it in the underlying storage, updates the cache,\n * and emits a change event to all registered listeners.\n *\n * @param value - The value to store (will be serialized before storage)\n *\n * @example\n * ```typescript\n * const storage = new KeyStorage<string>({ key: 'userName' });\n * storage.set('John Doe');\n * ```\n */\n set(value: Deserialized): void {\n const oldValue = this.get();\n const serialized = this.serializer.serialize(value);\n this.storage.setItem(this.key, serialized);\n this.cacheValue = value;\n this.eventBus.emit({\n newValue: value,\n oldValue: oldValue,\n });\n }\n\n /**\n * Removes the value from storage and notifies all listeners.\n *\n * Removes the item from the underlying storage, clears the cache,\n * and emits a change event indicating the value was removed.\n *\n * @example\n * ```typescript\n * const storage = new KeyStorage<string>({ key: 'userName' });\n * storage.remove(); // Removes the stored value\n * ```\n */\n remove(): void {\n const oldValue = this.get();\n this.storage.removeItem(this.key);\n this.cacheValue = null;\n this.eventBus.emit({\n oldValue: oldValue,\n newValue: null,\n });\n }\n\n /**\n * Cleans up resources used by the KeyStorage instance.\n *\n * Removes the internal event handler from the event bus.\n * Should be called when the KeyStorage instance is no longer needed\n * to prevent memory leaks.\n *\n * @example\n * ```typescript\n * const storage = new KeyStorage<string>({ key: 'userName' });\n * // ... use storage ...\n * storage.destroy(); // Clean up resources\n * ```\n */\n destroy() {\n this.eventBus.off(this.keyStorageHandler.name);\n }\n}\n"],"names":["InMemoryStorage","key","value","index","isBrowser","getStorage","JsonSerializer","IdentitySerializer","jsonSerializer","identitySerializer","typedIdentitySerializer","KeyStorage","options","nameGenerator","event","SerialTypedEventBus","listener","oldValue","serialized"],"mappings":"yTAaO,MAAMA,CAAmC,CAAzC,aAAA,CACL,KAAiB,UAAiC,GAAI,CAKtD,IAAI,QAAiB,CACnB,OAAO,KAAK,MAAM,IACpB,CAKA,OAAc,CACZ,KAAK,MAAM,MAAA,CACb,CAOA,QAAQC,EAA4B,CAClC,MAAMC,EAAQ,KAAK,MAAM,IAAID,CAAG,EAChC,OAAOC,IAAU,OAAYA,EAAQ,IACvC,CAOA,IAAIC,EAA8B,CAEhC,OADa,MAAM,KAAK,KAAK,MAAM,MAAM,EAC7BA,CAAK,GAAK,IACxB,CAMA,WAAWF,EAAmB,CAC5B,KAAK,MAAM,OAAOA,CAAG,CACvB,CAOA,QAAQA,EAAaC,EAAqB,CACxC,KAAK,MAAM,IAAID,EAAKC,CAAK,CAC3B,CACF,CC/CO,SAASE,GAAqB,CACnC,OAAO,OAAO,OAAW,GAC3B,CAOO,MAAMC,EAAa,IACpBD,IACK,OAAO,aAET,IAAIJ,ECKN,MAAMM,CAAkD,CAM7D,UAAUJ,EAAoB,CAC5B,OAAO,KAAK,UAAUA,CAAK,CAC7B,CAOA,YAAYA,EAAoB,CAC9B,OAAO,KAAK,MAAMA,CAAK,CACzB,CACF,CAMO,MAAMK,CAAkD,CAM7D,UAAUL,EAAa,CACrB,OAAOA,CACT,CAOA,YAAYA,EAAa,CACvB,OAAOA,CACT,CACF,CAKO,MAAMM,EAAiB,IAAIF,EAIrBG,EAAqB,IAAIF,EAE/B,SAASG,GAAoD,CAClE,OAAOD,CACT,CCbO,MAAME,CACgC,CAmB3C,YAAYC,EAA0C,CAdtD,KAAiB,aAAoC,KACrD,KAAQ,WAAkC,KAC1C,KAAiB,kBACf,CACE,KAAMC,EAAAA,cAAc,SAAS,YAAY,EACzC,OAASC,GAAsC,CAC7C,KAAK,WAAaA,EAAM,UAAY,IACtC,CAAA,EAQF,KAAK,IAAMF,EAAQ,IACnB,KAAK,WAAaA,EAAQ,YAAcJ,EACxC,KAAK,QAAUI,EAAQ,SAAWP,EAAA,EAClC,KAAK,SACHO,EAAQ,UACR,IAAIG,EAAAA,oBACF,cAAc,KAAK,GAAG,EAAA,EAE1B,KAAK,aAAeH,EAAQ,cAAgB,KAC5C,KAAK,SAAS,GAAG,KAAK,iBAAiB,CACzC,CAyBA,YACEI,EACuB,CACvB,YAAK,SAAS,GAAGA,CAAQ,EAClB,IAAM,KAAK,SAAS,IAAIA,EAAS,IAAI,CAC9C,CAiBA,KAA2B,CACzB,GAAI,KAAK,aAAe,MAAQ,KAAK,aAAe,OAClD,OAAO,KAAK,WAEd,MAAMd,EAAQ,KAAK,QAAQ,QAAQ,KAAK,GAAG,EAC3C,OAAIA,GAAU,KACL,KAAK,cAEd,KAAK,WAAa,KAAK,WAAW,YAAYA,CAAK,EAC5C,KAAK,WACd,CAgBA,IAAIA,EAA2B,CAC7B,MAAMe,EAAW,KAAK,IAAA,EAChBC,EAAa,KAAK,WAAW,UAAUhB,CAAK,EAClD,KAAK,QAAQ,QAAQ,KAAK,IAAKgB,CAAU,EACzC,KAAK,WAAahB,EAClB,KAAK,SAAS,KAAK,CACjB,SAAUA,EACV,SAAAe,CAAA,CACD,CACH,CAcA,QAAe,CACb,MAAMA,EAAW,KAAK,IAAA,EACtB,KAAK,QAAQ,WAAW,KAAK,GAAG,EAChC,KAAK,WAAa,KAClB,KAAK,SAAS,KAAK,CACjB,SAAAA,EACA,SAAU,IAAA,CACX,CACH,CAgBA,SAAU,CACR,KAAK,SAAS,IAAI,KAAK,kBAAkB,IAAI,CAC/C,CACF"}
|
package/dist/keyStorage.d.ts
CHANGED
|
@@ -37,6 +37,10 @@ export interface KeyStorageOptions<Deserialized> {
|
|
|
37
37
|
* Optional event bus for cross-tab communication. Defaults to SerialTypedEventBus
|
|
38
38
|
*/
|
|
39
39
|
eventBus?: TypedEventBus<StorageEvent<Deserialized>>;
|
|
40
|
+
/**
|
|
41
|
+
* Optional default value to return when no value exists in storage
|
|
42
|
+
*/
|
|
43
|
+
defaultValue?: Deserialized;
|
|
40
44
|
}
|
|
41
45
|
/**
|
|
42
46
|
* A storage wrapper that manages a single value associated with a specific key
|
|
@@ -48,6 +52,7 @@ export declare class KeyStorage<Deserialized> implements StorageListenable<Deser
|
|
|
48
52
|
private readonly serializer;
|
|
49
53
|
private readonly storage;
|
|
50
54
|
readonly eventBus: TypedEventBus<StorageEvent<Deserialized>>;
|
|
55
|
+
private readonly defaultValue;
|
|
51
56
|
private cacheValue;
|
|
52
57
|
private readonly keyStorageHandler;
|
|
53
58
|
/**
|
package/dist/keyStorage.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyStorage.d.ts","sourceRoot":"","sources":["../src/keyStorage.ts"],"names":[],"mappings":"AAaA,OAAO,
|
|
1
|
+
{"version":3,"file":"keyStorage.d.ts","sourceRoot":"","sources":["../src/keyStorage.ts"],"names":[],"mappings":"AAaA,OAAO,EAAkB,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EACL,YAAY,EAGZ,aAAa,EACd,MAAM,6BAA6B,CAAC;AAGrC,MAAM,WAAW,YAAY,CAAC,YAAY;IACxC,QAAQ,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,IAAI,CAAC;AAE/C,MAAM,WAAW,iBAAiB,CAAC,YAAY;IAC7C;;;;OAIG;IACH,WAAW,CACT,QAAQ,EAAE,YAAY,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,GACjD,qBAAqB,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB,CAAC,YAAY;IAC7C;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAE9C;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,QAAQ,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,CAAC;IAErD;;OAEG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED;;;;GAIG;AACH,qBAAa,UAAU,CAAC,YAAY,CAClC,YAAW,iBAAiB,CAAC,YAAY,CAAC;IAC1C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAmC;IAC9D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,SAAgB,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,CAAC;IACpE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA6B;IAC1D,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAM9B;IAEJ;;;OAGG;gBACS,OAAO,EAAE,iBAAiB,CAAC,YAAY,CAAC;IAapD;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,WAAW,CACT,QAAQ,EAAE,YAAY,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,GACjD,qBAAqB;IAKxB;;;;;;;;;;;;;;OAcG;IACH,GAAG,IAAI,YAAY,GAAG,IAAI;IAY1B;;;;;;;;;;;;;OAaG;IACH,GAAG,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;IAW9B;;;;;;;;;;;OAWG;IACH,MAAM,IAAI,IAAI;IAUd;;;;;;;;;;;;;OAaG;IACH,OAAO;CAGR"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ahoo-wang/fetcher-storage",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "A lightweight, cross-environment storage library with key-based storage and automatic environment detection. Provides consistent API for browser localStorage and in-memory storage with change notifications.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"storage",
|