diff --git a/frontend/cloud-staging.Dockerfile b/frontend/cloud-staging.Dockerfile new file mode 100644 index 0000000000..528d3f078b --- /dev/null +++ b/frontend/cloud-staging.Dockerfile @@ -0,0 +1,100 @@ +# Frontend (Cloud Staging) Dockerfile +# Multi-stage build: Node.js for building, nginx for serving + +# ============================================================================= +# Stage 1: Build +# ============================================================================= +FROM node:22-alpine AS builder + +# Install git, git-lfs, and coreutils (for env -S support in build scripts) +RUN apk add --no-cache git git-lfs coreutils + +# Install pnpm +RUN corepack enable && corepack prepare pnpm@latest --activate + +WORKDIR /app + +# Copy workspace configuration files +COPY pnpm-workspace.yaml package.json pnpm-lock.yaml tsconfig.base.json turbo.json tsup.base.ts ./ + +# Copy all workspace packages that frontend depends on (including transitive deps) +# frontend -> rivetkit, @rivetkit/engine-api-full +# rivetkit -> @rivetkit/virtual-websocket, @rivetkit/engine-runner +# @rivetkit/engine-runner -> @rivetkit/engine-runner-protocol +COPY frontend/ frontend/ +COPY engine/sdks/typescript/api-full/ engine/sdks/typescript/api-full/ +COPY engine/sdks/typescript/runner/ engine/sdks/typescript/runner/ +COPY engine/sdks/typescript/runner-protocol/ engine/sdks/typescript/runner-protocol/ +COPY rivetkit-typescript/packages/rivetkit/ rivetkit-typescript/packages/rivetkit/ +COPY shared/typescript/virtual-websocket/ shared/typescript/virtual-websocket/ + +# Copy generated API docs (used by rivetkit build) +COPY rivetkit-asyncapi/ rivetkit-asyncapi/ +COPY rivetkit-openapi/ rivetkit-openapi/ + +# Fetch LFS files if build platform doesn't support Git LFS natively +COPY scripts/docker/fetch-lfs.sh /tmp/fetch-lfs.sh +RUN chmod +x /tmp/fetch-lfs.sh && /tmp/fetch-lfs.sh + +# Arguments required before installing dependencies +ARG FONTAWESOME_PACKAGE_TOKEN="" +ENV FONTAWESOME_PACKAGE_TOKEN=${FONTAWESOME_PACKAGE_TOKEN} + +# Install dependencies (with pnpm store cache) +RUN --mount=type=cache,id=s/6fcfa400-4a51-4df5-9345-2918f7aca8b7-/pnpm/store,target=/pnpm/store \ + pnpm install --frozen-lockfile + +# Build arguments for environment variables +# Use placeholder URLs that pass validation but can be replaced at runtime +# Format: https://__PLACEHOLDER__.rivet.gg allows easy sed replacement +ARG VITE_APP_API_URL="https://VITE_APP_API_URL.placeholder.rivet.gg" +ARG VITE_APP_CLOUD_API_URL="https://VITE_APP_CLOUD_API_URL.placeholder.rivet.gg" +ARG VITE_APP_ASSETS_URL="https://VITE_APP_ASSETS_URL.placeholder.rivet.gg" +ARG VITE_APP_CLERK_PUBLISHABLE_KEY="pk_placeholder_clerk_key" +ARG VITE_APP_SENTRY_DSN="https://VITE_APP_SENTRY_DSN.placeholder.rivet.gg/0" +ARG VITE_APP_SENTRY_PROJECT_ID="0" +ARG VITE_APP_POSTHOG_API_KEY="" +ARG VITE_APP_POSTHOG_HOST="" +ARG DEPLOYMENT_TYPE="staging" +ARG FONTAWESOME_PACKAGE_TOKEN="" + +# Set environment variables for build +ENV VITE_APP_API_URL=${VITE_APP_API_URL} +ENV VITE_APP_CLOUD_API_URL=${VITE_APP_CLOUD_API_URL} +ENV VITE_APP_ASSETS_URL=${VITE_APP_ASSETS_URL} +ENV VITE_APP_CLERK_PUBLISHABLE_KEY=${VITE_APP_CLERK_PUBLISHABLE_KEY} +ENV VITE_APP_SENTRY_DSN=${VITE_APP_SENTRY_DSN} +ENV VITE_APP_SENTRY_PROJECT_ID=${VITE_APP_SENTRY_PROJECT_ID} +ENV VITE_APP_POSTHOG_API_KEY=${VITE_APP_POSTHOG_API_KEY} +ENV VITE_APP_POSTHOG_HOST=${VITE_APP_POSTHOG_HOST} +ENV DEPLOYMENT_TYPE=${DEPLOYMENT_TYPE} +ENV FONTAWESOME_PACKAGE_TOKEN=${FONTAWESOME_PACKAGE_TOKEN} + +# Build the cloud frontend using turbo (automatically builds all dependencies, with turbo cache) +RUN --mount=type=cache,id=s/6fcfa400-4a51-4df5-9345-2918f7aca8b7-/app/.turbo,target=/app/.turbo \ + npx turbo run build:cloud --filter=@rivetkit/engine-frontend + +# ============================================================================= +# Stage 2: Serve with Caddy +# ============================================================================= +FROM caddy:alpine + +# Install bash for entrypoint script +RUN apk add --no-cache bash + +# Copy Caddyfile configuration +COPY frontend/Caddyfile /etc/caddy/Caddyfile + +# Copy built files from builder stage +COPY --from=builder /app/frontend/dist /srv + +# Copy entrypoint script for runtime env var substitution +COPY frontend/docker-entrypoint.sh /docker-entrypoint.sh +RUN chmod +x /docker-entrypoint.sh + +# Default port (platform injects PORT env var) +ENV PORT=80 + +# Use custom entrypoint for env var substitution +ENTRYPOINT ["/docker-entrypoint.sh"] +CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile"] diff --git a/frontend/railway.cloud-staging.toml b/frontend/railway.cloud-staging.toml new file mode 100644 index 0000000000..5d484da79b --- /dev/null +++ b/frontend/railway.cloud-staging.toml @@ -0,0 +1,9 @@ +[build] +dockerfilePath = "frontend/cloud-staging.Dockerfile" +watchPatterns = ["/frontend/**", "/engine/sdks/typescript/**", "/rivetkit-typescript/**", "/pnpm-lock.yaml"] + +[deploy] +healthcheckPath = "/health" +restartPolicyType = "ON_FAILURE" +restartPolicyMaxRetries = 3 +internalPort = 80