local-risk-alert-feed 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. package/dist/cjs/adapters/index.js +8 -0
  2. package/dist/cjs/adapters/index.js.map +1 -0
  3. package/dist/cjs/adapters/lambda.js +143 -0
  4. package/dist/cjs/adapters/lambda.js.map +1 -0
  5. package/dist/cjs/adapters/vercel.js +119 -0
  6. package/dist/cjs/adapters/vercel.js.map +1 -0
  7. package/dist/cjs/core/alert-aggregator.js +207 -0
  8. package/dist/cjs/core/alert-aggregator.js.map +1 -0
  9. package/dist/cjs/core/alert-feed.js +236 -0
  10. package/dist/cjs/core/alert-feed.js.map +1 -0
  11. package/dist/cjs/core/index.js +22 -0
  12. package/dist/cjs/core/index.js.map +1 -0
  13. package/dist/cjs/core/plugin-registry.js +193 -0
  14. package/dist/cjs/core/plugin-registry.js.map +1 -0
  15. package/dist/cjs/core/plugin-resolver.js +121 -0
  16. package/dist/cjs/core/plugin-resolver.js.map +1 -0
  17. package/dist/cjs/core/time-range.js +67 -0
  18. package/dist/cjs/core/time-range.js.map +1 -0
  19. package/dist/cjs/errors/fetch-error.js +71 -0
  20. package/dist/cjs/errors/fetch-error.js.map +1 -0
  21. package/dist/cjs/errors/index.js +15 -0
  22. package/dist/cjs/errors/index.js.map +1 -0
  23. package/dist/cjs/errors/plugin-error.js +80 -0
  24. package/dist/cjs/errors/plugin-error.js.map +1 -0
  25. package/dist/cjs/errors/validation-error.js +49 -0
  26. package/dist/cjs/errors/validation-error.js.map +1 -0
  27. package/dist/cjs/geo/distance.js +94 -0
  28. package/dist/cjs/geo/distance.js.map +1 -0
  29. package/dist/cjs/geo/index.js +18 -0
  30. package/dist/cjs/geo/index.js.map +1 -0
  31. package/dist/cjs/geo/point-in-radius.js +86 -0
  32. package/dist/cjs/geo/point-in-radius.js.map +1 -0
  33. package/dist/cjs/index.js +90 -0
  34. package/dist/cjs/index.js.map +1 -0
  35. package/dist/cjs/plugins/air-quality/airnow.plugin.js +343 -0
  36. package/dist/cjs/plugins/air-quality/airnow.plugin.js.map +1 -0
  37. package/dist/cjs/plugins/air-quality/index.js +6 -0
  38. package/dist/cjs/plugins/air-quality/index.js.map +1 -0
  39. package/dist/cjs/plugins/base-plugin.js +213 -0
  40. package/dist/cjs/plugins/base-plugin.js.map +1 -0
  41. package/dist/cjs/plugins/events/index.js +6 -0
  42. package/dist/cjs/plugins/events/index.js.map +1 -0
  43. package/dist/cjs/plugins/events/phoenix-events.plugin.js +382 -0
  44. package/dist/cjs/plugins/events/phoenix-events.plugin.js.map +1 -0
  45. package/dist/cjs/plugins/fire-emt/index.js +6 -0
  46. package/dist/cjs/plugins/fire-emt/index.js.map +1 -0
  47. package/dist/cjs/plugins/fire-emt/phoenix-fire.plugin.js +262 -0
  48. package/dist/cjs/plugins/fire-emt/phoenix-fire.plugin.js.map +1 -0
  49. package/dist/cjs/plugins/index.js +28 -0
  50. package/dist/cjs/plugins/index.js.map +1 -0
  51. package/dist/cjs/plugins/police-blotter/index.js +6 -0
  52. package/dist/cjs/plugins/police-blotter/index.js.map +1 -0
  53. package/dist/cjs/plugins/police-blotter/phoenix-police.plugin.js +198 -0
  54. package/dist/cjs/plugins/police-blotter/phoenix-police.plugin.js.map +1 -0
  55. package/dist/cjs/plugins/pulsepoint/index.js +6 -0
  56. package/dist/cjs/plugins/pulsepoint/index.js.map +1 -0
  57. package/dist/cjs/plugins/pulsepoint/pulsepoint.plugin.js +275 -0
  58. package/dist/cjs/plugins/pulsepoint/pulsepoint.plugin.js.map +1 -0
  59. package/dist/cjs/plugins/traffic/arizona-traffic.plugin.js +391 -0
  60. package/dist/cjs/plugins/traffic/arizona-traffic.plugin.js.map +1 -0
  61. package/dist/cjs/plugins/traffic/index.js +6 -0
  62. package/dist/cjs/plugins/traffic/index.js.map +1 -0
  63. package/dist/cjs/plugins/weather/index.js +6 -0
  64. package/dist/cjs/plugins/weather/index.js.map +1 -0
  65. package/dist/cjs/plugins/weather/nws-weather.plugin.js +180 -0
  66. package/dist/cjs/plugins/weather/nws-weather.plugin.js.map +1 -0
  67. package/dist/cjs/schemas/alert.schema.js +93 -0
  68. package/dist/cjs/schemas/alert.schema.js.map +1 -0
  69. package/dist/cjs/schemas/index.js +24 -0
  70. package/dist/cjs/schemas/index.js.map +1 -0
  71. package/dist/cjs/schemas/query.schema.js +76 -0
  72. package/dist/cjs/schemas/query.schema.js.map +1 -0
  73. package/dist/cjs/types/alert.js +35 -0
  74. package/dist/cjs/types/alert.js.map +1 -0
  75. package/dist/cjs/types/config.js +13 -0
  76. package/dist/cjs/types/config.js.map +1 -0
  77. package/dist/cjs/types/geo.js +3 -0
  78. package/dist/cjs/types/geo.js.map +1 -0
  79. package/dist/cjs/types/index.js +16 -0
  80. package/dist/cjs/types/index.js.map +1 -0
  81. package/dist/cjs/types/plugin.js +3 -0
  82. package/dist/cjs/types/plugin.js.map +1 -0
  83. package/dist/cjs/types/query.js +28 -0
  84. package/dist/cjs/types/query.js.map +1 -0
  85. package/dist/cjs/utils/cache.js +188 -0
  86. package/dist/cjs/utils/cache.js.map +1 -0
  87. package/dist/cjs/utils/csv.js +189 -0
  88. package/dist/cjs/utils/csv.js.map +1 -0
  89. package/dist/cjs/utils/date.js +153 -0
  90. package/dist/cjs/utils/date.js.map +1 -0
  91. package/dist/cjs/utils/index.js +28 -0
  92. package/dist/cjs/utils/index.js.map +1 -0
  93. package/dist/cjs/utils/retry.js +109 -0
  94. package/dist/cjs/utils/retry.js.map +1 -0
  95. package/dist/esm/adapters/index.js +3 -0
  96. package/dist/esm/adapters/index.js.map +1 -0
  97. package/dist/esm/adapters/lambda.js +140 -0
  98. package/dist/esm/adapters/lambda.js.map +1 -0
  99. package/dist/esm/adapters/vercel.js +116 -0
  100. package/dist/esm/adapters/vercel.js.map +1 -0
  101. package/dist/esm/core/alert-aggregator.js +203 -0
  102. package/dist/esm/core/alert-aggregator.js.map +1 -0
  103. package/dist/esm/core/alert-feed.js +232 -0
  104. package/dist/esm/core/alert-feed.js.map +1 -0
  105. package/dist/esm/core/index.js +6 -0
  106. package/dist/esm/core/index.js.map +1 -0
  107. package/dist/esm/core/plugin-registry.js +189 -0
  108. package/dist/esm/core/plugin-registry.js.map +1 -0
  109. package/dist/esm/core/plugin-resolver.js +117 -0
  110. package/dist/esm/core/plugin-resolver.js.map +1 -0
  111. package/dist/esm/core/time-range.js +57 -0
  112. package/dist/esm/core/time-range.js.map +1 -0
  113. package/dist/esm/errors/fetch-error.js +67 -0
  114. package/dist/esm/errors/fetch-error.js.map +1 -0
  115. package/dist/esm/errors/index.js +4 -0
  116. package/dist/esm/errors/index.js.map +1 -0
  117. package/dist/esm/errors/plugin-error.js +71 -0
  118. package/dist/esm/errors/plugin-error.js.map +1 -0
  119. package/dist/esm/errors/validation-error.js +45 -0
  120. package/dist/esm/errors/validation-error.js.map +1 -0
  121. package/dist/esm/geo/distance.js +85 -0
  122. package/dist/esm/geo/distance.js.map +1 -0
  123. package/dist/esm/geo/index.js +3 -0
  124. package/dist/esm/geo/index.js.map +1 -0
  125. package/dist/esm/geo/point-in-radius.js +79 -0
  126. package/dist/esm/geo/point-in-radius.js.map +1 -0
  127. package/dist/esm/index.js +30 -0
  128. package/dist/esm/index.js.map +1 -0
  129. package/dist/esm/plugins/air-quality/airnow.plugin.js +339 -0
  130. package/dist/esm/plugins/air-quality/airnow.plugin.js.map +1 -0
  131. package/dist/esm/plugins/air-quality/index.js +2 -0
  132. package/dist/esm/plugins/air-quality/index.js.map +1 -0
  133. package/dist/esm/plugins/base-plugin.js +209 -0
  134. package/dist/esm/plugins/base-plugin.js.map +1 -0
  135. package/dist/esm/plugins/events/index.js +2 -0
  136. package/dist/esm/plugins/events/index.js.map +1 -0
  137. package/dist/esm/plugins/events/phoenix-events.plugin.js +378 -0
  138. package/dist/esm/plugins/events/phoenix-events.plugin.js.map +1 -0
  139. package/dist/esm/plugins/fire-emt/index.js +2 -0
  140. package/dist/esm/plugins/fire-emt/index.js.map +1 -0
  141. package/dist/esm/plugins/fire-emt/phoenix-fire.plugin.js +258 -0
  142. package/dist/esm/plugins/fire-emt/phoenix-fire.plugin.js.map +1 -0
  143. package/dist/esm/plugins/index.js +17 -0
  144. package/dist/esm/plugins/index.js.map +1 -0
  145. package/dist/esm/plugins/police-blotter/index.js +2 -0
  146. package/dist/esm/plugins/police-blotter/index.js.map +1 -0
  147. package/dist/esm/plugins/police-blotter/phoenix-police.plugin.js +194 -0
  148. package/dist/esm/plugins/police-blotter/phoenix-police.plugin.js.map +1 -0
  149. package/dist/esm/plugins/pulsepoint/index.js +2 -0
  150. package/dist/esm/plugins/pulsepoint/index.js.map +1 -0
  151. package/dist/esm/plugins/pulsepoint/pulsepoint.plugin.js +271 -0
  152. package/dist/esm/plugins/pulsepoint/pulsepoint.plugin.js.map +1 -0
  153. package/dist/esm/plugins/traffic/arizona-traffic.plugin.js +387 -0
  154. package/dist/esm/plugins/traffic/arizona-traffic.plugin.js.map +1 -0
  155. package/dist/esm/plugins/traffic/index.js +2 -0
  156. package/dist/esm/plugins/traffic/index.js.map +1 -0
  157. package/dist/esm/plugins/weather/index.js +2 -0
  158. package/dist/esm/plugins/weather/index.js.map +1 -0
  159. package/dist/esm/plugins/weather/nws-weather.plugin.js +176 -0
  160. package/dist/esm/plugins/weather/nws-weather.plugin.js.map +1 -0
  161. package/dist/esm/schemas/alert.schema.js +90 -0
  162. package/dist/esm/schemas/alert.schema.js.map +1 -0
  163. package/dist/esm/schemas/index.js +5 -0
  164. package/dist/esm/schemas/index.js.map +1 -0
  165. package/dist/esm/schemas/query.schema.js +72 -0
  166. package/dist/esm/schemas/query.schema.js.map +1 -0
  167. package/dist/esm/types/alert.js +32 -0
  168. package/dist/esm/types/alert.js.map +1 -0
  169. package/dist/esm/types/config.js +10 -0
  170. package/dist/esm/types/config.js.map +1 -0
  171. package/dist/esm/types/geo.js +2 -0
  172. package/dist/esm/types/geo.js.map +1 -0
  173. package/dist/esm/types/index.js +4 -0
  174. package/dist/esm/types/index.js.map +1 -0
  175. package/dist/esm/types/plugin.js +2 -0
  176. package/dist/esm/types/plugin.js.map +1 -0
  177. package/dist/esm/types/query.js +25 -0
  178. package/dist/esm/types/query.js.map +1 -0
  179. package/dist/esm/utils/cache.js +181 -0
  180. package/dist/esm/utils/cache.js.map +1 -0
  181. package/dist/esm/utils/csv.js +185 -0
  182. package/dist/esm/utils/csv.js.map +1 -0
  183. package/dist/esm/utils/date.js +142 -0
  184. package/dist/esm/utils/date.js.map +1 -0
  185. package/dist/esm/utils/index.js +5 -0
  186. package/dist/esm/utils/index.js.map +1 -0
  187. package/dist/esm/utils/retry.js +102 -0
  188. package/dist/esm/utils/retry.js.map +1 -0
  189. package/dist/types/adapters/index.d.ts +5 -0
  190. package/dist/types/adapters/index.d.ts.map +1 -0
  191. package/dist/types/adapters/lambda.d.ts +37 -0
  192. package/dist/types/adapters/lambda.d.ts.map +1 -0
  193. package/dist/types/adapters/vercel.d.ts +54 -0
  194. package/dist/types/adapters/vercel.d.ts.map +1 -0
  195. package/dist/types/core/alert-aggregator.d.ts +81 -0
  196. package/dist/types/core/alert-aggregator.d.ts.map +1 -0
  197. package/dist/types/core/alert-feed.d.ts +80 -0
  198. package/dist/types/core/alert-feed.d.ts.map +1 -0
  199. package/dist/types/core/index.d.ts +8 -0
  200. package/dist/types/core/index.d.ts.map +1 -0
  201. package/dist/types/core/plugin-registry.d.ts +91 -0
  202. package/dist/types/core/plugin-registry.d.ts.map +1 -0
  203. package/dist/types/core/plugin-resolver.d.ts +78 -0
  204. package/dist/types/core/plugin-resolver.d.ts.map +1 -0
  205. package/dist/types/core/time-range.d.ts +40 -0
  206. package/dist/types/core/time-range.d.ts.map +1 -0
  207. package/dist/types/errors/fetch-error.d.ts +46 -0
  208. package/dist/types/errors/fetch-error.d.ts.map +1 -0
  209. package/dist/types/errors/index.d.ts +5 -0
  210. package/dist/types/errors/index.d.ts.map +1 -0
  211. package/dist/types/errors/plugin-error.d.ts +42 -0
  212. package/dist/types/errors/plugin-error.d.ts.map +1 -0
  213. package/dist/types/errors/validation-error.d.ts +34 -0
  214. package/dist/types/errors/validation-error.d.ts.map +1 -0
  215. package/dist/types/geo/distance.d.ts +50 -0
  216. package/dist/types/geo/distance.d.ts.map +1 -0
  217. package/dist/types/geo/index.d.ts +3 -0
  218. package/dist/types/geo/index.d.ts.map +1 -0
  219. package/dist/types/geo/point-in-radius.d.ts +44 -0
  220. package/dist/types/geo/point-in-radius.d.ts.map +1 -0
  221. package/dist/types/index.d.ts +32 -0
  222. package/dist/types/index.d.ts.map +1 -0
  223. package/dist/types/plugins/air-quality/airnow.plugin.d.ts +84 -0
  224. package/dist/types/plugins/air-quality/airnow.plugin.d.ts.map +1 -0
  225. package/dist/types/plugins/air-quality/index.d.ts +3 -0
  226. package/dist/types/plugins/air-quality/index.d.ts.map +1 -0
  227. package/dist/types/plugins/base-plugin.d.ts +99 -0
  228. package/dist/types/plugins/base-plugin.d.ts.map +1 -0
  229. package/dist/types/plugins/events/index.d.ts +3 -0
  230. package/dist/types/plugins/events/index.d.ts.map +1 -0
  231. package/dist/types/plugins/events/phoenix-events.plugin.d.ts +71 -0
  232. package/dist/types/plugins/events/phoenix-events.plugin.d.ts.map +1 -0
  233. package/dist/types/plugins/fire-emt/index.d.ts +3 -0
  234. package/dist/types/plugins/fire-emt/index.d.ts.map +1 -0
  235. package/dist/types/plugins/fire-emt/phoenix-fire.plugin.d.ts +47 -0
  236. package/dist/types/plugins/fire-emt/phoenix-fire.plugin.d.ts.map +1 -0
  237. package/dist/types/plugins/index.d.ts +17 -0
  238. package/dist/types/plugins/index.d.ts.map +1 -0
  239. package/dist/types/plugins/police-blotter/index.d.ts +3 -0
  240. package/dist/types/plugins/police-blotter/index.d.ts.map +1 -0
  241. package/dist/types/plugins/police-blotter/phoenix-police.plugin.d.ts +49 -0
  242. package/dist/types/plugins/police-blotter/phoenix-police.plugin.d.ts.map +1 -0
  243. package/dist/types/plugins/pulsepoint/index.d.ts +3 -0
  244. package/dist/types/plugins/pulsepoint/index.d.ts.map +1 -0
  245. package/dist/types/plugins/pulsepoint/pulsepoint.plugin.d.ts +61 -0
  246. package/dist/types/plugins/pulsepoint/pulsepoint.plugin.d.ts.map +1 -0
  247. package/dist/types/plugins/traffic/arizona-traffic.plugin.d.ts +83 -0
  248. package/dist/types/plugins/traffic/arizona-traffic.plugin.d.ts.map +1 -0
  249. package/dist/types/plugins/traffic/index.d.ts +3 -0
  250. package/dist/types/plugins/traffic/index.d.ts.map +1 -0
  251. package/dist/types/plugins/weather/index.d.ts +3 -0
  252. package/dist/types/plugins/weather/index.d.ts.map +1 -0
  253. package/dist/types/plugins/weather/nws-weather.plugin.d.ts +50 -0
  254. package/dist/types/plugins/weather/nws-weather.plugin.d.ts.map +1 -0
  255. package/dist/types/schemas/alert.schema.d.ts +266 -0
  256. package/dist/types/schemas/alert.schema.d.ts.map +1 -0
  257. package/dist/types/schemas/index.d.ts +5 -0
  258. package/dist/types/schemas/index.d.ts.map +1 -0
  259. package/dist/types/schemas/query.schema.d.ts +150 -0
  260. package/dist/types/schemas/query.schema.d.ts.map +1 -0
  261. package/dist/types/types/alert.d.ts +96 -0
  262. package/dist/types/types/alert.d.ts.map +1 -0
  263. package/dist/types/types/config.d.ts +63 -0
  264. package/dist/types/types/config.d.ts.map +1 -0
  265. package/dist/types/types/geo.d.ts +33 -0
  266. package/dist/types/types/geo.d.ts.map +1 -0
  267. package/dist/types/types/index.d.ts +9 -0
  268. package/dist/types/types/index.d.ts.map +1 -0
  269. package/dist/types/types/plugin.d.ts +125 -0
  270. package/dist/types/types/plugin.d.ts.map +1 -0
  271. package/dist/types/types/query.d.ts +86 -0
  272. package/dist/types/types/query.d.ts.map +1 -0
  273. package/dist/types/utils/cache.d.ts +112 -0
  274. package/dist/types/utils/cache.d.ts.map +1 -0
  275. package/dist/types/utils/csv.d.ts +38 -0
  276. package/dist/types/utils/csv.d.ts.map +1 -0
  277. package/dist/types/utils/date.d.ts +47 -0
  278. package/dist/types/utils/date.d.ts.map +1 -0
  279. package/dist/types/utils/index.d.ts +7 -0
  280. package/dist/types/utils/index.d.ts.map +1 -0
  281. package/dist/types/utils/retry.d.ts +51 -0
  282. package/dist/types/utils/retry.d.ts.map +1 -0
  283. package/package.json +115 -0
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createVercelHandler = exports.createLambdaHandler = void 0;
4
+ var lambda_1 = require("./lambda");
5
+ Object.defineProperty(exports, "createLambdaHandler", { enumerable: true, get: function () { return lambda_1.createLambdaHandler; } });
6
+ var vercel_1 = require("./vercel");
7
+ Object.defineProperty(exports, "createVercelHandler", { enumerable: true, get: function () { return vercel_1.createVercelHandler; } });
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/index.ts"],"names":[],"mappings":";;;AAAA,mCAA+C;AAAtC,6GAAA,mBAAmB,OAAA;AAG5B,mCAA+C;AAAtC,6GAAA,mBAAmB,OAAA"}
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createLambdaHandler = createLambdaHandler;
4
+ const core_1 = require("../core");
5
+ const schemas_1 = require("../schemas");
6
+ const errors_1 = require("../errors");
7
+ /**
8
+ * Create an AWS Lambda handler for the AlertFeed.
9
+ *
10
+ * Supports both GET (query parameters) and POST (JSON body) requests.
11
+ *
12
+ * @param options - Handler configuration options
13
+ * @returns Lambda handler function
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * import { createLambdaHandler } from 'local-risk-alert-feed/adapters/lambda';
18
+ * import { PhoenixPolicePlugin } from 'local-risk-alert-feed/plugins/police-blotter';
19
+ *
20
+ * export const handler = createLambdaHandler({
21
+ * plugins: [{ plugin: new PhoenixPolicePlugin() }]
22
+ * });
23
+ * ```
24
+ */
25
+ function createLambdaHandler(options) {
26
+ const feed = new core_1.AlertFeed(options);
27
+ const corsOrigin = options.corsOrigin ?? '*';
28
+ const corsHeaders = [
29
+ 'Content-Type',
30
+ 'Authorization',
31
+ ...(options.corsHeaders ?? []),
32
+ ].join(', ');
33
+ const corsMethods = ['GET', 'POST', 'OPTIONS', ...(options.corsMethods ?? [])].join(', ');
34
+ // Initialize plugins
35
+ if (options.plugins) {
36
+ feed.registerPlugins(options.plugins).catch(console.error);
37
+ }
38
+ return async (event, _context) => {
39
+ // Handle CORS preflight
40
+ if (event.httpMethod === 'OPTIONS') {
41
+ return createCorsResponse(corsOrigin, corsHeaders, corsMethods);
42
+ }
43
+ try {
44
+ // Parse request
45
+ const requestData = parseRequest(event);
46
+ // Validate request
47
+ const parseResult = schemas_1.AlertQueryRequestSchema.safeParse(requestData);
48
+ if (!parseResult.success) {
49
+ return createErrorResponse(400, 'Validation Error', errors_1.ValidationError.fromZodError(parseResult.error).toJSON(), corsOrigin);
50
+ }
51
+ // Transform to query
52
+ const query = (0, schemas_1.transformRequestToQuery)(parseResult.data);
53
+ // Execute query
54
+ const response = await feed.query(query);
55
+ return createSuccessResponse(response, corsOrigin);
56
+ }
57
+ catch (error) {
58
+ console.error('AlertFeed error:', error);
59
+ if (error instanceof errors_1.ValidationError) {
60
+ return createErrorResponse(400, 'Validation Error', error.toJSON(), corsOrigin);
61
+ }
62
+ return createErrorResponse(500, 'Internal Server Error', {
63
+ message: error instanceof Error ? error.message : 'An unexpected error occurred',
64
+ }, corsOrigin);
65
+ }
66
+ };
67
+ }
68
+ /**
69
+ * Parse request data from Lambda event.
70
+ */
71
+ function parseRequest(event) {
72
+ if (event.httpMethod === 'POST' && event.body) {
73
+ try {
74
+ return JSON.parse(event.body);
75
+ }
76
+ catch {
77
+ throw new errors_1.ValidationError('Invalid JSON body', [
78
+ { path: 'body', message: 'Request body must be valid JSON', code: 'invalid_type' },
79
+ ]);
80
+ }
81
+ }
82
+ // Parse from query parameters
83
+ const params = event.queryStringParameters ?? {};
84
+ const multiParams = event.multiValueQueryStringParameters ?? {};
85
+ return {
86
+ latitude: params.latitude ? parseFloat(params.latitude) : undefined,
87
+ longitude: params.longitude ? parseFloat(params.longitude) : undefined,
88
+ radiusMeters: params.radiusMeters ? parseFloat(params.radiusMeters) : undefined,
89
+ limit: params.limit ? parseInt(params.limit, 10) : undefined,
90
+ minRiskLevel: params.minRiskLevel,
91
+ timeRange: params.timeRange,
92
+ categories: multiParams.categories ?? (params.categories ? [params.categories] : undefined),
93
+ temporalTypes: multiParams.temporalTypes ?? (params.temporalTypes ? [params.temporalTypes] : undefined),
94
+ includePluginResults: params.includePluginResults === 'true',
95
+ };
96
+ }
97
+ /**
98
+ * Create a success response.
99
+ */
100
+ function createSuccessResponse(data, corsOrigin) {
101
+ return {
102
+ statusCode: 200,
103
+ headers: getCorsHeaders(corsOrigin),
104
+ body: JSON.stringify(data),
105
+ };
106
+ }
107
+ /**
108
+ * Create an error response.
109
+ */
110
+ function createErrorResponse(statusCode, error, details, corsOrigin) {
111
+ return {
112
+ statusCode,
113
+ headers: getCorsHeaders(corsOrigin),
114
+ body: JSON.stringify({ error, ...details }),
115
+ };
116
+ }
117
+ /**
118
+ * Create a CORS preflight response.
119
+ */
120
+ function createCorsResponse(corsOrigin, corsHeaders, corsMethods) {
121
+ const origin = Array.isArray(corsOrigin) ? corsOrigin[0] : corsOrigin;
122
+ return {
123
+ statusCode: 204,
124
+ headers: {
125
+ 'Access-Control-Allow-Origin': origin,
126
+ 'Access-Control-Allow-Headers': corsHeaders,
127
+ 'Access-Control-Allow-Methods': corsMethods,
128
+ 'Access-Control-Max-Age': '86400',
129
+ },
130
+ body: '',
131
+ };
132
+ }
133
+ /**
134
+ * Get CORS headers for response.
135
+ */
136
+ function getCorsHeaders(corsOrigin) {
137
+ const origin = Array.isArray(corsOrigin) ? corsOrigin[0] : corsOrigin;
138
+ return {
139
+ 'Content-Type': 'application/json',
140
+ 'Access-Control-Allow-Origin': origin,
141
+ };
142
+ }
143
+ //# sourceMappingURL=lambda.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lambda.js","sourceRoot":"","sources":["../../../src/adapters/lambda.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createVercelHandler = createVercelHandler;
4
+ const core_1 = require("../core");
5
+ const schemas_1 = require("../schemas");
6
+ const errors_1 = require("../errors");
7
+ /**
8
+ * Create Next.js App Router handlers for the AlertFeed.
9
+ *
10
+ * Returns GET and POST handlers that can be exported from a route file.
11
+ *
12
+ * @param options - Handler configuration options
13
+ * @returns Object with GET and POST handlers
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * // app/api/alerts/route.ts
18
+ * import { createVercelHandler } from 'local-risk-alert-feed/adapters/vercel';
19
+ * import { PhoenixPolicePlugin } from 'local-risk-alert-feed/plugins/police-blotter';
20
+ *
21
+ * const { GET, POST } = createVercelHandler({
22
+ * plugins: [{ plugin: new PhoenixPolicePlugin() }]
23
+ * });
24
+ *
25
+ * export { GET, POST };
26
+ * ```
27
+ */
28
+ function createVercelHandler(options) {
29
+ const feed = new core_1.AlertFeed(options);
30
+ const corsOrigin = options.corsOrigin ?? '*';
31
+ // Initialize plugins
32
+ if (options.plugins) {
33
+ feed.registerPlugins(options.plugins).catch(console.error);
34
+ }
35
+ const handleRequest = async (request) => {
36
+ try {
37
+ // Parse request
38
+ const requestData = await parseRequest(request);
39
+ // Validate request
40
+ const parseResult = schemas_1.AlertQueryRequestSchema.safeParse(requestData);
41
+ if (!parseResult.success) {
42
+ return createErrorResponse(400, 'Validation Error', errors_1.ValidationError.fromZodError(parseResult.error).toJSON(), corsOrigin);
43
+ }
44
+ // Transform to query
45
+ const query = (0, schemas_1.transformRequestToQuery)(parseResult.data);
46
+ // Execute query
47
+ const response = await feed.query(query);
48
+ return createSuccessResponse(response, corsOrigin);
49
+ }
50
+ catch (error) {
51
+ console.error('AlertFeed error:', error);
52
+ if (error instanceof errors_1.ValidationError) {
53
+ return createErrorResponse(400, 'Validation Error', error.toJSON(), corsOrigin);
54
+ }
55
+ return createErrorResponse(500, 'Internal Server Error', {
56
+ message: error instanceof Error ? error.message : 'An unexpected error occurred',
57
+ }, corsOrigin);
58
+ }
59
+ };
60
+ return {
61
+ GET: handleRequest,
62
+ POST: handleRequest,
63
+ };
64
+ }
65
+ /**
66
+ * Parse request data from Next.js request.
67
+ */
68
+ async function parseRequest(request) {
69
+ if (request.method === 'POST') {
70
+ try {
71
+ return (await request.json());
72
+ }
73
+ catch {
74
+ throw new errors_1.ValidationError('Invalid JSON body', [
75
+ { path: 'body', message: 'Request body must be valid JSON', code: 'invalid_type' },
76
+ ]);
77
+ }
78
+ }
79
+ // Parse from query parameters
80
+ const params = request.nextUrl.searchParams;
81
+ return {
82
+ latitude: params.has('latitude') ? parseFloat(params.get('latitude')) : undefined,
83
+ longitude: params.has('longitude') ? parseFloat(params.get('longitude')) : undefined,
84
+ radiusMeters: params.has('radiusMeters') ? parseFloat(params.get('radiusMeters')) : undefined,
85
+ limit: params.has('limit') ? parseInt(params.get('limit'), 10) : undefined,
86
+ minRiskLevel: params.get('minRiskLevel') ?? undefined,
87
+ timeRange: params.get('timeRange') ?? undefined,
88
+ categories: params.getAll('categories').length > 0 ? params.getAll('categories') : undefined,
89
+ temporalTypes: params.getAll('temporalTypes').length > 0 ? params.getAll('temporalTypes') : undefined,
90
+ includePluginResults: params.get('includePluginResults') === 'true',
91
+ };
92
+ }
93
+ /**
94
+ * Create a success response.
95
+ */
96
+ function createSuccessResponse(data, corsOrigin) {
97
+ const origin = Array.isArray(corsOrigin) ? corsOrigin[0] : corsOrigin;
98
+ return new Response(JSON.stringify(data), {
99
+ status: 200,
100
+ headers: {
101
+ 'Content-Type': 'application/json',
102
+ 'Access-Control-Allow-Origin': origin,
103
+ },
104
+ });
105
+ }
106
+ /**
107
+ * Create an error response.
108
+ */
109
+ function createErrorResponse(statusCode, error, details, corsOrigin) {
110
+ const origin = Array.isArray(corsOrigin) ? corsOrigin[0] : corsOrigin;
111
+ return new Response(JSON.stringify({ error, ...details }), {
112
+ status: statusCode,
113
+ headers: {
114
+ 'Content-Type': 'application/json',
115
+ 'Access-Control-Allow-Origin': origin,
116
+ },
117
+ });
118
+ }
119
+ //# sourceMappingURL=vercel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vercel.js","sourceRoot":"","sources":["../../../src/adapters/vercel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,207 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AlertAggregator = void 0;
4
+ const types_1 = require("../types");
5
+ const geo_1 = require("../geo");
6
+ /**
7
+ * Aggregates, filters, deduplicates, and sorts alerts from multiple sources.
8
+ */
9
+ class AlertAggregator {
10
+ /**
11
+ * Aggregate alerts from multiple sources.
12
+ *
13
+ * Combines alerts, removes duplicates, filters by criteria, and sorts.
14
+ *
15
+ * @param alertSets - Arrays of alerts from different plugins
16
+ * @param options - Aggregation options
17
+ * @returns Aggregated and filtered alerts
18
+ */
19
+ aggregate(alertSets, options = {}) {
20
+ // Flatten all alerts
21
+ let alerts = alertSets.flat();
22
+ // Deduplicate
23
+ alerts = this.deduplicate(alerts);
24
+ // Filter by risk level
25
+ if (options.minRiskLevel) {
26
+ alerts = this.filterByRiskLevel(alerts, options.minRiskLevel);
27
+ }
28
+ // Filter by time range
29
+ if (options.timeRange) {
30
+ alerts = this.filterByTimeRange(alerts, options.timeRange);
31
+ }
32
+ // Filter by location radius
33
+ if (options.location && options.radiusMeters) {
34
+ alerts = this.filterByRadius(alerts, options.location, options.radiusMeters);
35
+ }
36
+ // Sort by priority (primary) and time (secondary)
37
+ alerts = this.sort(alerts, ['priority-asc', 'time-desc']);
38
+ // Apply limit
39
+ if (options.limit && alerts.length > options.limit) {
40
+ alerts = alerts.slice(0, options.limit);
41
+ }
42
+ return alerts;
43
+ }
44
+ /**
45
+ * Remove duplicate alerts based on ID and source.
46
+ *
47
+ * If two alerts have the same external ID from the same source,
48
+ * keep the one with the most recent issued timestamp.
49
+ */
50
+ deduplicate(alerts) {
51
+ const seen = new Map();
52
+ for (const alert of alerts) {
53
+ // Primary dedup key: alert ID
54
+ const primaryKey = alert.id;
55
+ // Secondary dedup key: source external ID (if available)
56
+ const secondaryKey = alert.source.externalId
57
+ ? `${alert.source.pluginId}:${alert.source.externalId}`
58
+ : null;
59
+ // Check primary key
60
+ const existingPrimary = seen.get(primaryKey);
61
+ if (existingPrimary) {
62
+ // Keep the more recent one
63
+ if (new Date(alert.timestamps.issued) > new Date(existingPrimary.timestamps.issued)) {
64
+ seen.set(primaryKey, alert);
65
+ }
66
+ continue;
67
+ }
68
+ // Check secondary key
69
+ if (secondaryKey) {
70
+ const existingSecondary = seen.get(secondaryKey);
71
+ if (existingSecondary) {
72
+ if (new Date(alert.timestamps.issued) > new Date(existingSecondary.timestamps.issued)) {
73
+ seen.set(secondaryKey, alert);
74
+ }
75
+ continue;
76
+ }
77
+ seen.set(secondaryKey, alert);
78
+ }
79
+ seen.set(primaryKey, alert);
80
+ }
81
+ return Array.from(seen.values());
82
+ }
83
+ /**
84
+ * Filter alerts by minimum risk level.
85
+ */
86
+ filterByRiskLevel(alerts, minLevel) {
87
+ const minValue = types_1.RISK_LEVEL_VALUES[minLevel];
88
+ return alerts.filter((alert) => types_1.RISK_LEVEL_VALUES[alert.riskLevel] >= minValue);
89
+ }
90
+ /**
91
+ * Filter alerts by time range.
92
+ *
93
+ * Includes alerts where:
94
+ * - The issued timestamp falls within the range, OR
95
+ * - The event start/end times overlap with the range
96
+ */
97
+ filterByTimeRange(alerts, range) {
98
+ const rangeStart = new Date(range.start).getTime();
99
+ const rangeEnd = new Date(range.end).getTime();
100
+ return alerts.filter((alert) => {
101
+ // Check if issued time is in range
102
+ const issuedTime = new Date(alert.timestamps.issued).getTime();
103
+ if (issuedTime >= rangeStart && issuedTime <= rangeEnd) {
104
+ return true;
105
+ }
106
+ // Check if event times overlap
107
+ const eventStart = alert.timestamps.eventStart
108
+ ? new Date(alert.timestamps.eventStart).getTime()
109
+ : null;
110
+ const eventEnd = alert.timestamps.eventEnd
111
+ ? new Date(alert.timestamps.eventEnd).getTime()
112
+ : null;
113
+ if (eventStart !== null && eventEnd !== null) {
114
+ // Event has both start and end - check for overlap
115
+ return eventStart <= rangeEnd && eventEnd >= rangeStart;
116
+ }
117
+ if (eventStart !== null) {
118
+ // Only start time - check if it's in range
119
+ return eventStart >= rangeStart && eventStart <= rangeEnd;
120
+ }
121
+ return false;
122
+ });
123
+ }
124
+ /**
125
+ * Filter alerts by distance from a center point.
126
+ */
127
+ filterByRadius(alerts, center, radiusMeters) {
128
+ return alerts.filter((alert) => {
129
+ const distance = (0, geo_1.haversineDistance)(center, alert.location.point);
130
+ return distance <= radiusMeters;
131
+ });
132
+ }
133
+ /**
134
+ * Sort alerts by one or more criteria.
135
+ *
136
+ * Later criteria are used as tiebreakers.
137
+ */
138
+ sort(alerts, orders) {
139
+ return [...alerts].sort((a, b) => {
140
+ for (const order of orders) {
141
+ const comparison = this.compare(a, b, order);
142
+ if (comparison !== 0)
143
+ return comparison;
144
+ }
145
+ return 0;
146
+ });
147
+ }
148
+ /**
149
+ * Compare two alerts based on a sort order.
150
+ */
151
+ compare(a, b, order) {
152
+ switch (order) {
153
+ case 'priority-asc':
154
+ return a.priority - b.priority;
155
+ case 'priority-desc':
156
+ return b.priority - a.priority;
157
+ case 'risk-asc':
158
+ return types_1.RISK_LEVEL_VALUES[a.riskLevel] - types_1.RISK_LEVEL_VALUES[b.riskLevel];
159
+ case 'risk-desc':
160
+ return types_1.RISK_LEVEL_VALUES[b.riskLevel] - types_1.RISK_LEVEL_VALUES[a.riskLevel];
161
+ case 'time-asc':
162
+ return new Date(a.timestamps.issued).getTime() - new Date(b.timestamps.issued).getTime();
163
+ case 'time-desc':
164
+ return new Date(b.timestamps.issued).getTime() - new Date(a.timestamps.issued).getTime();
165
+ case 'distance-asc':
166
+ case 'distance-desc':
167
+ // Distance sorting requires a reference point, not supported in basic compare
168
+ return 0;
169
+ }
170
+ }
171
+ /**
172
+ * Sort alerts by distance from a center point.
173
+ */
174
+ sortByDistance(alerts, center, ascending = true) {
175
+ return [...alerts].sort((a, b) => {
176
+ const distA = (0, geo_1.haversineDistance)(center, a.location.point);
177
+ const distB = (0, geo_1.haversineDistance)(center, b.location.point);
178
+ return ascending ? distA - distB : distB - distA;
179
+ });
180
+ }
181
+ /**
182
+ * Group alerts by category.
183
+ */
184
+ groupByCategory(alerts) {
185
+ const groups = new Map();
186
+ for (const alert of alerts) {
187
+ const existing = groups.get(alert.category) ?? [];
188
+ existing.push(alert);
189
+ groups.set(alert.category, existing);
190
+ }
191
+ return groups;
192
+ }
193
+ /**
194
+ * Group alerts by source plugin.
195
+ */
196
+ groupBySource(alerts) {
197
+ const groups = new Map();
198
+ for (const alert of alerts) {
199
+ const existing = groups.get(alert.source.pluginId) ?? [];
200
+ existing.push(alert);
201
+ groups.set(alert.source.pluginId, existing);
202
+ }
203
+ return groups;
204
+ }
205
+ }
206
+ exports.AlertAggregator = AlertAggregator;
207
+ //# sourceMappingURL=alert-aggregator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alert-aggregator.js","sourceRoot":"","sources":["../../../src/core/alert-aggregator.ts"],"names":[],"mappings":"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"}