kvozy 0.8.0 → 0.9.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.
@@ -25,6 +25,7 @@ export declare class BindValue<T> {
25
25
  getValue(): T;
26
26
  set(newValue: T): void;
27
27
  subscribe(callback: (value: T) => void): () => void;
28
+ reset(): void;
28
29
  getRaw(): string | null;
29
30
  setRaw(rawValue: string): void;
30
31
  private loadFromStorage;
@@ -49,6 +49,11 @@ class BindValue {
49
49
  this.subscribers.delete(callback);
50
50
  };
51
51
  }
52
+ reset() {
53
+ this.storage.removeItem(this.options.key);
54
+ this.value = this.options.defaultValue;
55
+ this.notifySubscribers();
56
+ }
52
57
  getRaw() {
53
58
  return this.storage.getItem(this.options.key);
54
59
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bindValue.js","sources":["../../../../src/bindValue.ts"],"sourcesContent":["export interface BindValueOptions<T> {\n key: string;\n defaultValue: T;\n serialize: (value: T) => string;\n deserialize: (serialized: string) => T;\n storage?: Storage;\n version?: string;\n migrate?: (oldSerialized: string, oldVersion: string | undefined) => T;\n}\n\nexport interface BindValueNSOptions<T> {\n prefix: string;\n defaultValue: T;\n serialize: (value: T) => string;\n deserialize: (serialized: string) => T;\n storage?: Storage;\n version?: string;\n migrate?: (oldSerialized: string, oldVersion: string | undefined) => T;\n}\n\nconst memoryStorage = new Map<string, string>();\n\nconst inMemoryStorage: Storage = {\n get length() {\n return memoryStorage.size;\n },\n clear() {\n memoryStorage.clear();\n },\n getItem(key: string) {\n return memoryStorage.get(key) ?? null;\n },\n key(index: number) {\n const keys = Array.from(memoryStorage.keys());\n return keys[index] ?? null;\n },\n removeItem(key: string) {\n memoryStorage.delete(key);\n },\n setItem(key: string, value: string) {\n memoryStorage.set(key, value);\n },\n};\n\nexport class BindValue<T> {\n private value: T;\n private subscribers: Set<(value: T) => void>;\n private storage: Storage;\n\n constructor(private options: BindValueOptions<T>) {\n this.storage = options.storage ?? inMemoryStorage;\n this.subscribers = new Set();\n this.value = this.loadFromStorage();\n }\n\n getValue(): T {\n return this.value;\n }\n\n set(newValue: T): void {\n this.value = newValue;\n this.saveToStorage(newValue);\n this.notifySubscribers();\n }\n\n subscribe(callback: (value: T) => void): () => void {\n this.subscribers.add(callback);\n return () => {\n this.subscribers.delete(callback);\n };\n }\n\n getRaw(): string | null {\n return this.storage.getItem(this.options.key);\n }\n\n setRaw(rawValue: string): void {\n let deserializedValue: T;\n const version = this.options.version;\n let serializedPart: string;\n\n if (version) {\n if (!rawValue.startsWith(\"\\x00\")) {\n return;\n }\n\n const parts = rawValue.split(\"\\x00\");\n if (parts.length < 3) {\n return;\n }\n\n const versionPart = parts[1];\n if (versionPart !== version) {\n return;\n }\n\n serializedPart = parts.slice(2).join(\"\\x00\");\n } else {\n serializedPart = rawValue;\n }\n\n try {\n deserializedValue = this.options.deserialize(serializedPart);\n } catch {\n return;\n }\n const serializedValue = this.options.serialize(deserializedValue);\n let reconstructedRaw: string;\n\n if (version) {\n reconstructedRaw = `\\x00${version}\\x00${serializedValue}`;\n } else {\n reconstructedRaw = serializedValue;\n }\n\n if (reconstructedRaw !== rawValue) {\n return;\n }\n\n this.storage.setItem(this.options.key, rawValue);\n this.value = deserializedValue;\n this.notifySubscribers();\n }\n\n private loadFromStorage(): T {\n const rawValue = this.storage.getItem(this.options.key);\n\n if (rawValue === null) {\n return this.options.defaultValue;\n }\n\n let oldVersion: string | undefined;\n let serializedValue: string;\n\n if (rawValue.startsWith(\"\\x00\")) {\n const parts = rawValue.split(\"\\x00\");\n if (parts.length >= 3) {\n oldVersion = parts[1];\n serializedValue = parts.slice(2).join(\"\\x00\");\n } else {\n serializedValue = rawValue;\n }\n } else {\n serializedValue = rawValue;\n }\n\n const currentVersion = this.options.version;\n\n if (oldVersion !== currentVersion) {\n if (this.options.migrate) {\n try {\n const migratedValue = this.options.migrate(\n serializedValue,\n oldVersion,\n );\n this.saveToStorage(migratedValue);\n return migratedValue;\n } catch {\n this.storage.removeItem(this.options.key);\n return this.options.defaultValue;\n }\n } else {\n this.storage.removeItem(this.options.key);\n return this.options.defaultValue;\n }\n }\n\n try {\n return this.options.deserialize(serializedValue);\n } catch {\n return this.options.defaultValue;\n }\n }\n\n private saveToStorage(value: T): void {\n try {\n const serialized = this.options.serialize(value);\n const version = this.options.version;\n\n if (version) {\n this.storage.setItem(\n this.options.key,\n `\\x00${version}\\x00${serialized}`,\n );\n } else {\n this.storage.setItem(this.options.key, serialized);\n }\n } catch {}\n }\n\n private notifySubscribers(): void {\n for (const subscriber of this.subscribers) {\n subscriber(this.value);\n }\n }\n}\n\nexport function bindValue<T>(options: BindValueOptions<T>): BindValue<T> {\n return new BindValue(options);\n}\n\nexport function _clearInMemoryStorage(): void {\n memoryStorage.clear();\n}\n\nexport class BindValueNS<T> {\n constructor(private options: BindValueNSOptions<T>) {\n if (!this.options.prefix || this.options.prefix.trim() === \"\") {\n throw new Error(\"Prefix cannot be empty\");\n }\n }\n\n bind(key: string): BindValue<T> {\n if (!key || key.trim() === \"\") {\n throw new Error(\"Key cannot be empty\");\n }\n\n return new BindValue<T>({\n key: `${this.options.prefix}\\x1F${key}`,\n defaultValue: this.options.defaultValue,\n serialize: this.options.serialize,\n deserialize: this.options.deserialize,\n storage: this.options.storage,\n version: this.options.version,\n migrate: this.options.migrate,\n });\n }\n}\n\nexport function bindValueNS<T>(options: BindValueNSOptions<T>): BindValueNS<T> {\n return new BindValueNS(options);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bindValue.js","sources":["../../../../src/bindValue.ts"],"sourcesContent":["export interface BindValueOptions<T> {\n key: string;\n defaultValue: T;\n serialize: (value: T) => string;\n deserialize: (serialized: string) => T;\n storage?: Storage;\n version?: string;\n migrate?: (oldSerialized: string, oldVersion: string | undefined) => T;\n}\n\nexport interface BindValueNSOptions<T> {\n prefix: string;\n defaultValue: T;\n serialize: (value: T) => string;\n deserialize: (serialized: string) => T;\n storage?: Storage;\n version?: string;\n migrate?: (oldSerialized: string, oldVersion: string | undefined) => T;\n}\n\nconst memoryStorage = new Map<string, string>();\n\nconst inMemoryStorage: Storage = {\n get length() {\n return memoryStorage.size;\n },\n clear() {\n memoryStorage.clear();\n },\n getItem(key: string) {\n return memoryStorage.get(key) ?? null;\n },\n key(index: number) {\n const keys = Array.from(memoryStorage.keys());\n return keys[index] ?? null;\n },\n removeItem(key: string) {\n memoryStorage.delete(key);\n },\n setItem(key: string, value: string) {\n memoryStorage.set(key, value);\n },\n};\n\nexport class BindValue<T> {\n private value: T;\n private subscribers: Set<(value: T) => void>;\n private storage: Storage;\n\n constructor(private options: BindValueOptions<T>) {\n this.storage = options.storage ?? inMemoryStorage;\n this.subscribers = new Set();\n this.value = this.loadFromStorage();\n }\n\n getValue(): T {\n return this.value;\n }\n\n set(newValue: T): void {\n this.value = newValue;\n this.saveToStorage(newValue);\n this.notifySubscribers();\n }\n\n subscribe(callback: (value: T) => void): () => void {\n this.subscribers.add(callback);\n return () => {\n this.subscribers.delete(callback);\n };\n }\n\n reset(): void {\n this.storage.removeItem(this.options.key);\n this.value = this.options.defaultValue;\n this.notifySubscribers();\n }\n\n getRaw(): string | null {\n return this.storage.getItem(this.options.key);\n }\n\n setRaw(rawValue: string): void {\n let deserializedValue: T;\n const version = this.options.version;\n let serializedPart: string;\n\n if (version) {\n if (!rawValue.startsWith(\"\\x00\")) {\n return;\n }\n\n const parts = rawValue.split(\"\\x00\");\n if (parts.length < 3) {\n return;\n }\n\n const versionPart = parts[1];\n if (versionPart !== version) {\n return;\n }\n\n serializedPart = parts.slice(2).join(\"\\x00\");\n } else {\n serializedPart = rawValue;\n }\n\n try {\n deserializedValue = this.options.deserialize(serializedPart);\n } catch {\n return;\n }\n const serializedValue = this.options.serialize(deserializedValue);\n let reconstructedRaw: string;\n\n if (version) {\n reconstructedRaw = `\\x00${version}\\x00${serializedValue}`;\n } else {\n reconstructedRaw = serializedValue;\n }\n\n if (reconstructedRaw !== rawValue) {\n return;\n }\n\n this.storage.setItem(this.options.key, rawValue);\n this.value = deserializedValue;\n this.notifySubscribers();\n }\n\n private loadFromStorage(): T {\n const rawValue = this.storage.getItem(this.options.key);\n\n if (rawValue === null) {\n return this.options.defaultValue;\n }\n\n let oldVersion: string | undefined;\n let serializedValue: string;\n\n if (rawValue.startsWith(\"\\x00\")) {\n const parts = rawValue.split(\"\\x00\");\n if (parts.length >= 3) {\n oldVersion = parts[1];\n serializedValue = parts.slice(2).join(\"\\x00\");\n } else {\n serializedValue = rawValue;\n }\n } else {\n serializedValue = rawValue;\n }\n\n const currentVersion = this.options.version;\n\n if (oldVersion !== currentVersion) {\n if (this.options.migrate) {\n try {\n const migratedValue = this.options.migrate(\n serializedValue,\n oldVersion,\n );\n this.saveToStorage(migratedValue);\n return migratedValue;\n } catch {\n this.storage.removeItem(this.options.key);\n return this.options.defaultValue;\n }\n } else {\n this.storage.removeItem(this.options.key);\n return this.options.defaultValue;\n }\n }\n\n try {\n return this.options.deserialize(serializedValue);\n } catch {\n return this.options.defaultValue;\n }\n }\n\n private saveToStorage(value: T): void {\n try {\n const serialized = this.options.serialize(value);\n const version = this.options.version;\n\n if (version) {\n this.storage.setItem(\n this.options.key,\n `\\x00${version}\\x00${serialized}`,\n );\n } else {\n this.storage.setItem(this.options.key, serialized);\n }\n } catch {}\n }\n\n private notifySubscribers(): void {\n for (const subscriber of this.subscribers) {\n subscriber(this.value);\n }\n }\n}\n\nexport function bindValue<T>(options: BindValueOptions<T>): BindValue<T> {\n return new BindValue(options);\n}\n\nexport function _clearInMemoryStorage(): void {\n memoryStorage.clear();\n}\n\nexport class BindValueNS<T> {\n constructor(private options: BindValueNSOptions<T>) {\n if (!this.options.prefix || this.options.prefix.trim() === \"\") {\n throw new Error(\"Prefix cannot be empty\");\n }\n }\n\n bind(key: string): BindValue<T> {\n if (!key || key.trim() === \"\") {\n throw new Error(\"Key cannot be empty\");\n }\n\n return new BindValue<T>({\n key: `${this.options.prefix}\\x1F${key}`,\n defaultValue: this.options.defaultValue,\n serialize: this.options.serialize,\n deserialize: this.options.deserialize,\n storage: this.options.storage,\n version: this.options.version,\n migrate: this.options.migrate,\n });\n }\n}\n\nexport function bindValueNS<T>(options: BindValueNSOptions<T>): BindValueNS<T> {\n return new BindValueNS(options);\n}\n"],"names":[],"mappings":";;;;;AAoBA,MAAM,oCAAoB,IAAA;AAE1B,MAAM,kBAA2B;AAAA,EAC/B,IAAI,SAAS;AACX,WAAO,cAAc;AAAA,EACvB;AAAA,EACA,QAAQ;AACN,kBAAc,MAAA;AAAA,EAChB;AAAA,EACA,QAAQ,KAAa;AACnB,WAAO,cAAc,IAAI,GAAG,KAAK;AAAA,EACnC;AAAA,EACA,IAAI,OAAe;AACjB,UAAM,OAAO,MAAM,KAAK,cAAc,MAAM;AAC5C,WAAO,KAAK,KAAK,KAAK;AAAA,EACxB;AAAA,EACA,WAAW,KAAa;AACtB,kBAAc,OAAO,GAAG;AAAA,EAC1B;AAAA,EACA,QAAQ,KAAa,OAAe;AAClC,kBAAc,IAAI,KAAK,KAAK;AAAA,EAC9B;AACF;AAEO,MAAM,UAAa;AAAA,EAKxB,YAAoB,SAA8B;AAJ1C;AACA;AACA;AAEY,SAAA,UAAA;AAClB,SAAK,UAAU,QAAQ,WAAW;AAClC,SAAK,kCAAkB,IAAA;AACvB,SAAK,QAAQ,KAAK,gBAAA;AAAA,EACpB;AAAA,EAEA,WAAc;AACZ,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,UAAmB;AACrB,SAAK,QAAQ;AACb,SAAK,cAAc,QAAQ;AAC3B,SAAK,kBAAA;AAAA,EACP;AAAA,EAEA,UAAU,UAA0C;AAClD,SAAK,YAAY,IAAI,QAAQ;AAC7B,WAAO,MAAM;AACX,WAAK,YAAY,OAAO,QAAQ;AAAA,IAClC;AAAA,EACF;AAAA,EAEA,QAAc;AACZ,SAAK,QAAQ,WAAW,KAAK,QAAQ,GAAG;AACxC,SAAK,QAAQ,KAAK,QAAQ;AAC1B,SAAK,kBAAA;AAAA,EACP;AAAA,EAEA,SAAwB;AACtB,WAAO,KAAK,QAAQ,QAAQ,KAAK,QAAQ,GAAG;AAAA,EAC9C;AAAA,EAEA,OAAO,UAAwB;AAC7B,QAAI;AACJ,UAAM,UAAU,KAAK,QAAQ;AAC7B,QAAI;AAEJ,QAAI,SAAS;AACX,UAAI,CAAC,SAAS,WAAW,IAAM,GAAG;AAChC;AAAA,MACF;AAEA,YAAM,QAAQ,SAAS,MAAM,IAAM;AACnC,UAAI,MAAM,SAAS,GAAG;AACpB;AAAA,MACF;AAEA,YAAM,cAAc,MAAM,CAAC;AAC3B,UAAI,gBAAgB,SAAS;AAC3B;AAAA,MACF;AAEA,uBAAiB,MAAM,MAAM,CAAC,EAAE,KAAK,IAAM;AAAA,IAC7C,OAAO;AACL,uBAAiB;AAAA,IACnB;AAEA,QAAI;AACF,0BAAoB,KAAK,QAAQ,YAAY,cAAc;AAAA,IAC7D,QAAQ;AACN;AAAA,IACF;AACA,UAAM,kBAAkB,KAAK,QAAQ,UAAU,iBAAiB;AAChE,QAAI;AAEJ,QAAI,SAAS;AACX,yBAAmB,KAAO,OAAO,KAAO,eAAe;AAAA,IACzD,OAAO;AACL,yBAAmB;AAAA,IACrB;AAEA,QAAI,qBAAqB,UAAU;AACjC;AAAA,IACF;AAEA,SAAK,QAAQ,QAAQ,KAAK,QAAQ,KAAK,QAAQ;AAC/C,SAAK,QAAQ;AACb,SAAK,kBAAA;AAAA,EACP;AAAA,EAEQ,kBAAqB;AAC3B,UAAM,WAAW,KAAK,QAAQ,QAAQ,KAAK,QAAQ,GAAG;AAEtD,QAAI,aAAa,MAAM;AACrB,aAAO,KAAK,QAAQ;AAAA,IACtB;AAEA,QAAI;AACJ,QAAI;AAEJ,QAAI,SAAS,WAAW,IAAM,GAAG;AAC/B,YAAM,QAAQ,SAAS,MAAM,IAAM;AACnC,UAAI,MAAM,UAAU,GAAG;AACrB,qBAAa,MAAM,CAAC;AACpB,0BAAkB,MAAM,MAAM,CAAC,EAAE,KAAK,IAAM;AAAA,MAC9C,OAAO;AACL,0BAAkB;AAAA,MACpB;AAAA,IACF,OAAO;AACL,wBAAkB;AAAA,IACpB;AAEA,UAAM,iBAAiB,KAAK,QAAQ;AAEpC,QAAI,eAAe,gBAAgB;AACjC,UAAI,KAAK,QAAQ,SAAS;AACxB,YAAI;AACF,gBAAM,gBAAgB,KAAK,QAAQ;AAAA,YACjC;AAAA,YACA;AAAA,UAAA;AAEF,eAAK,cAAc,aAAa;AAChC,iBAAO;AAAA,QACT,QAAQ;AACN,eAAK,QAAQ,WAAW,KAAK,QAAQ,GAAG;AACxC,iBAAO,KAAK,QAAQ;AAAA,QACtB;AAAA,MACF,OAAO;AACL,aAAK,QAAQ,WAAW,KAAK,QAAQ,GAAG;AACxC,eAAO,KAAK,QAAQ;AAAA,MACtB;AAAA,IACF;AAEA,QAAI;AACF,aAAO,KAAK,QAAQ,YAAY,eAAe;AAAA,IACjD,QAAQ;AACN,aAAO,KAAK,QAAQ;AAAA,IACtB;AAAA,EACF;AAAA,EAEQ,cAAc,OAAgB;AACpC,QAAI;AACF,YAAM,aAAa,KAAK,QAAQ,UAAU,KAAK;AAC/C,YAAM,UAAU,KAAK,QAAQ;AAE7B,UAAI,SAAS;AACX,aAAK,QAAQ;AAAA,UACX,KAAK,QAAQ;AAAA,UACb,KAAO,OAAO,KAAO,UAAU;AAAA,QAAA;AAAA,MAEnC,OAAO;AACL,aAAK,QAAQ,QAAQ,KAAK,QAAQ,KAAK,UAAU;AAAA,MACnD;AAAA,IACF,QAAQ;AAAA,IAAC;AAAA,EACX;AAAA,EAEQ,oBAA0B;AAChC,eAAW,cAAc,KAAK,aAAa;AACzC,iBAAW,KAAK,KAAK;AAAA,IACvB;AAAA,EACF;AACF;AAEO,SAAS,UAAa,SAA4C;AACvE,SAAO,IAAI,UAAU,OAAO;AAC9B;AAMO,MAAM,YAAe;AAAA,EAC1B,YAAoB,SAAgC;AAAhC,SAAA,UAAA;AAClB,QAAI,CAAC,KAAK,QAAQ,UAAU,KAAK,QAAQ,OAAO,KAAA,MAAW,IAAI;AAC7D,YAAM,IAAI,MAAM,wBAAwB;AAAA,IAC1C;AAAA,EACF;AAAA,EAEA,KAAK,KAA2B;AAC9B,QAAI,CAAC,OAAO,IAAI,KAAA,MAAW,IAAI;AAC7B,YAAM,IAAI,MAAM,qBAAqB;AAAA,IACvC;AAEA,WAAO,IAAI,UAAa;AAAA,MACtB,KAAK,GAAG,KAAK,QAAQ,MAAM,IAAO,GAAG;AAAA,MACrC,cAAc,KAAK,QAAQ;AAAA,MAC3B,WAAW,KAAK,QAAQ;AAAA,MACxB,aAAa,KAAK,QAAQ;AAAA,MAC1B,SAAS,KAAK,QAAQ;AAAA,MACtB,SAAS,KAAK,QAAQ;AAAA,MACtB,SAAS,KAAK,QAAQ;AAAA,IAAA,CACvB;AAAA,EACH;AACF;AAEO,SAAS,YAAe,SAAgD;AAC7E,SAAO,IAAI,YAAY,OAAO;AAChC;;;;;"}
@@ -4,6 +4,7 @@ export interface UseStorageReturn<T> {
4
4
  setValue: (value: T) => void;
5
5
  getRaw: () => string | null;
6
6
  setRaw: (rawValue: string) => void;
7
+ reset: () => void;
7
8
  }
8
9
  export declare function useStorage<T>(binding: BindValue<T>): UseStorageReturn<T>;
9
10
  export declare function useStorageNS<T>(namespace: BindValueNS<T>, options: {
@@ -14,7 +14,8 @@ function useStorage(binding) {
14
14
  value,
15
15
  setValue: set,
16
16
  getRaw: () => binding.getRaw(),
17
- setRaw: (rawValue) => binding.setRaw(rawValue)
17
+ setRaw: (rawValue) => binding.setRaw(rawValue),
18
+ reset: () => binding.reset()
18
19
  };
19
20
  }
20
21
  function useStorageNS(namespace, options) {
@@ -1 +1 @@
1
- {"version":3,"file":"useStorage.js","sources":["../../../../src/useStorage.ts"],"sourcesContent":["import { useState, useEffect } from \"react\";\nimport { type BindValue, type BindValueNS } from \"./bindValue.js\";\n\nexport interface UseStorageReturn<T> {\n value: T;\n setValue: (value: T) => void;\n getRaw: () => string | null;\n setRaw: (rawValue: string) => void;\n}\n\nexport function useStorage<T>(binding: BindValue<T>): UseStorageReturn<T> {\n const [value, setValue] = useState(binding.getValue());\n\n useEffect(() => {\n const unsubscribe = binding.subscribe(setValue);\n return unsubscribe;\n }, [binding]);\n\n const set = (newValue: T) => {\n binding.set(newValue);\n };\n\n return {\n value,\n setValue: set,\n getRaw: () => binding.getRaw(),\n setRaw: (rawValue: string) => binding.setRaw(rawValue),\n };\n}\n\nexport function useStorageNS<T>(\n namespace: BindValueNS<T>,\n options: { key: string },\n): UseStorageReturn<T> {\n const binding = namespace.bind(options.key);\n return useStorage(binding);\n}\n"],"names":["useState","useEffect"],"mappings":";;;AAUO,SAAS,WAAc,SAA4C;AACxE,QAAM,CAAC,OAAO,QAAQ,IAAIA,MAAAA,SAAS,QAAQ,UAAU;AAErDC,QAAAA,UAAU,MAAM;AACd,UAAM,cAAc,QAAQ,UAAU,QAAQ;AAC9C,WAAO;AAAA,EACT,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,MAAM,CAAC,aAAgB;AAC3B,YAAQ,IAAI,QAAQ;AAAA,EACtB;AAEA,SAAO;AAAA,IACL;AAAA,IACA,UAAU;AAAA,IACV,QAAQ,MAAM,QAAQ,OAAA;AAAA,IACtB,QAAQ,CAAC,aAAqB,QAAQ,OAAO,QAAQ;AAAA,EAAA;AAEzD;AAEO,SAAS,aACd,WACA,SACqB;AACrB,QAAM,UAAU,UAAU,KAAK,QAAQ,GAAG;AAC1C,SAAO,WAAW,OAAO;AAC3B;;;"}
1
+ {"version":3,"file":"useStorage.js","sources":["../../../../src/useStorage.ts"],"sourcesContent":["import { useState, useEffect } from \"react\";\nimport { type BindValue, type BindValueNS } from \"./bindValue.js\";\n\nexport interface UseStorageReturn<T> {\n value: T;\n setValue: (value: T) => void;\n getRaw: () => string | null;\n setRaw: (rawValue: string) => void;\n reset: () => void;\n}\n\nexport function useStorage<T>(binding: BindValue<T>): UseStorageReturn<T> {\n const [value, setValue] = useState(binding.getValue());\n\n useEffect(() => {\n const unsubscribe = binding.subscribe(setValue);\n return unsubscribe;\n }, [binding]);\n\n const set = (newValue: T) => {\n binding.set(newValue);\n };\n\n return {\n value,\n setValue: set,\n getRaw: () => binding.getRaw(),\n setRaw: (rawValue: string) => binding.setRaw(rawValue),\n reset: () => binding.reset(),\n };\n}\n\nexport function useStorageNS<T>(\n namespace: BindValueNS<T>,\n options: { key: string },\n): UseStorageReturn<T> {\n const binding = namespace.bind(options.key);\n return useStorage(binding);\n}\n"],"names":["useState","useEffect"],"mappings":";;;AAWO,SAAS,WAAc,SAA4C;AACxE,QAAM,CAAC,OAAO,QAAQ,IAAIA,MAAAA,SAAS,QAAQ,UAAU;AAErDC,QAAAA,UAAU,MAAM;AACd,UAAM,cAAc,QAAQ,UAAU,QAAQ;AAC9C,WAAO;AAAA,EACT,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,MAAM,CAAC,aAAgB;AAC3B,YAAQ,IAAI,QAAQ;AAAA,EACtB;AAEA,SAAO;AAAA,IACL;AAAA,IACA,UAAU;AAAA,IACV,QAAQ,MAAM,QAAQ,OAAA;AAAA,IACtB,QAAQ,CAAC,aAAqB,QAAQ,OAAO,QAAQ;AAAA,IACrD,OAAO,MAAM,QAAQ,MAAA;AAAA,EAAM;AAE/B;AAEO,SAAS,aACd,WACA,SACqB;AACrB,QAAM,UAAU,UAAU,KAAK,QAAQ,GAAG;AAC1C,SAAO,WAAW,OAAO;AAC3B;;;"}
@@ -25,6 +25,7 @@ export declare class BindValue<T> {
25
25
  getValue(): T;
26
26
  set(newValue: T): void;
27
27
  subscribe(callback: (value: T) => void): () => void;
28
+ reset(): void;
28
29
  getRaw(): string | null;
29
30
  setRaw(rawValue: string): void;
30
31
  private loadFromStorage;
@@ -47,6 +47,11 @@ class BindValue {
47
47
  this.subscribers.delete(callback);
48
48
  };
49
49
  }
50
+ reset() {
51
+ this.storage.removeItem(this.options.key);
52
+ this.value = this.options.defaultValue;
53
+ this.notifySubscribers();
54
+ }
50
55
  getRaw() {
51
56
  return this.storage.getItem(this.options.key);
52
57
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bindValue.mjs","sources":["../../../../src/bindValue.ts"],"sourcesContent":["export interface BindValueOptions<T> {\n key: string;\n defaultValue: T;\n serialize: (value: T) => string;\n deserialize: (serialized: string) => T;\n storage?: Storage;\n version?: string;\n migrate?: (oldSerialized: string, oldVersion: string | undefined) => T;\n}\n\nexport interface BindValueNSOptions<T> {\n prefix: string;\n defaultValue: T;\n serialize: (value: T) => string;\n deserialize: (serialized: string) => T;\n storage?: Storage;\n version?: string;\n migrate?: (oldSerialized: string, oldVersion: string | undefined) => T;\n}\n\nconst memoryStorage = new Map<string, string>();\n\nconst inMemoryStorage: Storage = {\n get length() {\n return memoryStorage.size;\n },\n clear() {\n memoryStorage.clear();\n },\n getItem(key: string) {\n return memoryStorage.get(key) ?? null;\n },\n key(index: number) {\n const keys = Array.from(memoryStorage.keys());\n return keys[index] ?? null;\n },\n removeItem(key: string) {\n memoryStorage.delete(key);\n },\n setItem(key: string, value: string) {\n memoryStorage.set(key, value);\n },\n};\n\nexport class BindValue<T> {\n private value: T;\n private subscribers: Set<(value: T) => void>;\n private storage: Storage;\n\n constructor(private options: BindValueOptions<T>) {\n this.storage = options.storage ?? inMemoryStorage;\n this.subscribers = new Set();\n this.value = this.loadFromStorage();\n }\n\n getValue(): T {\n return this.value;\n }\n\n set(newValue: T): void {\n this.value = newValue;\n this.saveToStorage(newValue);\n this.notifySubscribers();\n }\n\n subscribe(callback: (value: T) => void): () => void {\n this.subscribers.add(callback);\n return () => {\n this.subscribers.delete(callback);\n };\n }\n\n getRaw(): string | null {\n return this.storage.getItem(this.options.key);\n }\n\n setRaw(rawValue: string): void {\n let deserializedValue: T;\n const version = this.options.version;\n let serializedPart: string;\n\n if (version) {\n if (!rawValue.startsWith(\"\\x00\")) {\n return;\n }\n\n const parts = rawValue.split(\"\\x00\");\n if (parts.length < 3) {\n return;\n }\n\n const versionPart = parts[1];\n if (versionPart !== version) {\n return;\n }\n\n serializedPart = parts.slice(2).join(\"\\x00\");\n } else {\n serializedPart = rawValue;\n }\n\n try {\n deserializedValue = this.options.deserialize(serializedPart);\n } catch {\n return;\n }\n const serializedValue = this.options.serialize(deserializedValue);\n let reconstructedRaw: string;\n\n if (version) {\n reconstructedRaw = `\\x00${version}\\x00${serializedValue}`;\n } else {\n reconstructedRaw = serializedValue;\n }\n\n if (reconstructedRaw !== rawValue) {\n return;\n }\n\n this.storage.setItem(this.options.key, rawValue);\n this.value = deserializedValue;\n this.notifySubscribers();\n }\n\n private loadFromStorage(): T {\n const rawValue = this.storage.getItem(this.options.key);\n\n if (rawValue === null) {\n return this.options.defaultValue;\n }\n\n let oldVersion: string | undefined;\n let serializedValue: string;\n\n if (rawValue.startsWith(\"\\x00\")) {\n const parts = rawValue.split(\"\\x00\");\n if (parts.length >= 3) {\n oldVersion = parts[1];\n serializedValue = parts.slice(2).join(\"\\x00\");\n } else {\n serializedValue = rawValue;\n }\n } else {\n serializedValue = rawValue;\n }\n\n const currentVersion = this.options.version;\n\n if (oldVersion !== currentVersion) {\n if (this.options.migrate) {\n try {\n const migratedValue = this.options.migrate(\n serializedValue,\n oldVersion,\n );\n this.saveToStorage(migratedValue);\n return migratedValue;\n } catch {\n this.storage.removeItem(this.options.key);\n return this.options.defaultValue;\n }\n } else {\n this.storage.removeItem(this.options.key);\n return this.options.defaultValue;\n }\n }\n\n try {\n return this.options.deserialize(serializedValue);\n } catch {\n return this.options.defaultValue;\n }\n }\n\n private saveToStorage(value: T): void {\n try {\n const serialized = this.options.serialize(value);\n const version = this.options.version;\n\n if (version) {\n this.storage.setItem(\n this.options.key,\n `\\x00${version}\\x00${serialized}`,\n );\n } else {\n this.storage.setItem(this.options.key, serialized);\n }\n } catch {}\n }\n\n private notifySubscribers(): void {\n for (const subscriber of this.subscribers) {\n subscriber(this.value);\n }\n }\n}\n\nexport function bindValue<T>(options: BindValueOptions<T>): BindValue<T> {\n return new BindValue(options);\n}\n\nexport function _clearInMemoryStorage(): void {\n memoryStorage.clear();\n}\n\nexport class BindValueNS<T> {\n constructor(private options: BindValueNSOptions<T>) {\n if (!this.options.prefix || this.options.prefix.trim() === \"\") {\n throw new Error(\"Prefix cannot be empty\");\n }\n }\n\n bind(key: string): BindValue<T> {\n if (!key || key.trim() === \"\") {\n throw new Error(\"Key cannot be empty\");\n }\n\n return new BindValue<T>({\n key: `${this.options.prefix}\\x1F${key}`,\n defaultValue: this.options.defaultValue,\n serialize: this.options.serialize,\n deserialize: this.options.deserialize,\n storage: this.options.storage,\n version: this.options.version,\n migrate: this.options.migrate,\n });\n }\n}\n\nexport function bindValueNS<T>(options: BindValueNSOptions<T>): BindValueNS<T> {\n return new BindValueNS(options);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bindValue.mjs","sources":["../../../../src/bindValue.ts"],"sourcesContent":["export interface BindValueOptions<T> {\n key: string;\n defaultValue: T;\n serialize: (value: T) => string;\n deserialize: (serialized: string) => T;\n storage?: Storage;\n version?: string;\n migrate?: (oldSerialized: string, oldVersion: string | undefined) => T;\n}\n\nexport interface BindValueNSOptions<T> {\n prefix: string;\n defaultValue: T;\n serialize: (value: T) => string;\n deserialize: (serialized: string) => T;\n storage?: Storage;\n version?: string;\n migrate?: (oldSerialized: string, oldVersion: string | undefined) => T;\n}\n\nconst memoryStorage = new Map<string, string>();\n\nconst inMemoryStorage: Storage = {\n get length() {\n return memoryStorage.size;\n },\n clear() {\n memoryStorage.clear();\n },\n getItem(key: string) {\n return memoryStorage.get(key) ?? null;\n },\n key(index: number) {\n const keys = Array.from(memoryStorage.keys());\n return keys[index] ?? null;\n },\n removeItem(key: string) {\n memoryStorage.delete(key);\n },\n setItem(key: string, value: string) {\n memoryStorage.set(key, value);\n },\n};\n\nexport class BindValue<T> {\n private value: T;\n private subscribers: Set<(value: T) => void>;\n private storage: Storage;\n\n constructor(private options: BindValueOptions<T>) {\n this.storage = options.storage ?? inMemoryStorage;\n this.subscribers = new Set();\n this.value = this.loadFromStorage();\n }\n\n getValue(): T {\n return this.value;\n }\n\n set(newValue: T): void {\n this.value = newValue;\n this.saveToStorage(newValue);\n this.notifySubscribers();\n }\n\n subscribe(callback: (value: T) => void): () => void {\n this.subscribers.add(callback);\n return () => {\n this.subscribers.delete(callback);\n };\n }\n\n reset(): void {\n this.storage.removeItem(this.options.key);\n this.value = this.options.defaultValue;\n this.notifySubscribers();\n }\n\n getRaw(): string | null {\n return this.storage.getItem(this.options.key);\n }\n\n setRaw(rawValue: string): void {\n let deserializedValue: T;\n const version = this.options.version;\n let serializedPart: string;\n\n if (version) {\n if (!rawValue.startsWith(\"\\x00\")) {\n return;\n }\n\n const parts = rawValue.split(\"\\x00\");\n if (parts.length < 3) {\n return;\n }\n\n const versionPart = parts[1];\n if (versionPart !== version) {\n return;\n }\n\n serializedPart = parts.slice(2).join(\"\\x00\");\n } else {\n serializedPart = rawValue;\n }\n\n try {\n deserializedValue = this.options.deserialize(serializedPart);\n } catch {\n return;\n }\n const serializedValue = this.options.serialize(deserializedValue);\n let reconstructedRaw: string;\n\n if (version) {\n reconstructedRaw = `\\x00${version}\\x00${serializedValue}`;\n } else {\n reconstructedRaw = serializedValue;\n }\n\n if (reconstructedRaw !== rawValue) {\n return;\n }\n\n this.storage.setItem(this.options.key, rawValue);\n this.value = deserializedValue;\n this.notifySubscribers();\n }\n\n private loadFromStorage(): T {\n const rawValue = this.storage.getItem(this.options.key);\n\n if (rawValue === null) {\n return this.options.defaultValue;\n }\n\n let oldVersion: string | undefined;\n let serializedValue: string;\n\n if (rawValue.startsWith(\"\\x00\")) {\n const parts = rawValue.split(\"\\x00\");\n if (parts.length >= 3) {\n oldVersion = parts[1];\n serializedValue = parts.slice(2).join(\"\\x00\");\n } else {\n serializedValue = rawValue;\n }\n } else {\n serializedValue = rawValue;\n }\n\n const currentVersion = this.options.version;\n\n if (oldVersion !== currentVersion) {\n if (this.options.migrate) {\n try {\n const migratedValue = this.options.migrate(\n serializedValue,\n oldVersion,\n );\n this.saveToStorage(migratedValue);\n return migratedValue;\n } catch {\n this.storage.removeItem(this.options.key);\n return this.options.defaultValue;\n }\n } else {\n this.storage.removeItem(this.options.key);\n return this.options.defaultValue;\n }\n }\n\n try {\n return this.options.deserialize(serializedValue);\n } catch {\n return this.options.defaultValue;\n }\n }\n\n private saveToStorage(value: T): void {\n try {\n const serialized = this.options.serialize(value);\n const version = this.options.version;\n\n if (version) {\n this.storage.setItem(\n this.options.key,\n `\\x00${version}\\x00${serialized}`,\n );\n } else {\n this.storage.setItem(this.options.key, serialized);\n }\n } catch {}\n }\n\n private notifySubscribers(): void {\n for (const subscriber of this.subscribers) {\n subscriber(this.value);\n }\n }\n}\n\nexport function bindValue<T>(options: BindValueOptions<T>): BindValue<T> {\n return new BindValue(options);\n}\n\nexport function _clearInMemoryStorage(): void {\n memoryStorage.clear();\n}\n\nexport class BindValueNS<T> {\n constructor(private options: BindValueNSOptions<T>) {\n if (!this.options.prefix || this.options.prefix.trim() === \"\") {\n throw new Error(\"Prefix cannot be empty\");\n }\n }\n\n bind(key: string): BindValue<T> {\n if (!key || key.trim() === \"\") {\n throw new Error(\"Key cannot be empty\");\n }\n\n return new BindValue<T>({\n key: `${this.options.prefix}\\x1F${key}`,\n defaultValue: this.options.defaultValue,\n serialize: this.options.serialize,\n deserialize: this.options.deserialize,\n storage: this.options.storage,\n version: this.options.version,\n migrate: this.options.migrate,\n });\n }\n}\n\nexport function bindValueNS<T>(options: BindValueNSOptions<T>): BindValueNS<T> {\n return new BindValueNS(options);\n}\n"],"names":[],"mappings":"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"}
@@ -4,6 +4,7 @@ export interface UseStorageReturn<T> {
4
4
  setValue: (value: T) => void;
5
5
  getRaw: () => string | null;
6
6
  setRaw: (rawValue: string) => void;
7
+ reset: () => void;
7
8
  }
8
9
  export declare function useStorage<T>(binding: BindValue<T>): UseStorageReturn<T>;
9
10
  export declare function useStorageNS<T>(namespace: BindValueNS<T>, options: {
@@ -12,7 +12,8 @@ function useStorage(binding) {
12
12
  value,
13
13
  setValue: set,
14
14
  getRaw: () => binding.getRaw(),
15
- setRaw: (rawValue) => binding.setRaw(rawValue)
15
+ setRaw: (rawValue) => binding.setRaw(rawValue),
16
+ reset: () => binding.reset()
16
17
  };
17
18
  }
18
19
  function useStorageNS(namespace, options) {
@@ -1 +1 @@
1
- {"version":3,"file":"useStorage.mjs","sources":["../../../../src/useStorage.ts"],"sourcesContent":["import { useState, useEffect } from \"react\";\nimport { type BindValue, type BindValueNS } from \"./bindValue.js\";\n\nexport interface UseStorageReturn<T> {\n value: T;\n setValue: (value: T) => void;\n getRaw: () => string | null;\n setRaw: (rawValue: string) => void;\n}\n\nexport function useStorage<T>(binding: BindValue<T>): UseStorageReturn<T> {\n const [value, setValue] = useState(binding.getValue());\n\n useEffect(() => {\n const unsubscribe = binding.subscribe(setValue);\n return unsubscribe;\n }, [binding]);\n\n const set = (newValue: T) => {\n binding.set(newValue);\n };\n\n return {\n value,\n setValue: set,\n getRaw: () => binding.getRaw(),\n setRaw: (rawValue: string) => binding.setRaw(rawValue),\n };\n}\n\nexport function useStorageNS<T>(\n namespace: BindValueNS<T>,\n options: { key: string },\n): UseStorageReturn<T> {\n const binding = namespace.bind(options.key);\n return useStorage(binding);\n}\n"],"names":[],"mappings":";AAUO,SAAS,WAAc,SAA4C;AACxE,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,QAAQ,UAAU;AAErD,YAAU,MAAM;AACd,UAAM,cAAc,QAAQ,UAAU,QAAQ;AAC9C,WAAO;AAAA,EACT,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,MAAM,CAAC,aAAgB;AAC3B,YAAQ,IAAI,QAAQ;AAAA,EACtB;AAEA,SAAO;AAAA,IACL;AAAA,IACA,UAAU;AAAA,IACV,QAAQ,MAAM,QAAQ,OAAA;AAAA,IACtB,QAAQ,CAAC,aAAqB,QAAQ,OAAO,QAAQ;AAAA,EAAA;AAEzD;AAEO,SAAS,aACd,WACA,SACqB;AACrB,QAAM,UAAU,UAAU,KAAK,QAAQ,GAAG;AAC1C,SAAO,WAAW,OAAO;AAC3B;"}
1
+ {"version":3,"file":"useStorage.mjs","sources":["../../../../src/useStorage.ts"],"sourcesContent":["import { useState, useEffect } from \"react\";\nimport { type BindValue, type BindValueNS } from \"./bindValue.js\";\n\nexport interface UseStorageReturn<T> {\n value: T;\n setValue: (value: T) => void;\n getRaw: () => string | null;\n setRaw: (rawValue: string) => void;\n reset: () => void;\n}\n\nexport function useStorage<T>(binding: BindValue<T>): UseStorageReturn<T> {\n const [value, setValue] = useState(binding.getValue());\n\n useEffect(() => {\n const unsubscribe = binding.subscribe(setValue);\n return unsubscribe;\n }, [binding]);\n\n const set = (newValue: T) => {\n binding.set(newValue);\n };\n\n return {\n value,\n setValue: set,\n getRaw: () => binding.getRaw(),\n setRaw: (rawValue: string) => binding.setRaw(rawValue),\n reset: () => binding.reset(),\n };\n}\n\nexport function useStorageNS<T>(\n namespace: BindValueNS<T>,\n options: { key: string },\n): UseStorageReturn<T> {\n const binding = namespace.bind(options.key);\n return useStorage(binding);\n}\n"],"names":[],"mappings":";AAWO,SAAS,WAAc,SAA4C;AACxE,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,QAAQ,UAAU;AAErD,YAAU,MAAM;AACd,UAAM,cAAc,QAAQ,UAAU,QAAQ;AAC9C,WAAO;AAAA,EACT,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,MAAM,CAAC,aAAgB;AAC3B,YAAQ,IAAI,QAAQ;AAAA,EACtB;AAEA,SAAO;AAAA,IACL;AAAA,IACA,UAAU;AAAA,IACV,QAAQ,MAAM,QAAQ,OAAA;AAAA,IACtB,QAAQ,CAAC,aAAqB,QAAQ,OAAO,QAAQ;AAAA,IACrD,OAAO,MAAM,QAAQ,MAAA;AAAA,EAAM;AAE/B;AAEO,SAAS,aACd,WACA,SACqB;AACrB,QAAM,UAAU,UAAU,KAAK,QAAQ,GAAG;AAC1C,SAAO,WAAW,OAAO;AAC3B;"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kvozy",
3
3
  "type": "commonjs",
4
- "version": "0.8.0",
4
+ "version": "0.9.0",
5
5
  "types": "./__compiled__/cjs/src/index.d.ts",
6
6
  "module": "./__compiled__/esm/src/index.mjs",
7
7
  "main": "./__compiled__/cjs/src/index.js",