← back to Rentv Adintel
scripts/research.js
135 lines
#!/usr/bin/env node
'use strict';
/**
* CLI stub: node scripts/research.js <california|arizona|conferences>
*
* Wires to src/search/provider + src/adapters/manual-review IF present
* (guarded with try/require). When modules are unavailable, prints the
* manual search URLs that a human researcher should open instead.
*
* This is intentionally conservative — no live fetching from this stub
* (spec §6: no bypassing auth, robots, rate limits, or anti-bot controls).
*
* @module scripts/research
*/
require('../lib/env');
const MARKET = (process.argv[2] || '').toLowerCase();
if (!['california', 'arizona', 'conferences'].includes(MARKET)) {
console.error('Usage: node scripts/research.js <california|arizona|conferences>');
console.error('Valid markets: california, arizona, conferences');
process.exit(1);
}
// Try to load the real search provider module (may not exist yet)
let provider = null;
try {
provider = require('../src/search/provider');
} catch (_) {
// Not yet built — fall through to manual guidance
}
// Try to load the manual-review adapter
let manualReview = null;
try {
manualReview = require('../src/adapters/manual-review');
} catch (_) {
// Not yet built — fall through
}
// ---------------------------------------------------------------------------
// Manual research URL generators
// ---------------------------------------------------------------------------
/**
* Build the list of recommended manual search URLs for a given market.
* @param {'california'|'arizona'|'conferences'} market
* @returns {string[]}
*/
function manualSearchUrls(market) {
const rentv = 'https://rentv.com';
const rentvReview = 'https://rentvreview.com';
if (market === 'california') {
return [
`${rentv}/sponsors — RENTV CA sponsor pages`,
`${rentvReview}/advertisers — RENTV Review CA advertisers`,
'https://www.naiop.org/chapters/socal/events — NAIOP SoCal events & sponsors',
'https://www.boma.org/BOMA/Chapters/Greater_Los_Angeles/Events.aspx — BOMA LA sponsors',
'https://sccai.org/events — SCCAI OC/IE events',
'https://www.sfbart.com — SF Bay Area CRE events',
'Manual: search Google CSE for site:rentv.com "sponsor" OR "advertiser" california',
];
}
if (market === 'arizona') {
return [
`${rentv}/arizona — RENTV AZ market page`,
'https://www.naiop.org/chapters/az/events — NAIOP AZ events & sponsors',
'https://www.boma.org/BOMA/Chapters/Phoenix/Events.aspx — BOMA Phoenix sponsors',
'https://www.sior.com/events — SIOR Phoenix chapter',
'Manual: search Google CSE for site:rentv.com "sponsor" OR "advertiser" arizona',
];
}
// conferences
return [
'https://rentv.com/cre-talk — RENTV CRE Talk sponsors',
'https://www.naiop.org/events — NAIOP national conferences',
'https://www.bisnow.com/los-angeles/events — Bisnow LA sponsors',
'https://www.globest.com/events — GlobeSt CRE conference list',
'https://cretech.com/events — CREtech tech conference sponsors',
'https://www.corecnet.org/events — CoreNet Global chapters',
'Manual: search for "[event name] sponsors [year]" on Google',
];
}
// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------
(async () => {
console.log(`\n[research] Market: ${MARKET}`);
console.log('[research] Spec §6 compliance: no automated scraping of prohibited hosts.\n');
if (provider && typeof provider.runResearch === 'function') {
// Real provider is wired — delegate to it
console.log('[research] Using installed search provider:', provider.name || 'unknown');
try {
const result = await provider.runResearch({ market: MARKET });
console.log('[research] Results:', JSON.stringify(result, null, 2));
} catch (err) {
console.error('[research] Provider error:', err.message);
process.exit(1);
}
return;
}
if (manualReview && typeof manualReview.queueManualSearch === 'function') {
// Manual review adapter is wired — queue the search
console.log('[research] Manual review adapter found — queueing search items.');
try {
const queued = await manualReview.queueManualSearch({ market: MARKET });
console.log('[research] Queued', queued.count, 'manual review items.');
} catch (err) {
console.error('[research] Manual review adapter error:', err.message);
}
}
// Guidance output (always printed as a fallback / supplemental)
console.log('[research] Research modules not yet fully available.');
console.log('[research] Open these URLs manually in your browser to find advertiser evidence:\n');
const urls = manualSearchUrls(MARKET);
urls.forEach((u, i) => console.log(` ${i + 1}. ${u}`));
console.log('\n[research] After reviewing each page:');
console.log(' - Use the admin UI at /advertisers/new to add organizations.');
console.log(' - Use /ads/new to record ad sightings with source URLs.');
console.log(' - Use /events to record conference sponsor information.');
console.log('[research] All entries require a source_page_url and observed_at date.');
process.exit(0);
})();