/** * capture-dl.mjs — record the live requests + responses for the Sandpoint "DL" * zone (ZoneID 113165 / SpaceID 329522 / CustomerID 217) so we have a durable * record of its odd flat-rate behavior. * * Writes one JSON file per call (request line with tokens redacted by the client * + the full parsed response) to ~/Downloads/dl-capture/ plus a _summary.json. * * Usage: node capture-dl.mjs (needs ./.creds.json) */ import { readFileSync, mkdirSync, writeFileSync } from 'node:fs'; import { homedir } from 'node:os'; import { join } from 'node:path'; import { ParkSmarterClient } from './dist/index.js'; const c = JSON.parse(readFileSync('./.creds.json', 'utf8')); const OUT = join(homedir(), 'Downloads', 'dl-capture'); mkdirSync(OUT, { recursive: true }); const reqLog = []; const ps = new ParkSmarterClient({ environment: 'prodv2', timeoutMs: 20000, logRequests: true, // the client redacts Auth_Token/Application_Token/SessionId logSink: (line) => reqLog.push(line), }); await ps.loginWithPhone({ phoneNumber: c.phoneNumber, password: c.password }); const me = await ps.getUserDetail(); const vehicleId = me?.VehicleDetails?.[0]?.VehicleID; const base = { zoneId: 113165, spaceId: 329522, customerId: 217, vehicleId }; const save = (name, obj) => writeFileSync(join(OUT, `${name}.json`), JSON.stringify(obj, null, 2) + '\n'); const summary = { zone: base, note: 'Sandpoint DL zone — flat $0.10, MaxTime = minutes until the paid-window boundary; ParkingEstimateMulti errors here.', calls: [] }; async function cap(name, fn) { const from = reqLog.length; let response = null, error = null; try { response = await fn(); } catch (e) { error = `${e.name} ${e.status ?? ''} ${e.message}`; } const entry = { name, capturedField: 'request+response', request: reqLog.slice(from), response, error }; save(name, entry); summary.calls.push({ name, ok: !error, error }); console.log(` ${name}: ${error ? 'ERR ' + error : 'ok'}`); } console.log(`Capturing DL zone -> ${OUT}`); // The zone/space/policy record (search for DL by name). await cap('00-zone-DL', async () => { const byName = await ps.getMetersByZoneName('DL'); const z = (byName?.Zones || []).find((z) => (z.ZoneId ?? z.ZoneID) == 113165) ?? byName?.Zones?.[0]; return z ?? { note: 'DL zone not found by name lookup' }; }); // Single-estimate at a spread of durations (shows the flat $0.10 + moving MaxTime). for (const d of [5, 15, 30, 60, 120, 240, 480]) { await cap(`10-estimate-single-${String(d).padStart(3, '0')}min`, () => ps.getParkingEstimateSingle({ ...base, durationInMinutes: d, creditCardId: 0 }), ); } // The multi ladder (errors for this zone) and the item-based estimate. await cap('20-estimate-multi', () => ps.getParkingEstimateMulti(base)); await cap('21-estimate-items', () => ps.getParkingEstimateItems(base)); summary.capturedAtLocalNote = 'timestamps are inside each request/response line'; save('_summary', summary); console.log(`Done. ${summary.calls.length + 1} files in ${OUT}`);