feat: add debug script for inspecting raw API data per park+date
All checks were successful
Build and Deploy / Build & Push (push) Successful in 4m23s
All checks were successful
Build and Deploy / Build & Push (push) Successful in 4m23s
npm run debug -- --park greatadventure --date 2026-07-04 Prints the raw API response for that day alongside the parsed result so mismatched or missing hours can be traced to their source. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -97,6 +97,19 @@ async function fetchApi(url: string, attempt = 0, totalWaitedMs = 0): Promise<Ap
|
|||||||
return res.json() as Promise<ApiResponse>;
|
return res.json() as Promise<ApiResponse>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the raw API response for a month — used by scripts/debug.ts.
|
||||||
|
*/
|
||||||
|
export async function scrapeMonthRaw(
|
||||||
|
apiId: number,
|
||||||
|
year: number,
|
||||||
|
month: number
|
||||||
|
): Promise<ApiResponse> {
|
||||||
|
const dateParam = `${year}${String(month).padStart(2, "0")}`;
|
||||||
|
const url = `${API_BASE}/${apiId}?date=${dateParam}`;
|
||||||
|
return fetchApi(url);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch operating hours for an entire month in a single API call.
|
* Fetch operating hours for an entire month in a single API call.
|
||||||
* apiId must be pre-discovered via scripts/discover.ts.
|
* apiId must be pre-discovered via scripts/discover.ts.
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"scrape": "tsx scripts/scrape.ts",
|
"scrape": "tsx scripts/scrape.ts",
|
||||||
"scrape:force": "tsx scripts/scrape.ts --rescrape",
|
"scrape:force": "tsx scripts/scrape.ts --rescrape",
|
||||||
"discover": "tsx scripts/discover.ts"
|
"discover": "tsx scripts/discover.ts",
|
||||||
|
"debug": "tsx scripts/debug.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"better-sqlite3": "^12.8.0",
|
"better-sqlite3": "^12.8.0",
|
||||||
|
|||||||
111
scripts/debug.ts
Normal file
111
scripts/debug.ts
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/**
|
||||||
|
* Debug a specific park + date to inspect raw API data and parsed output.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* npm run debug -- --park greatadventure --date 2026-07-04
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { openDb, getApiId } from "../lib/db";
|
||||||
|
import { PARKS } from "../lib/parks";
|
||||||
|
import { scrapeMonthRaw } from "../lib/scrapers/sixflags";
|
||||||
|
|
||||||
|
function arg(flag: string): string | undefined {
|
||||||
|
const i = process.argv.indexOf(flag);
|
||||||
|
return i !== -1 ? process.argv[i + 1] : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fmt24(time: string): string {
|
||||||
|
const [h, m] = time.split(":").map(Number);
|
||||||
|
const period = h >= 12 ? "pm" : "am";
|
||||||
|
const h12 = h % 12 || 12;
|
||||||
|
return m === 0 ? `${h12}${period}` : `${h12}:${String(m).padStart(2, "0")}${period}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const parkId = arg("--park");
|
||||||
|
const dateStr = arg("--date");
|
||||||
|
|
||||||
|
if (!parkId || !dateStr) {
|
||||||
|
console.error("Usage: npm run debug -- --park <parkId> --date <YYYY-MM-DD>");
|
||||||
|
console.error("\nAvailable park IDs:");
|
||||||
|
for (const p of PARKS) console.error(` ${p.id.padEnd(24)} ${p.name}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const park = PARKS.find((p) => p.id === parkId);
|
||||||
|
if (!park) {
|
||||||
|
console.error(`Unknown park: "${parkId}"`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const match = dateStr.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
||||||
|
if (!match) {
|
||||||
|
console.error(`Invalid date: "${dateStr}" — expected YYYY-MM-DD`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
const [, yearStr, monthStr, dayStr] = match;
|
||||||
|
const year = parseInt(yearStr);
|
||||||
|
const month = parseInt(monthStr);
|
||||||
|
const day = parseInt(dayStr);
|
||||||
|
|
||||||
|
const db = openDb();
|
||||||
|
const apiId = getApiId(db, park.id);
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
if (apiId === null) {
|
||||||
|
console.error(`No API ID found for ${park.name} — run: npm run discover`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\nPark : ${park.name} (${park.id})`);
|
||||||
|
console.log(`API ID : ${apiId}`);
|
||||||
|
console.log(`Date : ${dateStr}`);
|
||||||
|
console.log(`\nFetching ${year}-${String(month).padStart(2, "0")} from API...\n`);
|
||||||
|
|
||||||
|
const raw = await scrapeMonthRaw(apiId, year, month);
|
||||||
|
|
||||||
|
// Find the specific day in the response
|
||||||
|
const targetDate = `${String(month).padStart(2, "0")}/${String(day).padStart(2, "0")}/${year}`;
|
||||||
|
const dayData = raw.dates.find((d) => d.date === targetDate);
|
||||||
|
|
||||||
|
if (!dayData) {
|
||||||
|
console.error(`Date ${dateStr} not found in API response.`);
|
||||||
|
console.log(`\nDates returned by API:`);
|
||||||
|
for (const d of raw.dates) console.log(` ${d.date}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Raw API response for this day ─────────────────────────────────────────
|
||||||
|
console.log("── Raw API response ─────────────────────────────────────────");
|
||||||
|
console.log(JSON.stringify(dayData, null, 2));
|
||||||
|
|
||||||
|
// ── Parsed result (what the scraper stores) ───────────────────────────────
|
||||||
|
console.log("\n── Parsed result ────────────────────────────────────────────");
|
||||||
|
const operating =
|
||||||
|
dayData.operatings?.find((o) => o.operatingTypeName === "Park") ??
|
||||||
|
dayData.operatings?.[0];
|
||||||
|
const item = operating?.items?.[0];
|
||||||
|
const hoursLabel =
|
||||||
|
item?.timeFrom && item?.timeTo
|
||||||
|
? `${fmt24(item.timeFrom)} – ${fmt24(item.timeTo)}`
|
||||||
|
: undefined;
|
||||||
|
const isOpen = !dayData.isParkClosed && hoursLabel !== undefined;
|
||||||
|
|
||||||
|
console.log(` isParkClosed : ${dayData.isParkClosed}`);
|
||||||
|
console.log(` operatings : ${dayData.operatings?.length ?? 0} entr${dayData.operatings?.length === 1 ? "y" : "ies"}`);
|
||||||
|
if (operating) {
|
||||||
|
console.log(` selected : "${operating.operatingTypeName}" (${operating.items?.length ?? 0} item(s))`);
|
||||||
|
if (item) {
|
||||||
|
console.log(` timeFrom : ${item.timeFrom} → ${fmt24(item.timeFrom)}`);
|
||||||
|
console.log(` timeTo : ${item.timeTo} → ${fmt24(item.timeTo)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(` hoursLabel : ${hoursLabel ?? "(none)"}`);
|
||||||
|
console.log(` isOpen : ${isOpen}`);
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((err) => {
|
||||||
|
console.error("Fatal:", err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user