e85a2508e8
CI / update (push) Successful in 52s
Previous behavior silently deleted static/shopping/*.svg when SHOPPING_*_NUMBER env vars were unset, then rsync --delete propagated the deletion to the prod server — the loyalty buttons disappeared on deploys where the env didn't reach the build (or during the brief rm→write window of a parallel run). Now the script exits non-zero with a clear message; deploy.sh's set -e aborts before any destructive sync.
63 lines
2.1 KiB
TypeScript
63 lines
2.1 KiB
TypeScript
/**
|
|
* Build-time generation of loyalty-card barcode SVGs.
|
|
*
|
|
* Reads card numbers from env vars and writes static/shopping/supercard.svg
|
|
* + static/shopping/cumulus.svg. Fails the build if any required env is
|
|
* unset so deploys can't silently ship a broken UI.
|
|
*
|
|
* SHOPPING_COOP_SUPERCARD_NUMBER → Data Matrix (Coop Supercard)
|
|
* SHOPPING_MIGROS_CUMULUS_NUMBER → Code 128 (Migros Cumulus)
|
|
*
|
|
* Run: pnpm exec vite-node scripts/generate-loyalty-cards.ts
|
|
*/
|
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
import { dirname, resolve } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { toSVG } from 'bwip-js/node';
|
|
|
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
const OUT_DIR = resolve(HERE, '..', 'static', 'shopping');
|
|
|
|
type CardSpec = {
|
|
envVar: string;
|
|
filename: string;
|
|
bcid: 'datamatrix' | 'code128';
|
|
scale: number;
|
|
parsefnc?: boolean;
|
|
};
|
|
|
|
const cards: CardSpec[] = [
|
|
// Coop Supercard uses GS1 Data Matrix with FNC1 separators between fields.
|
|
// Put ^FNC1 in the env value wherever the real symbol has a separator
|
|
// (dmtxread -G prints them as 0x1D); parsefnc: true turns each ^FNC1 into
|
|
// a genuine FNC1 codeword so the regenerated code matches the card.
|
|
{ envVar: 'SHOPPING_COOP_SUPERCARD_NUMBER', filename: 'supercard.svg', bcid: 'datamatrix', scale: 6, parsefnc: true },
|
|
{ envVar: 'SHOPPING_MIGROS_CUMULUS_NUMBER', filename: 'cumulus.svg', bcid: 'code128', scale: 3 }
|
|
];
|
|
|
|
mkdirSync(OUT_DIR, { recursive: true });
|
|
|
|
const missing = cards.filter((c) => !process.env[c.envVar]?.trim()).map((c) => c.envVar);
|
|
if (missing.length) {
|
|
console.error(`[loyalty-cards] missing required env: ${missing.join(', ')}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
for (const card of cards) {
|
|
const value = process.env[card.envVar]!.trim();
|
|
const outPath = resolve(OUT_DIR, card.filename);
|
|
|
|
const svg = toSVG({
|
|
bcid: card.bcid,
|
|
text: value,
|
|
scale: card.scale,
|
|
includetext: false,
|
|
paddingwidth: 8,
|
|
paddingheight: 8,
|
|
...(card.parsefnc ? { parsefnc: true } : {})
|
|
});
|
|
|
|
writeFileSync(outPath, svg, 'utf8');
|
|
console.log(`[loyalty-cards] wrote ${card.filename} (${card.bcid})`);
|
|
}
|