├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .gitignore
├── LICENSE
├── README.md
├── babel.config.js
├── dist
├── README.md
├── index.d.ts
├── index.js
├── index.js.map
├── lib
│ ├── vault.d.ts
│ ├── vault.js
│ ├── vault.js.map
│ ├── vault.min.js
│ └── vault.min.js.map
└── package.json
├── package-lock.json
├── package.json
├── src
├── index.ts
└── lib
│ ├── vault.test.ts
│ └── vault.ts
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "parser": "@typescript-eslint/parser",
4 | "plugins": ["@typescript-eslint"],
5 | "extends": [
6 | "eslint:recommended",
7 | "plugin:@typescript-eslint/eslint-recommended",
8 | "plugin:@typescript-eslint/recommended"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | npm-debug.log
3 | .DS_Store
4 | Thumbs.db
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | LICENSE
2 |
3 | The MIT License
4 |
5 | Copyright (c) 2022 Ultimate Courses
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in
15 | all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | THE SOFTWARE.
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | 🔒 @ultimate/vault
3 |
4 |
5 |
6 | 1KB typed localStorage
and sessionStorage
utility with data structure and prefix support.
7 |
8 |
9 |
10 |
11 |
12 |
13 | ## Installation
14 |
15 | Install via `npm i @ultimate/vault`.
16 |
17 | ## Documentation
18 |
19 | _ESModule_: Import `Vault` into your TypeScript or JavaScript project and create a new instance:
20 |
21 | ```ts
22 | import { Vault } from '@ultimate/vault';
23 |
24 | const localStorage = new Vault();
25 | ```
26 |
27 | _Global_: Access `window.Vault` if you are not using a module system:
28 |
29 | ```html
30 |
31 |
35 | ```
36 |
37 | ### Local or Session Storage
38 |
39 | By default `new Vault()` will use `localStorage`. You may specify the type of storage:
40 |
41 | ```ts
42 | const localStorage = new Vault({ type: 'local' });
43 | const sessionStorage = new Vault({ type: 'session' });
44 | ```
45 |
46 | As `Vault` is a `class` each instance works independently.
47 |
48 | ### Key Prefixes
49 |
50 | Create a prefix for each `Vault` instance:
51 |
52 | ```ts
53 | const localStorage = new Vault({ prefix: 'x9ea45' });
54 | ```
55 |
56 | All keys set into storage via this instance will be stored as `x9ea45-`.
57 |
58 | ### isSupported property
59 |
60 | Browser support is IE8+ so this shouldn't be wildly needed, but it's there anyway:
61 |
62 | ```ts
63 | const localStorage = new Vault();
64 |
65 | if (localStorage.isSupported) {
66 | // initialize...
67 | }
68 | ```
69 |
70 | ### `set(key: string, value: T): void`
71 |
72 | Set a key and value into storage using the typed `set` method:
73 |
74 | ```ts
75 | // TypeScript
76 | const localStorage = new Vault();
77 |
78 | interface User {
79 | name: string
80 | }
81 |
82 | localStorage.set('user', { name: 'Todd Motto' });
83 | ```
84 |
85 | All methods are available to use without TypeScript:
86 |
87 | ```js
88 | const localStorage = new Vault();
89 |
90 | localStorage.set('user', { name: 'Todd Motto' });
91 | ```
92 |
93 | ### `get(key: string): T | undefined`
94 |
95 | Get a value from storage using the typed `get` method:
96 |
97 | ```ts
98 | const localStorage = new Vault();
99 |
100 | interface User {
101 | name: string
102 | }
103 |
104 | localStorage.get('user');
105 | ```
106 |
107 | ### `remove(key: string): void`
108 |
109 | Remove an item from storage using the `remove` method:
110 |
111 | ```ts
112 | const localStorage = new Vault();
113 |
114 | localStorage.remove('user');
115 | ```
116 |
117 | ### `removeAll(): void`
118 |
119 | Remove _all_ items from storage:
120 |
121 | ```ts
122 | const localStorage = new Vault();
123 |
124 | localStorage.removeAll();
125 | ```
126 |
127 | ### `onChange(key: string, fn: (e: StorageEvent) => void): () => void`
128 |
129 | Listen to the `storage` change event from another tab, which is emitted when any storage value is changed. Here we can specify to only listen to specific property changes:
130 |
131 | ```ts
132 | const localStorage = new Vault();
133 |
134 | const unsubscribe = localStorage.onChange('user', (e: StorageEvent) => {
135 | // `user` was changed in another tab
136 | // we could use this new data to sync our UI
137 | console.log(e);
138 | });
139 |
140 | // remove the event listener when you're ready
141 | unsubscribe();
142 | ```
143 |
144 | ### Get all values
145 |
146 | Obtain all storage values by accessing the `value` getter:
147 |
148 | ```ts
149 | const localStorage = new Vault();
150 |
151 | console.log(localStorage.value); // { "user": "Todd Motto", ... }
152 | ```
153 |
154 | Returns an object with all keys and values. Values will remain a `string` type and will need parsing with `JSON.parse()` if you need to access the value.
155 |
156 | ### Length of Storage
157 |
158 | Access how many items are currently in storage with `length`:
159 |
160 | ```ts
161 | const localStorage = new Vault();
162 |
163 | console.log(localStorage.length); // 3
164 | ```
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line
2 | module.exports = {
3 | presets: [
4 | ["@babel/preset-env", { targets: { node: "current" } }],
5 | "@babel/preset-typescript",
6 | ],
7 | };
8 |
--------------------------------------------------------------------------------
/dist/README.md:
--------------------------------------------------------------------------------
1 |
2 | 🔒 @ultimate/vault
3 |
4 |
5 |
6 | 1KB typed localStorage
and sessionStorage
utility with data structure and prefix support.
7 |
8 |
9 |
10 |
11 |
12 |
13 | ## Installation
14 |
15 | Install via `npm i @ultimate/vault`.
16 |
17 | ## Documentation
18 |
19 | _ESModule_: Import `Vault` into your TypeScript or JavaScript project and create a new instance:
20 |
21 | ```ts
22 | import { Vault } from '@ultimate/vault';
23 |
24 | const localStorage = new Vault();
25 | ```
26 |
27 | _Global_: Access `window.Vault` if you are not using a module system:
28 |
29 | ```html
30 |
31 |
35 | ```
36 |
37 | ### Local or Session Storage
38 |
39 | By default `new Vault()` will use `localStorage`. You may specify the type of storage:
40 |
41 | ```ts
42 | const localStorage = new Vault({ type: 'local' });
43 | const sessionStorage = new Vault({ type: 'session' });
44 | ```
45 |
46 | As `Vault` is a `class` each instance works independently.
47 |
48 | ### Key Prefixes
49 |
50 | Create a prefix for each `Vault` instance:
51 |
52 | ```ts
53 | const localStorage = new Vault({ prefix: 'x9ea45' });
54 | ```
55 |
56 | All keys set into storage via this instance will be stored as `x9ea45-`.
57 |
58 | ### isSupported property
59 |
60 | Browser support is IE8+ so this shouldn't be wildly needed, but it's there anyway:
61 |
62 | ```ts
63 | const localStorage = new Vault();
64 |
65 | if (localStorage.isSupported) {
66 | // initialize...
67 | }
68 | ```
69 |
70 | ### `set(key: string, value: T): void`
71 |
72 | Set a key and value into storage using the typed `set` method:
73 |
74 | ```ts
75 | // TypeScript
76 | const localStorage = new Vault();
77 |
78 | interface User {
79 | name: string
80 | }
81 |
82 | localStorage.set('user', { name: 'Todd Motto' });
83 | ```
84 |
85 | All methods are available to use without TypeScript:
86 |
87 | ```js
88 | const localStorage = new Vault();
89 |
90 | localStorage.set('user', { name: 'Todd Motto' });
91 | ```
92 |
93 | ### `get(key: string): T | undefined`
94 |
95 | Get a value from storage using the typed `get` method:
96 |
97 | ```ts
98 | const localStorage = new Vault();
99 |
100 | interface User {
101 | name: string
102 | }
103 |
104 | localStorage.get('user');
105 | ```
106 |
107 | ### `remove(key: string): void`
108 |
109 | Remove an item from storage using the `remove` method:
110 |
111 | ```ts
112 | const localStorage = new Vault();
113 |
114 | localStorage.remove('user');
115 | ```
116 |
117 | ### `removeAll(): void`
118 |
119 | Remove _all_ items from storage:
120 |
121 | ```ts
122 | const localStorage = new Vault();
123 |
124 | localStorage.removeAll();
125 | ```
126 |
127 | ### `onChange(key: string, fn: (e: StorageEvent) => void): () => void`
128 |
129 | Listen to the `storage` change event from another tab, which is emitted when any storage value is changed. Here we can specify to only listen to specific property changes:
130 |
131 | ```ts
132 | const localStorage = new Vault();
133 |
134 | const unsubscribe = localStorage.onChange('user', (e: StorageEvent) => {
135 | // `user` was changed in another tab
136 | // we could use this new data to sync our UI
137 | console.log(e);
138 | });
139 |
140 | // remove the event listener when you're ready
141 | unsubscribe();
142 | ```
143 |
144 | ### Get all values
145 |
146 | Obtain all storage values by accessing the `value` getter:
147 |
148 | ```ts
149 | const localStorage = new Vault();
150 |
151 | console.log(localStorage.value); // { "user": "Todd Motto", ... }
152 | ```
153 |
154 | Returns an object with all keys and values. Values will remain a `string` type and will need parsing with `JSON.parse()` if you need to access the value.
155 |
156 | ### Length of Storage
157 |
158 | Access how many items are currently in storage with `length`:
159 |
160 | ```ts
161 | const localStorage = new Vault();
162 |
163 | console.log(localStorage.length); // 3
164 | ```
--------------------------------------------------------------------------------
/dist/index.d.ts:
--------------------------------------------------------------------------------
1 | export * from './lib/vault';
2 |
--------------------------------------------------------------------------------
/dist/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3 | if (k2 === undefined) k2 = k;
4 | var desc = Object.getOwnPropertyDescriptor(m, k);
5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6 | desc = { enumerable: true, get: function() { return m[k]; } };
7 | }
8 | Object.defineProperty(o, k2, desc);
9 | }) : (function(o, m, k, k2) {
10 | if (k2 === undefined) k2 = k;
11 | o[k2] = m[k];
12 | }));
13 | var __exportStar = (this && this.__exportStar) || function(m, exports) {
14 | for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15 | };
16 | Object.defineProperty(exports, "__esModule", { value: true });
17 | __exportStar(require("./lib/vault"), exports);
18 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/dist/index.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8CAA4B"}
--------------------------------------------------------------------------------
/dist/lib/vault.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Vault instance options
3 | * `type`: Either localStorage or sessionStorage
4 | * `prefix`: Set all keys of the instance with a prefix
5 | */
6 | export interface VaultOptions {
7 | type?: 'local' | 'session';
8 | prefix?: string;
9 | }
10 | /**
11 | * Vault class to manage storage
12 | */
13 | export declare class Vault {
14 | /**
15 | * Internal store, either localStorage or sessionStorage
16 | */
17 | private store;
18 | /**
19 | * Default options for each instance
20 | */
21 | private options;
22 | /**
23 | * Specify a `type` or `prefix` when instantiating
24 | */
25 | constructor(options: VaultOptions);
26 | /**
27 | * isSupported getter that returns a boolean
28 | * @returns boolean
29 | */
30 | get isSupported(): boolean;
31 | /**
32 | * An object of all storage items
33 | * @returns { [name: string]: any }
34 | */
35 | get value(): {
36 | [name: string]: any;
37 | };
38 | /**
39 | * How many items are in the storage
40 | * @returns number
41 | */
42 | get length(): number;
43 | /**
44 | * Returns the prefixed key if required
45 | * @returns string
46 | */
47 | private getKey;
48 | /**
49 | * Set a data structure to storage
50 | * @param key The key name to set, excluding the prefix
51 | * @param value Any non-function value (strings, numbers, booleans, arrays, objects)
52 | * @returns void
53 | */
54 | set(key: string, value: T): void;
55 | /**
56 | * Get an item from storage
57 | * @param key The key name to get, excluding the prefix
58 | * @returns The typed item or undefined if not found
59 | */
60 | get(key: string): T | undefined;
61 | /**
62 | * Remove an item from storaage
63 | * @param key The key name to get, excluding the prefix
64 | * @returns void
65 | */
66 | remove(key: string): void;
67 | /**
68 | * Remove all items from storage
69 | * @returns void
70 | */
71 | removeAll(): void;
72 | /**
73 | *
74 | * @param key The key name to listen for, excluding the prefix
75 | * @param fn Callback function on key's value change
76 | * @returns function to remove the event listener
77 | */
78 | onChange(key: string, fn: (e: StorageEvent) => void): () => void;
79 | }
80 |
--------------------------------------------------------------------------------
/dist/lib/vault.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __assign = (this && this.__assign) || function () {
3 | __assign = Object.assign || function(t) {
4 | for (var s, i = 1, n = arguments.length; i < n; i++) {
5 | s = arguments[i];
6 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7 | t[p] = s[p];
8 | }
9 | return t;
10 | };
11 | return __assign.apply(this, arguments);
12 | };
13 | Object.defineProperty(exports, "__esModule", { value: true });
14 | exports.Vault = void 0;
15 | /**
16 | * Vault class to manage storage
17 | */
18 | var Vault = /** @class */ (function () {
19 | /**
20 | * Specify a `type` or `prefix` when instantiating
21 | */
22 | function Vault(options) {
23 | /**
24 | * Default options for each instance
25 | */
26 | this.options = {
27 | type: 'local',
28 | prefix: '',
29 | };
30 | this.options = __assign(__assign({}, this.options), options);
31 | /* eslint-disable @typescript-eslint/no-explicit-any */
32 | this.store = window["".concat(this.options.type, "Storage")];
33 | }
34 | Object.defineProperty(Vault.prototype, "isSupported", {
35 | /**
36 | * isSupported getter that returns a boolean
37 | * @returns boolean
38 | */
39 | get: function () {
40 | return typeof Storage === 'function';
41 | },
42 | enumerable: false,
43 | configurable: true
44 | });
45 | Object.defineProperty(Vault.prototype, "value", {
46 | /**
47 | * An object of all storage items
48 | * @returns { [name: string]: any }
49 | */
50 | get: function () {
51 | return __assign({}, this.store);
52 | },
53 | enumerable: false,
54 | configurable: true
55 | });
56 | Object.defineProperty(Vault.prototype, "length", {
57 | /**
58 | * How many items are in the storage
59 | * @returns number
60 | */
61 | get: function () {
62 | return this.store.length;
63 | },
64 | enumerable: false,
65 | configurable: true
66 | });
67 | /**
68 | * Returns the prefixed key if required
69 | * @returns string
70 | */
71 | Vault.prototype.getKey = function (key) {
72 | if (this.options.prefix) {
73 | return "".concat(this.options.prefix, "-").concat(key);
74 | }
75 | return key;
76 | };
77 | /**
78 | * Set a data structure to storage
79 | * @param key The key name to set, excluding the prefix
80 | * @param value Any non-function value (strings, numbers, booleans, arrays, objects)
81 | * @returns void
82 | */
83 | Vault.prototype.set = function (key, value) {
84 | try {
85 | this.store.setItem(this.getKey(key), JSON.stringify(value));
86 | }
87 | catch (e) {
88 | if (e instanceof DOMException) {
89 | throw new Error("[Vault] Storage limit exceeded: ".concat(e));
90 | }
91 | else {
92 | throw new Error("[Vault] Unknown error: ".concat(e));
93 | }
94 | }
95 | };
96 | /**
97 | * Get an item from storage
98 | * @param key The key name to get, excluding the prefix
99 | * @returns The typed item or undefined if not found
100 | */
101 | Vault.prototype.get = function (key) {
102 | try {
103 | var value = this.store.getItem(this.getKey(key));
104 | if (value) {
105 | return JSON.parse(value);
106 | }
107 | }
108 | catch (e) {
109 | throw new Error("[Vault] Error parsing key \"".concat(this.getKey(key), "\": ").concat(e));
110 | }
111 | };
112 | /**
113 | * Remove an item from storaage
114 | * @param key The key name to get, excluding the prefix
115 | * @returns void
116 | */
117 | Vault.prototype.remove = function (key) {
118 | this.store.removeItem(this.getKey(key));
119 | };
120 | /**
121 | * Remove all items from storage
122 | * @returns void
123 | */
124 | Vault.prototype.removeAll = function () {
125 | this.store.clear();
126 | };
127 | /**
128 | *
129 | * @param key The key name to listen for, excluding the prefix
130 | * @param fn Callback function on key's value change
131 | * @returns function to remove the event listener
132 | */
133 | Vault.prototype.onChange = function (key, fn) {
134 | var prop = this.getKey(key);
135 | var onChange = function (e) { return prop === e[prop] && fn(e); };
136 | window.addEventListener('storage', onChange);
137 | return function () { return window.removeEventListener('storage', onChange); };
138 | };
139 | return Vault;
140 | }());
141 | exports.Vault = Vault;
142 | /* eslint-disable @typescript-eslint/no-explicit-any */
143 | window.Vault = Vault;
144 | //# sourceMappingURL=vault.js.map
--------------------------------------------------------------------------------
/dist/lib/vault.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"vault.js","sourceRoot":"","sources":["../../src/lib/vault.ts"],"names":[],"mappings":"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"}
--------------------------------------------------------------------------------
/dist/lib/vault.min.js:
--------------------------------------------------------------------------------
1 | "use strict";var __assign=this&&this.__assign||function(){return(__assign=Object.assign||function(t){for(var e,o=1,r=arguments.length;o {
9 | let vault: Vault;
10 |
11 | beforeEach(() => {
12 | vault = new Vault();
13 | });
14 |
15 | test('Vault creates a new instance', () => {
16 | // .toBe versus .toEqual
17 | expect(vault instanceof Vault).toEqual(true);
18 | });
19 |
20 | test('Vault reports browser support', () => {
21 | expect(vault.isSupported).toEqual(true);
22 | });
23 | });
24 |
25 | describe('Storage Types and Prefixes', () => {
26 | test('Defaults to window.localStorage', () => {
27 | const spy = jest.spyOn(Object.getPrototypeOf(localStorage), 'setItem'); // Storage.prototype
28 |
29 | const vault = new Vault({ type: 'local' });
30 | vault.set('x', 'y');
31 |
32 | expect(JSON.parse(localStorage.getItem('x') as string)).toEqual('y');
33 | expect(spy).toHaveBeenCalledWith('x', JSON.stringify('y'));
34 | });
35 |
36 | test('Defaults to window.sessionStorage', () => {
37 | const spy = jest.spyOn(Object.getPrototypeOf(sessionStorage), 'setItem'); // Storage.prototype
38 |
39 | const vault = new Vault({ type: 'session' });
40 | vault.set('x', 'y');
41 |
42 | expect(JSON.parse(sessionStorage.getItem('x') as string)).toEqual('y');
43 | expect(spy).toHaveBeenCalledWith('x', JSON.stringify('y'));
44 | });
45 |
46 | test('Prefixes all Storage set and get', () => {
47 | const spy = jest.spyOn(Object.getPrototypeOf(localStorage), 'setItem'); // Storage.prototype
48 |
49 | const vault = new Vault({ prefix: 'x8k0zae' });
50 | vault.set('prefix', 1234);
51 |
52 | // raw localStorage
53 | expect(JSON.parse(localStorage.getItem('prefix') as string)).toBeNull();
54 | expect(
55 | JSON.parse(localStorage.getItem('x8k0zae-prefix') as string)
56 | ).toEqual(1234);
57 | expect(spy).toHaveBeenCalledWith('x8k0zae-prefix', JSON.stringify(1234));
58 |
59 | // vault abstraction
60 | expect(vault.get('prefix')).toEqual(1234);
61 | expect(vault.get('x8k0zae-prefix')).not.toBeDefined();
62 | });
63 | });
64 |
65 | describe('Public Methods and Properties', () => {
66 | let vault: Vault;
67 |
68 | beforeEach(() => {
69 | vault = new Vault();
70 | vault.removeAll();
71 | });
72 |
73 | describe('Value Property', () => {
74 | test('Returns all unserialized values as an object', () => {
75 | vault.set('a', 1);
76 | vault.set('b', 2);
77 | vault.set('c', 3);
78 | // toEqual vs toStrictEqual:
79 | // https://dev.to/thejaredwilcurt/why-you-should-never-use-tobe-in-jest-48ca
80 | expect(vault.value).toEqual({ a: '1', b: '2', c: '3' });
81 | });
82 | });
83 |
84 | describe('Set and Get API', () => {
85 | test('Handles basic data types', () => {
86 | vault.set('string', 'y');
87 | vault.set('number', 88);
88 | vault.set('boolean', true);
89 | vault.set('array', [1, 2, 3, 4, 5]);
90 | vault.set('object', { a: 123, b: [] });
91 |
92 | expect(vault.get('string')).toEqual('y');
93 | expect(vault.get('number')).toEqual(88);
94 | expect(vault.get('boolean')).toEqual(true);
95 | expect(vault.get('array')).toEqual([1, 2, 3, 4, 5]);
96 | expect(vault.get('object')).toEqual({ a: 123, b: [] });
97 | });
98 |
99 | test('Should reject and throw Function values', () => {
100 | // expect(() => vault.set('function', () => 1234)).toThrow();
101 | expect(() => vault.set('function', () => 1234)).toThrowError(
102 | 'Cannot set functions to Storage - "() => 1234"'
103 | );
104 | });
105 | });
106 |
107 | describe('Remove API', () => {
108 | test('Removes a single property', () => {
109 | vault.set('x', 1);
110 | vault.set('y', 2);
111 | vault.set('z', 3);
112 |
113 | vault.remove('y');
114 |
115 | expect(vault.get('x')).toEqual(1);
116 | expect(vault.get('y')).toBeUndefined();
117 | expect(vault.get('z')).toEqual(3);
118 | });
119 |
120 | test('Removes all properties', () => {
121 | vault.set('x', 1);
122 | vault.set('y', 2);
123 | vault.set('z', 3);
124 |
125 | vault.removeAll();
126 |
127 | expect(vault.get('x')).toBeUndefined();
128 | expect(vault.get('y')).toBeUndefined();
129 | expect(vault.get('z')).toBeUndefined();
130 | });
131 | });
132 |
133 | describe('Remove API', () => {
134 | beforeEach(() => {
135 | vault.removeAll();
136 | });
137 |
138 | test('Tracks the length of items stored', () => {
139 | vault.set('x', 1);
140 | expect(vault.length).toEqual(1);
141 | vault.set('y', 2);
142 | expect(vault.length).toEqual(2);
143 | vault.set('z', 3);
144 | expect(vault.length).toEqual(3);
145 | });
146 | });
147 | });
148 |
--------------------------------------------------------------------------------
/src/lib/vault.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Vault instance options
3 | * `type`: Either localStorage or sessionStorage
4 | * `prefix`: Set all keys of the instance with a prefix
5 | */
6 | export interface VaultOptions {
7 | type?: 'local' | 'session';
8 | prefix?: string;
9 | }
10 |
11 | /**
12 | * Vault class to manage storage
13 | */
14 | export class Vault {
15 | /**
16 | * Internal store, either localStorage or sessionStorage
17 | */
18 | private store: Storage;
19 |
20 | /**
21 | * Default options for each instance
22 | */
23 | private options: Required = {
24 | type: 'local',
25 | prefix: '',
26 | };
27 |
28 | /**
29 | * Specify a `type` or `prefix` when instantiating
30 | */
31 | constructor(options?: VaultOptions) {
32 | this.options = { ...this.options, ...options };
33 | /* eslint-disable @typescript-eslint/no-explicit-any */
34 | this.store = (window as any)[`${this.options.type}Storage`];
35 | }
36 |
37 | /**
38 | * isSupported getter that returns a boolean
39 | * @returns boolean
40 | */
41 | get isSupported(): boolean {
42 | return typeof Storage === 'function';
43 | }
44 |
45 | /**
46 | * An object of all storage items
47 | * @returns { [name: string]: any }
48 | */
49 | get value(): { [name: string]: any } {
50 | return { ...this.store };
51 | }
52 |
53 | /**
54 | * How many items are in the storage
55 | * @returns number
56 | */
57 | get length(): number {
58 | return this.store.length;
59 | }
60 |
61 | /**
62 | * Returns the prefixed key if required
63 | * @returns string
64 | */
65 | private getKey(key: string): string {
66 | if (this.options.prefix) {
67 | return `${this.options.prefix}-${key}`;
68 | }
69 | return key;
70 | }
71 |
72 | /**
73 | * Set a data structure to storage
74 | * @param key The key name to set, excluding the prefix
75 | * @param value Any non-function value (strings, numbers, booleans, arrays, objects)
76 | * @returns void
77 | */
78 | set(key: string, value: T): void {
79 | if (typeof value === 'function') {
80 | throw new Error(`Cannot set functions to Storage - "${value}"`);
81 | }
82 | try {
83 | this.store.setItem(this.getKey(key), JSON.stringify(value));
84 | } catch (e) {
85 | if (e instanceof DOMException) {
86 | throw new Error(`[Vault] Storage limit exceeded: ${e}`);
87 | } else {
88 | throw new Error(`[Vault] Unknown error: ${e}`);
89 | }
90 | }
91 | }
92 |
93 | /**
94 | * Get an item from storage
95 | * @param key The key name to get, excluding the prefix
96 | * @returns The typed item or undefined if not found
97 | */
98 | get(key: string): T | undefined {
99 | try {
100 | const value = this.store.getItem(this.getKey(key));
101 | if (value) {
102 | return JSON.parse(value) as T;
103 | }
104 | } catch (e) {
105 | throw new Error(`[Vault] Error parsing key "${this.getKey(key)}": ${e}`);
106 | }
107 | }
108 |
109 | /**
110 | * Remove an item from storaage
111 | * @param key The key name to get, excluding the prefix
112 | * @returns void
113 | */
114 | remove(key: string): void {
115 | this.store.removeItem(this.getKey(key));
116 | }
117 |
118 | /**
119 | * Remove all items from storage
120 | * @returns void
121 | */
122 | removeAll(): void {
123 | this.store.clear();
124 | }
125 |
126 | /**
127 | *
128 | * @param key The key name to listen for, excluding the prefix
129 | * @param fn Callback function on key's value change
130 | * @returns function to remove the event listener
131 | */
132 | onChange(key: string, fn: (e: StorageEvent) => void): () => void {
133 | const prop = this.getKey(key);
134 | const onChange = (e: StorageEvent) => prop === (e as any)[prop] && fn(e);
135 | window.addEventListener('storage', onChange);
136 | return () => window.removeEventListener('storage', onChange);
137 | }
138 | }
139 |
140 | /* eslint-disable @typescript-eslint/no-explicit-any */
141 | (window as any).Vault = Vault;
142 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES5",
4 | "lib": ["DOM", "ES5"],
5 | "module": "CommonJS",
6 | "moduleResolution": "node",
7 | "declaration": true,
8 | "sourceMap": true,
9 | "outDir": "./dist",
10 | "esModuleInterop": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "strict": true,
13 | "skipLibCheck": true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------