@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.
Files changed (53) hide show
  1. package/README.md +21 -0
  2. package/dist/exploreEducationStatistics.d.ts +72 -0
  3. package/dist/exploreEducationStatistics.d.ts.map +1 -0
  4. package/dist/exploreEducationStatistics.js +110 -0
  5. package/dist/exploreEducationStatistics.js.map +1 -0
  6. package/dist/findATender.d.ts +76 -0
  7. package/dist/findATender.d.ts.map +1 -0
  8. package/dist/findATender.js +109 -0
  9. package/dist/findATender.js.map +1 -0
  10. package/dist/fingertipsIndicators.d.ts +67 -0
  11. package/dist/fingertipsIndicators.d.ts.map +1 -0
  12. package/dist/fingertipsIndicators.js +94 -0
  13. package/dist/fingertipsIndicators.js.map +1 -0
  14. package/dist/index.d.ts +40 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +20 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/londonDatastore.d.ts +46 -0
  19. package/dist/londonDatastore.d.ts.map +1 -0
  20. package/dist/londonDatastore.js +64 -0
  21. package/dist/londonDatastore.js.map +1 -0
  22. package/dist/nhsbsaCkan.d.ts +43 -0
  23. package/dist/nhsbsaCkan.d.ts.map +1 -0
  24. package/dist/nhsbsaCkan.js +61 -0
  25. package/dist/nhsbsaCkan.js.map +1 -0
  26. package/dist/nomis.d.ts +71 -0
  27. package/dist/nomis.d.ts.map +1 -0
  28. package/dist/nomis.js +126 -0
  29. package/dist/nomis.js.map +1 -0
  30. package/dist/postcodeLookup.d.ts +55 -0
  31. package/dist/postcodeLookup.d.ts.map +1 -0
  32. package/dist/postcodeLookup.js +89 -0
  33. package/dist/postcodeLookup.js.map +1 -0
  34. package/dist/publicHealthScotland.d.ts +43 -0
  35. package/dist/publicHealthScotland.d.ts.map +1 -0
  36. package/dist/publicHealthScotland.js +61 -0
  37. package/dist/publicHealthScotland.js.map +1 -0
  38. package/dist/registry.d.ts.map +1 -1
  39. package/dist/registry.js +22 -0
  40. package/dist/registry.js.map +1 -1
  41. package/dist/tflLineStatus.d.ts +59 -0
  42. package/dist/tflLineStatus.d.ts.map +1 -0
  43. package/dist/tflLineStatus.js +93 -0
  44. package/dist/tflLineStatus.js.map +1 -0
  45. package/dist/tnaDiscovery.d.ts +76 -0
  46. package/dist/tnaDiscovery.d.ts.map +1 -0
  47. package/dist/tnaDiscovery.js +101 -0
  48. package/dist/tnaDiscovery.js.map +1 -0
  49. package/dist/ukhsaDashboard.d.ts +92 -0
  50. package/dist/ukhsaDashboard.d.ts.map +1 -0
  51. package/dist/ukhsaDashboard.js +136 -0
  52. package/dist/ukhsaDashboard.js.map +1 -0
  53. package/package.json +11 -3
package/README.md CHANGED
@@ -19,6 +19,17 @@ builds work offline.
19
19
  | `police-crimes` | Home Office police.uk | none | Street-level crime within a mile of a point, counted by crime type and outcome |
20
20
  | `carbon-intensity` | National Energy System Operator | none | Half-hourly carbon intensity for Great Britain, with the window's cleanest and dirtiest half hours |
21
21
  | `parliament-seats` | UK Parliament Members API | none | Seats each party holds in the Commons, with the members counted behind them |
22
+ | `postcode-lookup` | postcodes.io (ONS and OS data) | none | One postcode's country, region, wards, and coordinates |
23
+ | `explore-education-statistics` | Department for Education | none | The most recent statistics releases, with their publish stamps |
24
+ | `london-datastore` | Greater London Authority | none | Every dataset on the London Datastore |
25
+ | `tna-discovery` | The National Archives | none | Catalogue records matching a search, with the total hit count |
26
+ | `ukhsa-dashboard` | UK Health Security Agency | none | Metric points for new HIV diagnoses in England |
27
+ | `nomis` | ONS Nomis | none | SDMX dataset definitions, with maintenance status and keywords |
28
+ | `fingertips-indicators` | Office for Health Improvement and Disparities | none | Public health indicator metadata, with unit, type, and data source |
29
+ | `find-a-tender` | Cabinet Office | none | Recent procurement notices as OCDS 1.1 releases |
30
+ | `tfl-line-status` | Transport for London | none | Live status of every Tube line, with disruption reasons |
31
+ | `public-health-scotland` | Public Health Scotland | none | Every dataset on the Public Health Scotland CKAN portal |
32
+ | `nhsbsa-ckan` | NHS Business Services Authority | none | Every dataset on the NHSBSA CKAN portal |
22
33
 
23
34
  The flood-monitoring adapters use `environment.data.gov.uk` under the Open
24
35
  Government Licence v3:
@@ -89,6 +100,16 @@ under the Open Parliament Licence v3.0:
89
100
  The call needs a house and a date, so the adapter asks for the caller's own
90
101
  date rather than a fixed one.
91
102
 
103
+ Eleven more keyless adapters landed on 2026-10-05: `postcode-lookup` reads
104
+ one postcode from postcodes.io, `explore-education-statistics` reads the
105
+ Department for Education's most recent releases, `london-datastore` and
106
+ `public-health-scotland` and `nhsbsa-ckan` read CKAN catalogues, `tna-discovery`
107
+ searches The National Archives catalogue, `ukhsa-dashboard` reads UKHSA metric
108
+ points, `nomis` reads the ONS Nomis SDMX catalogue, `fingertips-indicators`
109
+ reads OHID indicator metadata, `find-a-tender` reads OCDS procurement notices,
110
+ and `tfl-line-status` reads live Tube status. Endpoints, exact curl commands,
111
+ capture date, and licences are in `docs/CONNECTOR_DISCOVERY.md`.
112
+
92
113
  Note on sources that look obvious but are not usable: `api.ons.gov.uk` was
93
114
  retired on 2024-11-25 and now answers every request with a decommission notice.
94
115
  The beta API at `api.beta.ons.gov.uk/v1` replaced it for dataset metadata,
@@ -0,0 +1,72 @@
1
+ import type { UkDataAdapter } from './types.js';
2
+ /**
3
+ * The Department for Education's Explore Education Statistics publications
4
+ * API. Keyless, published under the Open Government Licence v3.
5
+ */
6
+ export declare const EXPLORE_EDUCATION_STATISTICS_SOURCE_ID = "explore-education-statistics";
7
+ /** Base URL for the Explore Education Statistics publications endpoint. */
8
+ export declare const EXPLORE_EDUCATION_PUBLICATIONS_URL = "https://api.education.gov.uk/statistics/v1/publications";
9
+ /** How many publications the adapter asks for per page by default. */
10
+ export declare const EXPLORE_EDUCATION_PUBLICATIONS_PAGE_SIZE = 20;
11
+ /** One published statistics release as the API lists it. */
12
+ export interface ExploreEducationPublication {
13
+ id: string;
14
+ title: string;
15
+ /** URL-safe identifier, unique across releases. */
16
+ slug: string;
17
+ summary: string;
18
+ /** Publication stamp the API reports, ISO 8601 with an offset. */
19
+ lastPublishedIso: string;
20
+ }
21
+ /** One page of the publications catalogue plus the API's paging counts. */
22
+ export interface ExploreEducationPublicationsPage {
23
+ page: number;
24
+ pageSize: number;
25
+ totalResults: number;
26
+ totalPages: number;
27
+ publications: ExploreEducationPublication[];
28
+ }
29
+ /** Rolled-up view of one publications page. */
30
+ export interface ExploreEducationPublicationsSummary {
31
+ publicationCount: number;
32
+ /** Total releases the API holds, not just this page. */
33
+ totalResults: number;
34
+ /** The most recent publish stamp on this page, or "" when the page is empty. */
35
+ latestPublishedIso: string;
36
+ }
37
+ /**
38
+ * Builds a publications URL for one page.
39
+ *
40
+ * @param page - one-based page number
41
+ * @param pageSize - records per page
42
+ * @returns the publications catalogue URL
43
+ */
44
+ export declare function buildExploreEducationPublicationsUrl(page: number, pageSize: number): string;
45
+ /**
46
+ * Parses an Explore Education Statistics publications payload.
47
+ *
48
+ * @param payload - the raw JSON body from the publications endpoint
49
+ * @returns the page of publications plus the API's paging counts
50
+ */
51
+ export declare function parseExploreEducationPublications(payload: unknown): ExploreEducationPublicationsPage;
52
+ /**
53
+ * Sums one publications page.
54
+ *
55
+ * @param page - a page from {@link parseExploreEducationPublications}
56
+ * @returns publication counts and the newest publish stamp on the page
57
+ */
58
+ export declare function summarizeExploreEducationPublications(page: ExploreEducationPublicationsPage): ExploreEducationPublicationsSummary;
59
+ /**
60
+ * Lists one page of Explore Education Statistics publications.
61
+ *
62
+ * @param options - page, page size, and an optional fetch implementation
63
+ * @returns the page of publications the endpoint returns
64
+ */
65
+ export declare function fetchExploreEducationPublications(options?: {
66
+ page?: number;
67
+ pageSize?: number;
68
+ fetchImpl?: typeof globalThis.fetch;
69
+ }): Promise<ExploreEducationPublicationsPage>;
70
+ /** Explore Education Statistics publications, keyless. */
71
+ export declare const exploreEducationStatisticsAdapter: UkDataAdapter<ExploreEducationPublicationsPage>;
72
+ //# sourceMappingURL=exploreEducationStatistics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exploreEducationStatistics.d.ts","sourceRoot":"","sources":["../src/exploreEducationStatistics.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,sCAAsC,iCAAiC,CAAC;AAErF,2EAA2E;AAC3E,eAAO,MAAM,kCAAkC,4DACY,CAAC;AAE5D,sEAAsE;AACtE,eAAO,MAAM,wCAAwC,KAAK,CAAC;AAE3D,4DAA4D;AAC5D,MAAM,WAAW,2BAA2B;IAC1C,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,2EAA2E;AAC3E,MAAM,WAAW,gCAAgC;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,2BAA2B,EAAE,CAAC;CAC7C;AAED,+CAA+C;AAC/C,MAAM,WAAW,mCAAmC;IAClD,gBAAgB,EAAE,MAAM,CAAC;IACzB,wDAAwD;IACxD,YAAY,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAoBD;;;;;;GAMG;AACH,wBAAgB,oCAAoC,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE3F;AAED;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,OAAO,GACf,gCAAgC,CAkBlC;AAED;;;;;GAKG;AACH,wBAAgB,qCAAqC,CACnD,IAAI,EAAE,gCAAgC,GACrC,mCAAmC,CAerC;AAED;;;;;GAKG;AACH,wBAAsB,iCAAiC,CACrD,OAAO,GAAE;IACP,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CAChC,GACL,OAAO,CAAC,gCAAgC,CAAC,CAc3C;AAED,0DAA0D;AAC1D,eAAO,MAAM,iCAAiC,EAAE,aAAa,CAAC,gCAAgC,CAc7F,CAAC"}
@@ -0,0 +1,110 @@
1
+ import { z } from 'zod';
2
+ import { UkSourceApiError, UkSourceParseError } from './errors.js';
3
+ import { readFixtureJson } from './fixtures.js';
4
+ /**
5
+ * The Department for Education's Explore Education Statistics publications
6
+ * API. Keyless, published under the Open Government Licence v3.
7
+ */
8
+ export const EXPLORE_EDUCATION_STATISTICS_SOURCE_ID = 'explore-education-statistics';
9
+ /** Base URL for the Explore Education Statistics publications endpoint. */
10
+ export const EXPLORE_EDUCATION_PUBLICATIONS_URL = 'https://api.education.gov.uk/statistics/v1/publications';
11
+ /** How many publications the adapter asks for per page by default. */
12
+ export const EXPLORE_EDUCATION_PUBLICATIONS_PAGE_SIZE = 20;
13
+ const EXPLORE_EDUCATION_PUBLICATION_SCHEMA = z.object({
14
+ id: z.string(),
15
+ title: z.string(),
16
+ slug: z.string(),
17
+ summary: z.string().nullable().optional(),
18
+ lastPublished: z.string(),
19
+ });
20
+ const EXPLORE_EDUCATION_PUBLICATIONS_SCHEMA = z.object({
21
+ paging: z.object({
22
+ page: z.number(),
23
+ pageSize: z.number(),
24
+ totalResults: z.number(),
25
+ totalPages: z.number(),
26
+ }),
27
+ results: z.array(EXPLORE_EDUCATION_PUBLICATION_SCHEMA),
28
+ });
29
+ /**
30
+ * Builds a publications URL for one page.
31
+ *
32
+ * @param page - one-based page number
33
+ * @param pageSize - records per page
34
+ * @returns the publications catalogue URL
35
+ */
36
+ export function buildExploreEducationPublicationsUrl(page, pageSize) {
37
+ return `${EXPLORE_EDUCATION_PUBLICATIONS_URL}?page=${page}&pageSize=${pageSize}`;
38
+ }
39
+ /**
40
+ * Parses an Explore Education Statistics publications payload.
41
+ *
42
+ * @param payload - the raw JSON body from the publications endpoint
43
+ * @returns the page of publications plus the API's paging counts
44
+ */
45
+ export function parseExploreEducationPublications(payload) {
46
+ const parsed = EXPLORE_EDUCATION_PUBLICATIONS_SCHEMA.safeParse(payload);
47
+ if (!parsed.success) {
48
+ throw new UkSourceParseError('explore-education-statistics', parsed.error.message);
49
+ }
50
+ return {
51
+ page: parsed.data.paging.page,
52
+ pageSize: parsed.data.paging.pageSize,
53
+ totalResults: parsed.data.paging.totalResults,
54
+ totalPages: parsed.data.paging.totalPages,
55
+ publications: parsed.data.results.map((publication) => ({
56
+ id: publication.id,
57
+ title: publication.title,
58
+ slug: publication.slug,
59
+ summary: publication.summary ?? '',
60
+ lastPublishedIso: publication.lastPublished,
61
+ })),
62
+ };
63
+ }
64
+ /**
65
+ * Sums one publications page.
66
+ *
67
+ * @param page - a page from {@link parseExploreEducationPublications}
68
+ * @returns publication counts and the newest publish stamp on the page
69
+ */
70
+ export function summarizeExploreEducationPublications(page) {
71
+ let latestPublishedIso = '';
72
+ let latestPublishedEpoch = Number.NEGATIVE_INFINITY;
73
+ for (const publication of page.publications) {
74
+ const epoch = Date.parse(publication.lastPublishedIso);
75
+ if (Number.isFinite(epoch) && epoch > latestPublishedEpoch) {
76
+ latestPublishedEpoch = epoch;
77
+ latestPublishedIso = publication.lastPublishedIso;
78
+ }
79
+ }
80
+ return {
81
+ publicationCount: page.publications.length,
82
+ totalResults: page.totalResults,
83
+ latestPublishedIso,
84
+ };
85
+ }
86
+ /**
87
+ * Lists one page of Explore Education Statistics publications.
88
+ *
89
+ * @param options - page, page size, and an optional fetch implementation
90
+ * @returns the page of publications the endpoint returns
91
+ */
92
+ export async function fetchExploreEducationPublications(options = {}) {
93
+ const { page = 1, pageSize = EXPLORE_EDUCATION_PUBLICATIONS_PAGE_SIZE, fetchImpl = globalThis.fetch, } = options;
94
+ const response = await fetchImpl(buildExploreEducationPublicationsUrl(page, pageSize));
95
+ if (!response.ok) {
96
+ throw new UkSourceApiError('explore-education-statistics', `HTTP ${response.status} listing publications`);
97
+ }
98
+ return parseExploreEducationPublications(await response.json());
99
+ }
100
+ /** Explore Education Statistics publications, keyless. */
101
+ export const exploreEducationStatisticsAdapter = {
102
+ id: EXPLORE_EDUCATION_STATISTICS_SOURCE_ID,
103
+ name: 'Department for Education Explore Education Statistics publications',
104
+ auth: 'none',
105
+ description: 'The most recent statistics releases the Department for Education has published.',
106
+ fetchLive: (options) => fetchExploreEducationPublications(options?.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
107
+ parse: parseExploreEducationPublications,
108
+ loadFixture: () => parseExploreEducationPublications(readFixtureJson('explore-education-statistics-2026-10-05.json')),
109
+ };
110
+ //# sourceMappingURL=exploreEducationStatistics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exploreEducationStatistics.js","sourceRoot":"","sources":["../src/exploreEducationStatistics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ import type { UkDataAdapter } from './types.js';
2
+ /**
3
+ * Find a Tender, the UK's post-Brexit public procurement service run by the
4
+ * Cabinet Office. Keyless, and the notices are published under the Open
5
+ * Government Licence v3, matching the licence the payload itself carries.
6
+ */
7
+ export declare const FIND_A_TENDER_SOURCE_ID = "find-a-tender";
8
+ /** The OCDS 1.1 release packages endpoint. */
9
+ export declare const FIND_A_TENDER_RELEASE_PACKAGES_URL = "https://www.find-tender.service.gov.uk/api/1.0/ocdsReleasePackages";
10
+ /** How many release packages the adapter asks for by default. */
11
+ export declare const FIND_A_TENDER_RELEASE_LIMIT = 10;
12
+ /** One Open Contracting Data Standard release, as Find a Tender publishes it. */
13
+ export interface FindATenderRelease {
14
+ /** Open Contracting identifier shared by every release of one tender. */
15
+ ocid: string;
16
+ /** The release id, unique within the tender. */
17
+ id: string;
18
+ /** When the release was published, ISO 8601 with an offset. */
19
+ date: string;
20
+ /** Release tags, such as "tender", "award", or "contractAmendment". */
21
+ tags: string[];
22
+ tenderTitle: string;
23
+ /** Tender status, such as "active" or "complete", or "" when unset. */
24
+ tenderStatus: string;
25
+ procurementMethod: string;
26
+ buyerName: string;
27
+ /** The tender value amount, or null when the release leaves it out. */
28
+ tenderValueAmount: number | null;
29
+ }
30
+ /** One page of OCDS releases plus the package metadata around them. */
31
+ export interface FindATenderReleasePage {
32
+ /** The package URI the service echoes back, including its own cursor. */
33
+ uri: string;
34
+ version: string;
35
+ publishedDate: string;
36
+ releases: FindATenderRelease[];
37
+ }
38
+ /** Release counts by tender status. */
39
+ export interface FindATenderStatusCount {
40
+ status: string;
41
+ releaseCount: number;
42
+ }
43
+ /** Rolled-up view of one page of Find a Tender releases. */
44
+ export interface FindATenderSummary {
45
+ releaseCount: number;
46
+ /** Releases with an unset tender status. */
47
+ unsetStatusCount: number;
48
+ statusCounts: FindATenderStatusCount[];
49
+ }
50
+ /**
51
+ * Parses an OCDS release packages payload into releases.
52
+ *
53
+ * @param payload - the raw JSON body from the release packages endpoint
54
+ * @returns the releases plus the package metadata
55
+ */
56
+ export declare function parseFindATenderReleases(payload: unknown): FindATenderReleasePage;
57
+ /**
58
+ * Counts the releases on one page by tender status.
59
+ *
60
+ * @param page - a page from {@link parseFindATenderReleases}
61
+ * @returns the release count and a per-status breakdown, most releases first
62
+ */
63
+ export declare function summarizeFindATenderReleases(page: FindATenderReleasePage): FindATenderSummary;
64
+ /**
65
+ * Lists the most recent Find a Tender release packages.
66
+ *
67
+ * @param options - release limit and an optional fetch implementation
68
+ * @returns the releases the endpoint returns
69
+ */
70
+ export declare function fetchFindATenderReleases(options?: {
71
+ limit?: number;
72
+ fetchImpl?: typeof globalThis.fetch;
73
+ }): Promise<FindATenderReleasePage>;
74
+ /** Find a Tender OCDS release packages, keyless. */
75
+ export declare const findATenderAdapter: UkDataAdapter<FindATenderReleasePage>;
76
+ //# sourceMappingURL=findATender.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findATender.d.ts","sourceRoot":"","sources":["../src/findATender.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,kBAAkB,CAAC;AAEvD,8CAA8C;AAC9C,eAAO,MAAM,kCAAkC,uEACuB,CAAC;AAEvE,iEAAiE;AACjE,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAE9C,iFAAiF;AACjF,MAAM,WAAW,kBAAkB;IACjC,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,EAAE,EAAE,MAAM,CAAC;IACX,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,uEAAuE;AACvE,MAAM,WAAW,sBAAsB;IACrC,yEAAyE;IACzE,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,kBAAkB,EAAE,CAAC;CAChC;AAED,uCAAuC;AACvC,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,4DAA4D;AAC5D,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,sBAAsB,EAAE,CAAC;CACxC;AA0BD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,sBAAsB,CAqBjF;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,sBAAsB,GAAG,kBAAkB,CAiB7F;AAED;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CAAO,GACpE,OAAO,CAAC,sBAAsB,CAAC,CAOjC;AAED,oDAAoD;AACpD,eAAO,MAAM,kBAAkB,EAAE,aAAa,CAAC,sBAAsB,CAWpE,CAAC"}
@@ -0,0 +1,109 @@
1
+ import { z } from 'zod';
2
+ import { UkSourceApiError, UkSourceParseError } from './errors.js';
3
+ import { readFixtureJson } from './fixtures.js';
4
+ /**
5
+ * Find a Tender, the UK's post-Brexit public procurement service run by the
6
+ * Cabinet Office. Keyless, and the notices are published under the Open
7
+ * Government Licence v3, matching the licence the payload itself carries.
8
+ */
9
+ export const FIND_A_TENDER_SOURCE_ID = 'find-a-tender';
10
+ /** The OCDS 1.1 release packages endpoint. */
11
+ export const FIND_A_TENDER_RELEASE_PACKAGES_URL = 'https://www.find-tender.service.gov.uk/api/1.0/ocdsReleasePackages';
12
+ /** How many release packages the adapter asks for by default. */
13
+ export const FIND_A_TENDER_RELEASE_LIMIT = 10;
14
+ const FIND_A_TENDER_RELEASE_SCHEMA = z.object({
15
+ ocid: z.string(),
16
+ id: z.string(),
17
+ date: z.string(),
18
+ tag: z.array(z.string()).optional(),
19
+ tender: z
20
+ .object({
21
+ title: z.string().nullable().optional(),
22
+ status: z.string().nullable().optional(),
23
+ procurementMethod: z.string().nullable().optional(),
24
+ value: z.object({ amount: z.number().nullable().optional() }).nullable().optional(),
25
+ })
26
+ .nullable()
27
+ .optional(),
28
+ buyer: z.object({ name: z.string().nullable().optional() }).nullable().optional(),
29
+ });
30
+ const FIND_A_TENDER_RELEASE_PACKAGE_SCHEMA = z.object({
31
+ uri: z.string(),
32
+ version: z.string(),
33
+ publishedDate: z.string(),
34
+ releases: z.array(FIND_A_TENDER_RELEASE_SCHEMA),
35
+ });
36
+ /**
37
+ * Parses an OCDS release packages payload into releases.
38
+ *
39
+ * @param payload - the raw JSON body from the release packages endpoint
40
+ * @returns the releases plus the package metadata
41
+ */
42
+ export function parseFindATenderReleases(payload) {
43
+ const parsed = FIND_A_TENDER_RELEASE_PACKAGE_SCHEMA.safeParse(payload);
44
+ if (!parsed.success) {
45
+ throw new UkSourceParseError('find-a-tender', parsed.error.message);
46
+ }
47
+ return {
48
+ uri: parsed.data.uri,
49
+ version: parsed.data.version,
50
+ publishedDate: parsed.data.publishedDate,
51
+ releases: parsed.data.releases.map((release) => ({
52
+ ocid: release.ocid,
53
+ id: release.id,
54
+ date: release.date,
55
+ tags: release.tag ?? [],
56
+ tenderTitle: release.tender?.title ?? '',
57
+ tenderStatus: release.tender?.status ?? '',
58
+ procurementMethod: release.tender?.procurementMethod ?? '',
59
+ buyerName: release.buyer?.name ?? '',
60
+ tenderValueAmount: release.tender?.value?.amount ?? null,
61
+ })),
62
+ };
63
+ }
64
+ /**
65
+ * Counts the releases on one page by tender status.
66
+ *
67
+ * @param page - a page from {@link parseFindATenderReleases}
68
+ * @returns the release count and a per-status breakdown, most releases first
69
+ */
70
+ export function summarizeFindATenderReleases(page) {
71
+ const countByStatus = new Map();
72
+ let unsetStatusCount = 0;
73
+ for (const release of page.releases) {
74
+ if (release.tenderStatus === '') {
75
+ unsetStatusCount += 1;
76
+ continue;
77
+ }
78
+ countByStatus.set(release.tenderStatus, (countByStatus.get(release.tenderStatus) ?? 0) + 1);
79
+ }
80
+ const statusCounts = [...countByStatus.entries()]
81
+ .map(([status, releaseCount]) => ({ status, releaseCount }))
82
+ .sort((left, right) => right.releaseCount - left.releaseCount || left.status.localeCompare(right.status));
83
+ return { releaseCount: page.releases.length, unsetStatusCount, statusCounts };
84
+ }
85
+ /**
86
+ * Lists the most recent Find a Tender release packages.
87
+ *
88
+ * @param options - release limit and an optional fetch implementation
89
+ * @returns the releases the endpoint returns
90
+ */
91
+ export async function fetchFindATenderReleases(options = {}) {
92
+ const { limit = FIND_A_TENDER_RELEASE_LIMIT, fetchImpl = globalThis.fetch } = options;
93
+ const response = await fetchImpl(`${FIND_A_TENDER_RELEASE_PACKAGES_URL}?limit=${limit}`);
94
+ if (!response.ok) {
95
+ throw new UkSourceApiError('find-a-tender', `HTTP ${response.status} listing releases`);
96
+ }
97
+ return parseFindATenderReleases(await response.json());
98
+ }
99
+ /** Find a Tender OCDS release packages, keyless. */
100
+ export const findATenderAdapter = {
101
+ id: FIND_A_TENDER_SOURCE_ID,
102
+ name: 'Find a Tender OCDS release packages',
103
+ auth: 'none',
104
+ description: 'The most recent public procurement notices Find a Tender publishes.',
105
+ fetchLive: (options) => fetchFindATenderReleases(options?.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
106
+ parse: parseFindATenderReleases,
107
+ loadFixture: () => parseFindATenderReleases(readFixtureJson('find-a-tender-2026-10-05.json')),
108
+ };
109
+ //# sourceMappingURL=findATender.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findATender.js","sourceRoot":"","sources":["../src/findATender.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ import type { UkDataAdapter } from './types.js';
2
+ /**
3
+ * The Office for Health Improvement and Disparities public health profiles,
4
+ * published by Fingertips. Keyless, under the Open Government Licence v3.
5
+ */
6
+ export declare const FINGERTIPS_INDICATORS_SOURCE_ID = "fingertips-indicators";
7
+ /** Base URL for the Fingertips indicator metadata call. */
8
+ export declare const FINGERTIPS_INDICATOR_METADATA_URL = "https://fingertips.phe.org.uk/api/indicator_metadata/by_indicator_id";
9
+ /** The indicator the adapter reads when the caller does not name one. */
10
+ export declare const DEFAULT_FINGERTIPS_INDICATOR_IDS: number[];
11
+ /** One public health indicator and the metadata behind it. */
12
+ export interface FingertipsIndicatorMetadata {
13
+ indicatorId: number;
14
+ name: string;
15
+ /** The body that produced the figures, such as the ONS. */
16
+ dataSource: string;
17
+ /** The unit the indicator counts in, or "" when Fingertips leaves it out. */
18
+ unitLabel: string;
19
+ /** The measure type, such as "Life expectancy". */
20
+ valueType: string;
21
+ /** The year basis, such as "Calendar". */
22
+ yearType: string;
23
+ /** When Fingertips last uploaded data, or "" when unset. */
24
+ lastUploadedAt: string;
25
+ /** Fingertips' override stamp for the last change, or "" when unset. */
26
+ latestChangeTimestampOverride: string;
27
+ }
28
+ /** Rolled-up view of the indicators a call returns. */
29
+ export interface FingertipsIndicatorsSummary {
30
+ indicatorCount: number;
31
+ /** The distinct data sources behind the indicators, sorted. */
32
+ dataSources: string[];
33
+ }
34
+ /**
35
+ * Builds the Fingertips indicator metadata URL for a set of indicator ids.
36
+ *
37
+ * @param indicatorIds - the indicator ids to read
38
+ * @returns the metadata URL, ids comma-separated
39
+ */
40
+ export declare function buildFingertipsIndicatorUrl(indicatorIds: number[]): string;
41
+ /**
42
+ * Parses a Fingertips indicator metadata payload.
43
+ *
44
+ * @param payload - the raw JSON body from the metadata endpoint
45
+ * @returns one entry per indicator the payload carries
46
+ */
47
+ export declare function parseFingertipsIndicators(payload: unknown): FingertipsIndicatorMetadata[];
48
+ /**
49
+ * Sums the indicators a call returns.
50
+ *
51
+ * @param indicators - indicators from {@link parseFingertipsIndicators}
52
+ * @returns the indicator count and the distinct data sources behind them
53
+ */
54
+ export declare function summarizeFingertipsIndicators(indicators: FingertipsIndicatorMetadata[]): FingertipsIndicatorsSummary;
55
+ /**
56
+ * Reads metadata for a set of Fingertips public health indicators.
57
+ *
58
+ * @param options - indicator ids and an optional fetch implementation
59
+ * @returns the indicator metadata the endpoint returns
60
+ */
61
+ export declare function fetchFingertipsIndicators(options?: {
62
+ indicatorIds?: number[];
63
+ fetchImpl?: typeof globalThis.fetch;
64
+ }): Promise<FingertipsIndicatorMetadata[]>;
65
+ /** Fingertips public health indicator metadata, keyless. */
66
+ export declare const fingertipsIndicatorsAdapter: UkDataAdapter<FingertipsIndicatorMetadata[]>;
67
+ //# sourceMappingURL=fingertipsIndicators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingertipsIndicators.d.ts","sourceRoot":"","sources":["../src/fingertipsIndicators.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,+BAA+B,0BAA0B,CAAC;AAEvE,2DAA2D;AAC3D,eAAO,MAAM,iCAAiC,yEAC0B,CAAC;AAEzE,yEAAyE;AACzE,eAAO,MAAM,gCAAgC,EAAE,MAAM,EAAY,CAAC;AAElE,8DAA8D;AAC9D,MAAM,WAAW,2BAA2B;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,6EAA6E;IAC7E,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,cAAc,EAAE,MAAM,CAAC;IACvB,wEAAwE;IACxE,6BAA6B,EAAE,MAAM,CAAC;CACvC;AAED,uDAAuD;AACvD,MAAM,WAAW,2BAA2B;IAC1C,cAAc,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAkBD;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,MAAM,CAE1E;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,2BAA2B,EAAE,CAezF;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,2BAA2B,EAAE,GACxC,2BAA2B,CAK7B;AAED;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CAAO,GAC7E,OAAO,CAAC,2BAA2B,EAAE,CAAC,CAOxC;AAED,4DAA4D;AAC5D,eAAO,MAAM,2BAA2B,EAAE,aAAa,CAAC,2BAA2B,EAAE,CAapF,CAAC"}
@@ -0,0 +1,94 @@
1
+ import { z } from 'zod';
2
+ import { UkSourceApiError, UkSourceParseError } from './errors.js';
3
+ import { readFixtureJson } from './fixtures.js';
4
+ /**
5
+ * The Office for Health Improvement and Disparities public health profiles,
6
+ * published by Fingertips. Keyless, under the Open Government Licence v3.
7
+ */
8
+ export const FINGERTIPS_INDICATORS_SOURCE_ID = 'fingertips-indicators';
9
+ /** Base URL for the Fingertips indicator metadata call. */
10
+ export const FINGERTIPS_INDICATOR_METADATA_URL = 'https://fingertips.phe.org.uk/api/indicator_metadata/by_indicator_id';
11
+ /** The indicator the adapter reads when the caller does not name one. */
12
+ export const DEFAULT_FINGERTIPS_INDICATOR_IDS = [90366];
13
+ const FINGERTIPS_INDICATOR_SCHEMA = z.object({
14
+ IID: z.number(),
15
+ LatestChangeTimestampOverride: z.string().nullable().optional(),
16
+ Unit: z.object({ Label: z.string() }).nullable().optional(),
17
+ YearType: z.object({ Name: z.string() }).nullable().optional(),
18
+ ValueType: z.object({ Name: z.string() }).nullable().optional(),
19
+ Descriptive: z
20
+ .object({ Name: z.string(), DataSource: z.string().nullable().optional() })
21
+ .nullable()
22
+ .optional(),
23
+ DataChange: z.object({ LastUploadedAt: z.string().nullable().optional() }).nullable().optional(),
24
+ });
25
+ /** Indicator metadata keyed by indicator id, as Fingertips returns it. */
26
+ const FINGERTIPS_INDICATORS_SCHEMA = z.record(z.string(), FINGERTIPS_INDICATOR_SCHEMA);
27
+ /**
28
+ * Builds the Fingertips indicator metadata URL for a set of indicator ids.
29
+ *
30
+ * @param indicatorIds - the indicator ids to read
31
+ * @returns the metadata URL, ids comma-separated
32
+ */
33
+ export function buildFingertipsIndicatorUrl(indicatorIds) {
34
+ return `${FINGERTIPS_INDICATOR_METADATA_URL}?indicator_ids=${indicatorIds.join(',')}`;
35
+ }
36
+ /**
37
+ * Parses a Fingertips indicator metadata payload.
38
+ *
39
+ * @param payload - the raw JSON body from the metadata endpoint
40
+ * @returns one entry per indicator the payload carries
41
+ */
42
+ export function parseFingertipsIndicators(payload) {
43
+ const parsed = FINGERTIPS_INDICATORS_SCHEMA.safeParse(payload);
44
+ if (!parsed.success) {
45
+ throw new UkSourceParseError('fingertips-indicators', parsed.error.message);
46
+ }
47
+ return Object.values(parsed.data).map((indicator) => ({
48
+ indicatorId: indicator.IID,
49
+ name: indicator.Descriptive?.Name ?? '',
50
+ dataSource: indicator.Descriptive?.DataSource ?? '',
51
+ unitLabel: indicator.Unit?.Label ?? '',
52
+ valueType: indicator.ValueType?.Name ?? '',
53
+ yearType: indicator.YearType?.Name ?? '',
54
+ lastUploadedAt: indicator.DataChange?.LastUploadedAt ?? '',
55
+ latestChangeTimestampOverride: indicator.LatestChangeTimestampOverride ?? '',
56
+ }));
57
+ }
58
+ /**
59
+ * Sums the indicators a call returns.
60
+ *
61
+ * @param indicators - indicators from {@link parseFingertipsIndicators}
62
+ * @returns the indicator count and the distinct data sources behind them
63
+ */
64
+ export function summarizeFingertipsIndicators(indicators) {
65
+ const dataSources = [...new Set(indicators.map((indicator) => indicator.dataSource))]
66
+ .filter((dataSource) => dataSource !== '')
67
+ .sort((left, right) => left.localeCompare(right));
68
+ return { indicatorCount: indicators.length, dataSources };
69
+ }
70
+ /**
71
+ * Reads metadata for a set of Fingertips public health indicators.
72
+ *
73
+ * @param options - indicator ids and an optional fetch implementation
74
+ * @returns the indicator metadata the endpoint returns
75
+ */
76
+ export async function fetchFingertipsIndicators(options = {}) {
77
+ const { indicatorIds = DEFAULT_FINGERTIPS_INDICATOR_IDS, fetchImpl = globalThis.fetch } = options;
78
+ const response = await fetchImpl(buildFingertipsIndicatorUrl(indicatorIds));
79
+ if (!response.ok) {
80
+ throw new UkSourceApiError('fingertips-indicators', `HTTP ${response.status} reading metadata`);
81
+ }
82
+ return parseFingertipsIndicators(await response.json());
83
+ }
84
+ /** Fingertips public health indicator metadata, keyless. */
85
+ export const fingertipsIndicatorsAdapter = {
86
+ id: FINGERTIPS_INDICATORS_SOURCE_ID,
87
+ name: 'Office for Health Improvement and Disparities Fingertips indicators',
88
+ auth: 'none',
89
+ description: 'Metadata for the public health indicators Fingertips publishes, with their sources.',
90
+ fetchLive: (options) => fetchFingertipsIndicators(options?.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
91
+ parse: parseFingertipsIndicators,
92
+ loadFixture: () => parseFingertipsIndicators(readFixtureJson('fingertips-indicators-2026-10-05.json')),
93
+ };
94
+ //# sourceMappingURL=fingertipsIndicators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingertipsIndicators.js","sourceRoot":"","sources":["../src/fingertipsIndicators.ts"],"names":[],"mappings":"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"}