### Quick Start: Log Request Lifecycle Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/logger/README.md Initialize a logger, log the start and end of a request, and handle potential errors. ```typescript import { createLogger, getRequestId, logRequestEnd, logRequestStart, } from "@supa-edge-toolkit/logger"; Deno.serve(async (req) => { const requestId = getRequestId(req); const logger = createLogger("my-function", requestId); const timer = logger.startTimer("request"); logRequestStart(logger, req); try { // Your logic here logger.info("Processing", { step: "validate" }); const result = { id: "123" }; logRequestEnd(logger, 200, timer.elapsed()); return new Response(JSON.stringify(result)); } catch (error) { logger.error("Failed", error); logRequestEnd(logger, 500, timer.elapsed()); return new Response("Error", { status: 500 }); } }); ``` -------------------------------- ### Quick Start: Verify User Token in Edge Function Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/auth/README.md A basic example of how to set up an Edge Function to verify user tokens and return user ID and role. Handles authentication errors gracefully. ```typescript import { AuthError, verifyUserToken } from "@supa-edge-toolkit/auth"; Deno.serve(async (req) => { try { const { userId, role } = await verifyUserToken(req); return new Response(JSON.stringify({ userId, role })); } catch (error) { if (error instanceof AuthError) { return new Response( JSON.stringify({ error: error.code, message: error.message }), { status: error.statusCode }, ); } throw error; } }); ``` -------------------------------- ### Install Validation Utilities Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/validation/README.md Import necessary validation functions and Zod from the toolkit. ```typescript import { commonSchemas, validateRequest, z, } from "jsr:@supa-edge-toolkit/validation"; ``` -------------------------------- ### logRequestStart Source: https://context7.com/spyrae/supabase-edge-toolkit/llms.txt Logs the start of a request, including HTTP method and path, using the provided logger instance. ```APIDOC ## `logRequestStart(logger, req)` ### Description Logs the initiation of an HTTP request. It captures the HTTP method and path from the `Request` object and includes them in the log message using the provided logger instance. This helps in tracking the beginning of request processing. ### Parameters - **logger** (Logger) - Required - The logger instance to use for emitting the log message. - **req** (Request) - Required - The incoming Deno `Request` object containing details about the request. ### Usage Example ```typescript const logger = createLogger("handler"); logRequestStart(logger, req); ``` ``` -------------------------------- ### Example Curl for Test Mode Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/auth/README.md An example of how to use curl to send a request to an Edge Function with the necessary headers for test mode authentication. ```bash curl -H "Authorization: Bearer " \ -H "X-Test-User-Id: user-to-impersonate" \ https://localhost:54321/functions/v1/my-function ``` -------------------------------- ### Quick Start: Fetch and Compile Prompt Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/langfuse/README.md Demonstrates fetching a prompt template from Langfuse and compiling it with specific variables. Ensure environment variables for Langfuse URL, public key, and secret key are set. ```typescript import { compilePrompt, getLangfusePrompt } from "@supa-edge-toolkit/langfuse"; const config = { host: Deno.env.get("LANGFUSE_URL")!, publicKey: Deno.env.get("LANGFUSE_PUBLIC_KEY")!, secretKey: Deno.env.get("LANGFUSE_SECRET_KEY")!, }; // Fetch prompt from Langfuse const promptData = await getLangfusePrompt("travel-assistant", config); // Compile with variables const messages = compilePrompt(promptData, { destination: "Paris", language: "English", }); // => [{ role: "system", content: "You are a travel guide for Paris..." }, ...] ``` -------------------------------- ### Install Logger Package Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/logger/README.md Import necessary functions from the logger package. ```typescript import { createLogger, getRequestId } from "jsr:@supa-edge-toolkit/logger"; ``` -------------------------------- ### Setup and Restore Test Environment Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/testing/README.md Use `setupTestEnv` to configure Supabase environment variables for testing, optionally overriding defaults. `restoreEnv` is used to revert to the original environment variables after tests. ```typescript import { restoreEnv, setupTestEnv, SUPABASE_TEST_ENV, } from "@supa-edge-toolkit/testing"; // Set Supabase test defaults + custom vars const original = setupTestEnv({ MY_API_KEY: "test" }); // SUPABASE_TEST_ENV defaults: // - SUPABASE_URL: "http://localhost:54321" // - SUPABASE_ANON_KEY: "test-anon-key" // - SUPABASE_SERVICE_ROLE_KEY: "test-service-role-key" // - SUPABASE_JWT_SECRET: "test-jwt-secret-for-unit-tests-only-32chars!" // Restore original env restoreEnv(original); ``` -------------------------------- ### createTestContext Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/testing/README.md Creates a comprehensive test environment including a mock fetch, an in-memory database, and environment variable setup. It also provides a cleanup function to restore the original fetch and environment variables. ```APIDOC ## createTestContext(options?) ### Description Create a complete test environment with mock fetch, in-memory DB, and env setup. ### Parameters #### Options - **dbSeed** (object) - Optional - Seed data for the in-memory database. - **extraHandlers** (array) - Optional - An array of custom request handlers. - **envOverrides** (object) - Optional - Environment variables to override. ### Returns An object containing: - **mockFetch**: The mock fetch function (also set as `globalThis.fetch`). - **dbState**: An instance of `MockDBState`. - **fetchLog**: An array of all fetch calls made. - **cleanup**: A function to restore the original fetch and environment variables. ### Handler priority 1. `extraHandlers` 2. Supabase REST handler (`/rest/v1/`) 3. Supabase Functions handler (`/functions/v1/`) Unmatched URLs will throw an error. ``` -------------------------------- ### Check Formatting Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/README.md Verify code formatting without making any modifications. Use this to ensure your changes adhere to the project's style guide. ```bash deno task fmt:check ``` -------------------------------- ### Quick Start: Test Edge Function with Mocked DB Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/testing/README.md Demonstrates setting up a test environment for an edge function. It mocks the fetch API and provides an in-memory database, allowing normal Supabase client usage within tests. Asserts fetch call counts and data. ```typescript import { assertFetchCount, createTestContext, } from "@supa-edge-toolkit/testing"; import { afterEach, describe, it } from "@std/testing/bdd"; import { assertEquals } from "@std/assert"; describe("my edge function", () => { let cleanup: () => void; afterEach(() => cleanup()); it("should query users", async () => { const ctx = createTestContext({ dbSeed: { users: [{ id: "u1", name: "Alice" }] }, }); cleanup = ctx.cleanup; // globalThis.fetch is already mocked — use Supabase client normally const response = await fetch( "http://localhost:54321/rest/v1/users?id=eq.u1", ); const data = await response.json(); assertEquals(data.length, 1); assertEquals(data[0].name, "Alice"); assertFetchCount(ctx.fetchLog, "/rest/v1/users", 1); }); }); ``` -------------------------------- ### Install Auth Middleware Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/auth/README.md Import necessary functions from the auth package for use in your Edge Functions. ```typescript import { AuthError, verifyCronSecret, verifyServiceRole, verifyUserToken, } from "jsr:@supa-edge-toolkit/auth"; ``` -------------------------------- ### Logger.startTimer Source: https://context7.com/spyrae/supabase-edge-toolkit/llms.txt Starts a timer for a specific operation, allowing for duration tracking. ```APIDOC ## `logger.startTimer(operationName)` ### Description Starts a timer for a specific named operation within the current logging context. This is useful for measuring the execution time of critical code sections, such as database queries or external API calls. ### Parameters - **operationName** (string) - Required - The name of the operation to time. ### Returns - (Timer) - An object with an `end` method to stop the timer and log the duration, and an `elapsed` method to get the duration in milliseconds without logging. ``` -------------------------------- ### Get Prompt Options Type Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/langfuse/README.md Defines optional parameters for fetching prompts, allowing specification of a label and a request timeout in milliseconds. ```typescript interface GetPromptOptions { label?: string; // default: "production" timeoutMs?: number; // default: 5000 } ``` -------------------------------- ### Create Test Context for Supabase REST Calls Source: https://context7.com/spyrae/supabase-edge-toolkit/llms.txt Use `createTestContext` to set up an in-memory Supabase DB and mock fetch. It supports seeding data, custom API handlers, environment overrides, and provides assertion helpers for fetch requests. The mock fetch is automatically installed as `globalThis.fetch`. ```typescript import { createTestContext, MockDBState, createMockFetch, createSupabaseRestHandler, assertFetchCount, assertNotFetched, findFetchCalls, getFetchBody, setupTestEnv, restoreEnv, SUPABASE_TEST_ENV, extractTableFromUrl, parsePostgrestFilters, } from "jsr:@supa-edge-toolkit/testing"; import { describe, it, afterEach } from "@std/testing/bdd"; import { assertEquals, assertExists } from "@std/assert"; describe("edge function: create-post", () => { let cleanup: () => void; afterEach(() => cleanup?.()); it("inserts a post and calls the AI service once", async () => { // Seed in-memory DB and register a custom handler for an external API const ctx = createTestContext({ dbSeed: { users: [{ id: "u1", name: "Alice", role: "admin" }], posts: [], }, extraHandlers: [ (url: string) => { if (!url.includes("api.openai.com")) return null; return new Response( JSON.stringify({ choices: [{ message: { content: "AI summary" } }] }), { headers: { "content-type": "application/json" } }, ); }, ], envOverrides: { OPENAI_API_KEY: "test-key" }, }); cleanup = ctx.cleanup; // ctx.mockFetch is set as globalThis.fetch — Supabase client just works // Supabase REST emulator supports: select, insert, update, upsert, delete, rpc const postRes = await fetch( "http://localhost:54321/rest/v1/posts", { method: "POST", headers: { "Content-Type": "application/json", "Prefer": "return=representation" }, body: JSON.stringify({ title: "Hello", user_id: "u1" }), }, ); const [post] = await postRes.json(); assertExists(post.id); assertEquals(post.title, "Hello"); // Assert Supabase DB was hit exactly once for POST /posts assertFetchCount(ctx.fetchLog, "/rest/v1/posts", 1); // Assert OpenAI was called assertFetchCount(ctx.fetchLog, "api.openai.com", 1); // Assert an unrelated URL was never called assertNotFetched(ctx.fetchLog, "/rest/v1/users"); // Inspect request body sent to OpenAI const aiBody = getFetchBody(ctx.fetchLog, "api.openai.com"); assertEquals(aiBody?.model, "gpt-4o"); // Find all calls matching a regex const restCalls = findFetchCalls(ctx.fetchLog, /\/rest\/v1\//); assertEquals(restCalls.length, 1); }); it("directly manipulates MockDBState", () => { const db = new MockDBState({ users: [{ id: "u1", name: "Alice" }], }); db.insert("posts", { id: "p1", title: "First", user_id: "u1" }); db.insert("tags", [{ name: "deno" }, { name: "supabase" }]); const { data, count } = db.select("posts", { user_id: "u1" }, { count: true, order: "title.asc", limit: 10, offset: 0, }); assertEquals(count, 1); assertEquals(data[0].title, "First"); db.update("posts", { id: "p1" }, { title: "Updated" }); db.upsert("users", { id: "u1", name: "Alice B." }, "id"); db.registerRpc("get_post_count", (args) => ({ total: 42 })); const { data: stats } = db.executeRpc("get_post_count", { user_id: "u1" }); assertEquals(stats.total, 42); const deleted = db.delete("tags", { name: "deno" }); assertEquals(deleted, 1); db.reset(); // clear all data }); }); ``` -------------------------------- ### Validation Options Example Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/validation/README.md Illustrates the available options for validation functions, including request ID for tracing, custom error messages, and strict mode to reject extra fields. ```typescript interface ValidateRequestOptions { requestId?: string; // Included in error response for tracing errorMessage?: string; // Custom error message (default: "Validation failed") strict?: boolean; // Reject extra fields (default: false) } ``` -------------------------------- ### Start and End Timer for Operation Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/logger/README.md Measure the duration of an operation and log its completion with context. ```typescript const timer = logger.startTimer("db_query"); const rows = await db.query("SELECT ..."); timer.end({ rows: rows.length }); // logs: "db_query completed" with duration_ms ``` -------------------------------- ### Create Supabase REST Handler Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/testing/README.md Emulate the PostgREST protocol for Supabase REST operations. This handler supports standard methods like GET, POST, PATCH, DELETE, and RPC, along with common filters. ```typescript createSupabaseRestHandler(dbState) ``` -------------------------------- ### Create Mock Fetch with Handlers and Log Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/testing/README.md Set up a mock fetch function using `createMockFetch`, providing custom URL handlers and a fetch log array. This mock can then be assigned to `globalThis.fetch`. ```typescript const fetchLog: FetchCall[] = []; const mockFetch = createMockFetch( [ (url) => url.includes("/my-api") ? new Response("ok") : null, createSupabaseRestHandler(db), ], fetchLog, ); globalThis.fetch = mockFetch; ``` -------------------------------- ### Create Test Context with Options Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/testing/README.md Initialize a test environment with options for database seeding, custom handlers, and environment variable overrides. The context provides access to mocked fetch, DB state, fetch logs, and a cleanup function. ```typescript const ctx = createTestContext({ dbSeed: { users: [{ id: "u1", name: "Alice" }] }, extraHandlers: [myCustomHandler], envOverrides: { MY_API_KEY: "test-key" }, }); // ctx.mockFetch — mock fetch function (also set as globalThis.fetch) // ctx.dbState — MockDBState instance // ctx.fetchLog — array of all fetch calls // ctx.cleanup() — restore original fetch and env ``` -------------------------------- ### Run All Tests Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/README.md Execute all tests across the 7 packages, comprising 265 test steps. Ensure all tests pass before contributing. ```bash deno task test ``` -------------------------------- ### Circuit Breaker for External API Calls Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/resilience/README.md Implement a circuit breaker for external API calls to prevent cascading failures. This example uses a factory method for external APIs. ```typescript import { CircuitBreaker, CircuitBreakerOpenError, } from "@supa-edge-toolkit/resilience"; const breaker = CircuitBreaker.forExternalApi("my-service"); try { const result = await breaker.call(async () => { const response = await fetch("https://api.example.com/data"); return response.json(); }); } catch (error) { if (error instanceof CircuitBreakerOpenError) { // Circuit is open — fail fast console.log(error.serviceName); console.log(error.remainingTimeoutMs); } } ``` -------------------------------- ### Fetch Prompt with Options Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/langfuse/README.md Fetch a prompt template by name, optionally specifying a label and a custom timeout in milliseconds. Defaults to 'production' label and 5000ms timeout. ```typescript const prompt = await getLangfusePrompt("my-prompt", config); const prompt = await getLangfusePrompt("my-prompt", config, { label: "staging", // default: "production" timeoutMs: 10000, // default: 5000 }); ``` -------------------------------- ### Quick Start: Validate Request Body Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/validation/README.md Demonstrates inline validation of a request body against a Zod schema. Handles CORS preflight requests and returns a validation error response if the schema is not met. ```typescript import { commonSchemas, validateRequest, z, } from "@supa-edge-toolkit/validation"; import { createCorsResponse, errorToResponse } from "@supa-edge-toolkit/errors"; const CreateUserSchema = z.object({ email: commonSchemas.email, name: commonSchemas.requiredString("name", 100), age: commonSchemas.positiveInt("age"), }); Deno.serve(async (req) => { if (req.method === "OPTIONS") return createCorsResponse(); // Inline validation — no try/catch needed const result = await validateRequest(req, CreateUserSchema); if (result.error) return result.error; const { email, name, age } = result.data; // ... use validated data }); ``` -------------------------------- ### Mock Supabase Client for Testing Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/README.md Sets up a test context with a mocked Supabase client, allowing tests to run against an in-memory database. Asserts fetch calls and cleans up resources. ```typescript import { assertFetchCount, createTestContext, } from "jsr:@supa-edge-toolkit/testing"; Deno.test("my edge function", async () => { const ctx = createTestContext({ dbSeed: { users: [{ id: "u1", name: "Alice" }] }, }); try { // globalThis.fetch is mocked — Supabase client works against in-memory DB const res = await fetch("http://localhost:54321/rest/v1/users?id=eq.u1"); const data = await res.json(); assertEquals(data[0].name, "Alice"); assertFetchCount(ctx.fetchLog, "/rest/v1/users", 1); } finally { ctx.cleanup(); } }); ``` -------------------------------- ### Import Langfuse Prompt Functions Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/langfuse/README.md Import the necessary functions for fetching and compiling prompts from the Langfuse client library. ```typescript import { compilePrompt, getLangfusePrompt, } from "jsr:@supa-edge-toolkit/langfuse"; ``` -------------------------------- ### Fetch and Compile Langfuse Prompts Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/README.md Fetches prompt data from Langfuse and compiles it with provided variables. Requires Langfuse URL and keys to be set as environment variables. ```typescript import { compilePrompt, getLangfusePrompt, } from "jsr:@supa-edge-toolkit/langfuse"; const config = { host: Deno.env.get("LANGFUSE_URL")!, publicKey: Deno.env.get("LANGFUSE_PUBLIC_KEY")!, secretKey: Deno.env.get("LANGFUSE_SECRET_KEY")!, }; const promptData = await getLangfusePrompt("my-prompt", config); const messages = compilePrompt(promptData, { name: "Alice" }); ``` -------------------------------- ### Fetch and Compile Langfuse Prompts in Deno Source: https://context7.com/spyrae/supabase-edge-toolkit/llms.txt Fetches a prompt template from Langfuse and compiles it with provided variables. Supports both text and chat prompt formats. Ensure Langfuse environment variables are set. ```typescript import { getLangfusePrompt, compilePrompt, compileSystemPrompt, } from "jsr:@supa-edge-toolkit/langfuse"; import type { LangfuseConfig, PromptData, ChatMessage } from "jsr:@supa-edge-toolkit/langfuse"; const config: LangfuseConfig = { host: Deno.env.get("LANGFUSE_URL")!, publicKey: Deno.env.get("LANGFUSE_PUBLIC_KEY")!, secretKey: Deno.env.get("LANGFUSE_SECRET_KEY")!, }; Deno.serve(async (req) => { const { destination, language } = await req.json(); // Fetch a chat prompt from Langfuse (label defaults to "production") const promptData: PromptData = await getLangfusePrompt("travel-assistant", config, { label: "production", timeoutMs: 8000, }); // Compile a chat prompt — replaces {{variable}} placeholders in all messages const messages: ChatMessage[] = compilePrompt(promptData, { destination, language, tone: "friendly", }) as ChatMessage[]; // Extract only the system message (useful when building OpenAI messages array) const systemPrompt: string = compileSystemPrompt(promptData, { destination }); // Compile a text prompt const textPromptData: PromptData = { type: "text", prompt: "Summarize {{topic}} in {{words}} words.", }; const text: string = compilePrompt(textPromptData, { topic: "Deno", words: "50" }) as string; const aiResponse = await fetch("https://api.openai.com/v1/chat/completions", { method: "POST", headers: { Authorization: `Bearer ${Deno.env.get("OPENAI_API_KEY")}` }, body: JSON.stringify({ model: promptData.config?.model ?? "gpt-4o", messages, max_tokens: promptData.config?.max_tokens ?? 1024, }), }); return new Response(await aiResponse.text(), { headers: { "Content-Type": "application/json" }, }); }); ``` -------------------------------- ### Format Code Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/README.md Automatically format the codebase according to project standards. This ensures a consistent code style. ```bash deno task fmt ``` -------------------------------- ### MockDBState Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/testing/README.md An in-memory database that emulates Supabase and PostgREST behavior, supporting common database operations. ```APIDOC ## MockDBState ### Description In-memory database that emulates Supabase/PostgREST behavior. ### Methods - **insert(tableName, data)**: Inserts data into a table. - **select(tableName, filter, options?)**: Selects data from a table with optional filtering and options like `count`, `order`, `limit`, `offset`, `single`. - **update(tableName, filter, data)**: Updates records in a table. - **upsert(tableName, data, conflictKey)**: Inserts or updates records based on a conflict key. - **delete(tableName, filter)**: Deletes records from a table. - **registerRpc(name, handler)**: Registers a stored procedure (RPC). - **executeRpc(name, args)**: Executes a registered RPC. - **reset()**: Resets the database to its initial state. ### Example Usage ```typescript const db = new MockDBState({ users: [{ id: "u1", name: "Alice" }], // seed data }); db.insert("posts", { title: "Hello", user_id: "u1" }); const { data, count } = db.select("users", { role: "admin" }, { count: true, order: "name.asc", limit: 10, offset: 0, }); db.update("users", { id: "u1" }, { name: "Alice Updated" }); db.upsert("settings", { id: "s1", value: "new" }, "id"); db.delete("users", { id: "u1" }); db.registerRpc("get_stats", (args) => ({ total: 42 })); const { data: stats } = db.executeRpc("get_stats", { category: "test" }); db.reset(); ``` ``` -------------------------------- ### Import Core Resilience Utilities Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/resilience/README.md Import the main components of the resilience toolkit for use in your Supabase Edge Functions. ```typescript import { CircuitBreaker, fetchWithTimeout, resilientFetch, withRetry, withTimeout, } from "jsr:@supa-edge-toolkit/resilience"; ``` -------------------------------- ### Import Testing Utilities Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/testing/README.md Import necessary testing utilities from the @supa-edge-toolkit/testing package. ```typescript import { assertFetchCount, createTestContext, MockDBState, } from "jsr:@supa-edge-toolkit/testing"; ``` -------------------------------- ### createMockFetch Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/testing/README.md Creates a mock fetch function that routes requests based on URL patterns and logs all fetch calls. ```APIDOC ## createMockFetch(handlers, fetchLog) ### Description Create a mock fetch function with URL pattern routing. ### Parameters - **handlers** (array) - An array of functions that take a URL and return a `Response` or `null` if the URL is not handled. - **fetchLog** (array) - An array to store `FetchCall` objects representing each fetch request. ### Returns A mock `fetch` function. ### Example Usage ```typescript const fetchLog: FetchCall[] = []; const mockFetch = createMockFetch([ (url) => url.includes("/my-api") ? new Response("ok") : null, createSupabaseRestHandler(db), // Assuming 'db' is a MockDBState instance ], fetchLog); globalThis.fetch = mockFetch; ``` ``` -------------------------------- ### Set Log Level via Environment Variable Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/logger/README.md Configure the minimum log level to be displayed using the LOG_LEVEL environment variable. ```bash LOG_LEVEL=warn # Only warn and error logs ``` -------------------------------- ### Handle AuthError Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/auth/README.md Demonstrates how to catch and inspect AuthError instances, accessing their code, status code, and message for user feedback or logging. ```typescript try { await verifyUserToken(req); } catch (error) { if (error instanceof AuthError) { console.log(error.code); // e.g. "INVALID_TOKEN" console.log(error.statusCode); // e.g. 401 console.log(error.message); // Human-readable message } } ``` -------------------------------- ### MockDBState: In-Memory Database Operations Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/testing/README.md Utilize MockDBState for an in-memory database that emulates Supabase/PostgREST. Supports seeding data and performing insert, select, update, upsert, delete, and RPC operations. ```typescript const db = new MockDBState({ users: [{ id: "u1", name: "Alice" }], // seed data }); // Insert db.insert("posts", { title: "Hello", user_id: "u1" }); db.insert("tags", [{ name: "deno" }, { name: "supabase" }]); // Select const { data, count } = db.select("users", { role: "admin" }, { count: true, order: "name.asc", limit: 10, offset: 0, }); // Single row const { data: user } = db.select("users", { id: "u1" }, { single: true }); // Update (adds updated_at) db.update("users", { id: "u1" }, { name: "Alice Updated" }); // Upsert (insert or update by conflict key) db.upsert("settings", { id: "s1", value: "new" }, "id"); // Delete const deletedCount = db.delete("users", { id: "u1" }); // RPC db.registerRpc("get_stats", (args) => ({ total: 42 })); const { data: stats } = db.executeRpc("get_stats", { category: "test" }); // Reset db.reset(); ``` -------------------------------- ### Create Supabase Functions Handler Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/testing/README.md A basic handler for `/functions/v1/` URLs that returns a success response. ```typescript createSupabaseFunctionsHandler() ``` -------------------------------- ### Options Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/validation/README.md Configuration options available for validation functions. ```APIDOC ## Options All validation functions accept an options object for customization: ```typescript interface ValidateRequestOptions { requestId?: string; // Included in error response for tracing errorMessage?: string; // Custom error message (default: "Validation failed") strict?: boolean; // Reject extra fields (default: false) } ``` ``` -------------------------------- ### compilePrompt Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/langfuse/README.md Replaces `{{variable}}` placeholders in a prompt template with provided values. Supports both text and chat prompt types. ```APIDOC ## compilePrompt(promptData, variables) ### Description Replace `{{variable}}` placeholders in a prompt template. ### Parameters #### Path Parameters - **promptData** (PromptData) - Required - The prompt template data. - **variables** (object) - Required - An object containing key-value pairs for variable replacement. ### Missing Variables Missing variables are replaced with an empty string. ``` -------------------------------- ### Import Core Functions Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/errors/README.md Import the necessary functions and error codes for creating responses and handling errors. ```typescript import { createErrorResponse, createSuccessResponse, ErrorCodes, errorToResponse, } from "jsr:@supa-edge-toolkit/errors"; ``` -------------------------------- ### Compile Text Prompt Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/langfuse/README.md Compile a text-based prompt template by replacing `{{variable}}` placeholders with provided values. Missing variables will be replaced with an empty string. ```typescript // Text prompt -> string const text = compilePrompt( { type: "text", prompt: "Hello {{name}}!" }, { name: "Alice" }, ); // => "Hello Alice!" ``` -------------------------------- ### Fetch Data with Resilience Options Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/README.md Fetches data from a URL with configurable timeout, retry attempts, and circuit breaker settings for increased reliability. ```typescript import { resilientFetch } from "jsr:@supa-edge-toolkit/resilience"; // Fetch with timeout (5s), retry (3 attempts), and circuit breaker const response = await resilientFetch("https://api.example.com/data", { timeout: { timeoutMs: 5000 }, retry: { maxAttempts: 3 }, circuitBreaker: { failureThreshold: 5 }, }); ``` -------------------------------- ### Lint Codebase Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/README.md Apply linting rules to maintain code quality and consistency across the project. ```bash deno task lint ``` -------------------------------- ### Compile Chat Prompt Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/langfuse/README.md Compile a chat prompt template, which is an array of messages, by replacing `{{variable}}` placeholders within each message's content. Missing variables are replaced with empty strings. ```typescript // Chat prompt -> ChatMessage[] const messages = compilePrompt( { type: "chat", prompt: [ { role: "system", content: "You are a {{role}}." }, { role: "user", content: "Help with {{topic}}." }, ], }, { role: "guide", topic: "hotels" }, ); // => [{ role: "system", content: "You are a guide." }, ...] ``` -------------------------------- ### createSupabaseRestHandler Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/testing/README.md Emulates the PostgREST protocol for handling standard Supabase REST operations. ```APIDOC ## createSupabaseRestHandler(dbState) ### Description PostgREST protocol emulator. Handles all standard Supabase REST operations. ### Parameters - **dbState** (MockDBState) - The instance of `MockDBState` to interact with. ### Supported Operations | Method | Supabase JS equivalent | Supported | | ------ | ---------------------------------------------- | --------- | | HEAD | `.select('*', { count: 'exact', head: true })` | Yes | | GET | `.select()` with filters, order, limit, single | Yes | | POST | `.insert()` | Yes | | POST | `.upsert()` (with `on_conflict`) | Yes | | PATCH | `.update()` | Yes | | DELETE | `.delete()` | Yes | | POST | `.rpc()` | Yes | **Supported filters:** `eq.VALUE`, `ilike.VALUE`, `is.null` ``` -------------------------------- ### createResilientFetch Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/resilience/README.md Create a pre-configured resilient fetch function for a specific service, applying consistent resilience settings. ```APIDOC ## createResilientFetch(serviceName, resilienceOptions?) ### Description Create a pre-configured resilient fetch function for a service. ### Parameters #### Path Parameters - `serviceName` (string): A name for the service being called, used for circuit breaker identification. - `resilienceOptions` (object, optional): Options to configure resilience features. - `timeout` (number): The timeout in milliseconds for the request. - `circuitBreaker` (object | false): Circuit breaker configuration or `false` to disable. - `retry` (object | false): Retry configuration or `false` to disable. ### Request Example ```typescript const apiFetch = createResilientFetch("my-api", { timeout: 10000, circuitBreaker: CIRCUIT_BREAKER_CONFIGS.EXTERNAL_API, retry: RETRY_CONFIGS.EXTERNAL_API, }); const response2 = await apiFetch("/v3/search", { headers: { Authorization: apiKey }, }); ``` ``` -------------------------------- ### Create Logger Instance Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/logger/README.md Instantiate a logger for a specific function, optionally with base context. ```typescript const logger = createLogger("my-function", "req-123"); const loggerWithContext = createLogger("my-function", "req-123", { env: "prod", }); ``` -------------------------------- ### CORS Configuration Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/errors/README.md Utilities for configuring and generating CORS headers. ```APIDOC ## CORS Configuration ### Description Provides default CORS headers and a function to create custom CORS headers. ### Usage ```typescript import { corsHeaders, createCorsHeaders } from "@supa-edge-toolkit/errors"; // Default headers (origin: *, standard headers/methods) const headers = corsHeaders; // Custom configuration const customHeaders = createCorsHeaders({ origin: "https://myapp.com", allowHeaders: ["authorization", "content-type", "x-custom-header"], allowMethods: ["GET", "POST"], }); ``` ``` -------------------------------- ### createLogger Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/logger/README.md Creates a logger instance bound to a specific function and request. It can optionally accept base context. ```APIDOC ## createLogger(functionName, requestId, baseContext?) Creates a logger instance bound to a specific function and request. ### Parameters - **functionName** (string) - The name of the function for which the logger is created. - **requestId** (string) - The unique identifier for the current request. - **baseContext** (object, optional) - An object containing base context to be included in all log messages. ### Example ```typescript const logger = createLogger("my-function", "req-123"); const loggerWithContext = createLogger("my-function", "req-123", { env: "prod", }); ``` ``` -------------------------------- ### createLogger Source: https://context7.com/spyrae/supabase-edge-toolkit/llms.txt Creates a structured JSON logger instance. It supports child loggers, per-operation timers, and automatic log-level selection based on HTTP status codes. Debug logs are always enabled locally and follow `LOG_LEVEL` in production. ```APIDOC ## `createLogger(functionName, requestId?, baseContext?)` ### Description Creates a structured JSON logger instance that emits logs compatible with Grafana/Loki. It supports child loggers, per-operation timers, and automatic log-level selection based on HTTP status. Debug logs are always on locally and follow `LOG_LEVEL` in production. ### Parameters - **functionName** (string) - Required - The name of the function or module where the logger is being used. - **requestId** (string) - Optional - A unique identifier for the current request or operation. - **baseContext** (object) - Optional - An object containing base context fields to be included in all log messages from this logger instance. ### Usage Example ```typescript import { createLogger, getRequestId, logRequestStart, logRequestEnd, } from "jsr:@supa-edge-toolkit/logger"; Deno.serve(async (req) => { const requestId = getRequestId(req); const logger = createLogger("process-order", requestId, { env: "prod" }); logRequestStart(logger, req); const dbTimer = logger.startTimer("db_fetch_order"); try { logger.debug("Fetching order", { orderId: "o-123" }); const order = await db.orders.findById("o-123"); dbTimer.end({ found: !!order }); const payLogger = logger.child({ step: "payment", orderId: "o-123" }); payLogger.info("Charging card", { amount: 4999 }); const totalMs = dbTimer.elapsed(); logger.info("Order processed", { orderId: "o-123", totalMs }); logRequestEnd(logger, 200, totalMs); return new Response(JSON.stringify(order)); } catch (error) { logger.error("Order processing failed", error, { orderId: "o-123" }); logRequestEnd(logger, 500, dbTimer.elapsed()); return new Response("Error", { status: 500 }); } }); ``` ### Output Example ```json { "timestamp": "2024-01-15T10:30:00.123Z", "level": "info", "function_name": "process-order", "request_id": "req-abc", "message": "db_fetch_order completed", "context": { "found": true }, "duration_ms": 12 } ``` ### Environment Variables - **LOG_LEVEL**: Controls the logging verbosity. Options: `debug`, `info`, `warn`, `error`. Debug logs are always on locally. ``` -------------------------------- ### Timer Methods Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/logger/README.md Methods for managing and querying the duration of a timed operation. ```APIDOC ## Timer Methods ### `end(context?)` Logs the completion of the timed operation, including the elapsed duration. - **context** (object, optional) - Additional context to include with the completion log. ### `elapsed()` Returns the elapsed time in milliseconds without logging the completion. ### Example ```typescript const timer = logger.startTimer("db_query"); const rows = await db.query("SELECT ..."); timer.end({ rows: rows.length }); // logs: "db_query completed" with duration_ms ``` ``` -------------------------------- ### withRetry Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/resilience/README.md Execute an operation with automatic retry on transient failures. Supports exponential backoff and jitter. ```APIDOC ## withRetry(operation, config?, onRetry?) ### Description Execute with automatic retry on transient failures. ### Parameters #### Path Parameters - `operation` (function): The asynchronous function to execute. - `config` (object, optional): Configuration for retry behavior. See Preset Configs. - `onRetry` (function, optional): A callback function executed before each retry attempt. Receives a context object with `attempt` and `maxAttempts`. ### Request Example ```typescript import { RETRY_CONFIGS, RetryError, withRetry, } from "@supa-edge-toolkit/resilience"; try { const data = await withRetry( async () => { const response = await fetch(url); if (!response.ok) { const error = new Error(`HTTP ${response.status}`); (error as any).statusCode = response.status; throw error; } return response.json(); }, RETRY_CONFIGS.EXTERNAL_API, (ctx) => console.log(`Retry ${ctx.attempt}/${ctx.maxAttempts}`), ); } catch (error) { if (error instanceof RetryError) { console.log(error.attempts); // total attempts made console.log(error.lastError); // the last error } } ``` ``` -------------------------------- ### Request Helpers Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/logger/README.md Utility functions for handling request-related information and logging. ```APIDOC ## Request Helpers ### `getRequestId(req)` Extracts the request ID from `x-request-id` or `x-correlation-id` headers. Falls back to generating a new UUID if headers are not present. - **req** (Request) - The incoming request object. - **Returns** (string) - The extracted or generated request ID. ### `generateRequestId()` Generates a new UUID v4 request ID. - **Returns** (string) - A newly generated UUID v4 string. ### `logRequestStart(logger, req, context?)` Logs the start of a request, including details like HTTP method, path, query parameters, and user agent. - **logger** (Logger) - The logger instance to use. - **req** (Request) - The incoming request object. - **context** (object, optional) - Additional context to include with the log message. ### `logRequestEnd(logger, status, durationMs, context?)` Logs the completion of a request. The log level is automatically determined by the HTTP status code. - **logger** (Logger) - The logger instance to use. - **status** (number) - The HTTP status code of the response. - **durationMs** (number) - The duration of the request in milliseconds. - **context** (object, optional) - Additional context to include with the log message. **Log Level Determination:** - 2xx/3xx status codes: `info` level. - 4xx status codes: `warn` level. - 5xx status codes: `error` level. ``` -------------------------------- ### createSupabaseFunctionsHandler Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/testing/README.md A simple handler for `/functions/v1/` URLs that returns a success response. ```APIDOC ## createSupabaseFunctionsHandler() ### Description Simple handler for `/functions/v1/` URLs. Returns `{ success: true }`. ### Returns A handler function for Supabase Functions endpoints. ``` -------------------------------- ### getLangfusePrompt Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/langfuse/README.md Fetches a prompt template from the Langfuse REST API. It allows specifying a label for different prompt versions and a timeout for the request. ```APIDOC ## getLangfusePrompt(name, config, options?) ### Description Fetch a prompt template from the Langfuse REST API. ### Parameters #### Path Parameters - **name** (string) - Required - Prompt name in Langfuse - **config** (LangfuseConfig) - Required - API connection settings - **options.label** (string) - Optional - Prompt label (default: "production") - **options.timeoutMs** (number) - Optional - Fetch timeout in ms (default: 5000) ### Throws Error if the API returns a non-2xx status. ``` -------------------------------- ### compileSystemPrompt Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/langfuse/README.md Compiles a prompt and extracts only the system message. This is useful for isolating system instructions from chat or text prompts. ```APIDOC ## compileSystemPrompt(promptData, variables) ### Description Compile and extract only the system message. ### Parameters #### Path Parameters - **promptData** (PromptData) - Required - The prompt template data. - **variables** (object) - Required - An object containing key-value pairs for variable replacement. ### Returns - For chat prompts: returns the content of the first "system" role message. - For text prompts: returns the full compiled string. - If no system message is found: returns an empty string. ``` -------------------------------- ### Create Standard Success Response Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/errors/README.md Use `createSuccessResponse` to generate a `Response` object for successful operations. You can pass data and optionally specify a custom HTTP status code. ```typescript return createSuccessResponse({ user: { id: "123" } }); ``` ```typescript return createSuccessResponse({ id: "new" }, { status: 201 }); ``` -------------------------------- ### Compile System Prompt Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/langfuse/README.md Extracts and compiles only the system message from a prompt template. For chat prompts, it returns the content of the first 'system' role message. For text prompts, it returns the full compiled string. Returns an empty string if no system message is found. ```typescript const systemPrompt = compileSystemPrompt(promptData, variables); ``` -------------------------------- ### Logger.child Source: https://context7.com/spyrae/supabase-edge-toolkit/llms.txt Creates a child logger instance that inherits all context fields from the parent logger. ```APIDOC ## `logger.child(context)` ### Description Creates a new logger instance that inherits all context fields from the parent logger. Any additional context provided to the `child` method will be merged with the parent's context. This is useful for adding specific details to logs within a particular scope or sub-operation. ### Parameters - **context** (object) - Required - An object containing additional context fields for the child logger. ### Returns - (Logger) - A new logger instance with inherited and merged context. ``` -------------------------------- ### resilientFetch Source: https://github.com/spyrae/supabase-edge-toolkit/blob/main/packages/resilience/README.md A comprehensive fetch wrapper that combines timeout, circuit breaker, and retry logic for robust network requests. ```APIDOC ## resilientFetch(url, options?, resilienceOptions?) ### Description Combines timeout + circuit breaker + retry into a single fetch call. ### Parameters #### Path Parameters - `url` (string): The URL to fetch. - `options` (object, optional): Standard fetch options (method, headers, body, etc.). - `resilienceOptions` (object, optional): Options to configure resilience features. - `serviceName` (string): A name for the service being called, used for circuit breaker identification. - `timeout` (number): The timeout in milliseconds for the request. - `circuitBreaker` (object | false): Circuit breaker configuration or `false` to disable. - `retry` (object | false): Retry configuration or `false` to disable. ### Request Example ```typescript import { CIRCUIT_BREAKER_CONFIGS, createResilientFetch, resilientFetch, RETRY_CONFIGS, } from "@supa-edge-toolkit/resilience"; // One-off call const response = await resilientFetch(url, { method: "GET", headers: { Authorization: apiKey }, }, { serviceName: "my-api", timeout: 10000, circuitBreaker: CIRCUIT_BREAKER_CONFIGS.EXTERNAL_API, retry: RETRY_CONFIGS.EXTERNAL_API, }); ``` ### Disabling features ```typescript // No circuit breaker await resilientFetch(url, {}, { circuitBreaker: false }); // No retry await resilientFetch(url, {}, { retry: false }); // Timeout only await resilientFetch(url, {}, { serviceName: "simple", timeout: 5000, circuitBreaker: false, retry: false, }); ``` ```