@iocium/cachekit
Version:
A pluggable, backend-agnostic caching adapter for Node.js and serverless platforms
224 lines (216 loc) • 6.77 kB
JavaScript
;
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
});