### Install Dependencies and Run Locally Source: https://github.com/get-convex/action-cache/blob/main/CONTRIBUTING.md Installs project dependencies and starts the development server. Run this before making code changes. ```sh npm i npm run dev ``` -------------------------------- ### ActionCache Configuration Example Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/types.md Example of how to configure and instantiate an ActionCache. Ensure the action reference is correctly typed and imported. ```typescript import { ActionCache } from "@convex-dev/action-cache"; const config: ActionCacheConfig = { action: internal.myAction, name: "myAction-v1", ttl: 1000 * 60 * 60 * 24, // 24 hours log: true, }; const cache = new ActionCache(components.actionCache, config); ``` -------------------------------- ### Register Action Cache Component (Example) Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/testing.md A concise example demonstrating the registration of the action-cache component with a specified name. ```typescript const t = convexTest(schema, {}); register(t, "actionCache"); ``` -------------------------------- ### Example Usage of Get Query Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/component-api.md Demonstrates how to use the 'get' query to retrieve a cached value. It shows conditional logic to handle both cache hits and misses, returning the cached value if available. ```typescript const result = await ctx.runQuery(component.lib.get, { name: "embeddings", args: { text: "hello" }, ttl: null, }); if (result.kind === "hit") { return result.value; } ``` -------------------------------- ### Example Metadata Documents Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/database-schema.md Illustrates the structure of documents stored in the metadata table. These examples show typical values for `_id`, `_creationTime`, `valueId`, and `expiresAt`. ```json { _id: Id("metadata", "..."), _creationTime: 1719648000000, valueId: Id("values", "..."), expiresAt: 1719733400000, // 24 hours later } ``` ```json { _id: Id("metadata", "..."), _creationTime: 1719648000000, valueId: Id("values", "..."), expiresAt: 1719648300000, // 5 minutes later } ``` -------------------------------- ### Install Action Cache Package Source: https://github.com/get-convex/action-cache/blob/main/README.md Command to install the Action Cache component package using npm. ```bash npm install @convex-dev/action-cache ``` -------------------------------- ### Action Cache TTL Examples Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/README.md Examples demonstrating how to set the Time To Live (TTL) for cache entries in milliseconds. Use these to define how long cache data should remain valid. ```typescript ttl: 1000 * 60, // 1 minute ttl: 1000 * 60 * 5, // 5 minutes ttl: 1000 * 60 * 60, // 1 hour ttl: 1000 * 60 * 60 * 24, // 1 day ttl: 1000 * 60 * 60 * 24 * 7, // 1 week ``` -------------------------------- ### Setup Convex Test Environment Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/quick-reference.md Initialize the Convex test environment and register the action cache module for testing. ```typescript import { convexTest } from "convex-test"; import { register } from "@convex-dev/action-cache/test"; const t = convexTest(schema, {}); register(t, "actionCache"); test("cache works", async () => { // Test cache operations... }); ``` -------------------------------- ### Initialize Action Cache Schema Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/database-schema.md Automatically creates the 'values' and 'metadata' tables when the component is installed. No manual schema setup is needed. ```typescript import cache from "@convex-dev/action-cache/convex.config.js"; const app = defineApp(); app.use(cache); // Creates the schema ``` -------------------------------- ### ActionCache Fetch Example with Type Inference Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/types.md Demonstrates how ActionCache infers argument and return types from a defined action. Shows a type error example for incorrect argument types. ```typescript const myAction = internalAction({ args: { text: v.string(), count: v.number() }, handler: async (_ctx, args) => ({ result: "processed" }), }); const cache = new ActionCache(components.actionCache, { action: myAction, }); // TypeScript infers args parameter type from myAction const result = await cache.fetch(ctx, { text: "hello", count: 5 }); // result is inferred as { result: "processed" } // This would be a type error: // const result = await cache.fetch(ctx, { text: 123 }); // number != string ``` -------------------------------- ### Quick Start: Create and Use Action Cache Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/README.md Demonstrates how to define an expensive action, create an ActionCache instance, and use it within another action to fetch cached results. ```typescript import { ActionCache } from "@convex-dev/action-cache"; import { components } from "./_generated/api"; import { internalAction, action } from "./_generated/server"; import { v } from "convex/values"; // Define the expensive action export const expensiveCompute = internalAction({ args: { input: v.string() }, handler: async (_ctx, { input }) => { // ... expensive work ... return { result: "..." }; }, }); // Create cache instance const cache = new ActionCache(components.actionCache, { action: internal.expensiveCompute, name: "compute-v1", ttl: 1000 * 60 * 60, // 1 hour }); // Use in your action export const myAction = action({ args: { input: v.string() }, handler: async (ctx, { input }) => { const cached = await cache.fetch(ctx, { input }); return cached; }, }); ``` -------------------------------- ### Instantiate ActionCache Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/api-reference.md Example of how to create a new ActionCache instance with a specific action, name, TTL, and logging enabled. Ensure the necessary imports are included. ```typescript import { ActionCache } from "@convex-dev/action-cache"; import { components } from "./_generated/api"; import { internal } from "./_generated/api"; const cache = new ActionCache(components.actionCache, { action: internal.example.myExpensiveAction, name: "myActionV1", ttl: 1000 * 60 * 60, // 1 hour log: true, }); ``` -------------------------------- ### Build One-Off Package Source: https://github.com/get-convex/action-cache/blob/main/CONTRIBUTING.md Cleans previous builds, installs exact dependencies, and packages the project. Use for creating distributable artifacts. ```sh npm run clean npm run ci npm pack ``` -------------------------------- ### Example Values Table Document (With TTL) Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/database-schema.md Illustrates the structure of a document in the `values` table for an entry with a Time-To-Live (TTL), including a reference to the `metadataId`. ```typescript // Entry with TTL { _id: Id("values", "..."), _creationTime: 1719648000000, name: "weather-v1", args: { lat: 40.7128, lon: -74.0060 }, value: { temperature: 75, humidity: 65 }, metadataId: Id("metadata", "..."), } ``` -------------------------------- ### Action Cache Initialization with TTL Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/types.md Demonstrates how to initialize an ActionCache with a specific Time-To-Live (TTL) using the DAY constant. This example sets the cache to expire after 7 days. ```typescript import { DAY } from "@convex-dev/action-cache/test"; const cache = new ActionCache(components.actionCache, { action: internal.expensive, ttl: DAY * 7, // 7 days }); ``` -------------------------------- ### Define Get Query for Action Cache Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/component-api.md Defines the signature for the 'get' query, which retrieves a value from the cache. It specifies arguments for cache name, entry identification, and TTL, and outlines the possible return types for cache hits and misses. ```typescript query({ args: { name: string; args: any; ttl: number | null; }; returns: { kind: "hit"; value: any; } | { kind: "miss"; expiredEntry?: Id<"values">; }; handler: async (ctx: QueryCtx, args) => ...; }) ``` -------------------------------- ### Example Values Table Document (Indefinite) Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/database-schema.md Illustrates the structure of a document in the `values` table for an entry without a Time-To-Live (TTL). ```typescript // Entry without TTL (indefinite) { _id: Id("values", "..."), _creationTime: 1719648000000, name: "geocode-v1", args: { location: "New York" }, value: [40.7128, -74.0060], // metadataId: undefined } ``` -------------------------------- ### Test get() Query for Cache Hit/Miss Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/testing.md Tests the get() query to verify correct cache hit and miss behavior. Ensures that a miss occurs on an empty cache and a hit occurs after a value is put. ```typescript test("get returns correct hit/miss", async () => { const t = convexTest(schema, {}); register(t); // Miss on empty cache const miss = await t.query(api.lib.get, { name: "cache1", args: { id: 123 }, ttl: null, }); expect(miss.kind).toBe("miss"); // Put a value await t.mutation(api.lib.put, { name: "cache1", args: { id: 123 }, value: { status: "ok" }, ttl: null, }); // Now hit const hit = await t.query(api.lib.get, { name: "cache1", args: { id: 123 }, ttl: null, }); expect(hit.kind).toBe("hit"); expect(hit.value).toEqual({ status: "ok" }); }); ``` -------------------------------- ### Test Cache Put and Get Operations Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/quick-reference.md Demonstrates putting a value into the cache with a TTL and then retrieving it. Verifies that the retrieval is a 'hit' and returns the correct data. ```typescript // Put a value await t.mutation(api.lib.put, { name: "test", args: { key: "value" }, value: "data", ttl: 1000 * 60, }); // Get it const result = await t.query(api.lib.get, { name: "test", args: { key: "value" }, ttl: null, }); expect(result.kind).toBe("hit"); expect(result.value).toBe("data"); ``` -------------------------------- ### Configure Action Cache in convex.config.ts Source: https://github.com/get-convex/action-cache/blob/main/README.md Example of how to configure the Action Cache component in your Convex project's `convex.config.ts` file by using the `defineApp` and `use` functions. ```typescript // convex/convex.config.ts import { defineApp } from "convex/server"; import cache from "@convex-dev/action-cache/convex.config.js"; const app = defineApp(); app.use(cache); export default app; ``` -------------------------------- ### Action Cache Logging Output Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/quick-reference.md Example JSON logs generated by the Action Cache, indicating cache hits and misses. These logs help in understanding cache behavior. ```json {"type":"action-cache-stats","name":"cache-name","get":"hit"} ``` ```json {"type":"action-cache-stats","name":"cache-name","get":"miss","put":"created"} ``` ```json {"type":"action-cache-stats","name":"cache-name","get":"miss","put":"hit"} ``` -------------------------------- ### Action Cache Invalidation Examples Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/README.md Provides examples for removing specific cache entries, clearing all entries for a given cache name, or clearing all caches within a component. Use these to manage cache data lifecycle. ```typescript // Remove specific entry await cache.remove(ctx, { id: 123 }); // Clear entire cache await cache.removeAllForName(ctx); // Clear all caches in component await removeAll(ctx, components.actionCache); ``` -------------------------------- ### Action Cache Type Inference Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/quick-reference.md Demonstrates how TypeScript infers argument types for cache.fetch() based on the action definition. Shows correct usage and a type error example. ```typescript const action = internalAction({ args: { text: v.string(), count: v.number() }, handler: async (_ctx, { text, count }) => ({ result: "..." }), }); const cache = new ActionCache(components.actionCache, { action, }); // TypeScript knows the argument type const result = await cache.fetch(ctx, { text: "hello", count: 5 }); // ✓ Correct types // This is a type error await cache.fetch(ctx, { text: 123 }); // ✗ number is not string ``` -------------------------------- ### Action Cache Statistics Log Format Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/README.md Example of the JSON log output for action cache statistics. It indicates cache hits, misses, and put operations. ```json {"type":"action-cache-stats","name":"expensive","get":"miss","put":"created"} ``` ```json {"type":"action-cache-stats","name":"expensive","get":"hit"} ``` -------------------------------- ### Pre-warm Cache with Cron Job Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/usage-examples.md Periodically pre-warm the cache using a cron job. This example defines a cron job that runs every hour to refresh cache entries for a list of locations, ensuring fresh data is available. ```typescript import { cronJobs } from "convex/server"; const crons = cronJobs(); export const refreshCaches = mutation({ args: {}, handler: async (ctx) => { const locations = ["New York", "Los Angeles", "Chicago"]; for (const location of locations) { try { await geocodeCache.fetch(ctx, { location }, { force: true }); console.log(`Refreshed cache for ${location}`); } catch (error) { console.error(`Failed to refresh ${location}:`, error); } } }, }); crons.interval("refresh-caches", { hours: 1 }, api.refreshCaches, {}); export default crons; ``` -------------------------------- ### Define TTL Values in Milliseconds Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/quick-reference.md Examples of defining Time-To-Live (TTL) values in milliseconds for cache entries, including options for no expiration (null). ```typescript 1000 // 1 second 1000 * 60 // 1 minute 1000 * 60 * 5 // 5 minutes 1000 * 60 * 60 // 1 hour 1000 * 60 * 60 * 24 // 1 day 1000 * 60 * 60 * 24 * 7 // 1 week null // No expiration ``` -------------------------------- ### Test Cache Behavior Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/usage-examples.md Register the action-cache component and test cache behavior. This example demonstrates how to set up tests using `convex-test` to verify that the cache returns a hit on subsequent calls. ```typescript import { convexTest } from "convex-test"; import schema from "./convex/schema"; import { register } from "@convex-dev/action-cache/test"; import { expect, test } from "vitest"; test("cache returns hit on second call", async () => { const t = convexTest(schema, {}); // Register the action-cache component register(t, "actionCache"); // Run tests with cache... }); ``` -------------------------------- ### get Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/component-api.md Retrieves a value from the cache. Returns a cache hit if the entry exists and has not expired, considering both the original TTL and any new TTL passed in this request. ```APIDOC ## get ### Description Retrieves a value from the cache. Returns a cache hit if the entry exists and has not expired, considering both the original TTL and any new TTL passed in this request. ### Method Query ### Endpoint `component.lib.get` ### Parameters #### Arguments - **name** (`string`) - Required - Cache name identifying the cache entry group - **args** (`any`) - Required - Serialized arguments that identify the specific cache entry - **ttl** (`number | null`) - Required - TTL in milliseconds; if provided, the entry is treated as expired if it exceeds this TTL from creation. Pass `null` for no TTL check ### Response #### Success Response - **kind**: "hit" (`string`) - Indicates a cache hit. - **value**: `any` - The cached value. #### Miss Response - **kind**: "miss" (`string`) - Indicates a cache miss. - **expiredEntry**: `Id<"values">` - Optional - Set if the entry was found but expired. ### Example ```typescript const result = await ctx.runQuery(component.lib.get, { name: "embeddings", args: { text: "hello" }, ttl: null, }); if (result.kind === "hit") { return result.value; } ``` ``` -------------------------------- ### Cache LLM Generations Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/usage-examples.md Cache computationally expensive LLM generations for up to 30 days. This example shows how to initialize an ActionCache for LLM operations and use it within an action to return cached results instantly for identical prompts. ```typescript const llmCache = new ActionCache(components.actionCache, { action: internal.llmGeneration, name: "llm-gen-v1", ttl: 1000 * 60 * 60 * 24 * 30, // 30 days }); export const llmGeneration = internalAction({ args: { prompt: v.string(), model: v.string() }, handler: async (_ctx, { prompt, model }) => { const response = await fetch("https://api.openai.com/v1/chat/completions", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${process.env.OPENAI_API_KEY}`, }, body: JSON.stringify({ model, messages: [{ role: "user", content: prompt }], }), }); const data = await response.json(); return data.choices[0].message.content; }, }); export const generateText = action({ args: { prompt: v.string(), model: v.string() }, handler: async (ctx, { prompt, model }) => { // Identical prompts return cached results instantly return llmCache.fetch(ctx, { prompt, model }); }, }); ``` -------------------------------- ### Cache Versioning Example Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/usage-examples.md Demonstrates how to invalidate cache entries by changing the cache name when the action implementation is updated. This ensures that new data uses the updated logic, while old data remains accessible via its original cache name. ```typescript // Version 1: Original implementation const cache = new ActionCache(components.actionCache, { action: internal.processData, name: "process-data-v1", ttl: 1000 * 60 * 60, }); // ... time passes, implementation changes ... // Version 2: Updated implementation with different output const cache = new ActionCache(components.actionCache, { action: internal.processData, name: "process-data-v2", // Changed name invalidates v1 cache ttl: 1000 * 60 * 60, }); // Both versions can coexist; old code uses v1, new code uses v2 ``` -------------------------------- ### Handle Concurrent Requests with Cache Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/usage-examples.md Efficiently handle multiple concurrent requests by sharing cache hits. This example shows how concurrent calls to `geocodeCache.fetch` can benefit from previously cached results, reducing the number of actual API calls. ```typescript export const batchGeocodeLocations = action({ args: { locations: v.array(v.string()) }, handler: async (ctx, { locations }) => { // Concurrent requests share cache hits const promises = locations.map(location => geocodeCache.fetch(ctx, { location }) ); const results = await Promise.all(promises); return results; }, }); // First request with ["NYC", "LA", "NYC"]: // - NYC: cache miss, API call // - LA: cache miss, API call // - NYC: cache hit (from first request) // Result: 2 API calls for 3 requests ``` -------------------------------- ### Test put() Mutation for New Entry Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/testing.md Tests the put() mutation to ensure it creates a new cache entry. Verifies that the entry is stored correctly and can be retrieved with a subsequent get() query. ```typescript test("put creates new entry", async () => { const t = convexTest(schema, {}); register(t); const result = await t.mutation(api.lib.put, { name: "test", args: { userId: 1 }, value: { name: "Alice" }, ttl: 3600000, }); expect(result.cacheHit).toBe(false); expect(result.deletedExpiredEntry).toBe(false); // Verify it was stored const hit = await t.query(api.lib.get, { name: "test", args: { userId: 1 }, ttl: null, }); expect(hit.kind).toBe("hit"); expect(hit.value).toEqual({ name: "Alice" }); }); ``` -------------------------------- ### Lazy Expiration Check in Get Query Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/database-schema.md Checks if an entry has expired during a `get` query. If expired, it returns a 'miss' kind with the expired entry's ID. ```typescript if (expiresAt && expiresAt <= Date.now()) { return { kind: "miss", expiredEntry: match._id }; } ``` -------------------------------- ### Basic Action Cache Implementation Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/README.md Demonstrates how to initialize an ActionCache with a specific action and TTL, and then fetch data. This is the fundamental pattern for using the cache. ```typescript const cache = new ActionCache(components.actionCache, { action: internal.expensiveAPI, ttl: 1000 * 60 * 60, }); const result = await cache.fetch(ctx, { query: "..." }); ``` -------------------------------- ### Get Query Result Type Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/types.md Represents the possible outcomes of a cache 'get' query. It can either be a 'hit' with the cached value or a 'miss', potentially indicating an expired entry. ```typescript type GetResult = { kind: "hit"; value: any; } | { kind: "miss"; expiredEntry?: Id<"values">; }; ``` -------------------------------- ### Initialize and Use ActionCache Source: https://github.com/get-convex/action-cache/blob/main/README.md Demonstrates how to initialize an ActionCache instance and use its fetch method within a Convex action. Ensure the return type of the action is explicitly defined. ```typescript import { action } from "./_generated/server"; import { components } from "./_generated/api"; import { ActionCache } from "@convex-dev/action-cache"; const cache = new ActionCache(components.actionCache, { action: internal.example.myExpensiveAction, }); export const myFunction = action({ // NOTE: If we're returning the result, we need explicitly type the return value. // Refer to https://docs.convex.dev/functions/actions#dealing-with-circular-type-inference for more info. handler: async (ctx, args): Promise<{ text: string }> => { // Call it with the parameters to `myExpensiveAction` const result = await cache.fetch(ctx, { foo: "bar" }); // Do something with the result or just return it return result; }, }); export const myExpensiveAction = internalAction({ args: { foo: v.string() }, handler: async (ctx, args): Promise<{ text: string }> { const data = await generateLLMResponse(ctx, args); return data; } }) ``` -------------------------------- ### Deploy New Version Source: https://github.com/get-convex/action-cache/blob/main/CONTRIBUTING.md Releases a new version of the project. Use `npm run release` for a standard release. ```sh npm run release ``` -------------------------------- ### Component API: Convex Queries and Mutations Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/INDEX.md Documentation for interacting with the Action Cache via Convex queries and mutations. ```APIDOC ## Component API ### Convex Query: get() Retrieves data from the cache. - **Arguments**: Arguments for the query. - **Returns**: The cached data or undefined. - **Expiration Logic**: Details on how cached data expires. ### Convex Mutations: #### put(data, options) Stores data in the cache. - **data** - The data to store. - **options** (object) - Optional - Options for putting data. - **concurrencyControl** - Enables concurrency control. #### remove() Removes an item from the cache. #### removeAll(options) Removes multiple items from the cache. - **options** (object) - Optional - Options for batch removal. - **batching** - Enables batch removal. ``` -------------------------------- ### Creating Multiple Action Cache Instances Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/configuration.md Illustrates how to create distinct ActionCache instances for different actions or versions. Each instance maintains separate entries and can be managed independently. ```typescript const embeddingCache = new ActionCache(components.actionCache, { action: internal.generateEmbedding, name: "embeddings-v1", ttl: 1000 * 60 * 60 * 24 * 7, // 7 days }); const weatherCache = new ActionCache(components.actionCache, { action: internal.fetchWeather, name: "weather-v1", ttl: 1000 * 60 * 5, // 5 minutes }); const summaryCache = new ActionCache(components.actionCache, { action: internal.summarizeText, name: "summaries-v2", // Changed from v1 to invalidate ttl: 1000 * 60 * 60 * 24, // 24 hours }); ``` -------------------------------- ### Initialize ActionCache with Name and TTL Source: https://github.com/get-convex/action-cache/blob/main/README.md Shows how to create an ActionCache instance with a specific name for identification and a TTL for cache expiration. The TTL is specified in milliseconds. ```typescript import { ActionCache } from "@convex-dev/action-cache"; import { components } from "./_generated/api"; const cache = new ActionCache(components.actionCache, { action: internal.example.myExpensiveAction, name: "myExpensiveActionV1", ttl: 1000 * 60 * 60 * 24 * 7, // 7 days }); ``` -------------------------------- ### Import Action Cache Testing Utilities Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/quick-reference.md Import the register function for setting up tests with the action cache. ```typescript import { register } from "@convex-dev/action-cache/test"; ``` -------------------------------- ### Deploy Alpha Release Source: https://github.com/get-convex/action-cache/blob/main/CONTRIBUTING.md Releases an alpha version of the project. Use `npm run alpha` for pre-release testing. ```sh npm run alpha ``` -------------------------------- ### Import Action Cache Configuration Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/quick-reference.md Import the cache configuration file for customizing action cache behavior. ```typescript import cache from "@convex-dev/action-cache/convex.config.js"; ``` -------------------------------- ### Run Project Tests Source: https://github.com/get-convex/action-cache/blob/main/CONTRIBUTING.md Executes a series of commands to clean, build, typecheck, lint, and run tests. Ensures code quality and correctness. ```sh npm run clean npm run build npm run typecheck npm run lint npm run test ``` -------------------------------- ### Component API Type Inference Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/architecture.md Illustrates how Convex generates types for component APIs, providing access to cache operations like get, put, and remove. ```typescript import { components } from "./_generated/api"; // components.actionCache is typed as ComponentApi // provides access to lib.get, lib.put, lib.remove, etc. ``` -------------------------------- ### Create an Action Cache Instance Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/quick-reference.md Instantiate an ActionCache with required action and optional name, ttl, and logging configurations. The 'action' property is mandatory. ```typescript import { ActionCache } from "@convex-dev/action-cache"; import { components } from "./_generated/api"; const cache = new ActionCache(components.actionCache, { action: internal.myAction, // Required name: "cache-name", // Optional, defaults to action name ttl: 1000 * 60 * 60, // Optional, milliseconds log: false, // Optional, enable logging }); ``` -------------------------------- ### ActionCache Constructor Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/api-reference.md Creates a new ActionCache instance. It takes a component API and a configuration object. ```APIDOC ## Constructor ActionCache ### Description Creates a new ActionCache instance. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **component** (`ComponentApi`) - Required - The registered action cache component from `components.actionCache` - **config** (`ActionCacheConfig`) - Required - Configuration object for the cache **ActionCacheConfig Type:** ```typescript interface ActionCacheConfig> { action: Action; name?: string; ttl?: number; log?: boolean; } ``` | Field | Type | Required | Default | Description | |-------|------|----------|---------|-------------| | action | `FunctionReference<"action">` | Yes | — | The action function that generates cache values when there is a miss | | name | `string` | No | Function name | Identifier for this cache, used as part of the cache key and for grouping entries | | ttl | `number` | No | Indefinite | Time-to-live in milliseconds; entries expire after this duration from creation | | log | `boolean` | No | false | Enable logging of cache hits and misses as JSON to stdout | ### Request Example ```typescript import { ActionCache } from "@convex-dev/action-cache"; import { components } from "./_generated/api"; import { internal } from "./_generated/api"; const cache = new ActionCache(components.actionCache, { action: internal.example.myExpensiveAction, name: "myActionV1", ttl: 1000 * 60 * 60, // 1 hour log: true, }); ``` ``` -------------------------------- ### Lookup Cache Entry by Key Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/database-schema.md Retrieves a specific cache entry using its name and arguments. Returns the entry or null if not found. Used by the `get` query and `lookup()` helper. ```typescript const match = await ctx.db .query("values") .withIndex("key", (q) => q.eq("name", name).eq("args", args)) .unique(); ``` -------------------------------- ### Register Action Cache in Tests Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/README.md Shows how to register the action cache component for use in Convex tests. This setup allows you to test cache functionality within your test environment. ```typescript import { convexTest } from "convex-test"; import { register } from "@convex-dev/action-cache/test"; const t = convexTest(schema, {}); register(t, "actionCache"); // Now test with cache... ``` -------------------------------- ### Import Action Cache API Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/quick-reference.md Import the main ActionCache class and the removeAll function for managing cache entries. ```typescript import { ActionCache, removeAll } from "@convex-dev/action-cache"; ``` -------------------------------- ### Caching Data with Time-Based Invalidation Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/usage-examples.md Cache data that becomes stale over time using ActionCache with a short TTL. This example demonstrates caching weather data for 5 minutes, after which it will be refetched. ```typescript const weatherCache = new ActionCache(components.actionCache, { action: internal.fetchWeather, name: "weather", ttl: 1000 * 60 * 5, // 5-minute cache }); export const getWeatherForLocation = action({ args: { lat: v.number(), lon: v.number() }, handler: async (ctx, args) => { // Weather data is fresh for 5 minutes, then refetched const weather = await weatherCache.fetch(ctx, args); return weather; }, }); ``` -------------------------------- ### Test Cache Expiration Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/quick-reference.md Tests that a cached item expires correctly after its TTL has passed. It uses fake timers to advance time and verifies that a subsequent get operation results in a 'miss'. ```typescript vi.useFakeTimers(); try { // Put with TTL await t.mutation(api.lib.put, { name: "test", args: { id: 1 }, value: "data", ttl: 1000, }); // Advance time vi.advanceTimersByTime(2000); // Now expired const result = await t.query(api.lib.get, { name: "test", args: { id: 1 }, ttl: null, }); expect(result.kind).toBe("miss"); } finally { vi.useRealTimers(); } ``` -------------------------------- ### ActionCache Constructor Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/README.md Initializes a new ActionCache instance. It requires the registered component and a configuration object specifying the action to cache, a name, and optional TTL and logging. ```APIDOC ## ActionCache Constructor ```typescript new ActionCache(component, config) ``` ### Parameters #### component - `ComponentApi` - Required - Registered component: `components.actionCache` #### config - `ActionCacheConfig` - Required - Configuration: `{ action, name?, ttl?, log? }` ``` -------------------------------- ### Configure Convex for Action Cache Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/quick-reference.md Configure your Convex project to use the action-cache component by importing and using the cache configuration. ```typescript // convex/convex.config.ts import cache from "@convex-dev/action-cache/convex.config.js"; const app = defineApp(); app.use(cache); export default app; ``` -------------------------------- ### ActionCache Class Methods Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/INDEX.md Reference for the ActionCache class, including its constructor, properties, and key methods for cache management. ```APIDOC ## ActionCache Class ### Description Provides an interface for interacting with the action cache. ### Constructor `new ActionCache(config)` - **config** (ActionCacheConfig) - Required - Configuration object for the cache instance. ### Properties - **name** (string) - The name of the cache instance. ### Methods #### fetch(options) Fetches data from the cache. - **options** (object) - Optional - Options for fetching. - **ttl** (number) - Time-to-live in milliseconds. - **force** (boolean) - Force a cache refresh. #### remove() Removes an item from the cache. #### removeAllForName(options) Removes all items for a specific cache name. - **options** (object) - Optional - Options for removal. - **batchSize** (number) - The size of batches for removal. ``` -------------------------------- ### Action Cache TTL Comparison Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/architecture.md Explains how Time-To-Live (TTL) values are handled when fetching cached entries. The applied TTL is the minimum of the creation TTL and the fetch TTL, ensuring the shortest duration is respected. ```plaintext Created with: TTL = 1 hour Fetched with: TTL = 5 minutes Applied TTL: min(1 hour, 5 minutes) = 5 minutes ``` -------------------------------- ### Configure fetch() options for Action Cache Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/configuration.md Override the default TTL or force a cache miss and refresh for a specific cache entry. ```typescript const value = await cache.fetch(ctx, args, { ttl?: 1000 * 60 * 5, // Override default TTL for this entry force?: true, // Force cache miss and refresh }); ``` -------------------------------- ### Cache Expensive Embedding Generation with OpenAI Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/usage-examples.md Demonstrates caching embedding generation using OpenAI's API. The cache is configured with a long TTL, suitable for embeddings that do not change. This example includes both the cache configuration and the action to perform vector search using cached embeddings. ```typescript const embeddingCache = new ActionCache(components.actionCache, { action: internal.generateEmbedding, name: "openai-embeddings-v1", ttl: 1000 * 60 * 60 * 24 * 365, // Cache for 1 year (embeddings don't change) }); export const generateEmbedding = internalAction({ args: { text: v.string() }, handler: async (_ctx, { text }) => { const apiKey = process.env.OPENAI_API_KEY; const response = await fetch("https://api.openai.com/v1/embeddings", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}`, }, body: JSON.stringify({ input: text, model: "text-embedding-ada-002", }), }); const data = await response.json(); return data.data[0].embedding as number[]; }, }); export const vectorSearch = action({ args: { query: v.string(), limit: v.number() }, handler: async (ctx, { query, limit }) => { // Get cached embedding for query const queryEmbedding = await embeddingCache.fetch(ctx, { text: query }); // Perform vector search with cached embedding const results = await ctx.vectorSearch("documents", "by_embedding", { vector: queryEmbedding, limit, }); return results; }, }); ``` -------------------------------- ### Test Cache Miss Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/testing.md Confirms that attempting to retrieve a non-existent key using `api.lib.get` results in a 'miss' response. ```typescript import { convexTest } from "convex-test"; import schema from "./convex/schema"; import { register } from "@convex-dev/action-cache/test"; import { api, components } from "./convex/_generated/api"; import { expect, test, vi } from "vitest"; test("cache miss returns miss", async () => { const t = convexTest(schema, {}); register(t); const result = await t.query(api.lib.get, { name: "test", args: { notFound: true }, ttl: null, }); expect(result.kind).toBe("miss"); }); ``` -------------------------------- ### Inspect All Cache Entries Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/quick-reference.md Retrieve and log all values stored in the action cache. ```typescript await t.run(async (ctx) => { const values = await ctx.db.query("values").collect(); console.log(JSON.stringify(values, null, 2)); }); ``` -------------------------------- ### Enable Action Cache Logging Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/README.md Enable logging for the ActionCache to monitor its performance. Logs are output to stdout in JSON format. ```typescript const cache = new ActionCache(components.actionCache, { action: internal.expensive, log: true, }); ``` -------------------------------- ### Cache Configuration with Logging Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/quick-reference.md Configure Action Cache with logging enabled. This can be helpful for debugging cache behavior. ```typescript // With logging const cache = new ActionCache(components.actionCache, { action: internal.expensive, ttl: 1000 * 60 * 60, log: true, }); ``` -------------------------------- ### Action Cache with Force Refresh Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/README.md Shows how to fetch data and force an update to the cache, bypassing existing cached data. Use this when you need the latest information regardless of cache status. ```typescript // Get fresh data and update cache const result = await cache.fetch(ctx, args, { force: true }); ``` -------------------------------- ### lookup Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/component-api.md Looks up a cache entry by name and arguments using the indexed `key` index on the values table. ```APIDOC ## lookup ### Description Looks up a cache entry by name and arguments using the indexed `key` index on the values table. ### Method query ### Arguments #### Required Arguments - **name** (string) - Cache name - **args** (unknown) - Arguments to match ### Returns `Doc<"values"> | null` — The cache document or null if not found. ``` -------------------------------- ### Setting Environment Variables in Convex Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/configuration.md Command to set environment variables for your Convex project. This is necessary for actions that rely on external configuration. ```bash npx convex env set OPENAI_API_KEY ``` -------------------------------- ### ActionCache Constructor Options Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/configuration.md Configure an ActionCache instance by providing an options object. The `action` field is required, specifying the Convex action to wrap. Optional fields include `name`, `ttl`, and `log`. ```typescript const cache = new ActionCache(component, { action: internal.myAction, // Required name?: "custom-name", // Optional ttl?: 1000 * 60 * 60 * 24, // Optional log?: true, // Optional }); ``` -------------------------------- ### Configure Batch Size for Cache Removal Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/configuration.md Customize the number of entries deleted per transaction using the `batchSize` option. Default is 100. Larger batches are faster but risk transaction limits; smaller batches are safer but require more mutations. ```typescript await cache.removeAllForName(ctx); ``` ```typescript await cache.removeAllForName(ctx, { batchSize: 50 }); ``` ```typescript await cache.removeAllForName(ctx, { batchSize: 1000 }); ``` -------------------------------- ### ActionCache Public API Methods Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/00-START-HERE.txt Reference for the core methods available on the ActionCache class for interacting with the cache. ```APIDOC ## ActionCache Methods ### `fetch(key: string, compute: () => Promise): Promise` #### Description Retrieves a value from the cache using the provided key. If the value is not found or has expired, it computes the value using the `compute` function and stores it in the cache before returning it. ### `remove(key: string): Promise` #### Description Deletes a single cache entry identified by the provided key. ### `removeAllForName(name: string): Promise` #### Description Deletes all cache entries associated with a specific cache name. ### `removeAll(): Promise` #### Description Deletes all cache entries within the entire ActionCache component. ``` -------------------------------- ### Component API: Helper Functions Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/INDEX.md Details on helper functions available within the component API. ```APIDOC ## Helper Functions ### lookup() Performs a lookup operation. ### del() Deletes an entry. ``` -------------------------------- ### Test ActionCache Client Fetch Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/testing.md Tests the ActionCache.fetch method within a Convex test environment. It sets up a mock action and uses ActionCache to fetch results, verifying the computed value. ```typescript import { ActionCache } from "@convex-dev/action-cache"; test("ActionCache.fetch works in tests", async () => { const t = convexTest(schema, {}); register(t); // Create a mock action const mockAction = async (ctx: any, args: any) => { return { computed: args.input * 2 }; }; // Use in ActionCache const cache = new ActionCache(components.actionCache, { action: mockAction as any, name: "test", ttl: 1000 * 60, }); // Test fetch const result = await cache.fetch({ runQuery: t.query, runMutation: t.mutation, runAction: () => Promise.resolve({ computed: 10 }) } as any, { input: 5 }); expect(result.computed).toBe(10); }); ``` -------------------------------- ### Set OpenAI API Key Environment Variable Source: https://github.com/get-convex/action-cache/blob/main/README.md Set your OpenAI API key as an environment variable before running the action. ```bash npx convex env set OPENAI_API_KEY ``` -------------------------------- ### Simple Cache Fetch Usage Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/quick-reference.md Fetch data from the cache using a simple cache instance. This is the most basic way to retrieve cached data. ```typescript export const getUser = action({ args: { id: v.string() }, handler: async (ctx, { id }) => { return await userCache.fetch(ctx, { id }); }, }); ``` -------------------------------- ### Create Embeddings Action Cache Source: https://github.com/get-convex/action-cache/blob/main/README.md Initialize an ActionCache instance for the embed action. A custom name 'embed-v1' is provided. ```typescript const embeddingsCache = new ActionCache(components.actionCache, { action: internal.example.embed, name: "embed-v1", }); ``` -------------------------------- ### ActionCache Constructor Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/README.md Initializes a new ActionCache instance. Requires a registered component and a configuration object specifying the action, name, and TTL. ```typescript new ActionCache(component, config) ``` -------------------------------- ### fetch() Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/api-reference.md Fetches a value from the cache. If the value is not found or has expired, it calls the associated action and caches the result. Supports optional TTL overrides and forced cache refreshes. ```APIDOC ## fetch() (async) ### Description Fetches a value from the cache, calling the action on a cache miss. This is a read-through cache: if the value exists and has not expired, it is returned immediately; otherwise, the action is called and the result is cached before being returned. ### Method `async fetch(ctx: ActionCtx, args: FunctionArgs, opts?: { ttl?: number; force?: boolean }): Promise>` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters Table | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | ctx | `ActionCtx` | Yes | — | Convex action context | | args | `FunctionArgs` | Yes | — | Arguments to pass to the cached action | | opts | `object` | No | — | Optional fetch behavior overrides | | opts.ttl | `number` | No | — | Override the default TTL for this entry; the shorter of the original TTL and this value is used | | opts.force | `boolean` | No | false | Force a cache miss, always executing the action and updating the cache | ### Returns `Promise>` — The cached or freshly computed value. ### Throws Any error thrown by the action will propagate to the caller. ### Example ```typescript // Basic cache fetch const result = await cache.fetch(ctx, { text: "hello" }); // Override TTL for this fetch const result = await cache.fetch(ctx, { text: "hello" }, { ttl: 1000 * 60 * 5 }); // Force refresh the cache const result = await cache.fetch(ctx, { text: "hello" }, { force: true }); ``` ``` -------------------------------- ### Type-Safe Action Cache with TypeScript Generics Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/README.md Demonstrates how to use TypeScript generics with ActionCache for type safety. It shows correct and incorrect usage for argument types. ```typescript const cache = new ActionCache(components.actionCache, { action: myAction, // type: internalAction<{ x: number }, { result: string }> }); // TypeScript infers argument type const result = await cache.fetch(ctx, { x: 42 }); // ✓ Correct // This is a type error const result = await cache.fetch(ctx, { x: "string" }); // ✗ Type error ``` -------------------------------- ### Configure removeAllForName() options for Action Cache Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/configuration.md Customize the batch size for clearing cache entries by name. Useful for tuning when clearing large caches. ```typescript await cache.removeAllForName(ctx, { batchSize?: 50, // Custom batch size }); ``` -------------------------------- ### Handle Action Errors Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/README.md Demonstrates how to catch errors thrown by cached actions. The cache state remains unchanged, and subsequent fetches will retry the action. ```typescript try { const result = await cache.fetch(ctx, args); } catch (error) { // Error thrown; cache not updated // Next fetch will retry the action } ``` -------------------------------- ### ActionCache Properties Source: https://github.com/get-convex/action-cache/blob/main/_autodocs/api-reference.md Properties available on the ActionCache instance. ```APIDOC ## Properties ### name #### Description The cache name used to identify and group cache entries. Set from the config name or defaults to the action's function name. #### Type ```typescript public name: string ``` ```