← back to Commercialrealestate

scripts/capture-schema.js

52 lines

// capture-schema.js — load Crexi UI searches and dump the exact /universal-search/search
// request body (filter keys) + response (listing shape). One warm session, few navigations.
const fs = require('fs');
const path = require('path');
const { chromium } = require('playwright-core');
const Browserbase = require('@browserbasehq/sdk').default;

const skillEnv = fs.readFileSync(process.env.HOME + '/.claude/skills/browserbase/.env', 'utf8');
const get = (txt, k) => (txt.match(new RegExp('^' + k + '=(.*)$', 'm')) || [])[1]?.replace(/['"]/g, '').trim();
const bb = new Browserbase({ apiKey: get(skillEnv, 'BROWSERBASE_API_KEY') });
const RAW = path.join(__dirname, '..', 'data', 'raw');

(async () => {
  const session = await bb.sessions.create({ projectId: get(skillEnv, 'BROWSERBASE_PROJECT_ID'),
    browserSettings: { solveCaptchas: true, viewport: { width: 1440, height: 900 } } });
  console.log('bb session', session.id);
  const browser = await chromium.connectOverCDP(session.connectUrl);
  const ctx = browser.contexts()[0];
  const page = ctx.pages()[0] || await ctx.newPage();
  page.setDefaultTimeout(60000);

  const caps = [];
  page.on('response', async (resp) => {
    const u = resp.url();
    if (!u.includes('api.crexi.com/universal-search/search')) return;
    try {
      const reqBody = resp.request().postData();
      const body = await resp.json();
      caps.push({ url: u, reqBody, respKeys: Object.keys(body), sample: (body.data || body.results || body.assets || [])[0] || null,
        count: (body.data || body.results || body.assets || []).length });
      console.log(`  captured search → ${ (body.data||body.results||body.assets||[]).length } items`);
    } catch (_) {}
  });

  // A search URL that applies type + location text via Crexi's query params
  const urls = [
    'https://www.crexi.com/properties?types[]=Multifamily&placeName=Van%20Nuys,%20CA',
    'https://www.crexi.com/properties/CA/los-angeles',
  ];
  for (const url of urls) {
    console.log('→', url);
    await page.goto(url, { waitUntil: 'domcontentloaded' }).catch(e => console.log('  nav err', e.message.split('\n')[0]));
    await page.waitForTimeout(7000);
    await page.mouse.wheel(0, 3000).catch(()=>{});
    await page.waitForTimeout(3000);
  }
  fs.writeFileSync(path.join(RAW, 'search-capture.json'), JSON.stringify(caps, null, 2));
  console.log(`\n=== saved ${caps.length} /universal-search/search captures ===`);
  await browser.close().catch(()=>{});
  process.exit(0);
})().catch(e => { console.error('FATAL', e); process.exit(1); });