#!/bin/bash # Copies Storage objects (binary files) from the OLD managed Supabase project's Storage # API to the new self-hosted Storage API, preserving bucket names, object paths and # content-type. Bucket definitions + storage.objects METADATA rows are already restored # by 02-restore-new.sh (they live in the `storage` schema, covered by schema.sql/data.sql) # — this script only moves the actual binary blobs, which live outside Postgres. set -euo pipefail : "${OLD_SUPABASE_URL:?e.g. https://cksuehzcimitsxmeloes.supabase.co}" : "${OLD_SERVICE_ROLE_KEY:?Old project's service_role key (Dashboard -> Project Settings -> API)}" : "${NEW_SUPABASE_URL:?e.g. https://api.caterium.ru}" : "${NEW_SERVICE_ROLE_KEY:?New stack's SERVICE_ROLE_KEY from .env}" TMP_DIR="$(mktemp -d)" trap 'rm -rf "$TMP_DIR"' EXIT echo "== Listing buckets on OLD project ==" BUCKETS=$(curl -sf "$OLD_SUPABASE_URL/storage/v1/bucket" \ -H "Authorization: Bearer $OLD_SERVICE_ROLE_KEY" \ -H "apikey: $OLD_SERVICE_ROLE_KEY" | jq -r '.[].id') for bucket in $BUCKETS; do echo "== Bucket: $bucket ==" OBJECTS=$(curl -sf -X POST "$OLD_SUPABASE_URL/storage/v1/object/list/$bucket" \ -H "Authorization: Bearer $OLD_SERVICE_ROLE_KEY" \ -H "apikey: $OLD_SERVICE_ROLE_KEY" \ -H "Content-Type: application/json" \ -d '{"limit": 1000, "offset": 0, "prefix": ""}' | jq -r '.[] | select(.id != null) | .name') count=0 while IFS= read -r path; do [ -z "$path" ] && continue local_file="$TMP_DIR/$(basename "$path")" curl -sf "$OLD_SUPABASE_URL/storage/v1/object/$bucket/$path" \ -H "Authorization: Bearer $OLD_SERVICE_ROLE_KEY" \ -H "apikey: $OLD_SERVICE_ROLE_KEY" \ -o "$local_file" curl -sf -X POST "$NEW_SUPABASE_URL/storage/v1/object/$bucket/$path" \ -H "Authorization: Bearer $NEW_SERVICE_ROLE_KEY" \ -H "apikey: $NEW_SERVICE_ROLE_KEY" \ -H "x-upsert: true" \ --data-binary "@$local_file" > /dev/null rm -f "$local_file" count=$((count + 1)) echo " copied: $bucket/$path" done <<< "$OBJECTS" echo " -> $count object(s) copied for bucket $bucket" done echo "" echo "Done. Spot-check: open a known photo URL under $NEW_SUPABASE_URL/storage/v1/object/public//" echo "and confirm it renders identically to the old one."