Files
gerbeur/api/db/migrations/0011_split_favicon_thumbnail.ts
khannurien f3f07ed1e3
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 49s
Build and Deploy Static Documentation Site / build-and-push (push) Successful in 22s
v3: every doc opens with the role, then the mechanism, then the details — the docs were written bottom-up: what a thing does first ("Declares the three contexts WSProvider fills…"), details that only make sense once its purpose is known next, and the reason it exists last ("…so that a feed doesn't re-render"), so a reader had nothing to hang the first sentences on. The README's rule caused it, since a module doc "opened with what the module does"; it now opens with the module's role in the app, and the value-side phrasing of a type ("Returned to Y by X") comes once the role is said, with WSContext as the before and after. WSContext.ts is rewritten that way throughout, and so are the docs elsewhere that buried their purpose in a trailing "so that" (the migrations, og, image-proxy, public-address, useFading, useFeedCache, the drafts), opened on a generic verb that hid it ("Holds", "Declares", "Loads", "Defines", "Types": the contexts and providers, the shared types, the models, the hooks), or were label fragments ("The page of a dump…", "A row of tabs."). A function whose verb is its action ("Stores session"), a props or result type, and a protocol message ("Sent by X when Y") already say their role and are left as they are. Only comments changed, and the catalogs only move their references; deno fmt, deno lint and doc:lint are clean.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 21:42:08 +00:00

75 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Stops older dumps from showing a site's icon as their thumbnail. The metadata
* fetch used to fall back on the page's icon, and then on a guessed
* `/favicon.ico`, so most thumbnails were a 16×16 icon, or a 404, that the UI
* stretched over a 128×72 box. It now stops at real artwork, and a missing
* `thumbnailUrl` means none, which the frontend draws a placeholder for. This
* gives the older rows that meaning, by moving their icons out of
* `rich_content.thumbnailUrl` into the new `faviconUrl`.
*
* It judges the stored URL alone and fetches nothing, so it doesn't fill
* `accentColor`. The frontend derives a hue from the hostname when it is
* missing, and refreshing a dump's metadata fetches the real one.
*
* @module
*/
import type { DatabaseSync } from "node:sqlite";
/**
* Checks whether a stored thumbnail URL is a site icon. It is loose on
* purpose, since artwork taken for an icon still shows whole on a tinted field,
* only not cropped to fill the box. 0012 fixes the rows it got wrong.
*/
function isIconUrl(raw: string): boolean {
let pathname: string;
try {
pathname = new URL(raw).pathname;
} catch {
return false;
}
return /favicon|apple-touch-icon|\/icons?\//i.test(pathname) ||
/\.(ico|svg)$/i.test(pathname);
}
/**
* Run once by `runMigrations`. It leaves alone a row that already has a
* `faviconUrl`, and one whose `rich_content` doesn't parse. 0012 undoes its
* mistakes.
*/
export function up(db: DatabaseSync): void {
const rows = db.prepare(
`SELECT id, rich_content FROM dumps
WHERE kind = 'url' AND rich_content IS NOT NULL;`,
).all() as { id: string; rich_content: string }[];
const update = db.prepare(
`UPDATE dumps SET rich_content = ? WHERE id = ?;`,
);
let patched = 0;
for (const row of rows) {
let rich: { thumbnailUrl?: string; faviconUrl?: string };
try {
rich = JSON.parse(row.rich_content);
} catch {
continue;
}
if (rich.faviconUrl || !rich.thumbnailUrl) continue;
if (!isIconUrl(rich.thumbnailUrl)) continue;
const { thumbnailUrl: _dropped, ...rest } = rich;
update.run(
JSON.stringify({ ...rest, faviconUrl: rich.thumbnailUrl }),
row.id,
);
patched++;
}
if (patched > 0) {
console.log(
`[migrate] 0011: reclassified ${patched} favicon thumbnail(s)`,
);
}
}