@uk-open-data-connectors/uk-sources 0.1.0 → 0.1.1
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 +21 -0
- package/dist/exploreEducationStatistics.d.ts +72 -0
- package/dist/exploreEducationStatistics.d.ts.map +1 -0
- package/dist/exploreEducationStatistics.js +110 -0
- package/dist/exploreEducationStatistics.js.map +1 -0
- package/dist/findATender.d.ts +76 -0
- package/dist/findATender.d.ts.map +1 -0
- package/dist/findATender.js +109 -0
- package/dist/findATender.js.map +1 -0
- package/dist/fingertipsIndicators.d.ts +67 -0
- package/dist/fingertipsIndicators.d.ts.map +1 -0
- package/dist/fingertipsIndicators.js +94 -0
- package/dist/fingertipsIndicators.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -1
- package/dist/londonDatastore.d.ts +46 -0
- package/dist/londonDatastore.d.ts.map +1 -0
- package/dist/londonDatastore.js +64 -0
- package/dist/londonDatastore.js.map +1 -0
- package/dist/nhsbsaCkan.d.ts +43 -0
- package/dist/nhsbsaCkan.d.ts.map +1 -0
- package/dist/nhsbsaCkan.js +61 -0
- package/dist/nhsbsaCkan.js.map +1 -0
- package/dist/nomis.d.ts +71 -0
- package/dist/nomis.d.ts.map +1 -0
- package/dist/nomis.js +126 -0
- package/dist/nomis.js.map +1 -0
- package/dist/postcodeLookup.d.ts +55 -0
- package/dist/postcodeLookup.d.ts.map +1 -0
- package/dist/postcodeLookup.js +89 -0
- package/dist/postcodeLookup.js.map +1 -0
- package/dist/publicHealthScotland.d.ts +43 -0
- package/dist/publicHealthScotland.d.ts.map +1 -0
- package/dist/publicHealthScotland.js +61 -0
- package/dist/publicHealthScotland.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/tflLineStatus.d.ts +59 -0
- package/dist/tflLineStatus.d.ts.map +1 -0
- package/dist/tflLineStatus.js +93 -0
- package/dist/tflLineStatus.js.map +1 -0
- package/dist/tnaDiscovery.d.ts +76 -0
- package/dist/tnaDiscovery.d.ts.map +1 -0
- package/dist/tnaDiscovery.js +101 -0
- package/dist/tnaDiscovery.js.map +1 -0
- package/dist/ukhsaDashboard.d.ts +92 -0
- package/dist/ukhsaDashboard.d.ts.map +1 -0
- package/dist/ukhsaDashboard.js +136 -0
- package/dist/ukhsaDashboard.js.map +1 -0
- package/package.json +11 -3
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { UkSourceApiError, UkSourceParseError } from './errors.js';
|
|
3
|
+
import { readFixtureJson } from './fixtures.js';
|
|
4
|
+
/**
|
|
5
|
+
* Discovery, The National Archives' catalogue search API. Keyless, and the
|
|
6
|
+
* catalogue metadata is published under the Open Government Licence v3.
|
|
7
|
+
*/
|
|
8
|
+
export const TNA_DISCOVERY_SOURCE_ID = 'tna-discovery';
|
|
9
|
+
/** Base URL for the Discovery record search. */
|
|
10
|
+
export const TNA_DISCOVERY_SEARCH_URL = 'https://discovery.nationalarchives.gov.uk/API/search/records';
|
|
11
|
+
/**
|
|
12
|
+
* The header Discovery expects for a JSON answer. On 2026-10-05 the endpoint
|
|
13
|
+
* also answered JSON without it, but the adapter sends it either way.
|
|
14
|
+
*/
|
|
15
|
+
export const TNA_DISCOVERY_ACCEPT_HEADER = 'application/json';
|
|
16
|
+
/** The search term the adapter asks for when the caller does not name one. */
|
|
17
|
+
export const DEFAULT_TNA_DISCOVERY_QUERY = 'test';
|
|
18
|
+
const TNA_DISCOVERY_RECORD_SCHEMA = z.object({
|
|
19
|
+
id: z.string(),
|
|
20
|
+
reference: z.string().nullable().optional(),
|
|
21
|
+
title: z.string().nullable().optional(),
|
|
22
|
+
description: z.string().nullable().optional(),
|
|
23
|
+
coveringDates: z.string().nullable().optional(),
|
|
24
|
+
catalogueLevel: z.number().nullable().optional(),
|
|
25
|
+
department: z.string().nullable().optional(),
|
|
26
|
+
heldBy: z.array(z.string()).nullable().optional(),
|
|
27
|
+
});
|
|
28
|
+
const TNA_DISCOVERY_SEARCH_SCHEMA = z.object({
|
|
29
|
+
records: z.array(TNA_DISCOVERY_RECORD_SCHEMA),
|
|
30
|
+
count: z.number(),
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* Builds a Discovery record search URL for one query.
|
|
34
|
+
*
|
|
35
|
+
* @param query - the free-text search term
|
|
36
|
+
* @returns the record search URL
|
|
37
|
+
*/
|
|
38
|
+
export function buildTnaDiscoverySearchUrl(query) {
|
|
39
|
+
return `${TNA_DISCOVERY_SEARCH_URL}?sps.searchQuery=${encodeURIComponent(query)}`;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Parses a Discovery record search payload.
|
|
43
|
+
*
|
|
44
|
+
* @param payload - the raw JSON body from the record search endpoint
|
|
45
|
+
* @returns the page of catalogue records plus the total hit count
|
|
46
|
+
*/
|
|
47
|
+
export function parseTnaDiscoveryRecords(payload) {
|
|
48
|
+
const parsed = TNA_DISCOVERY_SEARCH_SCHEMA.safeParse(payload);
|
|
49
|
+
if (!parsed.success) {
|
|
50
|
+
throw new UkSourceParseError('tna-discovery', parsed.error.message);
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
totalCount: parsed.data.count,
|
|
54
|
+
records: parsed.data.records.map((record) => ({
|
|
55
|
+
id: record.id,
|
|
56
|
+
reference: record.reference ?? '',
|
|
57
|
+
title: record.title ?? '',
|
|
58
|
+
description: record.description ?? '',
|
|
59
|
+
coveringDates: record.coveringDates ?? '',
|
|
60
|
+
catalogueLevel: record.catalogueLevel ?? null,
|
|
61
|
+
department: record.department ?? '',
|
|
62
|
+
heldBy: record.heldBy ?? [],
|
|
63
|
+
})),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Sums one Discovery search page.
|
|
68
|
+
*
|
|
69
|
+
* @param result - a page from {@link parseTnaDiscoveryRecords}
|
|
70
|
+
* @returns the page size and the total hit count
|
|
71
|
+
*/
|
|
72
|
+
export function summarizeTnaDiscoverySearch(result) {
|
|
73
|
+
return { recordCount: result.records.length, totalCount: result.totalCount };
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Searches the Discovery catalogue for one query.
|
|
77
|
+
*
|
|
78
|
+
* @param options - the search term and an optional fetch implementation
|
|
79
|
+
* @returns the page of records the search endpoint returns
|
|
80
|
+
*/
|
|
81
|
+
export async function fetchTnaDiscoveryRecords(options = {}) {
|
|
82
|
+
const { query = DEFAULT_TNA_DISCOVERY_QUERY, fetchImpl = globalThis.fetch } = options;
|
|
83
|
+
const response = await fetchImpl(buildTnaDiscoverySearchUrl(query), {
|
|
84
|
+
headers: { Accept: TNA_DISCOVERY_ACCEPT_HEADER },
|
|
85
|
+
});
|
|
86
|
+
if (!response.ok) {
|
|
87
|
+
throw new UkSourceApiError('tna-discovery', `HTTP ${response.status} searching records`);
|
|
88
|
+
}
|
|
89
|
+
return parseTnaDiscoveryRecords(await response.json());
|
|
90
|
+
}
|
|
91
|
+
/** The National Archives Discovery catalogue search, keyless. */
|
|
92
|
+
export const tnaDiscoveryAdapter = {
|
|
93
|
+
id: TNA_DISCOVERY_SOURCE_ID,
|
|
94
|
+
name: 'The National Archives Discovery catalogue search',
|
|
95
|
+
auth: 'none',
|
|
96
|
+
description: `Catalogue records matching "${DEFAULT_TNA_DISCOVERY_QUERY}", with the total hit count.`,
|
|
97
|
+
fetchLive: (options) => fetchTnaDiscoveryRecords(options?.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
|
|
98
|
+
parse: parseTnaDiscoveryRecords,
|
|
99
|
+
loadFixture: () => parseTnaDiscoveryRecords(readFixtureJson('tna-discovery-2026-10-05.json')),
|
|
100
|
+
};
|
|
101
|
+
//# sourceMappingURL=tnaDiscovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tnaDiscovery.js","sourceRoot":"","sources":["../src/tnaDiscovery.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;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,eAAe,CAAC;AAEvD,gDAAgD;AAChD,MAAM,CAAC,MAAM,wBAAwB,GACnC,8DAA8D,CAAC;AAEjE;;;GAGG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,kBAAkB,CAAC;AAE9D,8EAA8E;AAC9E,MAAM,CAAC,MAAM,2BAA2B,GAAG,MAAM,CAAC;AAgClD,MAAM,2BAA2B,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAC3C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACvC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAC7C,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAC/C,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAChD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAC5C,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;CAClD,CAAC,CAAC;AAEH,MAAM,2BAA2B,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,2BAA2B,CAAC;IAC7C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;CAClB,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CAAC,KAAa;IACtD,OAAO,GAAG,wBAAwB,oBAAoB,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;AACpF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CAAC,OAAgB;IACvD,MAAM,MAAM,GAAG,2BAA2B,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC9D,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,kBAAkB,CAAC,eAAe,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACtE,CAAC;IACD,OAAO;QACL,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK;QAC7B,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAC5C,EAAE,EAAE,MAAM,CAAC,EAAE;YACb,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,EAAE;YACjC,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE;YACzB,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,EAAE;YACrC,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,EAAE;YACzC,cAAc,EAAE,MAAM,CAAC,cAAc,IAAI,IAAI;YAC7C,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,EAAE;YACnC,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;SAC5B,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B,CACzC,MAAgC;IAEhC,OAAO,EAAE,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC;AAC/E,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,UAAmE,EAAE;IAErE,MAAM,EAAE,KAAK,GAAG,2BAA2B,EAAE,SAAS,GAAG,UAAU,CAAC,KAAK,EAAE,GAAG,OAAO,CAAC;IACtF,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,0BAA0B,CAAC,KAAK,CAAC,EAAE;QAClE,OAAO,EAAE,EAAE,MAAM,EAAE,2BAA2B,EAAE;KACjD,CAAC,CAAC;IACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,gBAAgB,CAAC,eAAe,EAAE,QAAQ,QAAQ,CAAC,MAAM,oBAAoB,CAAC,CAAC;IAC3F,CAAC;IACD,OAAO,wBAAwB,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;AACzD,CAAC;AAED,iEAAiE;AACjE,MAAM,CAAC,MAAM,mBAAmB,GAA4C;IAC1E,EAAE,EAAE,uBAAuB;IAC3B,IAAI,EAAE,kDAAkD;IACxD,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,+BAA+B,2BAA2B,8BAA8B;IACrG,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CACrB,wBAAwB,CACtB,OAAO,EAAE,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CACzE;IACH,KAAK,EAAE,wBAAwB;IAC/B,WAAW,EAAE,GAAG,EAAE,CAAC,wBAAwB,CAAC,eAAe,CAAC,+BAA+B,CAAC,CAAC;CAC9F,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { UkDataAdapter } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The UK Health Security Agency data dashboard API. Keyless, published under
|
|
4
|
+
* the Open Government Licence v3.
|
|
5
|
+
*/
|
|
6
|
+
export declare const UKHSA_DASHBOARD_SOURCE_ID = "ukhsa-dashboard";
|
|
7
|
+
/** Root of the UKHSA data dashboard API. */
|
|
8
|
+
export declare const UKHSA_DASHBOARD_API_BASE_URL = "https://api.ukhsa-dashboard.data.gov.uk";
|
|
9
|
+
/**
|
|
10
|
+
* The metric the adapter reads: new HIV diagnoses in England, a country-level
|
|
11
|
+
* annual series the dashboard publishes with real counts.
|
|
12
|
+
*/
|
|
13
|
+
export declare const UKHSA_DASHBOARD_METRIC_PATH: string;
|
|
14
|
+
/** How many metric points the adapter asks for per page by default. */
|
|
15
|
+
export declare const UKHSA_DASHBOARD_PAGE_SIZE = 10;
|
|
16
|
+
/** One metric point from the UKHSA dashboard. */
|
|
17
|
+
export interface UkhsaMetricPoint {
|
|
18
|
+
theme: string;
|
|
19
|
+
subTheme: string;
|
|
20
|
+
topic: string;
|
|
21
|
+
geographyType: string;
|
|
22
|
+
geography: string;
|
|
23
|
+
/** ONS geography code for the area, or "" when the API leaves it out. */
|
|
24
|
+
geographyCode: string;
|
|
25
|
+
metric: string;
|
|
26
|
+
metricGroup: string;
|
|
27
|
+
stratum: string;
|
|
28
|
+
/** "all" for the whole population, otherwise a named subgroup. */
|
|
29
|
+
sex: string;
|
|
30
|
+
age: string;
|
|
31
|
+
year: number;
|
|
32
|
+
/** Calendar month, 1 to 12, or null for a point that is not monthly. */
|
|
33
|
+
month: number | null;
|
|
34
|
+
/** Epidemiological week, or null for a point that is not weekly. */
|
|
35
|
+
epiweek: number | null;
|
|
36
|
+
/** The point's date, ISO 8601. */
|
|
37
|
+
date: string;
|
|
38
|
+
/** The measured value, or null where the API publishes none. */
|
|
39
|
+
metricValue: number | null;
|
|
40
|
+
/** True while the dashboard flags the point as still settling. */
|
|
41
|
+
inReportingDelayPeriod: boolean;
|
|
42
|
+
}
|
|
43
|
+
/** One page of UKHSA metric points plus the API's total count. */
|
|
44
|
+
export interface UkhsaMetricPage {
|
|
45
|
+
/** Total points the API holds for the metric, not just this page. */
|
|
46
|
+
totalCount: number;
|
|
47
|
+
points: UkhsaMetricPoint[];
|
|
48
|
+
}
|
|
49
|
+
/** Rolled-up view of one page of UKHSA metric points. */
|
|
50
|
+
export interface UkhsaMetricSummary {
|
|
51
|
+
pointCount: number;
|
|
52
|
+
totalCount: number;
|
|
53
|
+
/** Earliest and latest dates on the page, "" when the page is empty. */
|
|
54
|
+
firstDate: string;
|
|
55
|
+
lastDate: string;
|
|
56
|
+
/** The value on the latest point, or null when the page is empty. */
|
|
57
|
+
latestValue: number | null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Builds the metric URL for one page size.
|
|
61
|
+
*
|
|
62
|
+
* @param pageSize - how many metric points to ask for
|
|
63
|
+
* @returns the metric endpoint URL
|
|
64
|
+
*/
|
|
65
|
+
export declare function buildUkhsaMetricUrl(pageSize: number): string;
|
|
66
|
+
/**
|
|
67
|
+
* Parses a UKHSA dashboard metric payload.
|
|
68
|
+
*
|
|
69
|
+
* @param payload - the raw JSON body from the metric endpoint
|
|
70
|
+
* @returns the page of metric points plus the API's total count
|
|
71
|
+
*/
|
|
72
|
+
export declare function parseUkhsaMetricPoints(payload: unknown): UkhsaMetricPage;
|
|
73
|
+
/**
|
|
74
|
+
* Sums one page of UKHSA metric points.
|
|
75
|
+
*
|
|
76
|
+
* @param page - a page from {@link parseUkhsaMetricPoints}
|
|
77
|
+
* @returns point counts, the date range on the page, and the latest value
|
|
78
|
+
*/
|
|
79
|
+
export declare function summarizeUkhsaMetricPoints(page: UkhsaMetricPage): UkhsaMetricSummary;
|
|
80
|
+
/**
|
|
81
|
+
* Reads one page of UKHSA dashboard metric points.
|
|
82
|
+
*
|
|
83
|
+
* @param options - page size and an optional fetch implementation
|
|
84
|
+
* @returns the page of metric points the endpoint returns
|
|
85
|
+
*/
|
|
86
|
+
export declare function fetchUkhsaMetricPoints(options?: {
|
|
87
|
+
pageSize?: number;
|
|
88
|
+
fetchImpl?: typeof globalThis.fetch;
|
|
89
|
+
}): Promise<UkhsaMetricPage>;
|
|
90
|
+
/** UK Health Security Agency data dashboard metric points, keyless. */
|
|
91
|
+
export declare const ukhsaDashboardAdapter: UkDataAdapter<UkhsaMetricPage>;
|
|
92
|
+
//# sourceMappingURL=ukhsaDashboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ukhsaDashboard.d.ts","sourceRoot":"","sources":["../src/ukhsaDashboard.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,yBAAyB,oBAAoB,CAAC;AAE3D,4CAA4C;AAC5C,eAAO,MAAM,4BAA4B,4CAA4C,CAAC;AAEtF;;;GAGG;AACH,eAAO,MAAM,2BAA2B,QAEsC,CAAC;AAE/E,uEAAuE;AACvE,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAE5C,iDAAiD;AACjD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,oEAAoE;IACpE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,kEAAkE;IAClE,sBAAsB,EAAE,OAAO,CAAC;CACjC;AAED,kEAAkE;AAClE,MAAM,WAAW,eAAe;IAC9B,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,gBAAgB,EAAE,CAAC;CAC5B;AAED,yDAAyD;AACzD,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AA2BD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,eAAe,CA2BxE;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,eAAe,GAAG,kBAAkB,CAoBpF;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CAAO,GACvE,OAAO,CAAC,eAAe,CAAC,CAO1B;AAED,uEAAuE;AACvE,eAAO,MAAM,qBAAqB,EAAE,aAAa,CAAC,eAAe,CAWhE,CAAC"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { UkSourceApiError, UkSourceParseError } from './errors.js';
|
|
3
|
+
import { readFixtureJson } from './fixtures.js';
|
|
4
|
+
/**
|
|
5
|
+
* The UK Health Security Agency data dashboard API. Keyless, published under
|
|
6
|
+
* the Open Government Licence v3.
|
|
7
|
+
*/
|
|
8
|
+
export const UKHSA_DASHBOARD_SOURCE_ID = 'ukhsa-dashboard';
|
|
9
|
+
/** Root of the UKHSA data dashboard API. */
|
|
10
|
+
export const UKHSA_DASHBOARD_API_BASE_URL = 'https://api.ukhsa-dashboard.data.gov.uk';
|
|
11
|
+
/**
|
|
12
|
+
* The metric the adapter reads: new HIV diagnoses in England, a country-level
|
|
13
|
+
* annual series the dashboard publishes with real counts.
|
|
14
|
+
*/
|
|
15
|
+
export const UKHSA_DASHBOARD_METRIC_PATH = '/themes/infectious_disease/sub_themes/bloodborne/topics/HIV' +
|
|
16
|
+
'/geography_types/Nation/geographies/England/metrics/HIV_cases_newDiagnoses';
|
|
17
|
+
/** How many metric points the adapter asks for per page by default. */
|
|
18
|
+
export const UKHSA_DASHBOARD_PAGE_SIZE = 10;
|
|
19
|
+
const UKHSA_METRIC_POINT_SCHEMA = z.object({
|
|
20
|
+
theme: z.string(),
|
|
21
|
+
sub_theme: z.string(),
|
|
22
|
+
topic: z.string(),
|
|
23
|
+
geography_type: z.string(),
|
|
24
|
+
geography: z.string(),
|
|
25
|
+
geography_code: z.string().nullable().optional(),
|
|
26
|
+
metric: z.string(),
|
|
27
|
+
metric_group: z.string().nullable().optional(),
|
|
28
|
+
stratum: z.string().nullable().optional(),
|
|
29
|
+
sex: z.string(),
|
|
30
|
+
age: z.string(),
|
|
31
|
+
year: z.number(),
|
|
32
|
+
month: z.number().nullable().optional(),
|
|
33
|
+
epiweek: z.number().nullable().optional(),
|
|
34
|
+
date: z.string(),
|
|
35
|
+
metric_value: z.number().nullable().optional(),
|
|
36
|
+
in_reporting_delay_period: z.boolean(),
|
|
37
|
+
});
|
|
38
|
+
const UKHSA_METRIC_PAGE_SCHEMA = z.object({
|
|
39
|
+
count: z.number(),
|
|
40
|
+
results: z.array(UKHSA_METRIC_POINT_SCHEMA),
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* Builds the metric URL for one page size.
|
|
44
|
+
*
|
|
45
|
+
* @param pageSize - how many metric points to ask for
|
|
46
|
+
* @returns the metric endpoint URL
|
|
47
|
+
*/
|
|
48
|
+
export function buildUkhsaMetricUrl(pageSize) {
|
|
49
|
+
return `${UKHSA_DASHBOARD_API_BASE_URL}${UKHSA_DASHBOARD_METRIC_PATH}?page_size=${pageSize}`;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Parses a UKHSA dashboard metric payload.
|
|
53
|
+
*
|
|
54
|
+
* @param payload - the raw JSON body from the metric endpoint
|
|
55
|
+
* @returns the page of metric points plus the API's total count
|
|
56
|
+
*/
|
|
57
|
+
export function parseUkhsaMetricPoints(payload) {
|
|
58
|
+
const parsed = UKHSA_METRIC_PAGE_SCHEMA.safeParse(payload);
|
|
59
|
+
if (!parsed.success) {
|
|
60
|
+
throw new UkSourceParseError('ukhsa-dashboard', parsed.error.message);
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
totalCount: parsed.data.count,
|
|
64
|
+
points: parsed.data.results.map((point) => ({
|
|
65
|
+
theme: point.theme,
|
|
66
|
+
subTheme: point.sub_theme,
|
|
67
|
+
topic: point.topic,
|
|
68
|
+
geographyType: point.geography_type,
|
|
69
|
+
geography: point.geography,
|
|
70
|
+
geographyCode: point.geography_code ?? '',
|
|
71
|
+
metric: point.metric,
|
|
72
|
+
metricGroup: point.metric_group ?? '',
|
|
73
|
+
stratum: point.stratum ?? '',
|
|
74
|
+
sex: point.sex,
|
|
75
|
+
age: point.age,
|
|
76
|
+
year: point.year,
|
|
77
|
+
month: point.month ?? null,
|
|
78
|
+
epiweek: point.epiweek ?? null,
|
|
79
|
+
date: point.date,
|
|
80
|
+
metricValue: point.metric_value ?? null,
|
|
81
|
+
inReportingDelayPeriod: point.in_reporting_delay_period,
|
|
82
|
+
})),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Sums one page of UKHSA metric points.
|
|
87
|
+
*
|
|
88
|
+
* @param page - a page from {@link parseUkhsaMetricPoints}
|
|
89
|
+
* @returns point counts, the date range on the page, and the latest value
|
|
90
|
+
*/
|
|
91
|
+
export function summarizeUkhsaMetricPoints(page) {
|
|
92
|
+
let firstDate = '';
|
|
93
|
+
let lastDate = '';
|
|
94
|
+
let latestValue = null;
|
|
95
|
+
for (const point of page.points) {
|
|
96
|
+
if (firstDate === '' || point.date < firstDate) {
|
|
97
|
+
firstDate = point.date;
|
|
98
|
+
}
|
|
99
|
+
if (point.date >= lastDate) {
|
|
100
|
+
lastDate = point.date;
|
|
101
|
+
latestValue = point.metricValue;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
pointCount: page.points.length,
|
|
106
|
+
totalCount: page.totalCount,
|
|
107
|
+
firstDate,
|
|
108
|
+
lastDate,
|
|
109
|
+
latestValue,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Reads one page of UKHSA dashboard metric points.
|
|
114
|
+
*
|
|
115
|
+
* @param options - page size and an optional fetch implementation
|
|
116
|
+
* @returns the page of metric points the endpoint returns
|
|
117
|
+
*/
|
|
118
|
+
export async function fetchUkhsaMetricPoints(options = {}) {
|
|
119
|
+
const { pageSize = UKHSA_DASHBOARD_PAGE_SIZE, fetchImpl = globalThis.fetch } = options;
|
|
120
|
+
const response = await fetchImpl(buildUkhsaMetricUrl(pageSize));
|
|
121
|
+
if (!response.ok) {
|
|
122
|
+
throw new UkSourceApiError('ukhsa-dashboard', `HTTP ${response.status} reading metric points`);
|
|
123
|
+
}
|
|
124
|
+
return parseUkhsaMetricPoints(await response.json());
|
|
125
|
+
}
|
|
126
|
+
/** UK Health Security Agency data dashboard metric points, keyless. */
|
|
127
|
+
export const ukhsaDashboardAdapter = {
|
|
128
|
+
id: UKHSA_DASHBOARD_SOURCE_ID,
|
|
129
|
+
name: 'UK Health Security Agency data dashboard',
|
|
130
|
+
auth: 'none',
|
|
131
|
+
description: 'New HIV diagnoses in England, as annual counts from the UKHSA dashboard.',
|
|
132
|
+
fetchLive: (options) => fetchUkhsaMetricPoints(options?.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
|
|
133
|
+
parse: parseUkhsaMetricPoints,
|
|
134
|
+
loadFixture: () => parseUkhsaMetricPoints(readFixtureJson('ukhsa-dashboard-2026-10-05.json')),
|
|
135
|
+
};
|
|
136
|
+
//# sourceMappingURL=ukhsaDashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ukhsaDashboard.js","sourceRoot":"","sources":["../src/ukhsaDashboard.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uk-open-data-connectors/uk-sources",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@uk-open-data-connectors/config-eslint": "*",
|
|
33
33
|
"@uk-open-data-connectors/config-typescript": "*",
|
|
34
|
-
"@types/node": "22.20.
|
|
34
|
+
"@types/node": "22.20.5",
|
|
35
35
|
"eslint": "9.39.5",
|
|
36
36
|
"typescript": "6.0.3",
|
|
37
37
|
"vitest": "3.2.7"
|
|
@@ -42,5 +42,13 @@
|
|
|
42
42
|
"publishConfig": {
|
|
43
43
|
"access": "public"
|
|
44
44
|
},
|
|
45
|
-
"description": "Uniform TypeScript adapters for UK public data sources"
|
|
45
|
+
"description": "Uniform TypeScript adapters for UK public data sources",
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "git+https://github.com/olitreadwell/uk-open-data-connectors.git"
|
|
49
|
+
},
|
|
50
|
+
"homepage": "https://github.com/olitreadwell/uk-open-data-connectors#readme",
|
|
51
|
+
"bugs": {
|
|
52
|
+
"url": "https://github.com/olitreadwell/uk-open-data-connectors/issues"
|
|
53
|
+
}
|
|
46
54
|
}
|