From 373f7c47c043e654ccc77b688ae7eaf998d68083 Mon Sep 17 00:00:00 2001 From: ponzischeme89 Date: Wed, 29 Apr 2026 23:53:51 +1200 Subject: [PATCH] Deployment scripts --- .dockerignore | 24 + .env.alpha.example | 15 + README.md | 51 ++ backend/Dockerfile | 15 + .../data_entry_app_backend.egg-info/PKG-INFO | 2 +- backend/pyproject.toml | 2 +- deploy/nginx/clients.lean-101.conf | 101 +++ deploy/nginx/clients.lean-101.proxy.conf | 15 + docker-compose.alpha.yml | 61 ++ docker-compose.yml | 61 ++ frontend/Dockerfile | 23 + frontend/package-lock.json | 649 +++++++++++++++++- frontend/package.json | 3 +- frontend/src/lib/api.ts | 7 + .../src/lib/components/ClientShell.svelte | 28 +- frontend/src/routes/+page.svelte | 45 +- frontend/svelte.config.js | 3 +- 17 files changed, 1092 insertions(+), 13 deletions(-) create mode 100644 .dockerignore create mode 100644 .env.alpha.example create mode 100644 backend/Dockerfile create mode 100644 deploy/nginx/clients.lean-101.conf create mode 100644 deploy/nginx/clients.lean-101.proxy.conf create mode 100644 docker-compose.alpha.yml create mode 100644 docker-compose.yml create mode 100644 frontend/Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..9d142d6 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,24 @@ +.git +.gitignore +.svelte-kit +frontend/.svelte-kit +frontend/node_modules +frontend/build +backend/.pytest_cache +backend/.tmp +backend/pytest-cache-files-* +backend/data_entry_app_backend.egg-info +backend/__pycache__ +backend/app/__pycache__ +backend/tests/__pycache__ +*.pyc +*.pyo +*.pyd +*.log +*.sqlite +*.db +node_modules +npm-debug.log* +yarn-debug.log* +yarn-error.log* +dist diff --git a/.env.alpha.example b/.env.alpha.example new file mode 100644 index 0000000..0f130c0 --- /dev/null +++ b/.env.alpha.example @@ -0,0 +1,15 @@ +APP_NAME=Lean 101 Clients API +CLIENT_NAME=Hunter Premium Produce +CLIENT_EMAIL=operator@example.com +CLIENT_PASSWORD=changeme +CLIENT_TENANT_ID=hunter-premium-produce +ADMIN_NAME=Lean 101 +ADMIN_EMAIL=admin@lean101.local +ADMIN_PASSWORD=lean101-admin +AUTH_SECRET=replace-with-a-long-random-secret +ORIGIN=https://clients.lean-101.com +PUBLIC_API_BASE_URL=https://clients.lean-101.com +INTERNAL_API_BASE_URL=http://backend:8000 +CORS_ALLOW_ORIGINS=https://clients.lean-101.com +CLIENTS_APP_PORT=8081 +DATABASE_URL=sqlite:////data/data_entry_app.db diff --git a/README.md b/README.md index 75af02f..fb7e000 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,59 @@ Initial MVP implementation of the costing platform described in `CLAUDE.MD`. ```text backend/ FastAPI API, SQLAlchemy models, costing engine, seed data, tests frontend/ SvelteKit UI scaffold for dashboard and core modules +deploy/ nginx config and Docker deployment assets ``` +## Docker Alpha Deployment + +This repo now includes a production-oriented Docker setup for an alpha release: + +- `backend/Dockerfile` +- `frontend/Dockerfile` +- `docker-compose.yml` +- `docker-compose.alpha.yml` +- `deploy/nginx/clients.lean-101.conf` +- `deploy/nginx/clients.lean-101.proxy.conf` +- `.env.alpha.example` + +The compose stack runs three services: + +- `backend` on internal port `8000` +- `frontend` on internal port `3000` +- `nginx` on host port `8081` by default + +`nginx` routes: + +- `/api/*`, `/docs`, `/openapi.json`, `/health` to the FastAPI backend +- everything else to the Svelte frontend + +### Browser vs server API base URLs + +The frontend now supports: + +- `PUBLIC_API_BASE_URL` for browser requests +- `INTERNAL_API_BASE_URL` for server-side SvelteKit requests inside Docker + +This is important for a same-domain deployment such as `https://clients.lean-101.com`, where the browser should call the public domain while the frontend container should call the backend container directly. + +### Example `/srv` deploy + +```bash +mkdir -p /srv/lean101-clients +cd /srv/lean101-clients +git clone . +cp .env.alpha.example .env.alpha +docker compose --env-file .env.alpha up -d --build +``` + +This follows the same external pattern as your website container: + +- one compose project under `/srv/lean101-clients` +- one host-facing port, `8081`, for the app +- your existing public reverse proxy forwards `clients.lean-101.com` to `127.0.0.1:8081` + +If your server already has a host-level nginx handling domains and TLS, use `deploy/nginx/clients.lean-101.proxy.conf` as the upstream template and point the domain at `http://127.0.0.1:8081`. + ## Backend Create a virtual environment, install dependencies, then run: diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..0b37be4 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,15 @@ +FROM python:3.12-slim + +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 + +WORKDIR /app + +COPY backend /app + +RUN pip install --no-cache-dir --upgrade pip && \ + pip install --no-cache-dir . + +EXPOSE 8000 + +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/backend/data_entry_app_backend.egg-info/PKG-INFO b/backend/data_entry_app_backend.egg-info/PKG-INFO index 1cd9713..4f99b73 100644 --- a/backend/data_entry_app_backend.egg-info/PKG-INFO +++ b/backend/data_entry_app_backend.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: data-entry-app-backend -Version: 0.1.1 +Version: 0.1.2 Summary: Costing platform MVP backend Requires-Python: >=3.11 Requires-Dist: fastapi<1.0,>=0.115 diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 4b77900..36d1c32 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "data-entry-app-backend" -version = "0.1.1" +version = "0.1.2" description = "Costing platform MVP backend" requires-python = ">=3.11" dependencies = [ diff --git a/deploy/nginx/clients.lean-101.conf b/deploy/nginx/clients.lean-101.conf new file mode 100644 index 0000000..621b793 --- /dev/null +++ b/deploy/nginx/clients.lean-101.conf @@ -0,0 +1,101 @@ +upstream lean101_clients_frontend { + server frontend:3000; +} + +upstream lean101_clients_backend { + server backend:8000; +} + +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} + +server { + listen 80; + listen [::]:80; + server_name _; + + client_max_body_size 20m; + + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types text/plain text/css text/xml text/javascript application/javascript application/json application/xml image/svg+xml; + + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header X-XSS-Protection "1; mode=block" always; + + location /_app/immutable/ { + expires 1y; + add_header Cache-Control "public, immutable"; + proxy_pass http://lean101_clients_frontend; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location /assets/ { + expires 1y; + add_header Cache-Control "public, immutable"; + proxy_pass http://lean101_clients_frontend; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location /api/ { + proxy_pass http://lean101_clients_backend; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location /docs { + proxy_pass http://lean101_clients_backend; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location /openapi.json { + proxy_pass http://lean101_clients_backend; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location /health { + proxy_pass http://lean101_clients_backend; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location / { + proxy_pass http://lean101_clients_frontend; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + } + + server_tokens off; +} diff --git a/deploy/nginx/clients.lean-101.proxy.conf b/deploy/nginx/clients.lean-101.proxy.conf new file mode 100644 index 0000000..aa3e0e7 --- /dev/null +++ b/deploy/nginx/clients.lean-101.proxy.conf @@ -0,0 +1,15 @@ +server { + listen 80; + server_name clients.lean-101.com; + + location / { + proxy_pass http://127.0.0.1:8081; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } +} diff --git a/docker-compose.alpha.yml b/docker-compose.alpha.yml new file mode 100644 index 0000000..615f486 --- /dev/null +++ b/docker-compose.alpha.yml @@ -0,0 +1,61 @@ +services: + backend: + container_name: lean101-clients-backend + build: + context: . + dockerfile: backend/Dockerfile + restart: unless-stopped + environment: + APP_NAME: ${APP_NAME:-Lean 101 Clients API} + DATABASE_URL: ${DATABASE_URL:-sqlite:////data/data_entry_app.db} + CLIENT_NAME: ${CLIENT_NAME:-Hunter Premium Produce} + CLIENT_EMAIL: ${CLIENT_EMAIL:-operator@example.com} + CLIENT_PASSWORD: ${CLIENT_PASSWORD:-changeme} + CLIENT_TENANT_ID: ${CLIENT_TENANT_ID:-hunter-premium-produce} + ADMIN_NAME: ${ADMIN_NAME:-Lean 101} + ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@lean101.local} + ADMIN_PASSWORD: ${ADMIN_PASSWORD:-lean101-admin} + AUTH_SECRET: ${AUTH_SECRET:-change-me-in-production} + CORS_ALLOW_ORIGINS: ${CORS_ALLOW_ORIGINS:-https://clients.lean-101.com} + volumes: + - clients_app_data:/data + healthcheck: + test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health')"] + interval: 30s + timeout: 5s + retries: 5 + start_period: 20s + + frontend: + container_name: lean101-clients-frontend + build: + context: . + dockerfile: frontend/Dockerfile + restart: unless-stopped + environment: + ORIGIN: ${ORIGIN:-https://clients.lean-101.com} + PORT: 3000 + HOST: 0.0.0.0 + PUBLIC_API_BASE_URL: ${PUBLIC_API_BASE_URL:-https://clients.lean-101.com} + INTERNAL_API_BASE_URL: ${INTERNAL_API_BASE_URL:-http://backend:8000} + PUBLIC_API_PORT: ${PUBLIC_API_PORT:-8000} + depends_on: + backend: + condition: service_healthy + + nginx: + container_name: lean101-clients + image: nginx:1.27-alpine + restart: unless-stopped + depends_on: + frontend: + condition: service_started + backend: + condition: service_healthy + ports: + - "${CLIENTS_APP_PORT:-8081}:80" + volumes: + - ./deploy/nginx/clients.lean-101.conf:/etc/nginx/conf.d/default.conf:ro + +volumes: + clients_app_data: diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..615f486 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,61 @@ +services: + backend: + container_name: lean101-clients-backend + build: + context: . + dockerfile: backend/Dockerfile + restart: unless-stopped + environment: + APP_NAME: ${APP_NAME:-Lean 101 Clients API} + DATABASE_URL: ${DATABASE_URL:-sqlite:////data/data_entry_app.db} + CLIENT_NAME: ${CLIENT_NAME:-Hunter Premium Produce} + CLIENT_EMAIL: ${CLIENT_EMAIL:-operator@example.com} + CLIENT_PASSWORD: ${CLIENT_PASSWORD:-changeme} + CLIENT_TENANT_ID: ${CLIENT_TENANT_ID:-hunter-premium-produce} + ADMIN_NAME: ${ADMIN_NAME:-Lean 101} + ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@lean101.local} + ADMIN_PASSWORD: ${ADMIN_PASSWORD:-lean101-admin} + AUTH_SECRET: ${AUTH_SECRET:-change-me-in-production} + CORS_ALLOW_ORIGINS: ${CORS_ALLOW_ORIGINS:-https://clients.lean-101.com} + volumes: + - clients_app_data:/data + healthcheck: + test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health')"] + interval: 30s + timeout: 5s + retries: 5 + start_period: 20s + + frontend: + container_name: lean101-clients-frontend + build: + context: . + dockerfile: frontend/Dockerfile + restart: unless-stopped + environment: + ORIGIN: ${ORIGIN:-https://clients.lean-101.com} + PORT: 3000 + HOST: 0.0.0.0 + PUBLIC_API_BASE_URL: ${PUBLIC_API_BASE_URL:-https://clients.lean-101.com} + INTERNAL_API_BASE_URL: ${INTERNAL_API_BASE_URL:-http://backend:8000} + PUBLIC_API_PORT: ${PUBLIC_API_PORT:-8000} + depends_on: + backend: + condition: service_healthy + + nginx: + container_name: lean101-clients + image: nginx:1.27-alpine + restart: unless-stopped + depends_on: + frontend: + condition: service_started + backend: + condition: service_healthy + ports: + - "${CLIENTS_APP_PORT:-8081}:80" + volumes: + - ./deploy/nginx/clients.lean-101.conf:/etc/nginx/conf.d/default.conf:ro + +volumes: + clients_app_data: diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..af6ced8 --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,23 @@ +FROM node:20-bookworm-slim AS builder + +WORKDIR /app + +COPY frontend/package.json frontend/package-lock.json ./ +RUN npm ci + +COPY frontend ./ +RUN npm run build + +FROM node:20-bookworm-slim + +ENV NODE_ENV=production + +WORKDIR /app + +COPY --from=builder /app/build ./build +COPY --from=builder /app/package.json ./package.json +COPY --from=builder /app/node_modules ./node_modules + +EXPOSE 3000 + +CMD ["node", "build"] diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 7a266cd..ef4e4e2 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,14 +1,15 @@ { "name": "data-entry-app-frontend", - "version": "0.1.1", + "version": "0.1.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-entry-app-frontend", - "version": "0.1.1", + "version": "0.1.2", "devDependencies": { "@sveltejs/adapter-auto": "^3.2.0", + "@sveltejs/adapter-node": "^5.2.12", "@sveltejs/kit": "^2.7.1", "svelte": "^5.0.0", "typescript": "^5.5.4", @@ -400,6 +401,476 @@ "dev": true, "license": "MIT" }, + "node_modules/@rollup/plugin-commonjs": { + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-29.0.2.tgz", + "integrity": "sha512-S/ggWH1LU7jTyi9DxZOKyxpVd4hF/OZ0JrEbeLjXk/DFXwRny0tjD2c992zOUYQobLrVkRVMDdmHP16HKP7GRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "fdir": "^6.2.0", + "is-reference": "1.2.1", + "magic-string": "^0.30.3", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=16.0.0 || 14 >= 14.17" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/plugin-commonjs/node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@rollup/plugin-json": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", + "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.1.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz", + "integrity": "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.2.tgz", + "integrity": "sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.2.tgz", + "integrity": "sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.2.tgz", + "integrity": "sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.2.tgz", + "integrity": "sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.2.tgz", + "integrity": "sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.2.tgz", + "integrity": "sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.2.tgz", + "integrity": "sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.2.tgz", + "integrity": "sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.2.tgz", + "integrity": "sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.2.tgz", + "integrity": "sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.2.tgz", + "integrity": "sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.2.tgz", + "integrity": "sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.2.tgz", + "integrity": "sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.2.tgz", + "integrity": "sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.2.tgz", + "integrity": "sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.2.tgz", + "integrity": "sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.2.tgz", + "integrity": "sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.2.tgz", + "integrity": "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.2.tgz", + "integrity": "sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.2.tgz", + "integrity": "sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.2.tgz", + "integrity": "sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.2.tgz", + "integrity": "sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.2.tgz", + "integrity": "sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.2.tgz", + "integrity": "sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.2.tgz", + "integrity": "sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@standard-schema/spec": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", @@ -430,6 +901,22 @@ "@sveltejs/kit": "^2.0.0" } }, + "node_modules/@sveltejs/adapter-node": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-5.5.4.tgz", + "integrity": "sha512-45X92CXW+2J8ZUzPv3eLlKWEzINKiiGeFWTjyER4ZN4sGgNoaoeSkCY/QYNxHpPXy71QPsctwccBo9jJs0ySPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/plugin-commonjs": "^29.0.0", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-node-resolve": "^16.0.0", + "rollup": "^4.59.0" + }, + "peerDependencies": { + "@sveltejs/kit": "^2.4.0" + } + }, "node_modules/@sveltejs/kit": { "version": "2.58.0", "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.58.0.tgz", @@ -536,6 +1023,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/trusted-types": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", @@ -719,6 +1213,13 @@ "node": ">=6" } }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true, + "license": "MIT" + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -742,7 +1243,6 @@ "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -764,6 +1264,16 @@ "dev": true, "license": "MIT" }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-module-lexer": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", @@ -849,6 +1359,29 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/import-meta-resolve": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", @@ -860,6 +1393,29 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true, + "license": "MIT" + }, "node_modules/is-reference": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", @@ -1198,6 +1754,13 @@ ], "license": "MIT" }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, "node_modules/pathe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", @@ -1254,6 +1817,28 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/rolldown": { "version": "1.0.0-rc.17", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz", @@ -1288,6 +1873,51 @@ "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17" } }, + "node_modules/rollup": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.2.tgz", + "integrity": "sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.60.2", + "@rollup/rollup-android-arm64": "4.60.2", + "@rollup/rollup-darwin-arm64": "4.60.2", + "@rollup/rollup-darwin-x64": "4.60.2", + "@rollup/rollup-freebsd-arm64": "4.60.2", + "@rollup/rollup-freebsd-x64": "4.60.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.2", + "@rollup/rollup-linux-arm-musleabihf": "4.60.2", + "@rollup/rollup-linux-arm64-gnu": "4.60.2", + "@rollup/rollup-linux-arm64-musl": "4.60.2", + "@rollup/rollup-linux-loong64-gnu": "4.60.2", + "@rollup/rollup-linux-loong64-musl": "4.60.2", + "@rollup/rollup-linux-ppc64-gnu": "4.60.2", + "@rollup/rollup-linux-ppc64-musl": "4.60.2", + "@rollup/rollup-linux-riscv64-gnu": "4.60.2", + "@rollup/rollup-linux-riscv64-musl": "4.60.2", + "@rollup/rollup-linux-s390x-gnu": "4.60.2", + "@rollup/rollup-linux-x64-gnu": "4.60.2", + "@rollup/rollup-linux-x64-musl": "4.60.2", + "@rollup/rollup-openbsd-x64": "4.60.2", + "@rollup/rollup-openharmony-arm64": "4.60.2", + "@rollup/rollup-win32-arm64-msvc": "4.60.2", + "@rollup/rollup-win32-ia32-msvc": "4.60.2", + "@rollup/rollup-win32-x64-gnu": "4.60.2", + "@rollup/rollup-win32-x64-msvc": "4.60.2", + "fsevents": "~2.3.2" + } + }, "node_modules/set-cookie-parser": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.0.tgz", @@ -1341,6 +1971,19 @@ "dev": true, "license": "MIT" }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/svelte": { "version": "5.55.5", "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.55.5.tgz", diff --git a/frontend/package.json b/frontend/package.json index ab6dd53..19459f9 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "data-entry-app-frontend", - "version": "0.1.1", + "version": "0.1.2", "private": true, "type": "module", "scripts": { @@ -11,6 +11,7 @@ }, "devDependencies": { "@sveltejs/adapter-auto": "^3.2.0", + "@sveltejs/adapter-node": "^5.2.12", "@sveltejs/kit": "^2.7.1", "svelte": "^5.0.0", "typescript": "^5.5.4", diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index 0b0ce41..274ffee 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -42,6 +42,13 @@ type AuthMode = 'none' | 'client' | 'admin' | 'manager'; type ApiFetch = typeof fetch; function getApiBaseUrl() { + if (!browser) { + const internalBaseUrl = typeof process !== 'undefined' ? process.env.INTERNAL_API_BASE_URL?.trim() : ''; + if (internalBaseUrl) { + return internalBaseUrl.replace(/\/+$/, ''); + } + } + const configuredBaseUrl = env.PUBLIC_API_BASE_URL?.trim(); if (configuredBaseUrl) { return configuredBaseUrl.replace(/\/+$/, ''); diff --git a/frontend/src/lib/components/ClientShell.svelte b/frontend/src/lib/components/ClientShell.svelte index 809ea4f..ad57673 100644 --- a/frontend/src/lib/components/ClientShell.svelte +++ b/frontend/src/lib/components/ClientShell.svelte @@ -110,6 +110,7 @@ let restoredToken = $state(null); let paletteInput: HTMLInputElement | null = $state(null); const appVersion = `v${packageInfo.version}`; + const releaseStage = 'Alpha'; const currentYear = new Date().getFullYear(); const visibleDashboardItem = $derived( !$clientSession || !dashboardItem.moduleKey || hasModuleAccess($clientSession, dashboardItem.moduleKey) ? dashboardItem : null @@ -398,7 +399,10 @@ @@ -1074,6 +1078,28 @@ font-size: 0.74rem; } + .sidebar-version-row { + display: inline-flex; + align-items: center; + gap: 0.5rem; + flex-wrap: wrap; + } + + .release-pill { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.24rem 0.58rem; + border: 1px solid rgba(20, 130, 73, 0.16); + border-radius: 999px; + background: #eaf8ef; + color: #148249; + font-size: 0.68rem; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; + } + .main-shell { min-width: 0; display: flex; diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index e627586..06f285f 100644 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -34,6 +34,7 @@ let loginError = $state(''); const currentYear = new Date().getFullYear(); const appVersion = `v${packageInfo.version}`; + const releaseStage = 'Alpha'; const monthLabels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep']; @@ -287,7 +288,10 @@
- {appVersion} + + {appVersion} + {releaseStage} + © {currentYear} Hunter Premium Produce
@@ -304,7 +308,10 @@ Hunter Premium Produce - Secure Workspace Access +
+ Secure Workspace Access + {releaseStage} +
@@ -337,7 +344,10 @@
- {appVersion} + + {appVersion} + {releaseStage} + © {currentYear} Lean 101
@@ -346,7 +356,10 @@ {:else}
-

Client Workspace

+
+

Client Workspace

+ {releaseStage} +

Hunter Premium Produce costing overview.

Track input pricing, mix performance, and delivered product outcomes from one client-facing workspace.

@@ -766,6 +779,30 @@ justify-self: center; } + .auth-status-row, + .hero-label-row, + .version-badge { + display: inline-flex; + align-items: center; + gap: 0.55rem; + flex-wrap: wrap; + } + + .release-pill { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.28rem 0.62rem; + border: 1px solid rgba(20, 130, 73, 0.16); + border-radius: 999px; + background: #eaf8ef; + color: #148249; + font-size: 0.72rem; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; + } + .auth-copy { display: grid; gap: 0.55rem; diff --git a/frontend/svelte.config.js b/frontend/svelte.config.js index 69c2ea9..0e7712b 100644 --- a/frontend/svelte.config.js +++ b/frontend/svelte.config.js @@ -1,4 +1,4 @@ -import adapter from '@sveltejs/adapter-auto'; +import adapter from '@sveltejs/adapter-node'; /** @type {import('@sveltejs/kit').Config} */ const config = { @@ -8,4 +8,3 @@ const config = { }; export default config; -