#!/usr/bin/env bash # Refresh the local Payload seed snapshot from staging, then force-apply it to # the local development Payload database. Normal db:up never calls staging. set -euo pipefail SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" ROOT_DIR="$(cd -- "$SCRIPT_DIR/../.." && pwd)" COMPOSE_FILE="$ROOT_DIR/docker/compose.local.yml" SNAPSHOT="$ROOT_DIR/.local/payload-staging.dump" STAGING_ENV="" DEV_ENV="" SOURCE_PG_ENV="" ASSUME_YES=false [ "${1:-}" = "--yes" ] && ASSUME_YES=true info() { printf '▶ %s\n' "$*"; } die() { printf 'Error: %s\n' "$*" >&2; exit 1; } if command -v docker >/dev/null 2>&1; then RUNTIME=docker elif command -v podman >/dev/null 2>&1; then RUNTIME=podman else die "Docker or Podman is required."; fi "$RUNTIME" info >/dev/null 2>&1 || die "$RUNTIME is not usable." mkdir -p "$ROOT_DIR/.local" chmod 700 "$ROOT_DIR/.local" cleanup() { [ -z "$STAGING_ENV" ] || rm -f "$STAGING_ENV" [ -z "$DEV_ENV" ] || rm -f "$DEV_ENV" [ -z "$SOURCE_PG_ENV" ] || rm -f "$SOURCE_PG_ENV" rm -f "${SNAPSHOT}.tmp" } trap cleanup EXIT INT TERM HUP STAGING_ENV="$(mktemp "${TMPDIR:-/tmp}/convex-monorepo-staging.XXXXXX.env")" DEV_ENV="$(mktemp "${TMPDIR:-/tmp}/convex-monorepo-dev.XXXXXX.env")" sh "$ROOT_DIR/scripts/export-env" staging > "$STAGING_ENV" sh "$ROOT_DIR/scripts/export-env" dev > "$DEV_ENV" validate_url() { local env_file="$1" expected="$2" bunx dotenv -e "$env_file" -- node -e ' const expected = process.argv[1]; const raw = process.env.PAYLOAD_DB_URL; if (!raw) process.exit(2); const url = new URL(raw); const local = url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "::1"; if ((expected === "local") !== local) process.exit(3); ' "$expected" || die "PAYLOAD_DB_URL safety check failed for the $expected environment." } validate_url "$STAGING_ENV" remote validate_url "$DEV_ENV" local next_is_running=false if command -v ss >/dev/null 2>&1; then ss -ltnH 'sport = :3000' | grep -q . && next_is_running=true elif command -v lsof >/dev/null 2>&1; then lsof -nP -iTCP:3000 -sTCP:LISTEN >/dev/null 2>&1 && next_is_running=true elif curl -sS --max-time 1 http://localhost:3000 >/dev/null 2>&1; then next_is_running=true fi if [ "$next_is_running" = true ]; then die "Next is running on port 3000. Stop bun dev:next before replacing Payload data." fi SOURCE_PG_ENV="$(mktemp "${TMPDIR:-/tmp}/convex-monorepo-pg.XXXXXX.env")" PG_ENV_FILE="$SOURCE_PG_ENV" bunx dotenv -e "$STAGING_ENV" -- sh -c ' umask 077 printf "PGDATABASE=%s\n" "$PAYLOAD_DB_URL" > "$PG_ENV_FILE" ' if [ "$ASSUME_YES" != true ]; then printf 'This will download staging Payload data and replace the LOCAL Payload database.\n' printf 'The snapshot may contain user records and password hashes; it stays under .local/.\n' read -r -p 'Continue? [y/N] ' answer case "$answer" in y|Y|yes|YES) ;; *) echo "Cancelled."; exit 0 ;; esac fi info "Exporting a read-only snapshot from staging Payload Postgres" "$RUNTIME" run --rm --network host --env-file "$SOURCE_PG_ENV" \ docker.io/library/postgres:17 \ sh -c 'exec pg_dump --dbname="$PGDATABASE" --format=custom --no-owner --no-acl' \ > "${SNAPSHOT}.tmp" mv "${SNAPSHOT}.tmp" "$SNAPSHOT" chmod 600 "$SNAPSHOT" info "Ensuring local Payload Postgres is running" bash "$ROOT_DIR/scripts/db/seed-payload" --force --yes printf '\nLocal Payload seed snapshot refreshed and applied.\n' printf 'Snapshot: .local/payload-staging.dump\n' printf 'Normal db:up will reuse this snapshot and skip after .local/payload-seed-state.env exists.\n'