Major additions: - Multi-state expansion: states table, StateSelector, NationalDashboard, StateHeatmap, CrossStateCompare - Orchestrator services: trace service, error taxonomy, retry manager, proxy rotator - Discovery system: dutchie discovery service, geo validation, city seeding scripts - Analytics infrastructure: analytics v2 routes, brand/pricing/stores intelligence pages - Local development: setup-local.sh starts all 5 services (postgres, backend, cannaiq, findadispo, findagram) - Migrations 037-056: crawler profiles, states, analytics indexes, worker metadata Frontend pages added: - Discovery, ChainsDashboard, IntelligenceBrands, IntelligencePricing, IntelligenceStores - StateHeatmap, CrossStateCompare, SyncInfoPanel Components added: - StateSelector, OrchestratorTraceModal, WorkflowStepper 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
74 lines
2.9 KiB
TypeScript
74 lines
2.9 KiB
TypeScript
#!/usr/bin/env npx tsx
|
||
/**
|
||
* Discovery Entrypoint: Dutchie Cities (Auto)
|
||
*
|
||
* Attempts browser/API-based /cities discovery.
|
||
* Even if currently blocked (403), this runner preserves the auto-discovery path.
|
||
*
|
||
* Usage:
|
||
* npm run discovery:dt:cities:auto
|
||
* DATABASE_URL="..." npx tsx src/dutchie-az/discovery/discovery-dt-cities-auto.ts
|
||
*/
|
||
|
||
import { Pool } from 'pg';
|
||
import { DtCityDiscoveryService } from './DtCityDiscoveryService';
|
||
|
||
const DB_URL = process.env.DATABASE_URL || process.env.CANNAIQ_DB_URL ||
|
||
'postgresql://dutchie:dutchie_local_pass@localhost:54320/dutchie_menus';
|
||
|
||
async function main() {
|
||
console.log('╔══════════════════════════════════════════════════╗');
|
||
console.log('║ Dutchie City Discovery (AUTO) ║');
|
||
console.log('║ Browser + API fallback ║');
|
||
console.log('╚══════════════════════════════════════════════════╝');
|
||
console.log(`\nDatabase: ${DB_URL.replace(/:[^:@]+@/, ':****@')}`);
|
||
|
||
const pool = new Pool({ connectionString: DB_URL });
|
||
|
||
try {
|
||
const { rows } = await pool.query('SELECT NOW() as time');
|
||
console.log(`Connected at: ${rows[0].time}\n`);
|
||
|
||
const service = new DtCityDiscoveryService(pool);
|
||
const result = await service.runAutoDiscovery();
|
||
|
||
console.log('\n' + '═'.repeat(50));
|
||
console.log('SUMMARY');
|
||
console.log('═'.repeat(50));
|
||
console.log(`Cities found: ${result.citiesFound}`);
|
||
console.log(`Cities inserted: ${result.citiesInserted}`);
|
||
console.log(`Cities updated: ${result.citiesUpdated}`);
|
||
console.log(`Errors: ${result.errors.length}`);
|
||
console.log(`Duration: ${(result.durationMs / 1000).toFixed(1)}s`);
|
||
|
||
if (result.errors.length > 0) {
|
||
console.log('\nErrors:');
|
||
result.errors.forEach((e, i) => console.log(` ${i + 1}. ${e}`));
|
||
}
|
||
|
||
const stats = await service.getStats();
|
||
console.log('\nCurrent Database Stats:');
|
||
console.log(` Total cities: ${stats.total}`);
|
||
console.log(` Crawl enabled: ${stats.crawlEnabled}`);
|
||
console.log(` Never crawled: ${stats.neverCrawled}`);
|
||
|
||
if (result.citiesFound === 0) {
|
||
console.log('\n⚠️ No cities found via auto-discovery.');
|
||
console.log(' This may be due to Dutchie blocking scraping/API access.');
|
||
console.log(' Use manual seeding instead:');
|
||
console.log(' npm run discovery:dt:cities:manual -- --city-slug=ny-hudson --city-name=Hudson --state-code=NY');
|
||
process.exit(1);
|
||
}
|
||
|
||
console.log('\n✅ Auto city discovery completed');
|
||
process.exit(0);
|
||
} catch (error: any) {
|
||
console.error('\n❌ Auto city discovery failed:', error.message);
|
||
process.exit(1);
|
||
} finally {
|
||
await pool.end();
|
||
}
|
||
}
|
||
|
||
main();
|