{"version":3,"file":"memory.mjs","names":[],"sources":["../../src/object-cache/memory.ts"],"sourcesContent":["/**\n * In-isolate memory object-cache backend — RUNTIME ENTRY\n *\n * The default backend for the Node runtime and a sensible local-dev option.\n * Caches across requests within a single isolate/process; it is NOT shared\n * across isolates, so on a multi-isolate platform (Cloudflare) you want the KV\n * backend instead. Still useful on Node, where one long-lived process serves\n * every request.\n *\n * Wire it up with `memoryCache()` from `emdash`:\n *\n * ```ts\n * import { memoryCache } from \"@premium-cms/emdash\";\n * emdash({ objectCache: memoryCache() });\n * ```\n *\n * The store lives on `globalThis` behind a `Symbol.for` key so Vite SSR chunk\n * duplication doesn't create two independent caches (same pattern as\n * `request-context.ts`).\n */\n\nimport type { CreateObjectCacheBackendFn, ObjectCacheBackend } from \"./types.js\";\n\ninterface Entry {\n\tvalue: string;\n\t/** Absolute expiry in ms (`Date.now()` epoch), or `null` for none. */\n\texpiresAt: number | null;\n}\n\ninterface MemoryStore {\n\tmap: Map<string, Entry>;\n\tmaxEntries: number;\n}\n\nconst STORE_KEY = Symbol.for(\"emdash:object-cache:memory\");\nconst g = globalThis as Record<symbol, unknown>;\n\nfunction getStore(maxEntries: number): MemoryStore {\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- globalThis singleton pattern (see request-context.ts)\n\tconst existing = g[STORE_KEY] as MemoryStore | undefined;\n\tif (existing) {\n\t\t// First descriptor wins for sizing; later calls reuse the same map.\n\t\treturn existing;\n\t}\n\tconst store: MemoryStore = { map: new Map(), maxEntries };\n\tg[STORE_KEY] = store;\n\treturn store;\n}\n\n/**\n * Create the in-isolate memory backend.\n *\n * Config keys (all optional):\n * - `maxEntries` — soft cap on stored keys; oldest insertions are evicted\n *   first when exceeded (FIFO, cheap and good enough for a backstop). Default\n *   1000.\n */\nexport const createObjectCache: CreateObjectCacheBackendFn = (config): ObjectCacheBackend => {\n\tconst maxEntries = typeof config.maxEntries === \"number\" ? config.maxEntries : 1000;\n\tconst store = getStore(maxEntries);\n\n\treturn {\n\t\tget(key: string): Promise<string | null> {\n\t\t\tconst entry = store.map.get(key);\n\t\t\tif (!entry) return Promise.resolve(null);\n\t\t\tif (entry.expiresAt !== null && entry.expiresAt <= Date.now()) {\n\t\t\t\tstore.map.delete(key);\n\t\t\t\treturn Promise.resolve(null);\n\t\t\t}\n\t\t\treturn Promise.resolve(entry.value);\n\t\t},\n\t\tset(key: string, value: string, ttlSeconds?: number): Promise<void> {\n\t\t\t// Refresh insertion order so recently-written keys survive eviction.\n\t\t\tstore.map.delete(key);\n\t\t\tstore.map.set(key, {\n\t\t\t\tvalue,\n\t\t\t\texpiresAt: ttlSeconds && ttlSeconds > 0 ? Date.now() + ttlSeconds * 1000 : null,\n\t\t\t});\n\t\t\twhile (store.map.size > store.maxEntries) {\n\t\t\t\tconst oldest = store.map.keys().next().value;\n\t\t\t\tif (oldest === undefined) break;\n\t\t\t\tstore.map.delete(oldest);\n\t\t\t}\n\t\t\treturn Promise.resolve();\n\t\t},\n\t\tdelete(key: string): Promise<void> {\n\t\t\tstore.map.delete(key);\n\t\t\treturn Promise.resolve();\n\t\t},\n\t};\n};\n"],"mappings":";AAkCA,MAAM,YAAY,OAAO,IAAI,6BAA6B;AAC1D,MAAM,IAAI;AAEV,SAAS,SAAS,YAAiC;CAElD,MAAM,WAAW,EAAE;AACnB,KAAI,SAEH,QAAO;CAER,MAAM,QAAqB;EAAE,qBAAK,IAAI,KAAK;EAAE;EAAY;AACzD,GAAE,aAAa;AACf,QAAO;;;;;;;;;;AAWR,MAAa,qBAAiD,WAA+B;CAE5F,MAAM,QAAQ,SADK,OAAO,OAAO,eAAe,WAAW,OAAO,aAAa,IAC7C;AAElC,QAAO;EACN,IAAI,KAAqC;GACxC,MAAM,QAAQ,MAAM,IAAI,IAAI,IAAI;AAChC,OAAI,CAAC,MAAO,QAAO,QAAQ,QAAQ,KAAK;AACxC,OAAI,MAAM,cAAc,QAAQ,MAAM,aAAa,KAAK,KAAK,EAAE;AAC9D,UAAM,IAAI,OAAO,IAAI;AACrB,WAAO,QAAQ,QAAQ,KAAK;;AAE7B,UAAO,QAAQ,QAAQ,MAAM,MAAM;;EAEpC,IAAI,KAAa,OAAe,YAAoC;AAEnE,SAAM,IAAI,OAAO,IAAI;AACrB,SAAM,IAAI,IAAI,KAAK;IAClB;IACA,WAAW,cAAc,aAAa,IAAI,KAAK,KAAK,GAAG,aAAa,MAAO;IAC3E,CAAC;AACF,UAAO,MAAM,IAAI,OAAO,MAAM,YAAY;IACzC,MAAM,SAAS,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC;AACvC,QAAI,WAAW,OAAW;AAC1B,UAAM,IAAI,OAAO,OAAO;;AAEzB,UAAO,QAAQ,SAAS;;EAEzB,OAAO,KAA4B;AAClC,SAAM,IAAI,OAAO,IAAI;AACrB,UAAO,QAAQ,SAAS;;EAEzB"}