3a113aaa8f
Pre-launch audit findings (frontend):
- trades: unlock private history in-page. TradesPageClient only read a CACHED
view envelope, so a connected user who hadn't visited Settings first saw
"load settings once to unlock" with no way forward. Added an explicit
"Unlock trade history" button that mints the view envelope via
getOrCreateViewEnvelope (one signature, no gas) and reloads — no detour.
- wagmi: broaden connector from injected({target:'metaMask'}) to generic
injected(). The MetaMask pin made Rabby / Coinbase ext / Brave / Frame / OKX
and non-MetaMask browsers fail to connect. wagmi v2 EIP-6963 discovery covers
all injected wallets; still uses the native provider path (not the MM SDK).
- sitemap: drop /settings. It was emitted in sitemap.xml while robots.ts
disallows it — a self-contradicting crawler signal. Private pages stay out
of both.
- docs: note the app runs on port 3001 (package.json), not 3000. The CLAUDE.md
verify sweep targeted 3000 and would have reported every page as down.
- routing: COMMIT the Next.js 16 migration that was sitting uncommitted —
delete middleware.ts, add root proxy.ts (next-intl createMiddleware), update
next-env.d.ts. Vercel deploys from git, so leaving proxy.ts untracked would
have shipped the old routing. `next build` confirms "Proxy (Middleware)" is
active and all routes compile. tsc clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
68 lines
2.4 KiB
TypeScript
68 lines
2.4 KiB
TypeScript
import type { MetadataRoute } from 'next'
|
|
|
|
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL
|
|
|
|
// In production, warn loudly but don't crash — the sitemap will use the
|
|
// fallback URL. Set NEXT_PUBLIC_SITE_URL in your deployment env to get the
|
|
// correct absolute URLs in sitemap.xml.
|
|
if (!siteUrl && process.env.NODE_ENV === 'production') {
|
|
console.warn(
|
|
'[sitemap] NEXT_PUBLIC_SITE_URL is not set — sitemap will use https://trumpsignal.com as fallback. ' +
|
|
'Set this env var in your deployment to avoid incorrect sitemap URLs.',
|
|
)
|
|
}
|
|
|
|
const base = (siteUrl || 'https://trumpsignal.com').replace(/\/$/, '')
|
|
|
|
const routes: Array<{
|
|
path: string
|
|
priority: number
|
|
freq: MetadataRoute.Sitemap[number]['changeFrequency']
|
|
}> = [
|
|
{ path: '', priority: 1.0, freq: 'hourly' },
|
|
{ path: '/trump', priority: 0.9, freq: 'hourly' },
|
|
{ path: '/macro', priority: 0.9, freq: 'daily' },
|
|
{ path: '/kol', priority: 0.9, freq: 'daily' },
|
|
{ path: '/trades', priority: 0.8, freq: 'daily' },
|
|
{ path: '/analytics', priority: 0.7, freq: 'daily' },
|
|
{ path: '/methodology', priority: 0.8, freq: 'monthly' },
|
|
{ path: '/glossary', priority: 0.8, freq: 'monthly' },
|
|
{ path: '/case-studies', priority: 0.8, freq: 'monthly' },
|
|
// NOTE: /settings is intentionally NOT listed — it's user-personalized and
|
|
// robots.ts disallows it. Listing it here while disallowing in robots is a
|
|
// self-contradicting signal to crawlers. Keep private pages out of both.
|
|
{ path: '/privacy', priority: 0.3, freq: 'yearly' },
|
|
{ path: '/terms', priority: 0.3, freq: 'yearly' },
|
|
{ path: '/contact', priority: 0.4, freq: 'monthly' },
|
|
]
|
|
|
|
// i18n shelved — only emit English routes. Add 'zh' back when content is
|
|
// actually translated (otherwise Google flags duplicate content under hreflang).
|
|
const locales = ['en']
|
|
|
|
export default function sitemap(): MetadataRoute.Sitemap {
|
|
const now = new Date()
|
|
const entries: MetadataRoute.Sitemap = []
|
|
|
|
// Root landing (not locale-scoped)
|
|
entries.push({
|
|
url: base,
|
|
lastModified: now,
|
|
changeFrequency: 'hourly',
|
|
priority: 1.0,
|
|
})
|
|
|
|
for (const locale of locales) {
|
|
for (const r of routes) {
|
|
entries.push({
|
|
url: `${base}/${locale}${r.path}`,
|
|
lastModified: now,
|
|
changeFrequency: r.freq,
|
|
priority: r.priority,
|
|
})
|
|
}
|
|
}
|
|
|
|
return entries
|
|
}
|