keyv-cache-proxy
Advanced tools
| export {}; | ||
| //# sourceMappingURL=index.test.d.ts.map |
| {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""} |
| import { beforeEach, describe, expect, test } from "bun:test"; | ||
| import Keyv from "keyv"; | ||
| import KeyvCacheProxy, { globalThisCached } from "./index"; | ||
| describe("KeyvCacheProxy", () => { | ||
| let store; | ||
| beforeEach(() => { | ||
| store = new Keyv(); | ||
| }); | ||
| describe("Basic Caching", () => { | ||
| test("should cache method results", async () => { | ||
| let callCount = 0; | ||
| const obj = { | ||
| getValue: (x) => { | ||
| callCount++; | ||
| return x * 2; | ||
| }, | ||
| }; | ||
| const cached = KeyvCacheProxy({ store })(obj); | ||
| // First call - should execute method | ||
| const result1 = await cached.getValue(5); | ||
| expect(result1).toBe(10); | ||
| expect(callCount).toBe(1); | ||
| // Second call - should return cached result | ||
| const result2 = await cached.getValue(5); | ||
| expect(result2).toBe(10); | ||
| expect(callCount).toBe(1); // Should not increment | ||
| }); | ||
| test("should cache different arguments separately", async () => { | ||
| let callCount = 0; | ||
| const obj = { | ||
| add: (a, b) => { | ||
| callCount++; | ||
| return a + b; | ||
| }, | ||
| }; | ||
| const cached = KeyvCacheProxy({ store })(obj); | ||
| await cached.add(1, 2); | ||
| await cached.add(3, 4); | ||
| expect(callCount).toBe(2); | ||
| await cached.add(1, 2); // Cached | ||
| expect(callCount).toBe(2); | ||
| await cached.add(3, 4); // Cached | ||
| expect(callCount).toBe(2); | ||
| }); | ||
| test("should handle async methods", async () => { | ||
| const obj = { | ||
| async fetchData(id) { | ||
| await new Promise((resolve) => setTimeout(resolve, 10)); | ||
| return { id, data: "test" }; | ||
| }, | ||
| }; | ||
| const cached = KeyvCacheProxy({ store })(obj); | ||
| const result = await cached.fetchData(1); | ||
| expect(result).toEqual({ id: 1, data: "test" }); | ||
| }); | ||
| test("should convert sync methods to async", async () => { | ||
| const obj = { | ||
| syncMethod: (x) => x * 2, | ||
| }; | ||
| const cached = KeyvCacheProxy({ store })(obj); | ||
| const result = cached.syncMethod(5); | ||
| expect(result).toBeInstanceOf(Promise); | ||
| expect(await result).toBe(10); | ||
| }); | ||
| }); | ||
| describe("Hooks - onCache", () => { | ||
| test("should call onCache hook on every invocation", async () => { | ||
| const onCacheCalls = []; | ||
| const obj = { | ||
| getValue: (x) => x * 2, | ||
| }; | ||
| const cached = KeyvCacheProxy({ | ||
| store, | ||
| onCache: (key, value) => { | ||
| onCacheCalls.push({ key, value }); | ||
| }, | ||
| })(obj); | ||
| await cached.getValue(5); // First call - cache miss, onCache called with undefined | ||
| expect(onCacheCalls.length).toBe(1); | ||
| expect(onCacheCalls[0]?.value).toBe(undefined); | ||
| await cached.getValue(5); // Second call - cache hit, onCache called with cached value | ||
| expect(onCacheCalls.length).toBe(2); | ||
| expect(onCacheCalls[1]?.value).toBe(10); | ||
| expect(onCacheCalls[1]?.key).toContain("getValue"); | ||
| }); | ||
| test("should allow onCache to modify cached value", async () => { | ||
| const obj = { | ||
| getData: () => ({ value: 100 }), | ||
| }; | ||
| const cached = KeyvCacheProxy({ | ||
| store, | ||
| onCache: (_key, value) => { | ||
| // Only modify if value exists (cache hit) | ||
| if (value !== undefined) { | ||
| return { ...value, fromCache: true }; | ||
| } | ||
| }, | ||
| })(obj); | ||
| const result1 = await cached.getData(); | ||
| expect(result1).toEqual({ value: 100 }); | ||
| const result2 = await cached.getData(); | ||
| expect(result2).toMatchObject({ value: 100, fromCache: true }); | ||
| }); | ||
| test("should return original value if onCache returns undefined", async () => { | ||
| const obj = { | ||
| getValue: () => 42, | ||
| }; | ||
| const cached = KeyvCacheProxy({ | ||
| store, | ||
| onCache: (_key, _value) => { | ||
| // Return undefined to keep original | ||
| return undefined; | ||
| }, | ||
| })(obj); | ||
| await cached.getValue(); // Prime cache | ||
| const result = await cached.getValue(); | ||
| expect(result).toBe(42); | ||
| }); | ||
| test("should support async onCache hook", async () => { | ||
| const obj = { | ||
| getValue: () => 100, | ||
| }; | ||
| const cached = KeyvCacheProxy({ | ||
| store, | ||
| onCache: async (_key, value) => { | ||
| await new Promise((resolve) => setTimeout(resolve, 10)); | ||
| // Only modify on cache hit | ||
| if (value !== undefined) { | ||
| return value * 2; | ||
| } | ||
| }, | ||
| })(obj); | ||
| await cached.getValue(); // Prime cache | ||
| const result = await cached.getValue(); | ||
| expect(result).toBe(200); | ||
| }); | ||
| test("should force cache miss when onCache returns null", async () => { | ||
| let fetchCount = 0; | ||
| const obj = { | ||
| getValue: () => { | ||
| fetchCount++; | ||
| return fetchCount; | ||
| }, | ||
| }; | ||
| const cached = KeyvCacheProxy({ | ||
| store, | ||
| onCache: (_key, value) => { | ||
| // Return null to force refetch even if cached | ||
| if (value !== undefined) { | ||
| return null; // Force cache miss | ||
| } | ||
| }, | ||
| })(obj); | ||
| const result1 = await cached.getValue(); | ||
| expect(result1).toBe(1); | ||
| const result2 = await cached.getValue(); // Should refetch due to null | ||
| expect(result2).toBe(2); | ||
| expect(fetchCount).toBe(2); | ||
| }); | ||
| }); | ||
| describe("Hooks - onFetch", () => { | ||
| test("should call onFetch hook on cache miss", async () => { | ||
| const onFetchCalls = []; | ||
| const obj = { | ||
| getValue: (x) => x * 2, | ||
| }; | ||
| const cached = KeyvCacheProxy({ | ||
| store, | ||
| onFetch: (key, value) => { | ||
| onFetchCalls.push({ key, value }); | ||
| }, | ||
| })(obj); | ||
| await cached.getValue(5); | ||
| expect(onFetchCalls.length).toBe(1); | ||
| expect(onFetchCalls[0]?.value).toBe(10); | ||
| expect(onFetchCalls[0]?.key).toContain("getValue"); | ||
| await cached.getValue(5); // Cache hit - no fetch | ||
| expect(onFetchCalls.length).toBe(1); | ||
| }); | ||
| test("should allow onFetch to modify value before caching", async () => { | ||
| const obj = { | ||
| getData: () => ({ value: 100 }), | ||
| }; | ||
| const cached = KeyvCacheProxy({ | ||
| store, | ||
| onFetch: (_key, value) => { | ||
| return { ...value, fetchedAt: Date.now() }; | ||
| }, | ||
| })(obj); | ||
| const result1 = await cached.getData(); | ||
| expect(result1).toHaveProperty("fetchedAt"); | ||
| expect(result1.value).toBe(100); | ||
| // Should return modified cached value | ||
| const result2 = await cached.getData(); | ||
| expect(result2).toEqual(result1); | ||
| }); | ||
| test("should support async onFetch hook", async () => { | ||
| const obj = { | ||
| getValue: () => 50, | ||
| }; | ||
| const cached = KeyvCacheProxy({ | ||
| store, | ||
| onFetch: async (_key, value) => { | ||
| await new Promise((resolve) => setTimeout(resolve, 10)); | ||
| return value * 3; | ||
| }, | ||
| })(obj); | ||
| const result = await cached.getValue(); | ||
| expect(result).toBe(150); | ||
| }); | ||
| test("should cache modified value from onFetch", async () => { | ||
| let callCount = 0; | ||
| const obj = { | ||
| getValue: () => { | ||
| callCount++; | ||
| return 10; | ||
| }, | ||
| }; | ||
| const cached = KeyvCacheProxy({ | ||
| store, | ||
| onFetch: (_key, value) => value * 10, | ||
| })(obj); | ||
| const result1 = await cached.getValue(); | ||
| expect(result1).toBe(100); | ||
| const result2 = await cached.getValue(); | ||
| expect(result2).toBe(100); | ||
| expect(callCount).toBe(1); // Only called once | ||
| }); | ||
| }); | ||
| describe("Hooks - Combined", () => { | ||
| test("should call both hooks appropriately", async () => { | ||
| const hookCalls = []; | ||
| const obj = { | ||
| getValue: (x) => x, | ||
| }; | ||
| const cached = KeyvCacheProxy({ | ||
| store, | ||
| onCache: (_key, value) => { | ||
| hookCalls.push("cache"); | ||
| return value; | ||
| }, | ||
| onFetch: (_key, value) => { | ||
| hookCalls.push("fetch"); | ||
| return value; | ||
| }, | ||
| })(obj); | ||
| await cached.getValue(1); // cache miss: onCache(undefined), then onFetch | ||
| expect(hookCalls).toEqual(["cache", "fetch"]); | ||
| await cached.getValue(1); // cache hit: onCache(value) | ||
| expect(hookCalls).toEqual(["cache", "fetch", "cache"]); | ||
| await cached.getValue(2); // cache miss: onCache(undefined), then onFetch | ||
| expect(hookCalls).toEqual(["cache", "fetch", "cache", "cache", "fetch"]); | ||
| }); | ||
| test("should apply both modifications correctly", async () => { | ||
| const obj = { | ||
| getValue: () => ({ base: 1 }), | ||
| }; | ||
| const cached = KeyvCacheProxy({ | ||
| store, | ||
| onCache: (_key, value) => { | ||
| // Only modify on cache hit | ||
| if (value !== undefined) { | ||
| return { ...value, fromCache: true }; | ||
| } | ||
| }, | ||
| onFetch: (_key, value) => ({ ...value, fromFetch: true }), | ||
| })(obj); | ||
| const result1 = await cached.getValue(); | ||
| expect(result1).toMatchObject({ base: 1, fromFetch: true }); | ||
| const result2 = await cached.getValue(); | ||
| expect(result2).toMatchObject({ | ||
| base: 1, | ||
| fromFetch: true, | ||
| fromCache: true, | ||
| }); | ||
| }); | ||
| }); | ||
| describe("Nested Objects", () => { | ||
| test("should handle nested object methods", async () => { | ||
| let callCount = 0; | ||
| const obj = { | ||
| api: { | ||
| users: { | ||
| get: (id) => { | ||
| callCount++; | ||
| return { id, name: `User ${id}` }; | ||
| }, | ||
| }, | ||
| }, | ||
| }; | ||
| const cached = KeyvCacheProxy({ store })(obj); | ||
| await cached.api.users.get(1); | ||
| await cached.api.users.get(1); | ||
| expect(callCount).toBe(1); | ||
| }); | ||
| test("should propagate hooks to nested objects", async () => { | ||
| const hookCalls = []; | ||
| const obj = { | ||
| level1: { | ||
| level2: { | ||
| method: () => "result", | ||
| }, | ||
| }, | ||
| }; | ||
| const cached = KeyvCacheProxy({ | ||
| store, | ||
| onFetch: (key) => { | ||
| hookCalls.push(key); | ||
| }, | ||
| })(obj); | ||
| await cached.level1.level2.method(); | ||
| expect(hookCalls.length).toBe(1); | ||
| expect(hookCalls[0]).toContain("level1.level2.method"); | ||
| }); | ||
| test("should cache nested methods independently", async () => { | ||
| const calls = { method1: 0, method2: 0 }; | ||
| const obj = { | ||
| nested: { | ||
| method1: () => { | ||
| calls.method1++; | ||
| return "result1"; | ||
| }, | ||
| method2: () => { | ||
| calls.method2++; | ||
| return "result2"; | ||
| }, | ||
| }, | ||
| }; | ||
| const cached = KeyvCacheProxy({ store })(obj); | ||
| await cached.nested.method1(); | ||
| await cached.nested.method1(); | ||
| await cached.nested.method2(); | ||
| await cached.nested.method2(); | ||
| expect(calls.method1).toBe(1); | ||
| expect(calls.method2).toBe(1); | ||
| }); | ||
| }); | ||
| describe("Prefix", () => { | ||
| test("should add prefix to cache keys", async () => { | ||
| const keys = []; | ||
| const obj = { | ||
| getData: () => "data", | ||
| }; | ||
| const cached = KeyvCacheProxy({ | ||
| store, | ||
| prefix: "myapp:", | ||
| onFetch: (key) => { | ||
| keys.push(key); | ||
| }, | ||
| })(obj); | ||
| await cached.getData(); | ||
| expect(keys[0]).toStartWith("myapp:"); | ||
| }); | ||
| test("should prefix nested object keys correctly", async () => { | ||
| const keys = []; | ||
| const obj = { | ||
| api: { | ||
| getData: () => "data", | ||
| }, | ||
| }; | ||
| const cached = KeyvCacheProxy({ | ||
| store, | ||
| prefix: "app:", | ||
| onFetch: (key) => { | ||
| keys.push(key); | ||
| }, | ||
| })(obj); | ||
| await cached.api.getData(); | ||
| expect(keys[0]).toBe("app:api.getData:[]"); | ||
| }); | ||
| }); | ||
| describe("TTL", () => { | ||
| test("should expire cache after TTL", async () => { | ||
| let callCount = 0; | ||
| const obj = { | ||
| getValue: () => { | ||
| callCount++; | ||
| return callCount; | ||
| }, | ||
| }; | ||
| const cached = KeyvCacheProxy({ | ||
| store, | ||
| ttl: 100, // 100ms | ||
| })(obj); | ||
| const result1 = await cached.getValue(); | ||
| expect(result1).toBe(1); | ||
| const result2 = await cached.getValue(); | ||
| expect(result2).toBe(1); // Cached | ||
| // Wait for TTL to expire | ||
| await new Promise((resolve) => setTimeout(resolve, 150)); | ||
| const result3 = await cached.getValue(); | ||
| expect(result3).toBe(2); // Fresh call | ||
| }); | ||
| }); | ||
| describe("Non-function Properties", () => { | ||
| test("should return non-function properties as-is", async () => { | ||
| const obj = { | ||
| value: 42, | ||
| text: "hello", | ||
| method: () => "result", | ||
| }; | ||
| const cached = KeyvCacheProxy({ store })(obj); | ||
| expect(cached.value).toBe(42); | ||
| expect(cached.text).toBe("hello"); | ||
| }); | ||
| test("should handle null and undefined properties", async () => { | ||
| const obj = { | ||
| nullValue: null, | ||
| undefinedValue: undefined, | ||
| method: () => "result", | ||
| }; | ||
| const cached = KeyvCacheProxy({ store })(obj); | ||
| expect(cached.nullValue).toBe(null); | ||
| expect(cached.undefinedValue).toBe(undefined); | ||
| }); | ||
| }); | ||
| describe("Edge Cases", () => { | ||
| test("should handle methods with no arguments", async () => { | ||
| let callCount = 0; | ||
| const obj = { | ||
| getValue: () => { | ||
| callCount++; | ||
| return "value"; | ||
| }, | ||
| }; | ||
| const cached = KeyvCacheProxy({ store })(obj); | ||
| await cached.getValue(); | ||
| await cached.getValue(); | ||
| expect(callCount).toBe(1); | ||
| }); | ||
| test("should handle methods with complex object arguments", async () => { | ||
| let callCount = 0; | ||
| const obj = { | ||
| process: (data) => { | ||
| callCount++; | ||
| return data.nested.value; | ||
| }, | ||
| }; | ||
| const cached = KeyvCacheProxy({ store })(obj); | ||
| const arg = { id: 1, nested: { value: "test" } }; | ||
| await cached.process(arg); | ||
| await cached.process(arg); | ||
| expect(callCount).toBe(1); | ||
| }); | ||
| test("should handle undefined cache values", async () => { | ||
| const obj = { | ||
| getValue: () => undefined, | ||
| }; | ||
| const cached = KeyvCacheProxy({ store })(obj); | ||
| const result = await cached.getValue(); | ||
| expect(result).toBe(undefined); | ||
| }); | ||
| test("should handle null return values", async () => { | ||
| let _callCount = 0; | ||
| const obj = { | ||
| getValue: () => { | ||
| _callCount++; | ||
| return null; | ||
| }, | ||
| }; | ||
| const cached = KeyvCacheProxy({ store })(obj); | ||
| await cached.getValue(); | ||
| await cached.getValue(); | ||
| // Note: null values won't be cached because store.get returns undefined for missing keys | ||
| // This is expected Keyv behavior | ||
| }); | ||
| test("should handle errors in methods", async () => { | ||
| const obj = { | ||
| throwError: () => { | ||
| throw new Error("Test error"); | ||
| }, | ||
| }; | ||
| const cached = KeyvCacheProxy({ store })(obj); | ||
| await expect(cached.throwError()).rejects.toThrow("Test error"); | ||
| }); | ||
| test("should handle errors in hooks", async () => { | ||
| const obj = { | ||
| getValue: () => 42, | ||
| }; | ||
| const cached = KeyvCacheProxy({ | ||
| store, | ||
| onFetch: () => { | ||
| throw new Error("Hook error"); | ||
| }, | ||
| })(obj); | ||
| await expect(cached.getValue()).rejects.toThrow("Hook error"); | ||
| }); | ||
| test("should work with Map as store", async () => { | ||
| let callCount = 0; | ||
| const mapStore = new Map(); | ||
| const obj = { | ||
| getValue: (x) => { | ||
| callCount++; | ||
| return x * 2; | ||
| }, | ||
| }; | ||
| const cached = KeyvCacheProxy({ store: mapStore })(obj); | ||
| await cached.getValue(5); | ||
| await cached.getValue(5); | ||
| expect(callCount).toBe(1); | ||
| }); | ||
| }); | ||
| describe("Type Preservation", () => { | ||
| test("should preserve method signatures", async () => { | ||
| const obj = { | ||
| add: (a, b) => a + b, | ||
| concat: (a, b) => a + b, | ||
| }; | ||
| const cached = KeyvCacheProxy({ store })(obj); | ||
| const sum = await cached.add(1, 2); | ||
| const text = await cached.concat("hello", "world"); | ||
| expect(sum).toBe(3); | ||
| expect(text).toBe("helloworld"); | ||
| }); | ||
| }); | ||
| }); | ||
| describe("globalThisCached", () => { | ||
| test("should cache computed values", () => { | ||
| let callCount = 0; | ||
| const compute = () => { | ||
| callCount++; | ||
| return { value: 42 }; | ||
| }; | ||
| const uniqueKey = `test-key-${Math.random()}`; | ||
| const result1 = globalThisCached(uniqueKey, compute); | ||
| const result2 = globalThisCached(uniqueKey, compute); | ||
| expect(result1).toBe(result2); | ||
| expect(callCount).toBe(1); | ||
| }); | ||
| test("should support different cache keys", () => { | ||
| const key1 = `key1-${Math.random()}`; | ||
| const key2 = `key2-${Math.random()}`; | ||
| const result1 = globalThisCached(key1, () => ({ id: 1 })); | ||
| const result2 = globalThisCached(key2, () => ({ id: 2 })); | ||
| expect(result1).not.toBe(result2); | ||
| expect(result1.id).toBe(1); | ||
| expect(result2.id).toBe(2); | ||
| }); | ||
| test("should work with sync computations", () => { | ||
| const uniqueKey = `sync-${Math.random()}`; | ||
| const value = globalThisCached(uniqueKey, () => "test-value"); | ||
| expect(value).toBe("test-value"); | ||
| }); | ||
| test("should handle primitive values", () => { | ||
| const num = globalThisCached(`number-${Math.random()}`, () => 123); | ||
| const str = globalThisCached(`string-${Math.random()}`, () => "hello"); | ||
| const bool = globalThisCached(`boolean-${Math.random()}`, () => true); | ||
| expect(num).toBe(123); | ||
| expect(str).toBe("hello"); | ||
| expect(bool).toBe(true); | ||
| }); | ||
| }); | ||
| //# sourceMappingURL=index.test.js.map |
| {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"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"} |
+10
-14
@@ -8,22 +8,18 @@ #!/usr/bin/env bun --watch | ||
| const gh = KeyvCacheProxy({ | ||
| store: kv, | ||
| ttl: 600e3, | ||
| prefix: `github.`, | ||
| onHit: (key) => console.log(`Cache hit: ${key}`), | ||
| onMiss: (key) => console.log(`Cache miss: ${key}`), | ||
| store: kv, | ||
| ttl: 600e3, | ||
| prefix: `github.`, | ||
| onHit: (key) => console.log(`Cache hit: ${key}`), | ||
| onMiss: (key) => console.log(`Cache miss: ${key}`), | ||
| })( | ||
| new Octokit({ | ||
| // auth | ||
| }).rest, | ||
| new Octokit({ | ||
| // auth | ||
| }).rest, | ||
| ); | ||
| console.log( | ||
| (await gh.repos.get({ owner: "snomiao", repo: "snomiao" })).data.html_url, | ||
| ); | ||
| console.log((await gh.repos.get({ owner: "snomiao", repo: "snomiao" })).data.html_url); | ||
| // prints: cache miss: github.repos.get:[{"owner":"snomiao","repo":"snomiao"}] | ||
| // returns fresh result | ||
| console.log( | ||
| (await gh.repos.get({ owner: "snomiao", repo: "snomiao" })).data.html_url, | ||
| ); | ||
| console.log((await gh.repos.get({ owner: "snomiao", repo: "snomiao" })).data.html_url); | ||
| // prints: cache hit: github.repos.get:[{"owner":"snomiao","repo":"snomiao"}] | ||
| // returns cached result | ||
| //# sourceMappingURL=github.js.map |
+57
-23
@@ -10,4 +10,4 @@ import type Keyv from "keyv"; | ||
| * @param ttl - Time-to-live for cached entries in milliseconds. | ||
| * @param onMiss - Optional callback function invoked on cache misses. | ||
| * @param onHit - Optional callback function invoked on cache hits. | ||
| * @param onCache - Optional hook called when data is loaded from cache. Receives key and cached value, can return modified value. | ||
| * @param onFetch - Optional hook called when data is freshly fetched. Receives key and fetched value, can return modified value before caching. | ||
| * @param prefix - Optional prefix to prepend to cache keys. | ||
@@ -19,3 +19,3 @@ * | ||
| * | ||
| * for example, github api caching | ||
| * Basic usage with GitHub API caching | ||
| * ```ts | ||
@@ -28,24 +28,58 @@ * import { Keyv } from "keyv"; | ||
| * const gh = KeyvCacheProxy({ | ||
| * store: kv, | ||
| * ttl: 600e3, | ||
| * prefix: `api.`, | ||
| * // hooks | ||
| * onHit: (key) => console.log(`Cache hit: ${key}`), | ||
| * onMiss: (key) => console.log(`Cache miss: ${key}`), | ||
| * store: kv, | ||
| * ttl: 600e3, | ||
| * prefix: `api.`, | ||
| * // hooks for logging | ||
| * onCache: (key, value) => value ? console.log(`Cache hit: ${key}`) : console.log(`Cache miss: ${key}`), | ||
| * onFetch: (key, value) => console.log(`Fetched fresh: ${key}`), | ||
| * })(new Octokit()); | ||
| *r | ||
| * // first call - cache miss, fetches fresh data | ||
| * await gh.repos.get({ owner: "snomiao", repo: "snomiao" }); | ||
| * // prints: Cache miss: api.repos.get:[{"owner":"snomiao","repo":"snomiao"}] | ||
| * // prints: Fetched fresh: api.repos.get:[{"owner":"snomiao","repo":"snomiao"}] | ||
| * | ||
| * // first call, cache miss | ||
| * console.log( | ||
| * (await gh.repos.get({ owner: "snomiao", repo: "snomiao" })).data.html_url, | ||
| * ); | ||
| * // prints: cache miss: api.repos.get:[{"owner":"snomiao","repo":"snomiao"}] | ||
| * // returns fresh result | ||
| * // second call - cache hit, returns cached data | ||
| * await gh.repos.get({ owner: "snomiao", repo: "snomiao" }); | ||
| * // prints: Cache hit: api.repos.get:[{"owner":"snomiao","repo":"snomiao"}] | ||
| * ``` | ||
| * | ||
| * // second call, cache hit | ||
| * console.log( | ||
| * (await gh.repos.get({ owner: "snomiao", repo: "snomiao" })).data.html_url, | ||
| * ); | ||
| * // prints: cache hit: api.repos.get:[{"owner":"snomiao","repo":"snomiao"}] | ||
| * // returns cached result | ||
| * @example | ||
| * | ||
| * Advanced usage - modifying cached/fetched data | ||
| * ```ts | ||
| * const gh = KeyvCacheProxy({ | ||
| * store: kv, | ||
| * ttl: 600e3, | ||
| * // Modify cached data before returning (called on every invocation) | ||
| * onCache: (key, value) => { | ||
| * if (value !== undefined) { | ||
| * console.log(`Using cached data for ${key}`); | ||
| * return { ...value, fromCache: true }; | ||
| * } | ||
| * }, | ||
| * // Transform fetched data before caching | ||
| * onFetch: (key, value) => { | ||
| * console.log(`Caching fresh data for ${key}`); | ||
| * return { ...value, fetchedAt: Date.now() }; | ||
| * }, | ||
| * })(new Octokit()); | ||
| * ``` | ||
| * | ||
| * @example | ||
| * | ||
| * Force cache refresh by returning null from onCache | ||
| * ```ts | ||
| * const gh = KeyvCacheProxy({ | ||
| * store: kv, | ||
| * ttl: 600e3, | ||
| * onCache: (key, value) => { | ||
| * // Return null to force refetch even if cached | ||
| * if (shouldRefresh(value)) { | ||
| * return null; // Forces cache miss | ||
| * } | ||
| * return value; // Use cached value | ||
| * }, | ||
| * })(new Octokit()); | ||
| * ``` | ||
| */ | ||
@@ -55,4 +89,4 @@ export default function KeyvCacheProxy(options: { | ||
| ttl?: number; | ||
| onMiss?: (key: string) => void; | ||
| onHit?: (key: string) => void; | ||
| onCache?: (key: string, value: any) => Promise<any> | any; | ||
| onFetch?: (key: string, value: any) => Promise<any> | any; | ||
| prefix?: string; | ||
@@ -59,0 +93,0 @@ hot?: boolean; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,MAAM,CAAC;AAC7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,OAAO,EAAE;IAC/C,KAAK,EAAE,IAAI,GAAG,gBAAgB,GAAG,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;CACd,IAGQ,CAAC,SAAS,MAAM,EAAE,KAAK,CAAC,KAAG,eAAe,CAAC,CAAC,CAAC,CAmCrD;AAED,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI;KAC/B,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,MAAM,CAAC,GACvD,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GACnC,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GAClB,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GACrB,CAAC,CAAC,CAAC,CAAC;CACR,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,CAcrE"} | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,MAAM,CAAC;AAC7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+EG;AACH,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,OAAO,EAAE;IAC9C,KAAK,EAAE,IAAI,GAAG,gBAAgB,GAAG,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IAC1D,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,IAGS,CAAC,SAAS,MAAM,EAAE,KAAK,CAAC,KAAG,eAAe,CAAC,CAAC,CAAC,CAuDtD;AAED,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI;KAC9B,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,MAAM,CAAC,GACtD,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GACnC,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GACjB,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GACrB,CAAC,CAAC,CAAC,CAAC;CACX,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,CAcrE"} |
+80
-28
@@ -8,4 +8,4 @@ /** | ||
| * @param ttl - Time-to-live for cached entries in milliseconds. | ||
| * @param onMiss - Optional callback function invoked on cache misses. | ||
| * @param onHit - Optional callback function invoked on cache hits. | ||
| * @param onCache - Optional hook called when data is loaded from cache. Receives key and cached value, can return modified value. | ||
| * @param onFetch - Optional hook called when data is freshly fetched. Receives key and fetched value, can return modified value before caching. | ||
| * @param prefix - Optional prefix to prepend to cache keys. | ||
@@ -17,3 +17,3 @@ * | ||
| * | ||
| * for example, github api caching | ||
| * Basic usage with GitHub API caching | ||
| * ```ts | ||
@@ -26,27 +26,61 @@ * import { Keyv } from "keyv"; | ||
| * const gh = KeyvCacheProxy({ | ||
| * store: kv, | ||
| * ttl: 600e3, | ||
| * prefix: `api.`, | ||
| * // hooks | ||
| * onHit: (key) => console.log(`Cache hit: ${key}`), | ||
| * onMiss: (key) => console.log(`Cache miss: ${key}`), | ||
| * store: kv, | ||
| * ttl: 600e3, | ||
| * prefix: `api.`, | ||
| * // hooks for logging | ||
| * onCache: (key, value) => value ? console.log(`Cache hit: ${key}`) : console.log(`Cache miss: ${key}`), | ||
| * onFetch: (key, value) => console.log(`Fetched fresh: ${key}`), | ||
| * })(new Octokit()); | ||
| *r | ||
| * // first call - cache miss, fetches fresh data | ||
| * await gh.repos.get({ owner: "snomiao", repo: "snomiao" }); | ||
| * // prints: Cache miss: api.repos.get:[{"owner":"snomiao","repo":"snomiao"}] | ||
| * // prints: Fetched fresh: api.repos.get:[{"owner":"snomiao","repo":"snomiao"}] | ||
| * | ||
| * // first call, cache miss | ||
| * console.log( | ||
| * (await gh.repos.get({ owner: "snomiao", repo: "snomiao" })).data.html_url, | ||
| * ); | ||
| * // prints: cache miss: api.repos.get:[{"owner":"snomiao","repo":"snomiao"}] | ||
| * // returns fresh result | ||
| * // second call - cache hit, returns cached data | ||
| * await gh.repos.get({ owner: "snomiao", repo: "snomiao" }); | ||
| * // prints: Cache hit: api.repos.get:[{"owner":"snomiao","repo":"snomiao"}] | ||
| * ``` | ||
| * | ||
| * // second call, cache hit | ||
| * console.log( | ||
| * (await gh.repos.get({ owner: "snomiao", repo: "snomiao" })).data.html_url, | ||
| * ); | ||
| * // prints: cache hit: api.repos.get:[{"owner":"snomiao","repo":"snomiao"}] | ||
| * // returns cached result | ||
| * @example | ||
| * | ||
| * Advanced usage - modifying cached/fetched data | ||
| * ```ts | ||
| * const gh = KeyvCacheProxy({ | ||
| * store: kv, | ||
| * ttl: 600e3, | ||
| * // Modify cached data before returning (called on every invocation) | ||
| * onCache: (key, value) => { | ||
| * if (value !== undefined) { | ||
| * console.log(`Using cached data for ${key}`); | ||
| * return { ...value, fromCache: true }; | ||
| * } | ||
| * }, | ||
| * // Transform fetched data before caching | ||
| * onFetch: (key, value) => { | ||
| * console.log(`Caching fresh data for ${key}`); | ||
| * return { ...value, fetchedAt: Date.now() }; | ||
| * }, | ||
| * })(new Octokit()); | ||
| * ``` | ||
| * | ||
| * @example | ||
| * | ||
| * Force cache refresh by returning null from onCache | ||
| * ```ts | ||
| * const gh = KeyvCacheProxy({ | ||
| * store: kv, | ||
| * ttl: 600e3, | ||
| * onCache: (key, value) => { | ||
| * // Return null to force refetch even if cached | ||
| * if (shouldRefresh(value)) { | ||
| * return null; // Forces cache miss | ||
| * } | ||
| * return value; // Use cached value | ||
| * }, | ||
| * })(new Octokit()); | ||
| * ``` | ||
| */ | ||
| export default function KeyvCacheProxy(options) { | ||
| const { store, ttl, onMiss, onHit, prefix = "" } = options; | ||
| const { store, ttl, onCache, onFetch, prefix = "" } = options; | ||
| return (obj) => new Proxy(obj, { | ||
@@ -60,9 +94,27 @@ get(target, prop, receiver) { | ||
| const key = `${prefix}${String(prop)}:${JSON.stringify(args)}`; | ||
| const cached = await store.get(key); | ||
| // Check cache | ||
| let cached = await store.get(key); | ||
| if (onCache) { | ||
| const modified = await onCache(key, cached); | ||
| if (modified === null) { | ||
| cached = undefined; // treat null as cache miss | ||
| } | ||
| else if (modified !== undefined) { | ||
| return modified; // return modified cached value | ||
| } // else return original cached value | ||
| } | ||
| if (cached !== undefined) { | ||
| onHit?.(key); | ||
| // onCache hook - can modify cached value before returning | ||
| return cached; | ||
| } | ||
| onMiss?.(key); | ||
| const result = await method(...args); | ||
| // Fetch fresh data | ||
| let result = await method(...args); // call original method | ||
| // onFetch hook - can modify result before caching | ||
| if (onFetch) { | ||
| // call onFetch hook, can modify result before caching | ||
| const modified = await onFetch(key, result); | ||
| if (modified !== undefined) { | ||
| result = modified; | ||
| } | ||
| } | ||
| await store.set(key, result, ttl); | ||
@@ -77,4 +129,4 @@ return result; | ||
| ttl, | ||
| onMiss, | ||
| onHit, | ||
| onCache, | ||
| onFetch, | ||
| prefix: `${prefix}${String(prop)}.`, | ||
@@ -81,0 +133,0 @@ })(val); |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,OAOtC;IACA,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC;IAE3D,OAAO,CAAmB,GAAM,EAAsB,EAAE,CACvD,IAAI,KAAK,CAAC,GAAG,EAAE;QACd,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ;YACzB,wCAAwC;YACxC,MAAM,GAAG,GAAG,MAAM,CAAC,IAAe,CAAC,CAAC;YACpC,IAAI,OAAO,GAAG,KAAK,UAAU,EAAE,CAAC;gBAC/B,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC7B,OAAO,KAAK,EAAE,GAAG,IAAW,EAAE,EAAE;oBAC/B,MAAM,GAAG,GAAG,GAAG,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC/D,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;oBACpC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;wBAC1B,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC;wBACb,OAAO,MAAM,CAAC;oBACf,CAAC;oBACD,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;oBACd,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;oBAErC,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;oBAClC,OAAO,MAAM,CAAC;gBACf,CAAC,CAAC;YACH,CAAC;YACD,gCAAgC;YAChC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gBAC7C,OAAO,cAAc,CAAC;oBACrB,KAAK;oBACL,GAAG;oBACH,MAAM;oBACN,KAAK;oBACL,MAAM,EAAE,GAAG,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG;iBACnC,CAAC,CAAC,GAAG,CAAC,CAAC;YACT,CAAC;YACD,oDAAoD;YACpD,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC5C,CAAC;KACD,CAAuB,CAAC;AAC3B,CAAC;AAUD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,gBAAgB,CAAI,IAAY,EAAE,OAAgB;IACjE,MAAM,CAAC,GAAG,UAET,CAAC;IACF,CAAC,CAAC,iCAAiC,KAAK,IAAI,GAAG,EAAE,CAAC;IAElD,MAAM,KAAK,GAAG,CAAC,CAAC,iCAAiC,CAAC;IAClD,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACrB,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAM,CAAC;IAC7B,CAAC;SAAM,CAAC;QACP,MAAM,MAAM,GAAG,OAAO,EAAE,CAAC;QACzB,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACxB,OAAO,MAAM,CAAC;IACf,CAAC;AACF,CAAC"} | ||
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} |
+60
-60
| { | ||
| "name": "keyv-cache-proxy", | ||
| "version": "0.0.12", | ||
| "description": "A transparent caching proxy for any object using Keyv - automatically cache method calls with TTL support", | ||
| "type": "module", | ||
| "main": "./dist/index.js", | ||
| "module": "./dist/index.js", | ||
| "types": "./dist/index.d.ts", | ||
| "exports": { | ||
| ".": { | ||
| "types": "./dist/index.d.ts", | ||
| "import": "./dist/index.js", | ||
| "default": "./dist/index.js" | ||
| } | ||
| }, | ||
| "files": [ | ||
| "dist", | ||
| "README.md", | ||
| "LICENSE" | ||
| ], | ||
| "keywords": [ | ||
| "keyv", | ||
| "cache", | ||
| "proxy", | ||
| "caching", | ||
| "memoization", | ||
| "ttl", | ||
| "storage", | ||
| "key-value", | ||
| "method-cache", | ||
| "transparent-cache" | ||
| ], | ||
| "author": "snomiao", | ||
| "license": "MIT", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/snomiao/keyv-cache-proxy.git" | ||
| }, | ||
| "bugs": { | ||
| "url": "https://github.com/snomiao/keyv-cache-proxy/issues" | ||
| }, | ||
| "homepage": "https://github.com/snomiao/keyv-cache-proxy#readme", | ||
| "devDependencies": { | ||
| "@biomejs/biome": "^2.3.8", | ||
| "@types/bun": "latest", | ||
| "standard-version": "^9.5.0" | ||
| }, | ||
| "peerDependencies": { | ||
| "typescript": "^5.9.3", | ||
| "keyv": "^5.0.0" | ||
| }, | ||
| "dependencies": {}, | ||
| "scripts": { | ||
| "build": "tsc", | ||
| "fmt": "biome check --unsafe --write", | ||
| "prepack": "bun fmt && bun run build", | ||
| "release": "standard-version && git push --follow-tags && npm publish" | ||
| }, | ||
| "engines": { | ||
| "node": ">=18.0.0" | ||
| } | ||
| "name": "keyv-cache-proxy", | ||
| "version": "0.1.0", | ||
| "description": "A transparent caching proxy for any object using Keyv - automatically cache method calls with TTL support", | ||
| "type": "module", | ||
| "main": "./dist/index.js", | ||
| "module": "./dist/index.js", | ||
| "types": "./dist/index.d.ts", | ||
| "exports": { | ||
| ".": { | ||
| "types": "./dist/index.d.ts", | ||
| "import": "./dist/index.js", | ||
| "default": "./dist/index.js" | ||
| } | ||
| }, | ||
| "files": [ | ||
| "dist", | ||
| "README.md", | ||
| "LICENSE" | ||
| ], | ||
| "keywords": [ | ||
| "keyv", | ||
| "cache", | ||
| "proxy", | ||
| "caching", | ||
| "memoization", | ||
| "ttl", | ||
| "storage", | ||
| "key-value", | ||
| "method-cache", | ||
| "transparent-cache" | ||
| ], | ||
| "author": "snomiao", | ||
| "license": "MIT", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/snomiao/keyv-cache-proxy.git" | ||
| }, | ||
| "bugs": { | ||
| "url": "https://github.com/snomiao/keyv-cache-proxy/issues" | ||
| }, | ||
| "homepage": "https://github.com/snomiao/keyv-cache-proxy#readme", | ||
| "devDependencies": { | ||
| "@biomejs/biome": "^2.3.8", | ||
| "@types/bun": "latest", | ||
| "standard-version": "^9.5.0" | ||
| }, | ||
| "peerDependencies": { | ||
| "typescript": "^5.9.3", | ||
| "keyv": "^5.0.0" | ||
| }, | ||
| "dependencies": {}, | ||
| "scripts": { | ||
| "build": "tsc", | ||
| "fmt": "biome check --unsafe --write", | ||
| "prepack": "bun fmt && bun run build", | ||
| "release": "standard-version && git push --follow-tags && npm publish" | ||
| }, | ||
| "engines": { | ||
| "node": ">=18.0.0" | ||
| } | ||
| } |
+51
-12
@@ -11,3 +11,3 @@ # keyv-cache-proxy | ||
| - 🎯 **Deep proxy**: Automatically handles nested objects | ||
| - 📊 **Cache observability**: Optional callbacks for cache hits and misses | ||
| - 📊 **Cache observability**: Optional hooks for monitoring and modifying cached/fetched data | ||
| - 🔄 **Async-first**: Automatically converts all methods to async | ||
@@ -87,4 +87,4 @@ | ||
| prefix: 'github.', | ||
| onHit: (key) => console.log('Cache hit:', key), | ||
| onMiss: (key) => console.log('Cache miss:', key), | ||
| onCache: (key, value) => console.log('Cache hit:', key), | ||
| onFetch: (key, value) => console.log('Fetched fresh:', key), | ||
| })(new Octokit().rest); | ||
@@ -173,7 +173,9 @@ | ||
| ### Cache Observability | ||
| ### Cache Observability & Data Modification | ||
| Track cache performance: | ||
| ```typescript | ||
| let hits = 0; | ||
| let misses = 0; | ||
| let fetches = 0; | ||
@@ -183,9 +185,9 @@ const cached = KeyvCacheProxy({ | ||
| ttl: 60000, | ||
| onHit: (key) => { | ||
| onCache: (key, value) => { | ||
| hits++; | ||
| console.log(`Cache hit for ${key}. Total hits: ${hits}`); | ||
| }, | ||
| onMiss: (key) => { | ||
| misses++; | ||
| console.log(`Cache miss for ${key}. Total misses: ${misses}`); | ||
| onFetch: (key, value) => { | ||
| fetches++; | ||
| console.log(`Fetched fresh for ${key}. Total fetches: ${fetches}`); | ||
| }, | ||
@@ -195,2 +197,39 @@ })(myObject); | ||
| Modify cached/fetched data: | ||
| ```typescript | ||
| const cached = KeyvCacheProxy({ | ||
| store: new Keyv(), | ||
| ttl: 60000, | ||
| // Add metadata to cached data (called on every invocation) | ||
| onCache: (key, value) => { | ||
| if (value !== undefined) { | ||
| console.log('Returning cached data'); | ||
| return { ...value, fromCache: true, cachedAt: Date.now() }; | ||
| } | ||
| }, | ||
| // Transform fetched data before caching | ||
| onFetch: (key, value) => { | ||
| console.log('Processing fresh data'); | ||
| return { ...value, fetchedAt: Date.now(), processed: true }; | ||
| }, | ||
| })(myObject); | ||
| ``` | ||
| Force cache refresh: | ||
| ```typescript | ||
| const cached = KeyvCacheProxy({ | ||
| store: new Keyv(), | ||
| ttl: 60000, | ||
| onCache: (key, value) => { | ||
| // Return null to force refetch even if cached | ||
| if (value && isStale(value)) { | ||
| return null; // Forces cache miss and refetch | ||
| } | ||
| return value; // Use cached value | ||
| }, | ||
| })(myObject); | ||
| ``` | ||
| ## API | ||
@@ -205,6 +244,6 @@ | ||
| - `store` (required): A Keyv instance for cache storage | ||
| - `ttl` (required): Time-to-live in milliseconds for cached values | ||
| - `ttl` (optional): Time-to-live in milliseconds for cached values | ||
| - `prefix` (optional): Prefix for cache keys (default: `""`) | ||
| - `onHit` (optional): Callback function called on cache hits `(key: string) => void` | ||
| - `onMiss` (optional): Callback function called on cache misses `(key: string) => void` | ||
| - `onCache` (optional): Hook called on **every invocation** (before cache lookup). Receives cached value (or `undefined` on cache miss). Can modify the cached value or return `null` to force refetch: `(key: string, value: any) => any | null | Promise<any | null>` | ||
| - `onFetch` (optional): Hook called when data is freshly fetched (cache miss). Can modify the value before caching: `(key: string, value: any) => any | Promise<any>` | ||
@@ -211,0 +250,0 @@ #### Returns |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
68310
221.87%15
36.36%852
292.63%308
14.5%0
-100%7
Infinity%