@usa-open-data-connectors/usa-sources 0.1.2 → 0.1.4
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/LICENSE +21 -0
- package/README.md +442 -214
- package/dist/apiKey.d.ts +12 -0
- package/dist/apiKey.d.ts.map +1 -0
- package/dist/apiKey.js +18 -0
- package/dist/apiKey.js.map +1 -0
- package/dist/blsSeries.d.ts.map +1 -1
- package/dist/blsSeries.js +2 -4
- package/dist/blsSeries.js.map +1 -1
- package/dist/btsTransportationStats.d.ts +87 -0
- package/dist/btsTransportationStats.d.ts.map +1 -0
- package/dist/btsTransportationStats.js +130 -0
- package/dist/btsTransportationStats.js.map +1 -0
- package/dist/cdcCountyObesity.d.ts.map +1 -1
- package/dist/cdcCountyObesity.js +3 -5
- package/dist/cdcCountyObesity.js.map +1 -1
- package/dist/cdcSocrataCatalogue.d.ts +87 -0
- package/dist/cdcSocrataCatalogue.d.ts.map +1 -0
- package/dist/cdcSocrataCatalogue.js +130 -0
- package/dist/cdcSocrataCatalogue.js.map +1 -0
- package/dist/cfpbConsumerComplaints.d.ts +2 -0
- package/dist/cfpbConsumerComplaints.d.ts.map +1 -1
- package/dist/cfpbConsumerComplaints.js +12 -12
- package/dist/cfpbConsumerComplaints.js.map +1 -1
- package/dist/clinicalTrialsStudies.d.ts +92 -0
- package/dist/clinicalTrialsStudies.d.ts.map +1 -0
- package/dist/clinicalTrialsStudies.js +147 -0
- package/dist/clinicalTrialsStudies.js.map +1 -0
- package/dist/cpscProductRecalls.d.ts.map +1 -1
- package/dist/cpscProductRecalls.js +2 -4
- package/dist/cpscProductRecalls.js.map +1 -1
- package/dist/epaEnvirofactsFacilities.d.ts +94 -0
- package/dist/epaEnvirofactsFacilities.d.ts.map +1 -0
- package/dist/epaEnvirofactsFacilities.js +140 -0
- package/dist/epaEnvirofactsFacilities.js.map +1 -0
- package/dist/errors.d.ts +12 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +8 -4
- package/dist/errors.js.map +1 -1
- package/dist/estimatetaxIncomeTax.d.ts +140 -0
- package/dist/estimatetaxIncomeTax.d.ts.map +1 -0
- package/dist/estimatetaxIncomeTax.js +225 -0
- package/dist/estimatetaxIncomeTax.js.map +1 -0
- package/dist/fdicBankDirectory.d.ts +78 -0
- package/dist/fdicBankDirectory.d.ts.map +1 -0
- package/dist/fdicBankDirectory.js +122 -0
- package/dist/fdicBankDirectory.js.map +1 -0
- package/dist/femaDisasterDeclarations.d.ts.map +1 -1
- package/dist/femaDisasterDeclarations.js +2 -4
- package/dist/femaDisasterDeclarations.js.map +1 -1
- package/dist/healthdataSocrataCatalogue.d.ts +87 -0
- package/dist/healthdataSocrataCatalogue.d.ts.map +1 -0
- package/dist/healthdataSocrataCatalogue.js +130 -0
- package/dist/healthdataSocrataCatalogue.js.map +1 -0
- package/dist/http.d.ts +36 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +85 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +61 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +31 -1
- 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 +126 -0
- package/dist/ncbiPubmedSearch.js.map +1 -0
- package/dist/nceiAnnualTemperature.d.ts.map +1 -1
- package/dist/nceiAnnualTemperature.js +3 -5
- package/dist/nceiAnnualTemperature.js.map +1 -1
- package/dist/noaaSeaLevel.d.ts.map +1 -1
- package/dist/noaaSeaLevel.js +2 -4
- package/dist/noaaSeaLevel.js.map +1 -1
- package/dist/nwsPointForecast.d.ts +99 -0
- package/dist/nwsPointForecast.d.ts.map +1 -0
- package/dist/nwsPointForecast.js +147 -0
- package/dist/nwsPointForecast.js.map +1 -0
- package/dist/nycOpenDataCatalogue.d.ts +97 -0
- package/dist/nycOpenDataCatalogue.d.ts.map +1 -0
- package/dist/nycOpenDataCatalogue.js +151 -0
- package/dist/nycOpenDataCatalogue.js.map +1 -0
- package/dist/openFdaFoodRecalls.d.ts.map +1 -1
- package/dist/openFdaFoodRecalls.js +2 -4
- package/dist/openFdaFoodRecalls.js.map +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +30 -2
- 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 +215 -0
- package/dist/secEdgarFilings.js.map +1 -0
- package/dist/treasuryAvgInterestRate.d.ts.map +1 -1
- package/dist/treasuryAvgInterestRate.js +2 -4
- package/dist/treasuryAvgInterestRate.js.map +1 -1
- package/dist/treasuryDebtToPenny.d.ts +90 -0
- package/dist/treasuryDebtToPenny.d.ts.map +1 -0
- package/dist/treasuryDebtToPenny.js +168 -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 +119 -0
- package/dist/usaspendingAgencies.js.map +1 -0
- package/dist/usgsEarthquakes.d.ts.map +1 -1
- package/dist/usgsEarthquakes.js +2 -4
- package/dist/usgsEarthquakes.js.map +1 -1
- package/dist/usgsPeakStreamflow.d.ts.map +1 -1
- package/dist/usgsPeakStreamflow.js +3 -5
- package/dist/usgsPeakStreamflow.js.map +1 -1
- package/package.json +13 -4
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { UsSourceApiError, UsSourceParseError } from './errors.js';
|
|
3
|
+
import { httpGet } from './http.js';
|
|
4
|
+
import { readFixtureJson } from './fixtures.js';
|
|
5
|
+
/** Adapter id for the EPA Envirofacts facility source. */
|
|
6
|
+
export const EPA_ENVIROFACTS_FACILITIES_SOURCE_ID = 'epa-envirofacts-facilities';
|
|
7
|
+
/** Base URL for the EPA Envirofacts service. */
|
|
8
|
+
export const EPA_ENVIROFACTS_API_BASE = 'https://data.epa.gov/efservice';
|
|
9
|
+
/** Envirofacts table that holds the Toxics Release Inventory facility records. */
|
|
10
|
+
export const EPA_ENVIROFACTS_TABLE = 'TRI_FACILITY';
|
|
11
|
+
/** Envirofacts column the state filter reads. */
|
|
12
|
+
export const EPA_ENVIROFACTS_STATE_COLUMN = 'STATE_ABBR';
|
|
13
|
+
/** State the default URL asks for. */
|
|
14
|
+
export const EPA_ENVIROFACTS_STATE_ABBR = 'RI';
|
|
15
|
+
/** Row window one request reads, the first ten rows. */
|
|
16
|
+
export const EPA_ENVIROFACTS_ROW_WINDOW = '0:9';
|
|
17
|
+
/** Committed snapshot, so a build works when the Envirofacts host is unreachable. */
|
|
18
|
+
const EPA_ENVIROFACTS_FIXTURE_FILENAME = 'epa-envirofacts-facilities-2026-10-05.json';
|
|
19
|
+
// The service answers with a bare JSON array, and a rejected query answers
|
|
20
|
+
// with a body of {error}. The filter segment takes the value on its own: an
|
|
21
|
+
// "equals" operator is accepted in the URL but never narrows the rows, so the
|
|
22
|
+
// URL builder below does not use one.
|
|
23
|
+
const EPA_ENVIROFACTS_FACILITY_SCHEMA = z.object({
|
|
24
|
+
tri_facility_id: z.string(),
|
|
25
|
+
facility_name: z.string(),
|
|
26
|
+
street_address: z.string().nullable().optional(),
|
|
27
|
+
city_name: z.string().nullable().optional(),
|
|
28
|
+
county_name: z.string().nullable().optional(),
|
|
29
|
+
state_abbr: z.string(),
|
|
30
|
+
zip_code: z.string().nullable().optional(),
|
|
31
|
+
region: z.string().nullable().optional(),
|
|
32
|
+
fac_closed_ind: z.string().nullable().optional(),
|
|
33
|
+
parent_co_name: z.string().nullable().optional(),
|
|
34
|
+
});
|
|
35
|
+
const EPA_ENVIROFACTS_PAYLOAD_SCHEMA = z.union([
|
|
36
|
+
z.array(EPA_ENVIROFACTS_FACILITY_SCHEMA),
|
|
37
|
+
z.object({ error: z.string().optional() }),
|
|
38
|
+
]);
|
|
39
|
+
/** Reads the parent company, treating the register's "NA" as absent. */
|
|
40
|
+
function readEpaParentCompany(value) {
|
|
41
|
+
if (value === null || value === undefined) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
const trimmed = value.trim();
|
|
45
|
+
return trimmed === '' || trimmed === 'NA' ? null : trimmed;
|
|
46
|
+
}
|
|
47
|
+
/** Counts facilities per county, most facilities first, then by name. */
|
|
48
|
+
function countEpaEnvirofactsCounties(facilities) {
|
|
49
|
+
const counts = new Map();
|
|
50
|
+
for (const facility of facilities) {
|
|
51
|
+
counts.set(facility.countyName, (counts.get(facility.countyName) ?? 0) + 1);
|
|
52
|
+
}
|
|
53
|
+
return [...counts.entries()]
|
|
54
|
+
.sort(([leftCounty, leftCount], [rightCounty, rightCount]) => leftCount === rightCount ? leftCounty.localeCompare(rightCounty) : rightCount - leftCount)
|
|
55
|
+
.map(([countyName, facilityCount]) => ({ countyName, facilityCount }));
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Builds the request URL for one page of Toxics Release Inventory facilities.
|
|
59
|
+
*
|
|
60
|
+
* The endpoint is keyless, and the state segment does narrow the rows: the
|
|
61
|
+
* value sits directly after the column name, with no `equals` operator.
|
|
62
|
+
* Envirofacts accepts an `equals` segment without complaining but then
|
|
63
|
+
* returns the table's first rows instead of the ones asked for.
|
|
64
|
+
*
|
|
65
|
+
* @param options - an optional state code and row window
|
|
66
|
+
* @returns the full request URL
|
|
67
|
+
*/
|
|
68
|
+
export function buildEpaEnvirofactsFacilitiesUrl(options) {
|
|
69
|
+
const stateAbbr = options?.stateAbbr ?? EPA_ENVIROFACTS_STATE_ABBR;
|
|
70
|
+
const rowWindow = options?.rowWindow ?? EPA_ENVIROFACTS_ROW_WINDOW;
|
|
71
|
+
return `${EPA_ENVIROFACTS_API_BASE}/${EPA_ENVIROFACTS_TABLE}/${EPA_ENVIROFACTS_STATE_COLUMN}/${stateAbbr}/rows/${rowWindow}/JSON`;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Parses one response into the facilities in the page and its rollups.
|
|
75
|
+
*
|
|
76
|
+
* A row without a facility id, name, or state code fails the schema and stops
|
|
77
|
+
* the parse. An empty array is treated as a changed source, because the
|
|
78
|
+
* default query always returns rows.
|
|
79
|
+
*
|
|
80
|
+
* @param payload - the JSON body from the Envirofacts service
|
|
81
|
+
* @returns the facilities in the page, the open and closed counts, and the counties
|
|
82
|
+
*/
|
|
83
|
+
export function parseEpaEnvirofactsFacilitiesPayload(payload) {
|
|
84
|
+
const parsed = EPA_ENVIROFACTS_PAYLOAD_SCHEMA.safeParse(payload);
|
|
85
|
+
if (!parsed.success) {
|
|
86
|
+
throw new UsSourceParseError(EPA_ENVIROFACTS_FACILITIES_SOURCE_ID, parsed.error.message);
|
|
87
|
+
}
|
|
88
|
+
if (!Array.isArray(parsed.data)) {
|
|
89
|
+
throw new UsSourceApiError(EPA_ENVIROFACTS_FACILITIES_SOURCE_ID, parsed.data.error ?? 'The service rejected the query');
|
|
90
|
+
}
|
|
91
|
+
if (parsed.data.length === 0) {
|
|
92
|
+
throw new UsSourceParseError(EPA_ENVIROFACTS_FACILITIES_SOURCE_ID, 'The response carried no rows');
|
|
93
|
+
}
|
|
94
|
+
const facilities = parsed.data.map((row) => ({
|
|
95
|
+
facilityId: row.tri_facility_id,
|
|
96
|
+
facilityName: row.facility_name,
|
|
97
|
+
streetAddress: row.street_address ?? '',
|
|
98
|
+
city: row.city_name ?? '',
|
|
99
|
+
countyName: row.county_name ?? '',
|
|
100
|
+
stateAbbr: row.state_abbr,
|
|
101
|
+
postalCode: row.zip_code ?? '',
|
|
102
|
+
region: row.region ?? '',
|
|
103
|
+
closed: row.fac_closed_ind === '1',
|
|
104
|
+
parentCompanyName: readEpaParentCompany(row.parent_co_name),
|
|
105
|
+
}));
|
|
106
|
+
const closedCount = facilities.filter((facility) => facility.closed).length;
|
|
107
|
+
return {
|
|
108
|
+
facilities,
|
|
109
|
+
facilityCount: facilities.length,
|
|
110
|
+
openCount: facilities.length - closedCount,
|
|
111
|
+
closedCount,
|
|
112
|
+
counties: countEpaEnvirofactsCounties(facilities),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Reads one page of Toxics Release Inventory facilities from Envirofacts.
|
|
117
|
+
*
|
|
118
|
+
* One keyless request covers the page. The state segment in the URL narrows
|
|
119
|
+
* the rows, so the page holds facilities from the state that was asked for.
|
|
120
|
+
*
|
|
121
|
+
* @param options - an optional state code, row window, and fetch stub
|
|
122
|
+
* @returns the facilities in the page and its rollups
|
|
123
|
+
*/
|
|
124
|
+
export async function fetchEpaEnvirofactsFacilities(options) {
|
|
125
|
+
const fetchImpl = options?.fetchImpl ?? globalThis.fetch;
|
|
126
|
+
const url = buildEpaEnvirofactsFacilitiesUrl(options?.stateAbbr === undefined ? {} : { stateAbbr: options.stateAbbr });
|
|
127
|
+
const response = await httpGet(EPA_ENVIROFACTS_FACILITIES_SOURCE_ID, url, { fetchImpl });
|
|
128
|
+
return parseEpaEnvirofactsFacilitiesPayload(await response.json());
|
|
129
|
+
}
|
|
130
|
+
/** EPA Envirofacts Toxics Release Inventory facilities, keyless. */
|
|
131
|
+
export const epaEnvirofactsFacilitiesAdapter = {
|
|
132
|
+
id: EPA_ENVIROFACTS_FACILITIES_SOURCE_ID,
|
|
133
|
+
name: 'EPA Envirofacts facilities',
|
|
134
|
+
auth: 'none',
|
|
135
|
+
description: 'Toxics Release Inventory facilities from the EPA Envirofacts service, one row per site, with its county, address, and open or closed status.',
|
|
136
|
+
fetchLive: async (options) => fetchEpaEnvirofactsFacilities(options?.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
|
|
137
|
+
parse: (payload) => parseEpaEnvirofactsFacilitiesPayload(payload),
|
|
138
|
+
loadFixture: () => parseEpaEnvirofactsFacilitiesPayload(readFixtureJson(EPA_ENVIROFACTS_FIXTURE_FILENAME)),
|
|
139
|
+
};
|
|
140
|
+
//# sourceMappingURL=epaEnvirofactsFacilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"epaEnvirofactsFacilities.js","sourceRoot":"","sources":["../src/epaEnvirofactsFacilities.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
CHANGED
|
@@ -2,10 +2,20 @@
|
|
|
2
2
|
export declare class UsSourceError extends Error {
|
|
3
3
|
constructor(message: string, options?: ErrorOptions);
|
|
4
4
|
}
|
|
5
|
+
/** Extra detail carried by an API error. */
|
|
6
|
+
export interface UsSourceApiErrorDetails extends ErrorOptions {
|
|
7
|
+
/** HTTP status code, when the failure arrived as a response. */
|
|
8
|
+
status?: number | undefined;
|
|
9
|
+
/** Whether retrying the same request could succeed. */
|
|
10
|
+
retryable?: boolean | undefined;
|
|
11
|
+
}
|
|
5
12
|
/** The remote API rejected the request (HTTP error or bad payload). */
|
|
6
13
|
export declare class UsSourceApiError extends UsSourceError {
|
|
7
|
-
|
|
8
|
-
|
|
14
|
+
/** HTTP status code, when the failure arrived as a response. */
|
|
15
|
+
readonly status: number | undefined;
|
|
16
|
+
/** Whether retrying the same request could succeed. */
|
|
17
|
+
readonly retryable: boolean;
|
|
18
|
+
constructor(source: string, message: string, details?: UsSourceApiErrorDetails);
|
|
9
19
|
}
|
|
10
20
|
/** The remote payload did not match the expected shape. */
|
|
11
21
|
export declare class UsSourceParseError extends UsSourceError {
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,qBAAa,aAAc,SAAQ,KAAK;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,qBAAa,aAAc,SAAQ,KAAK;IACtC,YAAY,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,EAGlD;CACF;AAED,4CAA4C;AAC5C,MAAM,WAAW,uBAAwB,SAAQ,YAAY;IAC3D,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,uDAAuD;IACvD,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACjC;AAED,uEAAuE;AACvE,qBAAa,gBAAiB,SAAQ,aAAa;IACjD,gEAAgE;IAChE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,uDAAuD;IACvD,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAE5B,YAAY,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,uBAA4B,EAKjF;CACF;AAED,2DAA2D;AAC3D,qBAAa,kBAAmB,SAAQ,aAAa;aAEjC,MAAM,EAAE,MAAM;IADhC,YACkB,MAAM,EAAE,MAAM,EAC9B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,YAAY,EAIvB;CACF"}
|
package/dist/errors.js
CHANGED
|
@@ -7,11 +7,15 @@ export class UsSourceError extends Error {
|
|
|
7
7
|
}
|
|
8
8
|
/** The remote API rejected the request (HTTP error or bad payload). */
|
|
9
9
|
export class UsSourceApiError extends UsSourceError {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
/** HTTP status code, when the failure arrived as a response. */
|
|
11
|
+
status;
|
|
12
|
+
/** Whether retrying the same request could succeed. */
|
|
13
|
+
retryable;
|
|
14
|
+
constructor(source, message, details = {}) {
|
|
15
|
+
super(`${source}: ${message}`, details);
|
|
14
16
|
this.name = 'UsSourceApiError';
|
|
17
|
+
this.status = details.status;
|
|
18
|
+
this.retryable = details.retryable ?? false;
|
|
15
19
|
}
|
|
16
20
|
}
|
|
17
21
|
/** The remote payload did not match the expected shape. */
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,MAAM,OAAO,aAAc,SAAQ,KAAK;IACtC,YAAY,OAAe,EAAE,OAAsB;QACjD,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,MAAM,OAAO,aAAc,SAAQ,KAAK;IACtC,YAAY,OAAe,EAAE,OAAsB;QACjD,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AAUD,uEAAuE;AACvE,MAAM,OAAO,gBAAiB,SAAQ,aAAa;IACjD,gEAAgE;IACvD,MAAM,CAAqB;IACpC,uDAAuD;IAC9C,SAAS,CAAU;IAE5B,YAAY,MAAc,EAAE,OAAe,EAAE,OAAO,GAA4B,EAAE;QAChF,KAAK,CAAC,GAAG,MAAM,KAAK,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;QAC/B,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC;IAC9C,CAAC;CACF;AAED,2DAA2D;AAC3D,MAAM,OAAO,kBAAmB,SAAQ,aAAa;IAEjC,MAAM;IADxB,YACkB,MAAc,EAC9B,OAAe,EACf,OAAsB;QAEtB,KAAK,CAAC,GAAG,MAAM,KAAK,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;sBAJxB,MAAM;QAKtB,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import type { UsDataAdapter } from './types.js';
|
|
2
|
+
/** Adapter id for the EstimateTax income tax source. */
|
|
3
|
+
export declare const ESTIMATETAX_INCOME_TAX_SOURCE_ID = "estimatetax-income-tax";
|
|
4
|
+
/** Base URL for the EstimateTax API. */
|
|
5
|
+
export declare const ESTIMATETAX_API_BASE = "https://estimatetax.net";
|
|
6
|
+
/** Path of the one calculation endpoint. */
|
|
7
|
+
export declare const ESTIMATETAX_CALCULATE_PATH = "/api/v1/calculate";
|
|
8
|
+
/** Default annual income in the worked example. */
|
|
9
|
+
export declare const ESTIMATETAX_DEFAULT_INCOME = 85000;
|
|
10
|
+
/** Default state in the worked example. */
|
|
11
|
+
export declare const ESTIMATETAX_DEFAULT_STATE = "NY";
|
|
12
|
+
/** Default local jurisdiction in the worked example. */
|
|
13
|
+
export declare const ESTIMATETAX_DEFAULT_CITY = "new-york-city";
|
|
14
|
+
/** Filing statuses the API accepts. */
|
|
15
|
+
export declare const ESTIMATETAX_FILING_STATUSES: readonly ['single', 'married_jointly', 'married_separately', 'head_of_household'];
|
|
16
|
+
/** One filing status the API accepts. */
|
|
17
|
+
export type EstimateTaxFilingStatus = (typeof ESTIMATETAX_FILING_STATUSES)[number];
|
|
18
|
+
/** Inputs for one tax calculation. */
|
|
19
|
+
export interface EstimateTaxQuery {
|
|
20
|
+
/** Gross annual employment income, in US dollars. */
|
|
21
|
+
income: number;
|
|
22
|
+
/** How the taxpayer files. Defaults to single. */
|
|
23
|
+
filingStatus?: EstimateTaxFilingStatus;
|
|
24
|
+
/** Two-letter state code, or null for federal tax only. */
|
|
25
|
+
state?: string | null;
|
|
26
|
+
/** Local jurisdiction slug, where the state levies a local income tax. */
|
|
27
|
+
city?: string | null;
|
|
28
|
+
/** Pre-tax deductions such as a 401(k) or health premiums. */
|
|
29
|
+
preTaxDeductions?: number;
|
|
30
|
+
/** Net self-employment income. */
|
|
31
|
+
selfEmploymentIncome?: number;
|
|
32
|
+
}
|
|
33
|
+
/** The input block echoed back in a calculation. */
|
|
34
|
+
export interface EstimateTaxInput {
|
|
35
|
+
income: number;
|
|
36
|
+
filingStatus: EstimateTaxFilingStatus;
|
|
37
|
+
state: string | null;
|
|
38
|
+
city: string | null;
|
|
39
|
+
preTaxDeductions: number;
|
|
40
|
+
selfEmploymentIncome: number;
|
|
41
|
+
}
|
|
42
|
+
/** One federal bracket and how much tax the income paid in it. */
|
|
43
|
+
export interface EstimateTaxBracket {
|
|
44
|
+
rate: number;
|
|
45
|
+
taxableIncome: number;
|
|
46
|
+
tax: number;
|
|
47
|
+
}
|
|
48
|
+
/** Federal income tax, payroll tax, and the brackets the income crossed. */
|
|
49
|
+
export interface EstimateTaxFederal {
|
|
50
|
+
incomeTax: number;
|
|
51
|
+
totalFica: number;
|
|
52
|
+
marginalRate: number;
|
|
53
|
+
brackets: EstimateTaxBracket[];
|
|
54
|
+
}
|
|
55
|
+
/** State income tax for the chosen jurisdiction. */
|
|
56
|
+
export interface EstimateTaxState {
|
|
57
|
+
code: string;
|
|
58
|
+
name: string;
|
|
59
|
+
tax: number;
|
|
60
|
+
system: string;
|
|
61
|
+
}
|
|
62
|
+
/** Local income tax for the chosen city, county, or school district. */
|
|
63
|
+
export interface EstimateTaxLocal {
|
|
64
|
+
jurisdiction: string;
|
|
65
|
+
tax: number;
|
|
66
|
+
rate: number;
|
|
67
|
+
base: string;
|
|
68
|
+
}
|
|
69
|
+
/** The total tax and the income left after it. */
|
|
70
|
+
export interface EstimateTaxTotals {
|
|
71
|
+
totalTax: number;
|
|
72
|
+
netIncome: number;
|
|
73
|
+
effectiveRate: number;
|
|
74
|
+
effectiveIncomeTaxRate: number;
|
|
75
|
+
}
|
|
76
|
+
/** The official document behind one layer of the calculation. */
|
|
77
|
+
export interface EstimateTaxSource {
|
|
78
|
+
citation?: string;
|
|
79
|
+
authority?: string;
|
|
80
|
+
document?: string;
|
|
81
|
+
url: string;
|
|
82
|
+
/** The date the publisher checked the figure, under either API field name. */
|
|
83
|
+
checkedDate?: string;
|
|
84
|
+
}
|
|
85
|
+
/** Every source a calculation cites. */
|
|
86
|
+
export interface EstimateTaxSources {
|
|
87
|
+
federal: EstimateTaxSource;
|
|
88
|
+
state: EstimateTaxSource | null;
|
|
89
|
+
local: EstimateTaxSource | null;
|
|
90
|
+
}
|
|
91
|
+
/** One complete tax calculation. */
|
|
92
|
+
export interface EstimateTaxCalculation {
|
|
93
|
+
taxYear: number;
|
|
94
|
+
input: EstimateTaxInput;
|
|
95
|
+
federal: EstimateTaxFederal;
|
|
96
|
+
state: EstimateTaxState | null;
|
|
97
|
+
local: EstimateTaxLocal | null;
|
|
98
|
+
totals: EstimateTaxTotals;
|
|
99
|
+
sources: EstimateTaxSources;
|
|
100
|
+
}
|
|
101
|
+
/** The query the adapter uses when the caller gives none. */
|
|
102
|
+
export declare const ESTIMATETAX_DEFAULT_QUERY: EstimateTaxQuery;
|
|
103
|
+
/**
|
|
104
|
+
* Builds the request URL for one tax calculation.
|
|
105
|
+
*
|
|
106
|
+
* The endpoint is keyless and limited to 60 requests a minute. The default
|
|
107
|
+
* query is the $85,000 New York City case the committed fixture records.
|
|
108
|
+
*
|
|
109
|
+
* @param query - income and optional place, filing status, and deductions
|
|
110
|
+
* @returns the full request URL
|
|
111
|
+
*/
|
|
112
|
+
export declare function buildEstimateTaxUrl(query?: EstimateTaxQuery): string;
|
|
113
|
+
/**
|
|
114
|
+
* Parses one calculation into the tax parts and their cited sources.
|
|
115
|
+
*
|
|
116
|
+
* A state or local layer is null when the calculation does not include it.
|
|
117
|
+
* The parser refuses a missing federal bracket list, a negative amount, or a
|
|
118
|
+
* source block without the document URL, so a changed response cannot quietly
|
|
119
|
+
* produce a figure with no provenance.
|
|
120
|
+
*
|
|
121
|
+
* @param payload - the JSON body from the calculation endpoint
|
|
122
|
+
* @returns the calculation in the adapter's shape
|
|
123
|
+
*/
|
|
124
|
+
export declare function parseEstimateTaxCalculation(payload: unknown): EstimateTaxCalculation;
|
|
125
|
+
/**
|
|
126
|
+
* Reads one US income tax calculation.
|
|
127
|
+
*
|
|
128
|
+
* One keyless request answers the federal, state, and local layers together.
|
|
129
|
+
* Every layer carries the official document its figures came from.
|
|
130
|
+
*
|
|
131
|
+
* @param options - the calculation query and an optional fetch stub
|
|
132
|
+
* @returns the calculation in the adapter's shape
|
|
133
|
+
*/
|
|
134
|
+
export declare function fetchEstimateTaxCalculation(options?: {
|
|
135
|
+
query?: EstimateTaxQuery;
|
|
136
|
+
fetchImpl?: typeof globalThis.fetch;
|
|
137
|
+
}): Promise<EstimateTaxCalculation>;
|
|
138
|
+
/** EstimateTax US federal, state, and local income tax, keyless. */
|
|
139
|
+
export declare const estimatetaxIncomeTaxAdapter: UsDataAdapter<EstimateTaxCalculation>;
|
|
140
|
+
//# sourceMappingURL=estimatetaxIncomeTax.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"estimatetaxIncomeTax.d.ts","sourceRoot":"","sources":["../src/estimatetaxIncomeTax.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { UsSourceParseError } from './errors.js';
|
|
3
|
+
import { readFixtureJson } from './fixtures.js';
|
|
4
|
+
import { httpGet } from './http.js';
|
|
5
|
+
/** Adapter id for the EstimateTax income tax source. */
|
|
6
|
+
export const ESTIMATETAX_INCOME_TAX_SOURCE_ID = 'estimatetax-income-tax';
|
|
7
|
+
/** Base URL for the EstimateTax API. */
|
|
8
|
+
export const ESTIMATETAX_API_BASE = 'https://estimatetax.net';
|
|
9
|
+
/** Path of the one calculation endpoint. */
|
|
10
|
+
export const ESTIMATETAX_CALCULATE_PATH = '/api/v1/calculate';
|
|
11
|
+
/** Default annual income in the worked example. */
|
|
12
|
+
export const ESTIMATETAX_DEFAULT_INCOME = 85_000;
|
|
13
|
+
/** Default state in the worked example. */
|
|
14
|
+
export const ESTIMATETAX_DEFAULT_STATE = 'NY';
|
|
15
|
+
/** Default local jurisdiction in the worked example. */
|
|
16
|
+
export const ESTIMATETAX_DEFAULT_CITY = 'new-york-city';
|
|
17
|
+
/** Filing statuses the API accepts. */
|
|
18
|
+
export const ESTIMATETAX_FILING_STATUSES = [
|
|
19
|
+
'single',
|
|
20
|
+
'married_jointly',
|
|
21
|
+
'married_separately',
|
|
22
|
+
'head_of_household',
|
|
23
|
+
];
|
|
24
|
+
/** Committed snapshot, so a build works when EstimateTax is unreachable. */
|
|
25
|
+
const ESTIMATETAX_FIXTURE_FILENAME = 'estimatetax-income-tax-2026-10-18.json';
|
|
26
|
+
const ESTIMATETAX_SOURCE_SCHEMA = z.object({
|
|
27
|
+
citation: z.string().optional(),
|
|
28
|
+
authority: z.string().optional(),
|
|
29
|
+
document: z.string().optional(),
|
|
30
|
+
url: z.string().url(),
|
|
31
|
+
verified: z.string().optional(),
|
|
32
|
+
checked: z.string().optional(),
|
|
33
|
+
});
|
|
34
|
+
const ESTIMATETAX_INPUT_SCHEMA = z.object({
|
|
35
|
+
income: z.number().nonnegative(),
|
|
36
|
+
filingStatus: z.enum(ESTIMATETAX_FILING_STATUSES),
|
|
37
|
+
state: z.string().nullable().optional(),
|
|
38
|
+
city: z.string().nullable().optional(),
|
|
39
|
+
preTaxDeductions: z.number().nonnegative().optional(),
|
|
40
|
+
selfEmploymentIncome: z.number().nonnegative().optional(),
|
|
41
|
+
});
|
|
42
|
+
const ESTIMATETAX_BRACKET_SCHEMA = z.object({
|
|
43
|
+
rate: z.number().nonnegative(),
|
|
44
|
+
taxableInBracket: z.number().nonnegative(),
|
|
45
|
+
tax: z.number().nonnegative(),
|
|
46
|
+
});
|
|
47
|
+
const ESTIMATETAX_FEDERAL_SCHEMA = z.object({
|
|
48
|
+
incomeTax: z.number().nonnegative(),
|
|
49
|
+
totalFica: z.number().nonnegative(),
|
|
50
|
+
marginalRate: z.number().nonnegative(),
|
|
51
|
+
brackets: z.array(ESTIMATETAX_BRACKET_SCHEMA).min(1),
|
|
52
|
+
});
|
|
53
|
+
const ESTIMATETAX_STATE_SCHEMA = z.object({
|
|
54
|
+
code: z.string().min(2),
|
|
55
|
+
name: z.string().min(1),
|
|
56
|
+
tax: z.number().nonnegative(),
|
|
57
|
+
system: z.string().min(1),
|
|
58
|
+
});
|
|
59
|
+
const ESTIMATETAX_LOCAL_SCHEMA = z.object({
|
|
60
|
+
jurisdiction: z.string().min(1),
|
|
61
|
+
tax: z.number().nonnegative(),
|
|
62
|
+
rate: z.number().nonnegative(),
|
|
63
|
+
base: z.string().min(1),
|
|
64
|
+
});
|
|
65
|
+
const ESTIMATETAX_TOTALS_SCHEMA = z.object({
|
|
66
|
+
totalTax: z.number().nonnegative(),
|
|
67
|
+
netIncome: z.number().nonnegative(),
|
|
68
|
+
effectiveRate: z.number().nonnegative(),
|
|
69
|
+
effectiveIncomeTaxRate: z.number().nonnegative(),
|
|
70
|
+
});
|
|
71
|
+
const ESTIMATETAX_PAYLOAD_SCHEMA = z.object({
|
|
72
|
+
taxYear: z.number().int().positive(),
|
|
73
|
+
input: ESTIMATETAX_INPUT_SCHEMA,
|
|
74
|
+
federal: ESTIMATETAX_FEDERAL_SCHEMA,
|
|
75
|
+
state: ESTIMATETAX_STATE_SCHEMA.nullable().optional(),
|
|
76
|
+
local: ESTIMATETAX_LOCAL_SCHEMA.nullable().optional(),
|
|
77
|
+
totals: ESTIMATETAX_TOTALS_SCHEMA,
|
|
78
|
+
sources: z.object({
|
|
79
|
+
federal: ESTIMATETAX_SOURCE_SCHEMA,
|
|
80
|
+
state: ESTIMATETAX_SOURCE_SCHEMA.nullable().optional(),
|
|
81
|
+
local: ESTIMATETAX_SOURCE_SCHEMA.nullable().optional(),
|
|
82
|
+
}),
|
|
83
|
+
});
|
|
84
|
+
/** The query the adapter uses when the caller gives none. */
|
|
85
|
+
export const ESTIMATETAX_DEFAULT_QUERY = {
|
|
86
|
+
income: ESTIMATETAX_DEFAULT_INCOME,
|
|
87
|
+
filingStatus: 'single',
|
|
88
|
+
state: ESTIMATETAX_DEFAULT_STATE,
|
|
89
|
+
city: ESTIMATETAX_DEFAULT_CITY,
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Builds the request URL for one tax calculation.
|
|
93
|
+
*
|
|
94
|
+
* The endpoint is keyless and limited to 60 requests a minute. The default
|
|
95
|
+
* query is the $85,000 New York City case the committed fixture records.
|
|
96
|
+
*
|
|
97
|
+
* @param query - income and optional place, filing status, and deductions
|
|
98
|
+
* @returns the full request URL
|
|
99
|
+
*/
|
|
100
|
+
export function buildEstimateTaxUrl(query = ESTIMATETAX_DEFAULT_QUERY) {
|
|
101
|
+
const params = new URLSearchParams({ income: String(query.income) });
|
|
102
|
+
if (query.filingStatus !== undefined) {
|
|
103
|
+
params.set('filingStatus', query.filingStatus);
|
|
104
|
+
}
|
|
105
|
+
if (query.state !== undefined && query.state !== null) {
|
|
106
|
+
params.set('state', query.state);
|
|
107
|
+
}
|
|
108
|
+
if (query.city !== undefined && query.city !== null) {
|
|
109
|
+
params.set('city', query.city);
|
|
110
|
+
}
|
|
111
|
+
if (query.preTaxDeductions !== undefined) {
|
|
112
|
+
params.set('preTaxDeductions', String(query.preTaxDeductions));
|
|
113
|
+
}
|
|
114
|
+
if (query.selfEmploymentIncome !== undefined) {
|
|
115
|
+
params.set('selfEmploymentIncome', String(query.selfEmploymentIncome));
|
|
116
|
+
}
|
|
117
|
+
return `${ESTIMATETAX_API_BASE}${ESTIMATETAX_CALCULATE_PATH}?${params.toString()}`;
|
|
118
|
+
}
|
|
119
|
+
/** Turns the API's source block into the adapter's shape. */
|
|
120
|
+
function readEstimateTaxSource(source) {
|
|
121
|
+
const checkedDate = source.checked ?? source.verified;
|
|
122
|
+
return {
|
|
123
|
+
url: source.url,
|
|
124
|
+
...(source.citation === undefined ? {} : { citation: source.citation }),
|
|
125
|
+
...(source.authority === undefined ? {} : { authority: source.authority }),
|
|
126
|
+
...(source.document === undefined ? {} : { document: source.document }),
|
|
127
|
+
...(checkedDate === undefined ? {} : { checkedDate }),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Parses one calculation into the tax parts and their cited sources.
|
|
132
|
+
*
|
|
133
|
+
* A state or local layer is null when the calculation does not include it.
|
|
134
|
+
* The parser refuses a missing federal bracket list, a negative amount, or a
|
|
135
|
+
* source block without the document URL, so a changed response cannot quietly
|
|
136
|
+
* produce a figure with no provenance.
|
|
137
|
+
*
|
|
138
|
+
* @param payload - the JSON body from the calculation endpoint
|
|
139
|
+
* @returns the calculation in the adapter's shape
|
|
140
|
+
*/
|
|
141
|
+
export function parseEstimateTaxCalculation(payload) {
|
|
142
|
+
const parsed = ESTIMATETAX_PAYLOAD_SCHEMA.safeParse(payload);
|
|
143
|
+
if (!parsed.success) {
|
|
144
|
+
throw new UsSourceParseError(ESTIMATETAX_INCOME_TAX_SOURCE_ID, parsed.error.message);
|
|
145
|
+
}
|
|
146
|
+
const value = parsed.data;
|
|
147
|
+
return {
|
|
148
|
+
taxYear: value.taxYear,
|
|
149
|
+
input: {
|
|
150
|
+
income: value.input.income,
|
|
151
|
+
filingStatus: value.input.filingStatus,
|
|
152
|
+
state: value.input.state ?? null,
|
|
153
|
+
city: value.input.city ?? null,
|
|
154
|
+
preTaxDeductions: value.input.preTaxDeductions ?? 0,
|
|
155
|
+
selfEmploymentIncome: value.input.selfEmploymentIncome ?? 0,
|
|
156
|
+
},
|
|
157
|
+
federal: {
|
|
158
|
+
incomeTax: value.federal.incomeTax,
|
|
159
|
+
totalFica: value.federal.totalFica,
|
|
160
|
+
marginalRate: value.federal.marginalRate,
|
|
161
|
+
brackets: value.federal.brackets.map((bracket) => ({
|
|
162
|
+
rate: bracket.rate,
|
|
163
|
+
taxableIncome: bracket.taxableInBracket,
|
|
164
|
+
tax: bracket.tax,
|
|
165
|
+
})),
|
|
166
|
+
},
|
|
167
|
+
state: value.state === null || value.state === undefined
|
|
168
|
+
? null
|
|
169
|
+
: {
|
|
170
|
+
code: value.state.code,
|
|
171
|
+
name: value.state.name,
|
|
172
|
+
tax: value.state.tax,
|
|
173
|
+
system: value.state.system,
|
|
174
|
+
},
|
|
175
|
+
local: value.local === null || value.local === undefined
|
|
176
|
+
? null
|
|
177
|
+
: {
|
|
178
|
+
jurisdiction: value.local.jurisdiction,
|
|
179
|
+
tax: value.local.tax,
|
|
180
|
+
rate: value.local.rate,
|
|
181
|
+
base: value.local.base,
|
|
182
|
+
},
|
|
183
|
+
totals: {
|
|
184
|
+
totalTax: value.totals.totalTax,
|
|
185
|
+
netIncome: value.totals.netIncome,
|
|
186
|
+
effectiveRate: value.totals.effectiveRate,
|
|
187
|
+
effectiveIncomeTaxRate: value.totals.effectiveIncomeTaxRate,
|
|
188
|
+
},
|
|
189
|
+
sources: {
|
|
190
|
+
federal: readEstimateTaxSource(value.sources.federal),
|
|
191
|
+
state: value.sources.state === null || value.sources.state === undefined
|
|
192
|
+
? null
|
|
193
|
+
: readEstimateTaxSource(value.sources.state),
|
|
194
|
+
local: value.sources.local === null || value.sources.local === undefined
|
|
195
|
+
? null
|
|
196
|
+
: readEstimateTaxSource(value.sources.local),
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Reads one US income tax calculation.
|
|
202
|
+
*
|
|
203
|
+
* One keyless request answers the federal, state, and local layers together.
|
|
204
|
+
* Every layer carries the official document its figures came from.
|
|
205
|
+
*
|
|
206
|
+
* @param options - the calculation query and an optional fetch stub
|
|
207
|
+
* @returns the calculation in the adapter's shape
|
|
208
|
+
*/
|
|
209
|
+
export async function fetchEstimateTaxCalculation(options) {
|
|
210
|
+
const fetchImpl = options?.fetchImpl ?? globalThis.fetch;
|
|
211
|
+
const url = buildEstimateTaxUrl(options?.query ?? ESTIMATETAX_DEFAULT_QUERY);
|
|
212
|
+
const response = await httpGet(ESTIMATETAX_INCOME_TAX_SOURCE_ID, url, { fetchImpl });
|
|
213
|
+
return parseEstimateTaxCalculation(await response.json());
|
|
214
|
+
}
|
|
215
|
+
/** EstimateTax US federal, state, and local income tax, keyless. */
|
|
216
|
+
export const estimatetaxIncomeTaxAdapter = {
|
|
217
|
+
id: ESTIMATETAX_INCOME_TAX_SOURCE_ID,
|
|
218
|
+
name: 'EstimateTax US income tax',
|
|
219
|
+
auth: 'none',
|
|
220
|
+
description: 'US federal, state, and local income tax for one salary, with the official document behind every figure.',
|
|
221
|
+
fetchLive: async (options) => fetchEstimateTaxCalculation(options?.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
|
|
222
|
+
parse: (payload) => parseEstimateTaxCalculation(payload),
|
|
223
|
+
loadFixture: () => parseEstimateTaxCalculation(readFixtureJson(ESTIMATETAX_FIXTURE_FILENAME)),
|
|
224
|
+
};
|
|
225
|
+
//# sourceMappingURL=estimatetaxIncomeTax.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"estimatetaxIncomeTax.js","sourceRoot":"","sources":["../src/estimatetaxIncomeTax.ts"],"names":[],"mappings":"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"}
|