PHANTOM
🇮🇳 IN
Skip to content

Standard library for Supabase Edge Functions — errors, validation, auth, resilience, logging

License

Notifications You must be signed in to change notification settings

spyrae/supabase-edge-toolkit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

supabase-edge-toolkit

Production-tested standard library for Supabase Edge Functions. Modular, zero-config, Deno-native.

Built from real-world experience running 76 edge functions in production. Each module is independent — install only what you need.

Packages

Package Description Install
errors Error/success responses, CORS, error codes, exception converter jsr:@supa-edge-toolkit/errors
validation Schema validation with Zod, request/query/header parsing jsr:@supa-edge-toolkit/validation
auth JWT verification, auth middleware, secure test mode jsr:@supa-edge-toolkit/auth
resilience Timeout, circuit breaker, retry with exponential backoff jsr:@supa-edge-toolkit/resilience
logger Structured JSON logging with request context jsr:@supa-edge-toolkit/logger
testing MockDBState, PostgREST emulator, mock fetch, assertions jsr:@supa-edge-toolkit/testing
langfuse Lightweight Langfuse prompt fetcher for Deno jsr:@supa-edge-toolkit/langfuse

All packages are v0.1.0, MIT licensed, with full test coverage.

Quick Start

Error Handling

import {
  createCorsResponse,
  createSuccessResponse,
  errorToResponse,
  validationError,
} from "jsr:@supa-edge-toolkit/errors";

Deno.serve(async (req) => {
  if (req.method === "OPTIONS") return createCorsResponse();

  try {
    const body = await req.json();
    if (!body.email) {
      return validationError("Missing required fields", { email: "Required" });
    }
    return createSuccessResponse({ id: "123", email: body.email });
  } catch (error) {
    return errorToResponse(error);
  }
});

Authentication

import { AuthError, verifyUserToken } from "jsr:@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(error.message, { status: error.statusCode });
    }
    throw error;
  }
});

Validation

import { z } from "npm:zod";
import { parseRequestBody } from "jsr:@supa-edge-toolkit/validation";

Deno.serve(async (req) => {
  const schema = z.object({
    email: z.string().email(),
    name: z.string().min(1),
  });

  const body = await parseRequestBody(req, schema);
  // body is typed as { email: string; name: string }
});

Resilience

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 },
});

Logging

import { createLogger } from "jsr:@supa-edge-toolkit/logger";

const logger = createLogger("my-function");
logger.info("Processing request", { userId: "123", action: "create" });
// => {"timestamp":"...","level":"INFO","function":"my-function","message":"Processing request","userId":"123","action":"create"}

Testing

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();
  }
});

Langfuse Prompts

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" });

Why This Exists

Supabase Edge Functions lack a standard library. Every project ends up writing the same boilerplate:

  • CORS headers and error response formatting
  • JWT verification and auth middleware
  • Request body validation
  • Retry logic and timeouts for external API calls
  • Structured logging
  • Test utilities for mocking the Supabase client

This toolkit extracts these patterns into tested, independent modules. Each package works standalone — no framework lock-in, no mandatory dependencies between packages.

Design Principles

  • Zero coupling — packages are independent, install only what you need
  • Deno-native — built for Deno runtime, published on JSR
  • Production-tested — extracted from a system running 76 edge functions
  • Minimal API — small surface area, easy to learn
  • Type-safe — full TypeScript with strict types, no any

Development

# Run all tests (265 test steps across 7 packages)
deno task test

# Type check all packages
deno task check

# Lint
deno task lint

# Format
deno task fmt

# Check formatting without modifying
deno task fmt:check

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Run deno task test to ensure all tests pass
  4. Submit a pull request

Each package has its own README with detailed API documentation.

License

MIT

About

Standard library for Supabase Edge Functions — errors, validation, auth, resilience, logging

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •