tiny-essentials 1.19.0 → 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.
@@ -9,6 +9,22 @@ const customEncoders = new Map();
9
9
  /** @type {Map<any, DecodeFn>} */
10
10
  const customDecoders = new Map();
11
11
 
12
+ /** @type {Set<any>} */
13
+ const customTypesFreezed = new Set([
14
+ 'string',
15
+ 'boolean',
16
+ 'number',
17
+ 'object',
18
+ 'array',
19
+ String,
20
+ Boolean,
21
+ Number,
22
+ Object,
23
+ Array,
24
+ BigInt,
25
+ Symbol,
26
+ ]);
27
+
12
28
  /**
13
29
  * A function that encodes a value into a serializable JSON-compatible format.
14
30
  *
@@ -280,26 +296,49 @@ class TinyLocalStorage {
280
296
 
281
297
  ///////////////////////////////////////////////////
282
298
 
299
+ /**
300
+ * Checks whether a JSON-serializable type is already registered.
301
+ *
302
+ * @param {any} type - The type identifier, which can be a string (e.g., `"bigint"`, `"symbol"`)
303
+ * or a reference to a class/constructor function.
304
+ * @returns {boolean} True if the type has both an encoder and decoder registered.
305
+ */
306
+ static hasJsonType(type) {
307
+ return (customEncoders.has(type) && customDecoders.has(type)) || customTypesFreezed.has(type);
308
+ }
309
+
283
310
  /**
284
311
  * Registers a new JSON-serializable type with its encoder and decoder.
285
312
  *
286
- * @param {any} type - The type or primitive type name (e.g. `"bigint"`, `"symbol"`, etc).
287
- * @param {EncodeFn} encodeFn - The function that encodes the value.
288
- * @param {DecodeFn} decodeFn - An object with `check` and `decode` methods for restoring the value.
313
+ * @param {any} type - The type identifier, which can be a string (e.g., `"bigint"`, `"symbol"`)
314
+ * or a reference to a class/constructor function.
315
+ * @param {EncodeFn} encodeFn - A function that receives a value of this type and returns a JSON-safe representation.
316
+ * @param {DecodeFn} decodeFn - An object with `check(value)` to identify this type and `decode(value)` to restore it.
317
+ * @param {boolean} [freezeType=false] - If true, prevents this type from being unregistered later.
318
+ * @throws {Error} Throws an error if the type is frozen and cannot be registered.
289
319
  */
290
- static registerJsonType(type, encodeFn, decodeFn) {
320
+ static registerJsonType(type, encodeFn, decodeFn, freezeType = false) {
321
+ if (customTypesFreezed.has(type))
322
+ throw new Error(`Cannot register type "${type}" because it is frozen.`);
291
323
  customEncoders.set(type, encodeFn);
292
324
  customDecoders.set(type, decodeFn);
325
+ if (freezeType) customTypesFreezed.add(type);
293
326
  }
294
327
 
295
328
  /**
296
- * Removes a previously registered custom type from the encoding/decoding system.
329
+ * Unregisters a previously registered custom type from the encoding/decoding system.
297
330
  *
298
- * @param {string} type - The primitive name or constructor reference used in registration.
331
+ * @param {any} type - The primitive name or constructor reference used in the registration.
332
+ * @returns {boolean} Returns true if the type existed and was removed, or false if it wasn't found.
333
+ * @throws {Error} Throws an error if the type is frozen and cannot be unregistered.
299
334
  */
300
335
  static deleteJsonType(type) {
301
- customEncoders.delete(type);
302
- customDecoders.delete(type);
336
+ if (customTypesFreezed.has(type))
337
+ throw new Error(`Cannot remove type "${type}" because it is frozen.`);
338
+ let isDeleted = false;
339
+ if (customEncoders.delete(type)) isDeleted = true;
340
+ if (customDecoders.delete(type)) isDeleted = true;
341
+ return isDeleted;
303
342
  }
304
343
 
305
344
  //////////////////////////////////////////////////////
@@ -446,7 +485,7 @@ class TinyLocalStorage {
446
485
  }
447
486
  const encoded = this.#setJson(name, data);
448
487
  this.emit('setJson', name, data);
449
- this.#localStorage.setItem(name, JSON.stringify(encoded));
488
+ return this.#localStorage.setItem(name, JSON.stringify(encoded));
450
489
  }
451
490
 
452
491
  /**
@@ -516,8 +555,8 @@ class TinyLocalStorage {
516
555
  setDate(name, data) {
517
556
  if (!(data instanceof Date)) throw new Error('Value must be a Date.');
518
557
  const encoded = this.#setJson(name, data);
519
- this.#localStorage.setItem(name, JSON.stringify(encoded));
520
558
  this.emit('setDate', name, data);
559
+ return this.#localStorage.setItem(name, JSON.stringify(encoded));
521
560
  }
522
561
 
523
562
  /**
@@ -538,8 +577,8 @@ class TinyLocalStorage {
538
577
  setRegExp(name, data) {
539
578
  if (!(data instanceof RegExp)) throw new Error('Value must be a RegExp.');
540
579
  const encoded = this.#setJson(name, data);
541
- this.#localStorage.setItem(name, JSON.stringify(encoded));
542
580
  this.emit('setRegExp', name, data);
581
+ return this.#localStorage.setItem(name, JSON.stringify(encoded));
543
582
  }
544
583
 
545
584
  /**
@@ -560,8 +599,8 @@ class TinyLocalStorage {
560
599
  setBigInt(name, data) {
561
600
  if (typeof data !== 'bigint') throw new Error('Value must be a BigInt.');
562
601
  const encoded = this.#setJson(name, data);
563
- this.#localStorage.setItem(name, JSON.stringify(encoded));
564
602
  this.emit('setBigInt', name, data);
603
+ return this.#localStorage.setItem(name, JSON.stringify(encoded));
565
604
  }
566
605
 
567
606
  /**
@@ -583,8 +622,8 @@ class TinyLocalStorage {
583
622
  setSymbol(name, data) {
584
623
  if (typeof data !== 'symbol') throw new Error('Value must be a Symbol.');
585
624
  const encoded = this.#setJson(name, data);
586
- this.#localStorage.setItem(name, JSON.stringify(encoded));
587
625
  this.emit('setSymbol', name, data);
626
+ return this.#localStorage.setItem(name, JSON.stringify(encoded));
588
627
  }
589
628
 
590
629
  /**
@@ -644,7 +683,13 @@ class TinyLocalStorage {
644
683
  if (typeof data !== 'string') throw new Error('Value must be a string.');
645
684
 
646
685
  this.emit('setString', name, data);
647
- return this.#localStorage.setItem(name, data);
686
+ return this.#localStorage.setItem(
687
+ name,
688
+ JSON.stringify({
689
+ __string__: true,
690
+ value: data,
691
+ }),
692
+ );
648
693
  }
649
694
 
650
695
  /**
@@ -657,6 +702,15 @@ class TinyLocalStorage {
657
702
  if (typeof name !== 'string' || !name.length)
658
703
  throw new Error('Key must be a non-empty string.');
659
704
  let value = this.#localStorage.getItem(name);
705
+ try {
706
+ /** @type {{ value: string; __string__: boolean }} */
707
+ // @ts-ignore
708
+ value = JSON.parse(value);
709
+ if (!objChecker.isJsonObject(value) || !value.__string__ || typeof value.value !== 'string') return null;
710
+ value = value.value;
711
+ } catch {
712
+ value = null;
713
+ }
660
714
  if (typeof value === 'string') return value;
661
715
  return null;
662
716
  }
@@ -746,7 +800,7 @@ class TinyLocalStorage {
746
800
  * Clears all data from `localStorage`.
747
801
  */
748
802
  clearLocalStorage() {
749
- this.#localStorage.clear();
803
+ return this.#localStorage.clear();
750
804
  }
751
805
 
752
806
  /**
@@ -773,6 +827,7 @@ TinyLocalStorage.registerJsonType(
773
827
  decode: (value, decodeSpecialJson) =>
774
828
  new Map(value.data.map(([k, v]) => [k, decodeSpecialJson(v)])),
775
829
  },
830
+ true,
776
831
  );
777
832
 
778
833
  // Set
@@ -786,6 +841,7 @@ TinyLocalStorage.registerJsonType(
786
841
  check: (value) => value.__set__,
787
842
  decode: (value, decodeSpecialJson) => new Set(value.data.map(decodeSpecialJson)),
788
843
  },
844
+ true,
789
845
  );
790
846
 
791
847
  // Date
@@ -799,6 +855,7 @@ TinyLocalStorage.registerJsonType(
799
855
  check: (value) => value.__date__,
800
856
  decode: (value) => new Date(value.value),
801
857
  },
858
+ true,
802
859
  );
803
860
 
804
861
  // Regex
@@ -813,6 +870,7 @@ TinyLocalStorage.registerJsonType(
813
870
  check: (value) => value.__regexp__,
814
871
  decode: (value) => new RegExp(value.source, value.flags),
815
872
  },
873
+ true,
816
874
  );
817
875
 
818
876
  // Big Int
@@ -826,6 +884,7 @@ TinyLocalStorage.registerJsonType(
826
884
  check: (value) => value.__bigint__,
827
885
  decode: (value) => BigInt(value.value),
828
886
  },
887
+ true,
829
888
  );
830
889
 
831
890
  // Symbol
@@ -842,6 +901,7 @@ TinyLocalStorage.registerJsonType(
842
901
  return key != null ? Symbol.for(key) : Symbol();
843
902
  },
844
903
  },
904
+ true,
845
905
  );
846
906
 
847
907
  module.exports = TinyLocalStorage;
@@ -101,20 +101,33 @@ export type LocalStorageJsonValue = (Record<string | number | symbol, any> | any
101
101
  * This class is suitable for applications that require structured persistence in the browser.
102
102
  */
103
103
  declare class TinyLocalStorage {
104
+ /**
105
+ * Checks whether a JSON-serializable type is already registered.
106
+ *
107
+ * @param {any} type - The type identifier, which can be a string (e.g., `"bigint"`, `"symbol"`)
108
+ * or a reference to a class/constructor function.
109
+ * @returns {boolean} True if the type has both an encoder and decoder registered.
110
+ */
111
+ static hasJsonType(type: any): boolean;
104
112
  /**
105
113
  * Registers a new JSON-serializable type with its encoder and decoder.
106
114
  *
107
- * @param {any} type - The type or primitive type name (e.g. `"bigint"`, `"symbol"`, etc).
108
- * @param {EncodeFn} encodeFn - The function that encodes the value.
109
- * @param {DecodeFn} decodeFn - An object with `check` and `decode` methods for restoring the value.
115
+ * @param {any} type - The type identifier, which can be a string (e.g., `"bigint"`, `"symbol"`)
116
+ * or a reference to a class/constructor function.
117
+ * @param {EncodeFn} encodeFn - A function that receives a value of this type and returns a JSON-safe representation.
118
+ * @param {DecodeFn} decodeFn - An object with `check(value)` to identify this type and `decode(value)` to restore it.
119
+ * @param {boolean} [freezeType=false] - If true, prevents this type from being unregistered later.
120
+ * @throws {Error} Throws an error if the type is frozen and cannot be registered.
110
121
  */
111
- static registerJsonType(type: any, encodeFn: EncodeFn, decodeFn: DecodeFn): void;
122
+ static registerJsonType(type: any, encodeFn: EncodeFn, decodeFn: DecodeFn, freezeType?: boolean): void;
112
123
  /**
113
- * Removes a previously registered custom type from the encoding/decoding system.
124
+ * Unregisters a previously registered custom type from the encoding/decoding system.
114
125
  *
115
- * @param {string} type - The primitive name or constructor reference used in registration.
126
+ * @param {any} type - The primitive name or constructor reference used in the registration.
127
+ * @returns {boolean} Returns true if the type existed and was removed, or false if it wasn't found.
128
+ * @throws {Error} Throws an error if the type is frozen and cannot be unregistered.
116
129
  */
117
- static deleteJsonType(type: string): void;
130
+ static deleteJsonType(type: any): boolean;
118
131
  static encodeSpecialJson(value: any): any;
119
132
  static decodeSpecialJson(value: any): any;
120
133
  /**
@@ -4,6 +4,21 @@ import TinyEvents from './TinyEvents.mjs';
4
4
  const customEncoders = new Map();
5
5
  /** @type {Map<any, DecodeFn>} */
6
6
  const customDecoders = new Map();
7
+ /** @type {Set<any>} */
8
+ const customTypesFreezed = new Set([
9
+ 'string',
10
+ 'boolean',
11
+ 'number',
12
+ 'object',
13
+ 'array',
14
+ String,
15
+ Boolean,
16
+ Number,
17
+ Object,
18
+ Array,
19
+ BigInt,
20
+ Symbol,
21
+ ]);
7
22
  /**
8
23
  * A function that encodes a value into a serializable JSON-compatible format.
9
24
  *
@@ -243,25 +258,50 @@ class TinyLocalStorage {
243
258
  return this.#events.getMaxListeners();
244
259
  }
245
260
  ///////////////////////////////////////////////////
261
+ /**
262
+ * Checks whether a JSON-serializable type is already registered.
263
+ *
264
+ * @param {any} type - The type identifier, which can be a string (e.g., `"bigint"`, `"symbol"`)
265
+ * or a reference to a class/constructor function.
266
+ * @returns {boolean} True if the type has both an encoder and decoder registered.
267
+ */
268
+ static hasJsonType(type) {
269
+ return (customEncoders.has(type) && customDecoders.has(type)) || customTypesFreezed.has(type);
270
+ }
246
271
  /**
247
272
  * Registers a new JSON-serializable type with its encoder and decoder.
248
273
  *
249
- * @param {any} type - The type or primitive type name (e.g. `"bigint"`, `"symbol"`, etc).
250
- * @param {EncodeFn} encodeFn - The function that encodes the value.
251
- * @param {DecodeFn} decodeFn - An object with `check` and `decode` methods for restoring the value.
274
+ * @param {any} type - The type identifier, which can be a string (e.g., `"bigint"`, `"symbol"`)
275
+ * or a reference to a class/constructor function.
276
+ * @param {EncodeFn} encodeFn - A function that receives a value of this type and returns a JSON-safe representation.
277
+ * @param {DecodeFn} decodeFn - An object with `check(value)` to identify this type and `decode(value)` to restore it.
278
+ * @param {boolean} [freezeType=false] - If true, prevents this type from being unregistered later.
279
+ * @throws {Error} Throws an error if the type is frozen and cannot be registered.
252
280
  */
253
- static registerJsonType(type, encodeFn, decodeFn) {
281
+ static registerJsonType(type, encodeFn, decodeFn, freezeType = false) {
282
+ if (customTypesFreezed.has(type))
283
+ throw new Error(`Cannot register type "${type}" because it is frozen.`);
254
284
  customEncoders.set(type, encodeFn);
255
285
  customDecoders.set(type, decodeFn);
286
+ if (freezeType)
287
+ customTypesFreezed.add(type);
256
288
  }
257
289
  /**
258
- * Removes a previously registered custom type from the encoding/decoding system.
290
+ * Unregisters a previously registered custom type from the encoding/decoding system.
259
291
  *
260
- * @param {string} type - The primitive name or constructor reference used in registration.
292
+ * @param {any} type - The primitive name or constructor reference used in the registration.
293
+ * @returns {boolean} Returns true if the type existed and was removed, or false if it wasn't found.
294
+ * @throws {Error} Throws an error if the type is frozen and cannot be unregistered.
261
295
  */
262
296
  static deleteJsonType(type) {
263
- customEncoders.delete(type);
264
- customDecoders.delete(type);
297
+ if (customTypesFreezed.has(type))
298
+ throw new Error(`Cannot remove type "${type}" because it is frozen.`);
299
+ let isDeleted = false;
300
+ if (customEncoders.delete(type))
301
+ isDeleted = true;
302
+ if (customDecoders.delete(type))
303
+ isDeleted = true;
304
+ return isDeleted;
265
305
  }
266
306
  //////////////////////////////////////////////////////
267
307
  /**
@@ -392,7 +432,7 @@ class TinyLocalStorage {
392
432
  }
393
433
  const encoded = this.#setJson(name, data);
394
434
  this.emit('setJson', name, data);
395
- this.#localStorage.setItem(name, JSON.stringify(encoded));
435
+ return this.#localStorage.setItem(name, JSON.stringify(encoded));
396
436
  }
397
437
  /**
398
438
  * Retrieves a value from `localStorage`.
@@ -454,8 +494,8 @@ class TinyLocalStorage {
454
494
  if (!(data instanceof Date))
455
495
  throw new Error('Value must be a Date.');
456
496
  const encoded = this.#setJson(name, data);
457
- this.#localStorage.setItem(name, JSON.stringify(encoded));
458
497
  this.emit('setDate', name, data);
498
+ return this.#localStorage.setItem(name, JSON.stringify(encoded));
459
499
  }
460
500
  /**
461
501
  * Retrieves a Date from localStorage.
@@ -475,8 +515,8 @@ class TinyLocalStorage {
475
515
  if (!(data instanceof RegExp))
476
516
  throw new Error('Value must be a RegExp.');
477
517
  const encoded = this.#setJson(name, data);
478
- this.#localStorage.setItem(name, JSON.stringify(encoded));
479
518
  this.emit('setRegExp', name, data);
519
+ return this.#localStorage.setItem(name, JSON.stringify(encoded));
480
520
  }
481
521
  /**
482
522
  * Retrieves a RegExp from localStorage.
@@ -496,8 +536,8 @@ class TinyLocalStorage {
496
536
  if (typeof data !== 'bigint')
497
537
  throw new Error('Value must be a BigInt.');
498
538
  const encoded = this.#setJson(name, data);
499
- this.#localStorage.setItem(name, JSON.stringify(encoded));
500
539
  this.emit('setBigInt', name, data);
540
+ return this.#localStorage.setItem(name, JSON.stringify(encoded));
501
541
  }
502
542
  /**
503
543
  * Retrieves a BigInt from localStorage.
@@ -518,8 +558,8 @@ class TinyLocalStorage {
518
558
  if (typeof data !== 'symbol')
519
559
  throw new Error('Value must be a Symbol.');
520
560
  const encoded = this.#setJson(name, data);
521
- this.#localStorage.setItem(name, JSON.stringify(encoded));
522
561
  this.emit('setSymbol', name, data);
562
+ return this.#localStorage.setItem(name, JSON.stringify(encoded));
523
563
  }
524
564
  /**
525
565
  * Retrieves a Symbol from localStorage.
@@ -574,7 +614,10 @@ class TinyLocalStorage {
574
614
  if (typeof data !== 'string')
575
615
  throw new Error('Value must be a string.');
576
616
  this.emit('setString', name, data);
577
- return this.#localStorage.setItem(name, data);
617
+ return this.#localStorage.setItem(name, JSON.stringify({
618
+ __string__: true,
619
+ value: data,
620
+ }));
578
621
  }
579
622
  /**
580
623
  * Retrieves a string value from `localStorage`.
@@ -586,6 +629,17 @@ class TinyLocalStorage {
586
629
  if (typeof name !== 'string' || !name.length)
587
630
  throw new Error('Key must be a non-empty string.');
588
631
  let value = this.#localStorage.getItem(name);
632
+ try {
633
+ /** @type {{ value: string; __string__: boolean }} */
634
+ // @ts-ignore
635
+ value = JSON.parse(value);
636
+ if (!isJsonObject(value) || !value.__string__ || typeof value.value !== 'string')
637
+ return null;
638
+ value = value.value;
639
+ }
640
+ catch {
641
+ value = null;
642
+ }
589
643
  if (typeof value === 'string')
590
644
  return value;
591
645
  return null;
@@ -673,7 +727,7 @@ class TinyLocalStorage {
673
727
  * Clears all data from `localStorage`.
674
728
  */
675
729
  clearLocalStorage() {
676
- this.#localStorage.clear();
730
+ return this.#localStorage.clear();
677
731
  }
678
732
  /**
679
733
  * Destroys the storage instance by removing the storage event listener.
@@ -692,7 +746,7 @@ TinyLocalStorage.registerJsonType(Map, (value, encodeSpecialJson) => ({
692
746
  check: (value) => value.__map__,
693
747
  /** @param {{ data: any[] }} value */
694
748
  decode: (value, decodeSpecialJson) => new Map(value.data.map(([k, v]) => [k, decodeSpecialJson(v)])),
695
- });
749
+ }, true);
696
750
  // Set
697
751
  TinyLocalStorage.registerJsonType(Set, (value, encodeSpecialJson) => ({
698
752
  __set__: true,
@@ -700,7 +754,7 @@ TinyLocalStorage.registerJsonType(Set, (value, encodeSpecialJson) => ({
700
754
  }), {
701
755
  check: (value) => value.__set__,
702
756
  decode: (value, decodeSpecialJson) => new Set(value.data.map(decodeSpecialJson)),
703
- });
757
+ }, true);
704
758
  // Date
705
759
  TinyLocalStorage.registerJsonType(Date, (value) => ({
706
760
  __date__: true,
@@ -708,7 +762,7 @@ TinyLocalStorage.registerJsonType(Date, (value) => ({
708
762
  }), {
709
763
  check: (value) => value.__date__,
710
764
  decode: (value) => new Date(value.value),
711
- });
765
+ }, true);
712
766
  // Regex
713
767
  TinyLocalStorage.registerJsonType(RegExp, (value) => ({
714
768
  __regexp__: true,
@@ -717,7 +771,7 @@ TinyLocalStorage.registerJsonType(RegExp, (value) => ({
717
771
  }), {
718
772
  check: (value) => value.__regexp__,
719
773
  decode: (value) => new RegExp(value.source, value.flags),
720
- });
774
+ }, true);
721
775
  // Big Int
722
776
  TinyLocalStorage.registerJsonType('bigint', (value) => ({
723
777
  __bigint__: true,
@@ -725,7 +779,7 @@ TinyLocalStorage.registerJsonType('bigint', (value) => ({
725
779
  }), {
726
780
  check: (value) => value.__bigint__,
727
781
  decode: (value) => BigInt(value.value),
728
- });
782
+ }, true);
729
783
  // Symbol
730
784
  TinyLocalStorage.registerJsonType('symbol', (value) => ({
731
785
  __symbol__: true,
@@ -736,5 +790,5 @@ TinyLocalStorage.registerJsonType('symbol', (value) => ({
736
790
  const key = value.key;
737
791
  return key != null ? Symbol.for(key) : Symbol();
738
792
  },
739
- });
793
+ }, true);
740
794
  export default TinyLocalStorage;
@@ -243,7 +243,7 @@ Returns `true` if the browser supports the configured storage backend.
243
243
 
244
244
  ## 🧩 Custom Type Registration
245
245
 
246
- ### `registerJsonType(type, encodeFn, decodeFn)`
246
+ ### `registerJsonType(type, encodeFn, decodeFn, freezeType?)`
247
247
 
248
248
  Registers support for custom types with encoder/decoder logic.
249
249
 
@@ -254,10 +254,15 @@ registerJsonType(
254
254
  decodeFn: {
255
255
  check: (value: any) => boolean,
256
256
  decode: (value: any, decodeSpecialJson: DecodeFn) => any
257
- }
257
+ },
258
+ freezeType?: boolean // default: false
258
259
  ): void
259
260
  ```
260
261
 
262
+ Registers a custom type by associating it with encoder and decoder logic. If `freezeType` is set to `true`, the type becomes immutable and cannot be unregistered or overwritten later.
263
+
264
+ > ⚠️ Throws an error if trying to register a type that is already frozen.
265
+
261
266
  ---
262
267
 
263
268
  ### `deleteJsonType(type)`
@@ -265,10 +270,24 @@ registerJsonType(
265
270
  Unregisters a previously registered custom type.
266
271
 
267
272
  ```ts
268
- deleteJsonType(type: any): void
273
+ deleteJsonType(type: any): boolean
274
+ ```
275
+
276
+ Removes the encoder and decoder associated with the given type. Returns `true` if the type was found and removed, or `false` if it was not registered.
277
+
278
+ > ❌ Throws an error if the type was marked as frozen via `freezeType`.
279
+
280
+ ---
281
+
282
+ ### `hasJsonType(type)`
283
+
284
+ Checks whether a type is currently registered for custom encoding/decoding.
285
+
286
+ ```ts
287
+ hasJsonType(type: any): boolean
269
288
  ```
270
289
 
271
- Removes the encoder and decoder associated with the given type. Useful for cleanup or reconfiguration.
290
+ Returns `true` if the type has both encoder and decoder registered, otherwise `false`.
272
291
 
273
292
  ---
274
293
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiny-essentials",
3
- "version": "1.19.0",
3
+ "version": "1.19.2",
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",