### Install Project Dependencies Source: https://github.com/advenahq/supacache/blob/main/README.md Installs all necessary project dependencies using the pnpm package manager. This command should be run after cloning the repository. ```bash pnpm install ``` -------------------------------- ### Clone Supacache Repository Source: https://github.com/advenahq/supacache/blob/main/README.md Clones the Supacache project repository from GitHub and navigates into the project directory. This is the first step in the installation process. ```bash git clone https://github.com/AdvenaHQ/supacache.git cd supacache ``` -------------------------------- ### Configure Wrangler TOML for Supacache Worker Source: https://github.com/advenahq/supacache/blob/main/README.md Example configuration for the 'wrangler.toml' file, specifying environment variables for Supabase URL and D1 cache store table name, as well as D1 database bindings. ```toml # ... [vars] SUPABASE_URL = "https://djrwqopbrhnycewwjhoire.supabase.co" D1_CACHESTORE_TABLE_NAME = "supacache" [[d1_databases]] binding = "SUPACACHE_DB" database_name = "my-d1-database" # database_id = "2872f4f3-e9c9-4aa5-97a7-2ca6f530409f" # ... ``` -------------------------------- ### Configure and Deploy Supacache Worker with Wrangler Source: https://context7.com/advenahq/supacache/llms.txt Set up the wrangler.toml configuration file with Supabase and D1 database details, then deploy the worker using the Wrangler CLI. This includes installing dependencies, deploying, and setting up secrets for encryption and authentication keys. ```toml name = "supacache" main = "src/index.ts" compatibility_date = "2024-12-30" compatibility_flags = ["nodejs_compat"] [observability] enabled = true [vars] SUPABASE_URL = "https://djrwqopbrhnycewwjhoire.supabase.co" D1_CACHESTORE_TABLE_NAME = "supacache" [[d1_databases]] binding = "SUPACACHE_DB" database_name = "my-d1-database" database_id = "2872f4f3-e9c9-4aa5-97a7-2ca6f530409f" ``` ```bash # Install dependencies pnpm install # Deploy the worker wrangler deploy # Create encryption key (32 characters alphanumeric) wrangler secret put D1_CACHESTORE_ENCRYPTION_KEY # Create service auth key (64-256 characters alphanumeric) wrangler secret put SERVICE_AUTH_KEY # Generate types wrangler types # Redeploy with secrets wrangler deploy ``` -------------------------------- ### Deploy Supacache Worker to Cloudflare Source: https://github.com/advenahq/supacache/blob/main/README.md Deploys the configured Supacache worker to Cloudflare's Edge network. The CLI will guide through the worker creation process. ```bash wrangler deploy ``` -------------------------------- ### Validate Response Cacheability (TypeScript) Source: https://context7.com/advenahq/supacache/llms.txt Checks if an HTTP response is eligible for caching based on several conditions. It verifies the response status is OK (2xx), checks for 'no-store' in Cache-Control headers, ensures the request method is GET or HEAD, and applies specific rules for REST endpoints. ```typescript const shouldCacheResponse = (request: Request, response: Response) => { if (!response.ok) return false; if (response.status < 200 || response.status >= 300) return false; if (response?.headers?.get("Cache-Control")?.includes("no-store")) return false; if (request.method !== "GET" && request.method !== "HEAD") return false; if (request.url.includes("/rest/") && !request.url.includes("?select=")) return false; return true; }; // Examples const getRequest = new Request("https://api.com/rest/v1/users?select=*"); const okResponse = new Response("data", { status: 200 }); console.log(shouldCacheResponse(getRequest, okResponse)); // true const postRequest = new Request("https://api.com/rest/v1/users", { method: "POST" }); console.log(shouldCacheResponse(postRequest, okResponse)); // false - POST not cached const noStoreResponse = new Response("data", { headers: { "Cache-Control": "no-store" } }); console.log(shouldCacheResponse(getRequest, noStoreResponse)); // false ``` -------------------------------- ### Set Up D1 Database Schema for Cache Storage Source: https://context7.com/advenahq/supacache/llms.txt Initialize the D1 database with the required table structure for storing encrypted and compressed cache entries, including status, headers, and expiration tracking. This SQL script defines the schema and an index for efficient querying. ```sql CREATE TABLE supacache ( key TEXT PRIMARY KEY, body BLOB NOT NULL, status INTEGER NOT NULL, headers TEXT NOT NULL, expires DATETIME NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL ); CREATE INDEX idx_supacache_expires ON supacache(expires); ``` ```bash # Create D1 database with location hint wrangler d1 create my-d1-database --location=weur # Execute schema via CLI wrangler d1 execute my-d1-database --file=./schema.sql # Or via remote command wrangler d1 execute my-d1-database --remote --command="CREATE TABLE supacache (key TEXT PRIMARY KEY, body BLOB NOT NULL, status INTEGER NOT NULL, headers TEXT NOT NULL, expires DATETIME NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL)" ``` -------------------------------- ### Use Supabase SSR Client in Next.js (TypeScript) Source: https://github.com/advenahq/supacache/blob/main/README.md Demonstrates how to import and use the `useSupabase` hook within a Next.js application. It shows how to optionally specify a cache TTL and how to type the query results using generated schema types from Supabase. ```typescript import { useSupabase } from "../path/to/useSupabase"; import type { Database, Tables } from "../path/to/database.types"; // see: https://supabase.com/docs/reference/javascript/typescript-support#generating-typescript-types ... const supabase = await useSupabase(30); // Creates a Supabase server client which will cache eligible queries for 30 seconds const { data, error } = await supabase .from('countries') .select() .returns>(); ... ``` -------------------------------- ### Configure Supabase Client with Supacache Source: https://context7.com/advenahq/supacache/llms.txt This snippet demonstrates how to configure a standard supabase-js client to use Supacache. It involves creating a custom fetch function that includes authentication headers and a Time-To-Live (TTL) value for caching. The custom fetch is then passed to the Supabase client's global configuration. ```typescript import { createClient } from '@supabase/supabase-js' const useSupabase = async (cacheTTLSeconds?: number) => createClient( "https://supacache.my-cloudflare-domain.workers.dev", "your-supabase-public-anon-key", { global: { fetch: (input, init?: RequestInit) => { return fetch(input, { ...init, headers: { ...init?.headers, "X-Cache-Service-Key": "my-secret-key", "X-TTL": cacheTTLSeconds?.toString() || "900", }, }); }, }, }, ); // Create a client with 30 second cache TTL const supabase = await useSupabase(30); // This query will be cached for 30 seconds const { data, error } = await supabase .from('countries') .select(); console.log(data); // Returns cached or fresh data ``` -------------------------------- ### Dry-run Wrangler for Cloudflare Authentication Source: https://github.com/advenahq/supacache/blob/main/README.md Initializes the Wrangler CLI for Cloudflare authentication by running a development server. This step is necessary before deploying the worker. ```bash npx wrangler dev ``` -------------------------------- ### Create Supabase SSR Client with Caching (TypeScript) Source: https://github.com/advenahq/supacache/blob/main/README.md Initializes a Supabase client for server-side rendering in Next.js. It integrates custom cookie handling and leverages a Supabase Worker for API request caching. The cache's Time-To-Live (TTL) can be configured. This function requires Supabase URL, Anon Key, and a secret key for the cache worker. ```typescript import { createServerClient } from "@supabase/ssr"; import type { SupabaseClient } from "@supabase/supabase-js"; import type { GenericSchema } from "@supabase/supabase-js/dist/module/lib/types"; import { cookies } from "next/headers"; /** * Creates and returns a Supabase client configured for server-side usage with custom cookie handling and caching. * * @template Database - The type of the database schema. * @template SchemaName - The name of the schema within the database. * @template Schema - The schema definition. * * @param {number} [cacheTTLSeconds] - The time-to-live (TTL) for the cache in seconds. Defaults to 900 seconds (15 minutes) if not provided. * * @returns {Promise} A promise that resolves to a configured Supabase client. */ export async function useSupabase< Database = any, SchemaName extends string & keyof Database = "public" extends keyof Database ? "public" : string & keyof Database, Schema extends GenericSchema = Database[SchemaName] extends GenericSchema ? Database[SchemaName] : any, >(cacheTTLSeconds?: number): Promise { // Get the cookies from the request headers const cookieStore = await cookies(); // @ts-expect-error - This is a type error in the `@supabase/ssr` package. We are passing the correct options. return createServerClient( "https://supacache.my-cloudflare-domain.workers.dev", "your-supabase-public-anon-key", { cookies: { /** * Retrieves all cookies from the cookie store. */ getAll() { // Return all cookies from the cookie store when not using the service role return cookieStore.getAll(); }, /** * Sets multiple cookies using the provided array of cookie objects. */ // biome-ignore lint/suspicious/noExplicitAny: This is necessary to set cookies setAll(cookiesToSet: any) { try { for (const { name, value, options } of cookiesToSet) { cookieStore.set(name, value, options); } } catch (error) { // The `setAll` method was called from a Server Component. This can be ignored if you have middleware refreshing user sessions. } }, }, global: { // Use the Supacache Worker to cache requests to the Supabase API fetch: (input, init?: RequestInit) => { return fetch(input, { ...init, headers: { ...init?.headers, // Set the cache service key and TTL headers "X-Cache-Service-Key": "my-secret-key", // This is the SERVICE_AUTH_KEY secret you created in Step 4 of the Middlware (Worker) setup "X-TTL": cacheTTLSeconds?.toString() || "900", // 900 seconds = 15 minutes }, }); }, }, }, ); } // Export the Supabase client hook as the default export export default useSupabase; ``` -------------------------------- ### GZIP Compression and Decompression Utilities Source: https://context7.com/advenahq/supacache/llms.txt Provides GZIP compression and decompression for cached responses to minimize storage usage and reduce read/write costs. It takes a string as input and returns a base64 encoded string for compressed data. This can be combined with JSON compression for further efficiency. ```typescript import { gzipCompress, gzipExpand } from "./gzip"; // Compress a JSON string const jsonData = JSON.stringify({ users: Array(100).fill({ id: 1, name: "Test User", email: "test@example.com" }) }); const compressed = gzipCompress(jsonData); console.log(`Original: ${jsonData.length} bytes`); // ~5000 bytes console.log(`Compressed: ${compressed.length} bytes`); // ~200 bytes (base64) // Decompress back to original const decompressed = gzipExpand(compressed); console.log(JSON.parse(decompressed)); // Original data restored // Combined with JSON compression import { compress, decompress } from "compress-json"; const jsonCompressed = JSON.stringify(compress(JSON.parse(jsonData))); const gzipCompressed = gzipCompress(jsonCompressed); // Further size reduction for repetitive data ``` -------------------------------- ### Supabase JS Client Configuration with Supacache Source: https://github.com/advenahq/supacache/blob/main/README.md Configures the supabase-js client to use Supacache middleware by providing a custom fetcher. This includes setting necessary headers like 'X-Cache-Service-Key' for authorization and 'X-TTL' for cache duration. The middleware URL replaces the standard Supabase URL. ```typescript import { createClient } from '@supabase/supabase-js' const useSupabase = async (cacheTTLSeconds?: number) => createClient( "https://supacache.my-cloudflare-domain.workers.dev", "your-supabase-public-anon-key", { global: { fetch: (input, init?: RequestInit) => { return fetch(input, { ...init, headers: { ...init?.headers, "X-Cache-Service-Key": "my-secret-key", // This is the SERVICE_AUTH_KEY secret you created in Step 4 of the Middlware (Worker) setup "X-TTL": cacheTTLSeconds?.toString() || "900", // 900 seconds = 15 minutes }, }); }, }, }, ); ... const supabase = await useSupabase(30); // Creates a Supabase client which will cache eligible queries for 30 seconds const { data, error } = await supabase .from('countries') .select(); ... ``` -------------------------------- ### Implement Supacache Worker Fetch Handler Source: https://context7.com/advenahq/supacache/llms.txt The core worker logic for processing requests. It handles authentication, cache key generation, checking cache, and managing cache misses by fetching from Supabase and storing results. It uses environment variables for configuration and secrets. ```typescript export default { async fetch(request, env, ctx): Promise { const cacheServiceKey = request?.headers?.get("x-cache-service-key"); if (!isValidServiceKey(cacheServiceKey, env.SERVICE_AUTH_KEY)) return new Response("Unauthorized", { status: 401 }); const encryptionKey = await getEncryptionKey(env.D1_CACHESTORE_ENCRYPTION_KEY); const cacheKey = await generateCacheKey(request.url); const ttl = parseTTL(request?.headers); const supabaseUrl = env.SUPABASE_URL; if (!canCacheEndpoint(request.url)) { return await fetchFromSupabase(request, supabaseUrl); } try { const cachedResponse = await getCachedResponse( cacheKey, env.SUPACACHE_DB, env.D1_CACHESTORE_TABLE_NAME, encryptionKey, ); if (cachedResponse) { console.log(`🚀 Cache HIT for ${cacheKey}`); return cachedResponse; } console.log(`🐢 Cache MISS for ${cacheKey}`); const supabaseResponse = await fetchFromSupabase(request, supabaseUrl); if (shouldCacheResponse(request, supabaseResponse)) { const body = await supabaseResponse.clone().text(); await cacheResponse( cacheKey, body, supabaseResponse, ttl, env.SUPACACHE_DB, env.D1_CACHESTORE_TABLE_NAME, encryptionKey, ); } return supabaseResponse; } catch (error) { console.error("❌ Cache operation error:", error); return new Response("Internal Server Error", { status: 500 }); } }, } satisfies ExportedHandler; ``` -------------------------------- ### Next.js SSR Supabase Client with Supacache Source: https://context7.com/advenahq/supacache/llms.txt This TypeScript code provides a type-safe Server-Side Rendering (SSR) wrapper for Next.js applications using Supabase and Supacache. It handles cookie management for SSR environments and integrates Supacache's caching functionality by passing custom headers via a fetch wrapper. It also includes support for generated database types for enhanced type safety. ```typescript import { createServerClient } from "@supabase/ssr"; import type { SupabaseClient } from "@supabase/supabase-js"; import type { GenericSchema } from "@supabase/supabase-js/dist/module/lib/types"; import { cookies } from "next/headers"; export async function useSupabase( cacheTTLSeconds?: number ): Promise { const cookieStore = await cookies(); // @ts-expect-error - Type error in @supabase/ssr package return createServerClient( "https://supacache.my-cloudflare-domain.workers.dev", "your-supabase-public-anon-key", { cookies: { getAll() { return cookieStore.getAll(); }, setAll(cookiesToSet: any) { try { for (const { name, value, options } of cookiesToSet) { cookieStore.set(name, value, options); } } catch (error) { // Ignored in Server Components } }, }, global: { fetch: (input, init?: RequestInit) => { return fetch(input, { ...init, headers: { ...init?.headers, "X-Cache-Service-Key": "my-secret-key", "X-TTL": cacheTTLSeconds?.toString() || "900", }, }); }, }, }, ); } // Usage with generated types import type { Database, Tables } from "./database.types"; const supabase = await useSupabase(30); const { data, error } = await supabase .from('countries') .select() .returns>(); ``` -------------------------------- ### Create Supacache Table in D1 Database Source: https://github.com/advenahq/supacache/blob/main/README.md SQL statements to create the 'supacache' table in a Cloudflare D1 database. This table stores cached responses with columns for key, body, status, headers, and expiration. ```sql CREATE TABLE supacache ( key TEXT PRIMARY KEY, body BLOB NOT NULL, status INTEGER NOT NULL, headers TEXT NOT NULL, expires DATETIME NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL ); CREATE INDEX idx_supacache_expires ON advena (supacache); ``` -------------------------------- ### Generate Worker Types Source: https://github.com/advenahq/supacache/blob/main/README.md Generates TypeScript type definitions for the worker, which can be useful for better type checking and intellisense when interacting with the worker. ```bash wrangler types ``` -------------------------------- ### Generate MD5 Cache Key from URL (TypeScript) Source: https://context7.com/advenahq/supacache/llms.txt Generates a consistent MD5 hash for a given URL, serving as a unique identifier for cached responses. It utilizes the Web Crypto API for hashing. This function is asynchronous due to the nature of cryptographic operations. ```typescript const generateCacheKey = async (url: string) => { const encoder = new TextEncoder(); const data = encoder.encode(url); const hash = await crypto.subtle.digest("MD5", data); return Array.from(new Uint8Array(hash)) .map((b) => b.toString(16).padStart(2, "0")) .join(""); }; // Example usage const key1 = await generateCacheKey( "https://supacache.example.workers.dev/rest/v1/users?select=*" ); console.log(key1); // "5d41402abc4b2a76b9719d911017c592" const key2 = await generateCacheKey( "https://supacache.example.workers.dev/rest/v1/posts?select=*&limit=10" ); console.log(key2); // Different hash for different URL ``` -------------------------------- ### Parse TTL from Headers (TypeScript) Source: https://context7.com/advenahq/supacache/llms.txt Parses the Time-To-Live (TTL) for cache expiration from HTTP headers. It prioritizes the 'X-TTL' header, then checks 'Cache-Control' for 'max-age', falling back to a default of 900 seconds (15 minutes) if neither is found or if values are invalid. ```typescript const parseTTL = (headers: Headers): number => { const defaultTTL = 900; if (!headers) return defaultTTL; const ttlHeader = headers.get("x-ttl"); if (ttlHeader) { const parsed = Number.parseInt(ttlHeader, 10); return !Number.isNaN(parsed) && parsed > 0 ? parsed : defaultTTL; } const cacheControl = headers.get("Cache-Control"); if (cacheControl) { const maxAgeMatch = cacheControl.match(/max-age=(\d+)/); if (maxAgeMatch) { const parsed = Number.parseInt(maxAgeMatch[1], 10); return !Number.isNaN(parsed) && parsed > 0 ? parsed : defaultTTL; } } return defaultTTL; }; // Examples const headers1 = new Headers({ "X-TTL": "60" }); console.log(parseTTL(headers1)); // 60 seconds const headers2 = new Headers({ "Cache-Control": "max-age=3600" }); console.log(parseTTL(headers2)); // 3600 seconds const headers3 = new Headers(); console.log(parseTTL(headers3)); // 900 seconds (default) ``` -------------------------------- ### Forward Supabase Requests with TypeScript Source: https://context7.com/advenahq/supacache/llms.txt This TypeScript function forwards requests to Supabase by modifying the URL and headers. It removes specific worker headers ('x-cache-service-key', 'x-ttl') and updates the hostname to point to the Supabase project URL. The function preserves the original request method, headers (excluding the deleted ones), and body. ```typescript const fetchFromSupabase = async (request: Request, supabaseUrl: string) => { const url = new URL(request.url); url.protocol = "https"; url.hostname = new URL(supabaseUrl).hostname; const headers = new Headers(request.headers); headers.delete("x-cache-service-key"); headers.delete("x-ttl"); const init = { method: request.method, headers: [...headers], body: request.body, }; console.log("Fetching from Supabase:", url.toString()); return await fetch(url, init); }; // Example transformation // Input: https://worker.dev/rest/v1/users?select=* // Output: https://project.supabase.co/rest/v1/users?select=* const response = await fetchFromSupabase( new Request("https://worker.dev/rest/v1/users?select=*", { headers: { "Authorization": "Bearer token", "X-Cache-Service-Key": "secret", "X-TTL": "900" } }), "https://project.supabase.co" ); ``` -------------------------------- ### AES-GCM Encryption and Decryption Functions Source: https://context7.com/advenahq/supacache/llms.txt Implements AES-GCM encryption with random IVs for securing cached data at rest. It requires a 32-character alphanumeric secret for key derivation and uses cryptographic sublties for encrypt/decrypt operations. The output is a base64 encoded string of IV and ciphertext. ```typescript import { getEncryptionKey, encrypt, decrypt } from "./crypto"; // Derive encryption key from secret const encryptionKey = await getEncryptionKey("my32characteralphanumericsecret"); // Encrypt data const plaintext = JSON.stringify({ users: [{ id: 1, name: "Alice" }] }); const encrypted = await encrypt(plaintext, encryptionKey); console.log(encrypted); // "base64IV:base64Ciphertext" // Decrypt data const decrypted = await decrypt(encrypted, encryptionKey); console.log(JSON.parse(decrypted)); // { users: [{ id: 1, name: "Alice" }] } // Key generation from environment const key = await crypto.subtle.importKey( "raw", new TextEncoder().encode("my32characteralphanumericsecret"), { name: "AES-GCM" }, false, ["encrypt", "decrypt"], ); ``` -------------------------------- ### Cache Retrieval and Decryption Function Source: https://context7.com/advenahq/supacache/llms.txt Retrieves cached entries from D1 database, then reverses the encryption and compression pipeline to restore original response data. It queries for valid entries based on cache key and expiration. The function requires cache key, D1 database instance, table name, and encryption key. ```typescript const getCachedResponse = async ( cacheKey: string, db: D1Database, dbTableName: string, encryptionKey: CryptoKey, ) => { const result = await db .prepare( `SELECT key, body, status, headers, expires FROM "${dbTableName}" WHERE key = ? AND expires > CURRENT_TIMESTAMP` ) .bind(cacheKey) .first(); if (!result) return null; // Decrypt -> GZIP decompress -> JSON decompress const bodyAsUint8Array = new Uint8Array(result.body); const decrypted = await decrypt( new TextDecoder().decode(bodyAsUint8Array), encryptionKey ); const gzipDecompressed = gzipExpand(decrypted); const original = JSON.stringify(decompress(JSON.parse(gzipDecompressed))); const headers = new Headers(JSON.parse(result.headers)); return new Response(original, { status: Number(result.status), headers, }); }; // Usage returns null for expired/missing entries const cached = await getCachedResponse( "abc123hash", env.SUPACACHE_DB, "supacache", encryptionKey ); ``` -------------------------------- ### Push Service Authentication Key Secret to Worker Source: https://github.com/advenahq/supacache/blob/main/README.md Pushes the generated SERVICE_AUTH_KEY secret to the deployed Cloudflare worker. This key is used for authenticating requests from Supabase client instances. ```bash wrangler secret push SERVICE_AUTH_KEY ``` -------------------------------- ### Identify Cache Bypass Endpoints (TypeScript) Source: https://context7.com/advenahq/supacache/llms.txt Determines if a given URL should bypass the cache based on predefined path patterns. This is crucial for real-time data or dynamic content that should not be served from a stale cache. The function checks if the URL includes any of the paths in the `bypassCacheOnPath` array. ```typescript const bypassCacheOnPath = [ "/realtime/", "/subscriptions/", ]; const canCacheEndpoint = (url: string) => { return !bypassCacheOnPath.some((path) => url.includes(path)); }; // Examples console.log(canCacheEndpoint( "https://worker.dev/rest/v1/users?select=*" )); // true - REST endpoints are cacheable console.log(canCacheEndpoint( "https://worker.dev/realtime/v1/websocket" )); // false - realtime bypassed console.log(canCacheEndpoint( "https://worker.dev/subscriptions/changes" )); // false - subscriptions bypassed // Add custom bypass paths const customBypass = [...bypassCacheOnPath, "/admin/", "/auth/"]; ``` -------------------------------- ### Cache Response Storage Function Source: https://context7.com/advenahq/supacache/llms.txt Stores encrypted and compressed responses in D1 database with configurable TTL expiration. It combines JSON compression, GZIP compression, and AES-GCM encryption before storing. The function requires cache key, response body, Response object, TTL, D1 database instance, table name, and encryption key. ```typescript const cacheResponse = async ( cacheKey: string, body: string, response: Response, ttl: number, db: D1Database, dbTableName: string, encryptionKey: CryptoKey, ) => { const expires = new Date(Date.now() + ttl * 1000).toISOString(); const headers = JSON.stringify([...response.headers]); // Triple compression: JSON -> GZIP -> Encrypt const jsonCompressed = JSON.stringify(compress(JSON.parse(body))); const gzipCompressed = gzipCompress(jsonCompressed); const encrypted = await encrypt(gzipCompressed, encryptionKey); const bodyAsBlob = new TextEncoder().encode(encrypted); console.log(`💾 Caching ${cacheKey}. Expires ${expires}`); await db .prepare( `INSERT OR REPLACE INTO ${dbTableName} (key, body, status, headers, expires) VALUES (?, ?, ?, ?, ?)` ) .bind(cacheKey, bodyAsBlob, response.status, headers, expires) .run(); }; // Usage await cacheResponse( "abc123hash", '{"data":[{"id":1}]}', new Response(), 900, env.SUPACACHE_DB, "supacache", encryptionKey ); ``` -------------------------------- ### Push Encryption Key Secret to Worker Source: https://github.com/advenahq/supacache/blob/main/README.md Pushes the generated D1_CACHESTORE_ENCRYPTION_KEY secret to the deployed Cloudflare worker. This key is used for encrypting and decrypting cached data. ```bash wrangler secret push D1_CACHESTORE_ENCRYPTION_KEY ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.