@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
JavaScript
;
/**
* @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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