Skip to content

Commit 63787f4

Browse files
authored
Merge pull request #19 from BjornMelin/feat/react-optimizations
feat: react + accessibility optimizations, bundle size reductions, GHA for Vercel preview branches
2 parents f1aba59 + 11dbe46 commit 63787f4

107 files changed

Lines changed: 5428 additions & 1205 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ AUTH_ALLOWED_EMAILS=
2626
NEXT_PUBLIC_AUTH_SOCIAL_PROVIDERS=vercel
2727

2828
# App base URL (used for server-to-server callbacks like QStash)
29+
# Recommended:
30+
# - local/development: http://localhost:3000
31+
# - production: https://<prod-domain>
32+
# - preview: branch-scoped value should be set in Vercel Preview env
33+
# (auto-managed by .github/workflows/vercel-preview-env-sync.yml).
2934
APP_BASE_URL=
3035

3136
# Database (Neon Postgres)
@@ -46,6 +51,9 @@ UPSTASH_VECTOR_REST_URL=
4651
QSTASH_CURRENT_SIGNING_KEY=
4752
QSTASH_NEXT_SIGNING_KEY=
4853
QSTASH_TOKEN=
54+
# Optional compatibility variable exposed by some integrations.
55+
# Not required by src/lib/env.ts.
56+
QSTASH_URL=
4957

5058
# Vercel AI Gateway
5159
AI_GATEWAY_API_KEY=
@@ -63,7 +71,8 @@ FIRECRAWL_API_KEY=
6371

6472
# Vercel Sandbox (Code Mode)
6573
VERCEL_OIDC_TOKEN=
66-
# Required for Vercel Sandbox access-token auth mode (typically local dev/CI)
74+
# Required for Vercel Sandbox access-token fallback mode (typically local dev/CI).
75+
# Also requires VERCEL_TOKEN (defined below) and optional VERCEL_TEAM_ID.
6776
VERCEL_PROJECT_ID=
6877

6978
# MCP / Context7 (optional: only if your MCP transport needs a key)
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
name: Preview (Vercel env cleanup)
2+
3+
on:
4+
pull_request:
5+
branches: ["main"]
6+
types: [closed]
7+
workflow_dispatch:
8+
inputs:
9+
gitBranch:
10+
description: "Git branch name (for manual runs)"
11+
required: true
12+
type: string
13+
14+
permissions:
15+
contents: read
16+
17+
concurrency:
18+
group: vercel-preview-env-cleanup-${{ github.workflow }}-${{ github.event.pull_request.head.ref || inputs.gitBranch || github.ref_name }}
19+
cancel-in-progress: true
20+
21+
jobs:
22+
cleanup:
23+
name: Remove branch-scoped APP_BASE_URL
24+
runs-on: ${{ fromJSON(vars.ACTIONS_RUNNER_LABELS || '["ubuntu-latest"]') }}
25+
steps:
26+
- name: Checkout
27+
uses: actions/checkout@v6.0.2
28+
29+
- name: Cleanup branch-scoped preview env
30+
env:
31+
FORK_PR: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork }}
32+
GIT_BRANCH_INPUT: ${{ inputs.gitBranch }}
33+
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
34+
VERCEL_TEAM_ID: ${{ secrets.VERCEL_TEAM_ID }}
35+
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
36+
run: |
37+
set -euo pipefail
38+
39+
if [ "${FORK_PR}" = "true" ]; then
40+
echo "::warning::Fork pull request detected. Skipping cleanup because GitHub Actions secrets are unavailable."
41+
exit 0
42+
fi
43+
44+
if [ -z "${VERCEL_PROJECT_ID:-}" ] || [ -z "${VERCEL_TOKEN:-}" ]; then
45+
echo "::warning::Missing required secrets (VERCEL_PROJECT_ID, VERCEL_TOKEN). Skipping cleanup."
46+
exit 0
47+
fi
48+
49+
if ! command -v jq >/dev/null 2>&1; then
50+
echo "::warning::jq is not available on this runner. Skipping cleanup."
51+
exit 0
52+
fi
53+
54+
GIT_BRANCH="${GITHUB_HEAD_REF:-}"
55+
if [ -z "${GIT_BRANCH}" ]; then
56+
GIT_BRANCH="${GIT_BRANCH_INPUT:-}"
57+
fi
58+
if [ -z "${GIT_BRANCH}" ]; then
59+
GIT_BRANCH="${GITHUB_REF_NAME}"
60+
fi
61+
62+
if [ -z "${GIT_BRANCH}" ]; then
63+
echo "::warning::Unable to resolve git branch. Skipping cleanup."
64+
exit 0
65+
fi
66+
67+
echo "Using git branch: ${GIT_BRANCH}"
68+
69+
VERCEL_API_BASE="https://api.vercel.com"
70+
VERCEL_TEAM_QUERY=""
71+
if [ -n "${VERCEL_TEAM_ID:-}" ]; then
72+
VERCEL_TEAM_QUERY="teamId=${VERCEL_TEAM_ID}"
73+
fi
74+
75+
vercel_api() {
76+
local method="$1"
77+
local path="$2"
78+
local data="${3:-}"
79+
local resp=""
80+
local curl_status=0
81+
82+
if [ -n "$data" ]; then
83+
resp="$(curl -sS -X "$method" "${VERCEL_API_BASE}${path}" \
84+
-H "Authorization: Bearer ${VERCEL_TOKEN}" \
85+
-H "Accept: application/json" \
86+
-H "Content-Type: application/json" \
87+
-d "$data" \
88+
-w '\n%{http_code}' 2>&1)"
89+
curl_status=$?
90+
else
91+
resp="$(curl -sS -X "$method" "${VERCEL_API_BASE}${path}" \
92+
-H "Authorization: Bearer ${VERCEL_TOKEN}" \
93+
-H "Accept: application/json" \
94+
-w '\n%{http_code}' 2>&1)"
95+
curl_status=$?
96+
fi
97+
98+
if [ $curl_status -ne 0 ]; then
99+
printf '%s\n' "${resp}"
100+
printf '%s\n' "000"
101+
return 0
102+
fi
103+
104+
printf '%s\n' "${resp%$'\n'*}"
105+
printf '%s\n' "${resp##*$'\n'}"
106+
}
107+
108+
ENV_LIST_PATH="/v10/projects/${VERCEL_PROJECT_ID}/env?decrypt=false"
109+
if [ -n "${VERCEL_TEAM_QUERY:-}" ]; then
110+
ENV_LIST_PATH="${ENV_LIST_PATH}&${VERCEL_TEAM_QUERY}"
111+
fi
112+
113+
ENV_LIST_RESP="$(vercel_api GET "${ENV_LIST_PATH}")"
114+
ENV_LIST_HTTP_CODE="$(printf '%s' "$ENV_LIST_RESP" | tail -n 1)"
115+
ENV_LIST_JSON="$(printf '%s' "$ENV_LIST_RESP" | sed '$d')"
116+
117+
if [ "${ENV_LIST_HTTP_CODE}" != "200" ]; then
118+
echo "::warning::Failed to list environment variables (HTTP ${ENV_LIST_HTTP_CODE}). Skipping cleanup."
119+
exit 0
120+
fi
121+
122+
MATCHING_IDS="$(printf '%s' "$ENV_LIST_JSON" | jq -r --arg key "APP_BASE_URL" --arg branch "${GIT_BRANCH}" '
123+
(.envs // [])[]
124+
| select(.key == $key and (.gitBranch // "") == $branch and ((.target // []) | index("preview")))
125+
| .id
126+
')"
127+
128+
if [ -z "${MATCHING_IDS}" ]; then
129+
echo "No branch-scoped APP_BASE_URL entries found for '${GIT_BRANCH}'."
130+
exit 0
131+
fi
132+
133+
FAILED_DELETIONS=0
134+
while IFS= read -r ENV_ID; do
135+
if [ -z "${ENV_ID}" ] || [ "${ENV_ID}" = "null" ]; then
136+
continue
137+
fi
138+
139+
DELETE_PATH="/v9/projects/${VERCEL_PROJECT_ID}/env/${ENV_ID}"
140+
if [ -n "${VERCEL_TEAM_QUERY:-}" ]; then
141+
DELETE_PATH="${DELETE_PATH}?${VERCEL_TEAM_QUERY}"
142+
fi
143+
144+
DELETE_RESP="$(vercel_api DELETE "${DELETE_PATH}")"
145+
DELETE_HTTP_CODE="$(printf '%s' "$DELETE_RESP" | tail -n 1)"
146+
147+
if [ "${DELETE_HTTP_CODE}" = "200" ] || [ "${DELETE_HTTP_CODE}" = "204" ]; then
148+
echo "Deleted APP_BASE_URL env var id: ${ENV_ID}"
149+
else
150+
echo "::warning::Failed to delete env var id ${ENV_ID} (HTTP ${DELETE_HTTP_CODE})."
151+
FAILED_DELETIONS=$((FAILED_DELETIONS + 1))
152+
fi
153+
done <<EOF
154+
${MATCHING_IDS}
155+
EOF
156+
157+
if [ "${FAILED_DELETIONS}" -gt 0 ]; then
158+
echo "::warning::Cleanup completed with ${FAILED_DELETIONS} deletion warning(s)."
159+
fi

0 commit comments

Comments
 (0)