local-risk-alert-feed
A TypeScript library for aggregating local risk alerts from multiple data sources via a plugin system. Designed for SaaS and serverless applications.
Installation
npm install @vigilisai/local-risk-alert-feed
Quick Start
import {
AlertFeed,
NWSWeatherPlugin,
PhoenixFirePlugin,
NIFCWildfirePlugin,
ArizonaTrafficPlugin,
} from '@vigilisai/local-risk-alert-feed';
const feed = new AlertFeed({
continueOnPluginError: true,
pluginTimeoutMs: 30000,
});
await feed.registerPlugins([
{ plugin: new NWSWeatherPlugin() },
{ plugin: new PhoenixFirePlugin({ includeEMS: true }) },
{ plugin: new NIFCWildfirePlugin() },
{ plugin: new ArizonaTrafficPlugin() },
]);
const response = await feed.query({
location: { latitude: 33.4484, longitude: -112.074 },
timeRange: 'past-7d',
radiusMeters: 2000,
limit: 100,
});
console.log(`Found ${response.alerts.length} alerts`);
await feed.dispose();
Available Plugins
NWSWeatherPlugin | United States | weather | Real-time |
PhoenixFirePlugin | Phoenix metro | fire, medical | ~1-2 days |
NIFCWildfirePlugin | United States | fire | Real-time |
ArizonaTrafficPlugin | Arizona | traffic | Real-time |
PhoenixEventsPlugin | Phoenix area | event | Real-time |
PhoenixConventionCenterPlugin | Downtown Phoenix | event | Real-time |
AirNowPlugin | United States | air-quality | Real-time |
GlendaleEventsPlugin | Glendale, AZ | event | Scheduled |
GlendalePolicePlugin | Glendale, AZ | crime, traffic | ~24 hours |
GlendaleFirePlugin | Glendale, AZ | fire, medical | ~24 hours |
Plugin Configuration
NWSWeatherPlugin
National Weather Service alerts for the United States.
new NWSWeatherPlugin({
cacheTtlMs: 300000,
});
PhoenixFirePlugin
Fire and EMS incidents from Phoenix Fire Department (ArcGIS 30-day history).
new PhoenixFirePlugin({
includeEMS: true,
includeService: false,
limit: 500,
});
NIFCWildfirePlugin
Active wildfires from National Interagency Fire Center.
new NIFCWildfirePlugin({
includePrescribedBurns: false,
minAcres: 0,
states: ['AZ', 'CA', 'NV'],
});
PhoenixEventsPlugin
Events from Ticketmaster Discovery API.
new PhoenixEventsPlugin({
ticketmasterApiKey: process.env.TICKETMASTER_API_KEY,
limit: 100,
});
AirNowPlugin
Air quality data from EPA AirNow.
new AirNowPlugin({
apiKey: process.env.AIRNOW_API_KEY,
});
Cache Providers
The library uses a bring-your-own-client pattern for caching. No external dependencies are required.
In-Memory (Default)
Zero dependencies, suitable for development or single-instance deployments.
import { AlertFeed, InMemoryCacheProvider } from '@vigilisai/local-risk-alert-feed';
const feed = new AlertFeed({
cacheProvider: new InMemoryCacheProvider(),
});
Vercel KV
Pass your own @vercel/kv instance (any version).
import { kv } from '@vercel/kv';
import { AlertFeed, VercelKVCacheProvider } from '@vigilisai/local-risk-alert-feed';
const feed = new AlertFeed({
cacheProvider: new VercelKVCacheProvider(kv, 'my-prefix:'),
});
DynamoDB
Pass your own AWS SDK DynamoDB Document Client (any v3 version).
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
import { AlertFeed, DynamoDBCacheProvider } from '@vigilisai/local-risk-alert-feed';
const client = new DynamoDBClient({});
const docClient = DynamoDBDocumentClient.from(client);
const feed = new AlertFeed({
cacheProvider: new DynamoDBCacheProvider(docClient, {
tableName: 'alert-cache',
keyAttribute: 'pk',
valueAttribute: 'value',
ttlAttribute: 'ttl',
}),
});
Custom Cache Provider
Implement the CacheProvider interface for any backend.
import { CacheProvider, AlertFeed } from '@vigilisai/local-risk-alert-feed';
const customCache: CacheProvider = {
async get<T>(key: string): Promise<T | null> {
},
async set<T>(key: string, value: T, ttlMs?: number): Promise<void> {
},
async delete(key: string): Promise<void> {
},
async has(key: string): Promise<boolean> {
},
};
const feed = new AlertFeed({ cacheProvider: customCache });
Query Options
const response = await feed.query({
location: { latitude: 33.4484, longitude: -112.074 },
timeRange: 'past-7d',
radiusMeters: 2000,
categories: ['fire', 'weather'],
plugins: ['nws-weather'],
limit: 100,
includePluginResults: true,
});
Response Format
interface AlertFeedResponse {
alerts: Alert[];
meta: {
queriedAt: string;
timeRange: { start: string; end: string };
location: { latitude: number; longitude: number };
radiusMeters: number;
totalCount: number;
truncated: boolean;
};
pluginResults?: PluginResult[];
}
interface Alert {
id: string;
title: string;
description: string;
category: 'weather' | 'fire' | 'medical' | 'traffic' | 'event' | 'air-quality' | ...;
riskLevel: 'low' | 'moderate' | 'high' | 'severe' | 'extreme';
priority: number;
temporalType: 'real-time' | 'scheduled' | 'historical';
location: {
point: { latitude: number; longitude: number };
address?: string;
city?: string;
state?: string;
};
timestamps: {
issued: string;
eventStart?: string;
eventEnd?: string;
expires?: string;
};
source: {
id: string;
name: string;
};
url?: string;
metadata?: Record<string, unknown>;
}
Serverless Adapters
Vercel Edge/Serverless
import { createVercelHandler } from 'local-risk-alert-feed/adapters/vercel';
import { NWSWeatherPlugin, PhoenixFirePlugin } from '@vigilisai/local-risk-alert-feed';
export default createVercelHandler({
plugins: [
new NWSWeatherPlugin(),
new PhoenixFirePlugin(),
],
});
AWS Lambda
import { createLambdaHandler } from 'local-risk-alert-feed/adapters/lambda';
import { NWSWeatherPlugin, PhoenixFirePlugin } from '@vigilisai/local-risk-alert-feed';
export const handler = createLambdaHandler({
plugins: [
new NWSWeatherPlugin(),
new PhoenixFirePlugin(),
],
});
Creating Custom Plugins
Extend BasePlugin to create your own data source plugins.
import { BasePlugin, PluginMetadata, PluginFetchOptions, PluginFetchResult } from '@vigilisai/local-risk-alert-feed';
export class MyCustomPlugin extends BasePlugin {
readonly metadata: PluginMetadata = {
id: 'my-custom-plugin',
name: 'My Custom Data Source',
version: '1.0.0',
description: 'Fetches alerts from my custom API',
coverage: {
type: 'regional',
center: { latitude: 40.7128, longitude: -74.0060 },
radiusMeters: 50000,
description: 'New York City area',
},
supportedTemporalTypes: ['real-time'],
supportedCategories: ['custom'],
refreshIntervalMs: 60000,
};
async fetchAlerts(options: PluginFetchOptions): Promise<PluginFetchResult> {
const { location, timeRange, radiusMeters } = options;
const data = await this.fetchJson<MyApiResponse>('https://my-api.com/alerts');
const alerts = data.items.map(item => this.createAlert({
id: `my-plugin-${item.id}`,
title: item.title,
description: item.description,
riskLevel: 'moderate',
priority: 3,
category: 'custom',
temporalType: 'real-time',
location: {
point: { latitude: item.lat, longitude: item.lng },
},
timestamps: {
issued: item.createdAt,
},
}));
return { alerts, fromCache: false };
}
}
Environment Variables
TICKETMASTER_API_KEY=your_key_here
AIRNOW_API_KEY=your_key_here
License
UNLICENSED - Private package