UNPKG

@lineai/municipal-intel

Version:

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

287 lines 20.2 kB
"use strict"; /** * @lineai/municipal-intel * * Access municipal planning applications, building permits, and construction * activity data from major US cities. */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createMunicipalIntel = exports.MunicipalIntel = void 0; // Types __exportStar(require("./types"), exports); // Clients __exportStar(require("./clients"), exports); // Registry __exportStar(require("./registry"), exports); // Main API class const clients_1 = require("./clients"); const registry_1 = require("./registry"); /** * Main municipal intelligence API */ class MunicipalIntel { constructor(config = {}) { this.clientFactory = new clients_1.ClientFactory(config); this.registry = registry_1.sourceRegistry; } /** * Search municipal projects */ async search(params) { let source; if (params.municipalityId) { // Search specific municipality const foundSource = this.registry.getSource(params.municipalityId); if (!foundSource) { throw new Error(`Municipality not found: ${params.municipalityId}`); } source = foundSource; } else { // Default to first available source if no municipality specified const sources = this.registry.getImplementationReadySources(); if (sources.length === 0) { throw new Error('No available sources for search'); } source = sources[0]; } const client = this.clientFactory.createClient(source, params); return client.search(); } /** * Get a project by ID from a specific source */ async getProject(sourceId, projectId) { const source = this.registry.getSource(sourceId); if (!source) { throw new Error(`Source not found: ${sourceId}`); } // Create minimal params for getProject - we only need the municipalityId const params = { municipalityId: sourceId }; const client = this.clientFactory.createClient(source, params); return client.getProject(projectId); } /** * Get a project by its URL */ async getByUrl(url) { const sourceId = this.extractSourceFromUrl(url); if (!sourceId) { throw new Error(`Cannot determine source from URL: ${url}`); } const source = this.registry.getSource(sourceId); if (!source) { throw new Error(`Source not found: ${sourceId}`); } const params = { municipalityId: sourceId }; const client = this.clientFactory.createClient(source, params); return client.getByUrl(url); } /** * Extract source ID from municipal-intel URL */ extractSourceFromUrl(url) { try { const urlObj = new URL(url); // Expected format: /projects/{sourceId}/{datasetId}/{projectId} const pathParts = urlObj.pathname.split('/'); if (pathParts.length >= 4 && pathParts[1] === 'projects') { return pathParts[2]; // Return the sourceId part } return null; } catch (error) { return null; } } /** * Get available municipalities with their datasets (AI Discovery API) */ getAvailableMunicipalities() { const sources = this.registry.getAllSources(); return sources.map(source => { var _a; return ({ id: source.id, name: source.name, state: source.state, datasets: ((_a = source.api) === null || _a === void 0 ? void 0 : _a.datasets) ? Object.entries(source.api.datasets).map(([id, dataset]) => ({ id, name: dataset.name })) : [] }); }); } /** * Get search capabilities for a municipality */ getSearchCapabilities(municipalityId) { var _a, _b, _c; const source = this.registry.getSource(municipalityId); if (!source) { throw new Error(`Municipality not found: ${municipalityId}`); } // For now, return capabilities based on what our Socrata client supports // This could be enhanced to be source-specific const supportedFilters = ['submitDateFrom', 'submitDateTo', 'statuses', 'addresses', 'keywords']; const supportedSorts = ['submitDate', 'address']; const limitations = []; // Check if value field is available for value filters if ((_a = source.api) === null || _a === void 0 ? void 0 : _a.datasets) { const primaryDataset = Object.values(source.api.datasets)[0]; if ((_b = primaryDataset === null || primaryDataset === void 0 ? void 0 : primaryDataset.fieldMappings) === null || _b === void 0 ? void 0 : _b.value) { supportedFilters.push('minValue', 'maxValue'); supportedSorts.push('value'); } else { limitations.push('No value field available - minValue/maxValue filters not supported'); } // Check if approval date is available if ((_c = primaryDataset === null || primaryDataset === void 0 ? void 0 : primaryDataset.fieldMappings) === null || _c === void 0 ? void 0 : _c.approvalDate) { supportedFilters.push('approvalDateFrom', 'approvalDateTo'); supportedSorts.push('approvalDate'); } } return { supportedFilters, supportedSorts, limitations: limitations.length > 0 ? limitations : undefined }; } /** * Get field schema for a dataset */ getDatasetSchema(municipalityId, datasetId) { var _a; const source = this.registry.getSource(municipalityId); if (!source || !((_a = source.api) === null || _a === void 0 ? void 0 : _a.datasets)) { throw new Error(`Municipality or datasets not found: ${municipalityId}`); } // Get the specified dataset or the first one const dataset = datasetId ? source.api.datasets[datasetId] : Object.values(source.api.datasets)[0]; if (!dataset) { throw new Error(`Dataset not found: ${datasetId || 'default'}`); } // Convert fields to schema format const fieldMappings = dataset.fieldMappings || {}; const searchableLogicalFields = Object.keys(fieldMappings); return dataset.fields.map(fieldName => { const isSearchable = Object.values(fieldMappings).includes(fieldName); // Determine field type based on field name patterns let type = 'string'; if (fieldName.includes('date') || fieldName.includes('_date')) { type = 'date'; } else if (fieldName.includes('cost') || fieldName.includes('value') || fieldName.includes('amount')) { type = 'number'; } return { name: fieldName, type, searchable: isSearchable, description: isSearchable ? `Searchable field mapped to: ${searchableLogicalFields.find(logical => fieldMappings[logical] === fieldName)}` : undefined }; }); } /** * Get available sources */ getSources(filters) { let sources = this.registry.getAllSources(); if (filters === null || filters === void 0 ? void 0 : filters.state) { const filterState = filters.state.toLowerCase(); sources = sources.filter(s => s.state.toLowerCase() === filterState); } if (filters === null || filters === void 0 ? void 0 : filters.type) { sources = sources.filter(s => s.type === filters.type); } if (filters === null || filters === void 0 ? void 0 : filters.priority) { sources = sources.filter(s => s.priority === filters.priority); } if ((filters === null || filters === void 0 ? void 0 : filters.enabled) !== undefined) { sources = sources.filter(s => (s.enabled !== false) === filters.enabled); } return sources; } // /** // * Check health of a specific source // */ // async healthCheck(sourceId: string) { // const source = this.registry.getSource(sourceId); // if (!source) { // throw new Error(`Source not found: ${sourceId}`); // } // // const client = this.clientFactory.createClient(source); // const health = await client.healthCheck(); // // // Update registry with health info // this.registry.updateSourceStatus(sourceId, { // lastChecked: health.lastChecked.toISOString(), // lastError: health.status === 'unhealthy' ? health.error : undefined // }); // // return health; // } /** * Set universal Socrata authentication token */ setSocrataToken(token) { this.clientFactory.setSocrataToken(token); } /** * Register a new source at runtime */ registerSource(source) { this.registry.registerSource(source); } /** * Unregister a runtime source */ unregisterSource(id) { return this.registry.unregisterSource(id); } /** * Check if a source is built-in or runtime-added */ isBuiltInSource(id) { return this.registry.isBuiltInSource(id); } /** * Get registry information */ getRegistryInfo() { return this.registry.getRegistryInfo(); } } exports.MunicipalIntel = MunicipalIntel; /** * Create a new MunicipalIntel instance */ function createMunicipalIntel(config) { return new MunicipalIntel(config); } exports.createMunicipalIntel = createMunicipalIntel; // Default export exports.default = MunicipalIntel; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7OztHQUtHOzs7Ozs7Ozs7Ozs7Ozs7OztBQUVILFFBQVE7QUFDUiwwQ0FBd0I7QUFFeEIsVUFBVTtBQUNWLDRDQUEwQjtBQUUxQixXQUFXO0FBQ1gsNkNBQTJCO0FBRTNCLGlCQUFpQjtBQUNqQix1Q0FBK0Q7QUFDL0QseUNBQW1FO0FBR25FOztHQUVHO0FBQ0gsTUFBYSxjQUFjO0lBSXpCLFlBQVksU0FBOEIsRUFBRTtRQUMxQyxJQUFJLENBQUMsYUFBYSxHQUFHLElBQUksdUJBQWEsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUMvQyxJQUFJLENBQUMsUUFBUSxHQUFHLHlCQUFjLENBQUM7SUFDakMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLE1BQU0sQ0FBQyxNQUE2QjtRQUN4QyxJQUFJLE1BQXVCLENBQUM7UUFFNUIsSUFBSSxNQUFNLENBQUMsY0FBYyxFQUFFO1lBQ3pCLCtCQUErQjtZQUMvQixNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLENBQUM7WUFDbkUsSUFBSSxDQUFDLFdBQVcsRUFBRTtnQkFDaEIsTUFBTSxJQUFJLEtBQUssQ0FBQywyQkFBMkIsTUFBTSxDQUFDLGNBQWMsRUFBRSxDQUFDLENBQUM7YUFDckU7WUFDRCxNQUFNLEdBQUcsV0FBVyxDQUFDO1NBQ3RCO2FBQU07WUFDTCxpRUFBaUU7WUFDakUsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyw2QkFBNkIsRUFBRSxDQUFDO1lBQzlELElBQUksT0FBTyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUU7Z0JBQ3hCLE1BQU0sSUFBSSxLQUFLLENBQUMsaUNBQWlDLENBQUMsQ0FBQzthQUNwRDtZQUNELE1BQU0sR0FBRyxPQUFPLENBQUMsQ0FB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