SEO: fix Search Console indexing, add provider comparisons + free DNS checker#159
SEO: fix Search Console indexing, add provider comparisons + free DNS checker#159leoisadev1 wants to merge 1 commit into
Conversation
…checker Search Console reports ~450 pages stuck in "Discovered/Crawled - currently not indexed" and duplicate-canonical states. Root cause: 450 old-version doc snapshots under /docs/v/<x> are prerendered, sitemap-listed, self-canonical, and fully crawlable, so Google sees ~10x near-duplicate content. Indexing fixes: - Old-version docs now emit <meta name="robots" content="noindex, follow"> - Sitemap lists only current-version docs (~500 -> ~82 URLs) - Real per-page lastmod from git history via a committed manifest (scripts/generate-docs-lastmod.ts), replacing a hardcoded date - robots.txt comment documents why /docs/v/ stays crawlable (noindex must be seen to work) - Frontmatter guard test: every docs page needs a unique 40-170 char description New keyword surfaces: - /compare + 14 curated provider comparison pages (resend-vs-postmark, sendgrid-vs-mailgun, ...) generated from the SDK's own SUPPORTED_MESSAGE_FIELDS capability matrix, with hand-written intros, fallback-compatibility analysis, code for both adapters, and FAQPage JSON-LD; reversed slugs 301 to the canonical order - /tools/email-dns-checker: free SPF/DKIM/DMARC/MX checker using DNS-over-HTTPS server-side, with provider hints linking back to adapter docs and WebApplication JSON-LD - Nav links, sitemap entries, and cross-links from adapter/auth docs SUPPORTED_MESSAGE_FIELDS is now exported from @opencoredev/email-sdk and snapshotted to a client-safe JSON (guarded by a sync test). Generated-By: PostHog Code Task-Id: d350c3df-f1aa-4b85-9ba9-1b16318cbde9
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis PR updates the docs site for SEO and adds new provider comparison and DNS-checking pages. The main changes are:
Confidence Score: 4/5Mostly safe after fixing the package-root export issue. The docs-site changes are scoped and covered by generated data/tests. The root SDK export can break browser bundling for apps importing
What T-Rex did
Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant User
participant Browser as Email SDK docs site
participant Server as React Start server function
participant CF as Cloudflare DoH
participant Google as Google DoH
User->>Browser: "Open /tools/email-dns-checker?domain=example.com"
Browser->>Server: checkEmailDnsServerFn(domain)
Server->>Server: Normalize domain and check cache/rate limit
par Resolve records
Server->>CF: TXT example.com
Server->>CF: TXT _dmarc.example.com
Server->>CF: MX example.com
Server->>CF: TXT selector._domainkey.example.com
end
alt Cloudflare unavailable
Server->>Google: Repeat failed DoH lookup
end
Server->>Server: Parse SPF, DKIM, DMARC, MX, and provider hints
Server-->>Browser: DnsCheckResult
Browser-->>User: Render findings and shareable URL
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant User
participant Browser as Email SDK docs site
participant Server as React Start server function
participant CF as Cloudflare DoH
participant Google as Google DoH
User->>Browser: "Open /tools/email-dns-checker?domain=example.com"
Browser->>Server: checkEmailDnsServerFn(domain)
Server->>Server: Normalize domain and check cache/rate limit
par Resolve records
Server->>CF: TXT example.com
Server->>CF: TXT _dmarc.example.com
Server->>CF: MX example.com
Server->>CF: TXT selector._domainkey.example.com
end
alt Cloudflare unavailable
Server->>Google: Repeat failed DoH lookup
end
Server->>Server: Parse SPF, DKIM, DMARC, MX, and provider hints
Server-->>Browser: DnsCheckResult
Browser-->>User: Render findings and shareable URL
Reviews (1): Last reviewed commit: "feat(seo): fix GSC indexing issues, add ..." | Re-trigger Greptile |
| @@ -1,4 +1,6 @@ | |||
| export { createEmailClient } from "./core.js"; | |||
| export { SUPPORTED_MESSAGE_FIELDS } from "./utils.js"; | |||
There was a problem hiding this comment.
Avoid Node-only root import
Exporting SUPPORTED_MESSAGE_FIELDS from the package root makes @opencoredev/email-sdk depend on ./utils.js, whose top-level node:fs/promises import is visible to browser/client bundlers. Web apps that import createEmailClient from the root can now fail to bundle because the root entry pulls in a Node builtin.
Artifacts
Repro: generated browser bundling harness
- Contains supporting evidence from the run (text/javascript; charset=utf-8).
Repro: generated entry importing only createEmailClient
- Contains supporting evidence from the run (text/javascript; charset=utf-8).
Repro: verbose esbuild browser bundle failure showing utils.js and node:fs/promises
- Keeps the command output available without making the summary code-heavy.
Why
Google Search Console shows ~450 pages not indexed (434 "Discovered – currently not indexed", 9 "Crawled – not indexed", 5 "Duplicate, Google chose different canonical"). Root cause: the 450 old-version doc snapshots under
/docs/v/<x>are prerendered, listed in the sitemap with a hardcodedlastmod, self-canonicalized, and fully crawlable — Google sees ~10x near-duplicate content and refuses to index most of it.This PR fixes the indexing issues and adds two new keyword surfaces built on data only this project has.
Indexing fixes
noindex, followon old-version docs (src/routes/docs/$.tsx): baked into the prerendered HTML, deduped against the globalindex, follow(verified single tag in build output). Old versions stay reachable via the version picker./docs/v/entries.lastmodvalues from git history viascripts/generate-docs-lastmod.ts→ committeddocs-lastmod.generated.json(Vercel shallow-clones, so the manifest is committed; regenerate withbun run lastmod:generate).Disallow: /docs/v/would stop Google from ever seeing the noindex; a comment documents this.New: /compare (14 provider comparison pages)
resend-vs-postmark,sendgrid-vs-mailgun,mailgun-vs-ses, … generated from the SDK's ownSUPPORTED_MESSAGE_FIELDScapability matrix (now exported from the package and snapshotted to client-safe JSON with a drift-guard test). Each page: hand-written 120+ word intro (enforced by test), field-support table, computed fallback-compatibility analysis, compilable code snippets for both adapters, FAQ with FAQPage JSON-LD. Unknown slugs 404; reversed slugs 301 invercel.json. Cross-linked from the 8 highest-traffic adapter docs.New: /tools/email-dns-checker
Free SPF / DKIM / DMARC / MX checker. DNS-over-HTTPS (Cloudflare → Google fallback) server-side, pure unit-tested parsers, per-instance rate limiting + 60s result cache, provider hints mapping SPF includes to adapter docs, WebApplication JSON-LD, ~500 words of explainer content.
?domain=URLs are shareable but always canonicalize to the bare tool URL. Smoke-tested against live DNS.Verification done
bun run build: sitemap has 82 URLs / 0/docs/v/, old-version pages carry exactly onenoindex, followmeta, current pages keepindex, follow, canonicals + JSON-LD present in prerendered HTMLbun test(56 pass),bun run check-types,bun run types:check,bun run checkall greenAfter merging — Google Search Console steps
https://email-sdk.dev/sitemap.xml/docs/v/…page → expect "Excluded by 'noindex' tag"vercel.jsondoc redirects — no actionDisallow: /docs/v/(optional, crawl-budget only)Created with PostHog Code