@webgrip/astro-site-toolkit (0.3.0)
Installation
@webgrip:registry=npm install @webgrip/astro-site-toolkit@0.3.0"@webgrip/astro-site-toolkit": "0.3.0"About this package
@webgrip/astro-site-toolkit
Build-time guards and rigs shared by Webgrip Astro static sites. Extracted after the two sites' copies of the CSP validator diverged 125 vs 171 lines within a month — copy-reuse demonstrably fails for these; this package is reference-reuse.
Bins
webgrip-validate-csp [dist]— asserts every governed inline script AND stylesheet is authorised by its page's own meta CSP, per directive (a style-src hash cannot authorise a script). Wire into the build:"build": "astro build && webgrip-validate-csp".webgrip-serve-dist [dist]— serves dist/ with Cloudflare's auto-trailing-slash semantics and gzip, for Lighthouse rigs that must measure the site, not the server.PORT=0binds ephemerally; the bound port is printed.
Axe engine
// scripts/axe-scan.ts — the thin per-site file that stays in the consumer:
import { runAxeScan } from '@webgrip/astro-site-toolkit/axe-engine';
await runAxeScan({
// Pages that matter for a11y but carry no Lighthouse budget — with each
// site's own argued rationale. This is exactly the part that must NOT be
// shared.
a11yOnlyPages: ['/404.html'],
});
Ships TypeScript declarations (lib/axe-engine.d.mts), so a strict consumer needs no shims.
Peer deps (consumer installs): @axe-core/playwright, playwright-core. The page list is
read from lighthouserc.json so the two gates cannot drift apart.
Mail-auth drift
webgrip-validate-mail-auth [intent](defaultops/mail-auth.intent.yml) — reads a per-site intent file that declares, per domain, what should be published, and fails when the world disagrees: MX, SPF, DKIM key length, DMARC policy and report addresses, CAA, DNSSEC, and the MTA-STS policy (DNS records, served astext/plain, byte-identical to the repo copy). Exit 1 on drift, 2 without an intent file. Run it nightly from a scheduled workflow; wire it as"validate:mail-auth": "webgrip-validate-mail-auth".
Two things a generic checker gets wrong are decisions in the intent, not in the engine: a domain
whose spf is deliberately-absent fails when an SPF record appears, and a record that is
published while the intent still says published: false fails, so the declared state cannot
quietly fall behind the world. Steps the intent declares as not yet done are printed, not failed.
# ops/mail-auth.intent.yml
resolver: 8.8.8.8
mtaSts:
policyInRepo: public/.well-known/mta-sts.txt
policyUrl: https://mta-sts.example.nl/.well-known/mta-sts.txt
dnsRecordsPublished: true
domains:
example.nl:
mx: [smtp.google.com]
spf: v=spf1 include:_spf.google.com ~all
dkim:
- selector: google
keyCharacters: 408
dmarcPolicy: p=none
dmarcReportsTo: [dmarc@example.nl]
caa:
published: true
issuers: [letsencrypt.org]
dnssec:
dsPublished: true
mtaSts is optional; a site without a policy omits it. The engine is importable as
@webgrip/astro-site-toolkit/mail-auth (auditMailAuth(intent, lookups)), with lookups
injectable so a consumer can test its intent file against a fixture world without touching DNS.
Dependencies
Dependencies
| ID | Version |
|---|---|
| yaml | 2.9.0 |
Peer dependencies
| ID | Version |
|---|---|
| @axe-core/playwright | ^4.10.0 |
| playwright-core | ^1.50.0 |