phantom-frame 0.2.11

A high-performance prerendering proxy engine with caching support
Documentation
# ── Global settings (no section header) ─────────────────────────────────────

# HTTP listen port (default: 3000)
http_port = 3000

# Control port for cache management endpoints (default: 17809)
control_port = 17809

# Optional: Bearer token for /refresh-cache authentication
# If set, callers must include: Authorization: Bearer <token>
# control_auth = "your-secret-token-here"
# Values can reference environment variables using the $env:VAR syntax:
# control_auth = "$env:PF_CONTROL_AUTH"

# Optional: Load a .env file before resolving $env: references.
# false or absent → disabled (default)
# true            → load .env from the current working directory (silently ignored if absent)
# "./path/.env"   → load from the given path (error if file does not exist)
# dotenv = true
# dotenv = "./.env.local"

# Optional: HTTPS port — when set, cert_path and key_path are required.
# https_port = 443
# cert_path = "/etc/ssl/certs/fullchain.pem"
# key_path  = "/etc/ssl/private/privkey.pem"

# ── Server blocks ─────────────────────────────────────────────────────────────
#
# Each [server.NAME] block configures one reverse-proxy entry.
# bind_to controls where it is mounted in the Axum router:
#
#   bind_to = "*"      → fallback (catch-all), registered last
#   bind_to = "/api"   → nested under /api, registered before shorter prefixes
#
# Note: Router::nest strips the prefix before forwarding.  If your upstream
# expects the full path, encode the prefix in proxy_url instead.

[server.default]

# Mount point in the Axum router (default: "*")
bind_to = "*"

# The backend URL to proxy requests to
proxy_url = "http://localhost:8080"

# Optional: Paths to include in caching (empty means include all)
# Supports wildcards: * can appear anywhere in the pattern
# Supports method prefixes: "GET /api/*", "POST /*/users", etc.
# Examples: "/api/*", "/*/users", "/public/*/assets", "GET *"
include_paths = ["/api/*", "/public/*", "GET /admin/stats"]

# Optional: Paths to exclude from caching (empty means exclude none)
# Supports wildcards: * can appear anywhere in the pattern
# Supports method prefixes: "POST /api/*", "PUT *", etc.
# Exclude patterns override include patterns
exclude_paths = ["/api/admin/*", "/api/*/private", "POST *", "PUT *", "DELETE *"]

# Optional: Enable WebSocket / protocol-upgrade support (default: true)
# Upgrade requests bypass the cache and establish a direct TCP tunnel to the backend.
# Only active in Dynamic mode or PreGenerate mode with pre_generate_fallthrough = true.
# Pure SSG servers always return 501 for upgrade requests.
enable_websocket = true

# Optional: Only allow GET requests, reject all others (default: false)
# forward_get_only = false

# Optional: Control which response types are cached (default: "all")
# Available values: "all", "none", "only_html", "no_images", "only_images", "only_assets"
# cache_strategy = "none"

# Optional: Control how cached responses are stored in memory (default: "brotli")
# Available values: "none", "brotli", "gzip", "deflate"
# compress_strategy = "brotli"

# Optional: Control where cached response bodies are stored (default: "memory")
# Available values: "memory", "filesystem"
# cache_storage_mode = "filesystem"

# Optional: Override the directory used for filesystem-backed cache bodies
# cache_directory = "./.phantom-frame-cache"

# ── Webhooks ──────────────────────────────────────────────────────────────────
#
# Each [[server.NAME.webhooks]] entry defines one webhook for that server.
# Webhooks fire on every request, BEFORE cache reads are attempted, so access
# control is enforced even for cached responses.
#
# type = "blocking"  — phantom-frame POSTs request metadata to the URL and waits.
#                      2xx response → request is allowed to continue.
#                      Non-2xx response → the webhook's status code is returned to
#                      the client and the request is not forwarded.
#                      Timeout or connection error → 503 is returned to the client.
#
# type = "notify"    — phantom-frame fires a background POST and does not wait for
#                      a response. The request always proceeds immediately.
#
# The POST body contains: method, path, query, headers (no request body).
#
# [[server.default.webhooks]]
# url = "http://auth-service.internal/check"
# type = "blocking"
# timeout_ms = 3000    # optional, default 5000 ms
#
# [[server.default.webhooks]]
# url = "http://logger.internal/log"
# type = "notify"

# ── Example: multi-server config (SSG frontend + dynamic API backend) ─────────
#
# [server.frontend]
# bind_to = "*"
# proxy_url = "http://localhost:5173"
# proxy_mode = "pre_generate"
# pre_generate_paths = ["/", "/about", "/blog"]
# enable_websocket = false   # SSG — no backend at request time
#
# Optional: spawn a command and wait for proxy_url's port to accept connections.
# phantom-frame polls the port every 500 ms (360 s timeout) before serving.
# On Windows, commands are run via `cmd /C` so pnpm.cmd / npm.cmd etc. work as-is.
# On Unix, commands are run via `sh -c`.
#
# Simple command:
# execute = "pnpm run dev"
# execute_dir = "./apps/client"   # working directory (relative to where phantom-frame runs)
#
# Commands support && / || chaining — intermediate segments run to completion,
# the final segment becomes the long-running server process:
# execute = "pnpm install && pnpm run build && pnpm run start"
# execute = "pnpm run build || echo 'build failed' && pnpm run start"
#
# cd changes the working directory for subsequent segments in the chain:
# execute = "cd ./apps/client && pnpm install && pnpm run dev"
#
# Linux-style KEY=VALUE inline env prefixes are supported on all platforms:
# execute = "PORT=5173 NODE_ENV=production pnpm run start"
# execute = "cd ./apps/client && PORT=5173 pnpm run dev"
#
# [server.api]
# bind_to = "/api"
# proxy_url = "http://localhost:8080"
# proxy_mode = "dynamic"
# enable_websocket = true
# execute = "cargo build --release && cargo run --release"
# execute_dir = "./apps/server"