@alwatr/local-storage 6.3.2 โ†’ 6.3.4

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/CHANGELOG.md CHANGED
@@ -3,6 +3,21 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [6.3.4](https://github.com/Alwatr/nanolib/compare/@alwatr/local-storage@6.3.3...@alwatr/local-storage@6.3.4) (2025-09-27)
7
+
8
+ ### ๐Ÿงน Miscellaneous Chores
9
+
10
+ * exclude test files from package distribution ([86f4f2f](https://github.com/Alwatr/nanolib/commit/86f4f2f5985845c5cf3a3a9398de7b2f98ce53e7))
11
+
12
+ ## [6.3.3](https://github.com/Alwatr/nanolib/compare/@alwatr/local-storage@6.3.2...@alwatr/local-storage@6.3.3) (2025-09-22)
13
+
14
+ ### ๐Ÿ› Bug Fixes
15
+
16
+ * add constraint to createLocalStorageProvider generic type to extend JsonValue ([198ca49](https://github.com/Alwatr/nanolib/commit/198ca49042780aff15d3979bea3951bf094b3b15))
17
+ * add generic type constraint to LocalStorageProviderConfig to extend JsonValue ([9b97692](https://github.com/Alwatr/nanolib/commit/9b9769254613aac6ad94a0c2dd885c44e63b6ed2))
18
+ * refine generic type constraints in LocalStorageProvider to extend JsonValue ([6a05c12](https://github.com/Alwatr/nanolib/commit/6a05c12583326dbea8784f79f7c559b9a31d3cef))
19
+ * rename convertDataType method to convertDataType__ for consistency ([83ccb56](https://github.com/Alwatr/nanolib/commit/83ccb56a9ff95ba0c4e8e6a77cb67a010d60701a))
20
+
6
21
  ## [6.3.2](https://github.com/Alwatr/nanolib/compare/@alwatr/local-storage@6.3.1...@alwatr/local-storage@6.3.2) (2025-09-22)
7
22
 
8
23
  ### ๐Ÿ› Bug Fixes
package/dist/facade.d.ts CHANGED
@@ -22,5 +22,5 @@ import type { LocalStorageProviderConfig } from './type.js';
22
22
  * console.log(currentSettings); // { theme: 'dark', notifications: false }
23
23
  * ```
24
24
  */
25
- export declare function createLocalStorageProvider<T>(config: LocalStorageProviderConfig<T>): LocalStorageProvider<T>;
25
+ export declare function createLocalStorageProvider<T extends JsonValue>(config: LocalStorageProviderConfig<T>): LocalStorageProvider<T>;
26
26
  //# sourceMappingURL=facade.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"facade.d.ts","sourceRoot":"","sources":["../src/facade.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,oBAAoB,EAAC,MAAM,6BAA6B,CAAC;AAEjE,OAAO,KAAK,EAAC,0BAA0B,EAAC,MAAM,WAAW,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,EAAE,MAAM,EAAE,0BAA0B,CAAC,CAAC,CAAC,GAAG,oBAAoB,CAAC,CAAC,CAAC,CAE5G"}
1
+ {"version":3,"file":"facade.d.ts","sourceRoot":"","sources":["../src/facade.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,oBAAoB,EAAC,MAAM,6BAA6B,CAAC;AAEjE,OAAO,KAAK,EAAC,0BAA0B,EAAC,MAAM,WAAW,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,SAAS,SAAS,EAAE,MAAM,EAAE,0BAA0B,CAAC,CAAC,CAAC,GAAG,oBAAoB,CAAC,CAAC,CAAC,CAE9H"}
@@ -19,12 +19,12 @@ import type { LocalStorageProviderConfig, StorageMeta } from './type.js';
19
19
  * console.log(currentSettings); // { theme: 'dark', notifications: false }
20
20
  * ```
21
21
  */
22
- export declare class LocalStorageProvider<T> {
22
+ export declare class LocalStorageProvider<T extends JsonValue> {
23
23
  static readonly version: string;
24
24
  private readonly key__;
25
25
  protected readonly logger_: import("@alwatr/logger").AlwatrLogger;
26
- private meta__;
27
- protected readonly defaultValue__: Jsonify<T>;
26
+ private readonly meta__;
27
+ protected readonly defaultValue__: T;
28
28
  constructor(config: LocalStorageProviderConfig<T>);
29
29
  /**
30
30
  * Generates the versioned storage key.
@@ -57,24 +57,24 @@ export declare class LocalStorageProvider<T> {
57
57
  /**
58
58
  * Converts the provided data to a JSON-compatible format by simulating
59
59
  * a serialization/deserialization cycle. This ensures that the data
60
- * conforms to the `Jsonify<T>` type.
60
+ * conforms to the `T` type.
61
61
  *
62
62
  * @template T - The type of the input data.
63
63
  * @param data - The data to be converted to a JSON-compatible format.
64
- * @returns The converted data as `Jsonify<T>`.
64
+ * @returns The converted data as `T`.
65
65
  * @throws {Error} If the serialization/deserialization process fails.
66
66
  */
67
- convertDataType(data: T | Jsonify<T>): Jsonify<T>;
67
+ private convertDataType__;
68
68
  /**
69
69
  * Reads and parses the value from localStorage.
70
70
  * If the item doesn't exist, is invalid JSON, or doesn't match the expected type,
71
71
  * it writes and returns the default value.
72
72
  */
73
- read(): Jsonify<T>;
73
+ read(): T;
74
74
  /**
75
75
  * Serializes and writes a value to localStorage.
76
76
  */
77
- write(value: T | Jsonify<T>): void;
77
+ write(value: T): void;
78
78
  /**
79
79
  * Removes the item from localStorage.
80
80
  */
@@ -1 +1 @@
1
- {"version":3,"file":"local-storage.provider.d.ts","sourceRoot":"","sources":["../src/local-storage.provider.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,0BAA0B,EAAE,WAAW,EAAC,MAAM,WAAW,CAAC;AAEvE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,oBAAoB,CAAC,CAAC;IACjC,gBAAuB,OAAO,SAAuB;IAErD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,SAAS,CAAC,QAAQ,CAAC,OAAO,wCAAC;IAE3B,OAAO,CAAC,MAAM,CAAc;IAE5B,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;gBAElC,MAAM,EAAE,0BAA0B,CAAC,CAAC,CAAC;IAYjD;;;;OAIG;WACW,MAAM,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM;IAI/C;;;;;;;;;;;;;;;;OAgBG;WACW,GAAG,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO;IAK7C;;OAEG;IACH,OAAO,CAAC,eAAe;IAWvB;;;;;;;;;OASG;IACI,eAAe,CAAC,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAYxD;;;;OAIG;IACI,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC;IAyBzB;;OAEG;IACI,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI;IAmBzC;;OAEG;IACI,MAAM,IAAI,IAAI;IAIrB;;OAEG;IACH,OAAO,CAAC,SAAS;CASlB"}
1
+ {"version":3,"file":"local-storage.provider.d.ts","sourceRoot":"","sources":["../src/local-storage.provider.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,0BAA0B,EAAE,WAAW,EAAC,MAAM,WAAW,CAAC;AAEvE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,oBAAoB,CAAC,CAAC,SAAS,SAAS;IACnD,gBAAuB,OAAO,SAAuB;IAErD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,SAAS,CAAC,QAAQ,CAAC,OAAO,wCAAC;IAE3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwB;IAE/C,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC,CAAC;gBAEzB,MAAM,EAAE,0BAA0B,CAAC,CAAC,CAAC;IAYjD;;;;OAIG;WACW,MAAM,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM;IAI/C;;;;;;;;;;;;;;;;OAgBG;WACW,GAAG,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO;IAK7C;;OAEG;IACH,OAAO,CAAC,eAAe;IAWvB;;;;;;;;;OASG;IACH,OAAO,CAAC,iBAAiB;IAYzB;;;;OAIG;IACI,IAAI,IAAI,CAAC;IAyBhB;;OAEG;IACI,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI;IAmB5B;;OAEG;IACI,MAAM,IAAI,IAAI;IAIrB;;OAEG;IACH,OAAO,CAAC,SAAS;CASlB"}
package/dist/main.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /** ๐Ÿ“ฆ @alwatr/local-storage v6.3.2 */
2
- __dev_mode__: console.debug("๐Ÿ“ฆ @alwatr/local-storage v6.3.2");
3
- "use strict";var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from==="object"||typeof from==="function"){for(let key of __getOwnPropNames(from))if(!__hasOwnProp.call(to,key)&&key!==except)__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:true}),mod);var main_exports={};__export(main_exports,{LocalStorageProvider:()=>LocalStorageProvider,createLocalStorageProvider:()=>createLocalStorageProvider});module.exports=__toCommonJS(main_exports);var import_logger=require("@alwatr/logger");var LocalStorageProvider=class _LocalStorageProvider{static{this.version="6.3.2"}constructor(config){this.logger_=(0,import_logger.createLogger)(`local-storage-provider: ${config.name}, v: ${config.schemaVersion}`);this.logger_.logMethodArgs?.("constructor",{config});this.meta__={name:config.name,schemaVersion:config.schemaVersion};this.key__=_LocalStorageProvider.getKey(this.meta__);this.defaultValue__=this.convertDataType(config.defaultValue);this.migrate__()}static getKey(meta){return`${meta.name}.v${meta.schemaVersion}`}static has(meta){const key=_LocalStorageProvider.getKey(meta);return localStorage.getItem(key)!==null}handleDefault__(){this.logger_.logMethodArgs?.("handleDefault__",this.defaultValue__);try{this.write(this.defaultValue__)}catch(err){this.logger_.error("write","write_default_error",{err})}return this.defaultValue__}convertDataType(data){this.logger_.logMethod?.("convertDataType");try{return JSON.parse(JSON.stringify(data))}catch(err){this.logger_.error("convertDataType__","convert_data_type_error",{err});throw new Error("convert_data_type_error")}}read(){let value=null;try{value=localStorage.getItem(this.key__)}catch(err){this.logger_.error("read","read_local_storage_error",{err})}if(value===null){this.logger_.logMethod?.("read//no_value");return this.handleDefault__()}try{const parsedValue=JSON.parse(value);this.logger_.logMethodFull?.("read//value",void 0,{parsedValue});return parsedValue}catch(err){this.logger_.error("read","read_parse_error",{err});return this.handleDefault__()}}write(value){this.logger_.logMethodArgs?.("write",{value});let valueStr;try{valueStr=JSON.stringify(value)}catch(err){this.logger_.error("write","write_stringify_error",{err});throw new Error("write_stringify_error")}try{localStorage.setItem(this.key__,valueStr)}catch(err){this.logger_.error("write","write_local_storage_error",{err})}}remove(){localStorage.removeItem(this.key__)}migrate__(){if(this.meta__.schemaVersion<=1)return;for(let i=1;i<this.meta__.schemaVersion;i++){const oldKey=_LocalStorageProvider.getKey({name:this.meta__.name,schemaVersion:i});localStorage.removeItem(oldKey)}}};function createLocalStorageProvider(config){return new LocalStorageProvider(config)}0&&(module.exports={LocalStorageProvider,createLocalStorageProvider});
1
+ /** ๐Ÿ“ฆ @alwatr/local-storage v6.3.4 */
2
+ __dev_mode__: console.debug("๐Ÿ“ฆ @alwatr/local-storage v6.3.4");
3
+ "use strict";var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from==="object"||typeof from==="function"){for(let key of __getOwnPropNames(from))if(!__hasOwnProp.call(to,key)&&key!==except)__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:true}),mod);var main_exports={};__export(main_exports,{LocalStorageProvider:()=>LocalStorageProvider,createLocalStorageProvider:()=>createLocalStorageProvider});module.exports=__toCommonJS(main_exports);var import_logger=require("@alwatr/logger");var LocalStorageProvider=class _LocalStorageProvider{static{this.version="6.3.4"}constructor(config){this.logger_=(0,import_logger.createLogger)(`local-storage-provider: ${config.name}, v: ${config.schemaVersion}`);this.logger_.logMethodArgs?.("constructor",{config});this.meta__={name:config.name,schemaVersion:config.schemaVersion};this.key__=_LocalStorageProvider.getKey(this.meta__);this.defaultValue__=this.convertDataType__(config.defaultValue);this.migrate__()}static getKey(meta){return`${meta.name}.v${meta.schemaVersion}`}static has(meta){const key=_LocalStorageProvider.getKey(meta);return localStorage.getItem(key)!==null}handleDefault__(){this.logger_.logMethodArgs?.("handleDefault__",this.defaultValue__);try{this.write(this.defaultValue__)}catch(err){this.logger_.error("write","write_default_error",{err})}return this.defaultValue__}convertDataType__(data){this.logger_.logMethod?.("convertDataType");try{return JSON.parse(JSON.stringify(data))}catch(err){this.logger_.error("convertDataType__","convert_data_type_error",{err});throw new Error("convert_data_type_error")}}read(){let value=null;try{value=localStorage.getItem(this.key__)}catch(err){this.logger_.error("read","read_local_storage_error",{err})}if(value===null){this.logger_.logMethod?.("read//no_value");return this.handleDefault__()}try{const parsedValue=JSON.parse(value);this.logger_.logMethodFull?.("read//value",void 0,{parsedValue});return parsedValue}catch(err){this.logger_.error("read","read_parse_error",{err});return this.handleDefault__()}}write(value){this.logger_.logMethodArgs?.("write",{value});let valueStr;try{valueStr=JSON.stringify(value)}catch(err){this.logger_.error("write","write_stringify_error",{err});throw new Error("write_stringify_error")}try{localStorage.setItem(this.key__,valueStr)}catch(err){this.logger_.error("write","write_local_storage_error",{err})}}remove(){localStorage.removeItem(this.key__)}migrate__(){if(this.meta__.schemaVersion<=1)return;for(let i=1;i<this.meta__.schemaVersion;i++){const oldKey=_LocalStorageProvider.getKey({name:this.meta__.name,schemaVersion:i});localStorage.removeItem(oldKey)}}};function createLocalStorageProvider(config){return new LocalStorageProvider(config)}0&&(module.exports={LocalStorageProvider,createLocalStorageProvider});
4
4
  //# sourceMappingURL=main.cjs.map
package/dist/main.cjs.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/main.ts", "../src/local-storage.provider.ts", "../src/facade.ts"],
4
- "sourcesContent": ["export * from './local-storage.provider.js';\nexport * from './facade.js';\nexport type * from './type.js';\n", "import {createLogger} from '@alwatr/logger';\n\nimport type {LocalStorageProviderConfig, StorageMeta} from './type.js';\n\n/**\n * A provider class for managing a specific, versioned item in localStorage.\n * It encapsulates the logic for key generation, serialization, and migration.\n *\n * @example\n * ```typescript\n * const userSettings = new LocalStorageProvider({\n * name: 'user-settings',\n * version: 1,\n * defaultValue: { theme: 'light', notifications: true }\n * });\n *\n * // Write new settings\n * userSettings.write({ theme: 'dark', notifications: false });\n *\n * // Read the current settings\n * const currentSettings = userSettings.read();\n * console.log(currentSettings); // { theme: 'dark', notifications: false }\n * ```\n */\nexport class LocalStorageProvider<T> {\n public static readonly version = __package_version__;\n\n private readonly key__: string;\n protected readonly logger_;\n\n private meta__: StorageMeta;\n\n protected readonly defaultValue__: Jsonify<T>;\n\n constructor(config: LocalStorageProviderConfig<T>) {\n this.logger_ = createLogger(`local-storage-provider: ${config.name}, v: ${config.schemaVersion}`);\n this.logger_.logMethodArgs?.('constructor', {config});\n this.meta__ = {\n name: config.name,\n schemaVersion: config.schemaVersion,\n };\n this.key__ = LocalStorageProvider.getKey(this.meta__);\n this.defaultValue__ = this.convertDataType(config.defaultValue);\n this.migrate__();\n }\n\n /**\n * Generates the versioned storage key.\n * @param meta - An object containing the name and schemaVersion.\n * @returns The versioned key string.\n */\n public static getKey(meta: StorageMeta): string {\n return `${meta.name}.v${meta.schemaVersion}`;\n }\n\n /**\n * Statically checks if a versioned item exists in localStorage.\n * This method provides a high-performance way to check for data existence without the overhead of creating a full provider instance.\n *\n * @param meta - An object containing the name and version of the item to check.\n * @returns `true` if the item exists, otherwise `false`.\n *\n * @example\n * ```typescript\n * const formExists = LocalStorageProvider.has({ name: 'user-form', schemaVersion: 1 });\n * if (formExists) {\n * // Show the \"Thank you\" message\n * } else {\n * // Show the form\n * }\n * ```\n */\n public static has(meta: StorageMeta): boolean {\n const key = LocalStorageProvider.getKey(meta);\n return localStorage.getItem(key) !== null;\n }\n\n /**\n * Writes the default value to localStorage and returns it.\n */\n private handleDefault__(): Jsonify<T> {\n this.logger_.logMethodArgs?.('handleDefault__', this.defaultValue__);\n try {\n this.write(this.defaultValue__);\n }\n catch (err) {\n this.logger_.error('write', 'write_default_error', {err});\n }\n return this.defaultValue__;\n }\n\n /**\n * Converts the provided data to a JSON-compatible format by simulating\n * a serialization/deserialization cycle. This ensures that the data\n * conforms to the `Jsonify<T>` type.\n *\n * @template T - The type of the input data.\n * @param data - The data to be converted to a JSON-compatible format.\n * @returns The converted data as `Jsonify<T>`.\n * @throws {Error} If the serialization/deserialization process fails.\n */\n public convertDataType(data: T | Jsonify<T>): Jsonify<T> {\n this.logger_.logMethod?.('convertDataType');\n // Simulate real serialization/deserialization cycle for real types\n try {\n return JSON.parse(JSON.stringify(data)) as Jsonify<T>;\n }\n catch (err) {\n this.logger_.error('convertDataType__', 'convert_data_type_error', {err});\n throw new Error('convert_data_type_error');\n }\n }\n\n /**\n * Reads and parses the value from localStorage.\n * If the item doesn't exist, is invalid JSON, or doesn't match the expected type,\n * it writes and returns the default value.\n */\n public read(): Jsonify<T> {\n let value: string | null = null;\n try {\n value = localStorage.getItem(this.key__);\n }\n catch (err) {\n this.logger_.error('read', 'read_local_storage_error', {err});\n }\n\n if (value === null) {\n this.logger_.logMethod?.('read//no_value');\n return this.handleDefault__();\n }\n\n try {\n const parsedValue = JSON.parse(value) as Jsonify<T>;\n this.logger_.logMethodFull?.('read//value', undefined, {parsedValue});\n return parsedValue;\n }\n catch (err) {\n this.logger_.error('read', 'read_parse_error', {err});\n return this.handleDefault__();\n }\n }\n\n /**\n * Serializes and writes a value to localStorage.\n */\n public write(value: T | Jsonify<T>): void {\n this.logger_.logMethodArgs?.('write', {value});\n let valueStr: string;\n try {\n valueStr = JSON.stringify(value);\n }\n catch (err) {\n this.logger_.error('write', 'write_stringify_error', {err});\n throw new Error('write_stringify_error');\n }\n\n try {\n localStorage.setItem(this.key__, valueStr);\n }\n catch (err) {\n this.logger_.error('write', 'write_local_storage_error', {err});\n }\n }\n\n /**\n * Removes the item from localStorage.\n */\n public remove(): void {\n localStorage.removeItem(this.key__);\n }\n\n /**\n * Manages data migration by removing all previous versions of the item.\n */\n private migrate__(): void {\n if (this.meta__.schemaVersion <= 1) return;\n\n // Iterate from v1 up to the version just before the current one and remove them.\n for (let i = 1; i < this.meta__.schemaVersion; i++) {\n const oldKey = LocalStorageProvider.getKey({name: this.meta__.name, schemaVersion: i});\n localStorage.removeItem(oldKey);\n }\n }\n}\n", "import {LocalStorageProvider} from './local-storage.provider.js';\n\nimport type {LocalStorageProviderConfig} from './type.js';\n\n/**\n * Factory function to create a new LocalStorageProvider.\n *\n * @param config - The configuration for the provider.\n * @returns An instance of LocalStorageProvider.\n *\n * @example\n * ```typescript\n * const userSettings = createLocalStorageProvider({\n * name: 'user-settings',\n * schemaVersion: 1,\n * defaultValue: { theme: 'light', notifications: true }\n * });\n *\n * // Write new settings\n * userSettings.write({ theme: 'dark', notifications: false });\n *\n * // Read the current settings\n * const currentSettings = userSettings.read();\n * console.log(currentSettings); // { theme: 'dark', notifications: false }\n * ```\n */\nexport function createLocalStorageProvider<T>(config: LocalStorageProviderConfig<T>): LocalStorageProvider<T> {\n return new LocalStorageProvider<T>(config);\n}\n"],
5
- "mappings": ";;qqBAAA,+LCAA,kBAA2B,0BAwBpB,IAAM,qBAAN,MAAM,qBAAwB,CACnC,YAAuB,QAAU,QASjC,YAAY,OAAuC,CACjD,KAAK,WAAU,4BAAa,2BAA2B,OAAO,IAAI,QAAQ,OAAO,aAAa,EAAE,EAChG,KAAK,QAAQ,gBAAgB,cAAe,CAAC,MAAM,CAAC,EACpD,KAAK,OAAS,CACZ,KAAM,OAAO,KACb,cAAe,OAAO,aACxB,EACA,KAAK,MAAQ,sBAAqB,OAAO,KAAK,MAAM,EACpD,KAAK,eAAiB,KAAK,gBAAgB,OAAO,YAAY,EAC9D,KAAK,UAAU,CACjB,CAOA,OAAc,OAAO,KAA2B,CAC9C,MAAO,GAAG,KAAK,IAAI,KAAK,KAAK,aAAa,EAC5C,CAmBA,OAAc,IAAI,KAA4B,CAC5C,MAAM,IAAM,sBAAqB,OAAO,IAAI,EAC5C,OAAO,aAAa,QAAQ,GAAG,IAAM,IACvC,CAKQ,iBAA8B,CACpC,KAAK,QAAQ,gBAAgB,kBAAmB,KAAK,cAAc,EACnE,GAAI,CACF,KAAK,MAAM,KAAK,cAAc,CAChC,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,QAAS,sBAAuB,CAAC,GAAG,CAAC,CAC1D,CACA,OAAO,KAAK,cACd,CAYO,gBAAgB,KAAkC,CACvD,KAAK,QAAQ,YAAY,iBAAiB,EAE1C,GAAI,CACF,OAAO,KAAK,MAAM,KAAK,UAAU,IAAI,CAAC,CACxC,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,oBAAqB,0BAA2B,CAAC,GAAG,CAAC,EACxE,MAAM,IAAI,MAAM,yBAAyB,CAC3C,CACF,CAOO,MAAmB,CACxB,IAAI,MAAuB,KAC3B,GAAI,CACF,MAAQ,aAAa,QAAQ,KAAK,KAAK,CACzC,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,OAAQ,2BAA4B,CAAC,GAAG,CAAC,CAC9D,CAEA,GAAI,QAAU,KAAM,CAClB,KAAK,QAAQ,YAAY,gBAAgB,EACzC,OAAO,KAAK,gBAAgB,CAC9B,CAEA,GAAI,CACF,MAAM,YAAc,KAAK,MAAM,KAAK,EACpC,KAAK,QAAQ,gBAAgB,cAAe,OAAW,CAAC,WAAW,CAAC,EACpE,OAAO,WACT,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,OAAQ,mBAAoB,CAAC,GAAG,CAAC,EACpD,OAAO,KAAK,gBAAgB,CAC9B,CACF,CAKO,MAAM,MAA6B,CACxC,KAAK,QAAQ,gBAAgB,QAAS,CAAC,KAAK,CAAC,EAC7C,IAAI,SACJ,GAAI,CACF,SAAW,KAAK,UAAU,KAAK,CACjC,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,QAAS,wBAAyB,CAAC,GAAG,CAAC,EAC1D,MAAM,IAAI,MAAM,uBAAuB,CACzC,CAEA,GAAI,CACF,aAAa,QAAQ,KAAK,MAAO,QAAQ,CAC3C,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,QAAS,4BAA6B,CAAC,GAAG,CAAC,CAChE,CACF,CAKO,QAAe,CACpB,aAAa,WAAW,KAAK,KAAK,CACpC,CAKQ,WAAkB,CACxB,GAAI,KAAK,OAAO,eAAiB,EAAG,OAGpC,QAAS,EAAI,EAAG,EAAI,KAAK,OAAO,cAAe,IAAK,CAClD,MAAM,OAAS,sBAAqB,OAAO,CAAC,KAAM,KAAK,OAAO,KAAM,cAAe,CAAC,CAAC,EACrF,aAAa,WAAW,MAAM,CAChC,CACF,CACF,EC9JO,SAAS,2BAA8B,OAAgE,CAC5G,OAAO,IAAI,qBAAwB,MAAM,CAC3C",
4
+ "sourcesContent": ["export * from './local-storage.provider.js';\nexport * from './facade.js';\nexport type * from './type.js';\n", "import {createLogger} from '@alwatr/logger';\n\nimport type {LocalStorageProviderConfig, StorageMeta} from './type.js';\n\n/**\n * A provider class for managing a specific, versioned item in localStorage.\n * It encapsulates the logic for key generation, serialization, and migration.\n *\n * @example\n * ```typescript\n * const userSettings = new LocalStorageProvider({\n * name: 'user-settings',\n * version: 1,\n * defaultValue: { theme: 'light', notifications: true }\n * });\n *\n * // Write new settings\n * userSettings.write({ theme: 'dark', notifications: false });\n *\n * // Read the current settings\n * const currentSettings = userSettings.read();\n * console.log(currentSettings); // { theme: 'dark', notifications: false }\n * ```\n */\nexport class LocalStorageProvider<T extends JsonValue> {\n public static readonly version = __package_version__;\n\n private readonly key__: string;\n protected readonly logger_;\n\n private readonly meta__: Readonly<StorageMeta>;\n\n protected readonly defaultValue__: T;\n\n constructor(config: LocalStorageProviderConfig<T>) {\n this.logger_ = createLogger(`local-storage-provider: ${config.name}, v: ${config.schemaVersion}`);\n this.logger_.logMethodArgs?.('constructor', {config});\n this.meta__ = {\n name: config.name,\n schemaVersion: config.schemaVersion,\n };\n this.key__ = LocalStorageProvider.getKey(this.meta__);\n this.defaultValue__ = this.convertDataType__(config.defaultValue);\n this.migrate__();\n }\n\n /**\n * Generates the versioned storage key.\n * @param meta - An object containing the name and schemaVersion.\n * @returns The versioned key string.\n */\n public static getKey(meta: StorageMeta): string {\n return `${meta.name}.v${meta.schemaVersion}`;\n }\n\n /**\n * Statically checks if a versioned item exists in localStorage.\n * This method provides a high-performance way to check for data existence without the overhead of creating a full provider instance.\n *\n * @param meta - An object containing the name and version of the item to check.\n * @returns `true` if the item exists, otherwise `false`.\n *\n * @example\n * ```typescript\n * const formExists = LocalStorageProvider.has({ name: 'user-form', schemaVersion: 1 });\n * if (formExists) {\n * // Show the \"Thank you\" message\n * } else {\n * // Show the form\n * }\n * ```\n */\n public static has(meta: StorageMeta): boolean {\n const key = LocalStorageProvider.getKey(meta);\n return localStorage.getItem(key) !== null;\n }\n\n /**\n * Writes the default value to localStorage and returns it.\n */\n private handleDefault__(): T {\n this.logger_.logMethodArgs?.('handleDefault__', this.defaultValue__);\n try {\n this.write(this.defaultValue__);\n }\n catch (err) {\n this.logger_.error('write', 'write_default_error', {err});\n }\n return this.defaultValue__;\n }\n\n /**\n * Converts the provided data to a JSON-compatible format by simulating\n * a serialization/deserialization cycle. This ensures that the data\n * conforms to the `T` type.\n *\n * @template T - The type of the input data.\n * @param data - The data to be converted to a JSON-compatible format.\n * @returns The converted data as `T`.\n * @throws {Error} If the serialization/deserialization process fails.\n */\n private convertDataType__(data: T): T {\n this.logger_.logMethod?.('convertDataType');\n // Simulate real serialization/deserialization cycle for real types\n try {\n return JSON.parse(JSON.stringify(data)) as T;\n }\n catch (err) {\n this.logger_.error('convertDataType__', 'convert_data_type_error', {err});\n throw new Error('convert_data_type_error');\n }\n }\n\n /**\n * Reads and parses the value from localStorage.\n * If the item doesn't exist, is invalid JSON, or doesn't match the expected type,\n * it writes and returns the default value.\n */\n public read(): T {\n let value: string | null = null;\n try {\n value = localStorage.getItem(this.key__);\n }\n catch (err) {\n this.logger_.error('read', 'read_local_storage_error', {err});\n }\n\n if (value === null) {\n this.logger_.logMethod?.('read//no_value');\n return this.handleDefault__();\n }\n\n try {\n const parsedValue = JSON.parse(value) as T;\n this.logger_.logMethodFull?.('read//value', undefined, {parsedValue});\n return parsedValue;\n }\n catch (err) {\n this.logger_.error('read', 'read_parse_error', {err});\n return this.handleDefault__();\n }\n }\n\n /**\n * Serializes and writes a value to localStorage.\n */\n public write(value: T): void {\n this.logger_.logMethodArgs?.('write', {value});\n let valueStr: string;\n try {\n valueStr = JSON.stringify(value);\n }\n catch (err) {\n this.logger_.error('write', 'write_stringify_error', {err});\n throw new Error('write_stringify_error');\n }\n\n try {\n localStorage.setItem(this.key__, valueStr);\n }\n catch (err) {\n this.logger_.error('write', 'write_local_storage_error', {err});\n }\n }\n\n /**\n * Removes the item from localStorage.\n */\n public remove(): void {\n localStorage.removeItem(this.key__);\n }\n\n /**\n * Manages data migration by removing all previous versions of the item.\n */\n private migrate__(): void {\n if (this.meta__.schemaVersion <= 1) return;\n\n // Iterate from v1 up to the version just before the current one and remove them.\n for (let i = 1; i < this.meta__.schemaVersion; i++) {\n const oldKey = LocalStorageProvider.getKey({name: this.meta__.name, schemaVersion: i});\n localStorage.removeItem(oldKey);\n }\n }\n}\n", "import {LocalStorageProvider} from './local-storage.provider.js';\n\nimport type {LocalStorageProviderConfig} from './type.js';\n\n/**\n * Factory function to create a new LocalStorageProvider.\n *\n * @param config - The configuration for the provider.\n * @returns An instance of LocalStorageProvider.\n *\n * @example\n * ```typescript\n * const userSettings = createLocalStorageProvider({\n * name: 'user-settings',\n * schemaVersion: 1,\n * defaultValue: { theme: 'light', notifications: true }\n * });\n *\n * // Write new settings\n * userSettings.write({ theme: 'dark', notifications: false });\n *\n * // Read the current settings\n * const currentSettings = userSettings.read();\n * console.log(currentSettings); // { theme: 'dark', notifications: false }\n * ```\n */\nexport function createLocalStorageProvider<T extends JsonValue>(config: LocalStorageProviderConfig<T>): LocalStorageProvider<T> {\n return new LocalStorageProvider<T>(config);\n}\n"],
5
+ "mappings": ";;qqBAAA,+LCAA,kBAA2B,0BAwBpB,IAAM,qBAAN,MAAM,qBAA0C,CACrD,YAAuB,QAAU,QASjC,YAAY,OAAuC,CACjD,KAAK,WAAU,4BAAa,2BAA2B,OAAO,IAAI,QAAQ,OAAO,aAAa,EAAE,EAChG,KAAK,QAAQ,gBAAgB,cAAe,CAAC,MAAM,CAAC,EACpD,KAAK,OAAS,CACZ,KAAM,OAAO,KACb,cAAe,OAAO,aACxB,EACA,KAAK,MAAQ,sBAAqB,OAAO,KAAK,MAAM,EACpD,KAAK,eAAiB,KAAK,kBAAkB,OAAO,YAAY,EAChE,KAAK,UAAU,CACjB,CAOA,OAAc,OAAO,KAA2B,CAC9C,MAAO,GAAG,KAAK,IAAI,KAAK,KAAK,aAAa,EAC5C,CAmBA,OAAc,IAAI,KAA4B,CAC5C,MAAM,IAAM,sBAAqB,OAAO,IAAI,EAC5C,OAAO,aAAa,QAAQ,GAAG,IAAM,IACvC,CAKQ,iBAAqB,CAC3B,KAAK,QAAQ,gBAAgB,kBAAmB,KAAK,cAAc,EACnE,GAAI,CACF,KAAK,MAAM,KAAK,cAAc,CAChC,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,QAAS,sBAAuB,CAAC,GAAG,CAAC,CAC1D,CACA,OAAO,KAAK,cACd,CAYQ,kBAAkB,KAAY,CACpC,KAAK,QAAQ,YAAY,iBAAiB,EAE1C,GAAI,CACF,OAAO,KAAK,MAAM,KAAK,UAAU,IAAI,CAAC,CACxC,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,oBAAqB,0BAA2B,CAAC,GAAG,CAAC,EACxE,MAAM,IAAI,MAAM,yBAAyB,CAC3C,CACF,CAOO,MAAU,CACf,IAAI,MAAuB,KAC3B,GAAI,CACF,MAAQ,aAAa,QAAQ,KAAK,KAAK,CACzC,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,OAAQ,2BAA4B,CAAC,GAAG,CAAC,CAC9D,CAEA,GAAI,QAAU,KAAM,CAClB,KAAK,QAAQ,YAAY,gBAAgB,EACzC,OAAO,KAAK,gBAAgB,CAC9B,CAEA,GAAI,CACF,MAAM,YAAc,KAAK,MAAM,KAAK,EACpC,KAAK,QAAQ,gBAAgB,cAAe,OAAW,CAAC,WAAW,CAAC,EACpE,OAAO,WACT,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,OAAQ,mBAAoB,CAAC,GAAG,CAAC,EACpD,OAAO,KAAK,gBAAgB,CAC9B,CACF,CAKO,MAAM,MAAgB,CAC3B,KAAK,QAAQ,gBAAgB,QAAS,CAAC,KAAK,CAAC,EAC7C,IAAI,SACJ,GAAI,CACF,SAAW,KAAK,UAAU,KAAK,CACjC,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,QAAS,wBAAyB,CAAC,GAAG,CAAC,EAC1D,MAAM,IAAI,MAAM,uBAAuB,CACzC,CAEA,GAAI,CACF,aAAa,QAAQ,KAAK,MAAO,QAAQ,CAC3C,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,QAAS,4BAA6B,CAAC,GAAG,CAAC,CAChE,CACF,CAKO,QAAe,CACpB,aAAa,WAAW,KAAK,KAAK,CACpC,CAKQ,WAAkB,CACxB,GAAI,KAAK,OAAO,eAAiB,EAAG,OAGpC,QAAS,EAAI,EAAG,EAAI,KAAK,OAAO,cAAe,IAAK,CAClD,MAAM,OAAS,sBAAqB,OAAO,CAAC,KAAM,KAAK,OAAO,KAAM,cAAe,CAAC,CAAC,EACrF,aAAa,WAAW,MAAM,CAChC,CACF,CACF,EC9JO,SAAS,2BAAgD,OAAgE,CAC9H,OAAO,IAAI,qBAAwB,MAAM,CAC3C",
6
6
  "names": []
7
7
  }
package/dist/main.mjs CHANGED
@@ -1,4 +1,4 @@
1
- /** ๐Ÿ“ฆ @alwatr/local-storage v6.3.2 */
2
- __dev_mode__: console.debug("๐Ÿ“ฆ @alwatr/local-storage v6.3.2");
3
- import{createLogger}from"@alwatr/logger";var LocalStorageProvider=class _LocalStorageProvider{static{this.version="6.3.2"}constructor(config){this.logger_=createLogger(`local-storage-provider: ${config.name}, v: ${config.schemaVersion}`);this.logger_.logMethodArgs?.("constructor",{config});this.meta__={name:config.name,schemaVersion:config.schemaVersion};this.key__=_LocalStorageProvider.getKey(this.meta__);this.defaultValue__=this.convertDataType(config.defaultValue);this.migrate__()}static getKey(meta){return`${meta.name}.v${meta.schemaVersion}`}static has(meta){const key=_LocalStorageProvider.getKey(meta);return localStorage.getItem(key)!==null}handleDefault__(){this.logger_.logMethodArgs?.("handleDefault__",this.defaultValue__);try{this.write(this.defaultValue__)}catch(err){this.logger_.error("write","write_default_error",{err})}return this.defaultValue__}convertDataType(data){this.logger_.logMethod?.("convertDataType");try{return JSON.parse(JSON.stringify(data))}catch(err){this.logger_.error("convertDataType__","convert_data_type_error",{err});throw new Error("convert_data_type_error")}}read(){let value=null;try{value=localStorage.getItem(this.key__)}catch(err){this.logger_.error("read","read_local_storage_error",{err})}if(value===null){this.logger_.logMethod?.("read//no_value");return this.handleDefault__()}try{const parsedValue=JSON.parse(value);this.logger_.logMethodFull?.("read//value",void 0,{parsedValue});return parsedValue}catch(err){this.logger_.error("read","read_parse_error",{err});return this.handleDefault__()}}write(value){this.logger_.logMethodArgs?.("write",{value});let valueStr;try{valueStr=JSON.stringify(value)}catch(err){this.logger_.error("write","write_stringify_error",{err});throw new Error("write_stringify_error")}try{localStorage.setItem(this.key__,valueStr)}catch(err){this.logger_.error("write","write_local_storage_error",{err})}}remove(){localStorage.removeItem(this.key__)}migrate__(){if(this.meta__.schemaVersion<=1)return;for(let i=1;i<this.meta__.schemaVersion;i++){const oldKey=_LocalStorageProvider.getKey({name:this.meta__.name,schemaVersion:i});localStorage.removeItem(oldKey)}}};function createLocalStorageProvider(config){return new LocalStorageProvider(config)}export{LocalStorageProvider,createLocalStorageProvider};
1
+ /** ๐Ÿ“ฆ @alwatr/local-storage v6.3.4 */
2
+ __dev_mode__: console.debug("๐Ÿ“ฆ @alwatr/local-storage v6.3.4");
3
+ import{createLogger}from"@alwatr/logger";var LocalStorageProvider=class _LocalStorageProvider{static{this.version="6.3.4"}constructor(config){this.logger_=createLogger(`local-storage-provider: ${config.name}, v: ${config.schemaVersion}`);this.logger_.logMethodArgs?.("constructor",{config});this.meta__={name:config.name,schemaVersion:config.schemaVersion};this.key__=_LocalStorageProvider.getKey(this.meta__);this.defaultValue__=this.convertDataType__(config.defaultValue);this.migrate__()}static getKey(meta){return`${meta.name}.v${meta.schemaVersion}`}static has(meta){const key=_LocalStorageProvider.getKey(meta);return localStorage.getItem(key)!==null}handleDefault__(){this.logger_.logMethodArgs?.("handleDefault__",this.defaultValue__);try{this.write(this.defaultValue__)}catch(err){this.logger_.error("write","write_default_error",{err})}return this.defaultValue__}convertDataType__(data){this.logger_.logMethod?.("convertDataType");try{return JSON.parse(JSON.stringify(data))}catch(err){this.logger_.error("convertDataType__","convert_data_type_error",{err});throw new Error("convert_data_type_error")}}read(){let value=null;try{value=localStorage.getItem(this.key__)}catch(err){this.logger_.error("read","read_local_storage_error",{err})}if(value===null){this.logger_.logMethod?.("read//no_value");return this.handleDefault__()}try{const parsedValue=JSON.parse(value);this.logger_.logMethodFull?.("read//value",void 0,{parsedValue});return parsedValue}catch(err){this.logger_.error("read","read_parse_error",{err});return this.handleDefault__()}}write(value){this.logger_.logMethodArgs?.("write",{value});let valueStr;try{valueStr=JSON.stringify(value)}catch(err){this.logger_.error("write","write_stringify_error",{err});throw new Error("write_stringify_error")}try{localStorage.setItem(this.key__,valueStr)}catch(err){this.logger_.error("write","write_local_storage_error",{err})}}remove(){localStorage.removeItem(this.key__)}migrate__(){if(this.meta__.schemaVersion<=1)return;for(let i=1;i<this.meta__.schemaVersion;i++){const oldKey=_LocalStorageProvider.getKey({name:this.meta__.name,schemaVersion:i});localStorage.removeItem(oldKey)}}};function createLocalStorageProvider(config){return new LocalStorageProvider(config)}export{LocalStorageProvider,createLocalStorageProvider};
4
4
  //# sourceMappingURL=main.mjs.map
package/dist/main.mjs.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/local-storage.provider.ts", "../src/facade.ts"],
4
- "sourcesContent": ["import {createLogger} from '@alwatr/logger';\n\nimport type {LocalStorageProviderConfig, StorageMeta} from './type.js';\n\n/**\n * A provider class for managing a specific, versioned item in localStorage.\n * It encapsulates the logic for key generation, serialization, and migration.\n *\n * @example\n * ```typescript\n * const userSettings = new LocalStorageProvider({\n * name: 'user-settings',\n * version: 1,\n * defaultValue: { theme: 'light', notifications: true }\n * });\n *\n * // Write new settings\n * userSettings.write({ theme: 'dark', notifications: false });\n *\n * // Read the current settings\n * const currentSettings = userSettings.read();\n * console.log(currentSettings); // { theme: 'dark', notifications: false }\n * ```\n */\nexport class LocalStorageProvider<T> {\n public static readonly version = __package_version__;\n\n private readonly key__: string;\n protected readonly logger_;\n\n private meta__: StorageMeta;\n\n protected readonly defaultValue__: Jsonify<T>;\n\n constructor(config: LocalStorageProviderConfig<T>) {\n this.logger_ = createLogger(`local-storage-provider: ${config.name}, v: ${config.schemaVersion}`);\n this.logger_.logMethodArgs?.('constructor', {config});\n this.meta__ = {\n name: config.name,\n schemaVersion: config.schemaVersion,\n };\n this.key__ = LocalStorageProvider.getKey(this.meta__);\n this.defaultValue__ = this.convertDataType(config.defaultValue);\n this.migrate__();\n }\n\n /**\n * Generates the versioned storage key.\n * @param meta - An object containing the name and schemaVersion.\n * @returns The versioned key string.\n */\n public static getKey(meta: StorageMeta): string {\n return `${meta.name}.v${meta.schemaVersion}`;\n }\n\n /**\n * Statically checks if a versioned item exists in localStorage.\n * This method provides a high-performance way to check for data existence without the overhead of creating a full provider instance.\n *\n * @param meta - An object containing the name and version of the item to check.\n * @returns `true` if the item exists, otherwise `false`.\n *\n * @example\n * ```typescript\n * const formExists = LocalStorageProvider.has({ name: 'user-form', schemaVersion: 1 });\n * if (formExists) {\n * // Show the \"Thank you\" message\n * } else {\n * // Show the form\n * }\n * ```\n */\n public static has(meta: StorageMeta): boolean {\n const key = LocalStorageProvider.getKey(meta);\n return localStorage.getItem(key) !== null;\n }\n\n /**\n * Writes the default value to localStorage and returns it.\n */\n private handleDefault__(): Jsonify<T> {\n this.logger_.logMethodArgs?.('handleDefault__', this.defaultValue__);\n try {\n this.write(this.defaultValue__);\n }\n catch (err) {\n this.logger_.error('write', 'write_default_error', {err});\n }\n return this.defaultValue__;\n }\n\n /**\n * Converts the provided data to a JSON-compatible format by simulating\n * a serialization/deserialization cycle. This ensures that the data\n * conforms to the `Jsonify<T>` type.\n *\n * @template T - The type of the input data.\n * @param data - The data to be converted to a JSON-compatible format.\n * @returns The converted data as `Jsonify<T>`.\n * @throws {Error} If the serialization/deserialization process fails.\n */\n public convertDataType(data: T | Jsonify<T>): Jsonify<T> {\n this.logger_.logMethod?.('convertDataType');\n // Simulate real serialization/deserialization cycle for real types\n try {\n return JSON.parse(JSON.stringify(data)) as Jsonify<T>;\n }\n catch (err) {\n this.logger_.error('convertDataType__', 'convert_data_type_error', {err});\n throw new Error('convert_data_type_error');\n }\n }\n\n /**\n * Reads and parses the value from localStorage.\n * If the item doesn't exist, is invalid JSON, or doesn't match the expected type,\n * it writes and returns the default value.\n */\n public read(): Jsonify<T> {\n let value: string | null = null;\n try {\n value = localStorage.getItem(this.key__);\n }\n catch (err) {\n this.logger_.error('read', 'read_local_storage_error', {err});\n }\n\n if (value === null) {\n this.logger_.logMethod?.('read//no_value');\n return this.handleDefault__();\n }\n\n try {\n const parsedValue = JSON.parse(value) as Jsonify<T>;\n this.logger_.logMethodFull?.('read//value', undefined, {parsedValue});\n return parsedValue;\n }\n catch (err) {\n this.logger_.error('read', 'read_parse_error', {err});\n return this.handleDefault__();\n }\n }\n\n /**\n * Serializes and writes a value to localStorage.\n */\n public write(value: T | Jsonify<T>): void {\n this.logger_.logMethodArgs?.('write', {value});\n let valueStr: string;\n try {\n valueStr = JSON.stringify(value);\n }\n catch (err) {\n this.logger_.error('write', 'write_stringify_error', {err});\n throw new Error('write_stringify_error');\n }\n\n try {\n localStorage.setItem(this.key__, valueStr);\n }\n catch (err) {\n this.logger_.error('write', 'write_local_storage_error', {err});\n }\n }\n\n /**\n * Removes the item from localStorage.\n */\n public remove(): void {\n localStorage.removeItem(this.key__);\n }\n\n /**\n * Manages data migration by removing all previous versions of the item.\n */\n private migrate__(): void {\n if (this.meta__.schemaVersion <= 1) return;\n\n // Iterate from v1 up to the version just before the current one and remove them.\n for (let i = 1; i < this.meta__.schemaVersion; i++) {\n const oldKey = LocalStorageProvider.getKey({name: this.meta__.name, schemaVersion: i});\n localStorage.removeItem(oldKey);\n }\n }\n}\n", "import {LocalStorageProvider} from './local-storage.provider.js';\n\nimport type {LocalStorageProviderConfig} from './type.js';\n\n/**\n * Factory function to create a new LocalStorageProvider.\n *\n * @param config - The configuration for the provider.\n * @returns An instance of LocalStorageProvider.\n *\n * @example\n * ```typescript\n * const userSettings = createLocalStorageProvider({\n * name: 'user-settings',\n * schemaVersion: 1,\n * defaultValue: { theme: 'light', notifications: true }\n * });\n *\n * // Write new settings\n * userSettings.write({ theme: 'dark', notifications: false });\n *\n * // Read the current settings\n * const currentSettings = userSettings.read();\n * console.log(currentSettings); // { theme: 'dark', notifications: false }\n * ```\n */\nexport function createLocalStorageProvider<T>(config: LocalStorageProviderConfig<T>): LocalStorageProvider<T> {\n return new LocalStorageProvider<T>(config);\n}\n"],
5
- "mappings": ";;AAAA,OAAQ,iBAAmB,iBAwBpB,IAAM,qBAAN,MAAM,qBAAwB,CACnC,YAAuB,QAAU,QASjC,YAAY,OAAuC,CACjD,KAAK,QAAU,aAAa,2BAA2B,OAAO,IAAI,QAAQ,OAAO,aAAa,EAAE,EAChG,KAAK,QAAQ,gBAAgB,cAAe,CAAC,MAAM,CAAC,EACpD,KAAK,OAAS,CACZ,KAAM,OAAO,KACb,cAAe,OAAO,aACxB,EACA,KAAK,MAAQ,sBAAqB,OAAO,KAAK,MAAM,EACpD,KAAK,eAAiB,KAAK,gBAAgB,OAAO,YAAY,EAC9D,KAAK,UAAU,CACjB,CAOA,OAAc,OAAO,KAA2B,CAC9C,MAAO,GAAG,KAAK,IAAI,KAAK,KAAK,aAAa,EAC5C,CAmBA,OAAc,IAAI,KAA4B,CAC5C,MAAM,IAAM,sBAAqB,OAAO,IAAI,EAC5C,OAAO,aAAa,QAAQ,GAAG,IAAM,IACvC,CAKQ,iBAA8B,CACpC,KAAK,QAAQ,gBAAgB,kBAAmB,KAAK,cAAc,EACnE,GAAI,CACF,KAAK,MAAM,KAAK,cAAc,CAChC,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,QAAS,sBAAuB,CAAC,GAAG,CAAC,CAC1D,CACA,OAAO,KAAK,cACd,CAYO,gBAAgB,KAAkC,CACvD,KAAK,QAAQ,YAAY,iBAAiB,EAE1C,GAAI,CACF,OAAO,KAAK,MAAM,KAAK,UAAU,IAAI,CAAC,CACxC,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,oBAAqB,0BAA2B,CAAC,GAAG,CAAC,EACxE,MAAM,IAAI,MAAM,yBAAyB,CAC3C,CACF,CAOO,MAAmB,CACxB,IAAI,MAAuB,KAC3B,GAAI,CACF,MAAQ,aAAa,QAAQ,KAAK,KAAK,CACzC,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,OAAQ,2BAA4B,CAAC,GAAG,CAAC,CAC9D,CAEA,GAAI,QAAU,KAAM,CAClB,KAAK,QAAQ,YAAY,gBAAgB,EACzC,OAAO,KAAK,gBAAgB,CAC9B,CAEA,GAAI,CACF,MAAM,YAAc,KAAK,MAAM,KAAK,EACpC,KAAK,QAAQ,gBAAgB,cAAe,OAAW,CAAC,WAAW,CAAC,EACpE,OAAO,WACT,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,OAAQ,mBAAoB,CAAC,GAAG,CAAC,EACpD,OAAO,KAAK,gBAAgB,CAC9B,CACF,CAKO,MAAM,MAA6B,CACxC,KAAK,QAAQ,gBAAgB,QAAS,CAAC,KAAK,CAAC,EAC7C,IAAI,SACJ,GAAI,CACF,SAAW,KAAK,UAAU,KAAK,CACjC,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,QAAS,wBAAyB,CAAC,GAAG,CAAC,EAC1D,MAAM,IAAI,MAAM,uBAAuB,CACzC,CAEA,GAAI,CACF,aAAa,QAAQ,KAAK,MAAO,QAAQ,CAC3C,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,QAAS,4BAA6B,CAAC,GAAG,CAAC,CAChE,CACF,CAKO,QAAe,CACpB,aAAa,WAAW,KAAK,KAAK,CACpC,CAKQ,WAAkB,CACxB,GAAI,KAAK,OAAO,eAAiB,EAAG,OAGpC,QAAS,EAAI,EAAG,EAAI,KAAK,OAAO,cAAe,IAAK,CAClD,MAAM,OAAS,sBAAqB,OAAO,CAAC,KAAM,KAAK,OAAO,KAAM,cAAe,CAAC,CAAC,EACrF,aAAa,WAAW,MAAM,CAChC,CACF,CACF,EC9JO,SAAS,2BAA8B,OAAgE,CAC5G,OAAO,IAAI,qBAAwB,MAAM,CAC3C",
4
+ "sourcesContent": ["import {createLogger} from '@alwatr/logger';\n\nimport type {LocalStorageProviderConfig, StorageMeta} from './type.js';\n\n/**\n * A provider class for managing a specific, versioned item in localStorage.\n * It encapsulates the logic for key generation, serialization, and migration.\n *\n * @example\n * ```typescript\n * const userSettings = new LocalStorageProvider({\n * name: 'user-settings',\n * version: 1,\n * defaultValue: { theme: 'light', notifications: true }\n * });\n *\n * // Write new settings\n * userSettings.write({ theme: 'dark', notifications: false });\n *\n * // Read the current settings\n * const currentSettings = userSettings.read();\n * console.log(currentSettings); // { theme: 'dark', notifications: false }\n * ```\n */\nexport class LocalStorageProvider<T extends JsonValue> {\n public static readonly version = __package_version__;\n\n private readonly key__: string;\n protected readonly logger_;\n\n private readonly meta__: Readonly<StorageMeta>;\n\n protected readonly defaultValue__: T;\n\n constructor(config: LocalStorageProviderConfig<T>) {\n this.logger_ = createLogger(`local-storage-provider: ${config.name}, v: ${config.schemaVersion}`);\n this.logger_.logMethodArgs?.('constructor', {config});\n this.meta__ = {\n name: config.name,\n schemaVersion: config.schemaVersion,\n };\n this.key__ = LocalStorageProvider.getKey(this.meta__);\n this.defaultValue__ = this.convertDataType__(config.defaultValue);\n this.migrate__();\n }\n\n /**\n * Generates the versioned storage key.\n * @param meta - An object containing the name and schemaVersion.\n * @returns The versioned key string.\n */\n public static getKey(meta: StorageMeta): string {\n return `${meta.name}.v${meta.schemaVersion}`;\n }\n\n /**\n * Statically checks if a versioned item exists in localStorage.\n * This method provides a high-performance way to check for data existence without the overhead of creating a full provider instance.\n *\n * @param meta - An object containing the name and version of the item to check.\n * @returns `true` if the item exists, otherwise `false`.\n *\n * @example\n * ```typescript\n * const formExists = LocalStorageProvider.has({ name: 'user-form', schemaVersion: 1 });\n * if (formExists) {\n * // Show the \"Thank you\" message\n * } else {\n * // Show the form\n * }\n * ```\n */\n public static has(meta: StorageMeta): boolean {\n const key = LocalStorageProvider.getKey(meta);\n return localStorage.getItem(key) !== null;\n }\n\n /**\n * Writes the default value to localStorage and returns it.\n */\n private handleDefault__(): T {\n this.logger_.logMethodArgs?.('handleDefault__', this.defaultValue__);\n try {\n this.write(this.defaultValue__);\n }\n catch (err) {\n this.logger_.error('write', 'write_default_error', {err});\n }\n return this.defaultValue__;\n }\n\n /**\n * Converts the provided data to a JSON-compatible format by simulating\n * a serialization/deserialization cycle. This ensures that the data\n * conforms to the `T` type.\n *\n * @template T - The type of the input data.\n * @param data - The data to be converted to a JSON-compatible format.\n * @returns The converted data as `T`.\n * @throws {Error} If the serialization/deserialization process fails.\n */\n private convertDataType__(data: T): T {\n this.logger_.logMethod?.('convertDataType');\n // Simulate real serialization/deserialization cycle for real types\n try {\n return JSON.parse(JSON.stringify(data)) as T;\n }\n catch (err) {\n this.logger_.error('convertDataType__', 'convert_data_type_error', {err});\n throw new Error('convert_data_type_error');\n }\n }\n\n /**\n * Reads and parses the value from localStorage.\n * If the item doesn't exist, is invalid JSON, or doesn't match the expected type,\n * it writes and returns the default value.\n */\n public read(): T {\n let value: string | null = null;\n try {\n value = localStorage.getItem(this.key__);\n }\n catch (err) {\n this.logger_.error('read', 'read_local_storage_error', {err});\n }\n\n if (value === null) {\n this.logger_.logMethod?.('read//no_value');\n return this.handleDefault__();\n }\n\n try {\n const parsedValue = JSON.parse(value) as T;\n this.logger_.logMethodFull?.('read//value', undefined, {parsedValue});\n return parsedValue;\n }\n catch (err) {\n this.logger_.error('read', 'read_parse_error', {err});\n return this.handleDefault__();\n }\n }\n\n /**\n * Serializes and writes a value to localStorage.\n */\n public write(value: T): void {\n this.logger_.logMethodArgs?.('write', {value});\n let valueStr: string;\n try {\n valueStr = JSON.stringify(value);\n }\n catch (err) {\n this.logger_.error('write', 'write_stringify_error', {err});\n throw new Error('write_stringify_error');\n }\n\n try {\n localStorage.setItem(this.key__, valueStr);\n }\n catch (err) {\n this.logger_.error('write', 'write_local_storage_error', {err});\n }\n }\n\n /**\n * Removes the item from localStorage.\n */\n public remove(): void {\n localStorage.removeItem(this.key__);\n }\n\n /**\n * Manages data migration by removing all previous versions of the item.\n */\n private migrate__(): void {\n if (this.meta__.schemaVersion <= 1) return;\n\n // Iterate from v1 up to the version just before the current one and remove them.\n for (let i = 1; i < this.meta__.schemaVersion; i++) {\n const oldKey = LocalStorageProvider.getKey({name: this.meta__.name, schemaVersion: i});\n localStorage.removeItem(oldKey);\n }\n }\n}\n", "import {LocalStorageProvider} from './local-storage.provider.js';\n\nimport type {LocalStorageProviderConfig} from './type.js';\n\n/**\n * Factory function to create a new LocalStorageProvider.\n *\n * @param config - The configuration for the provider.\n * @returns An instance of LocalStorageProvider.\n *\n * @example\n * ```typescript\n * const userSettings = createLocalStorageProvider({\n * name: 'user-settings',\n * schemaVersion: 1,\n * defaultValue: { theme: 'light', notifications: true }\n * });\n *\n * // Write new settings\n * userSettings.write({ theme: 'dark', notifications: false });\n *\n * // Read the current settings\n * const currentSettings = userSettings.read();\n * console.log(currentSettings); // { theme: 'dark', notifications: false }\n * ```\n */\nexport function createLocalStorageProvider<T extends JsonValue>(config: LocalStorageProviderConfig<T>): LocalStorageProvider<T> {\n return new LocalStorageProvider<T>(config);\n}\n"],
5
+ "mappings": ";;AAAA,OAAQ,iBAAmB,iBAwBpB,IAAM,qBAAN,MAAM,qBAA0C,CACrD,YAAuB,QAAU,QASjC,YAAY,OAAuC,CACjD,KAAK,QAAU,aAAa,2BAA2B,OAAO,IAAI,QAAQ,OAAO,aAAa,EAAE,EAChG,KAAK,QAAQ,gBAAgB,cAAe,CAAC,MAAM,CAAC,EACpD,KAAK,OAAS,CACZ,KAAM,OAAO,KACb,cAAe,OAAO,aACxB,EACA,KAAK,MAAQ,sBAAqB,OAAO,KAAK,MAAM,EACpD,KAAK,eAAiB,KAAK,kBAAkB,OAAO,YAAY,EAChE,KAAK,UAAU,CACjB,CAOA,OAAc,OAAO,KAA2B,CAC9C,MAAO,GAAG,KAAK,IAAI,KAAK,KAAK,aAAa,EAC5C,CAmBA,OAAc,IAAI,KAA4B,CAC5C,MAAM,IAAM,sBAAqB,OAAO,IAAI,EAC5C,OAAO,aAAa,QAAQ,GAAG,IAAM,IACvC,CAKQ,iBAAqB,CAC3B,KAAK,QAAQ,gBAAgB,kBAAmB,KAAK,cAAc,EACnE,GAAI,CACF,KAAK,MAAM,KAAK,cAAc,CAChC,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,QAAS,sBAAuB,CAAC,GAAG,CAAC,CAC1D,CACA,OAAO,KAAK,cACd,CAYQ,kBAAkB,KAAY,CACpC,KAAK,QAAQ,YAAY,iBAAiB,EAE1C,GAAI,CACF,OAAO,KAAK,MAAM,KAAK,UAAU,IAAI,CAAC,CACxC,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,oBAAqB,0BAA2B,CAAC,GAAG,CAAC,EACxE,MAAM,IAAI,MAAM,yBAAyB,CAC3C,CACF,CAOO,MAAU,CACf,IAAI,MAAuB,KAC3B,GAAI,CACF,MAAQ,aAAa,QAAQ,KAAK,KAAK,CACzC,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,OAAQ,2BAA4B,CAAC,GAAG,CAAC,CAC9D,CAEA,GAAI,QAAU,KAAM,CAClB,KAAK,QAAQ,YAAY,gBAAgB,EACzC,OAAO,KAAK,gBAAgB,CAC9B,CAEA,GAAI,CACF,MAAM,YAAc,KAAK,MAAM,KAAK,EACpC,KAAK,QAAQ,gBAAgB,cAAe,OAAW,CAAC,WAAW,CAAC,EACpE,OAAO,WACT,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,OAAQ,mBAAoB,CAAC,GAAG,CAAC,EACpD,OAAO,KAAK,gBAAgB,CAC9B,CACF,CAKO,MAAM,MAAgB,CAC3B,KAAK,QAAQ,gBAAgB,QAAS,CAAC,KAAK,CAAC,EAC7C,IAAI,SACJ,GAAI,CACF,SAAW,KAAK,UAAU,KAAK,CACjC,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,QAAS,wBAAyB,CAAC,GAAG,CAAC,EAC1D,MAAM,IAAI,MAAM,uBAAuB,CACzC,CAEA,GAAI,CACF,aAAa,QAAQ,KAAK,MAAO,QAAQ,CAC3C,OACO,IAAK,CACV,KAAK,QAAQ,MAAM,QAAS,4BAA6B,CAAC,GAAG,CAAC,CAChE,CACF,CAKO,QAAe,CACpB,aAAa,WAAW,KAAK,KAAK,CACpC,CAKQ,WAAkB,CACxB,GAAI,KAAK,OAAO,eAAiB,EAAG,OAGpC,QAAS,EAAI,EAAG,EAAI,KAAK,OAAO,cAAe,IAAK,CAClD,MAAM,OAAS,sBAAqB,OAAO,CAAC,KAAM,KAAK,OAAO,KAAM,cAAe,CAAC,CAAC,EACrF,aAAa,WAAW,MAAM,CAChC,CACF,CACF,EC9JO,SAAS,2BAAgD,OAAgE,CAC9H,OAAO,IAAI,qBAAwB,MAAM,CAC3C",
6
6
  "names": []
7
7
  }
package/dist/type.d.ts CHANGED
@@ -9,7 +9,7 @@ export interface StorageMeta {
9
9
  */
10
10
  schemaVersion: number;
11
11
  }
12
- export interface LocalStorageProviderConfig<T> extends StorageMeta {
12
+ export interface LocalStorageProviderConfig<T extends JsonValue> extends StorageMeta {
13
13
  /**
14
14
  * The default value to use if no value is stored.
15
15
  */
@@ -1 +1 @@
1
- {"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../src/type.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,0BAA0B,CAAC,CAAC,CAAE,SAAQ,WAAW;IAChE;;OAEG;IACH,YAAY,EAAE,CAAC,CAAC;CACjB"}
1
+ {"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../src/type.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,0BAA0B,CAAC,CAAC,SAAS,SAAS,CAAE,SAAQ,WAAW;IAClF;;OAEG;IACH,YAAY,EAAE,CAAC,CAAC;CACjB"}
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@alwatr/local-storage",
3
3
  "description": "A modern, simple, and robust solution for managing versioned JSON objects in the browser's `localStorage`. This package provides a clean, class-based API with a factory function to ensure your application's data persistence is safe, maintainable, and future-proof.",
4
- "version": "6.3.2",
4
+ "version": "6.3.4",
5
5
  "author": "S. Ali Mihandoost <ali.mihandoost@gmail.com>",
6
6
  "bugs": "https://github.com/Alwatr/nanolib/issues",
7
7
  "dependencies": {
8
- "@alwatr/logger": "6.0.6"
8
+ "@alwatr/logger": "6.0.8"
9
9
  },
10
10
  "devDependencies": {
11
- "@alwatr/nano-build": "6.3.2",
12
- "@alwatr/prettier-config": "5.0.4",
13
- "@alwatr/tsconfig-base": "6.0.2",
14
- "@alwatr/type-helper": "6.1.2",
11
+ "@alwatr/nano-build": "6.3.4",
12
+ "@alwatr/prettier-config": "5.0.5",
13
+ "@alwatr/tsconfig-base": "6.0.3",
14
+ "@alwatr/type-helper": "6.1.4",
15
15
  "@jest/globals": "^30.1.2",
16
16
  "typescript": "^5.9.2"
17
17
  },
@@ -25,7 +25,8 @@
25
25
  "files": [
26
26
  "**/*.{js,mjs,cjs,map,d.ts,html,md,LEGAL.txt}",
27
27
  "LICENSE",
28
- "!demo/**/*"
28
+ "!demo/**/*",
29
+ "!**/*.test.js"
29
30
  ],
30
31
  "homepage": "https://github.com/Alwatr/nanolib/tree/next/packages/local-storage#readme",
31
32
  "keywords": [
@@ -75,5 +76,5 @@
75
76
  "sideEffects": false,
76
77
  "type": "module",
77
78
  "types": "./dist/main.d.ts",
78
- "gitHead": "ffa60604db6f5975bc91b62bdadd859cd0327fa1"
79
+ "gitHead": "c013ded43aff3937cf347de4e99125ab807d99e1"
79
80
  }
package/src/main.test.js DELETED
@@ -1,234 +0,0 @@
1
- import {describe, beforeEach, afterEach, it, expect, jest} from '@jest/globals';
2
- import {createLocalStorageProvider, LocalStorageProvider} from '@alwatr/local-storage';
3
-
4
- /**
5
- * @jest-environment jsdom
6
- */
7
- describe('LocalStorageProvider', () => {
8
- /**
9
- * @type {jest.Mocked<Pick<Storage, "getItem" | "setItem" | "removeItem">>}
10
- */
11
- let mockLocalStorage;
12
-
13
- beforeEach(() => {
14
- mockLocalStorage = {
15
- getItem: jest.fn(),
16
- setItem: jest.fn(),
17
- removeItem: jest.fn(),
18
- };
19
- Object.defineProperty(globalThis, 'localStorage', {
20
- value: mockLocalStorage,
21
- writable: true,
22
- });
23
- });
24
-
25
- afterEach(() => {
26
- jest.clearAllMocks();
27
- });
28
-
29
- describe('static getKey', () => {
30
- it('should generate the correct versioned key', () => {
31
- const key = LocalStorageProvider.getKey({name: 'test', schemaVersion: 1});
32
- expect(key).toBe('test.v1');
33
- });
34
-
35
- it('should handle different names and versions', () => {
36
- const key1 = LocalStorageProvider.getKey({name: 'user-settings', schemaVersion: 2});
37
- expect(key1).toBe('user-settings.v2');
38
- const key2 = LocalStorageProvider.getKey({name: 'form-data', schemaVersion: 5});
39
- expect(key2).toBe('form-data.v5');
40
- });
41
- });
42
-
43
- describe('static has', () => {
44
- it('should return true if item exists', () => {
45
- mockLocalStorage.getItem.mockReturnValue('{"value": "test"}');
46
- const exists = LocalStorageProvider.has({name: 'test', schemaVersion: 1});
47
- expect(exists).toBe(true);
48
- expect(mockLocalStorage.getItem).toHaveBeenCalledWith('test.v1');
49
- });
50
-
51
- it('should return false if item does not exist', () => {
52
- mockLocalStorage.getItem.mockReturnValue(null);
53
- const exists = LocalStorageProvider.has({name: 'test', schemaVersion: 1});
54
- expect(exists).toBe(false);
55
- });
56
-
57
- it('should return false for null value', () => {
58
- mockLocalStorage.getItem.mockReturnValue(null);
59
- const exists = LocalStorageProvider.has({name: 'test', schemaVersion: 1});
60
- expect(exists).toBe(false);
61
- });
62
- });
63
-
64
- describe('constructor and migration', () => {
65
- it('should initialize with config and migrate old versions', () => {
66
- const provider = createLocalStorageProvider({
67
- name: 'test',
68
- schemaVersion: 3,
69
- defaultValue: {key: 'value'},
70
- });
71
- expect(mockLocalStorage.removeItem).toHaveBeenCalledWith('test.v1');
72
- expect(mockLocalStorage.removeItem).toHaveBeenCalledWith('test.v2');
73
- });
74
-
75
- it('should not migrate if schemaVersion is 1', () => {
76
- const provider = createLocalStorageProvider({
77
- name: 'test',
78
- schemaVersion: 1,
79
- defaultValue: {key: 'value'},
80
- });
81
- expect(mockLocalStorage.removeItem).not.toHaveBeenCalled();
82
- });
83
-
84
- it('should migrate multiple old versions for higher schemaVersion', () => {
85
- const provider = createLocalStorageProvider({
86
- name: 'test',
87
- schemaVersion: 5,
88
- defaultValue: {key: 'value'},
89
- });
90
- expect(mockLocalStorage.removeItem).toHaveBeenCalledWith('test.v1');
91
- expect(mockLocalStorage.removeItem).toHaveBeenCalledWith('test.v2');
92
- expect(mockLocalStorage.removeItem).toHaveBeenCalledWith('test.v3');
93
- expect(mockLocalStorage.removeItem).toHaveBeenCalledWith('test.v4');
94
- });
95
- });
96
-
97
- describe('read', () => {
98
- it('should return default value if no item exists', () => {
99
- mockLocalStorage.getItem.mockReturnValue(null);
100
- const provider = createLocalStorageProvider({
101
- name: 'test',
102
- schemaVersion: 1,
103
- defaultValue: {key: 'default'},
104
- });
105
- const result = provider.read();
106
- expect(result).toEqual({key: 'default'});
107
- expect(mockLocalStorage.setItem).toHaveBeenCalledWith('test.v1', '{"key":"default"}');
108
- });
109
-
110
- it('should return parsed value if item exists', () => {
111
- mockLocalStorage.getItem.mockReturnValue('{"key":"stored"}');
112
- const provider = createLocalStorageProvider({
113
- name: 'test',
114
- schemaVersion: 1,
115
- defaultValue: {key: 'default'},
116
- });
117
- const result = provider.read();
118
- expect(result).toEqual({key: 'stored'});
119
- });
120
-
121
- it('should return default value on invalid JSON', () => {
122
- mockLocalStorage.getItem.mockReturnValue('invalid json');
123
- const provider = createLocalStorageProvider({
124
- name: 'test',
125
- schemaVersion: 1,
126
- defaultValue: {key: 'default'},
127
- });
128
- const result = provider.read();
129
- expect(result).toEqual({key: 'default'});
130
- });
131
-
132
- it('should handle complex default values', () => {
133
- mockLocalStorage.getItem.mockReturnValue(null);
134
- const provider = createLocalStorageProvider({
135
- name: 'test',
136
- schemaVersion: 1,
137
- defaultValue: {theme: 'dark', lastLogin: Date.now(), settings: [1, 2, 3]},
138
- });
139
- const result = provider.read();
140
- expect(result.theme).toBe('dark');
141
- expect(Array.isArray(result.settings)).toBe(true);
142
- });
143
- });
144
-
145
- describe('write', () => {
146
- it('should serialize and store the value', () => {
147
- const provider = createLocalStorageProvider({
148
- name: 'test',
149
- schemaVersion: 1,
150
- defaultValue: {key: 'default'},
151
- });
152
- provider.write({key: 'newValue'});
153
- expect(mockLocalStorage.setItem).toHaveBeenCalledWith('test.v1', '{"key":"newValue"}');
154
- });
155
-
156
- it('should handle write errors gracefully', () => {
157
- mockLocalStorage.setItem.mockImplementation(() => {
158
- throw new Error('Storage full');
159
- });
160
- const provider = createLocalStorageProvider({
161
- name: 'test',
162
- schemaVersion: 1,
163
- defaultValue: {key: 'default'},
164
- });
165
- expect(() => provider.write({key: 'value'})).not.toThrow();
166
- });
167
-
168
- it('should write different data types', () => {
169
- const provider = createLocalStorageProvider({
170
- name: 'test',
171
- schemaVersion: 1,
172
- /**
173
- * @type {string|number|Array<number>}
174
- */
175
- defaultValue: '',
176
- });
177
- provider.write('string value');
178
- expect(mockLocalStorage.setItem).toHaveBeenCalledWith('test.v1', '"string value"');
179
- provider.write(42);
180
- expect(mockLocalStorage.setItem).toHaveBeenCalledWith('test.v1', '42');
181
- provider.write([1, 2, 3]);
182
- expect(mockLocalStorage.setItem).toHaveBeenCalledWith('test.v1', '[1,2,3]');
183
- });
184
- });
185
-
186
- describe('remove', () => {
187
- it('should remove the item from storage', () => {
188
- const provider = createLocalStorageProvider({
189
- name: 'test',
190
- schemaVersion: 1,
191
- defaultValue: {key: 'default'},
192
- });
193
- provider.remove();
194
- expect(mockLocalStorage.removeItem).toHaveBeenCalledWith('test.v1');
195
- });
196
-
197
- it('should not throw if item does not exist', () => {
198
- const provider = createLocalStorageProvider({
199
- name: 'test',
200
- schemaVersion: 1,
201
- defaultValue: {key: 'default'},
202
- });
203
- expect(() => provider.remove()).not.toThrow();
204
- });
205
- });
206
-
207
- describe('createLocalStorageProvider factory', () => {
208
- it('should create a provider instance', () => {
209
- const provider = createLocalStorageProvider({
210
- name: 'factory-test',
211
- schemaVersion: 1,
212
- defaultValue: {created: true},
213
- });
214
- expect(provider).toBeInstanceOf(LocalStorageProvider);
215
- const result = provider.read();
216
- expect(result.created).toBe(true);
217
- });
218
-
219
- it('should handle different configurations', () => {
220
- const provider1 = createLocalStorageProvider({
221
- name: 'config1',
222
- schemaVersion: 2,
223
- defaultValue: 'default1',
224
- });
225
- const provider2 = createLocalStorageProvider({
226
- name: 'config2',
227
- schemaVersion: 1,
228
- defaultValue: {key: 'default2'},
229
- });
230
- expect(provider1.read()).toBe('default1');
231
- expect(provider2.read().key).toBe('default2');
232
- });
233
- });
234
- });