← back to Patternbank Archive

src/browser.js

52 lines

require('dotenv').config({ path: require('path').join(__dirname, '..', '.env') });
const { chromium } = require('playwright-core');
const Browserbase = require('@browserbasehq/sdk').default;

const UA = process.env.USER_AGENT
  || 'patternbank-archive-internal/0.1 (research; contact: steve@designerwallcoverings.com)';

let _bb;
function bb() {
  if (_bb) return _bb;
  _bb = new Browserbase({ apiKey: process.env.BROWSERBASE_API_KEY });
  return _bb;
}

async function newSession() {
  const s = await bb().sessions.create({
    projectId: process.env.BROWSERBASE_PROJECT_ID,
    browserSettings: {
      solveCaptchas: true,
      blockAds: true,
    },
  });
  return s; // { id, connectUrl, ... }
}

async function withPage(fn) {
  const session = await newSession();
  const browser = await chromium.connectOverCDP(session.connectUrl);
  let ctx, page;
  try {
    ctx = browser.contexts()[0] || await browser.newContext();
    await ctx.setExtraHTTPHeaders({ 'User-Agent': UA });
    page = ctx.pages()[0] || await ctx.newPage();
    return await fn(page, session);
  } finally {
    try { await browser.close(); } catch {}
  }
}

async function fetchHtml(url, { waitFor='networkidle', timeout=45000 }={}) {
  return withPage(async (page) => {
    const resp = await page.goto(url, { waitUntil: waitFor, timeout });
    const status = resp ? resp.status() : 0;
    const html = await page.content();
    return { status, html, finalUrl: page.url() };
  });
}

const sleep = (ms) => new Promise(r => setTimeout(r, ms));

module.exports = { newSession, withPage, fetchHtml, sleep, UA };