v3: comments say what the code can't — the documentation pass wanted JSDoc on every export and every field of an exported interface, which filled the code with restatements ("The dump.", "Whether it is loading.", "The props of X.", "Renders the X.") and module docs that told a reader nothing ("The hot and new feeds, and the props every main feed of the index takes."); some were wrong as well as vague. Every comment in api/, shared/ and src/ is rewritten under one rule, now stated in the README's "Comments" section: every module and export still has a JSDoc, and it gives context (who uses it and where), usage (what a caller must know: a precondition, what it leaves to the caller, a side effect) or its place in the chain (where its input comes from, where its output goes); a field, parameter, private function or local gets one only when it adds to its parent's, and context about a whole type goes on the type; a type's doc is phrased from the value's side ("Returned to Y by X when Z", "Passed to Y by X"); full sentences, as short as they can be, no label-colon-list; // goes wherever the code isn't obvious and says why, and the section banners and narration go. Every claim was checked against the code, which turned up some forty comments that were wrong: DumpCard's claimed it was only used by the hot and new feeds, the WebSocket welcome claimed to be a socket's first message (presence comes first), UpdateUserRequest said null removes a description (it keeps it), deletedDumpIds leaves out that it also holds dumps made private, THEME_COLOR claimed to mirror index.html's, and the like. The routers' JSDoc now says where they are mounted and what becomes of a thrown APIException. doc-lint.ts lets a field without a doc through; a module or export without one still fails. No code changes; 204 backend and 628 frontend tests pass, and doc:lint, deno check, deno lint and tsc are clean.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
khannurien
2026-09-29 14:31:14 +00:00
parent 42e0356d21
commit 0d4e344d77
287 changed files with 5679 additions and 5135 deletions

View File

@@ -1,5 +1,8 @@
/**
* Link previews: picks the provider for a URL and caches recent results.
* Fetches a link's preview through the provider that knows its site, and
* reuses it for a few minutes. `dump-service.ts` calls it when a link is
* posted, changed or refreshed, and `GET /api/preview` when the create form
* previews one.
*
* @module
*/
@@ -13,9 +16,9 @@ import { selfProvider } from "../remote/providers/self.ts";
import { genericProvider } from "../remote/providers/generic.ts";
/**
* The providers, in priority order. The first match wins.
* `selfProvider` resolves gerbeur URLs directly from the DB (no HTTP round-trip).
* `genericProvider` must stay last — it always matches.
* Lists the providers in priority order: the first that matches a URL reads
* it. `selfProvider` reads this site's own pages from the database, and
* `genericProvider` must stay last, since it matches every URL.
*/
const providers: RichContentProvider[] = [
youtubeProvider,
@@ -25,44 +28,51 @@ const providers: RichContentProvider[] = [
genericProvider,
];
/** The outcome of fetching a link's preview. */
/**
* Returned by {@link tryFetchRichContent} to `GET /api/preview`, which reports
* `ok` as `reached`, and to `refreshDumpMetadata`, which gives up when it is
* false.
*/
export interface FetchRichContentResult {
/**
* False when the page couldn't be reached at all, as opposed to reached and
* found to carry no metadata. Callers that already hold good metadata must
* not overwrite it with a failure stub.
* found to carry no metadata. A caller that already holds metadata must not
* overwrite it with the failure stub.
*/
ok: boolean;
/** The preview, or on failure a stub with just the URL and host. */
/**
* On failure, a stub holding the URL and its host name. Missing only when
* the URL doesn't parse.
*/
content?: RichContent;
}
/** How long a fetched preview is reused. */
const RECENT_TTL_MS = 5 * 60 * 1000;
/** The most previews kept; the oldest write goes first. */
/** How many previews are kept. The oldest written goes first. */
const RECENT_MAX = 200;
/**
* Previews fetched in the last few minutes, by URL. The create form previews a
* link and then posts it; without this the page was fetched twice, and the
* second fetch was the slow part of posting. Only successes are kept, and a
* metadata refresh (`fresh`) always goes to the page.
* Holds the previews fetched in the last few minutes, by URL. The create form
* previews a link and then posts it, and without this the second fetch of the
* page was the slow part of posting. Only successes are kept.
*/
const recent = new Map<
string,
{ at: number; result: Promise<FetchRichContentResult> }
>();
/** Forgets every cached preview (for the tests). */
/**
* Forgets every cached preview. The tests' `stubNetwork` calls it, since
* previews fetched from the previous stubbed network no longer apply.
*/
export function clearRichContentCache(): void {
recent.clear();
}
/**
* Fetches the preview of `url`, reporting whether the fetch itself succeeded.
* A preview fetched in the last five minutes is reused unless `fresh` is set.
*
* On failure it still yields a minimal stub so a *new* dump has something
* displayable, but `ok: false` lets callers with existing metadata keep it.
* Fetches the preview of `url`, and says whether the page could be reached. A
* preview fetched in the last five minutes is reused unless `fresh` is set, as
* a metadata refresh does. It never rejects: a failure resolves to a stub.
*/
export function tryFetchRichContent(
url: string,
@@ -86,7 +96,10 @@ export function tryFetchRichContent(
return result;
}
/** Fetches the preview of `url` through the first provider that matches. */
/**
* Fetches the preview of `url` through the first provider that matches, or
* makes the failure stub when the provider rejects.
*/
async function fetchRichContentUncached(
url: string,
): Promise<FetchRichContentResult> {
@@ -110,7 +123,11 @@ async function fetchRichContentUncached(
}
}
/** Returns the preview of `url`, or a minimal stub when it can't be fetched. */
/**
* Returns the preview of `url`, or a stub holding its host name when the page
* can't be reached. `createUrlDump` and `updateDump` use it for a new link,
* which has no earlier preview to keep.
*/
export async function fetchRichContent(
url: string,
): Promise<RichContent | undefined> {