Skip to content

fix(reporting): split "1 payment" into the three things it was confla… #187

fix(reporting): split "1 payment" into the three things it was confla…

fix(reporting): split "1 payment" into the three things it was confla… #187

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
quality:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- name: Install root dependencies
run: npm ci
- name: Install server dependencies
run: npm ci --prefix server
# Type-check the full Next.js project. Fast (~15s), catches API
# regressions that tests would miss.
- name: Typecheck
run: npm run typecheck
# Lint: error baseline is 0 as of Week 3 (2026-04-24). Warnings still
# permitted — ESLint exits 0 on warning-only runs, so this step passes
# until a real error regression slips in, at which point it blocks.
- name: Lint
run: npm run lint
# Full test suite: 508 vitest + 11 node:test = 519 assertions as of
# 2026-04-24. Covers color data, color utilities, collection prose lint,
# and the StoreKit JWS contract.
- name: Tests
run: npm test
# Smoke: make sure the production build still succeeds (catches breakage
# that only shows up at build time — static page generation, sitemap,
# Sentry source-map upload, etc.).
- name: Production build
run: npm run build
env:
NEXT_PUBLIC_SITE_URL: https://colorarchive.org
NEXT_PUBLIC_API_URL: https://api.colorarchive.org
# Sentry auth token is intentionally omitted in CI — source maps
# still upload from Vercel deploys where the token is set. Omitting
# here keeps CI from needing an org-level secret.
# The Figma plugin ships from this repo (figma-plugin/). All three bugs in
# the 2026-05-12 review rejection were of the "one CI command would have
# caught it" variety — this job is that command.
figma-plugin:
runs-on: ubuntu-latest
timeout-minutes: 10
defaults:
run:
working-directory: figma-plugin
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: figma-plugin/package-lock.json
- name: Install plugin dependencies
run: npm ci
# Type-check the main-thread source (src/code.ts) without emitting.
- name: Typecheck plugin
run: npx tsc --noEmit
# ui.html is not compiled — a syntax error in its inline <script> only
# surfaces at runtime inside Figma. Extract the script and parse it.
- name: Syntax-check ui.html script
run: |
node -e '
const fs = require("fs");
const html = fs.readFileSync("ui.html", "utf8");
const blocks = [...html.matchAll(/<script>([\s\S]*?)<\/script>/g)];
if (blocks.length === 0) { console.error("No <script> block found in ui.html"); process.exit(1); }
fs.writeFileSync("/tmp/ui-script.js", blocks.map(b => b[1]).join("\n;\n"));
'
node --check /tmp/ui-script.js
# The plugin UI iframe is a data: URL where localStorage ALWAYS throws
# SecurityError, and one unguarded touch at load kills the whole script
# (root cause of the 2026-05-12 rejection). Only the safe* wrapper
# definitions may reference it.
- name: Forbid bare localStorage in ui.html
run: |
BARE=$(grep -nE 'localStorage\s*\.' ui.html | grep -vE 'function safe(Get|Set|Remove)Item' || true)
if [ -n "$BARE" ]; then
echo "::error::Bare localStorage usage in ui.html — route it through the safe* wrappers (see figma-plugin/README.md):"
echo "$BARE"
exit 1
fi
echo "OK: no bare localStorage usage outside safe* wrappers"