functions

package
v0.1.0-rc.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 11, 2025 License: GPL-3.0 Imports: 17 Imported by: 0

README

Edge Functions - Deno Runtime (MVP)

Serverless functions powered by Deno runtime for executing JavaScript/TypeScript code.

Features

Implemented (MVP):

  • Deno 2.5.4 runtime integration via CLI
  • Function storage in PostgreSQL
  • HTTP invocation endpoint
  • Configurable permissions (net, env, read, write)
  • Execution logging and history
  • Timeout enforcement (30s default)
  • User authentication integration

⏸️ Deferred (Future Enhancement):

  • Cron scheduler for scheduled execution
  • Database triggers for event-driven execution
  • Admin UI integration
  • Function templates and examples

API Endpoints

Management Endpoints
# Create function
POST /api/v1/functions
{
  "name": "hello-world",
  "description": "A simple hello world function",
  "code": "async function handler(req) { return { status: 200, body: 'Hello World!' }; }",
  "enabled": true,
  "timeout_seconds": 30,
  "allow_net": true,
  "allow_env": true
}

# List all functions
GET /api/v1/functions

# Get specific function
GET /api/v1/functions/:name

# Update function
PUT /api/v1/functions/:name
{
  "code": "// Updated code",
  "enabled": true
}

# Delete function
DELETE /api/v1/functions/:name
Invocation Endpoint
# Invoke function
POST /api/v1/functions/:name/invoke
{
  "key": "value"
}

# View execution history
GET /api/v1/functions/:name/executions?limit=50

Writing Functions

Functions must export a handler function that accepts a request object:

async function handler(request) {
  // Request object structure:
  // {
  //   method: string,
  //   url: string,
  //   headers: { [key: string]: string },
  //   body: string,
  //   user_id: string (if authenticated)
  // }

  // Your function logic here
  const data = JSON.parse(request.body || "{}");

  // Return response
  return {
    status: 200,
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ message: "Success", data }),
  };
}
Available APIs

Functions have access to:

  • Deno standard library: All Deno APIs
  • Fluxbase API: Access via environment variables
    • FLUXBASE_URL: API endpoint
    • FLUXBASE_TOKEN: Authentication token
Example: Database Query
async function handler(request) {
  const url = Deno.env.get("FLUXBASE_URL");
  const token = Deno.env.get("FLUXBASE_TOKEN");

  // Query Fluxbase REST API
  const response = await fetch(`${url}/api/v1/tables/users`, {
    headers: {
      Authorization: `Bearer ${token}`,
      "Content-Type": "application/json",
    },
  });

  const users = await response.json();

  return {
    status: 200,
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ count: users.length, users }),
  };
}

Security Permissions

Functions run in a sandboxed Deno environment with configurable permissions:

Permission Description Default
allow_net Network access true
allow_env Environment variables true
allow_read Filesystem read false
allow_write Filesystem write false
allow_unauthenticated Allow invocation without auth false
Authentication Configuration

By default, all function management endpoints require authentication (JWT, API key, or service key):

  • Creating, listing, updating, and deleting functions
  • Viewing execution history

Function invocation requires at minimum an anon key (JWT token with role=anon) by default. This follows the Supabase authentication model where even "public" endpoints require project identification.

Authentication Options for Invocation
  1. Anon Key (JWT with role=anon) - Minimum required authentication

    curl -X POST https://fluxbase.example.com/api/v1/functions/my-function/invoke \
      -H "Authorization: Bearer $ANON_KEY" \
      -d '{"data": "value"}'
    
  2. User JWT - Authenticated user token

    curl -X POST https://fluxbase.example.com/api/v1/functions/my-function/invoke \
      -H "Authorization: Bearer $USER_TOKEN" \
      -d '{"data": "value"}'
    
  3. API Key - Scoped API key with execute:functions permission

    curl -X POST https://fluxbase.example.com/api/v1/functions/my-function/invoke \
      -H "X-API-Key: $API_KEY" \
      -d '{"data": "value"}'
    
  4. Service Key - Elevated privileges for backend services

    curl -X POST https://fluxbase.example.com/api/v1/functions/my-function/invoke \
      -H "X-Service-Key: $SERVICE_KEY" \
      -d '{"data": "value"}'
    
Generating Anon Keys

Generate an anon key using the helper script:

./scripts/generate-keys.sh
# Select option 3: Generate Anon Key

The anon key is a JWT token signed with your JWT_SECRET containing role=anon. Distribute this key to your client applications for public API access.

Allowing Completely Unauthenticated Access

For truly public endpoints that don't require any authentication (not even an anon key), set allow_unauthenticated: true:

  1. API Request - Set allow_unauthenticated when creating/updating:

    {
      "name": "public-webhook",
      "code": "...",
      "allow_unauthenticated": true
    }
    
  2. Code Comment - Add directive in your function code:

    // @fluxbase:allow-unauthenticated
    async function handler(request) {
      return { status: 200, body: "Truly public endpoint" };
    }
    

The comment directive is parsed when functions are loaded via the /api/v1/admin/functions/reload endpoint.

Note: Use allow_unauthenticated: true only for public webhooks or endpoints that must be accessible without any credentials. For most use cases, anon keys provide better security and usage tracking.

Execution Limits

  • Timeout: 30 seconds (configurable up to 300s)
  • Memory: 128MB (configurable up to 1024MB)
  • Concurrency: No limit (runs in separate Deno process per invocation)

Database Schema

-- Functions table
edge_functions (
  id, name, code, version, enabled,
  timeout_seconds, memory_limit_mb,
  allow_net, allow_env, allow_read, allow_write,
  cron_schedule, created_at, updated_at, created_by
)

-- Execution logs (30-day retention)
edge_function_executions (
  id, function_id, trigger_type, status, status_code,
  duration_ms, result, logs, error_message,
  executed_at, completed_at
)

-- Database triggers (future)
edge_function_triggers (
  id, function_id, table_name, events, condition
)

Architecture

Runtime: Deno CLI integration (shell execution)

  • Simple, no CGO dependencies
  • Easy to deploy (just install Deno binary)
  • Can be optimized with embedded Deno core later

Execution Flow:

  1. HTTP request → /api/v1/functions/:name/invoke
  2. Load function code from PostgreSQL
  3. Wrap code with runtime bridge
  4. Execute via deno run with permissions
  5. Capture stdout (response) and stderr (logs)
  6. Log execution to database
  7. Return response to client

Storage: PostgreSQL for function code and execution logs

Testing Functions

# Create a test function
curl -X POST http://localhost:8080/api/v1/functions \
  -H "Content-Type: application/json" \
  -d '{
    "name": "test",
    "code": "async function handler(req) { return { status: 200, body: JSON.stringify({ message: \"Hello from Deno!\" }) }; }",
    "enabled": true
  }'

# Invoke the function
curl -X POST http://localhost:8080/api/v1/functions/test/invoke \
  -H "Content-Type: application/json" \
  -d '{"name": "World"}'

# View execution logs
curl http://localhost:8080/api/v1/functions/test/executions

Future Enhancements

  • Cron Scheduler: Scheduled function execution
  • Database Triggers: Execute functions on table changes (INSERT/UPDATE/DELETE)
  • Admin UI: Monaco Editor for code editing, execution logs viewer
  • Function Templates: Pre-built examples (webhook handler, email sender, etc.)
  • Performance: Function code caching, connection pooling
  • Monitoring: Real-time execution metrics dashboard

Migration Path from Supabase

Fluxbase edge functions are compatible with Supabase's approach:

  • TypeScript/JavaScript runtime (Deno)
  • HTTP-triggered execution
  • Access to database via REST API
  • Environment variable support

Main difference: Fluxbase uses HTTP invocation instead of URL routing (can be added later).

Files

  • runtime.go - Deno execution manager
  • storage.go - PostgreSQL persistence
  • handler.go - HTTP API endpoints
  • migrations/012_edge_functions.up.sql - Database schema

License

MIT

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DeleteFunctionCode

func DeleteFunctionCode(functionsDir, functionName string) error

DeleteFunctionCode removes a function file from the filesystem

func FunctionExists

func FunctionExists(functionsDir, functionName string) (bool, error)

FunctionExists checks if a function file exists in the filesystem

func LoadFunctionCode

func LoadFunctionCode(functionsDir, functionName string) (string, error)

LoadFunctionCode loads function code from the filesystem

func SaveFunctionCode

func SaveFunctionCode(functionsDir, functionName, code string) error

SaveFunctionCode saves function code to the filesystem

func ValidateFunctionCode

func ValidateFunctionCode(code string) error

ValidateFunctionCode performs basic validation on function code

func ValidateFunctionName

func ValidateFunctionName(name string) error

ValidateFunctionName validates that a function name is safe and meets requirements

func ValidateFunctionPath

func ValidateFunctionPath(functionsDir, functionName string) (string, error)

ValidateFunctionPath validates that a constructed function path is safe This provides defense-in-depth by ensuring the final path is within the functions directory

Types

type DenoRuntime

type DenoRuntime struct {
	// contains filtered or unexported fields
}

DenoRuntime manages execution of Deno-based edge functions

func NewDenoRuntime

func NewDenoRuntime() *DenoRuntime

NewDenoRuntime creates a new Deno runtime manager

func (*DenoRuntime) Execute

func (r *DenoRuntime) Execute(ctx context.Context, code string, req ExecutionRequest, permissions Permissions) (*ExecutionResult, error)

Execute runs a Deno function with the given code and request context

type EdgeFunction

type EdgeFunction struct {
	ID                   uuid.UUID  `json:"id"`
	Name                 string     `json:"name"`
	Description          *string    `json:"description"`
	Code                 string     `json:"code"`
	Version              int        `json:"version"`
	CronSchedule         *string    `json:"cron_schedule"`
	Enabled              bool       `json:"enabled"`
	TimeoutSeconds       int        `json:"timeout_seconds"`
	MemoryLimitMB        int        `json:"memory_limit_mb"`
	AllowNet             bool       `json:"allow_net"`
	AllowEnv             bool       `json:"allow_env"`
	AllowRead            bool       `json:"allow_read"`
	AllowWrite           bool       `json:"allow_write"`
	AllowUnauthenticated bool       `json:"allow_unauthenticated"` // NEW: Allow invocation without authentication
	CreatedAt            time.Time  `json:"created_at"`
	UpdatedAt            time.Time  `json:"updated_at"`
	CreatedBy            *uuid.UUID `json:"created_by"`
}

EdgeFunction represents a stored edge function

type EdgeFunctionExecution

type EdgeFunctionExecution struct {
	ID             uuid.UUID  `json:"id"`
	FunctionID     uuid.UUID  `json:"function_id"`
	TriggerType    string     `json:"trigger_type"`
	TriggerPayload *string    `json:"trigger_payload"`
	Status         string     `json:"status"`
	StatusCode     *int       `json:"status_code"`
	DurationMs     *int       `json:"duration_ms"`
	Result         *string    `json:"result"`
	Logs           *string    `json:"logs"`
	ErrorMessage   *string    `json:"error_message"`
	ErrorStack     *string    `json:"error_stack"`
	ExecutedAt     time.Time  `json:"executed_at"`
	CompletedAt    *time.Time `json:"completed_at"`
}

EdgeFunctionExecution represents a function execution log

type ExecutionRequest

type ExecutionRequest struct {
	Method  string            `json:"method"`
	URL     string            `json:"url"`
	Headers map[string]string `json:"headers"`
	Body    string            `json:"body"`
	UserID  string            `json:"user_id,omitempty"`
}

ExecutionRequest represents a function invocation request

type ExecutionResult

type ExecutionResult struct {
	Status     int               `json:"status"`
	Headers    map[string]string `json:"headers"`
	Body       string            `json:"body"`
	Logs       string            `json:"logs"`
	Error      string            `json:"error,omitempty"`
	DurationMs int64             `json:"duration_ms"`
}

ExecutionResult represents the output of a function execution

type FunctionConfig

type FunctionConfig struct {
	AllowUnauthenticated bool
}

FunctionConfig contains configuration parsed from function code comments

func ParseFunctionConfig

func ParseFunctionConfig(code string) FunctionConfig

ParseFunctionConfig parses special @fluxbase directives from function code comments Supported directives:

  • // @fluxbase:allow-unauthenticated - Allows function invocation without authentication

type FunctionFileInfo

type FunctionFileInfo struct {
	Name         string // Function name (without .ts extension)
	Path         string // Full path to the file
	Size         int64  // File size in bytes
	ModifiedTime int64  // Unix timestamp of last modification
}

FunctionFileInfo contains information about a function file

func ListFunctionFiles

func ListFunctionFiles(functionsDir string) ([]FunctionFileInfo, error)

ListFunctionFiles scans the functions directory and returns all function files

type Handler

type Handler struct {
	// contains filtered or unexported fields
}

Handler manages HTTP endpoints for edge functions

func NewHandler

func NewHandler(db *pgxpool.Pool, functionsDir string) *Handler

NewHandler creates a new edge functions handler

func (*Handler) CreateFunction

func (h *Handler) CreateFunction(c *fiber.Ctx) error

CreateFunction creates a new edge function

func (*Handler) DeleteFunction

func (h *Handler) DeleteFunction(c *fiber.Ctx) error

DeleteFunction deletes a function

func (*Handler) GetExecutions

func (h *Handler) GetExecutions(c *fiber.Ctx) error

GetExecutions returns execution history

func (*Handler) GetFunction

func (h *Handler) GetFunction(c *fiber.Ctx) error

GetFunction gets a single function by name

func (*Handler) InvokeFunction

func (h *Handler) InvokeFunction(c *fiber.Ctx) error

InvokeFunction invokes an edge function

func (*Handler) ListFunctions

func (h *Handler) ListFunctions(c *fiber.Ctx) error

ListFunctions lists all edge functions

func (*Handler) RegisterAdminRoutes

func (h *Handler) RegisterAdminRoutes(app *fiber.App)

RegisterAdminRoutes registers admin-only routes for functions management These routes should be called with UnifiedAuthMiddleware and RequireRole("admin", "dashboard_admin")

func (*Handler) RegisterRoutes

func (h *Handler) RegisterRoutes(app *fiber.App, authService *auth.Service, apiKeyService *auth.APIKeyService, db *pgxpool.Pool, jwtManager *auth.JWTManager)

RegisterRoutes registers all edge function routes with authentication

func (*Handler) ReloadFunctions

func (h *Handler) ReloadFunctions(c *fiber.Ctx) error

ReloadFunctions scans the functions directory and syncs with database Admin-only endpoint - requires authentication and admin role

func (*Handler) SetScheduler

func (h *Handler) SetScheduler(scheduler *Scheduler)

SetScheduler sets the scheduler for this handler

func (*Handler) UpdateFunction

func (h *Handler) UpdateFunction(c *fiber.Ctx) error

UpdateFunction updates an existing function

type Permissions

type Permissions struct {
	AllowNet   bool
	AllowEnv   bool
	AllowRead  bool
	AllowWrite bool
}

Permissions represents Deno security permissions

func DefaultPermissions

func DefaultPermissions() Permissions

DefaultPermissions returns safe default permissions

type Scheduler

type Scheduler struct {
	// contains filtered or unexported fields
}

Scheduler manages scheduled execution of edge functions via cron

func NewScheduler

func NewScheduler(db *pgxpool.Pool) *Scheduler

NewScheduler creates a new scheduler for edge functions

func (*Scheduler) GetScheduleInfo

func (s *Scheduler) GetScheduleInfo(functionName string) (string, bool)

GetScheduleInfo returns schedule information for a function

func (*Scheduler) GetScheduledFunctions

func (s *Scheduler) GetScheduledFunctions() []string

GetScheduledFunctions returns a list of all currently scheduled functions

func (*Scheduler) RescheduleFunction

func (s *Scheduler) RescheduleFunction(fn EdgeFunction) error

RescheduleFunction updates a function's schedule (helper method)

func (*Scheduler) ScheduleFunction

func (s *Scheduler) ScheduleFunction(fn EdgeFunction) error

ScheduleFunction adds or updates a function's cron schedule

func (*Scheduler) Start

func (s *Scheduler) Start() error

Start initializes the scheduler and loads all enabled cron functions

func (*Scheduler) Stop

func (s *Scheduler) Stop()

Stop gracefully shuts down the scheduler

func (*Scheduler) UnscheduleFunction

func (s *Scheduler) UnscheduleFunction(functionName string)

UnscheduleFunction removes a function's cron schedule

type Storage

type Storage struct {
	// contains filtered or unexported fields
}

Storage manages edge function persistence

func NewStorage

func NewStorage(db *pgxpool.Pool) *Storage

NewStorage creates a new storage manager

func (*Storage) CreateFunction

func (s *Storage) CreateFunction(ctx context.Context, fn *EdgeFunction) error

CreateFunction creates a new edge function

func (*Storage) DeleteFunction

func (s *Storage) DeleteFunction(ctx context.Context, name string) error

DeleteFunction deletes a function by name

func (*Storage) GetExecutions

func (s *Storage) GetExecutions(ctx context.Context, functionName string, limit int) ([]EdgeFunctionExecution, error)

GetExecutions returns execution history for a function

func (*Storage) GetFunction

func (s *Storage) GetFunction(ctx context.Context, name string) (*EdgeFunction, error)

GetFunction retrieves a function by name

func (*Storage) ListFunctions

func (s *Storage) ListFunctions(ctx context.Context) ([]EdgeFunction, error)

ListFunctions returns all functions

func (*Storage) LogExecution

func (s *Storage) LogExecution(ctx context.Context, exec *EdgeFunctionExecution) error

LogExecution logs a function execution

func (*Storage) UpdateFunction

func (s *Storage) UpdateFunction(ctx context.Context, name string, updates map[string]interface{}) error

UpdateFunction updates an existing function

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL