tiny-essentials 1.19.2 → 1.19.3
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 +109 -21
- package/dist/v1/TinyEssentials.min.js +1 -1
- package/dist/v1/TinyLocalStorage.js +109 -21
- package/dist/v1/TinyLocalStorage.min.js +1 -1
- package/dist/v1/TinyUploadClicker.js +109 -21
- package/dist/v1/TinyUploadClicker.min.js +1 -1
- package/dist/v1/libs/TinyLocalStorage.cjs +109 -21
- package/dist/v1/libs/TinyLocalStorage.d.mts +29 -0
- package/dist/v1/libs/TinyLocalStorage.mjs +97 -21
- package/docs/v1/libs/TinyLocalStorage.md +53 -0
- package/package.json +1 -1
|
@@ -421,6 +421,12 @@ class TinyLocalStorage {
|
|
|
421
421
|
/** @type {Storage} */
|
|
422
422
|
#localStorage = window.localStorage;
|
|
423
423
|
|
|
424
|
+
/** @type {string|null} */
|
|
425
|
+
#dbKey = null;
|
|
426
|
+
|
|
427
|
+
/** @type {number} */
|
|
428
|
+
#version = 0;
|
|
429
|
+
|
|
424
430
|
/** @type {(ev: StorageEvent) => any} */
|
|
425
431
|
#storageEvent = (ev) => this.emit('storage', ev);
|
|
426
432
|
|
|
@@ -428,11 +434,84 @@ class TinyLocalStorage {
|
|
|
428
434
|
* Initializes the TinyLocalStorage instance and sets up cross-tab sync.
|
|
429
435
|
*
|
|
430
436
|
* Adds listener for the native `storage` event to support tab synchronization.
|
|
437
|
+
* @param {string} [dbName] - Unique database name.
|
|
431
438
|
*/
|
|
432
|
-
constructor() {
|
|
439
|
+
constructor(dbName) {
|
|
440
|
+
if (typeof dbName !== 'undefined' && typeof dbName !== 'string')
|
|
441
|
+
throw new TypeError('TinyLocalStorage: dbName must be a string if provided.');
|
|
442
|
+
if (typeof dbName === 'string') this.#dbKey = `LSDB::${dbName}`;
|
|
433
443
|
window.addEventListener('storage', this.#storageEvent);
|
|
434
444
|
}
|
|
435
445
|
|
|
446
|
+
/**
|
|
447
|
+
* Validates that a given key does not conflict with internal database keys.
|
|
448
|
+
*
|
|
449
|
+
* This method is used to prevent accidental overwriting of reserved `LSDB::` keys
|
|
450
|
+
* in `localStorage`, which are used internally by TinyLocalStorage for versioning
|
|
451
|
+
* and data management.
|
|
452
|
+
*
|
|
453
|
+
* @param {string} name - The key to validate before writing to localStorage.
|
|
454
|
+
* @throws {Error} If the key starts with `LSDB::`.
|
|
455
|
+
*/
|
|
456
|
+
#isProtectedDbKey(name) {
|
|
457
|
+
if (typeof name === 'string' && name.startsWith('LSDB::'))
|
|
458
|
+
throw new Error(`TinyLocalStorage: Key "${name}" may conflict with reserved dbKeys.`);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Updates the version of the storage and triggers migration if needed.
|
|
463
|
+
*
|
|
464
|
+
* @param {number} version - Desired version of the database.
|
|
465
|
+
* @param {(oldVersion: number, newVersion: number) => void} onUpgrade - Callback to perform migration logic.
|
|
466
|
+
* @throws {Error} If the database key has not been initialized.
|
|
467
|
+
* @throws {TypeError} If `version` is not a valid positive number.
|
|
468
|
+
* @throws {TypeError} If `onUpgrade` is not a function.
|
|
469
|
+
*/
|
|
470
|
+
updateStorageVersion(version, onUpgrade) {
|
|
471
|
+
if (typeof this.#dbKey !== 'string')
|
|
472
|
+
throw new Error(
|
|
473
|
+
'TinyLocalStorage: Database key is not initialized. Set a valid dbName in the constructor.',
|
|
474
|
+
);
|
|
475
|
+
if (typeof version !== 'number' || Number.isNaN(version) || version < 1)
|
|
476
|
+
throw new TypeError('TinyLocalStorage: version must be a positive number.');
|
|
477
|
+
if (typeof onUpgrade !== 'function')
|
|
478
|
+
throw new TypeError('TinyLocalStorage: onUpgrade must be a function.');
|
|
479
|
+
|
|
480
|
+
// @ts-ignore
|
|
481
|
+
const savedVersion = parseInt(localStorage.getItem(this.#dbKey), 10) || 0;
|
|
482
|
+
if (typeof savedVersion !== 'number' || Number.isNaN(savedVersion) || savedVersion < 0)
|
|
483
|
+
throw new TypeError('TinyLocalStorage: saved version in localStorage is not a valid number.');
|
|
484
|
+
|
|
485
|
+
if (version < savedVersion)
|
|
486
|
+
throw new Error(
|
|
487
|
+
`TinyLocalStorage: Cannot downgrade database version from ${savedVersion} to ${version}.`,
|
|
488
|
+
);
|
|
489
|
+
|
|
490
|
+
if (version > savedVersion) {
|
|
491
|
+
onUpgrade(savedVersion, version);
|
|
492
|
+
localStorage.setItem(this.#dbKey, String(version));
|
|
493
|
+
this.#version = version;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Gets the current database key used in localStorage.
|
|
499
|
+
*
|
|
500
|
+
* @returns {string|null} The database key, or null if not set.
|
|
501
|
+
*/
|
|
502
|
+
getDbKey() {
|
|
503
|
+
return this.#dbKey;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Gets the current version of the database.
|
|
508
|
+
*
|
|
509
|
+
* @returns {number} The current version number.
|
|
510
|
+
*/
|
|
511
|
+
getVersion() {
|
|
512
|
+
return this.#version;
|
|
513
|
+
}
|
|
514
|
+
|
|
436
515
|
/**
|
|
437
516
|
* Defines a custom storage interface (e.g. `sessionStorage`).
|
|
438
517
|
*
|
|
@@ -440,7 +519,7 @@ class TinyLocalStorage {
|
|
|
440
519
|
*/
|
|
441
520
|
setLocalStorage(localstorage) {
|
|
442
521
|
if (!(localstorage instanceof Storage))
|
|
443
|
-
throw new
|
|
522
|
+
throw new TypeError('Argument must be a valid instance of Storage.');
|
|
444
523
|
this.#localStorage = localstorage;
|
|
445
524
|
}
|
|
446
525
|
|
|
@@ -462,7 +541,7 @@ class TinyLocalStorage {
|
|
|
462
541
|
*/
|
|
463
542
|
#setJson(name, data) {
|
|
464
543
|
if (typeof name !== 'string' || !name.length)
|
|
465
|
-
throw new
|
|
544
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
466
545
|
return TinyLocalStorage.encodeSpecialJson(data);
|
|
467
546
|
}
|
|
468
547
|
|
|
@@ -475,13 +554,14 @@ class TinyLocalStorage {
|
|
|
475
554
|
* @param {LocalStorageJsonValue} data - The data to be serialized and stored.
|
|
476
555
|
*/
|
|
477
556
|
setJson(name, data) {
|
|
557
|
+
this.#isProtectedDbKey(name);
|
|
478
558
|
if (
|
|
479
559
|
!objChecker.isJsonObject(data) &&
|
|
480
560
|
!Array.isArray(data) &&
|
|
481
561
|
!(data instanceof Map) &&
|
|
482
562
|
!(data instanceof Set)
|
|
483
563
|
) {
|
|
484
|
-
throw new
|
|
564
|
+
throw new TypeError('The storage value is not a valid JSON-compatible structure.');
|
|
485
565
|
}
|
|
486
566
|
const encoded = this.#setJson(name, data);
|
|
487
567
|
this.emit('setJson', name, data);
|
|
@@ -499,7 +579,7 @@ class TinyLocalStorage {
|
|
|
499
579
|
*/
|
|
500
580
|
#getJson(name, defaultData) {
|
|
501
581
|
if (typeof name !== 'string' || !name.length)
|
|
502
|
-
throw new
|
|
582
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
503
583
|
|
|
504
584
|
const raw = this.#localStorage.getItem(name);
|
|
505
585
|
const fallbackTypes = {
|
|
@@ -553,7 +633,8 @@ class TinyLocalStorage {
|
|
|
553
633
|
* @param {Date} data
|
|
554
634
|
*/
|
|
555
635
|
setDate(name, data) {
|
|
556
|
-
|
|
636
|
+
this.#isProtectedDbKey(name);
|
|
637
|
+
if (!(data instanceof Date)) throw new TypeError('Value must be a Date.');
|
|
557
638
|
const encoded = this.#setJson(name, data);
|
|
558
639
|
this.emit('setDate', name, data);
|
|
559
640
|
return this.#localStorage.setItem(name, JSON.stringify(encoded));
|
|
@@ -575,7 +656,8 @@ class TinyLocalStorage {
|
|
|
575
656
|
* @param {RegExp} data
|
|
576
657
|
*/
|
|
577
658
|
setRegExp(name, data) {
|
|
578
|
-
|
|
659
|
+
this.#isProtectedDbKey(name);
|
|
660
|
+
if (!(data instanceof RegExp)) throw new TypeError('Value must be a RegExp.');
|
|
579
661
|
const encoded = this.#setJson(name, data);
|
|
580
662
|
this.emit('setRegExp', name, data);
|
|
581
663
|
return this.#localStorage.setItem(name, JSON.stringify(encoded));
|
|
@@ -597,7 +679,8 @@ class TinyLocalStorage {
|
|
|
597
679
|
* @param {bigint} data
|
|
598
680
|
*/
|
|
599
681
|
setBigInt(name, data) {
|
|
600
|
-
|
|
682
|
+
this.#isProtectedDbKey(name);
|
|
683
|
+
if (typeof data !== 'bigint') throw new TypeError('Value must be a BigInt.');
|
|
601
684
|
const encoded = this.#setJson(name, data);
|
|
602
685
|
this.emit('setBigInt', name, data);
|
|
603
686
|
return this.#localStorage.setItem(name, JSON.stringify(encoded));
|
|
@@ -620,7 +703,8 @@ class TinyLocalStorage {
|
|
|
620
703
|
* @param {symbol} data
|
|
621
704
|
*/
|
|
622
705
|
setSymbol(name, data) {
|
|
623
|
-
|
|
706
|
+
this.#isProtectedDbKey(name);
|
|
707
|
+
if (typeof data !== 'symbol') throw new TypeError('Value must be a Symbol.');
|
|
624
708
|
const encoded = this.#setJson(name, data);
|
|
625
709
|
this.emit('setSymbol', name, data);
|
|
626
710
|
return this.#localStorage.setItem(name, JSON.stringify(encoded));
|
|
@@ -653,8 +737,9 @@ class TinyLocalStorage {
|
|
|
653
737
|
* @param {any} data - The data to store.
|
|
654
738
|
*/
|
|
655
739
|
setItem(name, data) {
|
|
740
|
+
this.#isProtectedDbKey(name);
|
|
656
741
|
if (typeof name !== 'string' || !name.length)
|
|
657
|
-
throw new
|
|
742
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
658
743
|
this.emit('setItem', name, data);
|
|
659
744
|
return this.#localStorage.setItem(name, data);
|
|
660
745
|
}
|
|
@@ -667,7 +752,7 @@ class TinyLocalStorage {
|
|
|
667
752
|
*/
|
|
668
753
|
getItem(name) {
|
|
669
754
|
if (typeof name !== 'string' || !name.length)
|
|
670
|
-
throw new
|
|
755
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
671
756
|
return this.#localStorage.getItem(name);
|
|
672
757
|
}
|
|
673
758
|
|
|
@@ -678,9 +763,10 @@ class TinyLocalStorage {
|
|
|
678
763
|
* @param {string} data - The string to store.
|
|
679
764
|
*/
|
|
680
765
|
setString(name, data) {
|
|
766
|
+
this.#isProtectedDbKey(name);
|
|
681
767
|
if (typeof name !== 'string' || !name.length)
|
|
682
|
-
throw new
|
|
683
|
-
if (typeof data !== 'string') throw new
|
|
768
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
769
|
+
if (typeof data !== 'string') throw new TypeError('Value must be a string.');
|
|
684
770
|
|
|
685
771
|
this.emit('setString', name, data);
|
|
686
772
|
return this.#localStorage.setItem(
|
|
@@ -700,7 +786,7 @@ class TinyLocalStorage {
|
|
|
700
786
|
*/
|
|
701
787
|
getString(name) {
|
|
702
788
|
if (typeof name !== 'string' || !name.length)
|
|
703
|
-
throw new
|
|
789
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
704
790
|
let value = this.#localStorage.getItem(name);
|
|
705
791
|
try {
|
|
706
792
|
/** @type {{ value: string; __string__: boolean }} */
|
|
@@ -722,9 +808,10 @@ class TinyLocalStorage {
|
|
|
722
808
|
* @param {number} data - The number to store.
|
|
723
809
|
*/
|
|
724
810
|
setNumber(name, data) {
|
|
811
|
+
this.#isProtectedDbKey(name);
|
|
725
812
|
if (typeof name !== 'string' || !name.length)
|
|
726
|
-
throw new
|
|
727
|
-
if (typeof data !== 'number') throw new
|
|
813
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
814
|
+
if (typeof data !== 'number') throw new TypeError('Value must be a number.');
|
|
728
815
|
this.emit('setNumber', name, data);
|
|
729
816
|
return this.#localStorage.setItem(name, String(data));
|
|
730
817
|
}
|
|
@@ -737,7 +824,7 @@ class TinyLocalStorage {
|
|
|
737
824
|
*/
|
|
738
825
|
getNumber(name) {
|
|
739
826
|
if (typeof name !== 'string' || !name.length)
|
|
740
|
-
throw new
|
|
827
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
741
828
|
|
|
742
829
|
/** @type {number|string|null} */
|
|
743
830
|
let number = this.#localStorage.getItem(name);
|
|
@@ -756,9 +843,10 @@ class TinyLocalStorage {
|
|
|
756
843
|
* @param {boolean} data - The boolean value to store.
|
|
757
844
|
*/
|
|
758
845
|
setBool(name, data) {
|
|
846
|
+
this.#isProtectedDbKey(name);
|
|
759
847
|
if (typeof name !== 'string' || !name.length)
|
|
760
|
-
throw new
|
|
761
|
-
if (typeof data !== 'boolean') throw new
|
|
848
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
849
|
+
if (typeof data !== 'boolean') throw new TypeError('Value must be a boolean.');
|
|
762
850
|
this.emit('setBool', name, data);
|
|
763
851
|
return this.#localStorage.setItem(name, String(data));
|
|
764
852
|
}
|
|
@@ -771,7 +859,7 @@ class TinyLocalStorage {
|
|
|
771
859
|
*/
|
|
772
860
|
getBool(name) {
|
|
773
861
|
if (typeof name !== 'string' || !name.length)
|
|
774
|
-
throw new
|
|
862
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
775
863
|
|
|
776
864
|
const value = this.#localStorage.getItem(name);
|
|
777
865
|
if (typeof value === 'boolean') return value;
|
|
@@ -790,7 +878,7 @@ class TinyLocalStorage {
|
|
|
790
878
|
*/
|
|
791
879
|
removeItem(name) {
|
|
792
880
|
if (typeof name !== 'string' || !name.length)
|
|
793
|
-
throw new
|
|
881
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
794
882
|
|
|
795
883
|
this.emit('removeItem', name);
|
|
796
884
|
return this.#localStorage.removeItem(name);
|
|
@@ -130,6 +130,13 @@ declare class TinyLocalStorage {
|
|
|
130
130
|
static deleteJsonType(type: any): boolean;
|
|
131
131
|
static encodeSpecialJson(value: any): any;
|
|
132
132
|
static decodeSpecialJson(value: any): any;
|
|
133
|
+
/**
|
|
134
|
+
* Initializes the TinyLocalStorage instance and sets up cross-tab sync.
|
|
135
|
+
*
|
|
136
|
+
* Adds listener for the native `storage` event to support tab synchronization.
|
|
137
|
+
* @param {string} [dbName] - Unique database name.
|
|
138
|
+
*/
|
|
139
|
+
constructor(dbName?: string);
|
|
133
140
|
/**
|
|
134
141
|
* Enables or disables throwing an error when the maximum number of listeners is exceeded.
|
|
135
142
|
*
|
|
@@ -258,6 +265,28 @@ declare class TinyLocalStorage {
|
|
|
258
265
|
* @returns {number} The maximum number of listeners.
|
|
259
266
|
*/
|
|
260
267
|
getMaxListeners(): number;
|
|
268
|
+
/**
|
|
269
|
+
* Updates the version of the storage and triggers migration if needed.
|
|
270
|
+
*
|
|
271
|
+
* @param {number} version - Desired version of the database.
|
|
272
|
+
* @param {(oldVersion: number, newVersion: number) => void} onUpgrade - Callback to perform migration logic.
|
|
273
|
+
* @throws {Error} If the database key has not been initialized.
|
|
274
|
+
* @throws {TypeError} If `version` is not a valid positive number.
|
|
275
|
+
* @throws {TypeError} If `onUpgrade` is not a function.
|
|
276
|
+
*/
|
|
277
|
+
updateStorageVersion(version: number, onUpgrade: (oldVersion: number, newVersion: number) => void): void;
|
|
278
|
+
/**
|
|
279
|
+
* Gets the current database key used in localStorage.
|
|
280
|
+
*
|
|
281
|
+
* @returns {string|null} The database key, or null if not set.
|
|
282
|
+
*/
|
|
283
|
+
getDbKey(): string | null;
|
|
284
|
+
/**
|
|
285
|
+
* Gets the current version of the database.
|
|
286
|
+
*
|
|
287
|
+
* @returns {number} The current version number.
|
|
288
|
+
*/
|
|
289
|
+
getVersion(): number;
|
|
261
290
|
/**
|
|
262
291
|
* Defines a custom storage interface (e.g. `sessionStorage`).
|
|
263
292
|
*
|
|
@@ -375,16 +375,83 @@ class TinyLocalStorage {
|
|
|
375
375
|
//////////////////////////////////////////////////////
|
|
376
376
|
/** @type {Storage} */
|
|
377
377
|
#localStorage = window.localStorage;
|
|
378
|
+
/** @type {string|null} */
|
|
379
|
+
#dbKey = null;
|
|
380
|
+
/** @type {number} */
|
|
381
|
+
#version = 0;
|
|
378
382
|
/** @type {(ev: StorageEvent) => any} */
|
|
379
383
|
#storageEvent = (ev) => this.emit('storage', ev);
|
|
380
384
|
/**
|
|
381
385
|
* Initializes the TinyLocalStorage instance and sets up cross-tab sync.
|
|
382
386
|
*
|
|
383
387
|
* Adds listener for the native `storage` event to support tab synchronization.
|
|
388
|
+
* @param {string} [dbName] - Unique database name.
|
|
384
389
|
*/
|
|
385
|
-
constructor() {
|
|
390
|
+
constructor(dbName) {
|
|
391
|
+
if (typeof dbName !== 'undefined' && typeof dbName !== 'string')
|
|
392
|
+
throw new TypeError('TinyLocalStorage: dbName must be a string if provided.');
|
|
393
|
+
if (typeof dbName === 'string')
|
|
394
|
+
this.#dbKey = `LSDB::${dbName}`;
|
|
386
395
|
window.addEventListener('storage', this.#storageEvent);
|
|
387
396
|
}
|
|
397
|
+
/**
|
|
398
|
+
* Validates that a given key does not conflict with internal database keys.
|
|
399
|
+
*
|
|
400
|
+
* This method is used to prevent accidental overwriting of reserved `LSDB::` keys
|
|
401
|
+
* in `localStorage`, which are used internally by TinyLocalStorage for versioning
|
|
402
|
+
* and data management.
|
|
403
|
+
*
|
|
404
|
+
* @param {string} name - The key to validate before writing to localStorage.
|
|
405
|
+
* @throws {Error} If the key starts with `LSDB::`.
|
|
406
|
+
*/
|
|
407
|
+
#isProtectedDbKey(name) {
|
|
408
|
+
if (typeof name === 'string' && name.startsWith('LSDB::'))
|
|
409
|
+
throw new Error(`TinyLocalStorage: Key "${name}" may conflict with reserved dbKeys.`);
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Updates the version of the storage and triggers migration if needed.
|
|
413
|
+
*
|
|
414
|
+
* @param {number} version - Desired version of the database.
|
|
415
|
+
* @param {(oldVersion: number, newVersion: number) => void} onUpgrade - Callback to perform migration logic.
|
|
416
|
+
* @throws {Error} If the database key has not been initialized.
|
|
417
|
+
* @throws {TypeError} If `version` is not a valid positive number.
|
|
418
|
+
* @throws {TypeError} If `onUpgrade` is not a function.
|
|
419
|
+
*/
|
|
420
|
+
updateStorageVersion(version, onUpgrade) {
|
|
421
|
+
if (typeof this.#dbKey !== 'string')
|
|
422
|
+
throw new Error('TinyLocalStorage: Database key is not initialized. Set a valid dbName in the constructor.');
|
|
423
|
+
if (typeof version !== 'number' || Number.isNaN(version) || version < 1)
|
|
424
|
+
throw new TypeError('TinyLocalStorage: version must be a positive number.');
|
|
425
|
+
if (typeof onUpgrade !== 'function')
|
|
426
|
+
throw new TypeError('TinyLocalStorage: onUpgrade must be a function.');
|
|
427
|
+
// @ts-ignore
|
|
428
|
+
const savedVersion = parseInt(localStorage.getItem(this.#dbKey), 10) || 0;
|
|
429
|
+
if (typeof savedVersion !== 'number' || Number.isNaN(savedVersion) || savedVersion < 0)
|
|
430
|
+
throw new TypeError('TinyLocalStorage: saved version in localStorage is not a valid number.');
|
|
431
|
+
if (version < savedVersion)
|
|
432
|
+
throw new Error(`TinyLocalStorage: Cannot downgrade database version from ${savedVersion} to ${version}.`);
|
|
433
|
+
if (version > savedVersion) {
|
|
434
|
+
onUpgrade(savedVersion, version);
|
|
435
|
+
localStorage.setItem(this.#dbKey, String(version));
|
|
436
|
+
this.#version = version;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Gets the current database key used in localStorage.
|
|
441
|
+
*
|
|
442
|
+
* @returns {string|null} The database key, or null if not set.
|
|
443
|
+
*/
|
|
444
|
+
getDbKey() {
|
|
445
|
+
return this.#dbKey;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Gets the current version of the database.
|
|
449
|
+
*
|
|
450
|
+
* @returns {number} The current version number.
|
|
451
|
+
*/
|
|
452
|
+
getVersion() {
|
|
453
|
+
return this.#version;
|
|
454
|
+
}
|
|
388
455
|
/**
|
|
389
456
|
* Defines a custom storage interface (e.g. `sessionStorage`).
|
|
390
457
|
*
|
|
@@ -392,7 +459,7 @@ class TinyLocalStorage {
|
|
|
392
459
|
*/
|
|
393
460
|
setLocalStorage(localstorage) {
|
|
394
461
|
if (!(localstorage instanceof Storage))
|
|
395
|
-
throw new
|
|
462
|
+
throw new TypeError('Argument must be a valid instance of Storage.');
|
|
396
463
|
this.#localStorage = localstorage;
|
|
397
464
|
}
|
|
398
465
|
/**
|
|
@@ -412,7 +479,7 @@ class TinyLocalStorage {
|
|
|
412
479
|
*/
|
|
413
480
|
#setJson(name, data) {
|
|
414
481
|
if (typeof name !== 'string' || !name.length)
|
|
415
|
-
throw new
|
|
482
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
416
483
|
return TinyLocalStorage.encodeSpecialJson(data);
|
|
417
484
|
}
|
|
418
485
|
/**
|
|
@@ -424,11 +491,12 @@ class TinyLocalStorage {
|
|
|
424
491
|
* @param {LocalStorageJsonValue} data - The data to be serialized and stored.
|
|
425
492
|
*/
|
|
426
493
|
setJson(name, data) {
|
|
494
|
+
this.#isProtectedDbKey(name);
|
|
427
495
|
if (!isJsonObject(data) &&
|
|
428
496
|
!Array.isArray(data) &&
|
|
429
497
|
!(data instanceof Map) &&
|
|
430
498
|
!(data instanceof Set)) {
|
|
431
|
-
throw new
|
|
499
|
+
throw new TypeError('The storage value is not a valid JSON-compatible structure.');
|
|
432
500
|
}
|
|
433
501
|
const encoded = this.#setJson(name, data);
|
|
434
502
|
this.emit('setJson', name, data);
|
|
@@ -445,7 +513,7 @@ class TinyLocalStorage {
|
|
|
445
513
|
*/
|
|
446
514
|
#getJson(name, defaultData) {
|
|
447
515
|
if (typeof name !== 'string' || !name.length)
|
|
448
|
-
throw new
|
|
516
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
449
517
|
const raw = this.#localStorage.getItem(name);
|
|
450
518
|
const fallbackTypes = {
|
|
451
519
|
obj: () => ({}),
|
|
@@ -491,8 +559,9 @@ class TinyLocalStorage {
|
|
|
491
559
|
* @param {Date} data
|
|
492
560
|
*/
|
|
493
561
|
setDate(name, data) {
|
|
562
|
+
this.#isProtectedDbKey(name);
|
|
494
563
|
if (!(data instanceof Date))
|
|
495
|
-
throw new
|
|
564
|
+
throw new TypeError('Value must be a Date.');
|
|
496
565
|
const encoded = this.#setJson(name, data);
|
|
497
566
|
this.emit('setDate', name, data);
|
|
498
567
|
return this.#localStorage.setItem(name, JSON.stringify(encoded));
|
|
@@ -512,8 +581,9 @@ class TinyLocalStorage {
|
|
|
512
581
|
* @param {RegExp} data
|
|
513
582
|
*/
|
|
514
583
|
setRegExp(name, data) {
|
|
584
|
+
this.#isProtectedDbKey(name);
|
|
515
585
|
if (!(data instanceof RegExp))
|
|
516
|
-
throw new
|
|
586
|
+
throw new TypeError('Value must be a RegExp.');
|
|
517
587
|
const encoded = this.#setJson(name, data);
|
|
518
588
|
this.emit('setRegExp', name, data);
|
|
519
589
|
return this.#localStorage.setItem(name, JSON.stringify(encoded));
|
|
@@ -533,8 +603,9 @@ class TinyLocalStorage {
|
|
|
533
603
|
* @param {bigint} data
|
|
534
604
|
*/
|
|
535
605
|
setBigInt(name, data) {
|
|
606
|
+
this.#isProtectedDbKey(name);
|
|
536
607
|
if (typeof data !== 'bigint')
|
|
537
|
-
throw new
|
|
608
|
+
throw new TypeError('Value must be a BigInt.');
|
|
538
609
|
const encoded = this.#setJson(name, data);
|
|
539
610
|
this.emit('setBigInt', name, data);
|
|
540
611
|
return this.#localStorage.setItem(name, JSON.stringify(encoded));
|
|
@@ -555,8 +626,9 @@ class TinyLocalStorage {
|
|
|
555
626
|
* @param {symbol} data
|
|
556
627
|
*/
|
|
557
628
|
setSymbol(name, data) {
|
|
629
|
+
this.#isProtectedDbKey(name);
|
|
558
630
|
if (typeof data !== 'symbol')
|
|
559
|
-
throw new
|
|
631
|
+
throw new TypeError('Value must be a Symbol.');
|
|
560
632
|
const encoded = this.#setJson(name, data);
|
|
561
633
|
this.emit('setSymbol', name, data);
|
|
562
634
|
return this.#localStorage.setItem(name, JSON.stringify(encoded));
|
|
@@ -586,8 +658,9 @@ class TinyLocalStorage {
|
|
|
586
658
|
* @param {any} data - The data to store.
|
|
587
659
|
*/
|
|
588
660
|
setItem(name, data) {
|
|
661
|
+
this.#isProtectedDbKey(name);
|
|
589
662
|
if (typeof name !== 'string' || !name.length)
|
|
590
|
-
throw new
|
|
663
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
591
664
|
this.emit('setItem', name, data);
|
|
592
665
|
return this.#localStorage.setItem(name, data);
|
|
593
666
|
}
|
|
@@ -599,7 +672,7 @@ class TinyLocalStorage {
|
|
|
599
672
|
*/
|
|
600
673
|
getItem(name) {
|
|
601
674
|
if (typeof name !== 'string' || !name.length)
|
|
602
|
-
throw new
|
|
675
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
603
676
|
return this.#localStorage.getItem(name);
|
|
604
677
|
}
|
|
605
678
|
/**
|
|
@@ -609,10 +682,11 @@ class TinyLocalStorage {
|
|
|
609
682
|
* @param {string} data - The string to store.
|
|
610
683
|
*/
|
|
611
684
|
setString(name, data) {
|
|
685
|
+
this.#isProtectedDbKey(name);
|
|
612
686
|
if (typeof name !== 'string' || !name.length)
|
|
613
|
-
throw new
|
|
687
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
614
688
|
if (typeof data !== 'string')
|
|
615
|
-
throw new
|
|
689
|
+
throw new TypeError('Value must be a string.');
|
|
616
690
|
this.emit('setString', name, data);
|
|
617
691
|
return this.#localStorage.setItem(name, JSON.stringify({
|
|
618
692
|
__string__: true,
|
|
@@ -627,7 +701,7 @@ class TinyLocalStorage {
|
|
|
627
701
|
*/
|
|
628
702
|
getString(name) {
|
|
629
703
|
if (typeof name !== 'string' || !name.length)
|
|
630
|
-
throw new
|
|
704
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
631
705
|
let value = this.#localStorage.getItem(name);
|
|
632
706
|
try {
|
|
633
707
|
/** @type {{ value: string; __string__: boolean }} */
|
|
@@ -651,10 +725,11 @@ class TinyLocalStorage {
|
|
|
651
725
|
* @param {number} data - The number to store.
|
|
652
726
|
*/
|
|
653
727
|
setNumber(name, data) {
|
|
728
|
+
this.#isProtectedDbKey(name);
|
|
654
729
|
if (typeof name !== 'string' || !name.length)
|
|
655
|
-
throw new
|
|
730
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
656
731
|
if (typeof data !== 'number')
|
|
657
|
-
throw new
|
|
732
|
+
throw new TypeError('Value must be a number.');
|
|
658
733
|
this.emit('setNumber', name, data);
|
|
659
734
|
return this.#localStorage.setItem(name, String(data));
|
|
660
735
|
}
|
|
@@ -666,7 +741,7 @@ class TinyLocalStorage {
|
|
|
666
741
|
*/
|
|
667
742
|
getNumber(name) {
|
|
668
743
|
if (typeof name !== 'string' || !name.length)
|
|
669
|
-
throw new
|
|
744
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
670
745
|
/** @type {number|string|null} */
|
|
671
746
|
let number = this.#localStorage.getItem(name);
|
|
672
747
|
if (typeof number === 'number')
|
|
@@ -685,10 +760,11 @@ class TinyLocalStorage {
|
|
|
685
760
|
* @param {boolean} data - The boolean value to store.
|
|
686
761
|
*/
|
|
687
762
|
setBool(name, data) {
|
|
763
|
+
this.#isProtectedDbKey(name);
|
|
688
764
|
if (typeof name !== 'string' || !name.length)
|
|
689
|
-
throw new
|
|
765
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
690
766
|
if (typeof data !== 'boolean')
|
|
691
|
-
throw new
|
|
767
|
+
throw new TypeError('Value must be a boolean.');
|
|
692
768
|
this.emit('setBool', name, data);
|
|
693
769
|
return this.#localStorage.setItem(name, String(data));
|
|
694
770
|
}
|
|
@@ -700,7 +776,7 @@ class TinyLocalStorage {
|
|
|
700
776
|
*/
|
|
701
777
|
getBool(name) {
|
|
702
778
|
if (typeof name !== 'string' || !name.length)
|
|
703
|
-
throw new
|
|
779
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
704
780
|
const value = this.#localStorage.getItem(name);
|
|
705
781
|
if (typeof value === 'boolean')
|
|
706
782
|
return value;
|
|
@@ -719,7 +795,7 @@ class TinyLocalStorage {
|
|
|
719
795
|
*/
|
|
720
796
|
removeItem(name) {
|
|
721
797
|
if (typeof name !== 'string' || !name.length)
|
|
722
|
-
throw new
|
|
798
|
+
throw new TypeError('Key must be a non-empty string.');
|
|
723
799
|
this.emit('removeItem', name);
|
|
724
800
|
return this.#localStorage.removeItem(name);
|
|
725
801
|
}
|
|
@@ -32,6 +32,59 @@ console.log(storage.getDate('today') instanceof Date); // true
|
|
|
32
32
|
|
|
33
33
|
---
|
|
34
34
|
|
|
35
|
+
## 🏁 `constructor(dbName?: string)`
|
|
36
|
+
|
|
37
|
+
Initializes the `TinyLocalStorage` instance and sets up cross-tab synchronization.
|
|
38
|
+
|
|
39
|
+
### 🔧 Parameters
|
|
40
|
+
|
|
41
|
+
* `dbName` (optional, `string`) – A unique name for the database. It becomes the base key used internally in `localStorage`.
|
|
42
|
+
|
|
43
|
+
### 📡 Behavior
|
|
44
|
+
|
|
45
|
+
* Automatically adds a `storage` event listener to support syncing across browser tabs.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 🔁 `updateStorageVersion(version: number, onUpgrade: (oldVersion: number, newVersion: number) => void)`
|
|
50
|
+
|
|
51
|
+
Updates the version of the database. If the new version is higher than the current one, it triggers the provided migration callback.
|
|
52
|
+
|
|
53
|
+
### 🔧 Parameters
|
|
54
|
+
|
|
55
|
+
* `version` (`number`) – The desired new version of the database. Must be a positive integer.
|
|
56
|
+
* `onUpgrade` (`function`) – A callback function executed during upgrade. Receives `oldVersion` and `newVersion` as arguments.
|
|
57
|
+
|
|
58
|
+
### ⚠️ Throws
|
|
59
|
+
|
|
60
|
+
* `Error` – If the database key hasn't been initialized via the constructor.
|
|
61
|
+
* `TypeError` – If `version` is invalid (not a number, NaN, or < 1).
|
|
62
|
+
* `TypeError` – If `onUpgrade` is not a function.
|
|
63
|
+
* `TypeError` – If the saved version in `localStorage` is invalid.
|
|
64
|
+
* `Error` – If the provided `version` is lower than the stored version (downgrade is not supported).
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 🔑 `getDbKey(): string | null`
|
|
69
|
+
|
|
70
|
+
Returns the current internal database key used in `localStorage`.
|
|
71
|
+
|
|
72
|
+
### 🔙 Returns
|
|
73
|
+
|
|
74
|
+
* `string | null` – The full storage key prefix (e.g. `LSDB::yourDbName`), or `null` if uninitialized.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## 🧮 `getVersion(): number`
|
|
79
|
+
|
|
80
|
+
Returns the current active version of the storage system.
|
|
81
|
+
|
|
82
|
+
### 🔙 Returns
|
|
83
|
+
|
|
84
|
+
* `number` – The version number currently in use.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
35
88
|
## 📦 Storage Methods
|
|
36
89
|
|
|
37
90
|
### `setJson(key, data)`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tiny-essentials",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.3",
|
|
4
4
|
"description": "Collection of small, essential scripts designed to be used across various projects. These simple utilities are crafted for speed, ease of use, and versatility.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "npm run test:mjs && npm run test:cjs && npm run test:js",
|