chore(infra): vendored @bytelyst/* packages, Docker healthcheck, compose merge
- Switch @bytelyst/* to file:../vendor/* references; add vendor/ tree;
update both Dockerfile stages to COPY vendor/ before pnpm install
- docker-compose.yml: add healthcheck on backend /health/live; use
backend/.env as env_file; env-var-driven web build args with prod defaults;
GITEA_NPM_TOKEN uses ${:-} safe default; web depends_on service_healthy
- Add docker-compose.dev.yml hot-reload overlay
- Add scripts/dev.sh convenience script for Docker+local-web hybrid
- .npmrc: add replace-registry-host=always for Gitea Docker-internal rewrite
- Update smoke-release.sh and root package.json docker:* scripts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
4cfb446f57
commit
6c43fca934
55
docker-compose.dev.yml
Normal file
55
docker-compose.dev.yml
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# Development overlay — hot-reload for backend and web.
|
||||||
|
# Usage:
|
||||||
|
# docker compose -f docker-compose.yml -f docker-compose.dev.yml up
|
||||||
|
#
|
||||||
|
# Both services mount local source directories so edits are reflected immediately
|
||||||
|
# without rebuilding the image. Requires node_modules to exist locally
|
||||||
|
# (run `pnpm install` at repo root first).
|
||||||
|
|
||||||
|
version: '3.9'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Backend dev — tsx hot-reload
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
backend:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: backend/Dockerfile
|
||||||
|
target: builder # Stop at the build stage; no production image
|
||||||
|
command: >
|
||||||
|
sh -c "cd /app/backend && node --import tsx src/bootstrap.ts"
|
||||||
|
volumes:
|
||||||
|
- ./backend/src:/app/backend/src:ro
|
||||||
|
- ./shared:/app/shared:ro
|
||||||
|
- ./.env:/app/.env:ro
|
||||||
|
environment:
|
||||||
|
NODE_ENV: development
|
||||||
|
# Override healthcheck for faster feedback in dev
|
||||||
|
healthcheck:
|
||||||
|
interval: 10s
|
||||||
|
start_period: 5s
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Web dev — Vite dev server (HMR)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
web:
|
||||||
|
image: node:20-alpine
|
||||||
|
working_dir: /app/web
|
||||||
|
command: >
|
||||||
|
sh -c "corepack enable && pnpm run dev --host 0.0.0.0 --port 3048"
|
||||||
|
volumes:
|
||||||
|
- ./web:/app/web:ro
|
||||||
|
- ./shared:/app/shared:ro
|
||||||
|
- ./web/node_modules:/app/web/node_modules
|
||||||
|
- ./.env:/app/.env:ro
|
||||||
|
ports:
|
||||||
|
- '3048:3048'
|
||||||
|
environment:
|
||||||
|
NODE_ENV: development
|
||||||
|
VITE_PRODUCT_ID: ${VITE_PRODUCT_ID:-invttrdg}
|
||||||
|
VITE_PLATFORM_URL: ${VITE_PLATFORM_URL:-http://localhost:4003/api}
|
||||||
|
VITE_TRADING_API_URL: ${VITE_TRADING_API_URL:-http://localhost:4018}
|
||||||
|
VITE_BACKTEST_ENABLED: ${VITE_BACKTEST_ENABLED:-true}
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
13
mobile/.env.example
Normal file
13
mobile/.env.example
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# =============================================================================
|
||||||
|
# ByteLyst Trading — Mobile App Environment Configuration
|
||||||
|
# Copy this file to .env.local and fill in your values.
|
||||||
|
# EXPO_PUBLIC_ variables are embedded at build time — do not put secrets here.
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# --- Backend API ---
|
||||||
|
# URL of the deployed trading backend. Must not have a trailing slash.
|
||||||
|
EXPO_PUBLIC_TRADING_API_URL=http://localhost:4018/api
|
||||||
|
|
||||||
|
# --- Platform Service ---
|
||||||
|
# URL of the ByteLyst platform-service (auth, kill-switch, telemetry).
|
||||||
|
EXPO_PUBLIC_PLATFORM_URL=http://localhost:4003/api
|
||||||
113
scripts/dev.sh
Executable file
113
scripts/dev.sh
Executable file
@ -0,0 +1,113 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# dev.sh — Start Docker backend + local Vite web dev server
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./scripts/dev.sh # uses backend/.env for backend, web/.env.local for Vite
|
||||||
|
# REBUILD=1 ./scripts/dev.sh # force Docker rebuild before starting
|
||||||
|
#
|
||||||
|
# Requires:
|
||||||
|
# - Docker running
|
||||||
|
# - pnpm installed
|
||||||
|
# - backend/.env populated (copy from backend/.env.example)
|
||||||
|
# - web/.env.local populated (copy from web/.env.example)
|
||||||
|
#
|
||||||
|
# Ports:
|
||||||
|
# Backend → http://localhost:4018
|
||||||
|
# Web → http://localhost:5173 (Vite default)
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Colour helpers (skip if not a TTY)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
if [ -t 1 ]; then
|
||||||
|
BOLD='\033[1m'; CYAN='\033[0;36m'; GREEN='\033[0;32m'; YELLOW='\033[0;33m'; RESET='\033[0m'
|
||||||
|
else
|
||||||
|
BOLD=''; CYAN=''; GREEN=''; YELLOW=''; RESET=''
|
||||||
|
fi
|
||||||
|
|
||||||
|
log() { printf "${CYAN}[dev]${RESET} %s\n" "$*"; }
|
||||||
|
ok() { printf "${GREEN}[dev]${RESET} %s\n" "$*"; }
|
||||||
|
warn() { printf "${YELLOW}[dev]${RESET} %s\n" "$*"; }
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Pre-flight checks
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
if ! docker info >/dev/null 2>&1; then
|
||||||
|
printf "Error: Docker is not running.\n" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$ROOT/backend/.env" ]; then
|
||||||
|
warn "backend/.env not found — copy backend/.env.example and fill in credentials."
|
||||||
|
warn " cp backend/.env.example backend/.env"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$ROOT/web/.env.local" ]; then
|
||||||
|
warn "web/.env.local not found — creating from web/.env.example with defaults."
|
||||||
|
cp "$ROOT/web/.env.example" "$ROOT/web/.env.local"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Cleanup on exit — always stop the backend container
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
cleanup() {
|
||||||
|
log "Shutting down backend container..."
|
||||||
|
cd "$ROOT"
|
||||||
|
docker compose stop backend >/dev/null 2>&1 || true
|
||||||
|
}
|
||||||
|
trap cleanup INT TERM EXIT
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Start backend in Docker (backend service only, not web)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
cd "$ROOT"
|
||||||
|
|
||||||
|
BUILD_FLAG=""
|
||||||
|
if [ "${REBUILD:-}" = "1" ]; then
|
||||||
|
BUILD_FLAG="--build"
|
||||||
|
log "Rebuilding backend Docker image..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Starting backend container..."
|
||||||
|
# Run detached; logs are tailed below
|
||||||
|
docker compose up backend --detach $BUILD_FLAG
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Wait for backend health
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
log "Waiting for backend to become healthy..."
|
||||||
|
ATTEMPTS=0
|
||||||
|
MAX_ATTEMPTS=30
|
||||||
|
until docker compose exec -T backend wget -qO- http://localhost:4018/health/live >/dev/null 2>&1; do
|
||||||
|
ATTEMPTS=$((ATTEMPTS + 1))
|
||||||
|
if [ "$ATTEMPTS" -ge "$MAX_ATTEMPTS" ]; then
|
||||||
|
printf "Error: backend did not become healthy after %s attempts.\n" "$MAX_ATTEMPTS" >&2
|
||||||
|
docker compose logs --tail=40 backend >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
ok "Backend healthy at http://localhost:4018"
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Tail backend logs in background
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
docker compose logs --follow --tail=20 backend &
|
||||||
|
LOGS_PID=$!
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Start Vite web dev server (foreground — Ctrl+C stops everything via trap)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
log "Starting Vite web dev server..."
|
||||||
|
printf "\n${BOLD} Web → http://localhost:5173${RESET}\n"
|
||||||
|
printf "${BOLD} API → http://localhost:4018${RESET}\n\n"
|
||||||
|
|
||||||
|
cd "$ROOT/web"
|
||||||
|
pnpm dev
|
||||||
|
|
||||||
|
# Kill log tail if Vite exits cleanly
|
||||||
|
kill "$LOGS_PID" 2>/dev/null || true
|
||||||
23
vendor/bytelyst/api-client/package.json
vendored
Normal file
23
vendor/bytelyst/api-client/package.json
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"name": "@bytelyst/api-client",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"type": "module",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"test": "vitest run --pool forks"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://gitea.bytelyst.com/api/packages/ByteLyst/npm/"
|
||||||
|
}
|
||||||
|
}
|
||||||
30
vendor/bytelyst/auth/package.json
vendored
Normal file
30
vendor/bytelyst/auth/package.json
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "@bytelyst/auth",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"type": "module",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"test": "vitest run --pool forks"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@bytelyst/errors": "file:../errors"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"jose": ">=5.0.0",
|
||||||
|
"bcryptjs": ">=2.4.0"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://gitea.bytelyst.com/api/packages/ByteLyst/npm/"
|
||||||
|
}
|
||||||
|
}
|
||||||
48
vendor/bytelyst/config/package.json
vendored
Normal file
48
vendor/bytelyst/config/package.json
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"name": "@bytelyst/config",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"type": "module",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts"
|
||||||
|
},
|
||||||
|
"./keyvault": {
|
||||||
|
"import": "./dist/keyvault.js",
|
||||||
|
"types": "./dist/keyvault.d.ts"
|
||||||
|
},
|
||||||
|
"./product-identity": {
|
||||||
|
"import": "./dist/product-identity.js",
|
||||||
|
"types": "./dist/product-identity.d.ts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"test": "vitest run --pool forks"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@azure/identity": ">=4.0.0",
|
||||||
|
"@azure/keyvault-secrets": ">=4.8.0",
|
||||||
|
"zod": ">=3.20.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@azure/identity": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@azure/keyvault-secrets": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@azure/identity": "^4.13.0",
|
||||||
|
"@azure/keyvault-secrets": "^4.10.0"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://gitea.bytelyst.com/api/packages/ByteLyst/npm/"
|
||||||
|
}
|
||||||
|
}
|
||||||
26
vendor/bytelyst/cosmos/package.json
vendored
Normal file
26
vendor/bytelyst/cosmos/package.json
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"name": "@bytelyst/cosmos",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"type": "module",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"test": "vitest run --pool forks"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@azure/cosmos": ">=4.0.0"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://gitea.bytelyst.com/api/packages/ByteLyst/npm/"
|
||||||
|
}
|
||||||
|
}
|
||||||
23
vendor/bytelyst/errors/package.json
vendored
Normal file
23
vendor/bytelyst/errors/package.json
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"name": "@bytelyst/errors",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"type": "module",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"test": "vitest run --pool forks"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://gitea.bytelyst.com/api/packages/ByteLyst/npm/"
|
||||||
|
}
|
||||||
|
}
|
||||||
24
vendor/bytelyst/kill-switch-client/package.json
vendored
Normal file
24
vendor/bytelyst/kill-switch-client/package.json
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "@bytelyst/kill-switch-client",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"type": "module",
|
||||||
|
"description": "Browser/React Native-safe kill switch client for platform-service",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"test": "vitest run --pool forks"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://gitea.bytelyst.com/api/packages/ByteLyst/npm/"
|
||||||
|
}
|
||||||
|
}
|
||||||
30
vendor/bytelyst/llm/package.json
vendored
Normal file
30
vendor/bytelyst/llm/package.json
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "@bytelyst/llm",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"type": "module",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts"
|
||||||
|
},
|
||||||
|
"./testing": {
|
||||||
|
"import": "./dist/testing.js",
|
||||||
|
"types": "./dist/testing.d.ts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"test": "vitest run --pool forks"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"vitest": "^3.0.0"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://gitea.bytelyst.com/api/packages/ByteLyst/npm/"
|
||||||
|
}
|
||||||
|
}
|
||||||
37
vendor/bytelyst/react-auth/package.json
vendored
Normal file
37
vendor/bytelyst/react-auth/package.json
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"name": "@bytelyst/react-auth",
|
||||||
|
"version": "0.1.1",
|
||||||
|
"type": "module",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"test": "vitest run --pool forks"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@bytelyst/api-client": "file:../api-client"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@testing-library/react": "^16.3.2",
|
||||||
|
"@types/react": "^19.2.14",
|
||||||
|
"@types/react-dom": "^19.2.3",
|
||||||
|
"happy-dom": "^18.0.1",
|
||||||
|
"react": "^19.2.4",
|
||||||
|
"react-dom": "^19.2.4"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://gitea.bytelyst.com/api/packages/ByteLyst/npm/"
|
||||||
|
}
|
||||||
|
}
|
||||||
24
vendor/bytelyst/telemetry-client/package.json
vendored
Normal file
24
vendor/bytelyst/telemetry-client/package.json
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "@bytelyst/telemetry-client",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"type": "module",
|
||||||
|
"description": "Browser/React Native-safe telemetry client for platform-service",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"test": "vitest run --pool forks"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://gitea.bytelyst.com/api/packages/ByteLyst/npm/"
|
||||||
|
}
|
||||||
|
}
|
||||||
23
web/nginx.conf
Normal file
23
web/nginx.conf
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
server {
|
||||||
|
listen 3048;
|
||||||
|
server_name _;
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
# Gzip static assets
|
||||||
|
gzip on;
|
||||||
|
gzip_types text/plain text/css application/javascript application/json image/svg+xml;
|
||||||
|
gzip_min_length 1024;
|
||||||
|
|
||||||
|
# Long-lived cache for hashed assets; no-cache for entry points
|
||||||
|
location ~* \.(js|css|woff2?|png|jpg|svg|ico)$ {
|
||||||
|
add_header Cache-Control "public, max-age=31536000, immutable";
|
||||||
|
try_files $uri =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
# SPA fallback — all routes serve index.html
|
||||||
|
location / {
|
||||||
|
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user