#!/bin/sh # Fetch the ECB euro reference rates and write content/rates.json. # # Feeds the indicative national-currency line on the order page ("โ‰ˆ CA$920 ยท # ECB reference rate 2026-08-04"). Indicative is the contract: every charge is # in euros, the buyer's bank sets the real conversion โ€” so build-time daily # reference rates are exactly the right freshness, and no rate service is ever # called at page-view time (nothing third-party runs against visitors). # # Values are emitted as INTEGER micro-units of target currency per euro # (1 EUR = 1.0834 USD -> 1083400), so the C++ side never parses a decimal and # no float ever touches a money path. # # Like fetch-posts.sh: exits 0 on network failure, leaving any previous # rates.json in place โ€” a stale indicative rate labelled with its date beats a # failed deploy. set -eu OUT="content/rates.json" URL="https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml" TMP="$(mktemp)" trap 'rm -f "$TMP"' EXIT if ! curl -fsSL --max-time 30 \ -A 'catcrafts.net-buildfetch/1.0 (+https://catcrafts.net)' \ "$URL" -o "$TMP" 2>/dev/null; then echo "fetch-rates: ECB unreachable; keeping existing $OUT" >&2 exit 0 fi # The XML is a flat list: under one # . The ECB emits single-quoted attributes today; # normalising quotes first keeps this working if they ever switch to double. tr "'" '"' < "$TMP" > "$TMP.n" && mv "$TMP.n" "$TMP" DATE=$(grep -o 'time="[0-9-]*"' "$TMP" | head -n1 | cut -d'"' -f2) if [ -z "$DATE" ]; then echo "fetch-rates: unexpected ECB payload; keeping existing $OUT" >&2 exit 0 fi RATES=$(grep -o 'currency="[A-Z]*" rate="[0-9.]*"' "$TMP" | awk -F'"' ' { cur = $2; rate = $4 # decimal -> integer micros, without floats: split on the point and # right-pad the fraction to exactly six digits. n = split(rate, parts, ".") intpart = parts[1] frac = (n > 1) ? parts[2] : "" frac = substr(frac "000000", 1, 6) micro = intpart frac # strip leading zeros (but keep at least one digit) sub(/^0+/, "", micro); if (micro == "") micro = "0" printf "%s\"%s\":%s", (out++ ? "," : ""), cur, micro }') if [ -z "$RATES" ]; then echo "fetch-rates: no rates parsed; keeping existing $OUT" >&2 exit 0 fi printf '{"date":"%s","micro_per_eur":{%s}}\n' "$DATE" "$RATES" > "$OUT.new" # Sanity: the file must parse and contain USD, or something upstream changed # shape and the old file is the safer one. if command -v jq >/dev/null 2>&1; then if ! jq -e '.micro_per_eur.USD > 500000' "$OUT.new" >/dev/null 2>&1; then echo "fetch-rates: output failed sanity check; keeping existing $OUT" >&2 rm -f "$OUT.new" exit 0 fi fi mv "$OUT.new" "$OUT" count=$(grep -o ':' "$OUT" | wc -l) echo "fetch-rates: wrote $OUT ($DATE, $((count - 1)) currencies)"