UNPKG

@iocium/cachekit

Version:

A pluggable, backend-agnostic caching adapter for Node.js and serverless platforms

224 lines (216 loc) 6.77 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { D1Backend: () => D1Backend, KVBackend: () => KVBackend, MemcachedBackend: () => MemcachedBackend, MemoryBackend: () => MemoryBackend, RedisBackend: () => RedisBackend, createCacheKit: () => createCacheKit }); module.exports = __toCommonJS(index_exports); // src/lib/memory.ts var MemoryBackend = class { constructor() { this.store = /* @__PURE__ */ new Map(); } async get(key) { return this.store.get(key); } async set(key, record) { if (record.expiresAt !== void 0 && (!Number.isInteger(record.expiresAt) || record.expiresAt < 0)) { throw new Error("expiresAt must be a non-negative integer if provided"); } this.store.set(key, record); } async delete(key) { this.store.delete(key); } async clear() { this.store.clear(); } }; // src/lib/cache.ts function createCacheKit(options = {}) { const backend = options.backend || new MemoryBackend(); return { /** * Retrieves a value from cache if it exists and is not expired. */ async get(key) { const record = await backend.get(key); if (!record) return void 0; if (record.expiresAt && record.expiresAt < Date.now()) { await backend.delete(key); return void 0; } return record.value; }, /** * Stores a value in the cache, with optional TTL. */ async set(key, value, ttlMs) { if (ttlMs !== void 0 && (!Number.isInteger(ttlMs) || ttlMs < 0)) { throw new Error("TTL must be a non-negative integer if provided"); } const expiresAt = ttlMs ? Date.now() + ttlMs : void 0; await backend.set(key, { value, expiresAt }); }, /** * Deletes a key from the cache. */ async delete(key) { await backend.delete(key); }, /** * Clears all cache entries (where supported). */ async clear() { await backend.clear(); } }; } // src/lib/kv.ts var KVBackend = class { constructor(kv) { this.kv = kv; } async get(key) { const data = await this.kv.get(key, "json"); if (typeof data === "object" && data !== null && "value" in data) { return data; } return void 0; } async set(key, record) { if (record.expiresAt !== void 0 && (!Number.isInteger(record.expiresAt) || record.expiresAt < 0)) { throw new Error("expiresAt must be a non-negative integer if provided"); } let ttl = record.expiresAt ? Math.ceil((record.expiresAt - Date.now()) / 1e3) : void 0; if (ttl !== void 0 && ttl < 90) { ttl = 90; } await this.kv.put(key, JSON.stringify(record), ttl ? { expirationTtl: ttl } : {}); } async delete(key) { await this.kv.delete(key); } async clear() { throw new Error("KVBackend does not support clear()"); } }; // src/lib/d1.ts var D1Backend = class { constructor(db) { this.db = db; } async get(key) { const result = await this.db.prepare( "SELECT value, expiresAt FROM cache WHERE key = ?" ).bind(key).first(); if (!result || typeof result.value !== "string") return void 0; return { value: JSON.parse(result.value), expiresAt: result.expiresAt ?? void 0 }; } async set(key, record) { if (record.expiresAt !== void 0 && (!Number.isInteger(record.expiresAt) || record.expiresAt < 0)) { throw new Error("expiresAt must be a non-negative integer if provided"); } await this.db.prepare("INSERT OR REPLACE INTO cache (key, value, expiresAt) VALUES (?, ?, ?)").bind(key, JSON.stringify(record.value), record.expiresAt ?? null).run(); } async delete(key) { await this.db.prepare("DELETE FROM cache WHERE key = ?").bind(key).run(); } async clear() { await this.db.prepare("DELETE FROM cache").run(); } }; // src/lib/redis.ts var RedisBackend = class { constructor(redis) { this.redis = redis; } async get(key) { const raw = await this.redis.get(key); return raw ? JSON.parse(raw) : void 0; } async set(key, record) { if (record.expiresAt !== void 0 && (!Number.isInteger(record.expiresAt) || record.expiresAt < 0)) { throw new Error("expiresAt must be a non-negative integer if provided"); } const ttl = record.expiresAt ? Math.ceil((record.expiresAt - Date.now()) / 1e3) : void 0; if (ttl) await this.redis.set(key, JSON.stringify(record), "EX", ttl); else await this.redis.set(key, JSON.stringify(record)); } async delete(key) { await this.redis.del(key); } async clear() { await this.redis.flushall(); } }; // src/lib/memcached.ts var MemcachedBackend = class { constructor(memcached) { this.memcached = memcached; } async get(key) { const raw = await new Promise((resolve) => { this.memcached.get(key, (err, data2) => resolve(data2)); }); if (!raw) return void 0; const data = JSON.parse(raw); if (typeof data === "object" && data !== null && "value" in data) { return data; } return void 0; } async set(key, record) { if (record.expiresAt !== void 0 && (!Number.isInteger(record.expiresAt) || record.expiresAt < 0)) { throw new Error("expiresAt must be a non-negative integer if provided"); } const ttl = record.expiresAt ? Math.ceil((record.expiresAt - Date.now()) / 1e3) : 0; await new Promise((resolve, reject) => { this.memcached.set(key, JSON.stringify(record), ttl, (err) => err ? reject(err) : resolve()); }); } async delete(key) { await new Promise((resolve, reject) => { this.memcached.del(key, (err) => err ? reject(err) : resolve()); }); } async clear() { await new Promise((resolve, reject) => { this.memcached.flush((err) => err ? reject(err) : resolve()); }); } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { D1Backend, KVBackend, MemcachedBackend, MemoryBackend, RedisBackend, createCacheKit });