|
| 1 | +# ============================================================================= |
| 2 | +# Access keys (OPTIONAL: drives the invite-link `?share=<id>` flow) |
| 3 | +# ============================================================================= |
| 4 | +# |
| 5 | +# Leave SHARED_API_KEYS unset and the demo runs in BYOK-only mode: every |
| 6 | +# visitor brings their own provider key via the in-app Model Picker, and |
| 7 | +# the stream goes browser-direct (never through this server). This is |
| 8 | +# the easiest setup if you only need it for yourself. |
| 9 | +# |
| 10 | +# Set SHARED_API_KEYS to skip BYOK and let non-technical viewers chat |
| 11 | +# without pasting a key. Each entry maps a share id to an api key, a |
| 12 | +# model handle, and a per-IP lifetime cap on chat turns. Visitors land |
| 13 | +# on `?share=<id>` and the server pays for the LLM under your account. |
| 14 | +# Requests without a recognized `?share=<id>` still return 401 and the |
| 15 | +# client falls back to BYOK. |
| 16 | +# |
| 17 | +# Shape (per share id): |
| 18 | +# |
| 19 | +# { |
| 20 | +# "<share_id>": { |
| 21 | +# "api_key": "<provider api key>", |
| 22 | +# "model": "<anthropic_haiku_4_5 | deepseek_v4_flash>", |
| 23 | +# "rate_limit_turns_lifetime": 20 |
| 24 | +# } |
| 25 | +# } |
| 26 | +# |
| 27 | +# Each share id has its own per-IP lifetime counter. With REDIS_URL set |
| 28 | +# (see below), counters survive restarts and are shared across containers. |
| 29 | +# Without REDIS_URL, counters live in memory per container (fine for |
| 30 | +# single-instance / BYOK-only deployments). The reserved id "__default__" |
| 31 | +# is rejected at parse time. Example with two invites on two providers: |
| 32 | +# |
| 33 | +# SHARED_API_KEYS='{"preview-alice":{"api_key":"sk-ant-...","model":"anthropic_haiku_4_5","rate_limit_turns_lifetime":5},"customer-acme":{"api_key":"sk-...","model":"deepseek_v4_flash","rate_limit_turns_lifetime":100}}' |
| 34 | +# |
| 35 | +# Visitors then open `http://localhost:3001/?share=preview-alice` (or |
| 36 | +# the equivalent on your hosted domain). |
| 37 | +# |
| 38 | +# ----------------------------------------------------------------------------- |
| 39 | +# Base64 fallback (recommended for hosted deploys) |
| 40 | +# ----------------------------------------------------------------------------- |
| 41 | +# Some hosts (DigitalOcean App Platform, Render, fly.io app specs) mangle |
| 42 | +# embedded or surrounding quotes when storing JSON-shaped env vars. The |
| 43 | +# parser accepts a base64-encoded payload as an alternative: plain JSON |
| 44 | +# is tried first, base64-then-JSON second. Either works. |
| 45 | +# |
| 46 | +# Portable one-liner (macOS + Linux): |
| 47 | +# |
| 48 | +# printf '%s' '{"preview-alice":{"api_key":"sk-ant-...","model":"anthropic_haiku_4_5","rate_limit_turns_lifetime":5}}' | base64 | tr -d '\n' |
| 49 | +# |
| 50 | +# Paste the resulting ASCII-only string as the value, with no surrounding |
| 51 | +# quotes. The parser also auto-strips one wrapping pair of single or |
| 52 | +# double quotes if your host shell-escapes the value into the env. |
| 53 | +SHARED_API_KEYS= |
| 54 | + |
| 55 | +# ============================================================================= |
| 56 | +# Client configuration |
| 57 | +# ============================================================================= |
| 58 | + |
| 59 | +# SimplePDF company identifier. The subdomain piece of |
| 60 | +# <companyIdentifier>.simplepdf.com that serves the embedded editor. |
| 61 | +# Exposed to the browser (VITE_ prefix) because the iframe src is built |
| 62 | +# client-side. REQUIRED: the app throws at startup if unset. |
| 63 | +# |
| 64 | +# `form-copilot` is the public demo workspace and whitelists |
| 65 | +# `http://localhost:3001`, so the iframe loads as-is for local dev. To |
| 66 | +# host this on your own domain, set this to your own SimplePDF |
| 67 | +# Premium company identifier and whitelist your serving origin in the |
| 68 | +# SimplePDF dashboard. |
| 69 | +VITE_SIMPLEPDF_COMPANY_IDENTIFIER=form-copilot |
| 70 | + |
| 71 | + |
| 72 | +# Optional. Gates the TanStack Router devtools panel + chatty monitoring |
| 73 | +# logs. Leave unset in production / CI; set to "true" for local dev. |
| 74 | +# VITE_ENABLE_DEVTOOLS=true |
| 75 | + |
| 76 | +# ============================================================================= |
| 77 | +# Rate-limit storage (optional; required for multi-container deployments) |
| 78 | +# ============================================================================= |
| 79 | + |
| 80 | +# Connection URL to a Redis-protocol-compatible instance (Valkey, Redis, |
| 81 | +# KeyDB, etc.). Required for hosted deployments where you want |
| 82 | +# per-(share, IP) lifetime counters to survive restarts AND be shared |
| 83 | +# across multiple containers. Without it, counters live in memory per |
| 84 | +# container (fine for local dev, single-instance hosts, or BYOK-only |
| 85 | +# deployments). |
| 86 | +# |
| 87 | +# DO Managed Caching for Valkey: $15/mo single-node, drop-in protocol- |
| 88 | +# compatible. The dashboard returns a `rediss://default:<password>@<host>:25061/0` |
| 89 | +# URL. The password is INSIDE the URL, so this value is a secret and must |
| 90 | +# be stored as such (the deploy.template.yaml at the repo root marks it |
| 91 | +# `type: SECRET`). |
| 92 | +# REDIS_URL=rediss://default:<password>@<host>:25061/0 |
| 93 | + |
| 94 | +# REQUIRED when REDIS_URL is set (the server refuses to boot otherwise). |
| 95 | +# Salts the SHA-256 IP hash used in Redis keys (rl:<share>:<hash>). |
| 96 | +# Without a salt, a leak of the Redis snapshot lets anyone brute-force the |
| 97 | +# ~4B IPv4 space in minutes. With a salt, the brute force needs the |
| 98 | +# server-side secret too. Optional in BYOK-only mode (no REDIS_URL set), |
| 99 | +# since hashes never persist beyond the process. |
| 100 | +# |
| 101 | +# Generate with: openssl rand -hex 32 |
| 102 | +# IP_HASH_SALT= |
0 commit comments