@usa-open-data-connectors/usa-sources 0.1.7 → 0.1.9
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.
- package/README.md +229 -32
- package/dist/btsTransportationStats.d.ts +4 -0
- package/dist/btsTransportationStats.d.ts.map +1 -1
- package/dist/btsTransportationStats.js +3 -0
- package/dist/btsTransportationStats.js.map +1 -1
- package/dist/californiaOpenDataCatalogue.d.ts +84 -0
- package/dist/californiaOpenDataCatalogue.d.ts.map +1 -0
- package/dist/californiaOpenDataCatalogue.js +153 -0
- package/dist/californiaOpenDataCatalogue.js.map +1 -0
- package/dist/cdcSocrataCatalogue.d.ts +4 -0
- package/dist/cdcSocrataCatalogue.d.ts.map +1 -1
- package/dist/cdcSocrataCatalogue.js +3 -0
- package/dist/cdcSocrataCatalogue.js.map +1 -1
- package/dist/chicagoOpenDataCatalogue.d.ts +91 -0
- package/dist/chicagoOpenDataCatalogue.d.ts.map +1 -0
- package/dist/chicagoOpenDataCatalogue.js +133 -0
- package/dist/chicagoOpenDataCatalogue.js.map +1 -0
- package/dist/coloradoOpenDataCatalogue.d.ts +42 -0
- package/dist/coloradoOpenDataCatalogue.d.ts.map +1 -0
- package/dist/coloradoOpenDataCatalogue.js +45 -0
- package/dist/coloradoOpenDataCatalogue.js.map +1 -0
- package/dist/fccSocrataCatalogue.d.ts +91 -0
- package/dist/fccSocrataCatalogue.d.ts.map +1 -0
- package/dist/fccSocrataCatalogue.js +133 -0
- package/dist/fccSocrataCatalogue.js.map +1 -0
- package/dist/federalRegisterDocuments.d.ts +78 -0
- package/dist/federalRegisterDocuments.d.ts.map +1 -0
- package/dist/federalRegisterDocuments.js +119 -0
- package/dist/federalRegisterDocuments.js.map +1 -0
- package/dist/healthdataSocrataCatalogue.d.ts +4 -0
- package/dist/healthdataSocrataCatalogue.d.ts.map +1 -1
- package/dist/healthdataSocrataCatalogue.js +3 -0
- package/dist/healthdataSocrataCatalogue.js.map +1 -1
- package/dist/http.d.ts +14 -0
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +29 -1
- package/dist/http.js.map +1 -1
- package/dist/illinoisOpenDataCatalogue.d.ts +42 -0
- package/dist/illinoisOpenDataCatalogue.d.ts.map +1 -0
- package/dist/illinoisOpenDataCatalogue.js +45 -0
- package/dist/illinoisOpenDataCatalogue.js.map +1 -0
- package/dist/index.d.ts +76 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -1
- package/dist/losAngelesOpenDataCatalogue.d.ts +42 -0
- package/dist/losAngelesOpenDataCatalogue.d.ts.map +1 -0
- package/dist/losAngelesOpenDataCatalogue.js +48 -0
- package/dist/losAngelesOpenDataCatalogue.js.map +1 -0
- package/dist/michiganOpenDataCatalogue.d.ts +42 -0
- package/dist/michiganOpenDataCatalogue.d.ts.map +1 -0
- package/dist/michiganOpenDataCatalogue.js +45 -0
- package/dist/michiganOpenDataCatalogue.js.map +1 -0
- package/dist/newJerseyOpenDataCatalogue.d.ts +42 -0
- package/dist/newJerseyOpenDataCatalogue.d.ts.map +1 -0
- package/dist/newJerseyOpenDataCatalogue.js +48 -0
- package/dist/newJerseyOpenDataCatalogue.js.map +1 -0
- package/dist/nextBusTransitVehicles.d.ts.map +1 -1
- package/dist/nextBusTransitVehicles.js +14 -3
- package/dist/nextBusTransitVehicles.js.map +1 -1
- package/dist/nhtsaVehicleModels.d.ts +74 -0
- package/dist/nhtsaVehicleModels.d.ts.map +1 -0
- package/dist/nhtsaVehicleModels.js +139 -0
- package/dist/nhtsaVehicleModels.js.map +1 -0
- package/dist/nihReporterProjects.d.ts +98 -0
- package/dist/nihReporterProjects.d.ts.map +1 -0
- package/dist/nihReporterProjects.js +188 -0
- package/dist/nihReporterProjects.js.map +1 -0
- package/dist/nwsPointForecast.d.ts.map +1 -1
- package/dist/nwsPointForecast.js +13 -2
- package/dist/nwsPointForecast.js.map +1 -1
- package/dist/nyStateOpenDataCatalogue.d.ts +91 -0
- package/dist/nyStateOpenDataCatalogue.d.ts.map +1 -0
- package/dist/nyStateOpenDataCatalogue.js +133 -0
- package/dist/nyStateOpenDataCatalogue.js.map +1 -0
- package/dist/nycOpenDataCatalogue.d.ts +4 -0
- package/dist/nycOpenDataCatalogue.d.ts.map +1 -1
- package/dist/nycOpenDataCatalogue.js +3 -0
- package/dist/nycOpenDataCatalogue.js.map +1 -1
- package/dist/oregonOpenDataCatalogue.d.ts +42 -0
- package/dist/oregonOpenDataCatalogue.d.ts.map +1 -0
- package/dist/oregonOpenDataCatalogue.js +45 -0
- package/dist/oregonOpenDataCatalogue.js.map +1 -0
- package/dist/pennsylvaniaOpenDataCatalogue.d.ts +42 -0
- package/dist/pennsylvaniaOpenDataCatalogue.d.ts.map +1 -0
- package/dist/pennsylvaniaOpenDataCatalogue.js +48 -0
- package/dist/pennsylvaniaOpenDataCatalogue.js.map +1 -0
- package/dist/registry.d.ts +2 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +51 -3
- package/dist/registry.js.map +1 -1
- package/dist/sanFranciscoOpenDataCatalogue.d.ts +42 -0
- package/dist/sanFranciscoOpenDataCatalogue.d.ts.map +1 -0
- package/dist/sanFranciscoOpenDataCatalogue.js +48 -0
- package/dist/sanFranciscoOpenDataCatalogue.js.map +1 -0
- package/dist/seattleOpenDataCatalogue.d.ts +91 -0
- package/dist/seattleOpenDataCatalogue.d.ts.map +1 -0
- package/dist/seattleOpenDataCatalogue.js +133 -0
- package/dist/seattleOpenDataCatalogue.js.map +1 -0
- package/dist/socrataCatalogue.d.ts +121 -0
- package/dist/socrataCatalogue.d.ts.map +1 -0
- package/dist/socrataCatalogue.js +151 -0
- package/dist/socrataCatalogue.js.map +1 -0
- package/dist/socrataCatalogueMetadata.d.ts +19 -0
- package/dist/socrataCatalogueMetadata.d.ts.map +1 -0
- package/dist/socrataCatalogueMetadata.js +40 -0
- package/dist/socrataCatalogueMetadata.js.map +1 -0
- package/dist/texasOpenDataCatalogue.d.ts +91 -0
- package/dist/texasOpenDataCatalogue.d.ts.map +1 -0
- package/dist/texasOpenDataCatalogue.js +133 -0
- package/dist/texasOpenDataCatalogue.js.map +1 -0
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/vermontOpenDataCatalogue.d.ts +42 -0
- package/dist/vermontOpenDataCatalogue.d.ts.map +1 -0
- package/dist/vermontOpenDataCatalogue.js +45 -0
- package/dist/vermontOpenDataCatalogue.js.map +1 -0
- package/dist/washingtonStateOpenDataCatalogue.d.ts +42 -0
- package/dist/washingtonStateOpenDataCatalogue.d.ts.map +1 -0
- package/dist/washingtonStateOpenDataCatalogue.js +48 -0
- package/dist/washingtonStateOpenDataCatalogue.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { buildSocrataCatalogueUrl, createSocrataCatalogueAdapter, fetchSocrataCatalogue, parseSocrataCataloguePayload, SOCRATA_CATALOGUE_LIMIT, } from './socrataCatalogue.js';
|
|
2
|
+
/** Adapter id for the New Jersey Open Data catalogue source. */
|
|
3
|
+
export const NEW_JERSEY_OPEN_DATA_CATALOGUE_SOURCE_ID = 'new-jersey-open-data-catalogue';
|
|
4
|
+
/** Base URL for the New Jersey Open Data Socrata catalogue. */
|
|
5
|
+
export const NEW_JERSEY_OPEN_DATA_API_BASE = 'https://data.nj.gov/api/views.json';
|
|
6
|
+
/** How many catalogue entries one request reads. */
|
|
7
|
+
export const NEW_JERSEY_OPEN_DATA_CATALOGUE_LIMIT = SOCRATA_CATALOGUE_LIMIT;
|
|
8
|
+
/** Committed snapshot, so a build works when the New Jersey host is unreachable. */
|
|
9
|
+
const NEW_JERSEY_OPEN_DATA_FIXTURE_FILENAME = 'new-jersey-open-data-catalogue-2026-11-08.json';
|
|
10
|
+
/**
|
|
11
|
+
* Builds the request URL for one page of the New Jersey catalogue.
|
|
12
|
+
*
|
|
13
|
+
* @param options - an optional entry cap
|
|
14
|
+
* @returns the full request URL
|
|
15
|
+
*/
|
|
16
|
+
export function buildNewJerseyOpenDataCatalogueUrl(options) {
|
|
17
|
+
return buildSocrataCatalogueUrl(NEW_JERSEY_OPEN_DATA_API_BASE, options);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Parses one page of the New Jersey catalogue into entries and topic counts.
|
|
21
|
+
*
|
|
22
|
+
* @param payload - the JSON body from the New Jersey Socrata discovery API
|
|
23
|
+
* @returns the entries in the page, the counts, and the newest entry
|
|
24
|
+
*/
|
|
25
|
+
export function parseNewJerseyOpenDataCataloguePayload(payload) {
|
|
26
|
+
return parseSocrataCataloguePayload(NEW_JERSEY_OPEN_DATA_CATALOGUE_SOURCE_ID, payload);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Reads one page of the New Jersey Open Data catalogue.
|
|
30
|
+
*
|
|
31
|
+
* @param options - an optional entry cap and fetch stub
|
|
32
|
+
* @returns the entries in the page, the counts, and the newest entry
|
|
33
|
+
*/
|
|
34
|
+
export async function fetchNewJerseyOpenDataCatalogue(options) {
|
|
35
|
+
return fetchSocrataCatalogue({
|
|
36
|
+
sourceId: NEW_JERSEY_OPEN_DATA_CATALOGUE_SOURCE_ID,
|
|
37
|
+
apiBase: NEW_JERSEY_OPEN_DATA_API_BASE,
|
|
38
|
+
}, options);
|
|
39
|
+
}
|
|
40
|
+
/** New Jersey Open Data catalogue of datasets, files, and stories, keyless. */
|
|
41
|
+
export const newJerseyOpenDataCatalogueAdapter = createSocrataCatalogueAdapter({
|
|
42
|
+
sourceId: NEW_JERSEY_OPEN_DATA_CATALOGUE_SOURCE_ID,
|
|
43
|
+
name: 'New Jersey Open Data catalogue',
|
|
44
|
+
description: 'The New Jersey Open Data Socrata catalogue, one row per published dataset, file, story, or other resource, with its state topic, view count, and download count.',
|
|
45
|
+
apiBase: NEW_JERSEY_OPEN_DATA_API_BASE,
|
|
46
|
+
fixtureFilename: NEW_JERSEY_OPEN_DATA_FIXTURE_FILENAME,
|
|
47
|
+
});
|
|
48
|
+
//# sourceMappingURL=newJerseyOpenDataCatalogue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"newJerseyOpenDataCatalogue.js","sourceRoot":"","sources":["../src/newJerseyOpenDataCatalogue.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,6BAA6B,EAC7B,qBAAqB,EACrB,4BAA4B,EAC5B,uBAAuB,GAIxB,MAAM,uBAAuB,CAAC;AAE/B,gEAAgE;AAChE,MAAM,CAAC,MAAM,wCAAwC,GAAG,gCAAgC,CAAC;AAEzF,+DAA+D;AAC/D,MAAM,CAAC,MAAM,6BAA6B,GAAG,oCAAoC,CAAC;AAElF,oDAAoD;AACpD,MAAM,CAAC,MAAM,oCAAoC,GAAG,uBAAuB,CAAC;AAW5E,oFAAoF;AACpF,MAAM,qCAAqC,GAAG,gDAAgD,CAAC;AAE/F;;;;;GAKG;AACH,MAAM,UAAU,kCAAkC,CAAC,OAA4B;IAC7E,OAAO,wBAAwB,CAAC,6BAA6B,EAAE,OAAO,CAAC,CAAC;AAC1E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sCAAsC,CACpD,OAAgB;IAEhB,OAAO,4BAA4B,CAAC,wCAAwC,EAAE,OAAO,CAAC,CAAC;AACzF,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,+BAA+B,CAAC,OAGrD;IACC,OAAO,qBAAqB,CAC1B;QACE,QAAQ,EAAE,wCAAwC;QAClD,OAAO,EAAE,6BAA6B;KACvC,EACD,OAAO,CACR,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,MAAM,CAAC,MAAM,iCAAiC,GAAG,6BAA6B,CAAC;IAC7E,QAAQ,EAAE,wCAAwC;IAClD,IAAI,EAAE,gCAAgC;IACtC,WAAW,EACT,kKAAkK;IACpK,OAAO,EAAE,6BAA6B;IACtC,eAAe,EAAE,qCAAqC;CACvD,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nextBusTransitVehicles.d.ts","sourceRoot":"","sources":["../src/nextBusTransitVehicles.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,yDAAyD;AACzD,eAAO,MAAM,kCAAkC,6BAA6B,CAAC;AAE7E,iDAAiD;AACjD,eAAO,MAAM,qBAAqB,kDAAkD,CAAC;AAErF,iEAAiE;AACjE,eAAO,MAAM,qCAAqC,gBAAgB,CAAC;AAEnE,oDAAoD;AACpD,eAAO,MAAM,oCAAoC,QAAQ,CAAC;AAE1D,0DAA0D;AAC1D,eAAO,MAAM,gCAAgC;aAC3C,SAAS;aACT,QAAQ;CACA,CAAC;AAKX,0DAA0D;AAC1D,MAAM,WAAW,mBAAmB;IAClC,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,gDAAgD;AAChD,MAAM,WAAW,cAAc;IAC7B,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,QAAQ,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,YAAY,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,6EAA6E;IAC7E,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,qEAAqE;IACrE,kBAAkB,EAAE,MAAM,CAAC;IAC3B,6EAA6E;IAC7E,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,0DAA0D;AAC1D,MAAM,WAAW,sBAAsB;IACrC,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,iBAAiB,EAAE,MAAM,CAAC;IAC1B,8BAA8B;IAC9B,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,0CAA0C;IAC1C,YAAY,EAAE,MAAM,CAAC;IACrB,sDAAsD;IACtD,uBAAuB,EAAE,MAAM,CAAC;IAChC,mDAAmD;IACnD,qBAAqB,EAAE,MAAM,CAAC;IAC9B,gFAAgF;IAChF,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,8EAA8E;IAC9E,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAqDD;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAQzE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,OAAO,EAChB,KAAK,GAAE,mBAAsD,GAC5D,sBAAsB,CAyDxB;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,CAAC,EAAE;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACrC,GAAG,OAAO,CAAC,sBAAsB,CAAC,
|
|
1
|
+
{"version":3,"file":"nextBusTransitVehicles.d.ts","sourceRoot":"","sources":["../src/nextBusTransitVehicles.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,yDAAyD;AACzD,eAAO,MAAM,kCAAkC,6BAA6B,CAAC;AAE7E,iDAAiD;AACjD,eAAO,MAAM,qBAAqB,kDAAkD,CAAC;AAErF,iEAAiE;AACjE,eAAO,MAAM,qCAAqC,gBAAgB,CAAC;AAEnE,oDAAoD;AACpD,eAAO,MAAM,oCAAoC,QAAQ,CAAC;AAE1D,0DAA0D;AAC1D,eAAO,MAAM,gCAAgC;aAC3C,SAAS;aACT,QAAQ;CACA,CAAC;AAKX,0DAA0D;AAC1D,MAAM,WAAW,mBAAmB;IAClC,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,gDAAgD;AAChD,MAAM,WAAW,cAAc;IAC7B,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,QAAQ,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,YAAY,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,6EAA6E;IAC7E,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,qEAAqE;IACrE,kBAAkB,EAAE,MAAM,CAAC;IAC3B,6EAA6E;IAC7E,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,0DAA0D;AAC1D,MAAM,WAAW,sBAAsB;IACrC,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,iBAAiB,EAAE,MAAM,CAAC;IAC1B,8BAA8B;IAC9B,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,0CAA0C;IAC1C,YAAY,EAAE,MAAM,CAAC;IACrB,sDAAsD;IACtD,uBAAuB,EAAE,MAAM,CAAC;IAChC,mDAAmD;IACnD,qBAAqB,EAAE,MAAM,CAAC;IAC9B,gFAAgF;IAChF,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,8EAA8E;IAC9E,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAqDD;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAQzE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,OAAO,EAChB,KAAK,GAAE,mBAAsD,GAC5D,sBAAsB,CAyDxB;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,CAAC,EAAE;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACrC,GAAG,OAAO,CAAC,sBAAsB,CAAC,CA+BlC;AAED,0FAA0F;AAC1F,eAAO,MAAM,6BAA6B,EAAE,aAAa,CAAC,sBAAsB,CAU/E,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { XMLParser } from 'fast-xml-parser';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { UsSourceParseError } from './errors.js';
|
|
3
|
+
import { UsSourceApiError, UsSourceParseError } from './errors.js';
|
|
4
4
|
import { readFixtureText } from './fixtures.js';
|
|
5
5
|
import { httpGet } from './http.js';
|
|
6
6
|
/** Adapter id for the NextBus transit vehicle source. */
|
|
@@ -151,9 +151,20 @@ export function parseNextBusVehiclePayload(payload, query = NEXTBUS_PORTLAND_STR
|
|
|
151
151
|
* @returns one report per vehicle, plus counts and report ages
|
|
152
152
|
*/
|
|
153
153
|
export async function fetchNextBusVehicles(options) {
|
|
154
|
+
const agencyTag = options?.agencyTag;
|
|
155
|
+
const routeTag = options?.routeTag;
|
|
156
|
+
if ((agencyTag === undefined) !== (routeTag === undefined)) {
|
|
157
|
+
throw new UsSourceApiError(NEXTBUS_TRANSIT_VEHICLES_SOURCE_ID, 'Pass both agencyTag and routeTag, or neither.');
|
|
158
|
+
}
|
|
159
|
+
if (agencyTag?.trim().length === 0) {
|
|
160
|
+
throw new UsSourceApiError(NEXTBUS_TRANSIT_VEHICLES_SOURCE_ID, 'agencyTag must not be empty or whitespace.');
|
|
161
|
+
}
|
|
162
|
+
if (routeTag?.trim().length === 0) {
|
|
163
|
+
throw new UsSourceApiError(NEXTBUS_TRANSIT_VEHICLES_SOURCE_ID, 'routeTag must not be empty or whitespace.');
|
|
164
|
+
}
|
|
154
165
|
const query = {
|
|
155
|
-
agencyTag:
|
|
156
|
-
routeTag:
|
|
166
|
+
agencyTag: agencyTag?.trim() ?? NEXTBUS_PORTLAND_STREETCAR_AGENCY_TAG,
|
|
167
|
+
routeTag: routeTag?.trim() ?? NEXTBUS_PORTLAND_STREETCAR_ROUTE_TAG,
|
|
157
168
|
};
|
|
158
169
|
const response = await httpGet(NEXTBUS_TRANSIT_VEHICLES_SOURCE_ID, buildNextBusVehicleUrl(query), options?.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl });
|
|
159
170
|
return parseNextBusVehiclePayload(await response.text(), query);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nextBusTransitVehicles.js","sourceRoot":"","sources":["../src/nextBusTransitVehicles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"nextBusTransitVehicles.js","sourceRoot":"","sources":["../src/nextBusTransitVehicles.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { UsDataAdapter } from './types.js';
|
|
2
|
+
/** Adapter id for the NHTSA vehicle models source. */
|
|
3
|
+
export declare const NHTSA_VEHICLE_MODELS_SOURCE_ID = "nhtsa-vehicle-models";
|
|
4
|
+
/** Base URL for the NHTSA vehicle models API. */
|
|
5
|
+
export declare const NHTSA_VEHICLE_MODELS_API_BASE = "https://api.nhtsa.gov/vehicles/models";
|
|
6
|
+
/** Model year the default request reads. */
|
|
7
|
+
export declare const NHTSA_DEFAULT_MODEL_YEAR = 2025;
|
|
8
|
+
/** Make the default request reads. */
|
|
9
|
+
export declare const NHTSA_DEFAULT_MAKE = "Honda";
|
|
10
|
+
/** Largest page one request asks for. */
|
|
11
|
+
export declare const NHTSA_MODEL_PAGE_SIZE = 100;
|
|
12
|
+
/** Earliest model year the adapter accepts. */
|
|
13
|
+
export declare const NHTSA_MIN_MODEL_YEAR = 1900;
|
|
14
|
+
/** Latest model year the adapter accepts. */
|
|
15
|
+
export declare const NHTSA_MAX_MODEL_YEAR = 2100;
|
|
16
|
+
/** One vehicle model NHTSA lists for a model year and make. */
|
|
17
|
+
export interface NhtsaVehicleModel {
|
|
18
|
+
modelYear: number;
|
|
19
|
+
make: string;
|
|
20
|
+
vehicleModel: string;
|
|
21
|
+
}
|
|
22
|
+
/** One page of NHTSA vehicle models, with the service's pagination metadata. */
|
|
23
|
+
export interface NhtsaVehicleModelPage {
|
|
24
|
+
models: NhtsaVehicleModel[];
|
|
25
|
+
modelCount: number;
|
|
26
|
+
/** How many models the service says the query matches. */
|
|
27
|
+
totalCount: number;
|
|
28
|
+
offset: number;
|
|
29
|
+
max: number;
|
|
30
|
+
nextUrl: string | null;
|
|
31
|
+
}
|
|
32
|
+
/** Caller-selected filters for one model list. */
|
|
33
|
+
export interface NhtsaVehicleModelsQuery {
|
|
34
|
+
modelYear?: number;
|
|
35
|
+
make?: string;
|
|
36
|
+
max?: number;
|
|
37
|
+
offset?: number;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Builds the request URL for one page of vehicle models.
|
|
41
|
+
*
|
|
42
|
+
* The endpoint is keyless. The default query is the 2025 Honda model list,
|
|
43
|
+
* which is the page the committed fixture captured.
|
|
44
|
+
*
|
|
45
|
+
* @param query - an optional model year, make, page size, and offset
|
|
46
|
+
* @returns the full request URL
|
|
47
|
+
*/
|
|
48
|
+
export declare function buildNhtsaVehicleModelsUrl(query?: NhtsaVehicleModelsQuery): string;
|
|
49
|
+
/**
|
|
50
|
+
* Parses one page of vehicle models.
|
|
51
|
+
*
|
|
52
|
+
* A response whose service status is not 200 is an API error even when the
|
|
53
|
+
* host answers HTTP 200. A model without its year, make, or name is a changed
|
|
54
|
+
* shape and stops the parse. An empty page is valid.
|
|
55
|
+
*
|
|
56
|
+
* @param payload - the JSON body from the NHTSA vehicle models API
|
|
57
|
+
* @returns the models on the page and the service's pagination metadata
|
|
58
|
+
*/
|
|
59
|
+
export declare function parseNhtsaVehicleModelsPayload(payload: unknown): NhtsaVehicleModelPage;
|
|
60
|
+
/**
|
|
61
|
+
* Reads one page of NHTSA vehicle models.
|
|
62
|
+
*
|
|
63
|
+
* One keyless request returns the models for one model year and make, plus
|
|
64
|
+
* the service's total and next-page URL.
|
|
65
|
+
*
|
|
66
|
+
* @param query - an optional model year, make, page window, and fetch stub
|
|
67
|
+
* @returns the models on the page and the service's pagination metadata
|
|
68
|
+
*/
|
|
69
|
+
export declare function fetchNhtsaVehicleModels(query?: NhtsaVehicleModelsQuery & {
|
|
70
|
+
fetchImpl?: typeof globalThis.fetch;
|
|
71
|
+
}): Promise<NhtsaVehicleModelPage>;
|
|
72
|
+
/** NHTSA vehicle models for one model year and make, keyless. */
|
|
73
|
+
export declare const nhtsaVehicleModelsAdapter: UsDataAdapter<NhtsaVehicleModelPage>;
|
|
74
|
+
//# sourceMappingURL=nhtsaVehicleModels.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nhtsaVehicleModels.d.ts","sourceRoot":"","sources":["../src/nhtsaVehicleModels.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,sDAAsD;AACtD,eAAO,MAAM,8BAA8B,yBAAyB,CAAC;AAErE,iDAAiD;AACjD,eAAO,MAAM,6BAA6B,0CAA0C,CAAC;AAErF,4CAA4C;AAC5C,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C,sCAAsC;AACtC,eAAO,MAAM,kBAAkB,UAAU,CAAC;AAE1C,yCAAyC;AACzC,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC,+CAA+C;AAC/C,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAEzC,6CAA6C;AAC7C,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAEzC,+DAA+D;AAC/D,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,gFAAgF;AAChF,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,kDAAkD;AAClD,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA6DD;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,GAAE,uBAA4B,GAAG,MAAM,CAStF;AAED;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,OAAO,GAAG,qBAAqB,CAqBtF;AAED;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,GAAE,uBAAuB,GAAG;IAAE,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CAAO,GAC5E,OAAO,CAAC,qBAAqB,CAAC,CAUhC;AAED,iEAAiE;AACjE,eAAO,MAAM,yBAAyB,EAAE,aAAa,CAAC,qBAAqB,CAa1E,CAAC"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { UsSourceApiError, UsSourceParseError } from './errors.js';
|
|
3
|
+
import { readFixtureJson } from './fixtures.js';
|
|
4
|
+
import { httpGet } from './http.js';
|
|
5
|
+
/** Adapter id for the NHTSA vehicle models source. */
|
|
6
|
+
export const NHTSA_VEHICLE_MODELS_SOURCE_ID = 'nhtsa-vehicle-models';
|
|
7
|
+
/** Base URL for the NHTSA vehicle models API. */
|
|
8
|
+
export const NHTSA_VEHICLE_MODELS_API_BASE = 'https://api.nhtsa.gov/vehicles/models';
|
|
9
|
+
/** Model year the default request reads. */
|
|
10
|
+
export const NHTSA_DEFAULT_MODEL_YEAR = 2025;
|
|
11
|
+
/** Make the default request reads. */
|
|
12
|
+
export const NHTSA_DEFAULT_MAKE = 'Honda';
|
|
13
|
+
/** Largest page one request asks for. */
|
|
14
|
+
export const NHTSA_MODEL_PAGE_SIZE = 100;
|
|
15
|
+
/** Earliest model year the adapter accepts. */
|
|
16
|
+
export const NHTSA_MIN_MODEL_YEAR = 1900;
|
|
17
|
+
/** Latest model year the adapter accepts. */
|
|
18
|
+
export const NHTSA_MAX_MODEL_YEAR = 2100;
|
|
19
|
+
/** Committed snapshot, so a build works when the NHTSA host is unreachable. */
|
|
20
|
+
const NHTSA_VEHICLE_MODELS_FIXTURE_FILENAME = 'nhtsa-vehicle-models-2025-honda-2026-11-08.json';
|
|
21
|
+
const NHTSA_MODEL_SCHEMA = z.object({
|
|
22
|
+
modelYear: z.number().int(),
|
|
23
|
+
make: z.string().min(1),
|
|
24
|
+
vehicleModel: z.string().min(1),
|
|
25
|
+
});
|
|
26
|
+
const NHTSA_PAGINATION_SCHEMA = z.object({
|
|
27
|
+
count: z.number().int().nonnegative(),
|
|
28
|
+
max: z.number().int().nonnegative(),
|
|
29
|
+
offset: z.number().int().nonnegative(),
|
|
30
|
+
total: z.number().int().nonnegative(),
|
|
31
|
+
nextUrl: z.string().nullable().optional(),
|
|
32
|
+
});
|
|
33
|
+
const NHTSA_PAYLOAD_SCHEMA = z.object({
|
|
34
|
+
meta: z.object({
|
|
35
|
+
status: z.number().int(),
|
|
36
|
+
messages: z.array(z.unknown()).optional(),
|
|
37
|
+
pagination: NHTSA_PAGINATION_SCHEMA,
|
|
38
|
+
}),
|
|
39
|
+
results: z.array(NHTSA_MODEL_SCHEMA),
|
|
40
|
+
});
|
|
41
|
+
/** Throws when a model year or page value cannot be sent to the service. */
|
|
42
|
+
function validateNhtsaQuery(query) {
|
|
43
|
+
const modelYear = query.modelYear ?? NHTSA_DEFAULT_MODEL_YEAR;
|
|
44
|
+
if (!Number.isInteger(modelYear) ||
|
|
45
|
+
modelYear < NHTSA_MIN_MODEL_YEAR ||
|
|
46
|
+
modelYear > NHTSA_MAX_MODEL_YEAR) {
|
|
47
|
+
throw new UsSourceApiError(NHTSA_VEHICLE_MODELS_SOURCE_ID, `modelYear must be a whole number from ${NHTSA_MIN_MODEL_YEAR} to ${NHTSA_MAX_MODEL_YEAR}.`);
|
|
48
|
+
}
|
|
49
|
+
const make = query.make ?? NHTSA_DEFAULT_MAKE;
|
|
50
|
+
if (make.trim() === '') {
|
|
51
|
+
throw new UsSourceApiError(NHTSA_VEHICLE_MODELS_SOURCE_ID, 'make must not be blank.');
|
|
52
|
+
}
|
|
53
|
+
const max = query.max ?? NHTSA_MODEL_PAGE_SIZE;
|
|
54
|
+
if (!Number.isInteger(max) || max < 1) {
|
|
55
|
+
throw new UsSourceApiError(NHTSA_VEHICLE_MODELS_SOURCE_ID, 'max must be a whole number of at least 1.');
|
|
56
|
+
}
|
|
57
|
+
const offset = query.offset ?? 0;
|
|
58
|
+
if (!Number.isInteger(offset) || offset < 0) {
|
|
59
|
+
throw new UsSourceApiError(NHTSA_VEHICLE_MODELS_SOURCE_ID, 'offset must be a whole number of at least 0.');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Builds the request URL for one page of vehicle models.
|
|
64
|
+
*
|
|
65
|
+
* The endpoint is keyless. The default query is the 2025 Honda model list,
|
|
66
|
+
* which is the page the committed fixture captured.
|
|
67
|
+
*
|
|
68
|
+
* @param query - an optional model year, make, page size, and offset
|
|
69
|
+
* @returns the full request URL
|
|
70
|
+
*/
|
|
71
|
+
export function buildNhtsaVehicleModelsUrl(query = {}) {
|
|
72
|
+
validateNhtsaQuery(query);
|
|
73
|
+
const params = new URLSearchParams({
|
|
74
|
+
modelYear: String(query.modelYear ?? NHTSA_DEFAULT_MODEL_YEAR),
|
|
75
|
+
make: (query.make ?? NHTSA_DEFAULT_MAKE).trim(),
|
|
76
|
+
max: String(query.max ?? NHTSA_MODEL_PAGE_SIZE),
|
|
77
|
+
offset: String(query.offset ?? 0),
|
|
78
|
+
});
|
|
79
|
+
return `${NHTSA_VEHICLE_MODELS_API_BASE}?${params.toString()}`;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Parses one page of vehicle models.
|
|
83
|
+
*
|
|
84
|
+
* A response whose service status is not 200 is an API error even when the
|
|
85
|
+
* host answers HTTP 200. A model without its year, make, or name is a changed
|
|
86
|
+
* shape and stops the parse. An empty page is valid.
|
|
87
|
+
*
|
|
88
|
+
* @param payload - the JSON body from the NHTSA vehicle models API
|
|
89
|
+
* @returns the models on the page and the service's pagination metadata
|
|
90
|
+
*/
|
|
91
|
+
export function parseNhtsaVehicleModelsPayload(payload) {
|
|
92
|
+
const parsed = NHTSA_PAYLOAD_SCHEMA.safeParse(payload);
|
|
93
|
+
if (!parsed.success) {
|
|
94
|
+
throw new UsSourceParseError(NHTSA_VEHICLE_MODELS_SOURCE_ID, parsed.error.message);
|
|
95
|
+
}
|
|
96
|
+
if (parsed.data.meta.status !== 200) {
|
|
97
|
+
throw new UsSourceApiError(NHTSA_VEHICLE_MODELS_SOURCE_ID, `NHTSA reported status ${parsed.data.meta.status}`);
|
|
98
|
+
}
|
|
99
|
+
const pagination = parsed.data.meta.pagination;
|
|
100
|
+
return {
|
|
101
|
+
models: parsed.data.results,
|
|
102
|
+
modelCount: parsed.data.results.length,
|
|
103
|
+
totalCount: pagination.total,
|
|
104
|
+
offset: pagination.offset,
|
|
105
|
+
max: pagination.max,
|
|
106
|
+
nextUrl: pagination.nextUrl ?? null,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Reads one page of NHTSA vehicle models.
|
|
111
|
+
*
|
|
112
|
+
* One keyless request returns the models for one model year and make, plus
|
|
113
|
+
* the service's total and next-page URL.
|
|
114
|
+
*
|
|
115
|
+
* @param query - an optional model year, make, page window, and fetch stub
|
|
116
|
+
* @returns the models on the page and the service's pagination metadata
|
|
117
|
+
*/
|
|
118
|
+
export async function fetchNhtsaVehicleModels(query = {}) {
|
|
119
|
+
const fetchImpl = query.fetchImpl ?? globalThis.fetch;
|
|
120
|
+
const url = buildNhtsaVehicleModelsUrl({
|
|
121
|
+
...(query.modelYear === undefined ? {} : { modelYear: query.modelYear }),
|
|
122
|
+
...(query.make === undefined ? {} : { make: query.make }),
|
|
123
|
+
...(query.max === undefined ? {} : { max: query.max }),
|
|
124
|
+
...(query.offset === undefined ? {} : { offset: query.offset }),
|
|
125
|
+
});
|
|
126
|
+
const response = await httpGet(NHTSA_VEHICLE_MODELS_SOURCE_ID, url, { fetchImpl });
|
|
127
|
+
return parseNhtsaVehicleModelsPayload(await response.json());
|
|
128
|
+
}
|
|
129
|
+
/** NHTSA vehicle models for one model year and make, keyless. */
|
|
130
|
+
export const nhtsaVehicleModelsAdapter = {
|
|
131
|
+
id: NHTSA_VEHICLE_MODELS_SOURCE_ID,
|
|
132
|
+
name: 'NHTSA vehicle models',
|
|
133
|
+
auth: 'none',
|
|
134
|
+
description: 'Vehicle models NHTSA lists for one model year and make, one row per model, with the service total and next-page URL.',
|
|
135
|
+
fetchLive: async (options) => fetchNhtsaVehicleModels(options?.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
|
|
136
|
+
parse: (payload) => parseNhtsaVehicleModelsPayload(payload),
|
|
137
|
+
loadFixture: () => parseNhtsaVehicleModelsPayload(readFixtureJson(NHTSA_VEHICLE_MODELS_FIXTURE_FILENAME)),
|
|
138
|
+
};
|
|
139
|
+
//# sourceMappingURL=nhtsaVehicleModels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nhtsaVehicleModels.js","sourceRoot":"","sources":["../src/nhtsaVehicleModels.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { UsDataAdapter } from './types.js';
|
|
2
|
+
/** Adapter id for the NIH RePORTER funded-projects source. */
|
|
3
|
+
export declare const NIH_REPORTER_SOURCE_ID = "nih-reporter-projects";
|
|
4
|
+
/** Base URL for the NIH RePORTER v2 project search endpoint. */
|
|
5
|
+
export declare const NIH_REPORTER_SEARCH_URL = "https://api.reporter.nih.gov/v2/projects/search";
|
|
6
|
+
/** Fiscal year the committed fixture covers. */
|
|
7
|
+
export declare const NIH_REPORTER_DEFAULT_FISCAL_YEAR = 2025;
|
|
8
|
+
/** Number of projects one request asks for. */
|
|
9
|
+
export declare const NIH_REPORTER_PAGE_SIZE = 10;
|
|
10
|
+
/** One funded NIH project, trimmed to the fields a story reads. */
|
|
11
|
+
export interface NihReporterProject {
|
|
12
|
+
/** The agency's project number, e.g. "5R01AI000001-01". */
|
|
13
|
+
projectNumber: string;
|
|
14
|
+
/** Core project number shared by awards under the same project, or null. */
|
|
15
|
+
coreProjectNumber: string | null;
|
|
16
|
+
projectTitle: string;
|
|
17
|
+
fiscalYear: number;
|
|
18
|
+
/** Award amount in US dollars for the fiscal year, or null when absent. */
|
|
19
|
+
awardAmount: number | null;
|
|
20
|
+
organizationName: string;
|
|
21
|
+
organizationCity: string | null;
|
|
22
|
+
organizationState: string | null;
|
|
23
|
+
/** Investigator names with repeated whitespace collapsed. */
|
|
24
|
+
principalInvestigators: string[];
|
|
25
|
+
/** NIH institute or centre that administers the project, or null. */
|
|
26
|
+
administeringInstitute: string | null;
|
|
27
|
+
/** Project start date as YYYY-MM-DD, or null when absent. */
|
|
28
|
+
projectStartDate: string | null;
|
|
29
|
+
/** Project end date as YYYY-MM-DD, or null when absent. */
|
|
30
|
+
projectEndDate: string | null;
|
|
31
|
+
/** Public RePORTER page for the project, or null when absent. */
|
|
32
|
+
projectDetailUrl: string | null;
|
|
33
|
+
}
|
|
34
|
+
/** One page of NIH RePORTER projects, with the agency's total match count. */
|
|
35
|
+
export interface NihReporterProjectPage {
|
|
36
|
+
projects: NihReporterProject[];
|
|
37
|
+
projectCount: number;
|
|
38
|
+
totalCount: number;
|
|
39
|
+
offset: number;
|
|
40
|
+
limit: number;
|
|
41
|
+
/** Sum of the award amounts on this page, in US dollars. */
|
|
42
|
+
pageAwardAmountUsd: number;
|
|
43
|
+
}
|
|
44
|
+
/** Caller-selected filters for one project search. */
|
|
45
|
+
export interface NihReporterProjectQuery {
|
|
46
|
+
fiscalYear?: number;
|
|
47
|
+
limit?: number;
|
|
48
|
+
offset?: number;
|
|
49
|
+
}
|
|
50
|
+
/** JSON body sent to the NIH RePORTER v2 project search endpoint. */
|
|
51
|
+
export interface NihReporterSearchBody {
|
|
52
|
+
criteria: {
|
|
53
|
+
fiscal_years: number[];
|
|
54
|
+
agencies: string[];
|
|
55
|
+
};
|
|
56
|
+
include_fields: string[];
|
|
57
|
+
offset: number;
|
|
58
|
+
limit: number;
|
|
59
|
+
sort_field: string;
|
|
60
|
+
sort_order: 'asc' | 'desc';
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Builds the JSON body for one project search.
|
|
64
|
+
*
|
|
65
|
+
* The endpoint is keyless. The default page is fiscal 2025, the year the
|
|
66
|
+
* fixture covers, ordered by the largest award first so repeated calls return
|
|
67
|
+
* a stable, useful slice of the file.
|
|
68
|
+
*
|
|
69
|
+
* @param query - an optional fiscal year, page size, and offset
|
|
70
|
+
* @returns the request body for the search endpoint
|
|
71
|
+
*/
|
|
72
|
+
export declare function buildNihReporterSearchBody(query?: NihReporterProjectQuery): NihReporterSearchBody;
|
|
73
|
+
/**
|
|
74
|
+
* Parses one NIH RePORTER project search response.
|
|
75
|
+
*
|
|
76
|
+
* A body carrying a top-level message is an API error, even when the host
|
|
77
|
+
* answers HTTP 200. A project without its number, title, fiscal year, or
|
|
78
|
+
* organization is a changed shape and stops the parse.
|
|
79
|
+
*
|
|
80
|
+
* @param payload - the JSON body from the NIH RePORTER search endpoint
|
|
81
|
+
* @returns the projects on the page, the agency total, and the page award sum
|
|
82
|
+
*/
|
|
83
|
+
export declare function parseNihReporterProjectsPayload(payload: unknown): NihReporterProjectPage;
|
|
84
|
+
/**
|
|
85
|
+
* Reads one page of NIH-funded projects through the RePORTER search API.
|
|
86
|
+
*
|
|
87
|
+
* One keyless POST returns a page of projects, the total number of matches,
|
|
88
|
+
* and the combined award value on that page.
|
|
89
|
+
*
|
|
90
|
+
* @param options - an optional fiscal year, page window, and fetch stub
|
|
91
|
+
* @returns the projects on the page and the search totals
|
|
92
|
+
*/
|
|
93
|
+
export declare function fetchNihReporterProjects(options?: NihReporterProjectQuery & {
|
|
94
|
+
fetchImpl?: typeof globalThis.fetch;
|
|
95
|
+
}): Promise<NihReporterProjectPage>;
|
|
96
|
+
/** NIH RePORTER funded projects, one row per project, keyless. */
|
|
97
|
+
export declare const nihReporterProjectsAdapter: UsDataAdapter<NihReporterProjectPage>;
|
|
98
|
+
//# sourceMappingURL=nihReporterProjects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nihReporterProjects.d.ts","sourceRoot":"","sources":["../src/nihReporterProjects.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,8DAA8D;AAC9D,eAAO,MAAM,sBAAsB,0BAA0B,CAAC;AAE9D,gEAAgE;AAChE,eAAO,MAAM,uBAAuB,oDAAoD,CAAC;AAEzF,gDAAgD;AAChD,eAAO,MAAM,gCAAgC,OAAO,CAAC;AAErD,+CAA+C;AAC/C,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,mEAAmE;AACnE,MAAM,WAAW,kBAAkB;IACjC,2DAA2D;IAC3D,aAAa,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,6DAA6D;IAC7D,sBAAsB,EAAE,MAAM,EAAE,CAAC;IACjC,qEAAqE;IACrE,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,6DAA6D;IAC7D,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,2DAA2D;IAC3D,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,iEAAiE;IACjE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,8EAA8E;AAC9E,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,kBAAkB,EAAE,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,sDAAsD;AACtD,MAAM,WAAW,uBAAuB;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qEAAqE;AACrE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE;QACR,YAAY,EAAE,MAAM,EAAE,CAAC;QACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;IACF,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,KAAK,GAAG,MAAM,CAAC;CAC5B;AAwDD;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,GAAE,uBAA4B,GAClC,qBAAqB,CAYvB;AAmBD;;;;;;;;;GASG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,OAAO,GAAG,sBAAsB,CAkDxF;AAED;;;;;;;;GAQG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,GAAE,uBAAuB,GAAG;IAAE,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CAAO,GAC9E,OAAO,CAAC,sBAAsB,CAAC,CAYjC;AAED,kEAAkE;AAClE,eAAO,MAAM,0BAA0B,EAAE,aAAa,CAAC,sBAAsB,CAa5E,CAAC"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { UsSourceApiError, UsSourceParseError } from './errors.js';
|
|
3
|
+
import { readFixtureJson } from './fixtures.js';
|
|
4
|
+
import { httpPostJson } from './http.js';
|
|
5
|
+
/** Adapter id for the NIH RePORTER funded-projects source. */
|
|
6
|
+
export const NIH_REPORTER_SOURCE_ID = 'nih-reporter-projects';
|
|
7
|
+
/** Base URL for the NIH RePORTER v2 project search endpoint. */
|
|
8
|
+
export const NIH_REPORTER_SEARCH_URL = 'https://api.reporter.nih.gov/v2/projects/search';
|
|
9
|
+
/** Fiscal year the committed fixture covers. */
|
|
10
|
+
export const NIH_REPORTER_DEFAULT_FISCAL_YEAR = 2025;
|
|
11
|
+
/** Number of projects one request asks for. */
|
|
12
|
+
export const NIH_REPORTER_PAGE_SIZE = 10;
|
|
13
|
+
/** Committed snapshot, so a build works when the NIH host is unreachable. */
|
|
14
|
+
const NIH_REPORTER_FIXTURE_FILENAME = 'nih-reporter-projects-fy2025-2026-11-07.json';
|
|
15
|
+
/** Columns the adapter asks for. The full project record carries many more. */
|
|
16
|
+
const NIH_REPORTER_INCLUDE_FIELDS = [
|
|
17
|
+
'ProjectNum',
|
|
18
|
+
'CoreProjectNum',
|
|
19
|
+
'ProjectTitle',
|
|
20
|
+
'FiscalYear',
|
|
21
|
+
'AwardAmount',
|
|
22
|
+
'Organization',
|
|
23
|
+
'PrincipalInvestigators',
|
|
24
|
+
'ProjectStartDate',
|
|
25
|
+
'ProjectEndDate',
|
|
26
|
+
'AgencyIcAdmin',
|
|
27
|
+
'ProjectDetailUrl',
|
|
28
|
+
];
|
|
29
|
+
const NIH_REPORTER_PROJECT_SCHEMA = z.object({
|
|
30
|
+
fiscal_year: z.number(),
|
|
31
|
+
project_num: z.string(),
|
|
32
|
+
core_project_num: z.string().nullable().optional(),
|
|
33
|
+
project_title: z.string(),
|
|
34
|
+
award_amount: z.number().nullable().optional(),
|
|
35
|
+
organization: z.object({
|
|
36
|
+
org_name: z.string(),
|
|
37
|
+
org_city: z.string().nullable().optional(),
|
|
38
|
+
org_state: z.string().nullable().optional(),
|
|
39
|
+
}),
|
|
40
|
+
principal_investigators: z
|
|
41
|
+
.array(z.object({ full_name: z.string().optional() }))
|
|
42
|
+
.nullable()
|
|
43
|
+
.optional(),
|
|
44
|
+
agency_ic_admin: z
|
|
45
|
+
.object({ abbreviation: z.string().optional(), name: z.string().optional() })
|
|
46
|
+
.nullable()
|
|
47
|
+
.optional(),
|
|
48
|
+
project_start_date: z.string().nullable().optional(),
|
|
49
|
+
project_end_date: z.string().nullable().optional(),
|
|
50
|
+
project_detail_url: z.string().nullable().optional(),
|
|
51
|
+
});
|
|
52
|
+
const NIH_REPORTER_PAYLOAD_SCHEMA = z.object({
|
|
53
|
+
meta: z
|
|
54
|
+
.object({
|
|
55
|
+
total: z.number(),
|
|
56
|
+
offset: z.number(),
|
|
57
|
+
limit: z.number(),
|
|
58
|
+
})
|
|
59
|
+
.optional(),
|
|
60
|
+
results: z.array(NIH_REPORTER_PROJECT_SCHEMA).optional(),
|
|
61
|
+
message: z.string().optional(),
|
|
62
|
+
});
|
|
63
|
+
/**
|
|
64
|
+
* Builds the JSON body for one project search.
|
|
65
|
+
*
|
|
66
|
+
* The endpoint is keyless. The default page is fiscal 2025, the year the
|
|
67
|
+
* fixture covers, ordered by the largest award first so repeated calls return
|
|
68
|
+
* a stable, useful slice of the file.
|
|
69
|
+
*
|
|
70
|
+
* @param query - an optional fiscal year, page size, and offset
|
|
71
|
+
* @returns the request body for the search endpoint
|
|
72
|
+
*/
|
|
73
|
+
export function buildNihReporterSearchBody(query = {}) {
|
|
74
|
+
return {
|
|
75
|
+
criteria: {
|
|
76
|
+
fiscal_years: [query.fiscalYear ?? NIH_REPORTER_DEFAULT_FISCAL_YEAR],
|
|
77
|
+
agencies: ['NIH'],
|
|
78
|
+
},
|
|
79
|
+
include_fields: NIH_REPORTER_INCLUDE_FIELDS,
|
|
80
|
+
offset: query.offset ?? 0,
|
|
81
|
+
limit: query.limit ?? NIH_REPORTER_PAGE_SIZE,
|
|
82
|
+
sort_field: 'award_amount',
|
|
83
|
+
sort_order: 'desc',
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/** Converts an ISO timestamp or date to YYYY-MM-DD, or null when absent. */
|
|
87
|
+
function normalizeNihReporterDate(value, field) {
|
|
88
|
+
if (value === null || value === undefined) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
const match = /^(\d{4}-\d{2}-\d{2})/.exec(value);
|
|
92
|
+
if (match === null) {
|
|
93
|
+
throw new UsSourceParseError(NIH_REPORTER_SOURCE_ID, `Unreadable ${field}: ${value}`);
|
|
94
|
+
}
|
|
95
|
+
return match[1] ?? null;
|
|
96
|
+
}
|
|
97
|
+
/** Collapses the repeated spaces NIH writes inside investigator names. */
|
|
98
|
+
function normalizeInvestigatorName(name) {
|
|
99
|
+
return name.split(/\s+/).filter(Boolean).join(' ');
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Parses one NIH RePORTER project search response.
|
|
103
|
+
*
|
|
104
|
+
* A body carrying a top-level message is an API error, even when the host
|
|
105
|
+
* answers HTTP 200. A project without its number, title, fiscal year, or
|
|
106
|
+
* organization is a changed shape and stops the parse.
|
|
107
|
+
*
|
|
108
|
+
* @param payload - the JSON body from the NIH RePORTER search endpoint
|
|
109
|
+
* @returns the projects on the page, the agency total, and the page award sum
|
|
110
|
+
*/
|
|
111
|
+
export function parseNihReporterProjectsPayload(payload) {
|
|
112
|
+
const parsed = NIH_REPORTER_PAYLOAD_SCHEMA.safeParse(payload);
|
|
113
|
+
if (!parsed.success) {
|
|
114
|
+
throw new UsSourceParseError(NIH_REPORTER_SOURCE_ID, parsed.error.message);
|
|
115
|
+
}
|
|
116
|
+
if (parsed.data.message !== undefined) {
|
|
117
|
+
throw new UsSourceApiError(NIH_REPORTER_SOURCE_ID, parsed.data.message);
|
|
118
|
+
}
|
|
119
|
+
const meta = parsed.data.meta;
|
|
120
|
+
const rows = parsed.data.results;
|
|
121
|
+
if (meta === undefined || rows === undefined) {
|
|
122
|
+
throw new UsSourceParseError(NIH_REPORTER_SOURCE_ID, 'The response carried no meta block or results array');
|
|
123
|
+
}
|
|
124
|
+
const projects = rows.map((row) => ({
|
|
125
|
+
projectNumber: row.project_num,
|
|
126
|
+
coreProjectNumber: row.core_project_num ?? null,
|
|
127
|
+
projectTitle: row.project_title,
|
|
128
|
+
fiscalYear: row.fiscal_year,
|
|
129
|
+
awardAmount: row.award_amount ?? null,
|
|
130
|
+
organizationName: row.organization.org_name,
|
|
131
|
+
organizationCity: row.organization.org_city ?? null,
|
|
132
|
+
organizationState: row.organization.org_state ?? null,
|
|
133
|
+
principalInvestigators: (row.principal_investigators ?? []).flatMap((investigator) => {
|
|
134
|
+
if (investigator.full_name === undefined) {
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
const name = normalizeInvestigatorName(investigator.full_name);
|
|
138
|
+
return name === '' ? [] : [name];
|
|
139
|
+
}),
|
|
140
|
+
administeringInstitute: row.agency_ic_admin?.abbreviation === undefined || row.agency_ic_admin.abbreviation === ''
|
|
141
|
+
? (row.agency_ic_admin?.name ?? null)
|
|
142
|
+
: row.agency_ic_admin.abbreviation,
|
|
143
|
+
projectStartDate: normalizeNihReporterDate(row.project_start_date, 'project start date'),
|
|
144
|
+
projectEndDate: normalizeNihReporterDate(row.project_end_date, 'project end date'),
|
|
145
|
+
projectDetailUrl: row.project_detail_url ?? null,
|
|
146
|
+
}));
|
|
147
|
+
return {
|
|
148
|
+
projects,
|
|
149
|
+
projectCount: projects.length,
|
|
150
|
+
totalCount: meta.total,
|
|
151
|
+
offset: meta.offset,
|
|
152
|
+
limit: meta.limit,
|
|
153
|
+
pageAwardAmountUsd: projects.reduce((total, project) => total + (project.awardAmount ?? 0), 0),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Reads one page of NIH-funded projects through the RePORTER search API.
|
|
158
|
+
*
|
|
159
|
+
* One keyless POST returns a page of projects, the total number of matches,
|
|
160
|
+
* and the combined award value on that page.
|
|
161
|
+
*
|
|
162
|
+
* @param options - an optional fiscal year, page window, and fetch stub
|
|
163
|
+
* @returns the projects on the page and the search totals
|
|
164
|
+
*/
|
|
165
|
+
export async function fetchNihReporterProjects(options = {}) {
|
|
166
|
+
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
167
|
+
const body = buildNihReporterSearchBody({
|
|
168
|
+
...(options.fiscalYear === undefined ? {} : { fiscalYear: options.fiscalYear }),
|
|
169
|
+
...(options.limit === undefined ? {} : { limit: options.limit }),
|
|
170
|
+
...(options.offset === undefined ? {} : { offset: options.offset }),
|
|
171
|
+
});
|
|
172
|
+
const response = await httpPostJson(NIH_REPORTER_SOURCE_ID, NIH_REPORTER_SEARCH_URL, body, {
|
|
173
|
+
fetchImpl,
|
|
174
|
+
headers: { accept: 'application/json' },
|
|
175
|
+
});
|
|
176
|
+
return parseNihReporterProjectsPayload(await response.json());
|
|
177
|
+
}
|
|
178
|
+
/** NIH RePORTER funded projects, one row per project, keyless. */
|
|
179
|
+
export const nihReporterProjectsAdapter = {
|
|
180
|
+
id: NIH_REPORTER_SOURCE_ID,
|
|
181
|
+
name: 'NIH RePORTER funded projects',
|
|
182
|
+
auth: 'none',
|
|
183
|
+
description: 'NIH RePORTER funded projects for one fiscal year, with the project title, award amount, organization, principal investigators, and administering institute.',
|
|
184
|
+
fetchLive: async (options) => fetchNihReporterProjects(options?.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
|
|
185
|
+
parse: (payload) => parseNihReporterProjectsPayload(payload),
|
|
186
|
+
loadFixture: () => parseNihReporterProjectsPayload(readFixtureJson(NIH_REPORTER_FIXTURE_FILENAME)),
|
|
187
|
+
};
|
|
188
|
+
//# sourceMappingURL=nihReporterProjects.js.map
|