30 Commits

Author SHA1 Message Date
a31202f63b refactor: use explicit Git reference variables for more robust deployment target and image tag determination in Gitea workflow.
All checks were successful
Build & Deploy / 🔍 Prepare Environment (push) Successful in 5s
Build & Deploy / 🧪 QA (push) Successful in 1m33s
Build & Deploy / 🏗️ Build (push) Successful in 2m7s
Build & Deploy / 🚀 Deploy (push) Successful in 9s
Build & Deploy / 🔔 Notifications (push) Successful in 2s
2026-02-06 22:51:40 +01:00
0afd6bbb60 fix: logo position
All checks were successful
Build & Deploy / 🔍 Prepare Environment (push) Successful in 7s
Build & Deploy / 🧪 QA (push) Successful in 1m32s
Build & Deploy / 🏗️ Build (push) Successful in 4m44s
Build & Deploy / 🚀 Deploy (push) Successful in 13s
Build & Deploy / 🔔 Notifications (push) Successful in 2s
2026-02-06 21:42:43 +01:00
2c647f0284 chore: directus sync
All checks were successful
Build & Deploy / 🔍 Prepare Environment (push) Successful in 4s
Build & Deploy / 🧪 QA (push) Successful in 1m57s
Build & Deploy / 🏗️ Build (push) Successful in 2m3s
Build & Deploy / 🚀 Deploy (push) Successful in 33s
Build & Deploy / 🔔 Notifications (push) Successful in 2s
2026-02-06 21:35:00 +01:00
d9ff6d640d feat: Configure Traefik to use the infra network for services, add an internal Directus URL, and enhance Directus and Gatekeeper configurations.
All checks were successful
Build & Deploy / 🔍 Prepare Environment (push) Successful in 9s
Build & Deploy / 🧪 QA (push) Successful in 1m13s
Build & Deploy / 🏗️ Build (push) Successful in 4m51s
Build & Deploy / 🚀 Deploy (push) Successful in 10s
Build & Deploy / 🔔 Notifications (push) Successful in 1s
2026-02-06 19:23:35 +01:00
8ab9ec7d1f chore: bootstrap command 2026-02-06 19:11:19 +01:00
0cc67d54ef refactor: overhaul Directus sync script with schema wiping and restart, update branding, and rename CMS scripts. 2026-02-06 19:09:56 +01:00
cbb95a38cf feat: Introduce COOKIE_DOMAIN and NEXT_PUBLIC_BASE_URL environment variables for gatekeeper service configuration.
All checks were successful
Build & Deploy / 🔍 Prepare Environment (push) Successful in 9s
Build & Deploy / 🧪 QA (push) Successful in 1m17s
Build & Deploy / 🏗️ Build (push) Successful in 5m1s
Build & Deploy / 🚀 Deploy (push) Successful in 10s
Build & Deploy / 🔔 Notifications (push) Successful in 2s
2026-02-06 18:05:04 +01:00
5b163d6d74 feat: Enable dynamic app environment variable configuration via workflow and docker-compose.
All checks were successful
Build & Deploy / 🔍 Prepare Environment (push) Successful in 9s
Build & Deploy / 🧪 QA (push) Successful in 1m27s
Build & Deploy / 🏗️ Build (push) Successful in 2m6s
Build & Deploy / 🚀 Deploy (push) Successful in 23s
Build & Deploy / 🔔 Notifications (push) Successful in 2s
2026-02-06 17:26:28 +01:00
f6e774b5c9 feat: Add GATEKEEPER_PASSWORD environment variable for authentication.
All checks were successful
Build & Deploy / 🔍 Prepare Environment (push) Successful in 4s
Build & Deploy / 🧪 QA (push) Successful in 1m13s
Build & Deploy / 🏗️ Build (push) Successful in 5m2s
Build & Deploy / 🚀 Deploy (push) Successful in 12s
Build & Deploy / 🔔 Notifications (push) Successful in 2s
2026-02-06 17:07:25 +01:00
613c8b1645 fix: Streamline variable interpolation in deploy workflow and Traefik labels by removing unnecessary quoting and default fallbacks.
All checks were successful
Build & Deploy / 🔍 Prepare Environment (push) Successful in 4s
Build & Deploy / 🧪 QA (push) Successful in 1m14s
Build & Deploy / 🏗️ Build (push) Successful in 2m5s
Build & Deploy / 🚀 Deploy (push) Successful in 28s
Build & Deploy / 🔔 Notifications (push) Successful in 1s
2026-02-06 16:32:21 +01:00
9e1aae5d76 feat: Add dedicated subdomain routing for Gatekeeper and update its service alias for forward authentication middleware.
All checks were successful
Build & Deploy / 🔍 Prepare Environment (push) Successful in 5s
Build & Deploy / 🧪 QA (push) Successful in 1m14s
Build & Deploy / 🏗️ Build (push) Successful in 4m34s
Build & Deploy / 🚀 Deploy (push) Successful in 15s
Build & Deploy / 🔔 Notifications (push) Successful in 1s
2026-02-06 16:11:39 +01:00
f1e3ad1357 chore: npm update
All checks were successful
Build & Deploy / 🔍 Prepare Environment (push) Successful in 7s
Build & Deploy / 🧪 QA (push) Successful in 1m12s
Build & Deploy / 🏗️ Build (push) Successful in 4m41s
Build & Deploy / 🚀 Deploy (push) Successful in 15s
Build & Deploy / 🔔 Notifications (push) Successful in 2s
2026-02-06 15:52:49 +01:00
39b044c2c2 chore: Use caret version specifiers for Mintel dependencies.
Some checks failed
Build & Deploy / 🔍 Prepare Environment (push) Successful in 7s
Build & Deploy / 🧪 QA (push) Failing after 10s
Build & Deploy / 🏗️ Build (push) Successful in 5m32s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🔔 Notifications (push) Successful in 2s
2026-02-06 15:28:07 +01:00
c0c73315c8 chore(deploy): switch main branch to testing domain and add staging tag logic (aligned with klz-2026)
All checks were successful
Build & Deploy / 🔍 Prepare Environment (push) Successful in 5s
Build & Deploy / 🧪 QA (push) Successful in 1m29s
Build & Deploy / 🏗️ Build (push) Successful in 4m45s
Build & Deploy / 🚀 Deploy (push) Successful in 20s
Build & Deploy / 🔔 Notifications (push) Successful in 1s
2026-02-05 22:16:27 +01:00
72fbae0666 fix(deploy): remove redundant backticks from Traefik Host labels to fix double-quoting
All checks were successful
Build & Deploy / 🔍 Prepare Environment (push) Successful in 5s
Build & Deploy / 🧪 QA (push) Successful in 1m34s
Build & Deploy / 🏗️ Build (push) Successful in 2m6s
Build & Deploy / 🚀 Deploy (push) Successful in 14s
Build & Deploy / 🔔 Notifications (push) Successful in 2s
2026-02-05 22:10:04 +01:00
3ed32210ad fix(ci): quote .env heredoc and fix docker-compose extension
All checks were successful
Build & Deploy / 🔍 Prepare Environment (push) Successful in 4s
Build & Deploy / 🧪 QA (push) Successful in 1m56s
Build & Deploy / 🏗️ Build (push) Successful in 2m5s
Build & Deploy / 🚀 Deploy (push) Successful in 16s
Build & Deploy / 🔔 Notifications (push) Successful in 1s
2026-02-05 19:23:46 +01:00
f2366b5a38 fix(ci): refactor SSH deployment to manual ssh/scp (aligned with klz-2026)
Some checks failed
Build & Deploy / 🔍 Prepare Environment (push) Successful in 5s
Build & Deploy / 🧪 QA (push) Successful in 1m13s
Build & Deploy / 🏗️ Build (push) Successful in 4m47s
Build & Deploy / 🚀 Deploy (push) Failing after 6s
Build & Deploy / 🔔 Notifications (push) Successful in 2s
2026-02-05 14:19:57 +01:00
dccf6ad2ce fix(ci): pass NEXT_PUBLIC_TARGET to docker build and suppress sentry warnings
Some checks failed
Build & Deploy / 🔍 Prepare Environment (push) Successful in 4s
Build & Deploy / 🧪 QA (push) Successful in 1m12s
Build & Deploy / 🏗️ Build (push) Successful in 4m38s
Build & Deploy / 🚀 Deploy (push) Failing after 3s
Build & Deploy / 🔔 Notifications (push) Successful in 1s
2026-02-05 13:00:21 +01:00
788c9ca7ac fix(ci): restore Next 16 and isolate Docker build from base image workspace
Some checks failed
Build & Deploy / 🔍 Prepare Environment (push) Successful in 7s
Build & Deploy / 🧪 QA (push) Successful in 1m30s
Build & Deploy / 🏗️ Build (push) Failing after 1m58s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🔔 Notifications (push) Successful in 2s
2026-02-05 12:53:18 +01:00
34474de163 chore: delete pnpm-workspace.yaml.
Some checks failed
Build & Deploy / 🔍 Prepare Environment (push) Successful in 5s
Build & Deploy / 🧪 QA (push) Successful in 1m59s
Build & Deploy / 🏗️ Build (push) Failing after 2m42s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🔔 Notifications (push) Successful in 1s
2026-02-05 12:04:31 +01:00
12646e45e4 fix(ci): regenerate lockfile and relax frozen-lockfile for Docker 2026-02-05 12:03:46 +01:00
b25299a3a8 chore: Remove /dev from Next.js routes types import path in next-env.d.ts.
Some checks failed
Build & Deploy / 🔍 Prepare Environment (push) Successful in 8s
Build & Deploy / 🏗️ Build (push) Failing after 53s
Build & Deploy / 🧪 QA (push) Successful in 1m12s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🔔 Notifications (push) Successful in 2s
2026-02-05 11:58:26 +01:00
aa9b280f5c fix(ci): fix docker build by adding pnpm install in Dockerfile
Some checks failed
Build & Deploy / 🔍 Prepare Environment (push) Successful in 8s
Build & Deploy / 🏗️ Build (push) Failing after 39s
Build & Deploy / 🧪 QA (push) Successful in 1m30s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🔔 Notifications (push) Successful in 1s
2026-02-05 11:53:29 +01:00
2ec9a29565 fix(ci): align registry secret names with Mintel standard (USER/PASS)
Some checks failed
Build & Deploy / 🔍 Prepare Environment (push) Successful in 4s
Build & Deploy / 🏗️ Build (push) Failing after 42s
Build & Deploy / 🧪 QA (push) Successful in 1m30s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🔔 Notifications (push) Successful in 2s
2026-02-05 11:50:56 +01:00
20cafce97d fix(ci): fix eslint compatibility, downgrade to v8, and fix lint errors
Some checks failed
Build & Deploy / 🔍 Prepare Environment (push) Successful in 8s
Build & Deploy / 🏗️ Build (push) Failing after 12s
Build & Deploy / 🧪 QA (push) Successful in 1m13s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🔔 Notifications (push) Successful in 2s
2026-02-05 11:15:41 +01:00
31f931f7ce fix(ci): use eslint directly and fix lint step environment
Some checks failed
Build & Deploy / 🔍 Prepare Environment (push) Successful in 4s
Build & Deploy / 🏗️ Build (push) Failing after 9s
Build & Deploy / 🧪 QA (push) Failing after 43s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🔔 Notifications (push) Successful in 2s
2026-02-05 11:10:43 +01:00
e415b5118b fix(ci): use corepack enable for pnpm to avoid hang in runner
Some checks failed
Build & Deploy / 🔍 Prepare Environment (push) Successful in 4s
Build & Deploy / 🏗️ Build (push) Failing after 10s
Build & Deploy / 🧪 QA (push) Failing after 33s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🔔 Notifications (push) Successful in 1s
2026-02-05 11:08:34 +01:00
84aef6b860 fix(ci): use linux/arm64 platform to match infra
Some checks failed
Build & Deploy / 🔍 Prepare Environment (push) Successful in 4s
Build & Deploy / 🧪 QA (push) Failing after 6s
Build & Deploy / 🏗️ Build (push) Failing after 15s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🔔 Notifications (push) Successful in 2s
2026-02-05 10:57:04 +01:00
195932dde4 fix(ci): explicitly use shell: bash for all steps 2026-02-05 10:56:56 +01:00
977773fe94 fix(ci): add debug info and make maintenance optional 2026-02-05 10:56:42 +01:00
15 changed files with 614 additions and 405 deletions

3
.eslintrc.json Normal file
View File

@@ -0,0 +1,3 @@
{
"extends": ["next/core-web-vitals", "next/typescript"]
}

View File

@@ -28,10 +28,19 @@ jobs:
directus_host: ${{ steps.determine.outputs.directus_host }}
project_name: ${{ steps.determine.outputs.project_name }}
steps:
- name: 🧹 Maintenance (Runner Cleanup)
- name: 🔍 Debug Info
shell: bash
run: |
docker image prune -f
docker builder prune -f --filter "until=24h"
echo "ref_name: ${{ github.ref_name }}"
echo "ref_type: ${{ github.ref_type }}"
echo "tag: ${{ github.ref_name }}"
- name: 🧹 Maintenance (Runner Cleanup)
continue-on-error: true
shell: bash
run: |
docker image prune -f || true
docker builder prune -f --filter "until=24h" || true
- name: Checkout repository
uses: actions/checkout@v4
@@ -40,32 +49,63 @@ jobs:
- name: 🔍 Determine Environment
id: determine
shell: bash
run: |
TAG="${{ github.ref_name }}"
REF="${{ github.ref }}"
REF_NAME="${{ github.ref_name }}"
REF_TYPE="${{ github.ref_type }}"
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
DOMAIN_BASE="mb-grid-solutions.com"
PRJ_ID="mb-grid-solutions"
if [[ "${{ github.ref_type }}" == "branch" && "$TAG" == "main" ]]; then
TARGET="staging"
IMAGE_TAG="staging-${SHORT_SHA}"
ENV_FILE=".env.staging"
TRAEFIK_HOST="\`staging.${DOMAIN_BASE}\`"
NEXT_PUBLIC_BASE_URL="https://staging.${DOMAIN_BASE}"
DIRECTUS_URL="https://cms.staging.${DOMAIN_BASE}"
DIRECTUS_HOST="\`cms.staging.${DOMAIN_BASE}\`"
elif [[ "${{ github.ref_type }}" == "tag" ]]; then
TARGET="production"
IMAGE_TAG="$TAG"
ENV_FILE=".env.prod"
TRAEFIK_HOST="\`${DOMAIN_BASE}\`, \`www.${DOMAIN_BASE}\`"
NEXT_PUBLIC_BASE_URL="https://${DOMAIN_BASE}"
DIRECTUS_URL="https://cms.${DOMAIN_BASE}"
DIRECTUS_HOST="\`cms.${DOMAIN_BASE}\`"
else
TARGET="skip"
echo "Detecting environment for ref: $REF ($REF_NAME, type: $REF_TYPE)"
# Fallback for REF_TYPE if missing
if [[ -z "$REF_TYPE" ]]; then
if [[ "$REF" == refs/tags/* ]]; then
REF_TYPE="tag"
elif [[ "$REF" == refs/heads/* ]]; then
REF_TYPE="branch"
fi
fi
if [[ "$REF_TYPE" == "branch" && "$REF_NAME" == "main" ]]; then
TARGET="testing"
IMAGE_TAG="testing-${SHORT_SHA}"
ENV_FILE=".env.testing"
TRAEFIK_HOST="testing.${DOMAIN_BASE}"
NEXT_PUBLIC_BASE_URL="https://testing.${DOMAIN_BASE}"
DIRECTUS_URL="https://cms.testing.${DOMAIN_BASE}"
DIRECTUS_HOST="cms.testing.${DOMAIN_BASE}"
elif [[ "$REF_TYPE" == "tag" ]]; then
if [[ "$REF_NAME" =~ ^v[0-9]+\.[0-9]+(\.[0-9]+)?$ ]]; then
TARGET="production"
IMAGE_TAG="$REF_NAME"
ENV_FILE=".env.prod"
TRAEFIK_HOST="${DOMAIN_BASE}, www.${DOMAIN_BASE}"
NEXT_PUBLIC_BASE_URL="https://${DOMAIN_BASE}"
DIRECTUS_URL="https://cms.${DOMAIN_BASE}"
DIRECTUS_HOST="cms.${DOMAIN_BASE}"
elif [[ "$REF_NAME" =~ -rc || "$REF_NAME" =~ -beta || "$REF_NAME" =~ -alpha ]]; then
TARGET="staging"
IMAGE_TAG="$REF_NAME"
ENV_FILE=".env.staging"
TRAEFIK_HOST="staging.${DOMAIN_BASE}"
NEXT_PUBLIC_BASE_URL="https://staging.${DOMAIN_BASE}"
DIRECTUS_URL="https://cms.staging.${DOMAIN_BASE}"
DIRECTUS_HOST="cms.staging.${DOMAIN_BASE}"
else
TARGET="skip"
echo "Tag $REF_NAME did not match any environment pattern."
fi
else
TARGET="skip"
echo "Ref type $REF_TYPE is not handled for deployment."
fi
echo "Target determined: $TARGET"
echo "Image tag: $IMAGE_TAG"
echo "target=$TARGET" >> "$GITHUB_OUTPUT"
echo "image_tag=$IMAGE_TAG" >> "$GITHUB_OUTPUT"
echo "env_file=$ENV_FILE" >> "$GITHUB_OUTPUT"
@@ -85,16 +125,25 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
- name: Install dependencies
shell: bash
run: |
corepack enable
pnpm install --frozen-lockfile
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- run: pnpm lint
- run: pnpm build
- name: 🧪 Lint
shell: bash
run: pnpm lint
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: 🏗️ Build Test
shell: bash
run: pnpm build
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NEXT_PUBLIC_BASE_URL: https://dummy.test
@@ -114,15 +163,17 @@ jobs:
uses: docker/setup-buildx-action@v3
- name: 🔐 Registry Login
run: echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login registry.infra.mintel.me -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
run: echo "${{ secrets.REGISTRY_PASS }}" | docker login registry.infra.mintel.me -u "${{ secrets.REGISTRY_USER }}" --password-stdin
- name: 🏗️ Build and Push
shell: bash
run: |
docker buildx build \
--pull \
--platform linux/amd64,linux/arm64 \
--platform linux/arm64 \
--build-arg NPM_TOKEN=${{ secrets.NPM_TOKEN }} \
--build-arg NEXT_PUBLIC_BASE_URL=${{ needs.prepare.outputs.next_public_base_url }} \
--build-arg NEXT_PUBLIC_TARGET=${{ needs.prepare.outputs.target }} \
--build-arg DIRECTUS_URL=${{ needs.prepare.outputs.directus_url }} \
-t registry.infra.mintel.me/mintel/mb-grid-solutions:${{ needs.prepare.outputs.image_tag }} \
--push .
@@ -135,42 +186,83 @@ jobs:
container:
image: catthehacker/ubuntu:act-latest
steps:
- name: 🚀 Deploy via SSH
uses: appleboy/ssh-action@master
- name: Checkout repository
uses: actions/checkout@v4
with:
host: ${{ secrets.SSH_HOST }}
username: root
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
fetch-depth: 1
- name: 🚀 Deploy via SSH
shell: bash
run: |
echo "Deploying to alpha.mintel.me"
mkdir -p ~/.ssh
echo "${{ secrets.ALPHA_SSH_KEY }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan -H alpha.mintel.me >> ~/.ssh/known_hosts 2>/dev/null
# Generate Environment File
cat > .env.deploy << 'EOF'
ENV_FILE=${{ needs.prepare.outputs.env_file }}
IMAGE_TAG=${{ needs.prepare.outputs.image_tag }}
TRAEFIK_HOST=${{ needs.prepare.outputs.traefik_host }}
PROJECT_NAME=${{ needs.prepare.outputs.project_name }}
NEXT_PUBLIC_BASE_URL=${{ needs.prepare.outputs.next_public_base_url }}
# Directus
DIRECTUS_URL=${{ needs.prepare.outputs.directus_url }}
DIRECTUS_HOST=${{ needs.prepare.outputs.directus_host }}
INTERNAL_DIRECTUS_URL=http://directus:8055
DIRECTUS_API_TOKEN=${{ secrets.DIRECTUS_API_TOKEN || vars.DIRECTUS_API_TOKEN }}
DIRECTUS_ADMIN_EMAIL=${{ secrets.DIRECTUS_ADMIN_EMAIL || vars.DIRECTUS_ADMIN_EMAIL || 'admin@mintel.me' }}
DIRECTUS_ADMIN_PASSWORD=${{ secrets.DIRECTUS_ADMIN_PASSWORD || vars.DIRECTUS_ADMIN_PASSWORD }}
DIRECTUS_DB_NAME=${{ secrets.DIRECTUS_DB_NAME || vars.DIRECTUS_DB_NAME || 'directus' }}
DIRECTUS_DB_USER=${{ secrets.DIRECTUS_DB_USER || vars.DIRECTUS_DB_USER || 'directus' }}
DIRECTUS_DB_PASSWORD=${{ secrets.DIRECTUS_DB_PASSWORD || vars.DIRECTUS_DB_PASSWORD }}
DIRECTUS_KEY=${{ secrets.DIRECTUS_KEY || vars.DIRECTUS_KEY }}
DIRECTUS_SECRET=${{ secrets.DIRECTUS_SECRET || vars.DIRECTUS_SECRET }}
# SMTP Config
SMTP_HOST=${{ secrets.SMTP_HOST || vars.SMTP_HOST }}
SMTP_PORT=${{ secrets.SMTP_PORT || vars.SMTP_PORT || '587' }}
SMTP_SECURE=${{ secrets.SMTP_SECURE || vars.SMTP_SECURE || 'false' }}
SMTP_USER=${{ secrets.SMTP_USER || vars.SMTP_USER }}
SMTP_PASS=${{ secrets.SMTP_PASS || vars.SMTP_PASS }}
SMTP_FROM=${{ secrets.SMTP_FROM || vars.SMTP_FROM }}
CONTACT_RECIPIENT=${{ secrets.CONTACT_RECIPIENT || vars.CONTACT_RECIPIENT }}
# Authentication
GATEKEEPER_PASSWORD=${{ secrets.GATEKEEPER_PASSWORD || vars.GATEKEEPER_PASSWORD }}
AUTH_COOKIE_NAME=${{ secrets.AUTH_COOKIE_NAME || vars.AUTH_COOKIE_NAME || 'mintel_gatekeeper_session' }}
COOKIE_DOMAIN=${{ secrets.COOKIE_DOMAIN || vars.COOKIE_DOMAIN || '.mb-grid-solutions.com' }}
# External Services
SENTRY_DSN=${{ secrets.SENTRY_DSN || vars.SENTRY_DSN }}
GOTIFY_URL=${{ secrets.GOTIFY_URL || vars.GOTIFY_URL }}
GOTIFY_TOKEN=${{ secrets.GOTIFY_TOKEN || vars.GOTIFY_TOKEN }}
NEXT_PUBLIC_UMAMI_WEBSITE_ID=${{ secrets.NEXT_PUBLIC_UMAMI_WEBSITE_ID || vars.NEXT_PUBLIC_UMAMI_WEBSITE_ID }}
NEXT_PUBLIC_UMAMI_SCRIPT_URL=${{ secrets.NEXT_PUBLIC_UMAMI_SCRIPT_URL || vars.NEXT_PUBLIC_UMAMI_SCRIPT_URL }}
# Project
PROJECT_COLOR=${{ secrets.PROJECT_COLOR || vars.PROJECT_COLOR || '#82ed20' }}
EOF
APP_DIR="/home/deploy/sites/mb-grid-solutions.com"
ssh -o StrictHostKeyChecking=accept-new root@alpha.mintel.me "mkdir -p $APP_DIR"
scp -o StrictHostKeyChecking=accept-new .env.deploy root@alpha.mintel.me:$APP_DIR/${{ needs.prepare.outputs.env_file }}
scp -o StrictHostKeyChecking=accept-new docker-compose.yaml root@alpha.mintel.me:$APP_DIR/docker-compose.yaml
ssh -o StrictHostKeyChecking=accept-new root@alpha.mintel.me bash << 'EOF'
set -e
APP_DIR="/home/deploy/sites/mb-grid-solutions.com"
mkdir -p $APP_DIR
cd $APP_DIR
# Update Environment
cat > ${{ needs.prepare.outputs.env_file }} << EOF
IMAGE_TAG=${{ needs.prepare.outputs.image_tag }}
TRAEFIK_HOST=${{ needs.prepare.outputs.traefik_host }}
PROJECT_NAME=${{ needs.prepare.outputs.project_name }}
NEXT_PUBLIC_BASE_URL=${{ needs.prepare.outputs.next_public_base_url }}
# Directus
DIRECTUS_URL=${{ needs.prepare.outputs.directus_url }}
DIRECTUS_HOST=${{ needs.prepare.outputs.directus_host }}
DIRECTUS_API_TOKEN=${{ secrets.DIRECTUS_API_TOKEN }}
DIRECTUS_ADMIN_EMAIL=${{ secrets.DIRECTUS_ADMIN_EMAIL || 'admin@mintel.me' }}
DIRECTUS_ADMIN_PASSWORD=${{ secrets.DIRECTUS_ADMIN_PASSWORD }}
DIRECTUS_DB_NAME=${{ secrets.DIRECTUS_DB_NAME || 'directus' }}
DIRECTUS_DB_USER=${{ secrets.DIRECTUS_DB_USER || 'directus' }}
DIRECTUS_DB_PASSWORD=${{ secrets.DIRECTUS_DB_PASSWORD }}
DIRECTUS_KEY=${{ secrets.DIRECTUS_KEY }}
DIRECTUS_SECRET=${{ secrets.DIRECTUS_SECRET }}
EOF
# Sync docker-compose
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login registry.infra.mintel.me -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
echo "${{ secrets.REGISTRY_PASS }}" | docker login registry.infra.mintel.me -u "${{ secrets.REGISTRY_USER }}" --password-stdin
docker compose -p "${{ needs.prepare.outputs.project_name }}" --env-file ${{ needs.prepare.outputs.env_file }} pull
docker compose -p "${{ needs.prepare.outputs.project_name }}" --env-file ${{ needs.prepare.outputs.env_file }} up -d --remove-orphans
docker system prune -f --filter "until=24h"
EOF
notifications:
name: 🔔 Notifications
@@ -181,6 +273,7 @@ jobs:
image: catthehacker/ubuntu:act-latest
steps:
- name: Notify Gotify
shell: bash
run: |
STATUS="${{ needs.deploy.result }}"
COLOR="info"

View File

@@ -3,18 +3,33 @@ FROM registry.infra.mintel.me/mintel/nextjs:latest AS builder
WORKDIR /app
# Ensure we are in a clean, standalone environment
RUN rm -rf packages apps pnpm-workspace.yaml 2>/dev/null || true
# Build-time environment variables for Next.js
ARG NEXT_PUBLIC_BASE_URL
ARG NEXT_PUBLIC_UMAMI_WEBSITE_ID
ARG NEXT_PUBLIC_UMAMI_SCRIPT_URL
ARG NEXT_PUBLIC_TARGET
ARG DIRECTUS_URL
ARG NPM_TOKEN
ENV NEXT_PUBLIC_BASE_URL=$NEXT_PUBLIC_BASE_URL
ENV NEXT_PUBLIC_UMAMI_WEBSITE_ID=$NEXT_PUBLIC_UMAMI_WEBSITE_ID
ENV NEXT_PUBLIC_UMAMI_SCRIPT_URL=$NEXT_PUBLIC_UMAMI_SCRIPT_URL
ENV NEXT_PUBLIC_TARGET=$NEXT_PUBLIC_TARGET
ENV DIRECTUS_URL=$DIRECTUS_URL
ENV NPM_TOKEN=$NPM_TOKEN
ENV SENTRY_SUPPRESS_TURBOPACK_WARNING=1
# Enable corepack
RUN corepack enable
# Copy package files
COPY package.json pnpm-lock.yaml* .npmrc ./
# Install dependencies
RUN pnpm install --no-frozen-lockfile
# Copy local files
COPY . .

View File

@@ -143,25 +143,27 @@ export default function About() {
</Reveal>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
{t.raw("manifest.items").map((item: any, i: number) => {
const Icon = manifestIcons[i];
return (
<Reveal key={i} delay={i * 0.1}>
<div className="bg-white/5 p-10 rounded-3xl border border-white/10 group hover:-translate-y-1 transition-[box-shadow,transform] duration-300 h-full motion-fix relative overflow-hidden">
<div className="absolute top-0 left-0 w-full h-1 bg-accent/0 group-hover:bg-accent/50 transition-all duration-500" />
<div className="text-accent mb-6">
<Icon size={32} />
{t
.raw("manifest.items")
.map((item: { title: string; desc: string }, i: number) => {
const Icon = manifestIcons[i];
return (
<Reveal key={i} delay={i * 0.1}>
<div className="bg-white/5 p-10 rounded-3xl border border-white/10 group hover:-translate-y-1 transition-[box-shadow,transform] duration-300 h-full motion-fix relative overflow-hidden">
<div className="absolute top-0 left-0 w-full h-1 bg-accent/0 group-hover:bg-accent/50 transition-all duration-500" />
<div className="text-accent mb-6">
<Icon size={32} />
</div>
<h4 className="text-xl font-bold text-white mb-4">
{i + 1}. {item.title}
</h4>
<p className="text-slate-400 leading-relaxed">
{item.desc}
</p>
</div>
<h4 className="text-xl font-bold text-white mb-4">
{i + 1}. {item.title}
</h4>
<p className="text-slate-400 leading-relaxed">
{item.desc}
</p>
</div>
</Reveal>
);
})}
</Reveal>
);
})}
</div>
</div>
</section>

View File

@@ -1,6 +1,6 @@
"use client";
import React, { useRef, useState } from "react";
import React, { useState } from "react";
import { m, LazyMotion, domAnimation } from "framer-motion";
import Link from "next/link";
import { ArrowRight } from "lucide-react";

View File

@@ -2,6 +2,7 @@
import React, { useState } from "react";
import Image from "next/image";
import Link from "next/link";
import { Mail, MapPin, CheckCircle } from "lucide-react";
import { Button } from "./Button";
import { Counter } from "./Counter";
@@ -57,7 +58,7 @@ export default function Contact() {
buttonText: t("form.tryAgain") || "Erneut versuchen",
});
}
} catch (error) {
} catch {
setStatusModal({
isOpen: true,
type: "error",
@@ -279,12 +280,12 @@ export default function Contact() {
<p className="text-xs text-slate-400 text-center">
{t.rich("form.privacyNote", {
link: (chunks) => (
<a
<Link
href="/datenschutz"
className="text-accent hover:underline font-semibold"
>
{chunks}
</a>
</Link>
),
})}
</p>

View File

@@ -52,10 +52,10 @@ const Layout = ({ children }: { children: React.ReactNode }) => {
className="fixed top-0 left-0 right-0 z-[100]"
>
<header
className={`transition-all duration-300 flex items-center py-1 ${
className={`transition-all duration-300 flex items-center ${
isScrolled
? "bg-white/90 backdrop-blur-lg border-b border-slate-200 shadow-sm"
: "bg-gradient-to-b from-white/80 via-white/40 to-transparent"
? "bg-white/90 backdrop-blur-lg border-b border-slate-200 shadow-sm py-2"
: "bg-gradient-to-b from-white/80 via-white/40 to-transparent py-4"
}`}
>
<div className="container-custom flex justify-between items-center w-full relative z-10">
@@ -65,7 +65,7 @@ const Layout = ({ children }: { children: React.ReactNode }) => {
aria-label={`${t("nav.home")} - Zur Startseite`}
>
<div
className={`relative transition-all duration-300 ${isScrolled ? "h-[50px] md:h-[80px] w-[120px] md:w-[200px] mt-0 mb-[-10px]" : "h-[80px] md:h-[140px] w-[180px] md:w-[320px] mt-2 md:mt-4 mb-[-20px] md:mb-[-40px]"}`}
className={`relative transition-all duration-300 ${isScrolled ? "h-[50px] md:h-[60px] w-[120px] md:w-[150px]" : "h-[70px] md:h-[100px] w-[160px] md:w-[240px]"}`}
>
<Image
src="/assets/logo.png"

View File

@@ -8,39 +8,49 @@ services:
- ${ENV_FILE:-.env}
labels:
- "traefik.enable=true"
- "traefik.http.routers.${PROJECT_NAME:-mb-grid-solutions}.rule=Host(`${TRAEFIK_HOST:-mb-grid-solutions.localhost}`)"
- "traefik.http.routers.${PROJECT_NAME:-mb-grid-solutions}.entrypoints=websecure"
- "traefik.http.routers.${PROJECT_NAME:-mb-grid-solutions}.tls.certresolver=le"
- "traefik.http.routers.${PROJECT_NAME:-mb-grid-solutions}.tls=true"
- "traefik.http.services.${PROJECT_NAME:-mb-grid-solutions}.loadbalancer.server.port=3000"
- "traefik.http.routers.${PROJECT_NAME:-mb-grid-solutions}.middlewares=${PROJECT_NAME:-mb-grid-solutions}-auth"
- "traefik.http.routers.${PROJECT_NAME}.rule=Host(`${TRAEFIK_HOST:-mb-grid-solutions.localhost}`)"
- "traefik.http.routers.${PROJECT_NAME}.entrypoints=websecure"
- "traefik.http.routers.${PROJECT_NAME}.tls.certresolver=le"
- "traefik.http.routers.${PROJECT_NAME}.tls=true"
- "traefik.http.services.${PROJECT_NAME}.loadbalancer.server.port=3000"
- "traefik.http.routers.${PROJECT_NAME}.middlewares=${PROJECT_NAME}-auth"
- "traefik.docker.network=infra"
# Gatekeeper Router
- "traefik.http.routers.${PROJECT_NAME:-mb-grid-solutions}-gatekeeper.rule=Host(`${TRAEFIK_HOST:-mb-grid-solutions.localhost}`) && PathPrefix(`/gatekeeper`)"
- "traefik.http.routers.${PROJECT_NAME:-mb-grid-solutions}-gatekeeper.entrypoints=websecure"
- "traefik.http.routers.${PROJECT_NAME:-mb-grid-solutions}-gatekeeper.tls.certresolver=le"
- "traefik.http.routers.${PROJECT_NAME:-mb-grid-solutions}-gatekeeper.tls=true"
- "traefik.http.routers.${PROJECT_NAME:-mb-grid-solutions}-gatekeeper.service=${PROJECT_NAME:-mb-grid-solutions}-gatekeeper"
# Gatekeeper Router (Shared Host + dedicated Subdomain)
- "traefik.http.routers.${PROJECT_NAME}-gatekeeper.rule=(Host(`${TRAEFIK_HOST:-mb-grid-solutions.localhost}`) && PathPrefix(`/gatekeeper`)) || Host(`gatekeeper.${TRAEFIK_HOST:-mb-grid-solutions.localhost}`)"
- "traefik.http.routers.${PROJECT_NAME}-gatekeeper.entrypoints=websecure"
- "traefik.http.routers.${PROJECT_NAME}-gatekeeper.tls.certresolver=le"
- "traefik.http.routers.${PROJECT_NAME}-gatekeeper.tls=true"
- "traefik.http.routers.${PROJECT_NAME}-gatekeeper.service=${PROJECT_NAME}-gatekeeper"
# Auth Middleware Definition
- "traefik.http.middlewares.${PROJECT_NAME:-mb-grid-solutions}-auth.forwardauth.address=http://gatekeeper:3000/api/verify"
- "traefik.http.middlewares.${PROJECT_NAME:-mb-grid-solutions}-auth.forwardauth.trustForwardHeader=true"
- "traefik.http.middlewares.${PROJECT_NAME:-mb-grid-solutions}-auth.forwardauth.authResponseHeaders=X-Auth-User"
- "traefik.http.middlewares.${PROJECT_NAME}-auth.forwardauth.address=http://${PROJECT_NAME}-gatekeeper:3000/api/verify"
- "traefik.http.middlewares.${PROJECT_NAME}-auth.forwardauth.trustForwardHeader=true"
- "traefik.http.middlewares.${PROJECT_NAME}-auth.forwardauth.authResponseHeaders=X-Auth-User"
- "traefik.docker.network=infra"
gatekeeper:
image: registry.infra.mintel.me/mintel/gatekeeper:latest
container_name: ${PROJECT_NAME:-mb-grid-solutions}-gatekeeper
restart: always
networks:
- infra
infra:
aliases:
- ${PROJECT_NAME:-mb-grid-solutions}-gatekeeper
env_file:
- ${ENV_FILE:-.env}
environment:
PORT: 3000
PROJECT_NAME: "MB Grid Solutions"
PROJECT_COLOR: "#82ed20"
PORT: ${PORT:-3000}
PROJECT_NAME: ${PROJECT_NAME:-MB Grid Solutions}
PROJECT_COLOR: ${PROJECT_COLOR:-#82ed20}
COOKIE_DOMAIN: ${COOKIE_DOMAIN:-.mb-grid-solutions.com}
AUTH_COOKIE_NAME: ${AUTH_COOKIE_NAME:-mintel_gatekeeper_session}
GATEKEEPER_PASSWORD: ${GATEKEEPER_PASSWORD:-mintel}
# Dedicated Base URL for Gatekeeper subdomain to prevent redirect loops
NEXT_PUBLIC_BASE_URL: https://gatekeeper.${TRAEFIK_HOST:-mb-grid-solutions.localhost}
labels:
- "traefik.enable=true"
- "traefik.http.services.${PROJECT_NAME:-mb-grid-solutions}-gatekeeper.loadbalancer.server.port=3000"
- "traefik.http.services.${PROJECT_NAME}-gatekeeper.loadbalancer.server.port=3000"
- "traefik.docker.network=infra"
directus:
image: directus/directus:11
@@ -63,17 +73,23 @@ services:
DB_DATABASE: ${DIRECTUS_DB_NAME:-directus}
DB_USER: ${DIRECTUS_DB_USER:-directus}
DB_PASSWORD: ${DIRECTUS_DB_PASSWORD:-directus}
# Telemetry & Performance
LOGGER_LEVEL: ${LOG_LEVEL:-info}
SENTRY_DSN: ${SENTRY_DSN}
SENTRY_ENVIRONMENT: ${TARGET:-development}
volumes:
- ./directus/uploads:/directus/uploads
- ./directus/extensions:/directus/extensions
labels:
- "traefik.enable=true"
- "traefik.http.routers.${PROJECT_NAME:-mb-grid-solutions}-directus.rule=Host(`${DIRECTUS_HOST:-cms.mb-grid-solutions.localhost}`)"
- "traefik.http.routers.${PROJECT_NAME:-mb-grid-solutions}-directus.entrypoints=websecure"
- "traefik.http.routers.${PROJECT_NAME:-mb-grid-solutions}-directus.tls.certresolver=le"
- "traefik.http.routers.${PROJECT_NAME:-mb-grid-solutions}-directus.tls=true"
- "traefik.http.routers.${PROJECT_NAME:-mb-grid-solutions}-directus.middlewares=${PROJECT_NAME:-mb-grid-solutions}-auth"
- "traefik.http.services.${PROJECT_NAME:-mb-grid-solutions}-directus.loadbalancer.server.port=8055"
- "traefik.http.routers.${PROJECT_NAME}-directus.rule=Host(`${DIRECTUS_HOST:-cms.mb-grid-solutions.localhost}`)"
- "traefik.http.routers.${PROJECT_NAME}-directus.entrypoints=websecure"
- "traefik.http.routers.${PROJECT_NAME}-directus.tls.certresolver=le"
- "traefik.http.routers.${PROJECT_NAME}-directus.tls=true"
- "traefik.http.routers.${PROJECT_NAME}-directus.middlewares=${PROJECT_NAME}-forward,compress"
- "traefik.http.services.${PROJECT_NAME}-directus.loadbalancer.server.port=8055"
- "traefik.http.middlewares.${PROJECT_NAME}-forward.headers.customrequestheaders.X-Forwarded-Proto=https"
- "traefik.docker.network=infra"
directus-db:
image: postgres:15-alpine

View File

@@ -1,5 +0,0 @@
import { nextConfig } from "@mintel/eslint-config/next";
export default [
...nextConfig,
];

View File

@@ -1,7 +1,7 @@
import type { CacheService } from "./cache-service";
export class MemoryCacheService implements CacheService {
private cache = new Map<string, { value: any; expiry: number | null }>();
private cache = new Map<string, { value: unknown; expiry: number | null }>();
async get<T>(key: string): Promise<T | null> {
const item = this.cache.get(key);

View File

@@ -2,21 +2,22 @@
"name": "mb-grid-solutions.com",
"version": "1.0.0",
"type": "module",
"packageManager": "pnpm@10.18.3",
"scripts": {
"dev": "docker network create infra 2>/dev/null || true && echo '\\n🚀 Development Environment Starting...\\n\\n📱 App: http://mb-grid-solutions.localhost\\n🗄 CMS: http://cms.mb-grid-solutions.localhost/admin\\n🚦 Traefik: http://localhost:8080\\n\\n(Press Ctrl+C to stop)\\n' && docker compose down --remove-orphans && docker compose up app directus directus-db",
"dev:next": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"lint": "eslint app components lib scripts",
"test": "vitest",
"prepare": "husky",
"directus:bootstrap": "DIRECTUS_URL=http://localhost:8055 npx tsx --env-file=.env scripts/setup-directus.ts",
"directus:push:staging": "./scripts/sync-directus.sh push staging",
"directus:pull:staging": "./scripts/sync-directus.sh pull staging",
"directus:push:testing": "./scripts/sync-directus.sh push testing",
"directus:pull:testing": "./scripts/sync-directus.sh pull testing",
"directus:push:prod": "./scripts/sync-directus.sh push production",
"directus:pull:prod": "./scripts/sync-directus.sh pull production",
"cms:bootstrap": "DIRECTUS_URL=http://localhost:8055 npx tsx --env-file=.env scripts/setup-directus.ts",
"cms:push:staging": "./scripts/sync-directus.sh push staging",
"cms:pull:staging": "./scripts/sync-directus.sh pull staging",
"cms:push:testing": "./scripts/sync-directus.sh push testing",
"cms:pull:testing": "./scripts/sync-directus.sh pull testing",
"cms:push:prod": "./scripts/sync-directus.sh push production",
"cms:pull:prod": "./scripts/sync-directus.sh pull production",
"pagespeed:test": "mintel pagespeed test"
},
"keywords": [],
@@ -24,8 +25,8 @@
"license": "ISC",
"description": "",
"dependencies": {
"@mintel/next-config": "1.1.13",
"@mintel/next-utils": "1.1.13",
"@mintel/next-config": "^1.1.13",
"@mintel/next-utils": "^1.1.13",
"@sentry/nextjs": "^10.38.0",
"framer-motion": "^12.29.2",
"lucide-react": "^0.562.0",
@@ -41,10 +42,10 @@
"@commitlint/cli": "^20.4.0",
"@commitlint/config-conventional": "^20.4.0",
"@directus/sdk": "^21.0.0",
"@mintel/cli": "1.1.13",
"@mintel/eslint-config": "1.1.13",
"@mintel/husky-config": "1.1.13",
"@mintel/tsconfig": "1.1.13",
"@mintel/cli": "^1.1.13",
"@mintel/eslint-config": "^1.1.13",
"@mintel/husky-config": "^1.1.13",
"@mintel/tsconfig": "^1.1.13",
"@tailwindcss/postcss": "^4.1.18",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
@@ -54,8 +55,8 @@
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.2",
"autoprefixer": "^10.4.23",
"eslint": "^9.39.2",
"eslint-config-next": "^16.1.6",
"eslint": "^8.57.1",
"eslint-config-next": "15.1.6",
"husky": "^9.1.7",
"jsdom": "^27.4.0",
"lint-staged": "^16.2.7",

457
pnpm-lock.yaml generated
View File

@@ -9,10 +9,10 @@ importers:
.:
dependencies:
'@mintel/next-config':
specifier: 1.1.13
specifier: ^1.1.13
version: 1.1.13(@opentelemetry/context-async-hooks@2.5.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.5.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.211.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.5.0(@opentelemetry/api@1.9.0))(next@16.1.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(webpack@5.104.1)
'@mintel/next-utils':
specifier: 1.1.13
specifier: ^1.1.13
version: 1.1.13(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)
'@sentry/nextjs':
specifier: ^10.38.0
@@ -55,16 +55,16 @@ importers:
specifier: ^21.0.0
version: 21.0.0
'@mintel/cli':
specifier: 1.1.13
specifier: ^1.1.13
version: 1.1.13
'@mintel/eslint-config':
specifier: 1.1.13
version: 1.1.13(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
specifier: ^1.1.13
version: 1.1.13(eslint@8.57.1)(typescript@5.9.3)
'@mintel/husky-config':
specifier: 1.1.13
specifier: ^1.1.13
version: 1.1.13
'@mintel/tsconfig':
specifier: 1.1.13
specifier: ^1.1.13
version: 1.1.13
'@tailwindcss/postcss':
specifier: ^4.1.18
@@ -94,11 +94,11 @@ importers:
specifier: ^10.4.23
version: 10.4.24(postcss@8.5.6)
eslint:
specifier: ^9.39.2
version: 9.39.2(jiti@2.6.1)
specifier: ^8.57.1
version: 8.57.1
eslint-config-next:
specifier: ^16.1.6
version: 16.1.6(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
specifier: 15.1.6
version: 15.1.6(eslint@8.57.1)(typescript@5.9.3)
husky:
specifier: ^9.1.7
version: 9.1.7
@@ -520,34 +520,22 @@ packages:
resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
'@eslint/config-array@0.21.1':
resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/config-helpers@0.4.2':
resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/core@0.17.0':
resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/eslintrc@2.1.4':
resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
'@eslint/eslintrc@3.3.3':
resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/js@8.57.1':
resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
'@eslint/js@9.39.2':
resolution: {integrity: sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/object-schema@2.1.7':
resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/plugin-kit@0.4.1':
resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@exodus/bytes@1.11.0':
resolution: {integrity: sha512-wO3vd8nsEHdumsXrjGO/v4p6irbg7hy9kvIeR6i2AwylZSk4HJdWgL0FNaVquW1+AweJcdvU1IEpuIWk/WaPnA==}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
@@ -575,21 +563,18 @@ packages:
'@formatjs/intl-localematcher@0.8.1':
resolution: {integrity: sha512-xwEuwQFdtSq1UKtQnyTZWC+eHdv7Uygoa+H2k/9uzBVQjDyp9r20LNDNKedWXll7FssT3GRHvqsdJGYSUWqYFA==}
'@humanfs/core@0.19.1':
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
engines: {node: '>=18.18.0'}
'@humanfs/node@0.16.7':
resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==}
engines: {node: '>=18.18.0'}
'@humanwhocodes/config-array@0.13.0':
resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==}
engines: {node: '>=10.10.0'}
deprecated: Use @eslint/config-array instead
'@humanwhocodes/module-importer@1.0.1':
resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
engines: {node: '>=12.22'}
'@humanwhocodes/retry@0.4.3':
resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
engines: {node: '>=18.18'}
'@humanwhocodes/object-schema@2.0.3':
resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
deprecated: Use @eslint/object-schema instead
'@img/colour@1.0.0':
resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==}
@@ -887,9 +872,6 @@ packages:
'@next/eslint-plugin-next@15.1.6':
resolution: {integrity: sha512-+slMxhTgILUntZDGNgsKEYHUvpn72WP1YTlkmEhS51vnVd7S9jEEy0n9YAMcI21vUG4akTw9voWH02lrClt/yw==}
'@next/eslint-plugin-next@16.1.6':
resolution: {integrity: sha512-/Qq3PTagA6+nYVfryAtQ7/9FEr/6YVyvOtl6rZnGsbReGLf0jZU6gkpr1FuChAQpvV46a78p4cmHOVP8mbfSMQ==}
'@next/swc-darwin-arm64@15.1.6':
resolution: {integrity: sha512-u7lg4Mpl9qWpKgy6NzEkz/w0/keEHtOybmIl0ykgItBxEM5mYotS5PmqTpo+Rhg8FiOiWgwr8USxmKQkqLBCrw==}
engines: {node: '>= 10'}
@@ -2245,6 +2227,9 @@ packages:
resolution: {integrity: sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@ungap/structured-clone@1.3.0':
resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
'@unrs/resolver-binding-android-arm-eabi@1.11.1':
resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==}
cpu: [arm]
@@ -2838,6 +2823,10 @@ packages:
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
engines: {node: '>=0.10.0'}
doctrine@3.0.0:
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
engines: {node: '>=6.0.0'}
dom-accessibility-api@0.5.16:
resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==}
@@ -2957,15 +2946,6 @@ packages:
typescript:
optional: true
eslint-config-next@16.1.6:
resolution: {integrity: sha512-vKq40io2B0XtkkNDYyleATwblNt8xuh3FWp8SpSz3pt7P01OkBFlKsJZ2mWt5WsCySlDQLckb1zMY9yE9Qy0LA==}
peerDependencies:
eslint: '>=9.0.0'
typescript: '>=3.3.1'
peerDependenciesMeta:
typescript:
optional: true
eslint-import-resolver-node@0.3.9:
resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
@@ -3025,12 +3005,6 @@ packages:
peerDependencies:
eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0
eslint-plugin-react-hooks@7.0.1:
resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==}
engines: {node: '>=18'}
peerDependencies:
eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0
eslint-plugin-react@7.37.5:
resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==}
engines: {node: '>=4'}
@@ -3041,9 +3015,9 @@ packages:
resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
engines: {node: '>=8.0.0'}
eslint-scope@8.4.0:
resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
eslint-scope@7.2.2:
resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
eslint-visitor-keys@3.4.3:
resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
@@ -3053,20 +3027,20 @@ packages:
resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
eslint@9.39.2:
resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
eslint@8.57.1:
resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options.
hasBin: true
peerDependencies:
jiti: '*'
peerDependenciesMeta:
jiti:
optional: true
espree@10.4.0:
resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
espree@9.6.1:
resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
esquery@1.7.0:
resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==}
engines: {node: '>=0.10'}
@@ -3138,9 +3112,9 @@ packages:
picomatch:
optional: true
file-entry-cache@8.0.0:
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
engines: {node: '>=16.0.0'}
file-entry-cache@6.0.1:
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
engines: {node: ^10.12.0 || >=12.0.0}
fill-range@7.1.1:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
@@ -3150,9 +3124,9 @@ packages:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
engines: {node: '>=10'}
flat-cache@4.0.1:
resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
engines: {node: '>=16'}
flat-cache@3.2.0:
resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==}
engines: {node: ^10.12.0 || >=12.0.0}
flatted@3.3.3:
resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
@@ -3259,23 +3233,26 @@ packages:
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
hasBin: true
glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Glob versions prior to v9 are no longer supported
glob@9.3.5:
resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==}
engines: {node: '>=16 || 14 >=14.17'}
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
global-directory@4.0.1:
resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==}
engines: {node: '>=18'}
globals@13.24.0:
resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
engines: {node: '>=8'}
globals@14.0.0:
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
engines: {node: '>=18'}
globals@16.4.0:
resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==}
engines: {node: '>=18'}
globalthis@1.0.4:
resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
engines: {node: '>= 0.4'}
@@ -3287,6 +3264,9 @@ packages:
graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
graphemer@1.4.0:
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
has-bigints@1.1.0:
resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==}
engines: {node: '>= 0.4'}
@@ -3317,12 +3297,6 @@ packages:
help-me@5.0.0:
resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==}
hermes-estree@0.25.1:
resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==}
hermes-parser@0.25.1:
resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==}
hoist-non-react-statics@3.3.2:
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
@@ -3379,6 +3353,13 @@ packages:
resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
engines: {node: '>=8'}
inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
ini@4.1.1:
resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
@@ -3479,6 +3460,10 @@ packages:
resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==}
engines: {node: '>=8'}
is-path-inside@3.0.3:
resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
engines: {node: '>=8'}
is-plain-obj@4.1.0:
resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
engines: {node: '>=12'}
@@ -4024,6 +4009,10 @@ packages:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
path-is-absolute@1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
@@ -4244,6 +4233,11 @@ packages:
rfdc@1.4.1:
resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
rimraf@3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
deprecated: Rimraf versions prior to v4 are no longer supported
hasBin: true
rollup@3.29.5:
resolution: {integrity: sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==}
engines: {node: '>=14.18.0', npm: '>=8.0.0'}
@@ -4528,6 +4522,9 @@ packages:
engines: {node: '>=10'}
hasBin: true
text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
thread-stream@4.0.0:
resolution: {integrity: sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==}
engines: {node: '>=20'}
@@ -4585,6 +4582,10 @@ packages:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
type-fest@0.20.2:
resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
engines: {node: '>=10'}
type-fest@0.7.1:
resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==}
engines: {node: '>=8'}
@@ -4865,12 +4866,6 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
zod-validation-error@4.0.2:
resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==}
engines: {node: '>=18.0.0'}
peerDependencies:
zod: ^3.25.0 || ^4.0.0
zod@3.25.76:
resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
@@ -5254,29 +5249,27 @@ snapshots:
'@esbuild/win32-x64@0.27.2':
optional: true
'@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))':
'@eslint-community/eslint-utils@4.9.1(eslint@8.57.1)':
dependencies:
eslint: 9.39.2(jiti@2.6.1)
eslint: 8.57.1
eslint-visitor-keys: 3.4.3
'@eslint-community/regexpp@4.12.2': {}
'@eslint/config-array@0.21.1':
'@eslint/eslintrc@2.1.4':
dependencies:
'@eslint/object-schema': 2.1.7
ajv: 6.12.6
debug: 4.4.3
espree: 9.6.1
globals: 13.24.0
ignore: 5.3.2
import-fresh: 3.3.1
js-yaml: 4.1.1
minimatch: 3.1.2
strip-json-comments: 3.1.1
transitivePeerDependencies:
- supports-color
'@eslint/config-helpers@0.4.2':
dependencies:
'@eslint/core': 0.17.0
'@eslint/core@0.17.0':
dependencies:
'@types/json-schema': 7.0.15
'@eslint/eslintrc@3.3.3':
dependencies:
ajv: 6.12.6
@@ -5291,15 +5284,10 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@eslint/js@8.57.1': {}
'@eslint/js@9.39.2': {}
'@eslint/object-schema@2.1.7': {}
'@eslint/plugin-kit@0.4.1':
dependencies:
'@eslint/core': 0.17.0
levn: 0.4.1
'@exodus/bytes@1.11.0': {}
'@formatjs/ecma402-abstract@3.1.1':
@@ -5333,16 +5321,17 @@ snapshots:
'@formatjs/fast-memoize': 3.1.0
tslib: 2.8.1
'@humanfs/core@0.19.1': {}
'@humanfs/node@0.16.7':
'@humanwhocodes/config-array@0.13.0':
dependencies:
'@humanfs/core': 0.19.1
'@humanwhocodes/retry': 0.4.3
'@humanwhocodes/object-schema': 2.0.3
debug: 4.4.3
minimatch: 3.1.2
transitivePeerDependencies:
- supports-color
'@humanwhocodes/module-importer@1.0.1': {}
'@humanwhocodes/retry@0.4.3': {}
'@humanwhocodes/object-schema@2.0.3': {}
'@img/colour@1.0.0':
optional: true
@@ -5556,12 +5545,12 @@ snapshots:
fs-extra: 11.3.3
prompts: 2.4.2
'@mintel/eslint-config@1.1.13(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
'@mintel/eslint-config@1.1.13(eslint@8.57.1)(typescript@5.9.3)':
dependencies:
'@eslint/eslintrc': 3.3.3
'@eslint/js': 9.39.2
eslint-config-next: 15.1.6(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
typescript-eslint: 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
eslint-config-next: 15.1.6(eslint@8.57.1)(typescript@5.9.3)
typescript-eslint: 8.54.0(eslint@8.57.1)(typescript@5.9.3)
transitivePeerDependencies:
- eslint
- eslint-import-resolver-webpack
@@ -5625,10 +5614,6 @@ snapshots:
dependencies:
fast-glob: 3.3.1
'@next/eslint-plugin-next@16.1.6':
dependencies:
fast-glob: 3.3.1
'@next/swc-darwin-arm64@15.1.6':
optional: true
@@ -7060,7 +7045,7 @@ snapshots:
'@types/pg-pool@2.0.6':
dependencies:
'@types/pg': 8.6.1
'@types/pg': 8.15.6
'@types/pg-pool@2.0.7':
dependencies:
@@ -7092,15 +7077,15 @@ snapshots:
dependencies:
'@types/node': 25.2.0
'@typescript-eslint/eslint-plugin@8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
'@typescript-eslint/eslint-plugin@8.54.0(@typescript-eslint/parser@8.54.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3)':
dependencies:
'@eslint-community/regexpp': 4.12.2
'@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
'@typescript-eslint/parser': 8.54.0(eslint@8.57.1)(typescript@5.9.3)
'@typescript-eslint/scope-manager': 8.54.0
'@typescript-eslint/type-utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
'@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
'@typescript-eslint/type-utils': 8.54.0(eslint@8.57.1)(typescript@5.9.3)
'@typescript-eslint/utils': 8.54.0(eslint@8.57.1)(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.54.0
eslint: 9.39.2(jiti@2.6.1)
eslint: 8.57.1
ignore: 7.0.5
natural-compare: 1.4.0
ts-api-utils: 2.4.0(typescript@5.9.3)
@@ -7108,14 +7093,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
'@typescript-eslint/parser@8.54.0(eslint@8.57.1)(typescript@5.9.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.54.0
'@typescript-eslint/types': 8.54.0
'@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.54.0
debug: 4.4.3
eslint: 9.39.2(jiti@2.6.1)
eslint: 8.57.1
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
@@ -7138,13 +7123,13 @@ snapshots:
dependencies:
typescript: 5.9.3
'@typescript-eslint/type-utils@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
'@typescript-eslint/type-utils@8.54.0(eslint@8.57.1)(typescript@5.9.3)':
dependencies:
'@typescript-eslint/types': 8.54.0
'@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3)
'@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
'@typescript-eslint/utils': 8.54.0(eslint@8.57.1)(typescript@5.9.3)
debug: 4.4.3
eslint: 9.39.2(jiti@2.6.1)
eslint: 8.57.1
ts-api-utils: 2.4.0(typescript@5.9.3)
typescript: 5.9.3
transitivePeerDependencies:
@@ -7167,13 +7152,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
'@typescript-eslint/utils@8.54.0(eslint@8.57.1)(typescript@5.9.3)':
dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1))
'@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1)
'@typescript-eslint/scope-manager': 8.54.0
'@typescript-eslint/types': 8.54.0
'@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3)
eslint: 9.39.2(jiti@2.6.1)
eslint: 8.57.1
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
@@ -7183,6 +7168,8 @@ snapshots:
'@typescript-eslint/types': 8.54.0
eslint-visitor-keys: 4.2.1
'@ungap/structured-clone@1.3.0': {}
'@unrs/resolver-binding-android-arm-eabi@1.11.1':
optional: true
@@ -7796,6 +7783,10 @@ snapshots:
dependencies:
esutils: 2.0.3
doctrine@3.0.0:
dependencies:
esutils: 2.0.3
dom-accessibility-api@0.5.16: {}
dom-accessibility-api@0.6.3: {}
@@ -7984,19 +7975,19 @@ snapshots:
escape-string-regexp@4.0.0: {}
eslint-config-next@15.1.6(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3):
eslint-config-next@15.1.6(eslint@8.57.1)(typescript@5.9.3):
dependencies:
'@next/eslint-plugin-next': 15.1.6
'@rushstack/eslint-patch': 1.15.0
'@typescript-eslint/eslint-plugin': 8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
'@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
eslint: 9.39.2(jiti@2.6.1)
'@typescript-eslint/eslint-plugin': 8.54.0(@typescript-eslint/parser@8.54.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3)
'@typescript-eslint/parser': 8.54.0(eslint@8.57.1)(typescript@5.9.3)
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-react: 7.37.5(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-react-hooks: 5.2.0(eslint@9.39.2(jiti@2.6.1))
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.54.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1)
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.54.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.54.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1)
eslint-plugin-react: 7.37.5(eslint@8.57.1)
eslint-plugin-react-hooks: 5.2.0(eslint@8.57.1)
optionalDependencies:
typescript: 5.9.3
transitivePeerDependencies:
@@ -8004,26 +7995,6 @@ snapshots:
- eslint-plugin-import-x
- supports-color
eslint-config-next@16.1.6(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3):
dependencies:
'@next/eslint-plugin-next': 16.1.6
eslint: 9.39.2(jiti@2.6.1)
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-react: 7.37.5(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-react-hooks: 7.0.1(eslint@9.39.2(jiti@2.6.1))
globals: 16.4.0
typescript-eslint: 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
optionalDependencies:
typescript: 5.9.3
transitivePeerDependencies:
- '@typescript-eslint/parser'
- eslint-import-resolver-webpack
- eslint-plugin-import-x
- supports-color
eslint-import-resolver-node@0.3.9:
dependencies:
debug: 3.2.7
@@ -8032,33 +8003,33 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1)):
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.54.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1):
dependencies:
'@nolyfill/is-core-module': 1.0.39
debug: 4.4.3
eslint: 9.39.2(jiti@2.6.1)
eslint: 8.57.1
get-tsconfig: 4.13.1
is-bun-module: 2.0.0
stable-hash: 0.0.5
tinyglobby: 0.2.15
unrs-resolver: 1.11.1
optionalDependencies:
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.54.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.54.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
transitivePeerDependencies:
- supports-color
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)):
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.54.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.54.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1):
dependencies:
debug: 3.2.7
optionalDependencies:
'@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
eslint: 9.39.2(jiti@2.6.1)
'@typescript-eslint/parser': 8.54.0(eslint@8.57.1)(typescript@5.9.3)
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1))
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.54.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1)
transitivePeerDependencies:
- supports-color
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)):
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.54.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.54.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1):
dependencies:
'@rtsao/scc': 1.1.0
array-includes: 3.1.9
@@ -8067,9 +8038,9 @@ snapshots:
array.prototype.flatmap: 1.3.3
debug: 3.2.7
doctrine: 2.1.0
eslint: 9.39.2(jiti@2.6.1)
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1))
eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.54.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.54.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
hasown: 2.0.2
is-core-module: 2.16.1
is-glob: 4.0.3
@@ -8081,13 +8052,13 @@ snapshots:
string.prototype.trimend: 1.0.9
tsconfig-paths: 3.15.0
optionalDependencies:
'@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
'@typescript-eslint/parser': 8.54.0(eslint@8.57.1)(typescript@5.9.3)
transitivePeerDependencies:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
- supports-color
eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.2(jiti@2.6.1)):
eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.1):
dependencies:
aria-query: 5.3.2
array-includes: 3.1.9
@@ -8097,7 +8068,7 @@ snapshots:
axobject-query: 4.1.0
damerau-levenshtein: 1.0.8
emoji-regex: 9.2.2
eslint: 9.39.2(jiti@2.6.1)
eslint: 8.57.1
hasown: 2.0.2
jsx-ast-utils: 3.3.5
language-tags: 1.0.9
@@ -8106,22 +8077,11 @@ snapshots:
safe-regex-test: 1.1.0
string.prototype.includes: 2.0.1
eslint-plugin-react-hooks@5.2.0(eslint@9.39.2(jiti@2.6.1)):
eslint-plugin-react-hooks@5.2.0(eslint@8.57.1):
dependencies:
eslint: 9.39.2(jiti@2.6.1)
eslint: 8.57.1
eslint-plugin-react-hooks@7.0.1(eslint@9.39.2(jiti@2.6.1)):
dependencies:
'@babel/core': 7.29.0
'@babel/parser': 7.29.0
eslint: 9.39.2(jiti@2.6.1)
hermes-parser: 0.25.1
zod: 4.3.6
zod-validation-error: 4.0.2(zod@4.3.6)
transitivePeerDependencies:
- supports-color
eslint-plugin-react@7.37.5(eslint@9.39.2(jiti@2.6.1)):
eslint-plugin-react@7.37.5(eslint@8.57.1):
dependencies:
array-includes: 3.1.9
array.prototype.findlast: 1.2.5
@@ -8129,7 +8089,7 @@ snapshots:
array.prototype.tosorted: 1.1.4
doctrine: 2.1.0
es-iterator-helpers: 1.2.2
eslint: 9.39.2(jiti@2.6.1)
eslint: 8.57.1
estraverse: 5.3.0
hasown: 2.0.2
jsx-ast-utils: 3.3.5
@@ -8148,7 +8108,7 @@ snapshots:
esrecurse: 4.3.0
estraverse: 4.3.0
eslint-scope@8.4.0:
eslint-scope@7.2.2:
dependencies:
esrecurse: 4.3.0
estraverse: 5.3.0
@@ -8157,44 +8117,46 @@ snapshots:
eslint-visitor-keys@4.2.1: {}
eslint@9.39.2(jiti@2.6.1):
eslint@8.57.1:
dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1))
'@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1)
'@eslint-community/regexpp': 4.12.2
'@eslint/config-array': 0.21.1
'@eslint/config-helpers': 0.4.2
'@eslint/core': 0.17.0
'@eslint/eslintrc': 3.3.3
'@eslint/js': 9.39.2
'@eslint/plugin-kit': 0.4.1
'@humanfs/node': 0.16.7
'@eslint/eslintrc': 2.1.4
'@eslint/js': 8.57.1
'@humanwhocodes/config-array': 0.13.0
'@humanwhocodes/module-importer': 1.0.1
'@humanwhocodes/retry': 0.4.3
'@types/estree': 1.0.8
'@nodelib/fs.walk': 1.2.8
'@ungap/structured-clone': 1.3.0
ajv: 6.12.6
chalk: 4.1.2
cross-spawn: 7.0.6
debug: 4.4.3
doctrine: 3.0.0
escape-string-regexp: 4.0.0
eslint-scope: 8.4.0
eslint-visitor-keys: 4.2.1
espree: 10.4.0
eslint-scope: 7.2.2
eslint-visitor-keys: 3.4.3
espree: 9.6.1
esquery: 1.7.0
esutils: 2.0.3
fast-deep-equal: 3.1.3
file-entry-cache: 8.0.0
file-entry-cache: 6.0.1
find-up: 5.0.0
glob-parent: 6.0.2
globals: 13.24.0
graphemer: 1.4.0
ignore: 5.3.2
imurmurhash: 0.1.4
is-glob: 4.0.3
is-path-inside: 3.0.3
js-yaml: 4.1.1
json-stable-stringify-without-jsonify: 1.0.1
levn: 0.4.1
lodash.merge: 4.6.2
minimatch: 3.1.2
natural-compare: 1.4.0
optionator: 0.9.4
optionalDependencies:
jiti: 2.6.1
strip-ansi: 6.0.1
text-table: 0.2.0
transitivePeerDependencies:
- supports-color
@@ -8204,6 +8166,12 @@ snapshots:
acorn-jsx: 5.3.2(acorn@8.15.0)
eslint-visitor-keys: 4.2.1
espree@9.6.1:
dependencies:
acorn: 8.15.0
acorn-jsx: 5.3.2(acorn@8.15.0)
eslint-visitor-keys: 3.4.3
esquery@1.7.0:
dependencies:
estraverse: 5.3.0
@@ -8258,9 +8226,9 @@ snapshots:
optionalDependencies:
picomatch: 4.0.3
file-entry-cache@8.0.0:
file-entry-cache@6.0.1:
dependencies:
flat-cache: 4.0.1
flat-cache: 3.2.0
fill-range@7.1.1:
dependencies:
@@ -8271,10 +8239,11 @@ snapshots:
locate-path: 6.0.0
path-exists: 4.0.0
flat-cache@4.0.1:
flat-cache@3.2.0:
dependencies:
flatted: 3.3.3
keyv: 4.5.4
rimraf: 3.0.2
flatted@3.3.3: {}
@@ -8385,6 +8354,15 @@ snapshots:
package-json-from-dist: 1.0.1
path-scurry: 1.11.1
glob@7.2.3:
dependencies:
fs.realpath: 1.0.0
inflight: 1.0.6
inherits: 2.0.4
minimatch: 3.1.2
once: 1.4.0
path-is-absolute: 1.0.1
glob@9.3.5:
dependencies:
fs.realpath: 1.0.0
@@ -8396,9 +8374,11 @@ snapshots:
dependencies:
ini: 4.1.1
globals@14.0.0: {}
globals@13.24.0:
dependencies:
type-fest: 0.20.2
globals@16.4.0: {}
globals@14.0.0: {}
globalthis@1.0.4:
dependencies:
@@ -8409,6 +8389,8 @@ snapshots:
graceful-fs@4.2.11: {}
graphemer@1.4.0: {}
has-bigints@1.1.0: {}
has-flag@4.0.0: {}
@@ -8433,12 +8415,6 @@ snapshots:
help-me@5.0.0: {}
hermes-estree@0.25.1: {}
hermes-parser@0.25.1:
dependencies:
hermes-estree: 0.25.1
hoist-non-react-statics@3.3.2:
dependencies:
react-is: 16.13.1
@@ -8505,6 +8481,13 @@ snapshots:
indent-string@4.0.0: {}
inflight@1.0.6:
dependencies:
once: 1.4.0
wrappy: 1.0.2
inherits@2.0.4: {}
ini@4.1.1: {}
internal-slot@1.1.0:
@@ -8610,6 +8593,8 @@ snapshots:
is-obj@2.0.0: {}
is-path-inside@3.0.3: {}
is-plain-obj@4.1.0: {}
is-potential-custom-element-name@1.0.1: {}
@@ -9154,6 +9139,8 @@ snapshots:
path-exists@4.0.0: {}
path-is-absolute@1.0.1: {}
path-key@3.1.1: {}
path-parse@1.0.7: {}
@@ -9381,6 +9368,10 @@ snapshots:
rfdc@1.4.1: {}
rimraf@3.0.2:
dependencies:
glob: 7.2.3
rollup@3.29.5:
optionalDependencies:
fsevents: 2.3.3
@@ -9763,6 +9754,8 @@ snapshots:
commander: 2.20.3
source-map-support: 0.5.21
text-table@0.2.0: {}
thread-stream@4.0.0:
dependencies:
real-require: 0.2.0
@@ -9815,6 +9808,8 @@ snapshots:
dependencies:
prelude-ls: 1.2.1
type-fest@0.20.2: {}
type-fest@0.7.1: {}
typed-array-buffer@1.0.3:
@@ -9850,13 +9845,13 @@ snapshots:
possible-typed-array-names: 1.1.0
reflect.getprototypeof: 1.0.10
typescript-eslint@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3):
typescript-eslint@8.54.0(eslint@8.57.1)(typescript@5.9.3):
dependencies:
'@typescript-eslint/eslint-plugin': 8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
'@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
'@typescript-eslint/eslint-plugin': 8.54.0(@typescript-eslint/parser@8.54.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3)
'@typescript-eslint/parser': 8.54.0(eslint@8.57.1)(typescript@5.9.3)
'@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3)
'@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
eslint: 9.39.2(jiti@2.6.1)
'@typescript-eslint/utils': 8.54.0(eslint@8.57.1)(typescript@5.9.3)
eslint: 8.57.1
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
@@ -10143,10 +10138,6 @@ snapshots:
yocto-queue@0.1.0: {}
zod-validation-error@4.0.2(zod@4.3.6):
dependencies:
zod: 4.3.6
zod@3.25.76: {}
zod@4.3.6: {}

View File

@@ -7,26 +7,36 @@ import { createCollection, createField, updateSettings } from "@directus/sdk";
const client = createMintelDirectusClient();
async function setupBranding() {
const prjName = process.env.PROJECT_NAME || "Mintel Project";
const prjName = process.env.PROJECT_NAME || "MB Grid Solutions";
const prjColor = process.env.PROJECT_COLOR || "#82ed20";
console.log(`🎨 Setup Directus Branding for ${prjName}...`);
console.log(`🎨 Refining Directus Branding for ${prjName}...`);
await ensureDirectusAuthenticated(client);
const cssInjection = `
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
body, .v-app { font-family: 'Inter', sans-serif !important; }
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700&display=swap');
body, .v-app { font-family: 'Outfit', sans-serif !important; }
.public-view .v-card {
backdrop-filter: blur(20px);
background: rgba(255, 255, 255, 0.9) !important;
border-radius: 32px !important;
box-shadow: 0 50px 100px -20px rgba(0, 0, 0, 0.4) !important;
border: 1px solid rgba(255, 255, 255, 0.3) !important;
}
.v-navigation-drawer { background: #000c24 !important; }
.v-list-item--active {
color: ${prjColor} !important;
background: rgba(130, 237, 32, 0.1) !important;
}
</style>
<div style="font-family: 'Inter', sans-serif; text-align: center; margin-top: 24px;">
<p style="color: rgba(255,255,255,0.7); font-size: 14px; margin-bottom: 4px; font-weight: 500;">MINTEL INFRASTRUCTURE ENGINE</p>
<h1 style="color: #ffffff; font-size: 18px; font-weight: 700; margin: 0;">${prjName.toUpperCase()} <span style="color: ${prjColor};">RELIABILITY.</span></h1>
<div style="font-family: 'Outfit', sans-serif; text-align: center; margin-top: 24px;">
<p style="color: rgba(255,255,255,0.6); font-size: 11px; letter-spacing: 2px; margin-bottom: 4px; font-weight: 600; text-transform: uppercase;">Mintel Infrastructure Engine</p>
<h1 style="color: #ffffff; font-size: 20px; font-weight: 700; margin: 0; letter-spacing: -0.5px;">${prjName.toUpperCase()} <span style="color: ${prjColor};">SYNC.</span></h1>
</div>
`;
@@ -36,24 +46,23 @@ async function setupBranding() {
project_name: prjName,
project_color: prjColor,
public_note: cssInjection,
module_bar_background: "#00081a",
theme_light_overrides: {
primary: prjColor,
borderRadius: "16px",
borderRadius: "12px",
navigationBackground: "#000c24",
navigationForeground: "#ffffff",
moduleBarBackground: "#00081a",
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any),
);
console.log("✨ Branding applied!");
try {
await createCollectionAndFields();
console.log("🏗️ Schema alignment complete!");
} catch (error) {
console.error("❌ Error aligning schema:", error);
}
await createCollectionAndFields();
console.log("🏗️ Schema alignment complete!");
} catch (error) {
console.error("❌ Error setting up branding:", error);
console.error("❌ Error during bootstrap:", error);
}
}
@@ -68,8 +77,11 @@ async function createCollectionAndFields() {
meta: {
icon: "contact_mail",
display_template: "{{name}} <{{email}}>",
group: null,
sort: null,
collapse: "open",
},
} as any),
}),
);
// Add ID field
@@ -82,27 +94,57 @@ async function createCollectionAndFields() {
}),
);
console.log(`✅ Collection ${collectionName} created.`);
} catch (e: any) {
console.log(` Collection ${collectionName} status: ${e.message}`);
} catch {
console.log(` Collection ${collectionName} exists.`);
}
const safeAddField = async (field: string, type: string, meta: any = {}) => {
const safeAddField = async (
field: string,
type: string,
meta: Record<string, unknown> = {},
) => {
try {
await client.request(createField(collectionName, { field, type, meta }));
console.log(`✅ Field ${field} added.`);
} catch (e: any) {
} catch {
// Ignore if exists
}
};
await safeAddField("name", "string", { interface: "input" });
await safeAddField("email", "string", { interface: "input" });
await safeAddField("company", "string", { interface: "input" });
await safeAddField("message", "text", { interface: "textarea" });
await safeAddField("name", "string", {
interface: "input",
display: "raw",
width: "half",
});
await safeAddField("email", "string", {
interface: "input",
display: "raw",
width: "half",
});
await safeAddField("company", "string", {
interface: "input",
display: "raw",
width: "half",
});
await safeAddField("message", "text", {
interface: "textarea",
display: "raw",
width: "full",
});
await safeAddField("date_created", "timestamp", {
interface: "datetime",
special: ["date-created"],
display: "datetime",
display_options: { relative: true },
width: "half",
});
}
setupBranding();
setupBranding()
.then(() => {
process.exit(0);
})
.catch((err) => {
console.error("🚨 Fatal bootstrap error:", err);
process.exit(1);
});

View File

@@ -1,15 +1,13 @@
#!/bin/bash
# Mintel Directus Sync Engine
# Synchronizes Directus Data (Postgres + Uploads) between Local and Remote
# Configuration
REMOTE_HOST="${SSH_HOST:-root@alpha.mintel.me}"
ACTION=$1
ENV=$2
# Help
if [ -z "$ACTION" ] || [ -z "$ENV" ]; then
echo "Usage: mintel-sync [push|pull] [testing|staging|production]"
echo "Usage: ./scripts/sync-directus.sh [push|pull] [testing|staging|production]"
echo ""
echo "Commands:"
echo " push Sync LOCAL data -> REMOTE"
@@ -20,7 +18,10 @@ if [ -z "$ACTION" ] || [ -z "$ENV" ]; then
exit 1
fi
PRJ_ID=$(jq -r .name package.json | sed 's/@mintel\///')
# Project Configuration (extracted from package.json and aligned with deploy.yml)
PRJ_ID=$(jq -r .name package.json | sed 's/@mintel\///' | sed 's/\.com$//')
REMOTE_DIR="/home/deploy/sites/${PRJ_ID}.com"
case $ENV in
testing) PROJECT_NAME="${PRJ_ID}-testing"; ENV_FILE=".env.testing" ;;
staging) PROJECT_NAME="${PRJ_ID}-staging"; ENV_FILE=".env.staging" ;;
@@ -28,41 +29,90 @@ case $ENV in
*) echo "❌ Invalid environment: $ENV"; exit 1 ;;
esac
REMOTE_DIR="/home/deploy/sites/${PRJ_ID}.com"
# DB Details
# DB Details (matching docker-compose defaults)
DB_USER="directus"
DB_NAME="directus"
echo "🔍 Detecting local database..."
LOCAL_DB_CONTAINER=$(docker compose ps -q directus-db)
if [ -z "$LOCAL_DB_CONTAINER" ]; then
echo "❌ Local directus-db container not found. Running?"
echo "❌ Local directus-db container not found. Is it running? (npm run dev)"
exit 1
fi
if [ "$ACTION" == "push" ]; then
echo "🚀 Pushing LOCAL -> $ENV ($PROJECT_NAME)..."
# 1. DB Dump
echo "📦 Dumping local database..."
docker exec "$LOCAL_DB_CONTAINER" pg_dump -U "$DB_USER" --clean --if-exists --no-owner --no-privileges "$DB_NAME" > dump.sql
# 2. Upload Dump
echo "📤 Uploading dump to remote server..."
scp dump.sql "$REMOTE_HOST:$REMOTE_DIR/dump.sql"
# 3. Restore on Remote
echo "🔄 Restoring dump on $ENV..."
REMOTE_DB_CONTAINER=$(ssh "$REMOTE_HOST" "cd $REMOTE_DIR && docker compose -p $PROJECT_NAME ps -q directus-db")
if [ -z "$REMOTE_DB_CONTAINER" ]; then
echo "❌ Remote $ENV-db container not found!"
exit 1
fi
echo "🧹 Wiping remote database schema..."
ssh "$REMOTE_HOST" "docker exec $REMOTE_DB_CONTAINER psql -U $DB_USER $DB_NAME -c 'DROP SCHEMA public CASCADE; CREATE SCHEMA public;'"
echo "⚡ Restoring database..."
ssh "$REMOTE_HOST" "docker exec -i $REMOTE_DB_CONTAINER psql -U $DB_USER $DB_NAME < $REMOTE_DIR/dump.sql"
# 4. Sync Uploads
echo "📁 Syncing uploads (Local -> $ENV)..."
rsync -avz --progress ./directus/uploads/ "$REMOTE_HOST:$REMOTE_DIR/directus/uploads/"
# Clean up
rm dump.sql
ssh "$REMOTE_HOST" "rm $REMOTE_DIR/dump.sql"
echo "✨ Push complete!"
# 5. Restart Directus to trigger migrations and refresh schema cache
echo "🔄 Restarting remote Directus to apply migrations..."
ssh "$REMOTE_HOST" "cd $REMOTE_DIR && docker compose -p $PROJECT_NAME restart directus"
echo "✨ Push to $ENV complete!"
elif [ "$ACTION" == "pull" ]; then
echo "📥 Pulling $ENV -> LOCAL..."
echo "📥 Pulling $ENV Data -> LOCAL..."
# 1. DB Dump on Remote
echo "📦 Dumping remote database ($ENV)..."
REMOTE_DB_CONTAINER=$(ssh "$REMOTE_HOST" "cd $REMOTE_DIR && docker compose -p $PROJECT_NAME ps -q directus-db")
if [ -z "$REMOTE_DB_CONTAINER" ]; then
echo "❌ Remote $ENV-db container not found!"
exit 1
fi
ssh "$REMOTE_HOST" "docker exec $REMOTE_DB_CONTAINER pg_dump -U $DB_USER --clean --if-exists --no-owner --no-privileges $DB_NAME > $REMOTE_DIR/dump.sql"
# 2. Download Dump
echo "📥 Downloading dump..."
scp "$REMOTE_HOST:$REMOTE_DIR/dump.sql" dump.sql
# 3. Restore Locally
echo "🧹 Wiping local database schema..."
docker exec "$LOCAL_DB_CONTAINER" psql -U "$DB_USER" "$DB_NAME" -c 'DROP SCHEMA public CASCADE; CREATE SCHEMA public;'
echo "⚡ Restoring database locally..."
docker exec -i "$LOCAL_DB_CONTAINER" psql -U "$DB_USER" "$DB_NAME" < dump.sql
# 4. Sync Uploads
echo "📁 Syncing uploads ($ENV -> Local)..."
rsync -avz --progress "$REMOTE_HOST:$REMOTE_DIR/directus/uploads/" ./directus/uploads/
# Clean up
rm dump.sql
ssh "$REMOTE_HOST" "rm $REMOTE_DIR/dump.sql"
echo "✨ Pull complete!"
echo "✨ Pull to Local complete!"
fi

View File

@@ -3,6 +3,6 @@ import { validateMintelEnv } from "@mintel/next-utils";
try {
validateMintelEnv();
console.log("✅ Environment variables validated");
} catch (error) {
} catch {
process.exit(1);
}