UNPKG

idmp

Version:

A lightweight TypeScript library for deduplicating and caching async function calls with automatic retries, designed for idempotent network requests in React and Node.js.

84 lines (83 loc) 2.75 kB
/*! idmp v4.1.0 | (c) github/haozi | MIT */ import { createHash } from "crypto"; import { getOptions } from "idmp"; import { parse_UNSAFE, stringify_UNSAFE } from "json-web3"; import { createClient } from "redis"; import { fileURLToPath } from "url"; //#region src/index.ts var __filename = fileURLToPath(import.meta.url); var md5 = (data) => createHash("md5").update(data).digest("hex"); var cachePrefix = `/idmp/v4/${md5(__filename)}`; var udf = void 0; var encode = encodeURIComponent; var getCachePath = (globalKey) => `${cachePrefix}/${encode(globalKey)}`; var redisIdmpWrap = (_idmp, namespace, options) => { const client = createClient({ url: options.url }); client.once("error", (err) => { console.error("Redis Client Error", err); process.exit(err.code === "ECONNREFUSED" ? 1 : 0); }); const setData = async (key, data, maxAge) => { if (!key) return; if (!client.isOpen) await client.connect(); const cachePath = getCachePath(key); await client.set(cachePath, stringify_UNSAFE(data), { expiration: { type: "EX", value: Math.floor(maxAge / 1e3) } }); }; const getData = async (key) => { if (!key) return udf; if (!client.isOpen) await client.connect(); const cachePath = getCachePath(key); let redisLocalData; try { const rawData = await client.get(cachePath); if (!rawData) return udf; redisLocalData = parse_UNSAFE(rawData); } catch {} if (redisLocalData === udf) return udf; return redisLocalData; }; const deleteKeysByPrefix = async (prefix) => { const client = createClient({ url: options.url }); await client.connect(); let cursor = "0"; const pattern = `${prefix}*`; do { const { cursor: nextCursor, keys } = await client.scan(cursor, { MATCH: pattern, COUNT: 100 }); cursor = nextCursor; if (keys.length > 0) await client.del(keys); } while (cursor !== "0"); await client.quit(); }; const newIdmp = (globalKey, promiseFunc, options) => { globalKey = `${namespace}_${globalKey}`; const finalOptions = getOptions(options); return _idmp(globalKey, async () => { const localData = await getData(globalKey); if (localData !== udf) return localData; const memoryData = await promiseFunc(); if (memoryData !== udf) setData(globalKey, memoryData, finalOptions.maxAge); return memoryData; }, { maxAge: 0 }); }; newIdmp.flush = async (globalKey) => { _idmp.flush(globalKey); await client?.del(getCachePath(globalKey)); }; newIdmp.flushAll = async () => { _idmp.flushAll(); await deleteKeysByPrefix(cachePrefix); }; newIdmp.quit = async () => { if (client.isOpen) await client.quit(); }; return newIdmp; }; //#endregion export { cachePrefix, redisIdmpWrap as default, getCachePath }; //# sourceMappingURL=index.js.map