Render URL-only notes as rich link previews#27
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d0dff438d3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (!['http:', 'https:'].includes(parsed.protocol)) { | ||
| return null; | ||
| } | ||
|
|
||
| return parsed.toString(); |
There was a problem hiding this comment.
Reject private/internal URLs before fetching previews
normalizeUrl only enforces http(s) and then GET passes the result directly into buildWebPreview, so callers can request previews for hosts like localhost, RFC1918 ranges, or cloud metadata IPs. In any deployment where this function has internal network reachability, this creates an SSRF path that can probe or exfiltrate internal services. Add host/IP validation (including DNS resolution checks) before allowing server-side fetches.
Useful? React with 👍 / 👎.
| } finally { | ||
| clearTimeout(timeout); | ||
| } |
There was a problem hiding this comment.
Keep request timeout active while reading response body
The timeout is cleared as soon as fetch() returns a Response, but buildWebPreview then calls response.text() afterward. Since fetch resolves on headers, a target can send headers quickly and then stall/stream the body indefinitely, tying up the function until platform hard timeouts. Keep the abort timer active through body consumption (or enforce a body-size/read-time limit).
Useful? React with 👍 / 👎.
| .catch(() => null) | ||
| .then((preview) => { | ||
| linkPreviewCache.set(url, preview); | ||
| linkPreviewInflight.delete(url); |
There was a problem hiding this comment.
Do not cache failed preview lookups as completed
On any fetch/parsing error, loadLinkPreview converts the failure to null and stores that null in linkPreviewCache. ensureLinkPreview then sees the URL as cached and never retries, so transient failures permanently leave the card in a "Loading preview…" state until reload. Failed fetches should be retried (or cached with a short TTL/error state) instead of treated as a successful permanent result.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 88adb20ea5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| function findMetaContent(html, selectors) { | ||
| for (const selector of selectors) { | ||
| const regex = new RegExp(`<meta[^>]+${selector}[^>]+content=["']([^"']+)["'][^>]*>`, 'i'); |
There was a problem hiding this comment.
Parse meta tags regardless of attr order and apostrophes
The metadata extractor regex assumes the selected attribute appears before content and that the content value contains neither quote type (([^"']+)). In practice many pages emit tags like <meta content="..." property="og:description">, and descriptions often include apostrophes (e.g., Today's), so this code misses or truncates valid OG/Twitter metadata and produces degraded previews even when tags are present. Please make parsing attribute-order-independent and allow the opposite quote character inside quoted values.
Useful? React with 👍 / 👎.
Motivation
Description
http(s)URL notes on the client and render a preview block instead of plain transcription by addingextractSingleUrl,createUrlPreviewElement,ensureLinkPreview, and related logic inapp.jsand wiring it into the note card rendering flow.linkPreviewCacheandlinkPreviewInflightwithloadLinkPreviewto deduplicate in-flight requests and avoid duplicate network calls.GET /api/link-preview(api/link-preview.js) that normalizes/validates URLs, fetches Open Graph/Twitter meta for general pages, and uses Twitter oEmbed for tweet/status URLs to return a normalized preview payload.app.css(classes:.link-preview,.link-preview-title,.link-preview-excerpt,.link-preview-meta,.tweet-preview).Testing
npm test, which completed successfully and reported all tests passing (297/297tests passed and node/JS tests all OK).Codex Task