UNPKG

@solomonai/cache

Version:

<div align="center"> <h1 align="center">@solomonai/cache</h1> <h5>Cache all the things</h5> </div>

1 lines 18.6 kB
{"version":3,"sources":["../src/middleware/metrics.ts","../src/errors.ts","../src/middleware/encryption.ts"],"names":[],"mappings":"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","file":"middleware.mjs","sourcesContent":["import type { Result } from \"@unkey/error\";\nimport type { CacheError } from \"../errors\";\nimport type { Metrics } from \"../metrics\";\nimport type { Entry, Store } from \"../stores\";\nimport type { StoreMiddleware } from \"./interface\";\n\ntype Metric =\n | {\n metric: \"metric.cache.read\";\n key: string;\n hit: boolean;\n status?: \"fresh\" | \"stale\";\n latency: number;\n tier: string;\n namespace: string;\n }\n | {\n metric: \"metric.cache.write\";\n key: string;\n latency: number;\n tier: string;\n namespace: string;\n }\n | {\n metric: \"metric.cache.remove\";\n key: string;\n latency: number;\n tier: string;\n namespace: string;\n };\n\nexport function withMetrics(metrics: Metrics<Metric>): StoreMiddleware<any, any> {\n function wrap<TNamespace extends string, TValue>(\n store: Store<TNamespace, TValue>,\n ): Store<TNamespace, TValue> {\n return new StoreWithMetrics({ store, metrics });\n }\n return { wrap };\n}\n\nclass StoreWithMetrics<TNamespace extends string, TValue> implements Store<TNamespace, TValue> {\n public name: string;\n private readonly store: Store<TNamespace, TValue>;\n\n private readonly metrics: Metrics;\n\n constructor(opts: {\n store: Store<TNamespace, TValue>;\n metrics: Metrics;\n }) {\n this.name = opts.store.name;\n this.store = opts.store;\n this.metrics = opts.metrics;\n }\n\n public async get(\n namespace: TNamespace,\n key: string,\n ): Promise<Result<Entry<TValue> | undefined, CacheError>> {\n const start = performance.now();\n const res = await this.store.get(namespace, key);\n\n const now = Date.now();\n\n this.metrics.emit({\n metric: \"metric.cache.read\",\n hit: typeof res.val !== \"undefined\",\n status: res.val\n ? now <= res.val.freshUntil\n ? \"fresh\"\n : now <= res.val.staleUntil\n ? \"stale\"\n : undefined\n : undefined,\n latency: Math.round(performance.now() - start),\n tier: this.store.name,\n key,\n namespace,\n });\n\n return res;\n }\n\n public async set(\n namespace: TNamespace,\n key: string,\n value: Entry<TValue>,\n ): Promise<Result<void, CacheError>> {\n const start = performance.now();\n\n const res = await this.store.set(namespace, key, value);\n this.metrics.emit({\n metric: \"metric.cache.write\",\n latency: Math.round(performance.now() - start),\n tier: this.store.name,\n key,\n namespace,\n });\n return res;\n }\n\n public async remove(namespace: TNamespace, key: string): Promise<Result<void, CacheError>> {\n const start = performance.now();\n const res = this.store.remove(namespace, key);\n this.metrics.emit({\n metric: \"metric.cache.remove\",\n tier: this.store.name,\n latency: Math.round(performance.now() - start),\n key,\n namespace,\n });\n return res;\n }\n}\n","import { BaseError } from \"@unkey/error\";\n\nexport class CacheError extends BaseError {\n public readonly name = \"CacheError\";\n public readonly retry = false;\n\n public readonly tier: string;\n public readonly key: string;\n\n constructor(opts: {\n tier: string;\n key: string;\n message: string;\n }) {\n super(opts);\n this.name = \"CacheError\";\n this.tier = opts.tier;\n this.key = opts.key;\n }\n}\n","import { Err, type Result } from \"@unkey/error\";\nimport SuperJSON from \"superjson\";\nimport { CacheError } from \"../errors\";\nimport type { Entry, Store } from \"../stores\";\nimport type { StoreMiddleware } from \"./interface\";\n\n/**\n * EncryptedStore is a wrapper around a Store that encrypts and decrypts values using the Web Crypto API.\n *\n * The encryption key is stored in memory and a hash is injected into the cache key to allow rolling the key\n * without causing issues with decryption errors.\n *\n * Rolling the encryption key will therefore invalidate all cache entries.\n *\n * @example\n * ```ts\n * let store // some existing store implementation\n *\n * // generate a key with `openssl rand -base64 32` and load it from the environment\n * const encryptionKey = \"\"\n * store = EncryptedStore.fromBase64Key(store, encryptionKey)\n * ```\n */\n\nexport class EncryptedStore<TNamespace extends string, TValue = any>\n implements Store<TNamespace, TValue>\n{\n public name: string;\n private readonly encryptionKey: CryptoKey;\n private readonly encryptionKeyHash: string;\n private readonly store: Store<TNamespace, TValue>;\n\n constructor(opts: {\n store: Store<TNamespace, TValue>;\n encryptionKey: CryptoKey;\n encryptionKeyHash: string;\n }) {\n this.name = opts.store.name;\n this.store = opts.store;\n this.encryptionKey = opts.encryptionKey;\n this.encryptionKeyHash = opts.encryptionKeyHash;\n }\n\n /**\n *\n */\n private buildCacheKey(key: string): string {\n return [key, this.encryptionKeyHash].join(\"/\");\n }\n\n public async get(\n namespace: TNamespace,\n key: string,\n ): Promise<Result<Entry<TValue> | undefined, CacheError>> {\n const res = await this.store.get(namespace, this.buildCacheKey(key));\n\n if (res.err) {\n return res;\n }\n if (!res.val) {\n return res;\n }\n try {\n const { iv, ciphertext } = res.val.value as { iv: string; ciphertext: string };\n const decrypted = await this.decrypt(iv, ciphertext);\n\n res.val.value = SuperJSON.parse(decrypted);\n } catch (e) {\n return Err(new CacheError({ tier: this.name, key, message: (e as Error).message }));\n }\n\n return res;\n }\n\n public async set(\n namespace: TNamespace,\n key: string,\n value: Entry<TValue>,\n ): Promise<Result<void, CacheError>> {\n const { iv, ciphertext } = await this.encrypt(SuperJSON.stringify(value.value));\n // @ts-expect-error\n value.value = { iv, ciphertext };\n\n const res = await this.store.set(namespace, this.buildCacheKey(key), value);\n\n return res;\n }\n\n public async remove(namespace: TNamespace, key: string): Promise<Result<void, CacheError>> {\n const res = this.store.remove(namespace, this.buildCacheKey(key));\n\n return res;\n }\n\n private async encrypt(secret: string): Promise<{ iv: string; ciphertext: string }> {\n const iv = crypto.getRandomValues(new Uint8Array(32));\n const ciphertext = await crypto.subtle.encrypt(\n {\n name: \"AES-GCM\",\n iv,\n },\n this.encryptionKey,\n new TextEncoder().encode(secret),\n );\n return { iv: encode(iv), ciphertext: encode(ciphertext) };\n }\n\n private async decrypt(iv: string, ciphertext: string): Promise<string> {\n const decryptedBuffer = await crypto.subtle.decrypt(\n {\n name: \"AES-GCM\",\n iv: decode(iv),\n },\n this.encryptionKey,\n decode(ciphertext),\n );\n\n return new TextDecoder().decode(decryptedBuffer);\n }\n\n static async fromBase64Key<TNamespace extends string, TValue>(\n base64EncodedKey: string,\n ): Promise<{ wrap: (store: Store<TNamespace, TValue>) => Store<TNamespace, TValue> }> {\n const cryptoKey = await crypto.subtle.importKey(\n \"raw\",\n decode(base64EncodedKey),\n { name: \"AES-GCM\", length: 256 },\n false,\n [\"encrypt\", \"decrypt\"],\n );\n\n const hash = encode(await crypto.subtle.digest(\"SHA-256\", decode(base64EncodedKey)));\n\n return {\n wrap: (store) =>\n new EncryptedStore({ store, encryptionKey: cryptoKey, encryptionKeyHash: hash }),\n };\n }\n}\n\nconst base64abc = [\n \"A\",\n \"B\",\n \"C\",\n \"D\",\n \"E\",\n \"F\",\n \"G\",\n \"H\",\n \"I\",\n \"J\",\n \"K\",\n \"L\",\n \"M\",\n \"N\",\n \"O\",\n \"P\",\n \"Q\",\n \"R\",\n \"S\",\n \"T\",\n \"U\",\n \"V\",\n \"W\",\n \"X\",\n \"Y\",\n \"Z\",\n \"a\",\n \"b\",\n \"c\",\n \"d\",\n \"e\",\n \"f\",\n \"g\",\n \"h\",\n \"i\",\n \"j\",\n \"k\",\n \"l\",\n \"m\",\n \"n\",\n \"o\",\n \"p\",\n \"q\",\n \"r\",\n \"s\",\n \"t\",\n \"u\",\n \"v\",\n \"w\",\n \"x\",\n \"y\",\n \"z\",\n \"0\",\n \"1\",\n \"2\",\n \"3\",\n \"4\",\n \"5\",\n \"6\",\n \"7\",\n \"8\",\n \"9\",\n \"+\",\n \"/\",\n];\n\n/**\n * CREDIT: https://gist.github.com/enepomnyaschih/72c423f727d395eeaa09697058238727\n * Encodes a given Uint8Array, ArrayBuffer or string into RFC4648 base64 representation\n * @param data\n */\nfunction encode(data: ArrayBuffer | string): string {\n const uint8 =\n typeof data === \"string\"\n ? new TextEncoder().encode(data)\n : data instanceof Uint8Array\n ? data\n : new Uint8Array(data);\n let result = \"\";\n let i: number;\n const l = uint8.length;\n for (i = 2; i < l; i += 3) {\n result += base64abc[uint8[i - 2] >> 2];\n result += base64abc[((uint8[i - 2] & 0x03) << 4) | (uint8[i - 1] >> 4)];\n result += base64abc[((uint8[i - 1] & 0x0f) << 2) | (uint8[i] >> 6)];\n result += base64abc[uint8[i] & 0x3f];\n }\n if (i === l + 1) {\n // 1 octet yet to write\n result += base64abc[uint8[i - 2] >> 2];\n result += base64abc[(uint8[i - 2] & 0x03) << 4];\n result += \"==\";\n }\n if (i === l) {\n // 2 octets yet to write\n result += base64abc[uint8[i - 2] >> 2];\n result += base64abc[((uint8[i - 2] & 0x03) << 4) | (uint8[i - 1] >> 4)];\n result += base64abc[(uint8[i - 1] & 0x0f) << 2];\n result += \"=\";\n }\n return result.replaceAll(\"+\", \"-\").replaceAll(\"/\", \"_\").replaceAll(\"=\", \"\");\n}\n\n/**\n * Decodes a given RFC4648 base64 encoded string\n * @param b64\n */\nfunction decode(b64: string): Uint8Array {\n const paddedLength = b64.length + ((4 - (b64.length % 4)) % 4);\n const binString = atob(b64.replaceAll(\"-\", \"+\").replaceAll(\"_\", \"/\").padEnd(paddedLength, \"=\"));\n const size = binString.length;\n const bytes = new Uint8Array(size);\n for (let i = 0; i < size; i++) {\n bytes[i] = binString.charCodeAt(i);\n }\n return bytes;\n}\n\nexport async function withEncryption<TNamespace extends string, TValue = any>(\n base64Key: string,\n): Promise<StoreMiddleware<TNamespace, TValue>> {\n return await EncryptedStore.fromBase64Key(base64Key);\n}\n"]}