TypeScript 61.9%
HTML 37.2%
SQL 0.7%
1import { and, eq, lt, sql } from 'drizzle-orm';2import { connectors as connectorsTable, listingEvents, listings } from '@rareindex/database';3import { logger, newId } from '@rareindex/shared';4import { db } from './lib/db.ts';56/**7 * Listings not seen for 3× the connector refresh interval (min 3 days) are marked `removed`8 * (§171 change detection). They are kept for history; a later sighting re-opens them (relisted).9 */10export async function expireListings(): Promise<number> {11 const cons = await db().select({ id: connectorsTable.id, refresh: connectorsTable.refreshFrequencyMinutes }).from(connectorsTable);12 let n = 0;13 for (const c of cons) {14 const ttlMs = Math.max(3 * 86_400_000, c.refresh * 60_000 * 3);15 const cutoff = new Date(Date.now() - ttlMs);16 const stale = await db().select({ id: listings.id, price: listings.price, currency: listings.currency }).from(listings).where(and(eq(listings.connectorId, c.id), eq(listings.availability, 'available'), lt(listings.lastSeenAt, cutoff))).limit(5000);17 if (!stale.length) continue;18 await db().update(listings).set({ availability: 'removed', updatedAt: new Date() }).where(sql`${listings.id} in ${stale.map((s) => s.id)}`);19 await db().insert(listingEvents).values(stale.map((s) => ({ id: newId('event'), listingId: s.id, eventType: 'removed', oldPrice: s.price, currency: s.currency, occurredAt: new Date() })));20 n += stale.length;21 }22 if (n) logger.info({ expired: n }, 'listings expired');23 return n;24}25