feat(cache): single-owner caching across nginx, edge and content edits
Gitea Actions Runner Test / test-job (push) Successful in 0s
CI / check (push) Successful in 28s
CI / tests-unit (push) Successful in 1m39s
CI / tests-integration (push) Successful in 1m41s
CI / tests-ui (push) Successful in 2m27s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 3m35s

Rebuild production nginx from the repo (deployment/proxy/*) with a single
Cache-Control owner per route: the app stays the source, nginx only manages
headers, and Cloudflare stores the public API allowlist at the edge.

- deployment/proxy: nginx.conf, mime.types, nginx-cms.conf and the
  blue/green upstream snippet; config backed by scripts/nginx-sync.sh
  (idempotent install + reload, --check/--force).
- nginx serves Cache-Tag headers on the public allowlist (cms-public),
  gamedata, client and camera responses so the edge and purge stay in sync.
- src/lib/edge-cache.ts + tests: coalesced, fire-and-forget edge purges that
  no-op unless Cloudflare is configured; scripts/cf-purge.sh and
  cf-setup-cache.sh create and purge the cache rule.
- src/lib/cloudflare-api.ts: purgeCacheByTags/purgeCacheByUrls.
- Purge hooks after catalog exports (public + gamedata) and on shop, team,
  guild, photo and rare-values edits; ci-deploy purges after each release.
- src/proxy.ts excludes the imaging/images docs from the middleware matcher.
This commit is contained in:
openhands committed 2026-09-28 21:55:18 +02:00
1 parent 30dcecd530
commit 7697728d07
18 files changed
+1001 -1

No files matched your search

+64
View File
@@ -0,0 +1,64 @@
#!/usr/bin/env bash
# Purge the Cloudflare edge cache for one or more Cache-Tags.
#
# These tags are emitted by nginx (deployment/proxy/nginx-cms.conf):
# cms-public - de publieke API-allowlist (staff/teams/guilds/shop/values/…)
# cms-gamedata - /gamedata/ (furnidata, config)
# cms-client - /client/ + /nitro-client/ (game assets)
# cms-camera - /camera/
#
# Usage:
# scripts/cf-purge.sh cms-public
# scripts/cf-purge.sh cms-public cms-gamedata cms-client cms-camera
#
# Reads CLOUDFLARE_API_TOKEN / CLOUDFLARE_ZONE_ID from the environment or the
# repository .env. Fails loudly with a clear message when they are missing or
# still placeholders, so a pipeline either purges or aborts — never silently
# pretends it did.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ENV_FILE="$SCRIPT_DIR/../.env"
BASE="https://api.cloudflare.com/client/v4"
[[ $# -ge 1 ]] || { echo "usage: $0 <tag> [tag ...]" >&2; exit 64; }
TAGS=("$@")
load_env() {
local name="$1"
if [[ -n "${!name:-}" ]]; then
printf -v "$name" '%s' "${!name}"
return 0
fi
if [[ -f "$ENV_FILE" ]]; then
local line
line="$(grep -m1 "^$name=" "$ENV_FILE" | cut -d= -f2- | tr -d "'\"")" || true
if [[ -n "$line" ]]; then
printf -v "$name" '%s' "$line"
return 0
fi
fi
return 1
}
load_env CLOUDFLARE_API_TOKEN || { echo "error: CLOUDFLARE_API_TOKEN not configured" >&2; exit 1; }
load_env CLOUDFLARE_ZONE_ID || { echo "error: CLOUDFLARE_ZONE_ID not configured" >&2; exit 1; }
# Placeholder guard: the repo .env historically carried 2-char dummy values.
if [[ "${#CLOUDFLARE_API_TOKEN}" -lt 16 || "${#CLOUDFLARE_ZONE_ID}" -lt 16 ]]; then
echo "error: Cloudflare credentials look like placeholders; add a real token to .env" >&2
exit 1
fi
body="$(python3 -c 'import json,sys; print(json.dumps({"tags": sys.argv[1:]}))' "${TAGS[@]}")"
resp="$(curl -sS -m 20 -X POST \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
--data "$body" \
"$BASE/zones/$CLOUDFLARE_ZONE_ID/purge_cache")"
if ! python3 -c 'import json,sys; sys.exit(0 if json.load(sys.stdin).get("success") else 1)' <<<"$resp"; then
echo "error: Cloudflare purge failed: $resp" >&2
exit 1
fi
echo "purged tags: ${TAGS[*]}"
+125
View File
File diff suppressed because it is too large. Load diff
+6
View File
@@ -396,6 +396,12 @@ if [ "$secondary_backup_created" -eq 1 ]; then docker rm "$secondary_backup" ||
echo "Deployment verified: $sha"
# Een deploy kan de game client, furnidata (gamedata), camera en public API data
# verversen. Laat de Cloudflare edge-cache van die tags los (best-effort: alleen
# wanneer er een echte token + zone-id geconfigureerd is; no-op anders).
if [ -x "$deploy_dir/scripts/cf-purge.sh" ]; then
bash "$deploy_dir/scripts/cf-purge.sh" cms-public cms-gamedata cms-client cms-camera || true
fi
# Retain the current and previous releases; do not remove arbitrary named tags.
while IFS= read -r tag; do
if [[ "$tag" =~ ^epicnext-cms:(verified-)?[0-9a-f]{40}$ ]] && [ "$tag" != "$image" ] && [ "$tag" != "epicnext-cms:verified-$sha" ]; then
+110
View File
File diff suppressed because it is too large. Load diff