diff --git a/lib/sessionManager/index.ts b/lib/sessionManager/index.ts index 90c7384..de392b6 100644 --- a/lib/sessionManager/index.ts +++ b/lib/sessionManager/index.ts @@ -13,8 +13,8 @@ export const storageSettings: StorageSettingsType = { maxLength: 2000, }; -export { MemoryStorage } from "./stores/memory.ts"; -export { ChromeStore } from "./stores/chromeStore.ts"; -export { ExpoSecureStore } from "./stores/expoSecureStore.ts"; +export { MemoryStorage } from "./stores/memory.js"; +export { ChromeStore } from "./stores/chromeStore.js"; +export { ExpoSecureStore } from "./stores/expoSecureStore.js"; export { LocalStorage } from "./stores/localStorage.ts"; -export * from "./types.ts"; +export { type SessionManager, StorageKeys } from "./types.ts"; diff --git a/lib/sessionManager/stores/chromeStore.test.ts b/lib/sessionManager/stores/chromeStore.test.ts index 0fbeb98..ad2f751 100644 --- a/lib/sessionManager/stores/chromeStore.test.ts +++ b/lib/sessionManager/stores/chromeStore.test.ts @@ -43,6 +43,19 @@ describe.skip("GoogleStorage standard keys", () => { await sessionManager.getSessionItem(StorageKeys.accessToken), ).toBeNull(); }); + + it("should set many items", async () => { + await sessionManager.setItems({ + [StorageKeys.accessToken]: "accessTokenValue", + [StorageKeys.idToken]: "idTokenValue", + }); + expect(await sessionManager.getSessionItem(StorageKeys.accessToken)).toBe( + "accessTokenValue", + ); + expect(await sessionManager.getSessionItem(StorageKeys.idToken)).toBe( + "idTokenValue", + ); + }); }); // TODO: Fix tests, need to mock chrome storage diff --git a/lib/sessionManager/stores/chromeStore.ts b/lib/sessionManager/stores/chromeStore.ts index 62f3b44..6f00bf2 100644 --- a/lib/sessionManager/stores/chromeStore.ts +++ b/lib/sessionManager/stores/chromeStore.ts @@ -1,5 +1,5 @@ import { storageSettings } from "../index.js"; -import { StorageKeys, type SessionManager } from "../types.js"; +import { SessionBase, StorageKeys, type SessionManager } from "../types.js"; import { splitString } from "../utils.js"; function getStorageValue(key: string): unknown | undefined { @@ -18,7 +18,10 @@ function getStorageValue(key: string): unknown | undefined { * Provides a chrome.store.local based session manager implementation for the browser. * @class ChromeStore */ -export class ChromeStore implements SessionManager { +export class ChromeStore + extends SessionBase + implements SessionManager +{ /** * Clears all items from session store. * @returns {void} diff --git a/lib/sessionManager/stores/expoSecureStore.test.ts b/lib/sessionManager/stores/expoSecureStore.test.ts index 07a08e3..50a6ceb 100644 --- a/lib/sessionManager/stores/expoSecureStore.test.ts +++ b/lib/sessionManager/stores/expoSecureStore.test.ts @@ -43,6 +43,19 @@ describe.skip("ExpoSecureStore standard keys", () => { await sessionManager.getSessionItem(StorageKeys.accessToken), ).toBeNull(); }); + + it("should set many items", async () => { + await sessionManager.setItems({ + [StorageKeys.accessToken]: "accessTokenValue", + [StorageKeys.idToken]: "idTokenValue", + }); + expect(await sessionManager.getSessionItem(StorageKeys.accessToken)).toBe( + "accessTokenValue", + ); + expect(await sessionManager.getSessionItem(StorageKeys.idToken)).toBe( + "idTokenValue", + ); + }); }); describe.skip("ExpoSecureStore keys: storageKeys", () => { diff --git a/lib/sessionManager/stores/expoSecureStore.ts b/lib/sessionManager/stores/expoSecureStore.ts index 958b0e2..7cc6e07 100644 --- a/lib/sessionManager/stores/expoSecureStore.ts +++ b/lib/sessionManager/stores/expoSecureStore.ts @@ -1,5 +1,5 @@ import { storageSettings } from "../index.js"; -import { StorageKeys, type SessionManager } from "../types.js"; +import { SessionBase, StorageKeys } from "../types.js"; import { splitString } from "../utils.js"; let expoSecureStore: typeof import("expo-secure-store") | undefined = undefined; @@ -16,8 +16,11 @@ async function waitForExpoSecureStore() { * Provides a expo local store based session manager implementation for the browser. * @class ExpoSecureStore */ -export class ExpoSecureStore implements SessionManager { +export class ExpoSecureStore< + V extends string = StorageKeys, +> extends SessionBase { constructor() { + super(); this.loadExpoStore(); } diff --git a/lib/sessionManager/stores/localStorage.test.ts b/lib/sessionManager/stores/localStorage.test.ts index c7d91c8..3e6ab1c 100644 --- a/lib/sessionManager/stores/localStorage.test.ts +++ b/lib/sessionManager/stores/localStorage.test.ts @@ -34,7 +34,6 @@ describe("LocalStorage standard keys", () => { }); it("should set and get an item in session storage", async () => { - console.log("here"); await sessionManager.setSessionItem(StorageKeys.accessToken, "testValue"); expect(await sessionManager.getSessionItem(StorageKeys.accessToken)).toBe( "testValue", diff --git a/lib/sessionManager/stores/localStorage.ts b/lib/sessionManager/stores/localStorage.ts index 3b93fae..52005d8 100644 --- a/lib/sessionManager/stores/localStorage.ts +++ b/lib/sessionManager/stores/localStorage.ts @@ -1,24 +1,28 @@ import { storageSettings } from "../index.js"; -import { StorageKeys, type SessionManager } from "../types.js"; +import { SessionBase, StorageKeys, type SessionManager } from "../types.js"; import { splitString } from "../utils.js"; /** * Provides a localStorage based session manager implementation for the browser. * @class LocalStorage */ -export class LocalStorage implements SessionManager { +export class LocalStorage + extends SessionBase + implements SessionManager +{ constructor() { + super(); console.warn("LocalStorage store should not be used in production"); } - setItems: Set = new Set(); + private internalItems: Set = new Set(); /** * Clears all items from session store. * @returns {void} */ async destroySession(): Promise { - this.setItems.forEach((key) => { + this.internalItems.forEach((key) => { this.removeSessionItem(key); }); } @@ -35,7 +39,7 @@ export class LocalStorage implements SessionManager { ): Promise { // clear items first await this.removeSessionItem(itemKey); - this.setItems.add(itemKey); + this.internalItems.add(itemKey); if (typeof itemValue === "string") { splitString(itemValue, storageSettings.maxLength).forEach( @@ -97,6 +101,6 @@ export class LocalStorage implements SessionManager { index++; } - this.setItems.delete(itemKey); + this.internalItems.delete(itemKey); } } diff --git a/lib/sessionManager/stores/memory.test.ts b/lib/sessionManager/stores/memory.test.ts index 010c74e..9edadbd 100644 --- a/lib/sessionManager/stores/memory.test.ts +++ b/lib/sessionManager/stores/memory.test.ts @@ -43,6 +43,19 @@ describe("MemoryStorage standard keys", () => { await sessionManager.getSessionItem(StorageKeys.accessToken), ).toBeNull(); }); + + it("should set many items", async () => { + await sessionManager.setItems({ + [StorageKeys.accessToken]: "accessTokenValue", + [StorageKeys.idToken]: "idTokenValue", + }); + expect(await sessionManager.getSessionItem(StorageKeys.accessToken)).toBe( + "accessTokenValue", + ); + expect(await sessionManager.getSessionItem(StorageKeys.idToken)).toBe( + "idTokenValue", + ); + }); }); describe("MemoryStorage keys: storageKeys", () => { diff --git a/lib/sessionManager/stores/memory.ts b/lib/sessionManager/stores/memory.ts index eb78377..e133351 100644 --- a/lib/sessionManager/stores/memory.ts +++ b/lib/sessionManager/stores/memory.ts @@ -1,12 +1,15 @@ import { storageSettings } from "../index.js"; -import { StorageKeys, type SessionManager } from "../types.js"; +import { SessionBase, StorageKeys, type SessionManager } from "../types.js"; import { splitString } from "../utils.js"; /** * Provides a memory based session manager implementation for the browser. * @class MemoryStorage */ -export class MemoryStorage implements SessionManager { +export class MemoryStorage + extends SessionBase + implements SessionManager +{ private memCache: Record = {}; /** diff --git a/lib/sessionManager/types.ts b/lib/sessionManager/types.ts index e028df6..ceaf89a 100644 --- a/lib/sessionManager/types.ts +++ b/lib/sessionManager/types.ts @@ -18,7 +18,31 @@ export type StorageSettingsType = { maxLength: number; }; -export interface SessionManager { +export abstract class SessionBase + implements SessionManager +{ + abstract getSessionItem( + itemKey: V | StorageKeys, + ): Awaitable; + abstract setSessionItem( + itemKey: V | StorageKeys, + itemValue: T, + ): Awaitable; + abstract removeSessionItem(itemKey: V | StorageKeys): Awaitable; + abstract destroySession(): Awaitable; + + async setItems(items: Partial>): Awaitable { + await Promise.all( + (Object.entries(items) as [V | StorageKeys, unknown][]).map( + ([key, value]) => { + return this.setSessionItem(key, value); + }, + ), + ); + } +} + +export interface SessionManager { /** * * Gets the item for the provided key from the storage. @@ -49,4 +73,11 @@ export interface SessionManager { * Destroys the session */ destroySession: () => Awaitable; + + /** + * Sets multiple items simultaneously. + * @param {Record} items - Object containing key-value pairs to store + * @returns {Promise} + */ + setItems(items: Partial>): Awaitable; }