← back to Delivery Address Fix
scripts/lib.js
107 lines
// Shared helpers for delivery-address scripts. Zero deps beyond playwright.
const fs = require('fs');
const path = require('path');
const PLATFORMS = {
ubereats: {
home: 'https://www.ubereats.com/',
login: 'https://auth.uber.com/v2/?next_url=https%3A%2F%2Fwww.ubereats.com%2Flogin-redirect',
// BOTH domains: ubereats.com is the logged-in surface, auth.uber.com the
// login flow — and 'uber.com' is NOT a substring of 'ubereats.com'
// (caught live by 5x sweep 2, 2026-08-02).
match: ['ubereats.com', 'auth.uber.com'],
emailField: '#PHONE_NUMBER_or_EMAIL_ADDRESS',
emailSubmit: '#forward-button',
},
doordash: {
home: 'https://www.doordash.com/',
login: 'https://identity.doordash.com/auth',
match: 'doordash.com',
emailField: 'input[type="email"]',
emailSubmit: 'button[type="submit"]',
},
instacart: {
home: 'https://www.instacart.com/',
login: 'https://www.instacart.com/login',
match: 'instacart.com',
emailField: 'input[type="email"]',
emailSubmit: 'button[type="submit"]',
},
};
// playwright isn't vendored (no node_modules in this repo) — fall back to the
// machine's global npm roots when a plain require can't resolve it.
function requirePlaywright() {
try { return require('playwright'); } catch (e) {
const roots = [
path.join(process.env.HOME || '', '.npm-global', 'lib', 'node_modules'),
'/opt/homebrew/lib/node_modules',
'/usr/local/lib/node_modules',
];
for (const r of roots) {
const p = path.join(r, 'playwright');
if (fs.existsSync(p)) return require(p);
}
console.error('playwright not resolvable: npm i -g playwright (or npm i playwright in this repo)');
process.exit(1);
}
}
function parseArgs(argv) {
const args = {};
for (let i = 2; i < argv.length; i++) {
const m = argv[i].match(/^--([a-z-]+)$/);
if (m) { args[m[1]] = argv[i + 1]; i++; }
}
return args;
}
function loadConfig() {
const p = path.join(__dirname, '..', 'config.json');
return fs.existsSync(p) ? JSON.parse(fs.readFileSync(p, 'utf8')) : {};
}
function platform(name) {
const p = PLATFORMS[name];
if (!p) { console.error(`Unknown platform "${name}". One of: ${Object.keys(PLATFORMS).join(', ')}`); process.exit(2); }
return p;
}
function sessionDir(cfg, args) {
const dir = args['session-dir'] || cfg.session_dir ||
path.join(__dirname, '..', 'sessions', `${(args.user || cfg.user_email || 'user').replace(/[@.]/g, '_')}-${args.platform || 'session'}`);
fs.mkdirSync(dir, { recursive: true });
return dir;
}
// HARD RULE: select the tab by URL substring, never pages()[0] — other
// automations share the browser (Tesla tab hijacked slot 0 on 2026-08-02).
async function findTab(port, match) {
// match: url substring, comma-separated substrings, or array of substrings
const candidates = (Array.isArray(match) ? match : String(match).split(','))
.map(s => s.trim()).filter(Boolean);
const { chromium } = requirePlaywright();
const browser = await chromium.connectOverCDP(`http://127.0.0.1:${port}`);
const pages = browser.contexts()[0].pages();
const page = pages.find(p => candidates.some(c => p.url().includes(c)));
if (!page) {
console.error(`NO TAB matching "${candidates.join(' | ')}". Open tabs: ${pages.map(p => p.url()).join(' | ')}`);
process.exit(2);
}
return { browser, page };
}
async function dumpState(page, dir, label) {
const shot = path.join(dir, `${label}-${Date.now()}.png`);
await page.screenshot({ path: shot }).catch(() => {});
console.log('URL:', page.url());
console.log('SHOT:', shot);
console.log(await page.evaluate(() => document.body.innerText.slice(0, 1000)));
const inputs = await page.evaluate(() =>
Array.from(document.querySelectorAll('input')).map(i =>
({ t: i.type, ph: i.placeholder, val: i.value ? '<set>' : '', vis: !!i.offsetParent })));
console.log('INPUTS:', JSON.stringify(inputs.filter(i => i.vis)));
}
module.exports = { PLATFORMS, parseArgs, loadConfig, platform, sessionDir, findTab, dumpState, requirePlaywright };