@uk-open-data-connectors/uk-sources 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +206 -0
- package/dist/ancientWoodland.d.ts +102 -0
- package/dist/ancientWoodland.d.ts.map +1 -0
- package/dist/ancientWoodland.js +245 -0
- package/dist/ancientWoodland.js.map +1 -0
- package/dist/bankRate.d.ts +107 -0
- package/dist/bankRate.d.ts.map +1 -0
- package/dist/bankRate.js +251 -0
- package/dist/bankRate.js.map +1 -0
- package/dist/carbonIntensity.d.ts +151 -0
- package/dist/carbonIntensity.d.ts.map +1 -0
- package/dist/carbonIntensity.js +257 -0
- package/dist/carbonIntensity.js.map +1 -0
- package/dist/errors.d.ts +15 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +26 -0
- package/dist/errors.js.map +1 -0
- package/dist/fixtures.d.ts +5 -0
- package/dist/fixtures.d.ts.map +1 -0
- package/dist/fixtures.js +11 -0
- package/dist/fixtures.js.map +1 -0
- package/dist/floodMonitoring.d.ts +70 -0
- package/dist/floodMonitoring.d.ts.map +1 -0
- package/dist/floodMonitoring.js +164 -0
- package/dist/floodMonitoring.js.map +1 -0
- package/dist/foodHygiene.d.ts +68 -0
- package/dist/foodHygiene.d.ts.map +1 -0
- package/dist/foodHygiene.js +103 -0
- package/dist/foodHygiene.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/onsDatasets.d.ts +67 -0
- package/dist/onsDatasets.d.ts.map +1 -0
- package/dist/onsDatasets.js +111 -0
- package/dist/onsDatasets.js.map +1 -0
- package/dist/parliamentSeats.d.ts +115 -0
- package/dist/parliamentSeats.d.ts.map +1 -0
- package/dist/parliamentSeats.js +202 -0
- package/dist/parliamentSeats.js.map +1 -0
- package/dist/planningDatasets.d.ts +65 -0
- package/dist/planningDatasets.d.ts.map +1 -0
- package/dist/planningDatasets.js +100 -0
- package/dist/planningDatasets.js.map +1 -0
- package/dist/policeCrimes.d.ts +152 -0
- package/dist/policeCrimes.d.ts.map +1 -0
- package/dist/policeCrimes.js +262 -0
- package/dist/policeCrimes.js.map +1 -0
- package/dist/registry.d.ts +17 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +67 -0
- package/dist/registry.js.map +1 -0
- package/dist/tflBikePoints.d.ts +65 -0
- package/dist/tflBikePoints.d.ts.map +1 -0
- package/dist/tflBikePoints.js +149 -0
- package/dist/tflBikePoints.js.map +1 -0
- package/dist/types.d.ts +30 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { UkSourceApiError, UkSourceParseError } from './errors.js';
|
|
3
|
+
import { readFixtureJson } from './fixtures.js';
|
|
4
|
+
/**
|
|
5
|
+
* Half-hourly carbon intensity for Great Britain's electricity grid, from the
|
|
6
|
+
* National Energy System Operator's Carbon Intensity API. Every call answers
|
|
7
|
+
* without a key, and the API's own terms place the data under the Creative
|
|
8
|
+
* Commons Attribution 4.0 licence: <https://carbonintensity.org.uk/>
|
|
9
|
+
*/
|
|
10
|
+
export const CARBON_INTENSITY_SOURCE_ID = 'carbon-intensity';
|
|
11
|
+
/** Root every call here is built from. */
|
|
12
|
+
export const CARBON_INTENSITY_API_BASE_URL = 'https://api.carbonintensity.org.uk';
|
|
13
|
+
/** Half-hourly readings between two instants. */
|
|
14
|
+
export const CARBON_INTENSITY_RANGE_URL = `${CARBON_INTENSITY_API_BASE_URL}/intensity`;
|
|
15
|
+
/**
|
|
16
|
+
* The API refuses a range longer than 31 days ("The date range you have
|
|
17
|
+
* specified is greater than 31 days"). The window stays a day inside that.
|
|
18
|
+
*/
|
|
19
|
+
export const CARBON_INTENSITY_MAX_WINDOW_DAYS = 30;
|
|
20
|
+
/** How many complete days the default window covers. */
|
|
21
|
+
export const DEFAULT_CARBON_INTENSITY_WINDOW_DAYS = 30;
|
|
22
|
+
/** How long one reading covers. */
|
|
23
|
+
export const CARBON_INTENSITY_PERIOD_MINUTES = 30;
|
|
24
|
+
/** Milliseconds in a day, for turning a window length into an instant. */
|
|
25
|
+
const MILLISECONDS_PER_DAY = 86_400_000;
|
|
26
|
+
/** Milliseconds in the half hour one reading covers. */
|
|
27
|
+
const MILLISECONDS_PER_PERIOD = CARBON_INTENSITY_PERIOD_MINUTES * 60 * 1000;
|
|
28
|
+
/** Half-hour readings in a whole day. */
|
|
29
|
+
const PERIODS_PER_DAY = (24 * 60) / CARBON_INTENSITY_PERIOD_MINUTES;
|
|
30
|
+
/**
|
|
31
|
+
* The grades the API puts each half hour in, lowest intensity first. They are
|
|
32
|
+
* the operator's own words: "The index is a measure of the Carbon Intensity
|
|
33
|
+
* represented on a scale between 'very low', 'low', 'moderate', 'high', 'very
|
|
34
|
+
* high'."
|
|
35
|
+
*/
|
|
36
|
+
export const CARBON_INTENSITY_INDEX_BANDS = [
|
|
37
|
+
'very low',
|
|
38
|
+
'low',
|
|
39
|
+
'moderate',
|
|
40
|
+
'high',
|
|
41
|
+
'very high',
|
|
42
|
+
];
|
|
43
|
+
const CARBON_INTENSITY_RESPONSE_SCHEMA = z.object({
|
|
44
|
+
data: z.array(z.object({
|
|
45
|
+
from: z.string(),
|
|
46
|
+
to: z.string(),
|
|
47
|
+
intensity: z.object({
|
|
48
|
+
forecast: z.number().nullable(),
|
|
49
|
+
actual: z.number().nullable(),
|
|
50
|
+
index: z.string(),
|
|
51
|
+
}),
|
|
52
|
+
})),
|
|
53
|
+
});
|
|
54
|
+
const CARBON_INTENSITY_INSTANT_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}Z$/;
|
|
55
|
+
/** Milliseconds for an ISO instant, or NaN when the string is not one. */
|
|
56
|
+
function instantMilliseconds(instant) {
|
|
57
|
+
return CARBON_INTENSITY_INSTANT_PATTERN.test(instant) ? Date.parse(instant) : Number.NaN;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Writes a Date as the ISO instant the API takes in its path, e.g.
|
|
61
|
+
* `2026-08-30T00:00Z`.
|
|
62
|
+
*
|
|
63
|
+
* @param date - the instant to write
|
|
64
|
+
* @returns the instant as `YYYY-MM-DDThh:mmZ`
|
|
65
|
+
*/
|
|
66
|
+
export function formatCarbonIntensityInstant(date) {
|
|
67
|
+
return `${date.toISOString().slice(0, 16)}Z`;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Works out the window a build reads: whole UTC days, ending at the start of
|
|
71
|
+
* today, so every reading in it is settled rather than a forecast.
|
|
72
|
+
*
|
|
73
|
+
* @param options - how many days, and the clock to measure back from
|
|
74
|
+
* @returns the window's start and end as ISO instants
|
|
75
|
+
*/
|
|
76
|
+
export function resolveCarbonIntensityWindow(options = {}) {
|
|
77
|
+
const windowDays = options.windowDays ?? DEFAULT_CARBON_INTENSITY_WINDOW_DAYS;
|
|
78
|
+
if (!Number.isInteger(windowDays) || windowDays < 1) {
|
|
79
|
+
throw new UkSourceParseError(CARBON_INTENSITY_SOURCE_ID, `a window of ${String(windowDays)} days is not a whole number of days`);
|
|
80
|
+
}
|
|
81
|
+
if (windowDays > CARBON_INTENSITY_MAX_WINDOW_DAYS) {
|
|
82
|
+
throw new UkSourceParseError(CARBON_INTENSITY_SOURCE_ID, `the API refuses a range longer than ${String(CARBON_INTENSITY_MAX_WINDOW_DAYS)} days`);
|
|
83
|
+
}
|
|
84
|
+
const now = options.now ?? new Date();
|
|
85
|
+
const to = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
|
86
|
+
const from = new Date(to.getTime() - windowDays * MILLISECONDS_PER_DAY);
|
|
87
|
+
return { from: formatCarbonIntensityInstant(from), to: formatCarbonIntensityInstant(to) };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Checks a window a caller passed in rather than one the adapter worked out.
|
|
91
|
+
*
|
|
92
|
+
* The API refuses a range longer than 31 days and answers in half hours, so a
|
|
93
|
+
* window that is not a whole number of half hours, or that runs past the
|
|
94
|
+
* limit, throws here rather than at the API.
|
|
95
|
+
*
|
|
96
|
+
* @param window - the start and end a caller asked for
|
|
97
|
+
* @returns the same window, once it has been checked
|
|
98
|
+
*/
|
|
99
|
+
export function validateCarbonIntensityWindow(window) {
|
|
100
|
+
const { from, to } = window;
|
|
101
|
+
if (from === undefined || to === undefined) {
|
|
102
|
+
throw new UkSourceParseError(CARBON_INTENSITY_SOURCE_ID, 'a window needs both a start and an end');
|
|
103
|
+
}
|
|
104
|
+
const fromMilliseconds = instantMilliseconds(from);
|
|
105
|
+
const toMilliseconds = instantMilliseconds(to);
|
|
106
|
+
if (Number.isNaN(fromMilliseconds) || Number.isNaN(toMilliseconds)) {
|
|
107
|
+
throw new UkSourceParseError(CARBON_INTENSITY_SOURCE_ID, `expected instants as YYYY-MM-DDThh:mmZ, got ${from} and ${to}`);
|
|
108
|
+
}
|
|
109
|
+
const span = toMilliseconds - fromMilliseconds;
|
|
110
|
+
if (span <= 0) {
|
|
111
|
+
throw new UkSourceParseError(CARBON_INTENSITY_SOURCE_ID, `the window ends at ${to}, before it starts at ${from}`);
|
|
112
|
+
}
|
|
113
|
+
if (span % MILLISECONDS_PER_PERIOD !== 0) {
|
|
114
|
+
throw new UkSourceParseError(CARBON_INTENSITY_SOURCE_ID, `the window ${from} to ${to} is not a whole number of half hours`);
|
|
115
|
+
}
|
|
116
|
+
if (span > CARBON_INTENSITY_MAX_WINDOW_DAYS * MILLISECONDS_PER_DAY) {
|
|
117
|
+
throw new UkSourceParseError(CARBON_INTENSITY_SOURCE_ID, `the API refuses a range longer than ${String(CARBON_INTENSITY_MAX_WINDOW_DAYS)} days`);
|
|
118
|
+
}
|
|
119
|
+
return { from, to };
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Builds the URL for one window of half-hourly readings.
|
|
123
|
+
*
|
|
124
|
+
* @param window - the start and end of the window, as ISO instants
|
|
125
|
+
* @returns the full range URL
|
|
126
|
+
*/
|
|
127
|
+
export function buildCarbonIntensityWindowUrl(window) {
|
|
128
|
+
return `${CARBON_INTENSITY_RANGE_URL}/${window.from}/${window.to}`;
|
|
129
|
+
}
|
|
130
|
+
/** Counts the half hours the window holds at each grade, lowest grade first. */
|
|
131
|
+
function countByBand(periods) {
|
|
132
|
+
return CARBON_INTENSITY_INDEX_BANDS.map((index) => ({
|
|
133
|
+
index,
|
|
134
|
+
periodCount: periods.filter((period) => period.index === index).length,
|
|
135
|
+
}));
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Parses a range response into the readings the page draws.
|
|
139
|
+
*
|
|
140
|
+
* Every check here is one the page would otherwise show as a wrong number: a
|
|
141
|
+
* half hour with no settled reading, a period that does not run for half an
|
|
142
|
+
* hour, an instant that does not move forwards, or a grade the API's own band
|
|
143
|
+
* list does not carry all throw rather than quietly changing the counts.
|
|
144
|
+
*
|
|
145
|
+
* @param payload - the range response, or the committed fixture of one
|
|
146
|
+
* @returns every reading in the window, oldest first, with its totals
|
|
147
|
+
*/
|
|
148
|
+
export function parseCarbonIntensityWindow(payload) {
|
|
149
|
+
const parsed = CARBON_INTENSITY_RESPONSE_SCHEMA.safeParse(payload);
|
|
150
|
+
if (!parsed.success) {
|
|
151
|
+
throw new UkSourceParseError(CARBON_INTENSITY_SOURCE_ID, parsed.error.message);
|
|
152
|
+
}
|
|
153
|
+
const responses = parsed.data.data;
|
|
154
|
+
if (responses.length === 0) {
|
|
155
|
+
throw new UkSourceParseError(CARBON_INTENSITY_SOURCE_ID, 'the window returned no readings');
|
|
156
|
+
}
|
|
157
|
+
const bands = new Set(CARBON_INTENSITY_INDEX_BANDS);
|
|
158
|
+
let previousFrom = Number.NEGATIVE_INFINITY;
|
|
159
|
+
const periods = responses.map((response) => {
|
|
160
|
+
const from = instantMilliseconds(response.from);
|
|
161
|
+
const to = instantMilliseconds(response.to);
|
|
162
|
+
if (Number.isNaN(from) || Number.isNaN(to)) {
|
|
163
|
+
throw new UkSourceParseError(CARBON_INTENSITY_SOURCE_ID, `expected an instant as YYYY-MM-DDThh:mmZ, got ${JSON.stringify(response.from)}`);
|
|
164
|
+
}
|
|
165
|
+
if (to - from !== MILLISECONDS_PER_PERIOD) {
|
|
166
|
+
throw new UkSourceParseError(CARBON_INTENSITY_SOURCE_ID, `the half hour starting ${response.from} runs for ${String((to - from) / 60_000)} minutes`);
|
|
167
|
+
}
|
|
168
|
+
if (from <= previousFrom) {
|
|
169
|
+
throw new UkSourceParseError(CARBON_INTENSITY_SOURCE_ID, `the readings do not move forwards at ${response.from}`);
|
|
170
|
+
}
|
|
171
|
+
previousFrom = from;
|
|
172
|
+
if (response.intensity.actual === null) {
|
|
173
|
+
throw new UkSourceParseError(CARBON_INTENSITY_SOURCE_ID, `the half hour starting ${response.from} carries no settled reading`);
|
|
174
|
+
}
|
|
175
|
+
if (!bands.has(response.intensity.index)) {
|
|
176
|
+
throw new UkSourceParseError(CARBON_INTENSITY_SOURCE_ID, `unrecognised intensity grade ${JSON.stringify(response.intensity.index)}`);
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
from: response.from,
|
|
180
|
+
to: response.to,
|
|
181
|
+
intensity: response.intensity.actual,
|
|
182
|
+
index: response.intensity.index,
|
|
183
|
+
};
|
|
184
|
+
});
|
|
185
|
+
const total = periods.reduce((sum, period) => sum + period.intensity, 0);
|
|
186
|
+
const lowestPeriod = periods.reduce((lowest, period) => period.intensity < lowest.intensity ? period : lowest);
|
|
187
|
+
const highestPeriod = periods.reduce((highest, period) => period.intensity > highest.intensity ? period : highest);
|
|
188
|
+
const firstPeriod = periods[0];
|
|
189
|
+
const lastPeriod = periods.at(-1);
|
|
190
|
+
if (firstPeriod === undefined || lastPeriod === undefined) {
|
|
191
|
+
throw new UkSourceParseError(CARBON_INTENSITY_SOURCE_ID, 'the window holds no readings');
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
periodCount: periods.length,
|
|
195
|
+
dayCount: Math.floor(periods.length / PERIODS_PER_DAY),
|
|
196
|
+
firstPeriodFrom: firstPeriod.from,
|
|
197
|
+
lastPeriodTo: lastPeriod.to,
|
|
198
|
+
averageIntensity: Math.round(total / periods.length),
|
|
199
|
+
lowestPeriod,
|
|
200
|
+
highestPeriod,
|
|
201
|
+
bandCounts: countByBand(periods),
|
|
202
|
+
periods,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
/** One window of half-hourly readings, or a throw naming what failed. */
|
|
206
|
+
async function fetchCarbonIntensityPayload(options) {
|
|
207
|
+
const url = buildCarbonIntensityWindowUrl({ from: options.from, to: options.to });
|
|
208
|
+
const response = await options.fetchImpl(url, { headers: { accept: 'application/json' } });
|
|
209
|
+
if (!response.ok) {
|
|
210
|
+
throw new UkSourceApiError(CARBON_INTENSITY_SOURCE_ID, `HTTP ${response.status} from ${url}`);
|
|
211
|
+
}
|
|
212
|
+
return response.json();
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Reads a window of half-hourly carbon intensity.
|
|
216
|
+
*
|
|
217
|
+
* The range endpoint also returns the half hour that ends at the window's
|
|
218
|
+
* start, so the first response is dropped: without that, the window is a half
|
|
219
|
+
* hour longer than the whole days it claims to cover.
|
|
220
|
+
*
|
|
221
|
+
* A caller can also pass the window's own start and end, which is how a page
|
|
222
|
+
* aligns the window to whole days in its own time zone rather than to UTC.
|
|
223
|
+
*
|
|
224
|
+
* @param options - how many days, or an explicit window, and an optional fetch implementation
|
|
225
|
+
* @returns every reading in the window, oldest first, with its totals
|
|
226
|
+
*/
|
|
227
|
+
export async function fetchCarbonIntensityWindow(options = {}) {
|
|
228
|
+
const { from, to } = options.from === undefined && options.to === undefined
|
|
229
|
+
? resolveCarbonIntensityWindow(options)
|
|
230
|
+
: validateCarbonIntensityWindow({ from: options.from, to: options.to });
|
|
231
|
+
const payload = await fetchCarbonIntensityPayload({
|
|
232
|
+
from,
|
|
233
|
+
to,
|
|
234
|
+
fetchImpl: options.fetchImpl ?? globalThis.fetch,
|
|
235
|
+
});
|
|
236
|
+
const parsed = CARBON_INTENSITY_RESPONSE_SCHEMA.safeParse(payload);
|
|
237
|
+
if (!parsed.success) {
|
|
238
|
+
throw new UkSourceParseError(CARBON_INTENSITY_SOURCE_ID, parsed.error.message);
|
|
239
|
+
}
|
|
240
|
+
const windowStart = Date.parse(from);
|
|
241
|
+
return parseCarbonIntensityWindow({
|
|
242
|
+
data: parsed.data.data.filter((response) => instantMilliseconds(response.from) >= windowStart),
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
/** National Energy System Operator half-hourly carbon intensity, keyless. */
|
|
246
|
+
export const carbonIntensityAdapter = {
|
|
247
|
+
id: CARBON_INTENSITY_SOURCE_ID,
|
|
248
|
+
name: 'National Energy System Operator carbon intensity',
|
|
249
|
+
auth: 'none',
|
|
250
|
+
description: 'Half-hourly carbon intensity for Great Britain, with the cleanest and dirtiest half hours in the window.',
|
|
251
|
+
fetchLive: (options) => fetchCarbonIntensityWindow({
|
|
252
|
+
...(options?.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
|
|
253
|
+
}),
|
|
254
|
+
parse: parseCarbonIntensityWindow,
|
|
255
|
+
loadFixture: () => parseCarbonIntensityWindow(readFixtureJson('carbon-intensity.json')),
|
|
256
|
+
};
|
|
257
|
+
//# sourceMappingURL=carbonIntensity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"carbonIntensity.js","sourceRoot":"","sources":["../src/carbonIntensity.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Base error for any UK data source client in this package. */
|
|
2
|
+
export declare class UkSourceError extends Error {
|
|
3
|
+
constructor(message: string, options?: ErrorOptions);
|
|
4
|
+
}
|
|
5
|
+
/** The remote API rejected the request (HTTP error or bad payload). */
|
|
6
|
+
export declare class UkSourceApiError extends UkSourceError {
|
|
7
|
+
readonly source: string;
|
|
8
|
+
constructor(source: string, message: string, options?: ErrorOptions);
|
|
9
|
+
}
|
|
10
|
+
/** The remote payload did not match the expected shape. */
|
|
11
|
+
export declare class UkSourceParseError extends UkSourceError {
|
|
12
|
+
readonly source: string;
|
|
13
|
+
constructor(source: string, message: string, options?: ErrorOptions);
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,qBAAa,aAAc,SAAQ,KAAK;gBAC1B,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;CAIpD;AAED,uEAAuE;AACvE,qBAAa,gBAAiB,SAAQ,aAAa;aAE/B,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM,EAC9B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,YAAY;CAKzB;AAED,2DAA2D;AAC3D,qBAAa,kBAAmB,SAAQ,aAAa;aAEjC,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM,EAC9B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,YAAY;CAKzB"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Base error for any UK data source client in this package. */
|
|
2
|
+
export class UkSourceError extends Error {
|
|
3
|
+
constructor(message, options) {
|
|
4
|
+
super(message, options);
|
|
5
|
+
this.name = 'UkSourceError';
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/** The remote API rejected the request (HTTP error or bad payload). */
|
|
9
|
+
export class UkSourceApiError extends UkSourceError {
|
|
10
|
+
source;
|
|
11
|
+
constructor(source, message, options) {
|
|
12
|
+
super(`${source}: ${message}`, options);
|
|
13
|
+
this.source = source;
|
|
14
|
+
this.name = 'UkSourceApiError';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/** The remote payload did not match the expected shape. */
|
|
18
|
+
export class UkSourceParseError extends UkSourceError {
|
|
19
|
+
source;
|
|
20
|
+
constructor(source, message, options) {
|
|
21
|
+
super(`${source}: ${message}`, options);
|
|
22
|
+
this.source = source;
|
|
23
|
+
this.name = 'UkSourceParseError';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +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;AAED,uEAAuE;AACvE,MAAM,OAAO,gBAAiB,SAAQ,aAAa;IAE/B;IADlB,YACkB,MAAc,EAC9B,OAAe,EACf,OAAsB;QAEtB,KAAK,CAAC,GAAG,MAAM,KAAK,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;QAJxB,WAAM,GAAN,MAAM,CAAQ;QAK9B,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAED,2DAA2D;AAC3D,MAAM,OAAO,kBAAmB,SAAQ,aAAa;IAEjC;IADlB,YACkB,MAAc,EAC9B,OAAe,EACf,OAAsB;QAEtB,KAAK,CAAC,GAAG,MAAM,KAAK,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;QAJxB,WAAM,GAAN,MAAM,CAAQ;QAK9B,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Reads a committed fixture from src/fixtures as parsed JSON. */
|
|
2
|
+
export declare function readFixtureJson(filename: string): unknown;
|
|
3
|
+
/** Reads a committed fixture from src/fixtures as raw text. */
|
|
4
|
+
export declare function readFixtureText(filename: string): string;
|
|
5
|
+
//# sourceMappingURL=fixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../src/fixtures.ts"],"names":[],"mappings":"AAGA,kEAAkE;AAClE,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,+DAA+D;AAC/D,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAExD"}
|
package/dist/fixtures.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
/** Reads a committed fixture from src/fixtures as parsed JSON. */
|
|
4
|
+
export function readFixtureJson(filename) {
|
|
5
|
+
return JSON.parse(readFileSync(path.join(process.cwd(), 'src/fixtures', filename), 'utf8'));
|
|
6
|
+
}
|
|
7
|
+
/** Reads a committed fixture from src/fixtures as raw text. */
|
|
8
|
+
export function readFixtureText(filename) {
|
|
9
|
+
return readFileSync(path.join(process.cwd(), 'src/fixtures', filename), 'utf8');
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=fixtures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixtures.js","sourceRoot":"","sources":["../src/fixtures.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,kEAAkE;AAClE,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAC9F,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC;AAClF,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { UkDataAdapter } from './types.js';
|
|
2
|
+
/** One measure a station publishes, such as water level at 15 minute steps. */
|
|
3
|
+
export interface FloodMeasure {
|
|
4
|
+
id: string;
|
|
5
|
+
parameter: string;
|
|
6
|
+
parameterName: string;
|
|
7
|
+
qualifier: string;
|
|
8
|
+
unitName: string;
|
|
9
|
+
periodSeconds: number;
|
|
10
|
+
}
|
|
11
|
+
/** One monitoring station in the Environment Agency network. */
|
|
12
|
+
export interface FloodStation {
|
|
13
|
+
id: string;
|
|
14
|
+
notation: string;
|
|
15
|
+
label: string;
|
|
16
|
+
riverName: string;
|
|
17
|
+
catchmentName: string;
|
|
18
|
+
/** Null for the handful of groundwater stations that publish no coordinates. */
|
|
19
|
+
latitude: number | null;
|
|
20
|
+
/** Null for the handful of groundwater stations that publish no coordinates. */
|
|
21
|
+
longitude: number | null;
|
|
22
|
+
measures: FloodMeasure[];
|
|
23
|
+
}
|
|
24
|
+
/** One reading from a station measure. */
|
|
25
|
+
export interface FloodReading {
|
|
26
|
+
measureId: string;
|
|
27
|
+
dateTime: string;
|
|
28
|
+
value: number;
|
|
29
|
+
}
|
|
30
|
+
/** Rolled-up facts about a run of readings. */
|
|
31
|
+
export interface FloodReadingSummary {
|
|
32
|
+
count: number;
|
|
33
|
+
latest: FloodReading | undefined;
|
|
34
|
+
earliest: FloodReading | undefined;
|
|
35
|
+
minValue: number | undefined;
|
|
36
|
+
maxValue: number | undefined;
|
|
37
|
+
trend: 'rising' | 'falling' | 'steady' | 'unknown';
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Station the readings adapter probes by default: Bourton Dickler on the
|
|
41
|
+
* River Dikler, which publishes level readings every 15 minutes.
|
|
42
|
+
*/
|
|
43
|
+
export declare const DEFAULT_FLOOD_STATION_REFERENCE = "1029TH";
|
|
44
|
+
/** Parses an Environment Agency /id/stations payload into stations. */
|
|
45
|
+
export declare function parseFloodStations(payload: unknown): FloodStation[];
|
|
46
|
+
/** Parses an Environment Agency /readings payload into readings. */
|
|
47
|
+
export declare function parseFloodReadings(payload: unknown): FloodReading[];
|
|
48
|
+
/** Summarizes a run of readings: count, ends, range, and direction. */
|
|
49
|
+
export declare function summarizeFloodReadings(readings: FloodReading[]): FloodReadingSummary;
|
|
50
|
+
/**
|
|
51
|
+
* Lists monitoring stations from the Environment Agency flood-monitoring
|
|
52
|
+
* API. Keyless, Open Government Licence v3.
|
|
53
|
+
*/
|
|
54
|
+
export declare function fetchFloodStations(options?: {
|
|
55
|
+
limit?: number;
|
|
56
|
+
fetchImpl?: typeof globalThis.fetch;
|
|
57
|
+
}): Promise<FloodStation[]>;
|
|
58
|
+
/**
|
|
59
|
+
* Reads the most recent readings for one station. `_sorted` returns the
|
|
60
|
+
* newest first, so the first item is the current level.
|
|
61
|
+
*/
|
|
62
|
+
export declare function fetchFloodStationReadings(stationReference?: string, options?: {
|
|
63
|
+
limit?: number;
|
|
64
|
+
fetchImpl?: typeof globalThis.fetch;
|
|
65
|
+
}): Promise<FloodReading[]>;
|
|
66
|
+
/** Flood-monitoring station list adapter, keyless. */
|
|
67
|
+
export declare const floodStationsAdapter: UkDataAdapter<FloodStation[]>;
|
|
68
|
+
/** Flood-monitoring readings adapter for the default station, keyless. */
|
|
69
|
+
export declare const floodReadingsAdapter: UkDataAdapter<FloodReading[]>;
|
|
70
|
+
//# sourceMappingURL=floodMonitoring.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"floodMonitoring.d.ts","sourceRoot":"","sources":["../src/floodMonitoring.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,+EAA+E;AAC/E,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,gEAAgE;AAChE,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,gFAAgF;IAChF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,gFAAgF;IAChF,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B;AAED,0CAA0C;AAC1C,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,+CAA+C;AAC/C,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,YAAY,GAAG,SAAS,CAAC;IACjC,QAAQ,EAAE,YAAY,GAAG,SAAS,CAAC;IACnC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;CACpD;AAED;;;GAGG;AACH,eAAO,MAAM,+BAA+B,WAAW,CAAC;AAoDxD,uEAAuE;AACvE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,YAAY,EAAE,CAsBnE;AAED,oEAAoE;AACpE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,YAAY,EAAE,CAUnE;AAED,uEAAuE;AACvE,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,mBAAmB,CA8BpF;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CAAO,GACpE,OAAO,CAAC,YAAY,EAAE,CAAC,CASzB;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,CAC7C,gBAAgB,GAAE,MAAwC,EAC1D,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CAAO,GACpE,OAAO,CAAC,YAAY,EAAE,CAAC,CAUzB;AAED,sDAAsD;AACtD,eAAO,MAAM,oBAAoB,EAAE,aAAa,CAAC,YAAY,EAAE,CAS9D,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,oBAAoB,EAAE,aAAa,CAAC,YAAY,EAAE,CAY9D,CAAC"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { UkSourceApiError, UkSourceParseError } from './errors.js';
|
|
3
|
+
import { readFixtureJson } from './fixtures.js';
|
|
4
|
+
/**
|
|
5
|
+
* Station the readings adapter probes by default: Bourton Dickler on the
|
|
6
|
+
* River Dikler, which publishes level readings every 15 minutes.
|
|
7
|
+
*/
|
|
8
|
+
export const DEFAULT_FLOOD_STATION_REFERENCE = '1029TH';
|
|
9
|
+
/** How close two readings must be to count as steady, in metres. */
|
|
10
|
+
const STEADY_LEVEL_TOLERANCE_METRES = 0.01;
|
|
11
|
+
const FLOOD_MEASURE_SCHEMA = z.object({
|
|
12
|
+
'@id': z.string(),
|
|
13
|
+
parameter: z.string(),
|
|
14
|
+
parameterName: z.string(),
|
|
15
|
+
qualifier: z.string(),
|
|
16
|
+
unitName: z.string(),
|
|
17
|
+
period: z.number().optional(),
|
|
18
|
+
});
|
|
19
|
+
// The agency returns a bare string for most fields but wraps a few in an
|
|
20
|
+
// array, so both shapes have to be accepted.
|
|
21
|
+
const FLOOD_TEXT_SCHEMA = z.union([z.string(), z.array(z.string())]);
|
|
22
|
+
const FLOOD_STATION_SCHEMA = z.object({
|
|
23
|
+
'@id': z.string(),
|
|
24
|
+
notation: z.string(),
|
|
25
|
+
label: FLOOD_TEXT_SCHEMA,
|
|
26
|
+
riverName: FLOOD_TEXT_SCHEMA.optional(),
|
|
27
|
+
catchmentName: FLOOD_TEXT_SCHEMA.optional(),
|
|
28
|
+
lat: z.number().optional(),
|
|
29
|
+
long: z.number().optional(),
|
|
30
|
+
measures: z.array(FLOOD_MEASURE_SCHEMA).optional(),
|
|
31
|
+
});
|
|
32
|
+
/** Flattens a field that the agency publishes as a string or an array. */
|
|
33
|
+
function readFloodText(value) {
|
|
34
|
+
if (value === undefined) {
|
|
35
|
+
return '';
|
|
36
|
+
}
|
|
37
|
+
return Array.isArray(value) ? value.join(' / ') : value;
|
|
38
|
+
}
|
|
39
|
+
const FLOOD_STATIONS_RESPONSE_SCHEMA = z.object({
|
|
40
|
+
items: z.array(FLOOD_STATION_SCHEMA),
|
|
41
|
+
});
|
|
42
|
+
const FLOOD_READING_SCHEMA = z.object({
|
|
43
|
+
'@id': z.string(),
|
|
44
|
+
dateTime: z.string(),
|
|
45
|
+
measure: z.string(),
|
|
46
|
+
value: z.number(),
|
|
47
|
+
});
|
|
48
|
+
const FLOOD_READINGS_RESPONSE_SCHEMA = z.object({
|
|
49
|
+
items: z.array(FLOOD_READING_SCHEMA),
|
|
50
|
+
});
|
|
51
|
+
/** Parses an Environment Agency /id/stations payload into stations. */
|
|
52
|
+
export function parseFloodStations(payload) {
|
|
53
|
+
const parsed = FLOOD_STATIONS_RESPONSE_SCHEMA.safeParse(payload);
|
|
54
|
+
if (!parsed.success) {
|
|
55
|
+
throw new UkSourceParseError('flood-monitoring', parsed.error.message);
|
|
56
|
+
}
|
|
57
|
+
return parsed.data.items.map((station) => ({
|
|
58
|
+
id: station['@id'],
|
|
59
|
+
notation: station.notation,
|
|
60
|
+
label: readFloodText(station.label),
|
|
61
|
+
riverName: readFloodText(station.riverName),
|
|
62
|
+
catchmentName: readFloodText(station.catchmentName),
|
|
63
|
+
latitude: station.lat ?? null,
|
|
64
|
+
longitude: station.long ?? null,
|
|
65
|
+
measures: (station.measures ?? []).map((measure) => ({
|
|
66
|
+
id: measure['@id'],
|
|
67
|
+
parameter: measure.parameter,
|
|
68
|
+
parameterName: measure.parameterName,
|
|
69
|
+
qualifier: measure.qualifier,
|
|
70
|
+
unitName: measure.unitName,
|
|
71
|
+
periodSeconds: measure.period ?? 0,
|
|
72
|
+
})),
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
/** Parses an Environment Agency /readings payload into readings. */
|
|
76
|
+
export function parseFloodReadings(payload) {
|
|
77
|
+
const parsed = FLOOD_READINGS_RESPONSE_SCHEMA.safeParse(payload);
|
|
78
|
+
if (!parsed.success) {
|
|
79
|
+
throw new UkSourceParseError('flood-monitoring', parsed.error.message);
|
|
80
|
+
}
|
|
81
|
+
return parsed.data.items.map((reading) => ({
|
|
82
|
+
measureId: reading.measure,
|
|
83
|
+
dateTime: reading.dateTime,
|
|
84
|
+
value: reading.value,
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
/** Summarizes a run of readings: count, ends, range, and direction. */
|
|
88
|
+
export function summarizeFloodReadings(readings) {
|
|
89
|
+
if (readings.length === 0) {
|
|
90
|
+
return {
|
|
91
|
+
count: 0,
|
|
92
|
+
latest: undefined,
|
|
93
|
+
earliest: undefined,
|
|
94
|
+
minValue: undefined,
|
|
95
|
+
maxValue: undefined,
|
|
96
|
+
trend: 'unknown',
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
const ordered = [...readings].sort((left, right) => left.dateTime.localeCompare(right.dateTime));
|
|
100
|
+
const first = ordered[0];
|
|
101
|
+
const last = ordered[ordered.length - 1];
|
|
102
|
+
const values = ordered.map((reading) => reading.value);
|
|
103
|
+
const movement = last !== undefined && first !== undefined ? last.value - first.value : 0;
|
|
104
|
+
const trend = Math.abs(movement) <= STEADY_LEVEL_TOLERANCE_METRES
|
|
105
|
+
? 'steady'
|
|
106
|
+
: movement > 0
|
|
107
|
+
? 'rising'
|
|
108
|
+
: 'falling';
|
|
109
|
+
return {
|
|
110
|
+
count: ordered.length,
|
|
111
|
+
latest: last,
|
|
112
|
+
earliest: first,
|
|
113
|
+
minValue: Math.min(...values),
|
|
114
|
+
maxValue: Math.max(...values),
|
|
115
|
+
trend,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Lists monitoring stations from the Environment Agency flood-monitoring
|
|
120
|
+
* API. Keyless, Open Government Licence v3.
|
|
121
|
+
*/
|
|
122
|
+
export async function fetchFloodStations(options = {}) {
|
|
123
|
+
const { limit = 25, fetchImpl = globalThis.fetch } = options;
|
|
124
|
+
const response = await fetchImpl(`https://environment.data.gov.uk/flood-monitoring/id/stations?_limit=${limit}`);
|
|
125
|
+
if (!response.ok) {
|
|
126
|
+
throw new UkSourceApiError('flood-monitoring', `HTTP ${response.status} listing stations`);
|
|
127
|
+
}
|
|
128
|
+
return parseFloodStations(await response.json());
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Reads the most recent readings for one station. `_sorted` returns the
|
|
132
|
+
* newest first, so the first item is the current level.
|
|
133
|
+
*/
|
|
134
|
+
export async function fetchFloodStationReadings(stationReference = DEFAULT_FLOOD_STATION_REFERENCE, options = {}) {
|
|
135
|
+
const { limit = 96, fetchImpl = globalThis.fetch } = options;
|
|
136
|
+
const url = `https://environment.data.gov.uk/flood-monitoring/id/stations/${stationReference}` +
|
|
137
|
+
`/readings?_limit=${limit}&_sorted`;
|
|
138
|
+
const response = await fetchImpl(url);
|
|
139
|
+
if (!response.ok) {
|
|
140
|
+
throw new UkSourceApiError('flood-monitoring', `HTTP ${response.status} reading station`);
|
|
141
|
+
}
|
|
142
|
+
return parseFloodReadings(await response.json());
|
|
143
|
+
}
|
|
144
|
+
/** Flood-monitoring station list adapter, keyless. */
|
|
145
|
+
export const floodStationsAdapter = {
|
|
146
|
+
id: 'flood-stations',
|
|
147
|
+
name: 'Environment Agency flood-monitoring stations',
|
|
148
|
+
auth: 'none',
|
|
149
|
+
description: 'Monitoring stations with their river, catchment, and published measures.',
|
|
150
|
+
fetchLive: (options) => fetchFloodStations(options?.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
|
|
151
|
+
parse: parseFloodStations,
|
|
152
|
+
loadFixture: () => parseFloodStations(readFixtureJson('flood-stations.json')),
|
|
153
|
+
};
|
|
154
|
+
/** Flood-monitoring readings adapter for the default station, keyless. */
|
|
155
|
+
export const floodReadingsAdapter = {
|
|
156
|
+
id: 'flood-readings',
|
|
157
|
+
name: 'Environment Agency flood-monitoring readings',
|
|
158
|
+
auth: 'none',
|
|
159
|
+
description: 'Recent water level readings for one station, newest first.',
|
|
160
|
+
fetchLive: (options) => fetchFloodStationReadings(DEFAULT_FLOOD_STATION_REFERENCE, options?.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
|
|
161
|
+
parse: parseFloodReadings,
|
|
162
|
+
loadFixture: () => parseFloodReadings(readFixtureJson('flood-station-readings.json')),
|
|
163
|
+
};
|
|
164
|
+
//# sourceMappingURL=floodMonitoring.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"floodMonitoring.js","sourceRoot":"","sources":["../src/floodMonitoring.ts"],"names":[],"mappings":"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"}
|