Skip to content

Commit 38707bf

Browse files
committed
feat: added localStorage store
1 parent 375a260 commit 38707bf

File tree

3 files changed

+245
-3
lines changed

3 files changed

+245
-3
lines changed

lib/sessionManager/index.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ export const storageSettings: StorageSettingsType = {
1313
maxLength: 2000,
1414
};
1515

16-
export { MemoryStorage } from "./stores/memory.js";
17-
export { ChromeStore } from "./stores/chromeStore.js";
18-
export { ExpoSecureStore } from "./stores/expoSecureStore.js";
16+
export { MemoryStorage } from "./stores/memory.ts";
17+
export { ChromeStore } from "./stores/chromeStore.ts";
18+
export { ExpoSecureStore } from "./stores/expoSecureStore.ts";
19+
export { LocalStorage } from "./stores/localStorage.ts";
1920
export * from "./types.ts";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import { describe, it, expect, beforeEach, vi } from "vitest";
2+
import { LocalStorage } from "./localStorage";
3+
import { StorageKeys } from "../types";
4+
5+
enum ExtraKeys {
6+
testKey = "testKey2",
7+
}
8+
9+
const localStorageMock = (function () {
10+
let store: { [key: string]: string } = {};
11+
12+
return {
13+
getItem(key: string) {
14+
return store[key] || null;
15+
},
16+
setItem(key: string, value: string) {
17+
store[key] = String(value);
18+
},
19+
removeItem(key: string) {
20+
delete store[key];
21+
},
22+
clear() {
23+
store = {};
24+
},
25+
};
26+
})();
27+
vi.stubGlobal("localStorage", localStorageMock);
28+
29+
describe("LocalStorage standard keys", () => {
30+
let sessionManager: LocalStorage;
31+
32+
beforeEach(() => {
33+
sessionManager = new LocalStorage();
34+
});
35+
36+
it("should set and get an item in session storage", async () => {
37+
console.log("here");
38+
await sessionManager.setSessionItem(StorageKeys.accessToken, "testValue");
39+
expect(await sessionManager.getSessionItem(StorageKeys.accessToken)).toBe(
40+
"testValue",
41+
);
42+
});
43+
44+
it("should remove an item from session storage", async () => {
45+
await sessionManager.setSessionItem(StorageKeys.accessToken, "testValue");
46+
expect(await sessionManager.getSessionItem(StorageKeys.accessToken)).toBe(
47+
"testValue",
48+
);
49+
50+
await sessionManager.removeSessionItem(StorageKeys.accessToken);
51+
expect(
52+
await sessionManager.getSessionItem(StorageKeys.accessToken),
53+
).toBeNull();
54+
});
55+
56+
it("should clear all items from session storage", async () => {
57+
await sessionManager.setSessionItem(StorageKeys.accessToken, "testValue");
58+
expect(await sessionManager.getSessionItem(StorageKeys.accessToken)).toBe(
59+
"testValue",
60+
);
61+
sessionManager.destroySession();
62+
expect(
63+
await sessionManager.getSessionItem(StorageKeys.accessToken),
64+
).toBeNull();
65+
});
66+
67+
it("should clear all items from session storage", async () => {
68+
await sessionManager.setSessionItem(StorageKeys.accessToken, true);
69+
expect(await sessionManager.getSessionItem(StorageKeys.accessToken)).toBe(
70+
"true",
71+
);
72+
sessionManager.destroySession();
73+
expect(
74+
await sessionManager.getSessionItem(StorageKeys.accessToken),
75+
).toBeNull();
76+
});
77+
});
78+
79+
describe("LocalStorage keys: storageKeys", () => {
80+
let sessionManager: LocalStorage<ExtraKeys>;
81+
82+
beforeEach(() => {
83+
sessionManager = new LocalStorage<ExtraKeys>();
84+
});
85+
86+
it("should set and get an item in storage: StorageKeys", async () => {
87+
await sessionManager.setSessionItem(StorageKeys.accessToken, "testValue");
88+
expect(await sessionManager.getSessionItem(StorageKeys.accessToken)).toBe(
89+
"testValue",
90+
);
91+
});
92+
93+
it("should remove an item from storage: StorageKeys", async () => {
94+
await sessionManager.setSessionItem(StorageKeys.accessToken, "testValue");
95+
expect(await sessionManager.getSessionItem(StorageKeys.accessToken)).toBe(
96+
"testValue",
97+
);
98+
99+
await sessionManager.removeSessionItem(StorageKeys.accessToken);
100+
expect(
101+
await sessionManager.getSessionItem(StorageKeys.accessToken),
102+
).toBeNull();
103+
});
104+
105+
it("should clear all items from storage: StorageKeys", async () => {
106+
await sessionManager.setSessionItem(StorageKeys.accessToken, "testValue");
107+
expect(await sessionManager.getSessionItem(StorageKeys.accessToken)).toBe(
108+
"testValue",
109+
);
110+
111+
sessionManager.destroySession();
112+
expect(
113+
await sessionManager.getSessionItem(StorageKeys.accessToken),
114+
).toBeNull();
115+
});
116+
117+
it("should set and get an item in extra storage", async () => {
118+
await sessionManager.setSessionItem(ExtraKeys.testKey, "testValue");
119+
expect(await sessionManager.getSessionItem(ExtraKeys.testKey)).toBe(
120+
"testValue",
121+
);
122+
});
123+
124+
it("should remove an item from extra storage", async () => {
125+
await sessionManager.setSessionItem(ExtraKeys.testKey, "testValue");
126+
expect(await sessionManager.getSessionItem(ExtraKeys.testKey)).toBe(
127+
"testValue",
128+
);
129+
130+
sessionManager.removeSessionItem(ExtraKeys.testKey);
131+
expect(await sessionManager.getSessionItem(ExtraKeys.testKey)).toBeNull();
132+
});
133+
134+
it("should clear all items from extra storage", async () => {
135+
await sessionManager.setSessionItem(ExtraKeys.testKey, "testValue");
136+
expect(await sessionManager.getSessionItem(ExtraKeys.testKey)).toBe(
137+
"testValue",
138+
);
139+
140+
sessionManager.destroySession();
141+
expect(await sessionManager.getSessionItem(ExtraKeys.testKey)).toBeNull();
142+
});
143+
});
+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import { storageSettings } from "../index.js";
2+
import { StorageKeys, type SessionManager } from "../types.js";
3+
import { splitString } from "../utils.js";
4+
5+
/**
6+
* Provides a localStorage based session manager implementation for the browser.
7+
* @class LocalStorage
8+
*/
9+
export class LocalStorage<V = StorageKeys> implements SessionManager<V> {
10+
setItems: Set<V | StorageKeys> = new Set<V>();
11+
12+
/**
13+
* Clears all items from session store.
14+
* @returns {void}
15+
*/
16+
async destroySession(): Promise<void> {
17+
this.setItems.forEach((key) => {
18+
this.removeSessionItem(key);
19+
});
20+
}
21+
22+
/**
23+
* Sets the provided key-value store to the localStorage cache.
24+
* @param {V} itemKey
25+
* @param {unknown} itemValue
26+
* @returns {void}
27+
*/
28+
async setSessionItem(
29+
itemKey: V | StorageKeys,
30+
itemValue: unknown,
31+
): Promise<void> {
32+
// clear items first
33+
await this.removeSessionItem(itemKey);
34+
this.setItems.add(itemKey);
35+
36+
if (typeof itemValue === "string") {
37+
splitString(itemValue, storageSettings.maxLength).forEach(
38+
(splitValue, index) => {
39+
localStorage.setItem(
40+
`${storageSettings.keyPrefix}${itemKey}${index}`,
41+
splitValue,
42+
);
43+
},
44+
);
45+
return;
46+
}
47+
localStorage.setItem(
48+
`${storageSettings.keyPrefix}${itemKey}0`,
49+
itemValue as string,
50+
);
51+
}
52+
53+
/**
54+
* Gets the item for the provided key from the localStorage cache.
55+
* @param {string} itemKey
56+
* @returns {unknown | null}
57+
*/
58+
async getSessionItem(itemKey: V | StorageKeys): Promise<unknown | null> {
59+
if (
60+
localStorage.getItem(`${storageSettings.keyPrefix}${itemKey}0`) === null
61+
) {
62+
return null;
63+
}
64+
65+
let itemValue = "";
66+
let index = 0;
67+
let key = `${storageSettings.keyPrefix}${String(itemKey)}${index}`;
68+
while (localStorage.getItem(key) !== null) {
69+
itemValue += localStorage.getItem(key);
70+
index++;
71+
key = `${storageSettings.keyPrefix}${String(itemKey)}${index}`;
72+
}
73+
74+
return itemValue;
75+
}
76+
77+
/**
78+
* Removes the item for the provided key from the localStorage cache.
79+
* @param {V} itemKey
80+
* @returns {void}
81+
*/
82+
async removeSessionItem(itemKey: V | StorageKeys): Promise<void> {
83+
// Remove all items with the key prefix
84+
let index = 0;
85+
while (
86+
localStorage.getItem(
87+
`${storageSettings.keyPrefix}${String(itemKey)}${index}`,
88+
) !== null
89+
) {
90+
localStorage.removeItem(
91+
`${storageSettings.keyPrefix}${String(itemKey)}${index}`,
92+
);
93+
94+
index++;
95+
}
96+
this.setItems.delete(itemKey);
97+
}
98+
}

0 commit comments

Comments
 (0)