TypeScript 55.4%
Python 43.2%
SQL 1.2%
1import type { Metadata } from "next";2import Link from "next/link";3import { FieldChanges } from "@/components/field-changes";4import { LiveFeed } from "@/components/live-feed";5import { Badge, Chip, Empty, Flag, PageHeader, Panel, Score } from "@/components/ui";6import { api } from "@/lib/api";7import { agoIso, relTime, typeLabel, utcDateTime } from "@/lib/format";89export const dynamic = "force-dynamic";10export const metadata: Metadata = { title: "Silent changes", description: "Pricing, terms, API limits, documentation and product pages that changed quietly — no announcement matched. Previous state, current state, exact diff." };1112/** Dedicated silent-change experience (spec §23). */13export default async function SilentPage() {14 const [top, recent, count24] = await Promise.all([api.events({ silent_change: true, limit: 12, order: "signal", after: agoIso(48 * 3600e3) }), api.events({ silent_change: true, limit: 60 }), api.eventCount({ silent_change: true, after: agoIso(24 * 3600e3) })]);15 const byType = new Map<string, number>();16 for (const e of recent.items) byType.set(e.event_type, (byType.get(e.event_type) ?? 0) + 1);17 return (18 <>19 <PageHeader20 kicker={<span className="flex items-center gap-2"><Badge kind="silent" /> <span className="text-fg-subtle">{count24.count} in the last 24 h · first-party pages only · importance ≥ 45 · no matching announcement within 12 h</span></span>}21 title="Silent changes"22 description="Something was modified without an obvious public announcement: a price quietly changed, documentation rewritten, a feature removed, terms edited, an API limit adjusted, a product page gone. Each item shows the previous state, the current state and the exact diff."23 actions={<div className="flex flex-wrap gap-1">{[...byType.entries()].sort((a, b) => b[1] - a[1]).slice(0, 8).map(([t, n]) => <Chip key={t} href={`/live?silent_change=true&event_type=${t}`}>{typeLabel(t)} <span className="font-mono text-fg-subtle">{n}</span></Chip>)}</div>}24 />25 <Panel title="Most significant · 48 h" dense className="mb-4">26 {top.items.length === 0 ? (27 <Empty>No silent change detected in this period.</Empty>28 ) : (29 <ul className="grid gap-px bg-line md:grid-cols-2 xl:grid-cols-3">30 {top.items.map((e) => (31 <li key={e.id} className="flex flex-col gap-2 bg-panel p-3">32 <div className="flex items-center gap-2 text-[11px] text-fg-subtle">33 <Link href={`/source/${e.source?.id ?? e.source_id}`} className="truncate font-mono uppercase text-fg-muted hover:text-fg">{e.source?.name}</Link>34 {e.country && <Flag code={e.country} />}35 <Chip>{typeLabel(e.event_type)}</Chip>36 <span className="ml-auto whitespace-nowrap font-mono tabular" title={utcDateTime(e.detected_at)}>{relTime(e.detected_at)}</span>37 </div>38 <div className="flex items-start gap-2">39 <Score value={e.signal_score ?? e.importance} kind="signal" size="sm" />40 <Link href={`/event/${e.slug}`} className="font-medium leading-snug hover:underline">{e.title}</Link>41 </div>42 {e.field_changes?.length ? <FieldChanges items={e.field_changes} compact max={3} /> : <p className="line-clamp-3 text-[12px] text-fg-muted">{e.summary}</p>}43 <div className="mt-auto flex items-center gap-2 text-[11px]">44 <Link href={`/event/${e.slug}#diff`} className="text-info hover:underline">exact diff</Link>45 {e.old_snapshot_id && e.new_snapshot_id && <Link href={`/compare?a=${e.old_snapshot_id}&b=${e.new_snapshot_id}`} className="text-info hover:underline">before / after</Link>}46 <span className="ml-auto text-fg-subtle">{e.evidence_label}</span>47 </div>48 </li>49 ))}50 </ul>51 )}52 </Panel>53 <LiveFeed initial={recent.items} initialCursor={recent.nextCursor} fixed="silent" title="SILENT CHANGES · LIVE" showFilters={false} />54 </>55 );56}57