tiny-essentials 1.19.1 → 1.19.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/v1/TinyEssentials.js +69 -9
- package/dist/v1/TinyEssentials.min.js +1 -1
- package/dist/v1/TinyLocalStorage.js +70 -10
- package/dist/v1/TinyLocalStorage.min.js +1 -1
- package/dist/v1/TinyUploadClicker.js +69 -9
- package/dist/v1/TinyUploadClicker.min.js +1 -1
- package/dist/v1/libs/TinyLocalStorage.cjs +69 -9
- package/dist/v1/libs/TinyLocalStorage.d.mts +20 -7
- package/dist/v1/libs/TinyLocalStorage.mjs +69 -15
- package/docs/v1/libs/TinyLocalStorage.md +23 -4
- package/package.json +1 -1
|
@@ -445,6 +445,22 @@ const customEncoders = new Map();
|
|
|
445
445
|
/** @type {Map<any, DecodeFn>} */
|
|
446
446
|
const customDecoders = new Map();
|
|
447
447
|
|
|
448
|
+
/** @type {Set<any>} */
|
|
449
|
+
const customTypesFreezed = new Set([
|
|
450
|
+
'string',
|
|
451
|
+
'boolean',
|
|
452
|
+
'number',
|
|
453
|
+
'object',
|
|
454
|
+
'array',
|
|
455
|
+
String,
|
|
456
|
+
Boolean,
|
|
457
|
+
Number,
|
|
458
|
+
Object,
|
|
459
|
+
Array,
|
|
460
|
+
BigInt,
|
|
461
|
+
Symbol,
|
|
462
|
+
]);
|
|
463
|
+
|
|
448
464
|
/**
|
|
449
465
|
* A function that encodes a value into a serializable JSON-compatible format.
|
|
450
466
|
*
|
|
@@ -717,25 +733,48 @@ class TinyLocalStorage {
|
|
|
717
733
|
///////////////////////////////////////////////////
|
|
718
734
|
|
|
719
735
|
/**
|
|
720
|
-
*
|
|
736
|
+
* Checks whether a JSON-serializable type is already registered.
|
|
721
737
|
*
|
|
722
|
-
* @param {any} type - The type
|
|
723
|
-
*
|
|
724
|
-
* @
|
|
738
|
+
* @param {any} type - The type identifier, which can be a string (e.g., `"bigint"`, `"symbol"`)
|
|
739
|
+
* or a reference to a class/constructor function.
|
|
740
|
+
* @returns {boolean} True if the type has both an encoder and decoder registered.
|
|
725
741
|
*/
|
|
726
|
-
static
|
|
742
|
+
static hasJsonType(type) {
|
|
743
|
+
return (customEncoders.has(type) && customDecoders.has(type)) || customTypesFreezed.has(type);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* Registers a new JSON-serializable type with its encoder and decoder.
|
|
748
|
+
*
|
|
749
|
+
* @param {any} type - The type identifier, which can be a string (e.g., `"bigint"`, `"symbol"`)
|
|
750
|
+
* or a reference to a class/constructor function.
|
|
751
|
+
* @param {EncodeFn} encodeFn - A function that receives a value of this type and returns a JSON-safe representation.
|
|
752
|
+
* @param {DecodeFn} decodeFn - An object with `check(value)` to identify this type and `decode(value)` to restore it.
|
|
753
|
+
* @param {boolean} [freezeType=false] - If true, prevents this type from being unregistered later.
|
|
754
|
+
* @throws {Error} Throws an error if the type is frozen and cannot be registered.
|
|
755
|
+
*/
|
|
756
|
+
static registerJsonType(type, encodeFn, decodeFn, freezeType = false) {
|
|
757
|
+
if (customTypesFreezed.has(type))
|
|
758
|
+
throw new Error(`Cannot register type "${type}" because it is frozen.`);
|
|
727
759
|
customEncoders.set(type, encodeFn);
|
|
728
760
|
customDecoders.set(type, decodeFn);
|
|
761
|
+
if (freezeType) customTypesFreezed.add(type);
|
|
729
762
|
}
|
|
730
763
|
|
|
731
764
|
/**
|
|
732
|
-
*
|
|
765
|
+
* Unregisters a previously registered custom type from the encoding/decoding system.
|
|
733
766
|
*
|
|
734
|
-
* @param {
|
|
767
|
+
* @param {any} type - The primitive name or constructor reference used in the registration.
|
|
768
|
+
* @returns {boolean} Returns true if the type existed and was removed, or false if it wasn't found.
|
|
769
|
+
* @throws {Error} Throws an error if the type is frozen and cannot be unregistered.
|
|
735
770
|
*/
|
|
736
771
|
static deleteJsonType(type) {
|
|
737
|
-
|
|
738
|
-
|
|
772
|
+
if (customTypesFreezed.has(type))
|
|
773
|
+
throw new Error(`Cannot remove type "${type}" because it is frozen.`);
|
|
774
|
+
let isDeleted = false;
|
|
775
|
+
if (customEncoders.delete(type)) isDeleted = true;
|
|
776
|
+
if (customDecoders.delete(type)) isDeleted = true;
|
|
777
|
+
return isDeleted;
|
|
739
778
|
}
|
|
740
779
|
|
|
741
780
|
//////////////////////////////////////////////////////
|
|
@@ -1080,7 +1119,13 @@ class TinyLocalStorage {
|
|
|
1080
1119
|
if (typeof data !== 'string') throw new Error('Value must be a string.');
|
|
1081
1120
|
|
|
1082
1121
|
this.emit('setString', name, data);
|
|
1083
|
-
return this.#localStorage.setItem(
|
|
1122
|
+
return this.#localStorage.setItem(
|
|
1123
|
+
name,
|
|
1124
|
+
JSON.stringify({
|
|
1125
|
+
__string__: true,
|
|
1126
|
+
value: data,
|
|
1127
|
+
}),
|
|
1128
|
+
);
|
|
1084
1129
|
}
|
|
1085
1130
|
|
|
1086
1131
|
/**
|
|
@@ -1093,6 +1138,15 @@ class TinyLocalStorage {
|
|
|
1093
1138
|
if (typeof name !== 'string' || !name.length)
|
|
1094
1139
|
throw new Error('Key must be a non-empty string.');
|
|
1095
1140
|
let value = this.#localStorage.getItem(name);
|
|
1141
|
+
try {
|
|
1142
|
+
/** @type {{ value: string; __string__: boolean }} */
|
|
1143
|
+
// @ts-ignore
|
|
1144
|
+
value = JSON.parse(value);
|
|
1145
|
+
if (!isJsonObject(value) || !value.__string__ || typeof value.value !== 'string') return null;
|
|
1146
|
+
value = value.value;
|
|
1147
|
+
} catch {
|
|
1148
|
+
value = null;
|
|
1149
|
+
}
|
|
1096
1150
|
if (typeof value === 'string') return value;
|
|
1097
1151
|
return null;
|
|
1098
1152
|
}
|
|
@@ -1209,6 +1263,7 @@ TinyLocalStorage.registerJsonType(
|
|
|
1209
1263
|
decode: (value, decodeSpecialJson) =>
|
|
1210
1264
|
new Map(value.data.map(([k, v]) => [k, decodeSpecialJson(v)])),
|
|
1211
1265
|
},
|
|
1266
|
+
true,
|
|
1212
1267
|
);
|
|
1213
1268
|
|
|
1214
1269
|
// Set
|
|
@@ -1222,6 +1277,7 @@ TinyLocalStorage.registerJsonType(
|
|
|
1222
1277
|
check: (value) => value.__set__,
|
|
1223
1278
|
decode: (value, decodeSpecialJson) => new Set(value.data.map(decodeSpecialJson)),
|
|
1224
1279
|
},
|
|
1280
|
+
true,
|
|
1225
1281
|
);
|
|
1226
1282
|
|
|
1227
1283
|
// Date
|
|
@@ -1235,6 +1291,7 @@ TinyLocalStorage.registerJsonType(
|
|
|
1235
1291
|
check: (value) => value.__date__,
|
|
1236
1292
|
decode: (value) => new Date(value.value),
|
|
1237
1293
|
},
|
|
1294
|
+
true,
|
|
1238
1295
|
);
|
|
1239
1296
|
|
|
1240
1297
|
// Regex
|
|
@@ -1249,6 +1306,7 @@ TinyLocalStorage.registerJsonType(
|
|
|
1249
1306
|
check: (value) => value.__regexp__,
|
|
1250
1307
|
decode: (value) => new RegExp(value.source, value.flags),
|
|
1251
1308
|
},
|
|
1309
|
+
true,
|
|
1252
1310
|
);
|
|
1253
1311
|
|
|
1254
1312
|
// Big Int
|
|
@@ -1262,6 +1320,7 @@ TinyLocalStorage.registerJsonType(
|
|
|
1262
1320
|
check: (value) => value.__bigint__,
|
|
1263
1321
|
decode: (value) => BigInt(value.value),
|
|
1264
1322
|
},
|
|
1323
|
+
true,
|
|
1265
1324
|
);
|
|
1266
1325
|
|
|
1267
1326
|
// Symbol
|
|
@@ -1278,6 +1337,7 @@ TinyLocalStorage.registerJsonType(
|
|
|
1278
1337
|
return key != null ? Symbol.for(key) : Symbol();
|
|
1279
1338
|
},
|
|
1280
1339
|
},
|
|
1340
|
+
true,
|
|
1281
1341
|
);
|
|
1282
1342
|
|
|
1283
1343
|
/* harmony default export */ const libs_TinyLocalStorage = (TinyLocalStorage);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";var e={d:(t,r)=>{for(var n in r)e.o(r,n)&&!e.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:r[n]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)},t={};function r(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)&&"[object Object]"===Object.prototype.toString.call(e)}e.d(t,{TinyLocalStorage:()=>a});const n=class{#e=new Map;#t=10;#r=!1;setThrowOnMaxListeners(e){if("boolean"!=typeof e)throw new TypeError("setThrowOnMaxListeners(value): value must be a boolean");this.#r=e}getThrowOnMaxListeners(){return this.#r}#n(e,t,{once:r=!1}={}){let n=this.#e.get(e);Array.isArray(n)||(n=[],this.#e.set(e,n)),n.unshift({handler:t,config:{once:r}});const s=this.#t;if(s>0&&n.length>s){const t=`Possible memory leak detected. ${n.length} "${e}" listeners added. Use setMaxListeners() to increase limit.`;if(this.#r)throw new Error(t);console.warn(t)}}prependListener(e,t){if("string"!=typeof e)throw new TypeError("prepend(event, handler): event name must be a string");if("function"!=typeof t)throw new TypeError("prepend(event, handler): handler must be a function");this.#n(e,t)}prependListenerOnce(e,t){if("string"!=typeof e)throw new TypeError("prependOnceListener(event, handler): event name must be a string");if("function"!=typeof t)throw new TypeError("prependOnceListener(event, handler): handler must be a function");const r=(...n)=>{this.off(e,r),t(...n)};return this.#n(e,r,{once:!0}),r}#s(e,t,{once:r=!1}={}){let n=this.#e.get(e);Array.isArray(n)||(n=[],this.#e.set(e,n)),n.push({handler:t,config:{once:r}});const s=this.#t;if(s>0&&n.length>s){const t=`Possible memory leak detected. ${n.length} "${e}" listeners added. Use setMaxListeners() to increase limit.`;if(this.#r)throw new Error(t);console.warn(t)}}on(e,t){if("string"!=typeof e)throw new TypeError("on(event, handler): event name must be a string");if("function"!=typeof t)throw new TypeError("on(event, handler): handler must be a function");return this.#s(e,t)}once(e,t){if("string"!=typeof e)throw new TypeError("The event name must be a string.");if("function"!=typeof t)throw new TypeError("once(event, handler): handler must be a function");const r=n=>{this.off(e,r),"function"==typeof t&&t(n)};return this.#s(e,r,{once:!0}),r}appendListener(e,t){return this.on(e,t)}appendListenerOnce(e,t){return this.once(e,t)}off(e,t){if("string"!=typeof e)throw new TypeError("off(event, handler): event name must be a string");if("function"!=typeof t)throw new TypeError("off(event, handler): handler must be a function");const r=this.#e.get(e);if(!Array.isArray(r))return;const n=r.findIndex(e=>e.handler===t);-1!==n&&r.splice(n,1),0===r.length&&this.#e.delete(e)}offAll(e){if("string"!=typeof e)throw new TypeError("The event name must be a string.");this.#e.delete(e)}offAllTypes(){this.#e.clear()}listenerCount(e){if("string"!=typeof e)throw new TypeError("listenerCount(event): event name must be a string");const t=this.#e.get(e);return Array.isArray(t)?t.length:0}listeners(e){if("string"!=typeof e)throw new TypeError("listeners(event): event name must be a string");const t=this.#e.get(e);return Array.isArray(t)?[...t].filter(e=>!e.config.once).map(e=>e.handler):[]}onceListeners(e){if("string"!=typeof e)throw new TypeError("onceListeners(event): event name must be a string");const t=this.#e.get(e);return Array.isArray(t)?[...t].filter(e=>e.config.once).map(e=>e.handler):[]}allListeners(e){if("string"!=typeof e)throw new TypeError("allListeners(event): event name must be a string");const t=this.#e.get(e);return Array.isArray(t)?[...t].map(e=>e.handler):[]}eventNames(){return[...this.#e.keys()]}emit(e,...t){if("string"!=typeof e)throw new TypeError("emit(event, data): event name must be a string");const r=this.#e.get(e);return!(!Array.isArray(r)||0===r.length||(r.forEach(e=>e.handler(...t)),0))}setMaxListeners(e){if(!Number.isInteger(e)||e<0)throw new TypeError("setMaxListeners(n): n must be a non-negative integer");this.#t=e}getMaxListeners(){return this.#t}},s=new Map,o=new Map;class i{#o=new n;setThrowOnMaxListeners(e){return this.#o.setThrowOnMaxListeners(e)}getThrowOnMaxListeners(){return this.#o.getThrowOnMaxListeners()}prependListener(e,t){return this.#o.prependListener(e,t)}prependListenerOnce(e,t){return this.#o.prependListenerOnce(e,t)}appendListener(e,t){return this.#o.appendListener(e,t)}appendListenerOnce(e,t){return this.#o.appendListenerOnce(e,t)}on(e,t){return this.#o.on(e,t)}once(e,t){return this.#o.once(e,t)}off(e,t){return this.#o.off(e,t)}offAll(e){return this.#o.offAll(e)}offAllTypes(){return this.#o.offAllTypes()}listenerCount(e){return this.#o.listenerCount(e)}listeners(e){return this.#o.listeners(e)}onceListeners(e){return this.#o.onceListeners(e)}allListeners(e){return this.#o.allListeners(e)}eventNames(){return this.#o.eventNames()}emit(e,...t){return this.#o.emit(e,...t)}setMaxListeners(e){return this.#o.setMaxListeners(e)}getMaxListeners(){return this.#o.getMaxListeners()}static registerJsonType(e,t,r){s.set(e,t),o.set(e,r)}static deleteJsonType(e){s.delete(e),o.delete(e)}static encodeSpecialJson(e){if(void 0===e)return{__undefined__:!0};if(null===e)return{__null__:!0};for(const[t,r]of s.entries())if("string"!=typeof t&&e instanceof t||typeof e===t)return r(e,i.encodeSpecialJson);if(Array.isArray(e))return e.map(i.encodeSpecialJson);if(r(e)){const t={};for(const r in e)t[r]=i.encodeSpecialJson(e[r]);return t}return e}static decodeSpecialJson(e){const t=r(e);if(t){if(e.__undefined__)return;if(e.__null__)return null}if(Array.isArray(e))return e.map(i.decodeSpecialJson);if(t){for(const[t,r]of o.entries())if(r.check&&r.check(e))return r.decode(e,i.decodeSpecialJson);const t={};for(const r in e)t[r]=i.decodeSpecialJson(e[r]);return t}return e}#i=window.localStorage;#a=e=>this.emit("storage",e);constructor(){window.addEventListener("storage",this.#a)}setLocalStorage(e){if(!(e instanceof Storage))throw new Error("Argument must be a valid instance of Storage.");this.#i=e}localStorageExists(){return this.#i instanceof Storage}#l(e,t){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");return i.encodeSpecialJson(t)}setJson(e,t){if(!(r(t)||Array.isArray(t)||t instanceof Map||t instanceof Set))throw new Error("The storage value is not a valid JSON-compatible structure.");const n=this.#l(e,t);return this.emit("setJson",e,t),this.#i.setItem(e,JSON.stringify(n))}#c(e,t){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");const r=this.#i.getItem(e),n={obj:()=>({}),array:()=>[],map:()=>new Map,set:()=>new Set},s="function"==typeof n[t]?n[t]():null;let o;try{o=JSON.parse(r)}catch{return s}return{decoded:i.decodeSpecialJson(o),fallback:s}}getJson(e,t){const{decoded:n,fallback:s}=this.#c(e,t);return n instanceof Map||n instanceof Set||Array.isArray(n)||r(n)?n:s}setDate(e,t){if(!(t instanceof Date))throw new Error("Value must be a Date.");const r=this.#l(e,t);return this.emit("setDate",e,t),this.#i.setItem(e,JSON.stringify(r))}getDate(e){const t=this.#c(e).decoded;return t instanceof Date?t:null}setRegExp(e,t){if(!(t instanceof RegExp))throw new Error("Value must be a RegExp.");const r=this.#l(e,t);return this.emit("setRegExp",e,t),this.#i.setItem(e,JSON.stringify(r))}getRegExp(e){const t=this.#c(e).decoded;return t instanceof RegExp?t:null}setBigInt(e,t){if("bigint"!=typeof t)throw new Error("Value must be a BigInt.");const r=this.#l(e,t);return this.emit("setBigInt",e,t),this.#i.setItem(e,JSON.stringify(r))}getBigInt(e){const t=this.#c(e).decoded;return"bigint"==typeof t?t:null}setSymbol(e,t){if("symbol"!=typeof t)throw new Error("Value must be a Symbol.");const r=this.#l(e,t);return this.emit("setSymbol",e,t),this.#i.setItem(e,JSON.stringify(r))}getSymbol(e){const t=this.#c(e).decoded;return"symbol"==typeof t?t:null}getValue(e){return this.#c(e).decoded??null}setItem(e,t){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");return this.emit("setItem",e,t),this.#i.setItem(e,t)}getItem(e){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");return this.#i.getItem(e)}setString(e,t){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");if("string"!=typeof t)throw new Error("Value must be a string.");return this.emit("setString",e,t),this.#i.setItem(e,t)}getString(e){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");let t=this.#i.getItem(e);return"string"==typeof t?t:null}setNumber(e,t){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");if("number"!=typeof t)throw new Error("Value must be a number.");return this.emit("setNumber",e,t),this.#i.setItem(e,String(t))}getNumber(e){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");let t=this.#i.getItem(e);return"number"==typeof t||"string"==typeof t&&t.length>0&&(t=parseFloat(t),!Number.isNaN(t))?t:null}setBool(e,t){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");if("boolean"!=typeof t)throw new Error("Value must be a boolean.");return this.emit("setBool",e,t),this.#i.setItem(e,String(t))}getBool(e){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");const t=this.#i.getItem(e);if("boolean"==typeof t)return t;if("string"==typeof t){if("true"===t)return!0;if("false"===t)return!1}return null}removeItem(e){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");return this.emit("removeItem",e),this.#i.removeItem(e)}clearLocalStorage(){return this.#i.clear()}destroy(){window.removeEventListener("storage",this.#a),this.#o.offAllTypes()}}i.registerJsonType(Map,(e,t)=>({__map__:!0,data:Array.from(e.entries()).map(([e,r])=>[e,t(r)])}),{check:e=>e.__map__,decode:(e,t)=>new Map(e.data.map(([e,r])=>[e,t(r)]))}),i.registerJsonType(Set,(e,t)=>({__set__:!0,data:Array.from(e).map(t)}),{check:e=>e.__set__,decode:(e,t)=>new Set(e.data.map(t))}),i.registerJsonType(Date,e=>({__date__:!0,value:e.toISOString()}),{check:e=>e.__date__,decode:e=>new Date(e.value)}),i.registerJsonType(RegExp,e=>({__regexp__:!0,source:e.source,flags:e.flags}),{check:e=>e.__regexp__,decode:e=>new RegExp(e.source,e.flags)}),i.registerJsonType("bigint",e=>({__bigint__:!0,value:e.toString()}),{check:e=>e.__bigint__,decode:e=>BigInt(e.value)}),i.registerJsonType("symbol",e=>({__symbol__:!0,key:Symbol.keyFor(e)??e.description??null}),{check:e=>e.__symbol__,decode:e=>{const t=e.key;return null!=t?Symbol.for(t):Symbol()}});const a=i;window.TinyLocalStorage=t.TinyLocalStorage})();
|
|
1
|
+
(()=>{"use strict";var e={d:(t,r)=>{for(var n in r)e.o(r,n)&&!e.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:r[n]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)},t={};function r(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)&&"[object Object]"===Object.prototype.toString.call(e)}e.d(t,{TinyLocalStorage:()=>l});const n=class{#e=new Map;#t=10;#r=!1;setThrowOnMaxListeners(e){if("boolean"!=typeof e)throw new TypeError("setThrowOnMaxListeners(value): value must be a boolean");this.#r=e}getThrowOnMaxListeners(){return this.#r}#n(e,t,{once:r=!1}={}){let n=this.#e.get(e);Array.isArray(n)||(n=[],this.#e.set(e,n)),n.unshift({handler:t,config:{once:r}});const s=this.#t;if(s>0&&n.length>s){const t=`Possible memory leak detected. ${n.length} "${e}" listeners added. Use setMaxListeners() to increase limit.`;if(this.#r)throw new Error(t);console.warn(t)}}prependListener(e,t){if("string"!=typeof e)throw new TypeError("prepend(event, handler): event name must be a string");if("function"!=typeof t)throw new TypeError("prepend(event, handler): handler must be a function");this.#n(e,t)}prependListenerOnce(e,t){if("string"!=typeof e)throw new TypeError("prependOnceListener(event, handler): event name must be a string");if("function"!=typeof t)throw new TypeError("prependOnceListener(event, handler): handler must be a function");const r=(...n)=>{this.off(e,r),t(...n)};return this.#n(e,r,{once:!0}),r}#s(e,t,{once:r=!1}={}){let n=this.#e.get(e);Array.isArray(n)||(n=[],this.#e.set(e,n)),n.push({handler:t,config:{once:r}});const s=this.#t;if(s>0&&n.length>s){const t=`Possible memory leak detected. ${n.length} "${e}" listeners added. Use setMaxListeners() to increase limit.`;if(this.#r)throw new Error(t);console.warn(t)}}on(e,t){if("string"!=typeof e)throw new TypeError("on(event, handler): event name must be a string");if("function"!=typeof t)throw new TypeError("on(event, handler): handler must be a function");return this.#s(e,t)}once(e,t){if("string"!=typeof e)throw new TypeError("The event name must be a string.");if("function"!=typeof t)throw new TypeError("once(event, handler): handler must be a function");const r=n=>{this.off(e,r),"function"==typeof t&&t(n)};return this.#s(e,r,{once:!0}),r}appendListener(e,t){return this.on(e,t)}appendListenerOnce(e,t){return this.once(e,t)}off(e,t){if("string"!=typeof e)throw new TypeError("off(event, handler): event name must be a string");if("function"!=typeof t)throw new TypeError("off(event, handler): handler must be a function");const r=this.#e.get(e);if(!Array.isArray(r))return;const n=r.findIndex(e=>e.handler===t);-1!==n&&r.splice(n,1),0===r.length&&this.#e.delete(e)}offAll(e){if("string"!=typeof e)throw new TypeError("The event name must be a string.");this.#e.delete(e)}offAllTypes(){this.#e.clear()}listenerCount(e){if("string"!=typeof e)throw new TypeError("listenerCount(event): event name must be a string");const t=this.#e.get(e);return Array.isArray(t)?t.length:0}listeners(e){if("string"!=typeof e)throw new TypeError("listeners(event): event name must be a string");const t=this.#e.get(e);return Array.isArray(t)?[...t].filter(e=>!e.config.once).map(e=>e.handler):[]}onceListeners(e){if("string"!=typeof e)throw new TypeError("onceListeners(event): event name must be a string");const t=this.#e.get(e);return Array.isArray(t)?[...t].filter(e=>e.config.once).map(e=>e.handler):[]}allListeners(e){if("string"!=typeof e)throw new TypeError("allListeners(event): event name must be a string");const t=this.#e.get(e);return Array.isArray(t)?[...t].map(e=>e.handler):[]}eventNames(){return[...this.#e.keys()]}emit(e,...t){if("string"!=typeof e)throw new TypeError("emit(event, data): event name must be a string");const r=this.#e.get(e);return!(!Array.isArray(r)||0===r.length||(r.forEach(e=>e.handler(...t)),0))}setMaxListeners(e){if(!Number.isInteger(e)||e<0)throw new TypeError("setMaxListeners(n): n must be a non-negative integer");this.#t=e}getMaxListeners(){return this.#t}},s=new Map,o=new Map,i=new Set(["string","boolean","number","object","array",String,Boolean,Number,Object,Array,BigInt,Symbol]);class a{#o=new n;setThrowOnMaxListeners(e){return this.#o.setThrowOnMaxListeners(e)}getThrowOnMaxListeners(){return this.#o.getThrowOnMaxListeners()}prependListener(e,t){return this.#o.prependListener(e,t)}prependListenerOnce(e,t){return this.#o.prependListenerOnce(e,t)}appendListener(e,t){return this.#o.appendListener(e,t)}appendListenerOnce(e,t){return this.#o.appendListenerOnce(e,t)}on(e,t){return this.#o.on(e,t)}once(e,t){return this.#o.once(e,t)}off(e,t){return this.#o.off(e,t)}offAll(e){return this.#o.offAll(e)}offAllTypes(){return this.#o.offAllTypes()}listenerCount(e){return this.#o.listenerCount(e)}listeners(e){return this.#o.listeners(e)}onceListeners(e){return this.#o.onceListeners(e)}allListeners(e){return this.#o.allListeners(e)}eventNames(){return this.#o.eventNames()}emit(e,...t){return this.#o.emit(e,...t)}setMaxListeners(e){return this.#o.setMaxListeners(e)}getMaxListeners(){return this.#o.getMaxListeners()}static hasJsonType(e){return s.has(e)&&o.has(e)||i.has(e)}static registerJsonType(e,t,r,n=!1){if(i.has(e))throw new Error(`Cannot register type "${e}" because it is frozen.`);s.set(e,t),o.set(e,r),n&&i.add(e)}static deleteJsonType(e){if(i.has(e))throw new Error(`Cannot remove type "${e}" because it is frozen.`);let t=!1;return s.delete(e)&&(t=!0),o.delete(e)&&(t=!0),t}static encodeSpecialJson(e){if(void 0===e)return{__undefined__:!0};if(null===e)return{__null__:!0};for(const[t,r]of s.entries())if("string"!=typeof t&&e instanceof t||typeof e===t)return r(e,a.encodeSpecialJson);if(Array.isArray(e))return e.map(a.encodeSpecialJson);if(r(e)){const t={};for(const r in e)t[r]=a.encodeSpecialJson(e[r]);return t}return e}static decodeSpecialJson(e){const t=r(e);if(t){if(e.__undefined__)return;if(e.__null__)return null}if(Array.isArray(e))return e.map(a.decodeSpecialJson);if(t){for(const[t,r]of o.entries())if(r.check&&r.check(e))return r.decode(e,a.decodeSpecialJson);const t={};for(const r in e)t[r]=a.decodeSpecialJson(e[r]);return t}return e}#i=window.localStorage;#a=e=>this.emit("storage",e);constructor(){window.addEventListener("storage",this.#a)}setLocalStorage(e){if(!(e instanceof Storage))throw new Error("Argument must be a valid instance of Storage.");this.#i=e}localStorageExists(){return this.#i instanceof Storage}#l(e,t){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");return a.encodeSpecialJson(t)}setJson(e,t){if(!(r(t)||Array.isArray(t)||t instanceof Map||t instanceof Set))throw new Error("The storage value is not a valid JSON-compatible structure.");const n=this.#l(e,t);return this.emit("setJson",e,t),this.#i.setItem(e,JSON.stringify(n))}#c(e,t){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");const r=this.#i.getItem(e),n={obj:()=>({}),array:()=>[],map:()=>new Map,set:()=>new Set},s="function"==typeof n[t]?n[t]():null;let o;try{o=JSON.parse(r)}catch{return s}return{decoded:a.decodeSpecialJson(o),fallback:s}}getJson(e,t){const{decoded:n,fallback:s}=this.#c(e,t);return n instanceof Map||n instanceof Set||Array.isArray(n)||r(n)?n:s}setDate(e,t){if(!(t instanceof Date))throw new Error("Value must be a Date.");const r=this.#l(e,t);return this.emit("setDate",e,t),this.#i.setItem(e,JSON.stringify(r))}getDate(e){const t=this.#c(e).decoded;return t instanceof Date?t:null}setRegExp(e,t){if(!(t instanceof RegExp))throw new Error("Value must be a RegExp.");const r=this.#l(e,t);return this.emit("setRegExp",e,t),this.#i.setItem(e,JSON.stringify(r))}getRegExp(e){const t=this.#c(e).decoded;return t instanceof RegExp?t:null}setBigInt(e,t){if("bigint"!=typeof t)throw new Error("Value must be a BigInt.");const r=this.#l(e,t);return this.emit("setBigInt",e,t),this.#i.setItem(e,JSON.stringify(r))}getBigInt(e){const t=this.#c(e).decoded;return"bigint"==typeof t?t:null}setSymbol(e,t){if("symbol"!=typeof t)throw new Error("Value must be a Symbol.");const r=this.#l(e,t);return this.emit("setSymbol",e,t),this.#i.setItem(e,JSON.stringify(r))}getSymbol(e){const t=this.#c(e).decoded;return"symbol"==typeof t?t:null}getValue(e){return this.#c(e).decoded??null}setItem(e,t){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");return this.emit("setItem",e,t),this.#i.setItem(e,t)}getItem(e){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");return this.#i.getItem(e)}setString(e,t){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");if("string"!=typeof t)throw new Error("Value must be a string.");return this.emit("setString",e,t),this.#i.setItem(e,JSON.stringify({__string__:!0,value:t}))}getString(e){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");let t=this.#i.getItem(e);try{if(t=JSON.parse(t),!r(t)||!t.__string__||"string"!=typeof t.value)return null;t=t.value}catch{t=null}return"string"==typeof t?t:null}setNumber(e,t){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");if("number"!=typeof t)throw new Error("Value must be a number.");return this.emit("setNumber",e,t),this.#i.setItem(e,String(t))}getNumber(e){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");let t=this.#i.getItem(e);return"number"==typeof t||"string"==typeof t&&t.length>0&&(t=parseFloat(t),!Number.isNaN(t))?t:null}setBool(e,t){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");if("boolean"!=typeof t)throw new Error("Value must be a boolean.");return this.emit("setBool",e,t),this.#i.setItem(e,String(t))}getBool(e){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");const t=this.#i.getItem(e);if("boolean"==typeof t)return t;if("string"==typeof t){if("true"===t)return!0;if("false"===t)return!1}return null}removeItem(e){if("string"!=typeof e||!e.length)throw new Error("Key must be a non-empty string.");return this.emit("removeItem",e),this.#i.removeItem(e)}clearLocalStorage(){return this.#i.clear()}destroy(){window.removeEventListener("storage",this.#a),this.#o.offAllTypes()}}a.registerJsonType(Map,(e,t)=>({__map__:!0,data:Array.from(e.entries()).map(([e,r])=>[e,t(r)])}),{check:e=>e.__map__,decode:(e,t)=>new Map(e.data.map(([e,r])=>[e,t(r)]))},!0),a.registerJsonType(Set,(e,t)=>({__set__:!0,data:Array.from(e).map(t)}),{check:e=>e.__set__,decode:(e,t)=>new Set(e.data.map(t))},!0),a.registerJsonType(Date,e=>({__date__:!0,value:e.toISOString()}),{check:e=>e.__date__,decode:e=>new Date(e.value)},!0),a.registerJsonType(RegExp,e=>({__regexp__:!0,source:e.source,flags:e.flags}),{check:e=>e.__regexp__,decode:e=>new RegExp(e.source,e.flags)},!0),a.registerJsonType("bigint",e=>({__bigint__:!0,value:e.toString()}),{check:e=>e.__bigint__,decode:e=>BigInt(e.value)},!0),a.registerJsonType("symbol",e=>({__symbol__:!0,key:Symbol.keyFor(e)??e.description??null}),{check:e=>e.__symbol__,decode:e=>{const t=e.key;return null!=t?Symbol.for(t):Symbol()}},!0);const l=a;window.TinyLocalStorage=t.TinyLocalStorage})();
|
|
@@ -12198,6 +12198,22 @@ const customEncoders = new Map();
|
|
|
12198
12198
|
/** @type {Map<any, DecodeFn>} */
|
|
12199
12199
|
const customDecoders = new Map();
|
|
12200
12200
|
|
|
12201
|
+
/** @type {Set<any>} */
|
|
12202
|
+
const customTypesFreezed = new Set([
|
|
12203
|
+
'string',
|
|
12204
|
+
'boolean',
|
|
12205
|
+
'number',
|
|
12206
|
+
'object',
|
|
12207
|
+
'array',
|
|
12208
|
+
String,
|
|
12209
|
+
Boolean,
|
|
12210
|
+
Number,
|
|
12211
|
+
Object,
|
|
12212
|
+
Array,
|
|
12213
|
+
BigInt,
|
|
12214
|
+
Symbol,
|
|
12215
|
+
]);
|
|
12216
|
+
|
|
12201
12217
|
/**
|
|
12202
12218
|
* A function that encodes a value into a serializable JSON-compatible format.
|
|
12203
12219
|
*
|
|
@@ -12469,26 +12485,49 @@ class TinyLocalStorage {
|
|
|
12469
12485
|
|
|
12470
12486
|
///////////////////////////////////////////////////
|
|
12471
12487
|
|
|
12488
|
+
/**
|
|
12489
|
+
* Checks whether a JSON-serializable type is already registered.
|
|
12490
|
+
*
|
|
12491
|
+
* @param {any} type - The type identifier, which can be a string (e.g., `"bigint"`, `"symbol"`)
|
|
12492
|
+
* or a reference to a class/constructor function.
|
|
12493
|
+
* @returns {boolean} True if the type has both an encoder and decoder registered.
|
|
12494
|
+
*/
|
|
12495
|
+
static hasJsonType(type) {
|
|
12496
|
+
return (customEncoders.has(type) && customDecoders.has(type)) || customTypesFreezed.has(type);
|
|
12497
|
+
}
|
|
12498
|
+
|
|
12472
12499
|
/**
|
|
12473
12500
|
* Registers a new JSON-serializable type with its encoder and decoder.
|
|
12474
12501
|
*
|
|
12475
|
-
* @param {any} type - The type
|
|
12476
|
-
*
|
|
12477
|
-
* @param {
|
|
12502
|
+
* @param {any} type - The type identifier, which can be a string (e.g., `"bigint"`, `"symbol"`)
|
|
12503
|
+
* or a reference to a class/constructor function.
|
|
12504
|
+
* @param {EncodeFn} encodeFn - A function that receives a value of this type and returns a JSON-safe representation.
|
|
12505
|
+
* @param {DecodeFn} decodeFn - An object with `check(value)` to identify this type and `decode(value)` to restore it.
|
|
12506
|
+
* @param {boolean} [freezeType=false] - If true, prevents this type from being unregistered later.
|
|
12507
|
+
* @throws {Error} Throws an error if the type is frozen and cannot be registered.
|
|
12478
12508
|
*/
|
|
12479
|
-
static registerJsonType(type, encodeFn, decodeFn) {
|
|
12509
|
+
static registerJsonType(type, encodeFn, decodeFn, freezeType = false) {
|
|
12510
|
+
if (customTypesFreezed.has(type))
|
|
12511
|
+
throw new Error(`Cannot register type "${type}" because it is frozen.`);
|
|
12480
12512
|
customEncoders.set(type, encodeFn);
|
|
12481
12513
|
customDecoders.set(type, decodeFn);
|
|
12514
|
+
if (freezeType) customTypesFreezed.add(type);
|
|
12482
12515
|
}
|
|
12483
12516
|
|
|
12484
12517
|
/**
|
|
12485
|
-
*
|
|
12518
|
+
* Unregisters a previously registered custom type from the encoding/decoding system.
|
|
12486
12519
|
*
|
|
12487
|
-
* @param {
|
|
12520
|
+
* @param {any} type - The primitive name or constructor reference used in the registration.
|
|
12521
|
+
* @returns {boolean} Returns true if the type existed and was removed, or false if it wasn't found.
|
|
12522
|
+
* @throws {Error} Throws an error if the type is frozen and cannot be unregistered.
|
|
12488
12523
|
*/
|
|
12489
12524
|
static deleteJsonType(type) {
|
|
12490
|
-
|
|
12491
|
-
|
|
12525
|
+
if (customTypesFreezed.has(type))
|
|
12526
|
+
throw new Error(`Cannot remove type "${type}" because it is frozen.`);
|
|
12527
|
+
let isDeleted = false;
|
|
12528
|
+
if (customEncoders.delete(type)) isDeleted = true;
|
|
12529
|
+
if (customDecoders.delete(type)) isDeleted = true;
|
|
12530
|
+
return isDeleted;
|
|
12492
12531
|
}
|
|
12493
12532
|
|
|
12494
12533
|
//////////////////////////////////////////////////////
|
|
@@ -12833,7 +12872,13 @@ class TinyLocalStorage {
|
|
|
12833
12872
|
if (typeof data !== 'string') throw new Error('Value must be a string.');
|
|
12834
12873
|
|
|
12835
12874
|
this.emit('setString', name, data);
|
|
12836
|
-
return this.#localStorage.setItem(
|
|
12875
|
+
return this.#localStorage.setItem(
|
|
12876
|
+
name,
|
|
12877
|
+
JSON.stringify({
|
|
12878
|
+
__string__: true,
|
|
12879
|
+
value: data,
|
|
12880
|
+
}),
|
|
12881
|
+
);
|
|
12837
12882
|
}
|
|
12838
12883
|
|
|
12839
12884
|
/**
|
|
@@ -12846,6 +12891,15 @@ class TinyLocalStorage {
|
|
|
12846
12891
|
if (typeof name !== 'string' || !name.length)
|
|
12847
12892
|
throw new Error('Key must be a non-empty string.');
|
|
12848
12893
|
let value = this.#localStorage.getItem(name);
|
|
12894
|
+
try {
|
|
12895
|
+
/** @type {{ value: string; __string__: boolean }} */
|
|
12896
|
+
// @ts-ignore
|
|
12897
|
+
value = JSON.parse(value);
|
|
12898
|
+
if (!isJsonObject(value) || !value.__string__ || typeof value.value !== 'string') return null;
|
|
12899
|
+
value = value.value;
|
|
12900
|
+
} catch {
|
|
12901
|
+
value = null;
|
|
12902
|
+
}
|
|
12849
12903
|
if (typeof value === 'string') return value;
|
|
12850
12904
|
return null;
|
|
12851
12905
|
}
|
|
@@ -12962,6 +13016,7 @@ TinyLocalStorage.registerJsonType(
|
|
|
12962
13016
|
decode: (value, decodeSpecialJson) =>
|
|
12963
13017
|
new Map(value.data.map(([k, v]) => [k, decodeSpecialJson(v)])),
|
|
12964
13018
|
},
|
|
13019
|
+
true,
|
|
12965
13020
|
);
|
|
12966
13021
|
|
|
12967
13022
|
// Set
|
|
@@ -12975,6 +13030,7 @@ TinyLocalStorage.registerJsonType(
|
|
|
12975
13030
|
check: (value) => value.__set__,
|
|
12976
13031
|
decode: (value, decodeSpecialJson) => new Set(value.data.map(decodeSpecialJson)),
|
|
12977
13032
|
},
|
|
13033
|
+
true,
|
|
12978
13034
|
);
|
|
12979
13035
|
|
|
12980
13036
|
// Date
|
|
@@ -12988,6 +13044,7 @@ TinyLocalStorage.registerJsonType(
|
|
|
12988
13044
|
check: (value) => value.__date__,
|
|
12989
13045
|
decode: (value) => new Date(value.value),
|
|
12990
13046
|
},
|
|
13047
|
+
true,
|
|
12991
13048
|
);
|
|
12992
13049
|
|
|
12993
13050
|
// Regex
|
|
@@ -13002,6 +13059,7 @@ TinyLocalStorage.registerJsonType(
|
|
|
13002
13059
|
check: (value) => value.__regexp__,
|
|
13003
13060
|
decode: (value) => new RegExp(value.source, value.flags),
|
|
13004
13061
|
},
|
|
13062
|
+
true,
|
|
13005
13063
|
);
|
|
13006
13064
|
|
|
13007
13065
|
// Big Int
|
|
@@ -13015,6 +13073,7 @@ TinyLocalStorage.registerJsonType(
|
|
|
13015
13073
|
check: (value) => value.__bigint__,
|
|
13016
13074
|
decode: (value) => BigInt(value.value),
|
|
13017
13075
|
},
|
|
13076
|
+
true,
|
|
13018
13077
|
);
|
|
13019
13078
|
|
|
13020
13079
|
// Symbol
|
|
@@ -13031,6 +13090,7 @@ TinyLocalStorage.registerJsonType(
|
|
|
13031
13090
|
return key != null ? Symbol.for(key) : Symbol();
|
|
13032
13091
|
},
|
|
13033
13092
|
},
|
|
13093
|
+
true,
|
|
13034
13094
|
);
|
|
13035
13095
|
|
|
13036
13096
|
/* harmony default export */ const libs_TinyLocalStorage = ((/* unused pure expression or super */ null && (TinyLocalStorage)));
|