Skip to main content
Glama
by microsoft
memcache.ts3.94 kB
// Import necessary modules and types import { CACHE_FORMAT_VERSION, CACHE_SHA_LENGTH, CHANGE } from "./constants" import { hash } from "./crypto" import type { CacheEntry } from "./cache" import debug, { Debugger } from "debug" /** * A cache class that manages entries stored in JSONL format. * It allows storage and retrieval of cache entries with unique SHA identifiers. * @template K - Type of the key * @template V - Type of the value */ export class MemoryCache<K, V> extends EventTarget implements WorkspaceFileCache<any, any> { protected _entries: Record<string, CacheEntry<V>> private _pending: Record<string, Promise<V>> private readonly hashOptions: HashOptions protected dbg: Debugger // Constructor is private to enforce the use of byName factory method constructor(public readonly name: string) { super() // Initialize EventTarget this.dbg = debug(`genaiscript:cache:${name}`) // Initialize debugger this.hashOptions = { salt: CACHE_FORMAT_VERSION, length: CACHE_SHA_LENGTH, } satisfies HashOptions } protected async initialize() { if (this._entries) return this._entries = {} this._pending = {} } /** * Retrieve all values from the cache. * @returns */ async values(): Promise<V[]> { await this.initialize() return Object.values(this._entries).map((kv) => kv.val) } /** * Get the value associated with a specific key. * @param key - The key of the entry * @returns A promise resolving to the value */ async get(key: K): Promise<V> { if (key === undefined) return undefined // Handle undefined key await this.initialize() const sha = await this.getSha(key) const res = this._entries[sha]?.val this.dbg(`get ${sha}: ${res !== undefined ? "hit" : "miss"}`) return res } async getOrUpdate( key: K, updater: () => Promise<V>, validator?: (val: V) => boolean ): Promise<{ key: string; value: V; cached?: boolean }> { await this.initialize() const sha = await this.getSha(key) if (this._entries[sha]) { this.dbg(`getup ${sha}: hit`) return { key: sha, value: this._entries[sha].val, cached: true } } if (this._pending[sha]) { this.dbg(`getup ${sha}: hit (pending)`) return { key: sha, value: await this._pending[sha], cached: true } } try { const p = updater() this._pending[sha] = p const value = await p if (!validator || validator(value)) { await this.set(key, value) this.dbg(`set ${sha}: updated`) } return { key: sha, value, cached: false } } finally { delete this._pending[sha] } } protected async appendEntry(entry: CacheEntry<V>) {} /** * Set a key-value pair in the cache, triggering a change event. * @param key - The key to set * @param val - The value to set * @param options - Optional trace options */ async set(key: K, val: V) { await this.initialize() const sha = await this.getSha(key) const ent = { sha, val } satisfies CacheEntry<V> const ex = this._entries[sha] if (ex !== undefined && JSON.stringify(ex) == JSON.stringify(ent)) return // No change this._entries[sha] = ent await this.appendEntry(ent) this.dispatchEvent(new Event(CHANGE)) // Notify listeners this.dbg(`set ${sha}: updated`) } /** * Compute SHA for a given key. * @param key - The key to compute SHA for * @returns A promise resolving to the SHA string */ async getSha(key: K) { const sha = await hash(key, this.hashOptions) return sha } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/microsoft/genaiscript'

If you have feedback or need assistance with the MCP directory API, please join our Discord server