scripts/start-cloudflare-workers.sh
Rama main · réplica de lectura del repositorio original.
#!/usr/bin/env bash
# Script to start Cloudflare Workers for testing
# This script starts all workers (API, Plugin, Files) in the background
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
echo "Starting Cloudflare Workers for testing..."
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
run_supabase_status_env() {
# Prefer the repo wrapper so worktrees get isolated Supabase stacks.
if command -v bun >/dev/null 2>&1; then
if bun run supabase:status -- -o env 2>/dev/null; then
return 0
fi
fi
# A scoped job must never discover another job's default Supabase stack.
if [[ -n "${SUPABASE_WORKTREE_INSTANCE:-}" || -n "${SUPABASE_WORKTREE_PORT_OFFSET:-}" ]]; then
return 1
fi
# Legacy fallback for unscoped developer commands.
if command -v supabase >/dev/null 2>&1; then
supabase status -o env 2>/dev/null && return 0
fi
bunx supabase status -o env 2>/dev/null && return 0
return 1
}
# Extract a single variable from `supabase status -o env`, preserving any '=' in values (JWT padding).
get_supabase_status_var() {
local key_regex="$1"
# Output looks like: KEY="value" or KEY=value
printf '%s\n' "${SUPA_ENV}" \
| grep -E "^(${key_regex})=" \
| head -n 1 \
| sed -E 's/^[^=]+=//' \
| sed -E 's/^"//; s/"$//'
}
# Build a runtime env file with local Supabase keys so we don't commit secrets.
BASE_ENV_FILE="${ROOT_DIR}/cloudflare_workers/.env.local"
RUNTIME_ENV_FILE="$(mktemp "${TMPDIR:-/tmp}/capgo-cloudflare-env.XXXXXX")"
chmod 600 "${RUNTIME_ENV_FILE}"
if [ -f "${BASE_ENV_FILE}" ]; then
cp "${BASE_ENV_FILE}" "${RUNTIME_ENV_FILE}"
else
echo -e "${YELLOW}Warning: ${BASE_ENV_FILE} not found - starting with empty base env${NC}"
fi
SUPA_ENV="$(run_supabase_status_env || true)"
SUPABASE_URL_FROM_STATUS="$(get_supabase_status_var 'API_URL')"
SUPABASE_DB_URL_FROM_STATUS="$(get_supabase_status_var 'DB_URL')"
# Supabase CLI has historically emitted either SERVICE_ROLE_KEY/ANON_KEY or SECRET_KEY/PUBLISHABLE_KEY.
SUPABASE_SERVICE_ROLE_KEY_FROM_STATUS="$(get_supabase_status_var 'SERVICE_ROLE_KEY|SECRET_KEY')"
SUPABASE_ANON_KEY_FROM_STATUS="$(get_supabase_status_var 'ANON_KEY|PUBLISHABLE_KEY')"
# Allow overrides via environment, otherwise use supabase status output.
SUPABASE_URL="${SUPABASE_URL:-${SUPABASE_URL_FROM_STATUS}}"
SUPABASE_DB_URL="${SUPABASE_DB_URL:-${SUPABASE_DB_URL_FROM_STATUS}}"
MAIN_SUPABASE_DB_URL="${MAIN_SUPABASE_DB_URL:-${SUPABASE_DB_URL_FROM_STATUS}}"
LOCAL_READ_REPLICA_SUPABASE_DB_URL="${LOCAL_READ_REPLICA_SUPABASE_DB_URL:-${SUPABASE_DB_URL}}"
SUPABASE_SERVICE_ROLE_KEY="${SUPABASE_SERVICE_ROLE_KEY:-${SUPABASE_SERVICE_ROLE_KEY_FROM_STATUS}}"
SUPABASE_ANON_KEY="${SUPABASE_ANON_KEY:-${SUPABASE_ANON_KEY_FROM_STATUS}}"
if [ -z "${SUPABASE_SERVICE_ROLE_KEY}" ] || [ -z "${SUPABASE_ANON_KEY}" ] || [ -z "${SUPABASE_URL}" ] || [ -z "${SUPABASE_DB_URL}" ] || [ -z "${MAIN_SUPABASE_DB_URL}" ]; then
echo -e "${YELLOW}Missing Supabase keys for Cloudflare Workers.${NC}"
echo "Ensure Supabase is running, or set SUPABASE_URL, SUPABASE_DB_URL, MAIN_SUPABASE_DB_URL, SUPABASE_SERVICE_ROLE_KEY and SUPABASE_ANON_KEY in your environment."
exit 1
fi
# Cloudflare local testing defaults. Each isolated test process gets its own port
# band, while a zero offset preserves the familiar local endpoints.
WORKER_PORT_OFFSET="${CLOUDFLARE_WORKER_PORT_OFFSET:-0}"
if ! [[ "${WORKER_PORT_OFFSET}" =~ ^[0-9]+$ ]]; then
echo "CLOUDFLARE_WORKER_PORT_OFFSET must be a non-negative integer." >&2
exit 1
fi
WORKER_PORT_OFFSET=$((10#${WORKER_PORT_OFFSET}))
if (( WORKER_PORT_OFFSET > 50000 )); then
echo "CLOUDFLARE_WORKER_PORT_OFFSET is too large." >&2
exit 1
fi
CLOUDFLARE_API_PORT=$((8787 + WORKER_PORT_OFFSET))
CLOUDFLARE_PLUGIN_PORT=$((8788 + WORKER_PORT_OFFSET))
CLOUDFLARE_FILES_PORT=$((8789 + WORKER_PORT_OFFSET))
CLOUDFLARE_FUNCTION_URL="${CLOUDFLARE_FUNCTION_URL:-http://127.0.0.1:${CLOUDFLARE_API_PORT}}"
STRIPE_WEBHOOK_SECRET="${STRIPE_WEBHOOK_SECRET:-testsecret}"
API_INSPECTOR_PORT="${API_INSPECTOR_PORT:-$((9230 + WORKER_PORT_OFFSET))}"
PLUGIN_INSPECTOR_PORT="${PLUGIN_INSPECTOR_PORT:-$((9231 + WORKER_PORT_OFFSET))}"
FILES_INSPECTOR_PORT="${FILES_INSPECTOR_PORT:-$((9232 + WORKER_PORT_OFFSET))}"
if [[ -n "${CLOUDFLARE_PERSIST_DIR:-}" ]]; then
PERSIST_DIR="${CLOUDFLARE_PERSIST_DIR}"
if [[ "${PERSIST_DIR}" != /* ]]; then
PERSIST_DIR="${ROOT_DIR}/${PERSIST_DIR}"
fi
elif (( WORKER_PORT_OFFSET == 0 )); then
PERSIST_DIR="${ROOT_DIR}/.wrangler-shared"
else
PERSIST_DIR="${ROOT_DIR}/.wrangler-shared-${WORKER_PORT_OFFSET}"
fi
mkdir -p "${PERSIST_DIR}"
# Route worker S3 calls through the selected isolated Supabase API endpoint.
S3_ENDPOINT_TO_USE="${S3_ENDPOINT:-${SUPABASE_URL%/}/storage/v1/s3}"
# Sign them with that Storage instance's S3 keys, not the MinIO defaults in .env.local.
S3_ACCESS_KEY_ID_TO_USE="${S3_ACCESS_KEY_ID:-$(get_supabase_status_var 'S3_PROTOCOL_ACCESS_KEY_ID')}"
S3_SECRET_ACCESS_KEY_TO_USE="${S3_SECRET_ACCESS_KEY:-$(get_supabase_status_var 'S3_PROTOCOL_ACCESS_KEY_SECRET')}"
S3_REGION_TO_USE="${S3_REGION:-$(get_supabase_status_var 'S3_PROTOCOL_REGION')}"
API_PID=''
PLUGIN_PID=''
FILES_PID=''
cleanup() {
local pid
echo -e "\n${YELLOW}Stopping workers...${NC}"
for pid in "${API_PID}" "${PLUGIN_PID}" "${FILES_PID}"; do
if [[ -z "${pid}" ]]; then
continue
fi
if kill -0 "${pid}" 2>/dev/null; then
kill "${pid}" 2>/dev/null || true
fi
wait "${pid}" 2>/dev/null || true
done
rm -f "${RUNTIME_ENV_FILE}" 2>/dev/null || true
echo -e "${GREEN}All workers stopped${NC}"
}
trap cleanup EXIT INT TERM
cat >> "${RUNTIME_ENV_FILE}" <<ENV_EOF
MAIN_SUPABASE_DB_URL=${MAIN_SUPABASE_DB_URL}
SUPABASE_DB_URL=${SUPABASE_DB_URL}
LOCAL_READ_REPLICA_SUPABASE_DB_URL=${LOCAL_READ_REPLICA_SUPABASE_DB_URL}
SUPABASE_URL=${SUPABASE_URL}
SUPABASE_SERVICE_ROLE_KEY=${SUPABASE_SERVICE_ROLE_KEY}
SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY}
CLOUDFLARE_FUNCTION_URL=${CLOUDFLARE_FUNCTION_URL}
FILES_PUBLIC_URL=http://127.0.0.1:${CLOUDFLARE_FILES_PORT}
STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET}
S3_ENDPOINT=${S3_ENDPOINT_TO_USE}
# Worker requests must keep the isolated Storage API host instead of their own host.
S3_REWRITE_LOCAL_ENDPOINT=false
RATE_LIMIT_API_KEY=999999
RATE_LIMIT_FAILED_AUTH=999999
RATE_LIMIT_CHANNEL_SELF_IP=999999
# Like the Supabase test runtime, finish request work before assertions run.
CAPGO_PREVENT_BACKGROUND_FUNCTIONS=true
# MCP Events integration tests subscribe to loopback challenge URLs.
CAPGO_ALLOW_LOCAL_WEBHOOK_URLS=true
ENV_EOF
for s3_var in S3_ACCESS_KEY_ID S3_SECRET_ACCESS_KEY S3_REGION; do
s3_value_var="${s3_var}_TO_USE"
if [[ -n "${!s3_value_var}" ]]; then
printf '%s=%s\n' "${s3_var}" "${!s3_value_var}" >> "${RUNTIME_ENV_FILE}"
fi
done
WRANGLER_DEV="${ROOT_DIR}/scripts/wrangler-dev-compat.sh"
# Start API worker on its isolated port.
echo -e "${GREEN}Starting API worker on port ${CLOUDFLARE_API_PORT}...${NC}"
(cd "${ROOT_DIR}/cloudflare_workers/api" && exec bash "${WRANGLER_DEV}" --local -c wrangler.jsonc --port "${CLOUDFLARE_API_PORT}" --inspector-port "${API_INSPECTOR_PORT}" --env-file="${RUNTIME_ENV_FILE}" --env=local --persist-to "${PERSIST_DIR}") &
API_PID=$!
# Wait a bit for the first worker to start.
sleep 3
# Start Plugin worker on its isolated port.
echo -e "${GREEN}Starting Plugin worker on port ${CLOUDFLARE_PLUGIN_PORT}...${NC}"
(cd "${ROOT_DIR}/cloudflare_workers/plugin" && exec bash "${WRANGLER_DEV}" --local -c wrangler.jsonc --port "${CLOUDFLARE_PLUGIN_PORT}" --inspector-port "${PLUGIN_INSPECTOR_PORT}" --env-file="${RUNTIME_ENV_FILE}" --env=local --persist-to "${PERSIST_DIR}") &
PLUGIN_PID=$!
# Wait a bit for the second worker to start.
sleep 3
# Start Files worker on its isolated port.
echo -e "${GREEN}Starting Files worker on port ${CLOUDFLARE_FILES_PORT}...${NC}"
(cd "${ROOT_DIR}/cloudflare_workers/files" && exec bash "${WRANGLER_DEV}" --local -c wrangler.jsonc --port "${CLOUDFLARE_FILES_PORT}" --inspector-port "${FILES_INSPECTOR_PORT}" --env-file="${RUNTIME_ENV_FILE}" --env=local --persist-to "${PERSIST_DIR}") &
FILES_PID=$!
echo -e "${GREEN}All workers started!${NC}"
echo "API Worker PID: ${API_PID} (http://127.0.0.1:${CLOUDFLARE_API_PORT})"
echo "Plugin Worker PID: ${PLUGIN_PID} (http://127.0.0.1:${CLOUDFLARE_PLUGIN_PORT})"
echo "Files Worker PID: ${FILES_PID} (http://127.0.0.1:${CLOUDFLARE_FILES_PORT})"
echo ""
echo "Press Ctrl+C to stop all workers"
# Wait for all background processes.
wait