===== app/page.tsx ===== 'use client'; import { useEffect, useState } from 'react'; import { display, duration, inspect, number, ratio } from '../lib/metrics'; type Snapshot = { data: Record; fetchedAt: string }; const totals = [['totalJobs','Jobs posted'],['totalCompleted','Jobs completed'],['totalAgents','Registered agents'],['totalVolumeUsdc','Reported volume · USDC'],['escrowedUsdc','Currently escrowed · USDC']] as const; export default function Home() { const [snapshot,setSnapshot] = useState(null); const [error,setError] = useState(''); const [loading,setLoading] = useState(true); async function refresh() { setLoading(true); try { const r = await fetch('/api/stats', { cache:'no-store', signal:AbortSignal.timeout(12000) }); if (!r.ok) throw new Error(`The source returned HTTP ${r.status}.`); const next = await r.json(); if (!next.data || typeof next.data !== 'object' || Array.isArray(next.data)) throw new Error('The source returned an unexpected response.'); setSnapshot(next);setError(''); } catch(e) { setError(e instanceof Error?e.message:'The source could not be reached.'); } finally {setLoading(false);} } useEffect(()=>{void refresh();},[]); const s=snapshot?.data??{}; const share=ratio(s.totalCompleted,s.totalJobs); const warnings=inspect(s); return
POCKETLAB / OBSERVATORY

MOLTJOBS / PUBLIC MARKET DATA

A market, measured.

Live totals and the limits of what they tell us.

{snapshot?`${error?'Last good fetch':'Fetched'} ${new Date(snapshot.fetchedAt).toLocaleString()}`:'Waiting for the first response'}

{error&&
{snapshot?'STALE DATA — ':'DATA UNAVAILABLE — '}{error} {snapshot?'The last successful response remains below.':'No values have been substituted.'}
} {!snapshot&&!error&&

Reading the public API. Unknown values are shown as —.

}
{totals.map(([key,label],i)=>

{label}

{display(s[key])}{i===2?'Registration is not activity.':i===3?'API-reported; not net worker earnings.':i===4?'Not yet settled income.':'Cumulative count reported by the API.'}
)}

COMPLETION / CONTEXT

{share===null?'—':`${(share*100).toFixed(1)}%`}

Jobs marked completed

Completed jobs ÷ all posted jobs. This is a snapshot share, not the probability that a bid will earn money. It mixes jobs of different ages and states.

TWO DIFFERENT CLOCKS

How long does work take?

Reported durationMedianMean
Time to fill{duration(s.medianTimeToFillMs)}{duration(s.avgTimeToFillMs)}
Time to complete{duration(s.medianCompletionTimeMs)}{duration(s.avgCompletionTimeMs)}

Completion timing sample: {display(s.completionSampleSize)} jobs. Fill-time sample size and the measurement window are not supplied.

Mean and median can diverge when a few jobs take much longer. These figures do not predict when your job will be assigned or paid.

READ BEFORE COMPARING

What the feed leaves out

Disputes

Raw reported rate: {number(s.disputeRate)===null?'—':String(s.disputeRate)}. The endpoint does not expose its denominator, units, or inclusion rules. Zero does not establish zero risk.

Market activity

Registered agents need not be active. Total jobs need not be available. Volume should not be divided by registrations and presented as expected earnings.

Evidence

These are platform-reported totals. This page does not independently reconcile transactions on-chain or verify whether each completed job paid its worker.

{snapshot&&warnings.length>0&&

Data quality notes

    {warnings.map(w=>
  • {w}
  • )}
}
Inspect the raw response
{snapshot?JSON.stringify(snapshot.data,null,2):'No successful response yet.'}
; } ===== app/api/stats/route.ts ===== export async function GET() { try { const upstream=await fetch('https://api.moltjobs.io/v1/stats',{cache:'no-store',signal:AbortSignal.timeout(8000),headers:{Accept:'application/json'}}); if(!upstream.ok)return Response.json({error:'Statistics source unavailable'},{status:502,headers:{'Cache-Control':'no-store'}}); const body=await upstream.json(); if(!body.data||typeof body.data!=='object'||Array.isArray(body.data))return Response.json({error:'Unexpected statistics schema'},{status:502}); return Response.json({data:body.data,fetchedAt:new Date().toISOString()},{headers:{'Cache-Control':'no-store'}}); }catch{return Response.json({error:'Statistics fetch failed'},{status:502,headers:{'Cache-Control':'no-store'}});} } ===== lib/metrics.ts ===== export const number = (x: unknown): number|null => typeof x==='number'&&Number.isFinite(x)?x:null; export const display=(x:unknown)=>number(x)===null?'—':new Intl.NumberFormat('en-US',{maximumFractionDigits:4}).format(x as number); export function ratio(a:unknown,b:unknown):number|null {const n=number(a),d=number(b);return n===null||d===null||d<=0?null:n/d;} export function duration(x:unknown):string {const n=number(x);if(n===null||n<0)return '—';const h=n/3600000;return h>=48?`${(h/24).toFixed(2)} days`:`${h.toFixed(2)} hours`;} export function inspect(s:Record):string[]{ const notes:string[]=[]; for(const k of ['totalJobs','totalCompleted','totalAgents','totalVolumeUsdc','escrowedUsdc','avgCompletionTimeMs','medianCompletionTimeMs','avgTimeToFillMs','medianTimeToFillMs','completionSampleSize','disputeRate']){ const v=number(s[k]);if(v===null)notes.push(`${k} is missing or is not a finite number.`);else if(v<0)notes.push(`${k} is negative; do not interpret it as a valid count, duration, or amount.`); } const share=ratio(s.totalCompleted,s.totalJobs);if(share!==null&&share>1)notes.push('Completed jobs exceed total jobs. The visual bar is capped at 100%; the reported figures remain visible.'); const n=number(s.completionSampleSize);if(n!==null&&n<20)notes.push(`Completion timing is based on only ${n} observations. Treat comparisons cautiously.`); const skew=ratio(s.avgTimeToFillMs,s.medianTimeToFillMs);if(skew!==null&&skew>=3)notes.push(`Mean time to fill is ${skew.toFixed(1)}× its median. The feed does not include individual observations to explain the gap.`); return notes; } ===== app/globals.css ===== @import 'tailwindcss'; @import 'tw-animate-css'; @import 'shadcn/tailwind.css'; :root{--background:#0b1120;--foreground:#edf4fb;--card:#121e30;--primary:#60e5c1;--border:#2b3a50;--muted-foreground:#aebfd1;--radius:.5rem} *{box-sizing:border-box}body{margin:0;background:var(--background);color:var(--foreground);font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.6}main{max-width:1280px;margin:auto;padding:0 36px}a{color:inherit;text-underline-offset:4px}a:hover{color:#60e5c1}button{font:inherit;background:#60e5c1;color:#071921;border:0;border-radius:5px;padding:11px 20px;font-weight:700;cursor:pointer}button:disabled{opacity:.6;cursor:wait}:focus-visible{outline:3px solid #fbbf24;outline-offset:5px}header{display:flex;justify-content:space-between;gap:20px;align-items:center;border-bottom:1px solid var(--border);padding:26px 0}.brand{font:700 14px monospace;letter-spacing:.1em;text-decoration:none}.brand span{font-weight:400;color:#9cb0c6}nav{display:flex;gap:24px;font-size:14px}.intro{display:flex;justify-content:space-between;align-items:center;gap:30px;padding:52px 0 32px}.eyebrow{font:700 12px monospace;letter-spacing:.12em;color:#60e5c1;margin:0 0 12px}h1{font-size:clamp(32px,4.5vw,54px);letter-spacing:-.045em;line-height:1.1;margin:0 0 14px}h2{font-size:22px;line-height:1.35;margin:8px 0 22px;letter-spacing:-.02em}h3{font-size:16px;margin:0 0 8px}.lede{margin:0;color:#aebfd1;font-size:18px}.refresh{text-align:right;flex-shrink:0}.refresh p{font:12px monospace;color:#aebfd1;margin-top:12px}.totals{display:grid;grid-template-columns:repeat(5,1fr);border:1px solid var(--border);border-radius:8px;overflow:hidden}.metric{padding:24px 22px;border-right:1px solid var(--border);background:#101b2c}.metric:last-child{border:0}.metric p{font-size:14px;color:#bacbdc;margin:0 0 10px}.metric strong{font-family:monospace;font-size:34px;line-height:1.2;font-weight:500;display:block;font-variant-numeric:tabular-nums}.metric small{font-size:12px;color:#9ab0c7;display:block;margin-top:15px;line-height:1.5}.metric.highlight{background:#133a38}.metric.highlight strong{color:#86f4d8}.analysis{display:grid;grid-template-columns:.85fr 1.4fr;gap:24px;margin:24px 0}.panel{border:1px solid var(--border);border-radius:8px;background:#111b2c;padding:28px}.panel p{color:#b5c7da}.panel .eyebrow{color:#60e5c1}.big{font:500 54px/1.2 monospace;letter-spacing:-.05em}.completion h2{font-size:16px;margin-top:8px}.track{height:8px;background:#25364a;border-radius:5px;margin:24px 0}.track span{height:100%;display:block;background:#60e5c1;border-radius:5px}.completion p:last-child,.timing p,.caveats p{font-size:14px}.timing table{width:100%;border-collapse:collapse;font-size:14px}.timing th{text-align:left;font-weight:400}.timing td{text-align:right;font:16px monospace}.timing th:not(:first-child){text-align:right;color:#9eb4cb}.timing td,.timing th{padding:13px 0;border-bottom:1px solid var(--border)}.sample{background:#19273a;border-left:3px solid #60e5c1;padding:12px}.caveats{margin:24px 0}.caveat-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:30px}.notice{border-left:3px solid #f7c566;background:#342a1b;color:#f9e3b6;padding:16px 22px;margin:20px 0;font-size:14px}.notice h2{font-size:16px;margin:0 0 8px}.notice ul{padding-left:20px;list-style:disc;margin:0}.raw{border:1px solid var(--border);border-radius:8px;margin:24px 0}.raw summary{padding:18px 24px;cursor:pointer;color:#b5c7da;font-size:14px}pre{overflow:auto;padding:0 24px 24px;margin:0;font-size:13px}footer{border-top:1px solid var(--border);padding:20px 0 32px;display:flex;gap:20px;justify-content:space-between;color:#94a9c1;font-size:12px}b{color:#e9f3ff} @media(max-width:1000px){.totals{grid-template-columns:repeat(3,1fr)}.metric{border-bottom:1px solid var(--border)}.analysis{grid-template-columns:1fr 1.3fr}.intro{align-items:flex-start}.refresh{max-width:220px}} @media(max-width:700px){main{padding:0 18px}header{align-items:flex-start;flex-direction:column;padding:20px 0}nav{gap:24px}.intro{flex-direction:column;gap:20px;padding:32px 0}.refresh{text-align:left;max-width:100%}.totals{grid-template-columns:repeat(2,1fr)}.metric{padding:18px}.metric strong{font-size:30px}.analysis,.caveat-grid{grid-template-columns:1fr}.panel{padding:22px}.caveat-grid{gap:20px}footer{flex-direction:column;gap:0}.timing td{font-size:14px}.timing th{max-width:90px}.metric:last-child{grid-column:1/-1}} ===== app/layout.tsx ===== import type { Metadata } from 'next'; import './globals.css'; export const metadata: Metadata = {title:'MoltJobs Observatory | PocketLab',description:'Live marketplace totals, timing, and data quality caveats from the MoltJobs public API.'}; export default function RootLayout({children}:{children:React.ReactNode}){return {children};} ===== package.json ===== { "name": "sites-project", "version": "0.1.0", "private": true, "engines": { "node": ">=22.13.0" }, "scripts": { "dev": "vinext dev", "build": "vinext build", "start": "wrangler dev --config dist/server/wrangler.json", "lint": "oxlint", "format": "oxfmt" }, "dependencies": { "react": "19.2.6", "react-dom": "19.2.6", "react-server-dom-webpack": "19.2.6", "vinext": "1.0.0-beta.5", "@base-ui/react": "1.7.0", "@shadcn/react": "0.3.0", "class-variance-authority": "0.7.1", "clsx": "2.1.1", "cmdk": "1.1.1", "date-fns": "4.1.0", "embla-carousel-react": "8.5.2", "input-otp": "1.4.2", "lucide-react": "1.31.0", "react-day-picker": "9.8.1", "react-resizable-panels": "4.5.8", "recharts": "3.8.0", "shadcn": "4.18.0", "tailwind-merge": "3.6.0", "tw-animate-css": "1.4.0" }, "devDependencies": { "@cloudflare/vite-plugin": "1.37.1", "@cloudflare/workers-types": "4.20260515.1", "@openai/sites-vite-plugin": "0.2.0", "@tailwindcss/postcss": "4.2.1", "@types/node": "22.19.19", "@types/react": "19.2.14", "@types/react-dom": "19.2.3", "@vitejs/plugin-react": "6.0.2", "@vitejs/plugin-rsc": "0.5.26", "oxfmt": "0.61.0", "oxlint": "1.76.0", "oxlint-tsgolint": "7.0.2001", "tailwindcss": "4.2.1", "typescript": "5.9.3", "vite": "8.0.13", "wrangler": "4.92.0" }, "type": "module" }