SPB Git forge

spb/rareindex

Public
54commits 1branches 0releases
7.1 MBsize
maindefault branch
10 days agolast push
TypeScript 61.9% HTML 37.2% SQL 0.7%
3.9 KB · 57 lines typescript
Raw Blame History
1/**2 * Live fixture capture for limitless-tcg: one English set list page (trimmed to 12 rows), one Japanese3 * set list page (no prices), and one card price-history payload.4 * Usage: pnpm tsx connectors/api/limitless-tcg/_capture.ts5 */6import { saveFixture } from '@rareindex/connectors/testing';7import { parseCardPage, parseSetIndex, parseSetList, type LimitlessPayload } from './index.js';8import { HTML_HEADERS, JSON_HEADERS } from '../_g1-cards-eu-jp-lib/index.js';910const SITE = 'https://limitlesstcg.com';11const text = async (u: string) => (await fetch(u, { headers: HTML_HEADERS })).text();12const wait = (ms: number) => new Promise((r) => setTimeout(r, ms));1314const en = parseSetIndex(await text(`${SITE}/cards`), 'en');15const meg = en.find((s) => s.code === 'MEG') ?? en[0]!;16await wait(1500);17const enList = parseSetList(await text(`${SITE}/cards/${meg.code}?display=list`));18const enPayload: LimitlessPayload = { type: 'set', set: { ...meg, name: enList.setName ?? meg.name }, cards: enList.cards.slice(0, 12) };19saveFixture('limitless-tcg', 'en-set-list', {20  raw: { url: `${SITE}/cards/${meg.code}?display=list`, externalId: `set:en:${meg.code}`, kind: 'catalog_item', engine: 'api', fetchedAt: new Date(), payload: enPayload },21  expect: { minCount: 12, kinds: ['catalog_item', 'price_observation'], requiredFields: ['attributes.set', 'attributes.number', 'attributes.identifiers.limitless_card'] },22  note: `Live capture ${new Date().toISOString().slice(0, 10)} — ${SITE}/cards/${meg.code}?display=list, first 12 of ${enList.cards.length} rows (USD via TCGplayer, EUR via Cardmarket relayed)`,23});24console.log('en', meg, enList.cards.length, enList.cards[0]);2526await wait(1500);27const jp = parseSetIndex(await text(`${SITE}/cards/jp`), 'jp');28const jset = jp.find((s) => s.code === 'M6') ?? jp[0]!;29await wait(1500);30const jpList = parseSetList(await text(`${SITE}/cards/jp/${jset.code}?display=list`));31const jpPayload: LimitlessPayload = { type: 'set', set: { ...jset, name: jpList.setName ?? jset.name }, cards: jpList.cards.slice(0, 8) };32saveFixture('limitless-tcg', 'jp-set-list-no-prices', {33  raw: { url: `${SITE}/cards/jp/${jset.code}?display=list`, externalId: `set:jp:${jset.code}`, kind: 'catalog_item', engine: 'api', fetchedAt: new Date(), payload: jpPayload },34  expect: { count: 8, kinds: ['catalog_item'], requiredFields: ['attributes.set', 'attributes.number'] },35  note: `Live capture ${new Date().toISOString().slice(0, 10)} — Japanese set ${jset.code}: list rows have empty USD/EUR cells, so catalog items only`,36});37console.log('jp', jset, jpList.cards.length, jpList.cards[0]);3839await wait(1500);40const card = enList.cards[0]!;41const cardHtml = await text(card.url);42const cp = parseCardPage(cardHtml);43await wait(1500);44const hist = (await (await fetch(`${SITE}/api/cards/${cp.cardId}/prices`, { headers: { ...JSON_HEADERS, referer: card.url } })).json()) as { tcgplayer: [number, number][]; cardmarket: [number, number][] };45const histPayload: LimitlessPayload = {46  type: 'history',47  set: { ...meg, name: enList.setName ?? meg.name },48  card: { number: card.number, name: cp.name ?? card.name, url: card.url, cardId: cp.cardId!, rarity: cp.rarity ?? card.rarity, image: cp.image ?? card.image, tcgplayerId: cp.tcgplayerId ?? card.usd?.tcgplayerId ?? null },49  history: { tcgplayer: hist.tcgplayer.slice(-20), cardmarket: hist.cardmarket.slice(-20) },50};51saveFixture('limitless-tcg', 'card-price-history', {52  raw: { url: card.url, externalId: `history:en:${meg.code}/${card.number}`, kind: 'price_observation', engine: 'api', fetchedAt: new Date(), payload: histPayload },53  expect: { minCount: 10, kinds: ['price_observation'], requiredFields: ['observationDate', 'attributes.number'] },54  note: `Live capture ${new Date().toISOString().slice(0, 10)} — ${SITE}/api/cards/${cp.cardId}/prices (last 20 points per provider; values are cents, timestamps epoch ms)`,55});56console.log('history', cp, hist.tcgplayer.length, hist.cardmarket.length);57