// Pure query layer shared by the IndexStore Durable Object and the in-memory store (tests / node).
import { search, view, marketStats, OUR_HOSTS } from './engine.js';
/** tier: lite | preview | pick | market. Returns plain JSON (no rows beyond what the tier needs). */
export function queryIndex(rows, tier, v, nowS) {
const opts = { maxPrice: v.maxPrice ?? null, network: v.network ?? null, minPayers: v.minPayers ?? 0, nowS };
if (tier === 'market') {
const s = search(rows, v.need || '', { ...opts, limit: 0, perHost: 1e9 });
const hits = s.all;
const bySeller = new Map();
for (const h of hits) {
const r = h.r; if (r.p === null || r.p >= 5) continue;
const e = bySeller.get(r.h) || { host: r.h, service: r.s, resources: 0, calls_30d: 0, payers_30d_max: 0, est_revenue_30d_usd: 0, prices: [], ours: OUR_HOSTS.test(r.h) || undefined };
e.resources++; e.calls_30d += r.c || 0; e.payers_30d_max = Math.max(e.payers_30d_max, r.y || 0); e.est_revenue_30d_usd += (r.c || 0) * r.p; e.prices.push(r.p);
bySeller.set(r.h, e);
}
const sellers = [...bySeller.values()].map((e) => ({ ...e, est_revenue_30d_usd: Math.round(e.est_revenue_30d_usd * 100) / 100, price_range_usd: [Math.min(...e.prices), Math.max(...e.prices)], prices: undefined }))
.sort((a, b) => b.est_revenue_30d_usd - a.est_revenue_30d_usd);
const top = s.all.slice().sort((a, b) => ((b.r.y || 0) - (a.r.y || 0)) || ((b.r.c || 0) - (a.r.c || 0))).slice(0, v.limit || 10).map((h, i) => view(h, i + 1));
return { terms: s.terms, stats: marketStats(hits), top_sellers: sellers.slice(0, v.limit || 10), top_resources_by_payers: top, total_sellers: sellers.length };
}
const limit = tier === 'preview' ? 3 : tier === 'lite' ? 5 : 10;
const s = search(rows, v.need, { ...opts, limit });
const out = { terms: s.terms, matches: s.matches, hosts: s.hosts, results: s.top.map((h, i) => view(h, i + 1)) };
if (tier === 'pick') out.stats = marketStats(s.all);
return out;
}
agentgate-source: code mirror on Cloudflare Pages. All repos