TypeScript 61.9%
HTML 37.2%
SQL 0.7%
1import 'server-only';2import { createHmac } from 'node:crypto';3import { IMAGE_WIDTHS, imageKey, type ImageWidth } from './images-core';45/**6 * Server-side helpers that turn a third-party image URL into signed `/img/…` proxy URLs.7 * Signing (HMAC over the URL with SESSION_SECRET) means only URLs the server chose to render8 * can be proxied — never arbitrary hosts.9 */10function secret(): string {11 return process.env.SESSION_SECRET ?? 'dev-only-session-secret-change-me-please';12}1314export function signImageUrl(url: string): string {15 return createHmac('sha256', secret()).update(`img:${url}`).digest('base64url').slice(0, 20);16}1718export function verifyImageSignature(url: string, sig: string): boolean {19 return sig.length >= 20 && signImageUrl(url) === sig;20}2122function b64url(s: string): string {23 return Buffer.from(s, 'utf8').toString('base64url');24}2526export function imgSrc(url: string, width: ImageWidth | number = 384, fmt: 'webp' | 'avif' = 'webp'): string {27 const key = imageKey(url);28 return `/img/${key}.${fmt}?w=${width}&u=${b64url(url)}&s=${signImageUrl(url)}`;29}3031export interface ImageProps {32 src: string;33 srcSet: string;34}3536/** `src` + `srcSet` for a responsive `<img>`; `maxWidth` trims useless large variants for thumbnails. */37export function imageProps(url: string | null | undefined, opts: { maxWidth?: number } = {}): ImageProps | null {38 if (!url || !/^https?:\/\//i.test(url)) return null;39 const max = opts.maxWidth ?? 1200;40 const widths = IMAGE_WIDTHS.filter((w) => w <= Math.max(96, max * 2));41 const list = widths.length ? widths : [IMAGE_WIDTHS[0]];42 return {43 src: imgSrc(url, list[Math.min(list.length - 1, Math.max(0, list.findIndex((w) => w >= max)))] ?? 384),44 srcSet: list.map((w) => `${imgSrc(url, w)} ${w}w`).join(', '),45 };46}47