Skip to content

fix(docs): replace linkinator with static broken link checker and fix 134 broken links#8103

Merged
steveruizok merged 5 commits intomainfrom
steve/static-broken-link-checker
Feb 28, 2026
Merged

fix(docs): replace linkinator with static broken link checker and fix 134 broken links#8103
steveruizok merged 5 commits intomainfrom
steve/static-broken-link-checker

Conversation

@steveruizok
Copy link
Copy Markdown
Collaborator

@steveruizok steveruizok commented Feb 27, 2026

In order to catch broken internal links before they ship (like the ones fixed in #8102), this PR replaces the linkinator-based HTTP crawler with a static checker that validates links against the content database. The old checker required a running server, couldn't fail the build, and missed most broken links. The new checker runs after refresh-everything and before next build, failing early if any broken links are found.

Along the way, this fixes all 134 broken internal links found across the docs:

  • 25 content files with stale /docs/* paths (should be /sdk-features/*), wrong heading anchors, double-prefixed paths, and renamed example links
  • API doc generator skipping TypeAlias/Interface namespace members (the // TODO: document these that caused T.Validatable etc. to generate broken links)
  • Namespace member path generation producing standalone paths like T-Validatable instead of anchor links like T#Validatable

The checker uses a --fail flag to control behavior: yarn check-links --fail (used in build) exits non-zero on broken links, while yarn check-links (used in dev) only warns. This ensures broken links never block the dev server from starting.

Additionally, this adds a standalone yarn check-external-links script for manually checking external (HTTP/HTTPS) links across all docs content. It deduplicates URLs, uses HEAD with GET fallback (30s timeout, 10 concurrent requests), and retries transient failures with backoff. A skip list filters out domains that block automated requests (npmjs.com, shadertoy.com). This replaces the external link checking that was previously handled by linkinator but is too slow/flaky for the build pipeline.

Also refactors the hardcoded Framer path prefixes into a shared fetchFramerPaths() utility that fetches the live Framer sitemap. Both the link checker and app/sitemap.ts now use this, so the list stays up to date automatically.

Fixes a broken external link to the removed custom-toolbar example in the v2.1.0 release notes.

Change type

  • improvement

Test plan

  1. cd apps/docs && yarn refresh-everything && yarn check-links — should pass with 0 broken links (warnings only)
  2. yarn check-links --fail — same result but would exit 1 if any broken links existed
  3. Manually add a broken link to a content file (e.g. [test](/nonexistent)) and run yarn check-links --fail — should exit 1 with the broken link reported
  4. Run yarn build from apps/docs — check-links runs with --fail before next build
  5. yarn check-external-links — checks all ~630 unique external URLs, reports broken ones
  • Unit tests
  • End to end tests

Release notes

  • Fix 134 broken internal links across SDK docs, starter kits, and API reference
  • Add static broken link checker to docs build pipeline (replaces linkinator)
  • Add standalone external link checker script (yarn check-external-links)
  • Document TypeAlias and Interface members within API reference namespaces

… 134 broken links

Rewrites the check-links script to validate internal links against
content.db instead of crawling a running server. Moves the check before
next build so broken links fail the build early. Fixes all 134 broken
links found across docs content, SDK features, starter kits, and
auto-generated API reference pages.

Key changes:
- checkBrokenLinks.ts: static DB-based checker that extracts links from
  article content and validates paths/anchors against the DB
- getApiMarkdown.ts: render TypeAlias/Interface namespace members on
  parent page instead of skipping them
- utils.ts: namespace members link as anchors on parent page instead of
  generating broken standalone paths
- 25 content files: fix stale /docs/* paths, wrong anchors, renamed examples
- package.json: run check-links before next build, remove linkinator
@huppy-bot huppy-bot bot added the improvement Product improvement label Feb 27, 2026
@vercel
Copy link
Copy Markdown

vercel bot commented Feb 27, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
examples Ready Ready Preview Feb 27, 2026 10:16am
tldraw-docs Ready Ready Preview Feb 27, 2026 10:16am
4 Skipped Deployments
Project Deployment Actions Updated (UTC)
analytics Ignored Ignored Preview Feb 27, 2026 10:16am
chat-template Skipped Skipped Feb 27, 2026 10:16am
tldraw-shader Skipped Skipped Feb 27, 2026 10:16am
workflow-template Skipped Skipped Feb 27, 2026 10:16am

Request Review

Pass --fail to check-links in the build script. Without --fail, broken
links are reported as warnings so they never block the dev server.
@steveruizok steveruizok requested review from MitjaBezensek and removed request for MitjaBezensek February 27, 2026 08:26
@steveruizok steveruizok marked this pull request as draft February 27, 2026 08:34
@steveruizok
Copy link
Copy Markdown
Collaborator Author

bot lost external link checking, re-steering

Add a standalone script to check external (HTTP/HTTPS) links across
docs content. Refactors extractLinks out of the internal checker so
both scripts share link extraction logic.

The external checker deduplicates URLs, uses HEAD with GET fallback,
10s timeout, and 10 concurrent requests. Run manually with
`yarn check-external-links` from apps/docs.
@steveruizok steveruizok added the maybe An idea, something to try and see label Feb 27, 2026
const fragment = hashIdx >= 0 ? url.slice(hashIdx + 1).toLowerCase() : null

// Empty path with fragment = same-page anchor
if (urlPath === '' && fragment) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure we can hit this part at all, we filter out fragment only links in extractInternalLinks.

Add a new empty content.db file to the repository as a placeholder for content database storage. The file is currently an empty blob and contains no data.
}

// Framer rewrite prefixes — any path starting with these is served externally
const FRAMER_PREFIXES = [
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have some logic for getting the framer sitemap here

async function fetchFramerSitemap(

We could use that instead so that we don't have stale values / have to update this when we add / remove framer pages.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done!

Introduce utils/framer-sitemap.ts to fetch and parse the Framer sitemap into a set of pathnames. Replace the previous inline XML parsing in apps/docs/app/sitemap.ts with fetchFramerPaths(), filter out root and docs-conflicting routes, and append Framer URLs to the docs sitemap. Update apps/docs/scripts/lib/checkBrokenLinks.ts to call fetchFramerPaths() at runtime and remove the hardcoded FRAMER_PREFIXES/isFramerPath logic, preventing maintenance of a stale prefix list and centralizing Framer sitemap handling.
@vercel vercel bot temporarily deployed to Preview – chat-template February 27, 2026 10:08 Inactive
@vercel vercel bot temporarily deployed to Preview – tldraw-shader February 27, 2026 10:08 Inactive
@vercel vercel bot temporarily deployed to Preview – workflow-template February 27, 2026 10:08 Inactive
@steveruizok steveruizok marked this pull request as ready for review February 28, 2026 13:36
@steveruizok steveruizok added this pull request to the merge queue Feb 28, 2026
Merged via the queue into main with commit 9892cdf Feb 28, 2026
19 checks passed
@steveruizok steveruizok deleted the steve/static-broken-link-checker branch February 28, 2026 13:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

improvement Product improvement maybe An idea, something to try and see

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants