storage-in-memory.ts, storage-interface.ts

a generic key-value storage interface backed by many implementations

storage-in-memory.ts

import {
	StorageInterface,
	StorageListOptions,
	StorageListResult,
} from './storage-interface';

export interface InMemoryStorageOptions {
	namespace?: string;
}

export class InMemoryStorage implements StorageInterface {
	namespace = 'storage-in-memory';
	#store: Map<unknown, unknown>;

	constructor(options?: InMemoryStorageOptions) {
		this.#store = new Map();
		if (options?.namespace) {
			this.namespace = options.namespace;
		}
	}

	async get<T>(key: string) {
		return this.#store.get(key) as T;
	}

	async put<T>(key: string, value: T) {
		return this.#store.set(key, value);
	}

	async delete(key: string) {
		return this.#store.delete(key);
	}

	async list(options: StorageListOptions) {
		const keys = Array.from(this.#store.keys()) as string[];
		const prefix = options.prefix;

		let matchedKeys = keys;

		if (prefix) {
			const prefixParts = prefix.split(':');
			matchedKeys = keys.filter((key) => {
				const keyParts = key.split(':');
				if (keyParts.length < prefixParts.length) {
					return false;
				}

				for (let i = 0; i < prefixParts.length; i++) {
					const keyPart = keyParts[i];
					const prefixPart = prefixParts[i];
					if (prefixPart === '*' || prefixPart === keyPart) {
						continue;
					} else {
						return false;
					}
				}
				return true;
			});
		}

		return {
			keys: matchedKeys,
			list_complete: true,
			cacheStatus: null,
		} as StorageListResult;
	}
}

storage-interface.ts

export abstract class StorageInterface {
	abstract namespace: string;

	abstract put<T = unknown>(key: string, value: T): Promise<unknown>;
	abstract get<T = unknown>(key: string): Promise<T>;
	abstract delete(key: string): Promise<unknown>;
	abstract list(options: StorageListOptions): Promise<StorageListResult>;
}

export interface StorageListOptions {
	limit?: number;
	prefix?: string | null;
	cursor?: string | null;
}

export interface StorageListResult {
	keys: string[];
	list_complete: boolean;
	cacheStatus: string | null;
}