Spaces:
Paused
Paused
File size: 7,710 Bytes
c293b5b 3d64dad c293b5b 3d64dad c293b5b 3d64dad c293b5b 3d64dad c293b5b 3d64dad c293b5b 3d64dad c293b5b 3d64dad c293b5b 3a88149 c293b5b 3d64dad 3a88149 c293b5b 3d64dad c293b5b 3d64dad c293b5b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | FROM oven/bun:1-slim
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
git ca-certificates curl sqlite3 rsync python3 \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
ARG LUMIVERSE_REPO=https://github.com/CloudCompile/Lumiverse.git
ARG LUMIVERSE_REF=Leaderboard
RUN git clone --depth 1 --branch "${LUMIVERSE_REF}" "${LUMIVERSE_REPO}" .
# This patch only applies to forks/branches that still have the old
# unpatched host-only rewrite block. If the fork has already diverged
# (different code, or already fixed upstream), the patch is skipped
# instead of failing the whole build.
RUN cat > /tmp/patch-auth-rewrite.mjs <<'PATCH'
import { readFileSync, writeFileSync } from "fs";
const path = "src/app.ts";
const src = readFileSync(path, "utf8");
const before = `app.on(["POST", "GET"], "/api/auth/*", (c) => {
const host = c.req.header("host");
if (host) {
const url = new URL(c.req.url);
const rewritten = new URL(url.pathname + url.search, \`http://\${host}\`);
return auth.handler(new Request(rewritten.toString(), c.req.raw));
}
return auth.handler(c.req.raw);
});`;
const after = `app.on(["POST", "GET"], "/api/auth/*", (c) => {
const host = c.req.header("x-forwarded-host") || c.req.header("host");
const proto = c.req.header("x-forwarded-proto") || "http";
if (host) {
const url = new URL(c.req.url);
const rewritten = new URL(url.pathname + url.search, \`\${proto}://\${host}\`);
return auth.handler(new Request(rewritten.toString(), c.req.raw));
}
return auth.handler(c.req.raw);
});`;
if (src.includes("x-forwarded-host") || src.includes("x-forwarded-proto")) {
console.log("[patch] src/app.ts already forwards x-forwarded-host/proto — skipping patch");
process.exit(0);
}
if (!src.includes(before)) {
console.warn("[patch] Expected auth rewrite block not found in src/app.ts — skipping patch");
console.warn("[patch] This fork/branch may have a different auth setup. If HTTPS auth redirects");
console.warn("[patch] fail at runtime, this file will need a manual patch.");
process.exit(0);
}
writeFileSync(path, src.replace(before, after), "utf8");
console.log("[patch] Patched src/app.ts for x-forwarded-proto/host");
PATCH
RUN bun /tmp/patch-auth-rewrite.mjs
RUN rm -f package-lock.json && bun install --production
WORKDIR /app/frontend
RUN rm -f package-lock.json && bun install && bun run build
RUN printf "self.addEventListener('install',e=>self.skipWaiting());self.addEventListener('activate',e=>e.waitUntil(self.clients.claim()));\n" > /app/frontend/dist/sw.js
RUN test -f /app/frontend/dist/index.html
WORKDIR /app
ENV NODE_ENV=production
ENV PORT=7860
ENV DATA_DIR=/app/data
ENV FRONTEND_DIR=/app/frontend/dist
ENV TRUST_ANY_ORIGIN=true
ENV OWNER_PASSWORD=admin123
# === DATA INTEGRITY & CORRUPTION RECOVERY ===
# Create a recovery script that runs before the app starts
RUN cat > /app/check-and-repair-data.sh <<'REPAIR'
#!/usr/bin/env sh
set -e
DATA_DIR="${DATA_DIR:-/app/data}"
echo "[integrity] Starting pre-startup data checks..."
# Ensure data directory structure exists
mkdir -p "$DATA_DIR"
# Critical check: top-level entries (users, uploads, extensions) must be
# directories. HF Spaces storage remounts have been observed to leave these
# as stray files instead. If any of them is a file, quarantine it before
# trying to mkdir, or every startup will fail with "File exists".
for entry in users uploads extensions; do
entry_path="$DATA_DIR/$entry"
if [ -e "$entry_path" ] && [ ! -d "$entry_path" ]; then
echo "[integrity] $entry_path exists but is not a directory (corrupted remount)"
echo "[integrity] Quarantining to ${entry_path}.corrupted-$(date +%s)"
mv "$entry_path" "${entry_path}.corrupted-$(date +%s)"
fi
done
USERS_DIR="$DATA_DIR/users"
# If users directory exists, scan for corrupted entries
if [ -d "$USERS_DIR" ]; then
echo "[integrity] Checking user directories for corruption..."
find "$USERS_DIR" -maxdepth 1 -type f 2>/dev/null | while read -r corrupt_file; do
# There should be NO files directly in users/ — only directories
echo "[integrity] Found stray file in users/: $corrupt_file"
echo "[integrity] Moving to quarantine: ${corrupt_file}.corrupted"
mv "$corrupt_file" "${corrupt_file}.corrupted"
done
# Check each user's subdirectory for storage file/directory collision
find "$USERS_DIR" -maxdepth 2 -name "storage" -type f 2>/dev/null | while read -r storage_file; do
user_dir=$(dirname "$storage_file")
echo "[integrity] Found file where directory expected: $storage_file"
echo "[integrity] This was caused by HF Spaces storage remount. Removing corrupt file..."
rm -f "$storage_file"
echo "[integrity] Directory will be auto-created on first use"
done
fi
# Pre-create critical directories to prevent race conditions.
# These run with '|| true' as a last-resort safety net: the loop above should
# have already cleared any file/directory collisions, but if something
# unexpected still blocks mkdir, log it instead of crashing the container —
# the app's own provisioning code can then surface a clearer error.
mkdir -p "$DATA_DIR/users" || echo "[integrity] WARNING: could not create $DATA_DIR/users, check manually"
mkdir -p "$DATA_DIR/uploads" || echo "[integrity] WARNING: could not create $DATA_DIR/uploads, check manually"
mkdir -p "$DATA_DIR/extensions" || echo "[integrity] WARNING: could not create $DATA_DIR/extensions, check manually"
# Verify SQLite database integrity if it exists
DB_PATH="$DATA_DIR/lumiverse.db"
if [ -e "$DB_PATH" ]; then
echo "[integrity] Inspecting $DB_PATH..."
ls -la "$DB_PATH" 2>&1 || true
file "$DB_PATH" 2>&1 || true
if [ ! -f "$DB_PATH" ]; then
echo "[integrity] $DB_PATH exists but is not a regular file (corrupted remount)"
echo "[integrity] Quarantining to ${DB_PATH}.corrupted-$(date +%s)"
mv "$DB_PATH" "${DB_PATH}.corrupted-$(date +%s)"
else
echo "[integrity] Running SQLite integrity check..."
if ! sqlite3 "$DB_PATH" "PRAGMA integrity_check;" 2>&1 | grep -q "ok"; then
echo "[integrity] WARNING: Database integrity check failed (disk I/O error or corruption)."
echo "[integrity] NOT deleting or overwriting the database automatically — that risks data loss."
echo "[integrity] Backing up as-is to ${DB_PATH}.bak-$(date +%s) for manual inspection."
cp "$DB_PATH" "${DB_PATH}.bak-$(date +%s)" 2>&1 || echo "[integrity] Backup copy also failed — underlying mount may be unhealthy."
echo "[integrity] The app will attempt to start anyway; if it cannot open the database,"
echo "[integrity] this usually means the persistent storage mount itself needs to be"
echo "[integrity] detached and reattached from the Space's Settings page."
else
echo "[integrity] Database integrity check passed"
fi
fi
else
echo "[integrity] No existing database found at $DB_PATH (fresh install or not yet created)"
fi
echo "[integrity] Pre-startup checks complete"
REPAIR
RUN chmod +x /app/check-and-repair-data.sh
# Startup script that runs integrity check BEFORE the app
RUN cat > /app/start.sh <<'SH'
#!/usr/bin/env sh
set -eu
export DATA_DIR="${DATA_DIR:-/app/data}"
# Run data integrity checks first
/app/check-and-repair-data.sh
# Then start the app
exec bun run scripts/runner.ts
SH
RUN chmod +x /app/start.sh
USER root
# Create data directory with proper permissions
RUN mkdir -p /app/data && chown -R bun:bun /app/data
# Pre-create user directory to prevent first-run permission issues
RUN mkdir -p /app/data/users && chown -R bun:bun /app/data/users
EXPOSE 7860
VOLUME /app/data
USER bun
CMD ["/app/start.sh"] |