Replace PostgreSQL and Docker deployment with embedded Turso, Drizzle relational queries v2, native systemd deployment on port 43821, and fresh SQLite migrations.
Hop-State: A_06FP5KEDBTB4A9ZT7QB498G Hop-Proposal: R_06FP5KDWMCKVVMQZT4MVZ28 Hop-Task: T_06FP5DZ7T0G45FG93PT90B8 Hop-Attempt: AT_06FP5DZ7T0PKQW99V27JCV8
This commit is contained in:
@@ -1,9 +0,0 @@
|
||||
import { db } from '../src/db';
|
||||
|
||||
async function main() {
|
||||
await db.execute(`ALTER TABLE chat_messages ADD COLUMN IF NOT EXISTS sender_did text;`);
|
||||
console.log('Added sender_did column to chat_messages');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,40 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Caddy Entrypoint Script for Synapsis
|
||||
# Reads the dynamic port from the shared file and starts Caddy
|
||||
|
||||
set -e
|
||||
|
||||
SHARED_PORT_FILE="/var/run/synapsis/port"
|
||||
DEFAULT_PORT=3000
|
||||
|
||||
# Wait for the port file to exist (with timeout)
|
||||
echo "⏳ Waiting for Synapsis app to announce its port..."
|
||||
TIMEOUT=60
|
||||
ELAPSED=0
|
||||
|
||||
while [ ! -f "$SHARED_PORT_FILE" ] && [ $ELAPSED -lt $TIMEOUT ]; do
|
||||
sleep 1
|
||||
ELAPSED=$((ELAPSED + 1))
|
||||
done
|
||||
|
||||
if [ -f "$SHARED_PORT_FILE" ]; then
|
||||
APP_PORT=$(cat "$SHARED_PORT_FILE")
|
||||
echo "✅ Found Synapsis app on port: $APP_PORT"
|
||||
else
|
||||
echo "⚠️ Port file not found after ${TIMEOUT}s, using default port: $DEFAULT_PORT"
|
||||
APP_PORT=$DEFAULT_PORT
|
||||
fi
|
||||
|
||||
export APP_PORT
|
||||
|
||||
# Validate that APP_PORT is a number
|
||||
if ! echo "$APP_PORT" | grep -qE '^[0-9]+$'; then
|
||||
echo "❌ Invalid port number: $APP_PORT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🌐 Starting Caddy reverse proxy to app:$APP_PORT..."
|
||||
echo ""
|
||||
|
||||
# Start Caddy with the environment variable set
|
||||
exec caddy run --config /etc/caddy/Caddyfile --adapter caddyfile
|
||||
@@ -1,203 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Synapsis Docker Entrypoint Script
|
||||
# Handles database migrations, port detection, and application startup
|
||||
|
||||
set -e
|
||||
|
||||
# Default port range for auto-detection
|
||||
PORT_START=${PORT_START:-3000}
|
||||
PORT_END=${PORT_END:-3020}
|
||||
|
||||
# Function to check if a port is available
|
||||
check_port_available() {
|
||||
local port=$1
|
||||
if ! nc -z localhost "$port" 2>/dev/null; then
|
||||
return 0 # Port is available
|
||||
else
|
||||
return 1 # Port is in use
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to find first available port in range
|
||||
find_available_port() {
|
||||
local start=$1
|
||||
local end=$2
|
||||
|
||||
for port in $(seq "$start" "$end"); do
|
||||
if check_port_available "$port"; then
|
||||
echo "$port"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
echo "ERROR: No available ports found in range $start-$end" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
# Handle PORT=auto
|
||||
if [ "${PORT}" = "auto" ]; then
|
||||
echo "🔍 PORT=auto detected, scanning for available port in range ${PORT_START}-${PORT_END}..."
|
||||
|
||||
DETECTED_PORT=$(find_available_port "$PORT_START" "$PORT_END")
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "❌ Failed to find an available port. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export PORT="$DETECTED_PORT"
|
||||
echo "✅ Using automatically detected port: $PORT"
|
||||
else
|
||||
echo "📡 Using configured port: $PORT"
|
||||
fi
|
||||
|
||||
# Ensure PORT is set
|
||||
if [ -z "$PORT" ]; then
|
||||
echo "⚠️ PORT not set, defaulting to 3000"
|
||||
export PORT=3000
|
||||
fi
|
||||
|
||||
# Write port to shared file for Caddy to read
|
||||
SHARED_PORT_FILE="/var/run/synapsis/port"
|
||||
mkdir -p "$(dirname "$SHARED_PORT_FILE")"
|
||||
echo "$PORT" > "$SHARED_PORT_FILE"
|
||||
echo "📝 Port $PORT written to $SHARED_PORT_FILE"
|
||||
|
||||
# Export HOSTNAME for Next.js
|
||||
export HOSTNAME="0.0.0.0"
|
||||
|
||||
# ============================================
|
||||
# Database Migrations
|
||||
# ============================================
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo " Synapsis - Starting Application"
|
||||
echo "========================================"
|
||||
echo " Time: $(date)"
|
||||
echo " Working Dir: $(pwd)"
|
||||
echo " Database URL: ${DATABASE_URL%%:*}://***@***"
|
||||
echo " Port: $PORT"
|
||||
echo "========================================"
|
||||
|
||||
# Ensure DATABASE_URL is set
|
||||
if [ -z "$DATABASE_URL" ]; then
|
||||
echo "❌ DATABASE_URL is not set. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Normalize domain inputs (strip scheme/path) to avoid localhost/protocol issues
|
||||
sanitize_domain() {
|
||||
echo "$1" | sed -E 's#^[a-zA-Z]+://##; s#/.*$##'
|
||||
}
|
||||
|
||||
# Normalize DOMAIN if provided
|
||||
if [ -n "$DOMAIN" ]; then
|
||||
CLEAN_DOMAIN=$(sanitize_domain "$DOMAIN")
|
||||
if [ "$CLEAN_DOMAIN" != "$DOMAIN" ]; then
|
||||
export DOMAIN="$CLEAN_DOMAIN"
|
||||
echo "🌐 DOMAIN normalized to $DOMAIN"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Normalize NEXT_PUBLIC_NODE_DOMAIN if provided
|
||||
if [ -n "$NEXT_PUBLIC_NODE_DOMAIN" ]; then
|
||||
CLEAN_NODE_DOMAIN=$(sanitize_domain "$NEXT_PUBLIC_NODE_DOMAIN")
|
||||
if [ "$CLEAN_NODE_DOMAIN" != "$NEXT_PUBLIC_NODE_DOMAIN" ]; then
|
||||
export NEXT_PUBLIC_NODE_DOMAIN="$CLEAN_NODE_DOMAIN"
|
||||
echo "🌐 NEXT_PUBLIC_NODE_DOMAIN normalized to $NEXT_PUBLIC_NODE_DOMAIN"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Ensure NEXT_PUBLIC_NODE_DOMAIN is set (fallback to DOMAIN)
|
||||
if [ -z "$NEXT_PUBLIC_NODE_DOMAIN" ] && [ -n "$DOMAIN" ]; then
|
||||
export NEXT_PUBLIC_NODE_DOMAIN="$DOMAIN"
|
||||
echo "🌐 NEXT_PUBLIC_NODE_DOMAIN set to $NEXT_PUBLIC_NODE_DOMAIN"
|
||||
fi
|
||||
|
||||
# Fail fast if running in production with localhost domain
|
||||
if [ "$NODE_ENV" = "production" ]; then
|
||||
case "$NEXT_PUBLIC_NODE_DOMAIN" in
|
||||
""|localhost|localhost:*|127.0.0.1|127.0.0.1:*)
|
||||
if [ -z "$ALLOW_LOCALHOST" ]; then
|
||||
echo "❌ NEXT_PUBLIC_NODE_DOMAIN is set to localhost in production."
|
||||
echo " Set DOMAIN to your public domain in .env, or set ALLOW_LOCALHOST=1 to bypass."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Ensure NEXT_PUBLIC_APP_URL is set for background jobs
|
||||
if [ -z "$NEXT_PUBLIC_APP_URL" ] && [ -n "$NEXT_PUBLIC_NODE_DOMAIN" ]; then
|
||||
case "$NEXT_PUBLIC_NODE_DOMAIN" in
|
||||
http://*|https://*)
|
||||
NEXT_PUBLIC_APP_URL="$NEXT_PUBLIC_NODE_DOMAIN"
|
||||
;;
|
||||
localhost*|127.0.0.1*)
|
||||
NEXT_PUBLIC_APP_URL="http://$NEXT_PUBLIC_NODE_DOMAIN"
|
||||
;;
|
||||
*)
|
||||
NEXT_PUBLIC_APP_URL="https://$NEXT_PUBLIC_NODE_DOMAIN"
|
||||
;;
|
||||
esac
|
||||
export NEXT_PUBLIC_APP_URL
|
||||
echo "🌐 NEXT_PUBLIC_APP_URL set to $NEXT_PUBLIC_APP_URL"
|
||||
fi
|
||||
|
||||
# Function to wait for database
|
||||
wait_for_db() {
|
||||
echo ""
|
||||
echo "⏳ Waiting for PostgreSQL..."
|
||||
|
||||
# Extract host and port from DATABASE_URL
|
||||
DB_HOST=$(echo "$DATABASE_URL" | sed -n 's#.*@\([^/:]*\).*#\1#p')
|
||||
DB_PORT=$(echo "$DATABASE_URL" | sed -n 's#.*:\([0-9][0-9]*\)/.*#\1#p')
|
||||
DB_HOST=${DB_HOST:-postgres}
|
||||
DB_PORT=${DB_PORT:-5432}
|
||||
|
||||
max_retries=30
|
||||
retry_count=0
|
||||
|
||||
while ! nc -z "$DB_HOST" "$DB_PORT" 2>/dev/null; do
|
||||
retry_count=$((retry_count + 1))
|
||||
if [ $retry_count -ge $max_retries ]; then
|
||||
echo "❌ Failed to connect to database after $max_retries attempts"
|
||||
exit 1
|
||||
fi
|
||||
echo " Attempt $retry_count/$max_retries - waiting for $DB_HOST:$DB_PORT..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
echo "✅ Database is ready!"
|
||||
}
|
||||
|
||||
# Function to run database migrations
|
||||
run_migrations() {
|
||||
echo ""
|
||||
echo "🔄 Running database migrations..."
|
||||
echo " Current directory: $(pwd)"
|
||||
echo " Drizzle directory contents:"
|
||||
ls -la drizzle/ 2>/dev/null || echo " (drizzle dir not found or empty)"
|
||||
|
||||
# Run migrations using npm script
|
||||
echo " Executing: npm run db:push"
|
||||
if npm run db:push 2>&1; then
|
||||
echo "✅ Migration step complete"
|
||||
else
|
||||
echo "❌ Migration failed"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Wait for database
|
||||
wait_for_db
|
||||
|
||||
# Run migrations
|
||||
run_migrations
|
||||
|
||||
echo "🚀 Starting Synapsis on port $PORT..."
|
||||
echo ""
|
||||
|
||||
# Start the Next.js application
|
||||
exec node server.js
|
||||
@@ -1,120 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
IMAGE_REPO="${IMAGE_REPO:-ghcr.io/gnosyslabs/synapsis}"
|
||||
PACKAGE_API="${PACKAGE_API:-/orgs/GnosysLabs/packages/container/synapsis/versions?per_page=100}"
|
||||
BUILDER="${BUILDER:-}"
|
||||
PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}"
|
||||
DATE_PREFIX="${DATE_PREFIX:-$(date -u +%Y.%m.%d)}"
|
||||
SOURCE_REPO="${SOURCE_REPO:-https://github.com/GnosysLabs/Synapsis}"
|
||||
PRUNE_BUILD_CACHE="${PRUNE_BUILD_CACHE:-1}"
|
||||
APP_VERSION="${APP_VERSION:-}"
|
||||
EXTRA_TAGS="${EXTRA_TAGS:-}"
|
||||
|
||||
require_command() {
|
||||
if ! command -v "$1" >/dev/null 2>&1; then
|
||||
echo "❌ Required command not found: $1" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
require_command docker
|
||||
require_command gh
|
||||
require_command git
|
||||
|
||||
CURRENT_SHA="$(git rev-parse --short HEAD)"
|
||||
CURRENT_FULL_SHA="$(git rev-parse HEAD)"
|
||||
BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
GITHUB_URL="${SOURCE_REPO}/commit/${CURRENT_FULL_SHA}"
|
||||
|
||||
if [ -z "${APP_VERSION}" ]; then
|
||||
existing_tags="$(
|
||||
gh api "${PACKAGE_API}" --paginate --jq '.[].metadata.container.tags[]?' 2>/dev/null || true
|
||||
)"
|
||||
|
||||
max_build=0
|
||||
for tag in ${existing_tags}; do
|
||||
case "${tag}" in
|
||||
"${DATE_PREFIX}".*)
|
||||
build_number="${tag##${DATE_PREFIX}.}"
|
||||
case "${build_number}" in
|
||||
''|*[!0-9]*)
|
||||
;;
|
||||
*)
|
||||
if [ "${build_number}" -gt "${max_build}" ]; then
|
||||
max_build="${build_number}"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
next_build=$((max_build + 1))
|
||||
APP_VERSION="${DATE_PREFIX}.${next_build}"
|
||||
fi
|
||||
|
||||
BUILD_ARGS="
|
||||
--platform ${PLATFORMS}
|
||||
--build-arg APP_VERSION=${APP_VERSION}
|
||||
--build-arg APP_COMMIT=${CURRENT_FULL_SHA}
|
||||
--build-arg APP_BUILD_DATE=${BUILD_DATE}
|
||||
--build-arg APP_GITHUB_URL=${GITHUB_URL}
|
||||
--build-arg APP_IMAGE_REPO=${IMAGE_REPO}
|
||||
--build-arg APP_SOURCE_REPO=${SOURCE_REPO}
|
||||
"
|
||||
|
||||
TAG_ARGS="
|
||||
-t ${IMAGE_REPO}:latest
|
||||
-t ${IMAGE_REPO}:${APP_VERSION}
|
||||
-t ${IMAGE_REPO}:${CURRENT_SHA}
|
||||
"
|
||||
|
||||
for extra_tag in ${EXTRA_TAGS}; do
|
||||
TAG_ARGS="${TAG_ARGS}
|
||||
-t ${IMAGE_REPO}:${extra_tag}"
|
||||
done
|
||||
|
||||
echo "========================================"
|
||||
echo " Synapsis Docker Publish"
|
||||
echo "========================================"
|
||||
echo " Version: ${APP_VERSION}"
|
||||
echo " Commit: ${CURRENT_SHA}"
|
||||
echo " Build Date: ${BUILD_DATE}"
|
||||
echo " Image: ${IMAGE_REPO}"
|
||||
echo " Platforms: ${PLATFORMS}"
|
||||
echo "========================================"
|
||||
|
||||
set -- docker buildx build
|
||||
|
||||
if [ -n "${BUILDER}" ]; then
|
||||
set -- "$@" --builder "${BUILDER}"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
set -- "$@" $BUILD_ARGS -f docker/Dockerfile
|
||||
# shellcheck disable=SC2086
|
||||
set -- "$@" $TAG_ARGS --push .
|
||||
|
||||
"$@"
|
||||
|
||||
echo ""
|
||||
echo "✅ Published:"
|
||||
echo " ${IMAGE_REPO}:latest"
|
||||
echo " ${IMAGE_REPO}:${APP_VERSION}"
|
||||
echo " ${IMAGE_REPO}:${CURRENT_SHA}"
|
||||
|
||||
for extra_tag in ${EXTRA_TAGS}; do
|
||||
echo " ${IMAGE_REPO}:${extra_tag}"
|
||||
done
|
||||
|
||||
if [ "${PRUNE_BUILD_CACHE}" = "1" ]; then
|
||||
echo ""
|
||||
echo "🧹 Pruning BuildKit cache"
|
||||
if [ -n "${BUILDER}" ]; then
|
||||
docker buildx prune --builder "${BUILDER}" -af >/dev/null
|
||||
else
|
||||
docker buildx prune -af >/dev/null
|
||||
fi
|
||||
fi
|
||||
@@ -10,7 +10,7 @@ async function main() {
|
||||
console.log('--- Inspecting Remote Key ---');
|
||||
|
||||
const entry = await db.query.handleRegistry.findFirst({
|
||||
where: eq(handleRegistry.did, TARGET_DID),
|
||||
where: { did: TARGET_DID },
|
||||
});
|
||||
|
||||
if (!entry) {
|
||||
|
||||
@@ -47,7 +47,7 @@ async function migrateDIDs() {
|
||||
|
||||
// Find all users with legacy did:synapsis: format
|
||||
const legacyUsers = await db.query.users.findMany({
|
||||
where: (users, { like }) => like(users.did, 'did:synapsis:%'),
|
||||
where: { did: { like: 'did:synapsis:%' } },
|
||||
});
|
||||
|
||||
console.log(`Found ${legacyUsers.length} users with legacy DID format\n`);
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { migrate } from 'drizzle-orm/tursodatabase/migrator';
|
||||
import { db } from '../src/db';
|
||||
|
||||
async function main() {
|
||||
const result = await migrate(db, { migrationsFolder: './drizzle' });
|
||||
|
||||
if (result) {
|
||||
throw new Error(`Database migration failed: ${JSON.stringify(result)}`);
|
||||
}
|
||||
|
||||
console.log('Database migrations are up to date.');
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user