@usa-open-data-connectors/usa-sources 0.1.1 → 0.1.3
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/dist/btsTransportationStats.d.ts +87 -0
- package/dist/btsTransportationStats.d.ts.map +1 -0
- package/dist/btsTransportationStats.js +132 -0
- package/dist/btsTransportationStats.js.map +1 -0
- package/dist/cdcSocrataCatalogue.d.ts +87 -0
- package/dist/cdcSocrataCatalogue.d.ts.map +1 -0
- package/dist/cdcSocrataCatalogue.js +132 -0
- package/dist/cdcSocrataCatalogue.js.map +1 -0
- package/dist/clinicalTrialsStudies.d.ts +92 -0
- package/dist/clinicalTrialsStudies.d.ts.map +1 -0
- package/dist/clinicalTrialsStudies.js +149 -0
- package/dist/clinicalTrialsStudies.js.map +1 -0
- package/dist/epaEnvirofactsFacilities.d.ts +94 -0
- package/dist/epaEnvirofactsFacilities.d.ts.map +1 -0
- package/dist/epaEnvirofactsFacilities.js +142 -0
- package/dist/epaEnvirofactsFacilities.js.map +1 -0
- package/dist/fdicBankDirectory.d.ts +78 -0
- package/dist/fdicBankDirectory.d.ts.map +1 -0
- package/dist/fdicBankDirectory.js +124 -0
- package/dist/fdicBankDirectory.js.map +1 -0
- package/dist/healthdataSocrataCatalogue.d.ts +87 -0
- package/dist/healthdataSocrataCatalogue.d.ts.map +1 -0
- package/dist/healthdataSocrataCatalogue.js +132 -0
- package/dist/healthdataSocrataCatalogue.js.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -1
- package/dist/ncbiPubmedSearch.d.ts +71 -0
- package/dist/ncbiPubmedSearch.d.ts.map +1 -0
- package/dist/ncbiPubmedSearch.js +128 -0
- package/dist/ncbiPubmedSearch.js.map +1 -0
- package/dist/nwsPointForecast.d.ts +99 -0
- package/dist/nwsPointForecast.d.ts.map +1 -0
- package/dist/nwsPointForecast.js +146 -0
- package/dist/nwsPointForecast.js.map +1 -0
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +22 -0
- package/dist/registry.js.map +1 -1
- package/dist/secEdgarFilings.d.ts +103 -0
- package/dist/secEdgarFilings.d.ts.map +1 -0
- package/dist/secEdgarFilings.js +214 -0
- package/dist/secEdgarFilings.js.map +1 -0
- package/dist/treasuryDebtToPenny.d.ts +90 -0
- package/dist/treasuryDebtToPenny.d.ts.map +1 -0
- package/dist/treasuryDebtToPenny.js +170 -0
- package/dist/treasuryDebtToPenny.js.map +1 -0
- package/dist/usaspendingAgencies.d.ts +78 -0
- package/dist/usaspendingAgencies.d.ts.map +1 -0
- package/dist/usaspendingAgencies.js +121 -0
- package/dist/usaspendingAgencies.js.map +1 -0
- package/package.json +10 -2
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { UsSourceApiError, UsSourceParseError } from './errors.js';
|
|
3
|
+
import { readFixtureJson } from './fixtures.js';
|
|
4
|
+
/** Adapter id for the ClinicalTrials.gov studies source. */
|
|
5
|
+
export const CLINICALTRIALS_STUDIES_SOURCE_ID = 'clinicaltrials-studies';
|
|
6
|
+
/** Base URL for the ClinicalTrials.gov studies API. */
|
|
7
|
+
export const CLINICALTRIALS_STUDIES_API_BASE = 'https://clinicaltrials.gov/api/v2/studies';
|
|
8
|
+
/** Page size for one request. */
|
|
9
|
+
export const CLINICALTRIALS_STUDIES_PAGE_SIZE = 10;
|
|
10
|
+
/** Committed snapshot, so a build works when the ClinicalTrials host is unreachable. */
|
|
11
|
+
const CLINICALTRIALS_STUDIES_FIXTURE_FILENAME = 'clinicaltrials-studies-2026-10-05.json';
|
|
12
|
+
const CLINICALTRIALS_STUDY_SCHEMA = z.object({
|
|
13
|
+
protocolSection: z
|
|
14
|
+
.object({
|
|
15
|
+
identificationModule: z
|
|
16
|
+
.object({ nctId: z.string().optional(), briefTitle: z.string().optional() })
|
|
17
|
+
.optional(),
|
|
18
|
+
statusModule: z
|
|
19
|
+
.object({
|
|
20
|
+
overallStatus: z.string().optional(),
|
|
21
|
+
startDateStruct: z.object({ date: z.string().optional() }).optional(),
|
|
22
|
+
lastUpdatePostDateStruct: z.object({ date: z.string().optional() }).optional(),
|
|
23
|
+
})
|
|
24
|
+
.optional(),
|
|
25
|
+
sponsorCollaboratorsModule: z
|
|
26
|
+
.object({ leadSponsor: z.object({ name: z.string().optional() }).optional() })
|
|
27
|
+
.optional(),
|
|
28
|
+
conditionsModule: z.object({ conditions: z.array(z.string()).optional() }).optional(),
|
|
29
|
+
designModule: z
|
|
30
|
+
.object({
|
|
31
|
+
studyType: z.string().optional(),
|
|
32
|
+
phases: z.array(z.string()).optional(),
|
|
33
|
+
enrollmentInfo: z
|
|
34
|
+
.object({ count: z.number().optional(), type: z.string().optional() })
|
|
35
|
+
.optional(),
|
|
36
|
+
})
|
|
37
|
+
.optional(),
|
|
38
|
+
})
|
|
39
|
+
.optional(),
|
|
40
|
+
});
|
|
41
|
+
const CLINICALTRIALS_PAYLOAD_SCHEMA = z.object({
|
|
42
|
+
studies: z.array(CLINICALTRIALS_STUDY_SCHEMA).optional(),
|
|
43
|
+
nextPageToken: z.string().optional(),
|
|
44
|
+
});
|
|
45
|
+
/**
|
|
46
|
+
* Builds the request URL for one page of studies.
|
|
47
|
+
*
|
|
48
|
+
* The endpoint is keyless. The default page size is small on purpose: one
|
|
49
|
+
* study carries a deep protocol record, so a caller reading many pages should
|
|
50
|
+
* pass the page token from the previous response.
|
|
51
|
+
*
|
|
52
|
+
* @param options - an optional page size
|
|
53
|
+
* @returns the full request URL
|
|
54
|
+
*/
|
|
55
|
+
export function buildClinicalTrialsStudiesUrl(options) {
|
|
56
|
+
const params = new URLSearchParams({
|
|
57
|
+
pageSize: String(options?.pageSize ?? CLINICALTRIALS_STUDIES_PAGE_SIZE),
|
|
58
|
+
});
|
|
59
|
+
return `${CLINICALTRIALS_STUDIES_API_BASE}?${params.toString()}`;
|
|
60
|
+
}
|
|
61
|
+
/** Counts studies per recruitment status, most studies first, ties by name. */
|
|
62
|
+
function countClinicalTrialStatuses(studies) {
|
|
63
|
+
const counts = new Map();
|
|
64
|
+
for (const study of studies) {
|
|
65
|
+
counts.set(study.overallStatus, (counts.get(study.overallStatus) ?? 0) + 1);
|
|
66
|
+
}
|
|
67
|
+
return [...counts.entries()]
|
|
68
|
+
.sort(([leftStatus, leftCount], [rightStatus, rightCount]) => leftCount === rightCount ? leftStatus.localeCompare(rightStatus) : rightCount - leftCount)
|
|
69
|
+
.map(([status, studyCount]) => ({ status, studyCount }));
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Parses one page of studies into the fields a story reads.
|
|
73
|
+
*
|
|
74
|
+
* A study without a registry id or a brief title is a changed shape and stops
|
|
75
|
+
* the parse. Optional protocol blocks are read when present and left null
|
|
76
|
+
* when the registry did not carry them.
|
|
77
|
+
*
|
|
78
|
+
* @param payload - the JSON body from the ClinicalTrials.gov studies API
|
|
79
|
+
* @returns the studies in the page, the status counts, and the next page token
|
|
80
|
+
*/
|
|
81
|
+
export function parseClinicalTrialsStudiesPayload(payload) {
|
|
82
|
+
const parsed = CLINICALTRIALS_PAYLOAD_SCHEMA.safeParse(payload);
|
|
83
|
+
if (!parsed.success) {
|
|
84
|
+
throw new UsSourceParseError(CLINICALTRIALS_STUDIES_SOURCE_ID, parsed.error.message);
|
|
85
|
+
}
|
|
86
|
+
const rows = parsed.data.studies ?? [];
|
|
87
|
+
if (rows.length === 0) {
|
|
88
|
+
throw new UsSourceParseError(CLINICALTRIALS_STUDIES_SOURCE_ID, 'The response carried no studies');
|
|
89
|
+
}
|
|
90
|
+
const studies = rows.map((row) => {
|
|
91
|
+
const protocol = row.protocolSection;
|
|
92
|
+
const nctId = protocol?.identificationModule?.nctId;
|
|
93
|
+
const briefTitle = protocol?.identificationModule?.briefTitle;
|
|
94
|
+
if (nctId === undefined || briefTitle === undefined) {
|
|
95
|
+
throw new UsSourceParseError(CLINICALTRIALS_STUDIES_SOURCE_ID, 'A study arrived without its registry id or brief title');
|
|
96
|
+
}
|
|
97
|
+
const status = protocol?.statusModule;
|
|
98
|
+
const design = protocol?.designModule;
|
|
99
|
+
return {
|
|
100
|
+
nctId,
|
|
101
|
+
briefTitle,
|
|
102
|
+
overallStatus: status?.overallStatus ?? '',
|
|
103
|
+
studyType: design?.studyType ?? null,
|
|
104
|
+
phases: design?.phases ?? [],
|
|
105
|
+
conditions: protocol?.conditionsModule?.conditions ?? [],
|
|
106
|
+
leadSponsor: protocol?.sponsorCollaboratorsModule?.leadSponsor?.name ?? null,
|
|
107
|
+
enrollmentCount: design?.enrollmentInfo?.count ?? null,
|
|
108
|
+
enrollmentType: design?.enrollmentInfo?.type ?? null,
|
|
109
|
+
startDate: status?.startDateStruct?.date ?? null,
|
|
110
|
+
lastUpdatePostDate: status?.lastUpdatePostDateStruct?.date ?? null,
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
return {
|
|
114
|
+
studies,
|
|
115
|
+
studyCount: studies.length,
|
|
116
|
+
statusCounts: countClinicalTrialStatuses(studies),
|
|
117
|
+
nextPageToken: parsed.data.nextPageToken ?? null,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Reads one page of registered clinical studies.
|
|
122
|
+
*
|
|
123
|
+
* One keyless request covers the page. The response also carries a token for
|
|
124
|
+
* the next page of the same query, which the adapter keeps on the page it
|
|
125
|
+
* returns.
|
|
126
|
+
*
|
|
127
|
+
* @param options - an optional page size and fetch stub
|
|
128
|
+
* @returns the studies in the page, the status counts, and the next page token
|
|
129
|
+
*/
|
|
130
|
+
export async function fetchClinicalTrialsStudies(options) {
|
|
131
|
+
const fetchImpl = options?.fetchImpl ?? globalThis.fetch;
|
|
132
|
+
const url = buildClinicalTrialsStudiesUrl(options?.pageSize === undefined ? {} : { pageSize: options.pageSize });
|
|
133
|
+
const response = await fetchImpl(url);
|
|
134
|
+
if (!response.ok) {
|
|
135
|
+
throw new UsSourceApiError(CLINICALTRIALS_STUDIES_SOURCE_ID, `HTTP ${response.status} reading the studies`);
|
|
136
|
+
}
|
|
137
|
+
return parseClinicalTrialsStudiesPayload(await response.json());
|
|
138
|
+
}
|
|
139
|
+
/** ClinicalTrials.gov registered studies, one row per study, keyless. */
|
|
140
|
+
export const clinicalTrialsStudiesAdapter = {
|
|
141
|
+
id: CLINICALTRIALS_STUDIES_SOURCE_ID,
|
|
142
|
+
name: 'ClinicalTrials.gov studies',
|
|
143
|
+
auth: 'none',
|
|
144
|
+
description: 'Registered clinical studies from ClinicalTrials.gov, one row per study, with the status, phase, lead sponsor, and enrollment.',
|
|
145
|
+
fetchLive: async (options) => fetchClinicalTrialsStudies(options?.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
|
|
146
|
+
parse: (payload) => parseClinicalTrialsStudiesPayload(payload),
|
|
147
|
+
loadFixture: () => parseClinicalTrialsStudiesPayload(readFixtureJson(CLINICALTRIALS_STUDIES_FIXTURE_FILENAME)),
|
|
148
|
+
};
|
|
149
|
+
//# sourceMappingURL=clinicalTrialsStudies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clinicalTrialsStudies.js","sourceRoot":"","sources":["../src/clinicalTrialsStudies.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { UsDataAdapter } from './types.js';
|
|
2
|
+
/** Adapter id for the EPA Envirofacts facility source. */
|
|
3
|
+
export declare const EPA_ENVIROFACTS_FACILITIES_SOURCE_ID = "epa-envirofacts-facilities";
|
|
4
|
+
/** One Toxics Release Inventory facility from the Envirofacts service. */
|
|
5
|
+
export interface EpaEnvirofactsFacility {
|
|
6
|
+
/** The EPA's own TRI facility id. */
|
|
7
|
+
facilityId: string;
|
|
8
|
+
/** Facility name as the register holds it. */
|
|
9
|
+
facilityName: string;
|
|
10
|
+
/** Street address of the site. */
|
|
11
|
+
streetAddress: string;
|
|
12
|
+
/** City of the site. */
|
|
13
|
+
city: string;
|
|
14
|
+
/** County the site sits in, spelled the way the service spells it. */
|
|
15
|
+
countyName: string;
|
|
16
|
+
/** Two-letter state code the service reports for the site. */
|
|
17
|
+
stateAbbr: string;
|
|
18
|
+
/** Postal code of the site. */
|
|
19
|
+
postalCode: string;
|
|
20
|
+
/** EPA region number as the service reports it, for example "1". */
|
|
21
|
+
region: string;
|
|
22
|
+
/** True when the service marks the facility as closed. */
|
|
23
|
+
closed: boolean;
|
|
24
|
+
/** Parent company name, or null when the service reports "NA" or leaves it out. */
|
|
25
|
+
parentCompanyName: string | null;
|
|
26
|
+
}
|
|
27
|
+
/** One county and how many facilities in the page sit there. */
|
|
28
|
+
export interface EpaEnvirofactsCountyCount {
|
|
29
|
+
countyName: string;
|
|
30
|
+
facilityCount: number;
|
|
31
|
+
}
|
|
32
|
+
/** One page of facilities, folded for a story. */
|
|
33
|
+
export interface EpaEnvirofactsFacilityPage {
|
|
34
|
+
facilities: EpaEnvirofactsFacility[];
|
|
35
|
+
facilityCount: number;
|
|
36
|
+
/** Facilities the service does not mark as closed. */
|
|
37
|
+
openCount: number;
|
|
38
|
+
/** Facilities the service marks as closed. */
|
|
39
|
+
closedCount: number;
|
|
40
|
+
/** Counties the facilities in the page sit in, most facilities first. */
|
|
41
|
+
counties: EpaEnvirofactsCountyCount[];
|
|
42
|
+
}
|
|
43
|
+
/** Base URL for the EPA Envirofacts service. */
|
|
44
|
+
export declare const EPA_ENVIROFACTS_API_BASE = "https://data.epa.gov/efservice";
|
|
45
|
+
/** Envirofacts table that holds the Toxics Release Inventory facility records. */
|
|
46
|
+
export declare const EPA_ENVIROFACTS_TABLE = "TRI_FACILITY";
|
|
47
|
+
/** Envirofacts column the state filter reads. */
|
|
48
|
+
export declare const EPA_ENVIROFACTS_STATE_COLUMN = "STATE_ABBR";
|
|
49
|
+
/** State the default URL asks for. */
|
|
50
|
+
export declare const EPA_ENVIROFACTS_STATE_ABBR = "RI";
|
|
51
|
+
/** Row window one request reads, the first ten rows. */
|
|
52
|
+
export declare const EPA_ENVIROFACTS_ROW_WINDOW = "0:9";
|
|
53
|
+
/**
|
|
54
|
+
* Builds the request URL for one page of Toxics Release Inventory facilities.
|
|
55
|
+
*
|
|
56
|
+
* The endpoint is keyless, and the state segment does narrow the rows: the
|
|
57
|
+
* value sits directly after the column name, with no `equals` operator.
|
|
58
|
+
* Envirofacts accepts an `equals` segment without complaining but then
|
|
59
|
+
* returns the table's first rows instead of the ones asked for.
|
|
60
|
+
*
|
|
61
|
+
* @param options - an optional state code and row window
|
|
62
|
+
* @returns the full request URL
|
|
63
|
+
*/
|
|
64
|
+
export declare function buildEpaEnvirofactsFacilitiesUrl(options?: {
|
|
65
|
+
stateAbbr?: string;
|
|
66
|
+
rowWindow?: string;
|
|
67
|
+
}): string;
|
|
68
|
+
/**
|
|
69
|
+
* Parses one response into the facilities in the page and its rollups.
|
|
70
|
+
*
|
|
71
|
+
* A row without a facility id, name, or state code fails the schema and stops
|
|
72
|
+
* the parse. An empty array is treated as a changed source, because the
|
|
73
|
+
* default query always returns rows.
|
|
74
|
+
*
|
|
75
|
+
* @param payload - the JSON body from the Envirofacts service
|
|
76
|
+
* @returns the facilities in the page, the open and closed counts, and the counties
|
|
77
|
+
*/
|
|
78
|
+
export declare function parseEpaEnvirofactsFacilitiesPayload(payload: unknown): EpaEnvirofactsFacilityPage;
|
|
79
|
+
/**
|
|
80
|
+
* Reads one page of Toxics Release Inventory facilities from Envirofacts.
|
|
81
|
+
*
|
|
82
|
+
* One keyless request covers the page. The state segment in the URL narrows
|
|
83
|
+
* the rows, so the page holds facilities from the state that was asked for.
|
|
84
|
+
*
|
|
85
|
+
* @param options - an optional state code, row window, and fetch stub
|
|
86
|
+
* @returns the facilities in the page and its rollups
|
|
87
|
+
*/
|
|
88
|
+
export declare function fetchEpaEnvirofactsFacilities(options?: {
|
|
89
|
+
stateAbbr?: string;
|
|
90
|
+
fetchImpl?: typeof globalThis.fetch;
|
|
91
|
+
}): Promise<EpaEnvirofactsFacilityPage>;
|
|
92
|
+
/** EPA Envirofacts Toxics Release Inventory facilities, keyless. */
|
|
93
|
+
export declare const epaEnvirofactsFacilitiesAdapter: UsDataAdapter<EpaEnvirofactsFacilityPage>;
|
|
94
|
+
//# sourceMappingURL=epaEnvirofactsFacilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"epaEnvirofactsFacilities.d.ts","sourceRoot":"","sources":["../src/epaEnvirofactsFacilities.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,0DAA0D;AAC1D,eAAO,MAAM,oCAAoC,+BAA+B,CAAC;AAEjF,0EAA0E;AAC1E,MAAM,WAAW,sBAAsB;IACrC,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,YAAY,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,UAAU,EAAE,MAAM,CAAC;IACnB,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;IAClB,+BAA+B;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,MAAM,EAAE,OAAO,CAAC;IAChB,mFAAmF;IACnF,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,gEAAgE;AAChE,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,kDAAkD;AAClD,MAAM,WAAW,0BAA0B;IACzC,UAAU,EAAE,sBAAsB,EAAE,CAAC;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,QAAQ,EAAE,yBAAyB,EAAE,CAAC;CACvC;AAED,gDAAgD;AAChD,eAAO,MAAM,wBAAwB,mCAAmC,CAAC;AAEzE,kFAAkF;AAClF,eAAO,MAAM,qBAAqB,iBAAiB,CAAC;AAEpD,iDAAiD;AACjD,eAAO,MAAM,4BAA4B,eAAe,CAAC;AAEzD,sCAAsC;AACtC,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAE/C,wDAAwD;AACxD,eAAO,MAAM,0BAA0B,QAAQ,CAAC;AAmDhD;;;;;;;;;;GAUG;AACH,wBAAgB,gCAAgC,CAAC,OAAO,CAAC,EAAE;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,MAAM,CAIT;AAED;;;;;;;;;GASG;AACH,wBAAgB,oCAAoC,CAAC,OAAO,EAAE,OAAO,GAAG,0BAA0B,CAwCjG;AAED;;;;;;;;GAQG;AACH,wBAAsB,6BAA6B,CAAC,OAAO,CAAC,EAAE;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACrC,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAatC;AAED,oEAAoE;AACpE,eAAO,MAAM,+BAA+B,EAAE,aAAa,CAAC,0BAA0B,CAarF,CAAC"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { UsSourceApiError, UsSourceParseError } from './errors.js';
|
|
3
|
+
import { readFixtureJson } from './fixtures.js';
|
|
4
|
+
/** Adapter id for the EPA Envirofacts facility source. */
|
|
5
|
+
export const EPA_ENVIROFACTS_FACILITIES_SOURCE_ID = 'epa-envirofacts-facilities';
|
|
6
|
+
/** Base URL for the EPA Envirofacts service. */
|
|
7
|
+
export const EPA_ENVIROFACTS_API_BASE = 'https://data.epa.gov/efservice';
|
|
8
|
+
/** Envirofacts table that holds the Toxics Release Inventory facility records. */
|
|
9
|
+
export const EPA_ENVIROFACTS_TABLE = 'TRI_FACILITY';
|
|
10
|
+
/** Envirofacts column the state filter reads. */
|
|
11
|
+
export const EPA_ENVIROFACTS_STATE_COLUMN = 'STATE_ABBR';
|
|
12
|
+
/** State the default URL asks for. */
|
|
13
|
+
export const EPA_ENVIROFACTS_STATE_ABBR = 'RI';
|
|
14
|
+
/** Row window one request reads, the first ten rows. */
|
|
15
|
+
export const EPA_ENVIROFACTS_ROW_WINDOW = '0:9';
|
|
16
|
+
/** Committed snapshot, so a build works when the Envirofacts host is unreachable. */
|
|
17
|
+
const EPA_ENVIROFACTS_FIXTURE_FILENAME = 'epa-envirofacts-facilities-2026-10-05.json';
|
|
18
|
+
// The service answers with a bare JSON array, and a rejected query answers
|
|
19
|
+
// with a body of {error}. The filter segment takes the value on its own: an
|
|
20
|
+
// "equals" operator is accepted in the URL but never narrows the rows, so the
|
|
21
|
+
// URL builder below does not use one.
|
|
22
|
+
const EPA_ENVIROFACTS_FACILITY_SCHEMA = z.object({
|
|
23
|
+
tri_facility_id: z.string(),
|
|
24
|
+
facility_name: z.string(),
|
|
25
|
+
street_address: z.string().nullable().optional(),
|
|
26
|
+
city_name: z.string().nullable().optional(),
|
|
27
|
+
county_name: z.string().nullable().optional(),
|
|
28
|
+
state_abbr: z.string(),
|
|
29
|
+
zip_code: z.string().nullable().optional(),
|
|
30
|
+
region: z.string().nullable().optional(),
|
|
31
|
+
fac_closed_ind: z.string().nullable().optional(),
|
|
32
|
+
parent_co_name: z.string().nullable().optional(),
|
|
33
|
+
});
|
|
34
|
+
const EPA_ENVIROFACTS_PAYLOAD_SCHEMA = z.union([
|
|
35
|
+
z.array(EPA_ENVIROFACTS_FACILITY_SCHEMA),
|
|
36
|
+
z.object({ error: z.string().optional() }),
|
|
37
|
+
]);
|
|
38
|
+
/** Reads the parent company, treating the register's "NA" as absent. */
|
|
39
|
+
function readEpaParentCompany(value) {
|
|
40
|
+
if (value === null || value === undefined) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const trimmed = value.trim();
|
|
44
|
+
return trimmed === '' || trimmed === 'NA' ? null : trimmed;
|
|
45
|
+
}
|
|
46
|
+
/** Counts facilities per county, most facilities first, then by name. */
|
|
47
|
+
function countEpaEnvirofactsCounties(facilities) {
|
|
48
|
+
const counts = new Map();
|
|
49
|
+
for (const facility of facilities) {
|
|
50
|
+
counts.set(facility.countyName, (counts.get(facility.countyName) ?? 0) + 1);
|
|
51
|
+
}
|
|
52
|
+
return [...counts.entries()]
|
|
53
|
+
.sort(([leftCounty, leftCount], [rightCounty, rightCount]) => leftCount === rightCount ? leftCounty.localeCompare(rightCounty) : rightCount - leftCount)
|
|
54
|
+
.map(([countyName, facilityCount]) => ({ countyName, facilityCount }));
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Builds the request URL for one page of Toxics Release Inventory facilities.
|
|
58
|
+
*
|
|
59
|
+
* The endpoint is keyless, and the state segment does narrow the rows: the
|
|
60
|
+
* value sits directly after the column name, with no `equals` operator.
|
|
61
|
+
* Envirofacts accepts an `equals` segment without complaining but then
|
|
62
|
+
* returns the table's first rows instead of the ones asked for.
|
|
63
|
+
*
|
|
64
|
+
* @param options - an optional state code and row window
|
|
65
|
+
* @returns the full request URL
|
|
66
|
+
*/
|
|
67
|
+
export function buildEpaEnvirofactsFacilitiesUrl(options) {
|
|
68
|
+
const stateAbbr = options?.stateAbbr ?? EPA_ENVIROFACTS_STATE_ABBR;
|
|
69
|
+
const rowWindow = options?.rowWindow ?? EPA_ENVIROFACTS_ROW_WINDOW;
|
|
70
|
+
return `${EPA_ENVIROFACTS_API_BASE}/${EPA_ENVIROFACTS_TABLE}/${EPA_ENVIROFACTS_STATE_COLUMN}/${stateAbbr}/rows/${rowWindow}/JSON`;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Parses one response into the facilities in the page and its rollups.
|
|
74
|
+
*
|
|
75
|
+
* A row without a facility id, name, or state code fails the schema and stops
|
|
76
|
+
* the parse. An empty array is treated as a changed source, because the
|
|
77
|
+
* default query always returns rows.
|
|
78
|
+
*
|
|
79
|
+
* @param payload - the JSON body from the Envirofacts service
|
|
80
|
+
* @returns the facilities in the page, the open and closed counts, and the counties
|
|
81
|
+
*/
|
|
82
|
+
export function parseEpaEnvirofactsFacilitiesPayload(payload) {
|
|
83
|
+
const parsed = EPA_ENVIROFACTS_PAYLOAD_SCHEMA.safeParse(payload);
|
|
84
|
+
if (!parsed.success) {
|
|
85
|
+
throw new UsSourceParseError(EPA_ENVIROFACTS_FACILITIES_SOURCE_ID, parsed.error.message);
|
|
86
|
+
}
|
|
87
|
+
if (!Array.isArray(parsed.data)) {
|
|
88
|
+
throw new UsSourceApiError(EPA_ENVIROFACTS_FACILITIES_SOURCE_ID, parsed.data.error ?? 'The service rejected the query');
|
|
89
|
+
}
|
|
90
|
+
if (parsed.data.length === 0) {
|
|
91
|
+
throw new UsSourceParseError(EPA_ENVIROFACTS_FACILITIES_SOURCE_ID, 'The response carried no rows');
|
|
92
|
+
}
|
|
93
|
+
const facilities = parsed.data.map((row) => ({
|
|
94
|
+
facilityId: row.tri_facility_id,
|
|
95
|
+
facilityName: row.facility_name,
|
|
96
|
+
streetAddress: row.street_address ?? '',
|
|
97
|
+
city: row.city_name ?? '',
|
|
98
|
+
countyName: row.county_name ?? '',
|
|
99
|
+
stateAbbr: row.state_abbr,
|
|
100
|
+
postalCode: row.zip_code ?? '',
|
|
101
|
+
region: row.region ?? '',
|
|
102
|
+
closed: row.fac_closed_ind === '1',
|
|
103
|
+
parentCompanyName: readEpaParentCompany(row.parent_co_name),
|
|
104
|
+
}));
|
|
105
|
+
const closedCount = facilities.filter((facility) => facility.closed).length;
|
|
106
|
+
return {
|
|
107
|
+
facilities,
|
|
108
|
+
facilityCount: facilities.length,
|
|
109
|
+
openCount: facilities.length - closedCount,
|
|
110
|
+
closedCount,
|
|
111
|
+
counties: countEpaEnvirofactsCounties(facilities),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Reads one page of Toxics Release Inventory facilities from Envirofacts.
|
|
116
|
+
*
|
|
117
|
+
* One keyless request covers the page. The state segment in the URL narrows
|
|
118
|
+
* the rows, so the page holds facilities from the state that was asked for.
|
|
119
|
+
*
|
|
120
|
+
* @param options - an optional state code, row window, and fetch stub
|
|
121
|
+
* @returns the facilities in the page and its rollups
|
|
122
|
+
*/
|
|
123
|
+
export async function fetchEpaEnvirofactsFacilities(options) {
|
|
124
|
+
const fetchImpl = options?.fetchImpl ?? globalThis.fetch;
|
|
125
|
+
const url = buildEpaEnvirofactsFacilitiesUrl(options?.stateAbbr === undefined ? {} : { stateAbbr: options.stateAbbr });
|
|
126
|
+
const response = await fetchImpl(url);
|
|
127
|
+
if (!response.ok) {
|
|
128
|
+
throw new UsSourceApiError(EPA_ENVIROFACTS_FACILITIES_SOURCE_ID, `HTTP ${response.status} reading the facilities`);
|
|
129
|
+
}
|
|
130
|
+
return parseEpaEnvirofactsFacilitiesPayload(await response.json());
|
|
131
|
+
}
|
|
132
|
+
/** EPA Envirofacts Toxics Release Inventory facilities, keyless. */
|
|
133
|
+
export const epaEnvirofactsFacilitiesAdapter = {
|
|
134
|
+
id: EPA_ENVIROFACTS_FACILITIES_SOURCE_ID,
|
|
135
|
+
name: 'EPA Envirofacts facilities',
|
|
136
|
+
auth: 'none',
|
|
137
|
+
description: 'Toxics Release Inventory facilities from the EPA Envirofacts service, one row per site, with its county, address, and open or closed status.',
|
|
138
|
+
fetchLive: async (options) => fetchEpaEnvirofactsFacilities(options?.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
|
|
139
|
+
parse: (payload) => parseEpaEnvirofactsFacilitiesPayload(payload),
|
|
140
|
+
loadFixture: () => parseEpaEnvirofactsFacilitiesPayload(readFixtureJson(EPA_ENVIROFACTS_FIXTURE_FILENAME)),
|
|
141
|
+
};
|
|
142
|
+
//# sourceMappingURL=epaEnvirofactsFacilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"epaEnvirofactsFacilities.js","sourceRoot":"","sources":["../src/epaEnvirofactsFacilities.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { UsDataAdapter } from './types.js';
|
|
2
|
+
/** Adapter id for the FDIC bank directory source. */
|
|
3
|
+
export declare const FDIC_BANK_DIRECTORY_SOURCE_ID = "fdic-bank-directory";
|
|
4
|
+
/** One bank in the FDIC's institution directory. */
|
|
5
|
+
export interface FdicBank {
|
|
6
|
+
/** The FDIC's own certificate number for the bank. */
|
|
7
|
+
id: string;
|
|
8
|
+
/** The bank's legal name. */
|
|
9
|
+
name: string;
|
|
10
|
+
/** City of the bank's main office. */
|
|
11
|
+
city: string;
|
|
12
|
+
/** Two-letter state code of the main office. */
|
|
13
|
+
stateAbbr: string;
|
|
14
|
+
}
|
|
15
|
+
/** One state and how many banks in the page sit there. */
|
|
16
|
+
export interface FdicBankStateCount {
|
|
17
|
+
stateAbbr: string;
|
|
18
|
+
bankCount: number;
|
|
19
|
+
}
|
|
20
|
+
/** One page of the bank directory, folded for a story. */
|
|
21
|
+
export interface FdicBankDirectory {
|
|
22
|
+
/** One entry per bank in the page. */
|
|
23
|
+
banks: FdicBank[];
|
|
24
|
+
bankCount: number;
|
|
25
|
+
/** How many banks the FDIC holds in total, not just in this page. */
|
|
26
|
+
totalBanks: number;
|
|
27
|
+
/** States the banks in the page sit in, most banks first. */
|
|
28
|
+
states: FdicBankStateCount[];
|
|
29
|
+
}
|
|
30
|
+
/** Base URL for the FDIC institutions API. */
|
|
31
|
+
export declare const FDIC_BANK_API_BASE = "https://banks.data.fdic.gov/api/institutions";
|
|
32
|
+
/** Row cap for one request. */
|
|
33
|
+
export declare const FDIC_BANK_ROW_LIMIT = 10;
|
|
34
|
+
/** Columns the adapter asks for. The directory carries many more. */
|
|
35
|
+
export declare const FDIC_BANK_FIELDS = "NAME,CITY,STALP";
|
|
36
|
+
/**
|
|
37
|
+
* Builds the request URL for one page of the bank directory.
|
|
38
|
+
*
|
|
39
|
+
* The endpoint is keyless. The `fields` parameter trims the response to the
|
|
40
|
+
* columns a story reads, which keeps each row small. The service answers the
|
|
41
|
+
* banks.data.fdic.gov host with a redirect to api.fdic.gov, which fetch
|
|
42
|
+
* follows.
|
|
43
|
+
*
|
|
44
|
+
* @param options - an optional row cap and column list
|
|
45
|
+
* @returns the full request URL
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildFdicBankDirectoryUrl(options?: {
|
|
48
|
+
rowLimit?: number;
|
|
49
|
+
fields?: string;
|
|
50
|
+
}): string;
|
|
51
|
+
/**
|
|
52
|
+
* Parses one response into the banks in the page and the state counts.
|
|
53
|
+
*
|
|
54
|
+
* A row without an id, name, city, or state is a changed shape and stops the
|
|
55
|
+
* parse. The API's own total is used for `totalBanks`, falling back to the
|
|
56
|
+
* page size when the envelope omits it.
|
|
57
|
+
*
|
|
58
|
+
* @param payload - the JSON body from the FDIC institutions API
|
|
59
|
+
* @returns the banks in the page, the total the FDIC reports, and state counts
|
|
60
|
+
*/
|
|
61
|
+
export declare function parseFdicBankDirectoryPayload(payload: unknown): FdicBankDirectory;
|
|
62
|
+
/**
|
|
63
|
+
* Reads one page of the FDIC's bank directory.
|
|
64
|
+
*
|
|
65
|
+
* One keyless request covers the page. The service trims each row to the
|
|
66
|
+
* columns asked for, so a story gets names, cities, and states without the
|
|
67
|
+
* full institution record.
|
|
68
|
+
*
|
|
69
|
+
* @param options - an optional row cap and fetch stub
|
|
70
|
+
* @returns the banks in the page, the FDIC total, and the state counts
|
|
71
|
+
*/
|
|
72
|
+
export declare function fetchFdicBankDirectory(options?: {
|
|
73
|
+
rowLimit?: number;
|
|
74
|
+
fetchImpl?: typeof globalThis.fetch;
|
|
75
|
+
}): Promise<FdicBankDirectory>;
|
|
76
|
+
/** FDIC bank directory, one row per insured institution, keyless. */
|
|
77
|
+
export declare const fdicBankDirectoryAdapter: UsDataAdapter<FdicBankDirectory>;
|
|
78
|
+
//# sourceMappingURL=fdicBankDirectory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fdicBankDirectory.d.ts","sourceRoot":"","sources":["../src/fdicBankDirectory.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,qDAAqD;AACrD,eAAO,MAAM,6BAA6B,wBAAwB,CAAC;AAEnE,oDAAoD;AACpD,MAAM,WAAW,QAAQ;IACvB,sDAAsD;IACtD,EAAE,EAAE,MAAM,CAAC;IACX,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,0DAA0D;AAC1D,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,0DAA0D;AAC1D,MAAM,WAAW,iBAAiB;IAChC,sCAAsC;IACtC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAC;IACnB,6DAA6D;IAC7D,MAAM,EAAE,kBAAkB,EAAE,CAAC;CAC9B;AAED,8CAA8C;AAC9C,eAAO,MAAM,kBAAkB,iDAAiD,CAAC;AAEjF,+BAA+B;AAC/B,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,qEAAqE;AACrE,eAAO,MAAM,gBAAgB,oBAAoB,CAAC;AAuBlD;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,MAAM,CAMT;AAeD;;;;;;;;;GASG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,OAAO,GAAG,iBAAiB,CAiCjF;AAED;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,CAAC,EAAE;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACrC,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAa7B;AAED,qEAAqE;AACrE,eAAO,MAAM,wBAAwB,EAAE,aAAa,CAAC,iBAAiB,CAYrE,CAAC"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { UsSourceApiError, UsSourceParseError } from './errors.js';
|
|
3
|
+
import { readFixtureJson } from './fixtures.js';
|
|
4
|
+
/** Adapter id for the FDIC bank directory source. */
|
|
5
|
+
export const FDIC_BANK_DIRECTORY_SOURCE_ID = 'fdic-bank-directory';
|
|
6
|
+
/** Base URL for the FDIC institutions API. */
|
|
7
|
+
export const FDIC_BANK_API_BASE = 'https://banks.data.fdic.gov/api/institutions';
|
|
8
|
+
/** Row cap for one request. */
|
|
9
|
+
export const FDIC_BANK_ROW_LIMIT = 10;
|
|
10
|
+
/** Columns the adapter asks for. The directory carries many more. */
|
|
11
|
+
export const FDIC_BANK_FIELDS = 'NAME,CITY,STALP';
|
|
12
|
+
/** Committed snapshot, so a build works when the FDIC host is unreachable. */
|
|
13
|
+
const FDIC_BANK_FIXTURE_FILENAME = 'fdic-bank-directory-2026-10-05.json';
|
|
14
|
+
// The API wraps each institution in a result object with its own score, and
|
|
15
|
+
// answers a rejected request with an HTTP error and a body of {errors}.
|
|
16
|
+
const FDIC_BANK_ROW_SCHEMA = z.object({
|
|
17
|
+
data: z.object({
|
|
18
|
+
ID: z.string().optional(),
|
|
19
|
+
NAME: z.string().optional(),
|
|
20
|
+
CITY: z.string().optional(),
|
|
21
|
+
STALP: z.string().optional(),
|
|
22
|
+
}),
|
|
23
|
+
});
|
|
24
|
+
const FDIC_BANK_PAYLOAD_SCHEMA = z.object({
|
|
25
|
+
meta: z.object({ total: z.number().optional() }).optional(),
|
|
26
|
+
totals: z.object({ count: z.number().optional() }).optional(),
|
|
27
|
+
data: z.array(FDIC_BANK_ROW_SCHEMA).optional(),
|
|
28
|
+
errors: z.array(z.unknown()).optional(),
|
|
29
|
+
});
|
|
30
|
+
/**
|
|
31
|
+
* Builds the request URL for one page of the bank directory.
|
|
32
|
+
*
|
|
33
|
+
* The endpoint is keyless. The `fields` parameter trims the response to the
|
|
34
|
+
* columns a story reads, which keeps each row small. The service answers the
|
|
35
|
+
* banks.data.fdic.gov host with a redirect to api.fdic.gov, which fetch
|
|
36
|
+
* follows.
|
|
37
|
+
*
|
|
38
|
+
* @param options - an optional row cap and column list
|
|
39
|
+
* @returns the full request URL
|
|
40
|
+
*/
|
|
41
|
+
export function buildFdicBankDirectoryUrl(options) {
|
|
42
|
+
const params = new URLSearchParams({
|
|
43
|
+
limit: String(options?.rowLimit ?? FDIC_BANK_ROW_LIMIT),
|
|
44
|
+
fields: options?.fields ?? FDIC_BANK_FIELDS,
|
|
45
|
+
});
|
|
46
|
+
return `${FDIC_BANK_API_BASE}?${params.toString()}`;
|
|
47
|
+
}
|
|
48
|
+
/** Counts banks per state in the order they were seen. */
|
|
49
|
+
function countFdicBankStates(banks) {
|
|
50
|
+
const counts = new Map();
|
|
51
|
+
for (const bank of banks) {
|
|
52
|
+
counts.set(bank.stateAbbr, (counts.get(bank.stateAbbr) ?? 0) + 1);
|
|
53
|
+
}
|
|
54
|
+
return [...counts.entries()]
|
|
55
|
+
.sort(([leftState, leftCount], [rightState, rightCount]) => leftCount === rightCount ? leftState.localeCompare(rightState) : rightCount - leftCount)
|
|
56
|
+
.map(([stateAbbr, bankCount]) => ({ stateAbbr, bankCount }));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Parses one response into the banks in the page and the state counts.
|
|
60
|
+
*
|
|
61
|
+
* A row without an id, name, city, or state is a changed shape and stops the
|
|
62
|
+
* parse. The API's own total is used for `totalBanks`, falling back to the
|
|
63
|
+
* page size when the envelope omits it.
|
|
64
|
+
*
|
|
65
|
+
* @param payload - the JSON body from the FDIC institutions API
|
|
66
|
+
* @returns the banks in the page, the total the FDIC reports, and state counts
|
|
67
|
+
*/
|
|
68
|
+
export function parseFdicBankDirectoryPayload(payload) {
|
|
69
|
+
const parsed = FDIC_BANK_PAYLOAD_SCHEMA.safeParse(payload);
|
|
70
|
+
if (!parsed.success) {
|
|
71
|
+
throw new UsSourceParseError(FDIC_BANK_DIRECTORY_SOURCE_ID, parsed.error.message);
|
|
72
|
+
}
|
|
73
|
+
if (parsed.data.errors !== undefined && parsed.data.errors.length > 0) {
|
|
74
|
+
throw new UsSourceApiError(FDIC_BANK_DIRECTORY_SOURCE_ID, 'The API rejected the request');
|
|
75
|
+
}
|
|
76
|
+
const rows = parsed.data.data ?? [];
|
|
77
|
+
if (rows.length === 0) {
|
|
78
|
+
throw new UsSourceParseError(FDIC_BANK_DIRECTORY_SOURCE_ID, 'The response carried no rows');
|
|
79
|
+
}
|
|
80
|
+
const banks = rows.map((row) => {
|
|
81
|
+
const { ID, NAME, CITY, STALP } = row.data;
|
|
82
|
+
if (ID === undefined || NAME === undefined || CITY === undefined || STALP === undefined) {
|
|
83
|
+
throw new UsSourceParseError(FDIC_BANK_DIRECTORY_SOURCE_ID, 'A bank row arrived without its id, name, city, or state');
|
|
84
|
+
}
|
|
85
|
+
return { id: ID, name: NAME, city: CITY, stateAbbr: STALP };
|
|
86
|
+
});
|
|
87
|
+
const totalBanks = parsed.data.totals?.count ?? parsed.data.meta?.total ?? banks.length;
|
|
88
|
+
return {
|
|
89
|
+
banks,
|
|
90
|
+
bankCount: banks.length,
|
|
91
|
+
totalBanks,
|
|
92
|
+
states: countFdicBankStates(banks),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Reads one page of the FDIC's bank directory.
|
|
97
|
+
*
|
|
98
|
+
* One keyless request covers the page. The service trims each row to the
|
|
99
|
+
* columns asked for, so a story gets names, cities, and states without the
|
|
100
|
+
* full institution record.
|
|
101
|
+
*
|
|
102
|
+
* @param options - an optional row cap and fetch stub
|
|
103
|
+
* @returns the banks in the page, the FDIC total, and the state counts
|
|
104
|
+
*/
|
|
105
|
+
export async function fetchFdicBankDirectory(options) {
|
|
106
|
+
const fetchImpl = options?.fetchImpl ?? globalThis.fetch;
|
|
107
|
+
const url = buildFdicBankDirectoryUrl(options?.rowLimit === undefined ? {} : { rowLimit: options.rowLimit });
|
|
108
|
+
const response = await fetchImpl(url);
|
|
109
|
+
if (!response.ok) {
|
|
110
|
+
throw new UsSourceApiError(FDIC_BANK_DIRECTORY_SOURCE_ID, `HTTP ${response.status} reading the bank directory`);
|
|
111
|
+
}
|
|
112
|
+
return parseFdicBankDirectoryPayload(await response.json());
|
|
113
|
+
}
|
|
114
|
+
/** FDIC bank directory, one row per insured institution, keyless. */
|
|
115
|
+
export const fdicBankDirectoryAdapter = {
|
|
116
|
+
id: FDIC_BANK_DIRECTORY_SOURCE_ID,
|
|
117
|
+
name: 'FDIC bank directory',
|
|
118
|
+
auth: 'none',
|
|
119
|
+
description: 'Insured banks in the FDIC institution directory, one row per bank, with the city and state of its main office.',
|
|
120
|
+
fetchLive: async (options) => fetchFdicBankDirectory(options?.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
|
|
121
|
+
parse: (payload) => parseFdicBankDirectoryPayload(payload),
|
|
122
|
+
loadFixture: () => parseFdicBankDirectoryPayload(readFixtureJson(FDIC_BANK_FIXTURE_FILENAME)),
|
|
123
|
+
};
|
|
124
|
+
//# sourceMappingURL=fdicBankDirectory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fdicBankDirectory.js","sourceRoot":"","sources":["../src/fdicBankDirectory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhD,qDAAqD;AACrD,MAAM,CAAC,MAAM,6BAA6B,GAAG,qBAAqB,CAAC;AA+BnE,8CAA8C;AAC9C,MAAM,CAAC,MAAM,kBAAkB,GAAG,8CAA8C,CAAC;AAEjF,+BAA+B;AAC/B,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAEtC,qEAAqE;AACrE,MAAM,CAAC,MAAM,gBAAgB,GAAG,iBAAiB,CAAC;AAElD,8EAA8E;AAC9E,MAAM,0BAA0B,GAAG,qCAAqC,CAAC;AAEzE,4EAA4E;AAC5E,wEAAwE;AACxE,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;QACb,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QACzB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC3B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC3B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAC7B,CAAC;CACH,CAAC,CAAC;AAEH,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC3D,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC7D,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,QAAQ,EAAE;IAC9C,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE;CACxC,CAAC,CAAC;AAEH;;;;;;;;;;GAUG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAGzC;IACC,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;QACjC,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,QAAQ,IAAI,mBAAmB,CAAC;QACvD,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,gBAAgB;KAC5C,CAAC,CAAC;IACH,OAAO,GAAG,kBAAkB,IAAI,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;AACtD,CAAC;AAED,0DAA0D;AAC1D,SAAS,mBAAmB,CAAC,KAAiB;IAC5C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;SACzB,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC,EAAE,EAAE,CACzD,SAAS,KAAK,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG,SAAS,CACxF;SACA,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;AACjE,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,6BAA6B,CAAC,OAAgB;IAC5D,MAAM,MAAM,GAAG,wBAAwB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC3D,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,kBAAkB,CAAC,6BAA6B,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACpF,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,gBAAgB,CAAC,6BAA6B,EAAE,8BAA8B,CAAC,CAAC;IAC5F,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;IACpC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,kBAAkB,CAAC,6BAA6B,EAAE,8BAA8B,CAAC,CAAC;IAC9F,CAAC;IAED,MAAM,KAAK,GAAe,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACzC,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC;QAC3C,IAAI,EAAE,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxF,MAAM,IAAI,kBAAkB,CAC1B,6BAA6B,EAC7B,yDAAyD,CAC1D,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC;IAExF,OAAO;QACL,KAAK;QACL,SAAS,EAAE,KAAK,CAAC,MAAM;QACvB,UAAU;QACV,MAAM,EAAE,mBAAmB,CAAC,KAAK,CAAC;KACnC,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,OAG5C;IACC,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,UAAU,CAAC,KAAK,CAAC;IACzD,MAAM,GAAG,GAAG,yBAAyB,CACnC,OAAO,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CACtE,CAAC;IACF,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,gBAAgB,CACxB,6BAA6B,EAC7B,QAAQ,QAAQ,CAAC,MAAM,6BAA6B,CACrD,CAAC;IACJ,CAAC;IACD,OAAO,6BAA6B,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;AAC9D,CAAC;AAED,qEAAqE;AACrE,MAAM,CAAC,MAAM,wBAAwB,GAAqC;IACxE,EAAE,EAAE,6BAA6B;IACjC,IAAI,EAAE,qBAAqB;IAC3B,IAAI,EAAE,MAAM;IACZ,WAAW,EACT,gHAAgH;IAClH,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAC3B,sBAAsB,CACpB,OAAO,EAAE,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CACzE;IACH,KAAK,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,6BAA6B,CAAC,OAAO,CAAC;IAC1D,WAAW,EAAE,GAAG,EAAE,CAAC,6BAA6B,CAAC,eAAe,CAAC,0BAA0B,CAAC,CAAC;CAC9F,CAAC"}
|