Data & API Reference

AstroBlast has no server-side API. There are no application endpoints, no authentication, and no database. This page documents the static routes the distribution serves and the client-side data contract, which is the entirety of the application's data surface.

Hostnames

HostRoleCertificate
astroblast.andrewnorman.orgCanonical. Route 53 A and AAAA alias records to the distribution.ACM, DNS-validated, auto-renewing
<id>.cloudfront.netAlways reachable. Test against this when DNS is in doubt.CloudFront default

TLS terminates at CloudFront using SNI, with a minimum protocol version of TLSv1.2_2021 - CloudFront's strongest policy, which excludes every SHA-1 and CBC cipher suite. Plain HTTP is redirected, not served.

HTTP routes

All routes are GET only, served by CloudFront from an S3 origin. Any other method returns 405 from the origin path; unmatched paths are rewritten to the game page so a deep link never dead-ends.

RouteObjectTypeCacheDescription
GET /index.htmltext/htmlno-cache, must-revalidateThe game. Default root object.
GET /about.htmlabout.htmltext/htmlno-cache, must-revalidateProject description, dependencies, privacy.
GET /api.htmlapi.htmltext/htmlno-cache, must-revalidateThis page.
GET /sitemap.htmlsitemap.htmltext/htmlno-cache, must-revalidateHuman-readable site structure.
GET /sitemap.xmlsitemap.xmlapplication/xmlno-cache, must-revalidateMachine-readable sitemap.
GET /robots.txtrobots.txttext/plainno-cache, must-revalidateCrawler directives.
GET /<anything else>index.htmltext/html-403/404 from S3 is rewritten to /index.html with status 200.

HTML is served with a short revalidating cache so a redeploy is visible immediately; the CloudFront edge cache is additionally invalidated on every deploy.

Response headers

Applied by a CloudFront response headers policy on every response:

Strict-Transport-Security: max-age=63072000; includeSubDomains
Content-Security-Policy:   default-src 'self'; script-src 'self' 'unsafe-inline';
                           style-src 'self' 'unsafe-inline'; img-src 'self' data:;
                           connect-src 'none'; base-uri 'none'; form-action 'none';
                           object-src 'none'; frame-ancestors 'none'
X-Content-Type-Options:    nosniff
Referrer-Policy:           strict-origin-when-cross-origin

'unsafe-inline' is required because the game is deliberately a single self-contained document with an inline <script> and <style>. Since connect-src is 'none' and no external origin is reachable, the residual risk is confined to the document itself.

Client-side storage schema

BackendKeyTypeExampleLifetime
window.localStorageastroblast.highscoreinteger as string"24850"Until site data cleared

Reads and writes are wrapped in try/catch: in private-browsing modes or with site data blocked, the game runs normally and the high score is session-only.

Debug handle

The page exposes a small read/write handle on window for smoke tests and console debugging. It is not a stable interface and carries no compatibility guarantee.

window.AstroBlast = {
  version:   "1.0.0",
  G:         { state, score, wave, lives, high, ship, rocks[], bullets[], foes[], parts[] },
  CFG:       { dt, ship{}, bullet{}, rockSizes{}, wave{}, saucer{}, ... },
  startGame: function ()   // resets state and begins a new run
}

Example - drive a headless smoke test:

// in a browser console or Playwright page.evaluate()
AstroBlast.startGame();
AstroBlast.G.state;        // "playing"
AstroBlast.G.rocks.length; // 4 on wave 1

Extending with a real backend

A global leaderboard would add an Amazon API Gateway HTTP API in front of an AWS Lambda function writing to Amazon DynamoDB, fronted by the same distribution under a /api/* behaviour. That would require relaxing connect-src to 'self' and adding server-side score validation and rate limiting, since any client-submitted score is untrusted by construction. It is intentionally not built here.