Skip to content

Commit

Permalink
Merge pull request #16 from kinde-oss/feat/storageSetItems
Browse files Browse the repository at this point in the history
feat: add setItems to storage
  • Loading branch information
DanielRivers authored Oct 25, 2024
2 parents 153dda5 + aa264e8 commit f379624
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 18 deletions.
8 changes: 4 additions & 4 deletions lib/sessionManager/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
13 changes: 13 additions & 0 deletions lib/sessionManager/stores/chromeStore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 5 additions & 2 deletions lib/sessionManager/stores/chromeStore.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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<V = StorageKeys> implements SessionManager<V> {
export class ChromeStore<V extends string = StorageKeys>
extends SessionBase<V>
implements SessionManager<V>
{
/**
* Clears all items from session store.
* @returns {void}
Expand Down
13 changes: 13 additions & 0 deletions lib/sessionManager/stores/expoSecureStore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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", () => {
Expand Down
7 changes: 5 additions & 2 deletions lib/sessionManager/stores/expoSecureStore.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -16,8 +16,11 @@ async function waitForExpoSecureStore() {
* Provides a expo local store based session manager implementation for the browser.
* @class ExpoSecureStore
*/
export class ExpoSecureStore<V = StorageKeys> implements SessionManager<V> {
export class ExpoSecureStore<
V extends string = StorageKeys,
> extends SessionBase<V> {
constructor() {
super();
this.loadExpoStore();
}

Expand Down
1 change: 0 additions & 1 deletion lib/sessionManager/stores/localStorage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
16 changes: 10 additions & 6 deletions lib/sessionManager/stores/localStorage.ts
Original file line number Diff line number Diff line change
@@ -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<V = StorageKeys> implements SessionManager<V> {
export class LocalStorage<V extends string = StorageKeys>
extends SessionBase<V>
implements SessionManager<V>
{
constructor() {
super();
console.warn("LocalStorage store should not be used in production");
}

setItems: Set<V | StorageKeys> = new Set<V>();
private internalItems: Set<V | StorageKeys> = new Set<V>();

/**
* Clears all items from session store.
* @returns {void}
*/
async destroySession(): Promise<void> {
this.setItems.forEach((key) => {
this.internalItems.forEach((key) => {
this.removeSessionItem(key);
});
}
Expand All @@ -35,7 +39,7 @@ export class LocalStorage<V = StorageKeys> implements SessionManager<V> {
): Promise<void> {
// clear items first
await this.removeSessionItem(itemKey);
this.setItems.add(itemKey);
this.internalItems.add(itemKey);

if (typeof itemValue === "string") {
splitString(itemValue, storageSettings.maxLength).forEach(
Expand Down Expand Up @@ -97,6 +101,6 @@ export class LocalStorage<V = StorageKeys> implements SessionManager<V> {

index++;
}
this.setItems.delete(itemKey);
this.internalItems.delete(itemKey);
}
}
13 changes: 13 additions & 0 deletions lib/sessionManager/stores/memory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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", () => {
Expand Down
7 changes: 5 additions & 2 deletions lib/sessionManager/stores/memory.ts
Original file line number Diff line number Diff line change
@@ -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<V = StorageKeys> implements SessionManager<V> {
export class MemoryStorage<V extends string = StorageKeys>
extends SessionBase<V>
implements SessionManager<V>
{
private memCache: Record<string, unknown> = {};

/**
Expand Down
33 changes: 32 additions & 1 deletion lib/sessionManager/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,31 @@ export type StorageSettingsType = {
maxLength: number;
};

export interface SessionManager<V = StorageKeys> {
export abstract class SessionBase<V extends string = StorageKeys>
implements SessionManager<V>
{
abstract getSessionItem<T = unknown>(
itemKey: V | StorageKeys,
): Awaitable<T | unknown | null>;
abstract setSessionItem<T = unknown>(
itemKey: V | StorageKeys,
itemValue: T,
): Awaitable<void>;
abstract removeSessionItem(itemKey: V | StorageKeys): Awaitable<void>;
abstract destroySession(): Awaitable<void>;

async setItems(items: Partial<Record<V, unknown>>): Awaitable<void> {
await Promise.all(
(Object.entries(items) as [V | StorageKeys, unknown][]).map(
([key, value]) => {
return this.setSessionItem(key, value);
},
),
);
}
}

export interface SessionManager<V extends string = StorageKeys> {
/**
*
* Gets the item for the provided key from the storage.
Expand Down Expand Up @@ -49,4 +73,11 @@ export interface SessionManager<V = StorageKeys> {
* Destroys the session
*/
destroySession: () => Awaitable<void>;

/**
* Sets multiple items simultaneously.
* @param {Record<V | StorageKeys, unknown>} items - Object containing key-value pairs to store
* @returns {Promise<void>}
*/
setItems(items: Partial<Record<V, unknown>>): Awaitable<void>;
}

0 comments on commit f379624

Please sign in to comment.