UNPKG

@lineai/municipal-intel

Version:

AI-first municipal data API providing natural language descriptions of building permits and planning applications from major US cities

333 lines 26.6 kB
"use strict"; /** * Socrata API client for municipal data * Used by San Francisco, NYC, Oakland, Sacramento */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SocrataClient = void 0; const axios_1 = __importDefault(require("axios")); const base_client_1 = require("../base-client"); /** * Socrata API client */ class SocrataClient extends base_client_1.BaseMunicipalClient { constructor(config, params) { super(config); this.resetTime = Date.now() + 60000; // 1 minute from now if (!this.source.api || this.source.api.type !== 'socrata') { throw new Error('SocrataClient requires a source with api.type = "socrata"'); } this.appToken = config.appToken; this.params = params; // const apiSource = this.source.api as ApiSource; this.datasetConfig = this.source.api.datasets[params.datasetId || this.source.api.defaultDataset]; // Create axios instance this.api = axios_1.default.create({ baseURL: this.source.api.baseUrl, timeout: this.timeout, headers: Object.assign({ 'User-Agent': config.userAgent || 'municipal-intel/0.1.0' }, (this.appToken && { 'X-App-Token': this.appToken })) }); // Add response interceptor for error handling this.api.interceptors.response.use((response) => { return response; }, (error) => { var _a, _b, _c; if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 429) { const resetTime = this.resetTime; throw new base_client_1.RateLimitError(this.source.id, new Date(resetTime)); } throw new base_client_1.MunicipalDataError(error.message, this.source.id, (_b = error.response) === null || _b === void 0 ? void 0 : _b.status, (_c = error.response) === null || _c === void 0 ? void 0 : _c.data); }); } /** * Execute a SoQL query against a dataset */ async query(sq = {}) { const response = await this.api.get(this.datasetConfig.endpoint, { params: this.cleanParams(sq) }); this.log(`Retrieved ${response.data.length} records`); return response.data; } /** * Search for municipal projects */ async search() { var _a; const adjustments = []; const soqlQuery = this.buildSoQLQuery(adjustments); const data = await this.query(soqlQuery); const projects = data.map(item => this.normalizeProject(item)); // Get total count if needed let total = projects.length; if (this.params.limit && projects.length === this.params.limit) { const countQuery = Object.assign(Object.assign({}, soqlQuery), { $select: 'count(*) as total', $limit: 1, $order: undefined }); const countResult = await this.query(countQuery); total = parseInt(((_a = countResult[0]) === null || _a === void 0 ? void 0 : _a.total) || '0'); } return { projects, total, page: Math.floor((this.params.offset || 0) / (this.params.limit || 100)) + 1, pageSize: this.params.limit || 100, hasMore: total > (this.params.offset || 0) + projects.length, adjustments }; } /** * Get a project by its URL */ async getByUrl(url) { try { // Extract the ID from the URL const id = this.extractIdFromUrl(url); if (!id) { return null; } return this.getProject(id); } catch (error) { console.warn(`Error getting project by URL ${url}: ${error}`); return null; } } /** * Extract project ID from a municipal-intel URL */ extractIdFromUrl(url) { try { const urlObj = new URL(url); // Expected format: /projects/{sourceId}/{datasetId}/{projectId} const pathParts = urlObj.pathname.split('/'); if (pathParts.length >= 5 && pathParts[1] === 'projects') { return pathParts[4]; // Return the project ID part } return null; } catch (error) { return null; } } /** * Get a specific project by ID */ async getProject(id) { const idField = this.getIdField(); if (!idField) { throw new base_client_1.MunicipalDataError(`Missing field mapping for 'id' in source ${this.source.id}. Please add to fieldMappings in registry.`, this.source.id); } const query = { $where: `${idField} = '${id.replace(`${this.source.id}-`, '')}'`, $limit: 1 }; const data = await this.query(query); return data.length > 0 ? this.normalizeProject(data[0]) : null; } /** * Get available project types */ async getAvailableTypes() { const typeField = this.getTypeField(); if (!typeField) return []; const query = { $select: `distinct ${typeField}`, $limit: 1000 }; const data = await this.query(query); return data.map(item => item[typeField]).filter(Boolean); } /** * Check if the data source is healthy */ async healthCheck() { const startTime = Date.now(); try { // Simple health check - try to fetch one record const query = { $limit: 1 }; await this.query(query); const latency = Date.now() - startTime; return { status: 'healthy', latency, lastChecked: new Date() }; } catch (error) { const latency = Date.now() - startTime; return { status: 'unhealthy', latency, error: error.message, lastChecked: new Date() }; } } /** * Build SoQL query from search parameters */ buildSoQLQuery(adjustments = []) { const params = this.params; const query = { $limit: params.limit || 100, $offset: this.params.offset || 0, $order: this.buildOrderClause(params) }; const whereConditions = []; // Date filters if (params.submitDateFrom) { const field = this.getDateField('submit'); if (field) { this.validateDateParameter(params.submitDateFrom, 'submitDateFrom'); // Socrata doesn't like Z timezone indicator, remove it const dateString = params.submitDateFrom.toISOString().replace('Z', ''); whereConditions.push(`${field} >= '${dateString}'`); } } if (params.submitDateTo) { const field = this.getDateField('submit'); if (field) { this.validateDateParameter(params.submitDateTo, 'submitDateTo'); // Socrata doesn't like Z timezone indicator, remove it const dateString = params.submitDateTo.toISOString().replace('Z', ''); whereConditions.push(`${field} <= '${dateString}'`); } } // Value filters if (params.minValue) { const field = this.getValueField(); if (field) { // All Socrata sources store numeric values as text strings, requires casting whereConditions.push(`${field}::number >= ${params.minValue}`); } else { // No value field available - skip filter and record adjustment adjustments.push(`${this.source.id.toUpperCase()}: Skipped minValue filter - no value field available in dataset`); } } // Status filters if (params.statuses && params.statuses.length > 0) { const field = this.getStatusField(); if (field) { const statusList = params.statuses.map(s => `'${s}'`).join(','); whereConditions.push(`${field} in (${statusList})`); } } // Address filters if (params.addresses && params.addresses.length > 0) { const field = this.getAddressField(); if (field) { const addressConditions = params.addresses.map(addr => `upper(${field}) like upper('%${addr}%')`); whereConditions.push(`(${addressConditions.join(' OR ')})`); } } // Keywords if (params.keywords && params.keywords.length > 0) { const searchText = params.keywords.join(' '); query.$q = searchText; } if (whereConditions.length > 0) { query.$where = whereConditions.join(' AND '); } return query; } /** * Clean query parameters (remove undefined values) */ cleanParams(sq) { const cleaned = {}; for (const [key, value] of Object.entries(sq)) { if (value !== undefined && value !== null) { cleaned[key] = value; } } return cleaned; } /** * Build ORDER BY clause */ buildOrderClause(params) { const sortBy = params.sortBy || 'submitDate'; const order = params.sortOrder || 'desc'; const field = this.getFieldMapping(sortBy); if (!field) { // If field mapping not available, try to use a default field or skip ordering return `:created_at ${order}`; // Most Socrata datasets have this system field } return `${field} ${order}`; } /** * Get field mapping for this source (returns null if missing) */ getFieldMapping(logicalField) { var _a; const mappings = (_a = this.datasetConfig) === null || _a === void 0 ? void 0 : _a.fieldMappings; return (mappings === null || mappings === void 0 ? void 0 : mappings[logicalField]) || null; } // Placeholder methods - would be implemented per source getIdField() { return this.getFieldMapping('id'); } getTypeField() { return this.getFieldMapping('title'); } getDateField(type) { return type === 'submit' ? this.getFieldMapping('submitDate') : this.getFieldMapping('approvalDate'); } getValueField() { return this.getFieldMapping('value'); } getStatusField() { return this.getFieldMapping('status'); } getAddressField() { return this.getFieldMapping('address'); } /** * Normalize raw data to MunicipalProject using dataset-specific description */ normalizeProject(data) { var _a; // Get ID field for unique identifier const idField = this.getFieldMapping('id'); const id = idField ? data[idField] || 'unknown' : 'unknown'; // Use dataset-specific description method let description = 'Municipal Project'; if ((_a = this.datasetConfig) === null || _a === void 0 ? void 0 : _a.getDescription) { try { description = this.datasetConfig.getDescription(data); } catch (error) { console.warn(`Error generating description for ${this.source.id}: ${error}`); description = `${this.source.name} Record`; } } return { id: `${this.source.id}-${id}`, source: this.source.id, description, url: this.generateProjectUrl(id), rawData: data, lastUpdated: new Date() }; } /** * Generate a project URL for accessing full details */ generateProjectUrl(id) { var _a; const datasetId = this.params.datasetId || ((_a = this.source.api) === null || _a === void 0 ? void 0 : _a.defaultDataset) || 'default'; return `https://municipal-intel.lineai.com/projects/${this.source.id}/${datasetId}/${id}`; } /** * Validate that date parameter is a proper Date object */ validateDateParameter(dateParam, paramName) { if (!(dateParam instanceof Date)) { const actualType = Array.isArray(dateParam) ? 'array' : typeof dateParam; throw new base_client_1.MunicipalDataError(`Invalid ${paramName}: expected Date object, got ${actualType}. Use: new Date('2024-01-01') or new Date()`, this.source.id); } if (isNaN(dateParam.getTime())) { throw new base_client_1.MunicipalDataError(`Invalid ${paramName}: Date object contains invalid date. Check your date values.`, this.source.id); } } } exports.SocrataClient = SocrataClient; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2NsaWVudHMvc29jcmF0YS9jbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7R0FHRzs7Ozs7O0FBRUgsa0RBQTREO0FBSTVELGdEQUF3SDtBQXNCeEg7O0dBRUc7QUFDSCxNQUFhLGFBQWMsU0FBUSxpQ0FBbUI7SUFPcEQsWUFBWSxNQUEyQixFQUFFLE1BQTZCO1FBQ3BFLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUxDLGNBQVMsR0FBVyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsS0FBSyxDQUFDLENBQUMsb0JBQW9CO1FBTzNFLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEtBQUssU0FBUyxFQUFFO1lBQzFELE1BQU0sSUFBSSxLQUFLLENBQUMsMkRBQTJELENBQUMsQ0FBQztTQUM5RTtRQUVELElBQUksQ0FBQyxRQUFRLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQztRQUNoQyxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUNyQixrREFBa0Q7UUFDbEQsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLFNBQVMsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUdsRyx3QkFBd0I7UUFDeEIsSUFBSSxDQUFDLEdBQUcsR0FBRyxlQUFLLENBQUMsTUFBTSxDQUFDO1lBQ3RCLE9BQU8sRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPO1lBQ2hDLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTztZQUNyQixPQUFPLGtCQUNMLFlBQVksRUFBRSxNQUFNLENBQUMsU0FBUyxJQUFJLHVCQUF1QixJQUN0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