diff --git a/src/auctions.ts b/src/auctions.ts index 24f38dd..0c867d2 100644 --- a/src/auctions.ts +++ b/src/auctions.ts @@ -1,7 +1,7 @@ import { Database } from 'bun:sqlite' import { mkdirSync } from 'node:fs' import { dirname } from 'node:path' -import { randomBytes } from 'node:crypto' +import { createHash, randomBytes } from 'node:crypto' import { Hono } from 'hono' import { RateLimiter } from './ratelimit.js' @@ -62,9 +62,14 @@ function validImage(type: string, bytes: Uint8Array): boolean { return false } +// The stylesheet URL carries a hash of its contents, so a browser never keeps an old copy +// after a deploy (a cached pre-theme stylesheet left the Blue switch doing nothing). +let cssVersion: string | undefined +const cssHref = () => `/style.css?v=${(cssVersion ??= createHash('sha256').update(AUCTIONS_CSS).digest('hex').slice(0, 12))}` + function page(theme: AuctionTheme, title: string, body: string, description = 'A home for art, artists and the stories behind every piece.', canonicalPath = '/') { return ` -${esc(title)} · Art Auctions +${esc(title)} · Art Auctions
AArt AuctionsTHE HOUSE FOR ORIGINAL WORK
${body}` } @@ -153,7 +158,7 @@ export function createAuctionApp(house: AuctionHouse) { c.header('set-cookie', `${THEME_COOKIE}=${name}; Path=/; Max-Age=31536000; SameSite=Lax; Secure`) return c.redirect(target, 303) }) - app.get('/style.css', (c) => c.body(AUCTIONS_CSS, 200, { 'content-type': 'text/css; charset=utf-8', 'cache-control': 'public, max-age=3600' })) + app.get('/style.css', (c) => c.body(AUCTIONS_CSS, 200, { 'content-type': 'text/css; charset=utf-8', 'cache-control': c.req.query('v') ? 'public, max-age=31536000, immutable' : 'no-cache' })) app.get('/image/:id', (c) => { const image = house.image(c.req.param('id')) if (!image) return c.text('Not found', 404) diff --git a/test/auctions.test.ts b/test/auctions.test.ts index 4826f72..0cd7ccd 100644 --- a/test/auctions.test.ts +++ b/test/auctions.test.ts @@ -90,7 +90,11 @@ describe('Art Auctions House', () => { expect(warm).toContain('data-theme="blue"') expect(warm).toContain('content="#eef3fa"') - const css = await (await app.fetch(new Request('https://auctions.pit.world/style.css'))).text() + const href = /