@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
@@ -0,0 +1,55 @@
1
+ import type { UkDataAdapter } from './types.js';
2
+ /**
3
+ * postcodes.io, a free keyless lookup over ONS and Ordnance Survey postcode
4
+ * data published under the Open Government Licence v3. The service itself is
5
+ * a third party, not a government API: the postcode data is OGL, the lookup
6
+ * and the geocoding around it are postcodes.io's own.
7
+ */
8
+ export declare const POSTCODE_LOOKUP_SOURCE_ID = "postcode-lookup";
9
+ /** Base URL for the postcodes.io single postcode lookup. */
10
+ export declare const POSTCODES_IO_BASE_URL = "https://api.postcodes.io/postcodes/";
11
+ /** The postcode the adapter looks up when the caller does not name one. */
12
+ export declare const DEFAULT_POSTCODE_QUERY = "SW1A1AA";
13
+ /** One postcode and the administrative areas it falls inside. */
14
+ export interface PostcodeLookupRecord {
15
+ /** The postcode as the service formats it, letters and digits spaced. */
16
+ postcode: string;
17
+ country: string;
18
+ /** English region or devolved nation region, or null when unset. */
19
+ region: string | null;
20
+ adminDistrict: string | null;
21
+ adminWard: string | null;
22
+ parliamentaryConstituency: string | null;
23
+ latitude: number;
24
+ longitude: number;
25
+ /** The NHS area the postcode sits in, or null when unset. */
26
+ nhsHa: string | null;
27
+ }
28
+ /**
29
+ * Builds the postcodes.io lookup URL for one postcode.
30
+ *
31
+ * @param postcode - the postcode to look up, spaced or unspaced
32
+ * @returns the single postcode lookup URL
33
+ */
34
+ export declare function buildPostcodeLookupUrl(postcode: string): string;
35
+ /**
36
+ * Parses a postcodes.io single postcode payload.
37
+ *
38
+ * @param payload - the raw JSON body from the lookup endpoint
39
+ * @returns the postcode record the service returns
40
+ */
41
+ export declare function parsePostcodeLookup(payload: unknown): PostcodeLookupRecord;
42
+ /**
43
+ * Looks up one postcode. The service answers 404 for an unknown postcode,
44
+ * which becomes an API error like any other failed request.
45
+ *
46
+ * @param postcode - the postcode to look up, default SW1A 1AA
47
+ * @param options - an optional fetch implementation
48
+ * @returns the postcode record the service returns
49
+ */
50
+ export declare function fetchPostcodeLookup(postcode?: string, options?: {
51
+ fetchImpl?: typeof globalThis.fetch;
52
+ }): Promise<PostcodeLookupRecord>;
53
+ /** postcodes.io single postcode lookup, keyless. */
54
+ export declare const postcodeLookupAdapter: UkDataAdapter<PostcodeLookupRecord>;
55
+ //# sourceMappingURL=postcodeLookup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postcodeLookup.d.ts","sourceRoot":"","sources":["../src/postcodeLookup.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,oBAAoB,CAAC;AAE3D,4DAA4D;AAC5D,eAAO,MAAM,qBAAqB,wCAAwC,CAAC;AAE3E,2EAA2E;AAC3E,eAAO,MAAM,sBAAsB,YAAY,CAAC;AAEhD,iEAAiE;AACjE,MAAM,WAAW,oBAAoB;IACnC,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,yBAAyB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAmBD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,oBAAoB,CAiB1E;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,GAAE,MAA+B,EACzC,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CAAO,GACpD,OAAO,CAAC,oBAAoB,CAAC,CAO/B;AAED,oDAAoD;AACpD,eAAO,MAAM,qBAAqB,EAAE,aAAa,CAAC,oBAAoB,CAYrE,CAAC"}
@@ -0,0 +1,89 @@
1
+ import { z } from 'zod';
2
+ import { UkSourceApiError, UkSourceParseError } from './errors.js';
3
+ import { readFixtureJson } from './fixtures.js';
4
+ /**
5
+ * postcodes.io, a free keyless lookup over ONS and Ordnance Survey postcode
6
+ * data published under the Open Government Licence v3. The service itself is
7
+ * a third party, not a government API: the postcode data is OGL, the lookup
8
+ * and the geocoding around it are postcodes.io's own.
9
+ */
10
+ export const POSTCODE_LOOKUP_SOURCE_ID = 'postcode-lookup';
11
+ /** Base URL for the postcodes.io single postcode lookup. */
12
+ export const POSTCODES_IO_BASE_URL = 'https://api.postcodes.io/postcodes/';
13
+ /** The postcode the adapter looks up when the caller does not name one. */
14
+ export const DEFAULT_POSTCODE_QUERY = 'SW1A1AA';
15
+ const POSTCODE_RESULT_SCHEMA = z.object({
16
+ postcode: z.string(),
17
+ country: z.string(),
18
+ region: z.string().nullable().optional(),
19
+ admin_district: z.string().nullable().optional(),
20
+ admin_ward: z.string().nullable().optional(),
21
+ parliamentary_constituency: z.string().nullable().optional(),
22
+ latitude: z.number(),
23
+ longitude: z.number(),
24
+ nhs_ha: z.string().nullable().optional(),
25
+ });
26
+ const POSTCODE_LOOKUP_SCHEMA = z.object({
27
+ status: z.number(),
28
+ result: POSTCODE_RESULT_SCHEMA,
29
+ });
30
+ /**
31
+ * Builds the postcodes.io lookup URL for one postcode.
32
+ *
33
+ * @param postcode - the postcode to look up, spaced or unspaced
34
+ * @returns the single postcode lookup URL
35
+ */
36
+ export function buildPostcodeLookupUrl(postcode) {
37
+ return `${POSTCODES_IO_BASE_URL}${encodeURIComponent(postcode)}`;
38
+ }
39
+ /**
40
+ * Parses a postcodes.io single postcode payload.
41
+ *
42
+ * @param payload - the raw JSON body from the lookup endpoint
43
+ * @returns the postcode record the service returns
44
+ */
45
+ export function parsePostcodeLookup(payload) {
46
+ const parsed = POSTCODE_LOOKUP_SCHEMA.safeParse(payload);
47
+ if (!parsed.success) {
48
+ throw new UkSourceParseError('postcode-lookup', parsed.error.message);
49
+ }
50
+ const result = parsed.data.result;
51
+ return {
52
+ postcode: result.postcode,
53
+ country: result.country,
54
+ region: result.region ?? null,
55
+ adminDistrict: result.admin_district ?? null,
56
+ adminWard: result.admin_ward ?? null,
57
+ parliamentaryConstituency: result.parliamentary_constituency ?? null,
58
+ latitude: result.latitude,
59
+ longitude: result.longitude,
60
+ nhsHa: result.nhs_ha ?? null,
61
+ };
62
+ }
63
+ /**
64
+ * Looks up one postcode. The service answers 404 for an unknown postcode,
65
+ * which becomes an API error like any other failed request.
66
+ *
67
+ * @param postcode - the postcode to look up, default SW1A 1AA
68
+ * @param options - an optional fetch implementation
69
+ * @returns the postcode record the service returns
70
+ */
71
+ export async function fetchPostcodeLookup(postcode = DEFAULT_POSTCODE_QUERY, options = {}) {
72
+ const { fetchImpl = globalThis.fetch } = options;
73
+ const response = await fetchImpl(buildPostcodeLookupUrl(postcode));
74
+ if (!response.ok) {
75
+ throw new UkSourceApiError('postcode-lookup', `HTTP ${response.status} looking up ${postcode}`);
76
+ }
77
+ return parsePostcodeLookup(await response.json());
78
+ }
79
+ /** postcodes.io single postcode lookup, keyless. */
80
+ export const postcodeLookupAdapter = {
81
+ id: POSTCODE_LOOKUP_SOURCE_ID,
82
+ name: 'postcodes.io postcode lookup',
83
+ auth: 'none',
84
+ description: `One postcode's country, region, wards, and coordinates, default ${DEFAULT_POSTCODE_QUERY}.`,
85
+ fetchLive: (options) => fetchPostcodeLookup(DEFAULT_POSTCODE_QUERY, options?.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
86
+ parse: parsePostcodeLookup,
87
+ loadFixture: () => parsePostcodeLookup(readFixtureJson('postcode-lookup-2026-10-05.json')),
88
+ };
89
+ //# sourceMappingURL=postcodeLookup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postcodeLookup.js","sourceRoot":"","sources":["../src/postcodeLookup.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;;;;;GAKG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,iBAAiB,CAAC;AAE3D,4DAA4D;AAC5D,MAAM,CAAC,MAAM,qBAAqB,GAAG,qCAAqC,CAAC;AAE3E,2EAA2E;AAC3E,MAAM,CAAC,MAAM,sBAAsB,GAAG,SAAS,CAAC;AAkBhD,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACxC,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,0BAA0B,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAC5D,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;CACzC,CAAC,CAAC;AAEH,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,MAAM,EAAE,sBAAsB;CAC/B,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,QAAgB;IACrD,OAAO,GAAG,qBAAqB,GAAG,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;AACnE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,MAAM,MAAM,GAAG,sBAAsB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACzD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,kBAAkB,CAAC,iBAAiB,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;IAClC,OAAO;QACL,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,IAAI;QAC7B,aAAa,EAAE,MAAM,CAAC,cAAc,IAAI,IAAI;QAC5C,SAAS,EAAE,MAAM,CAAC,UAAU,IAAI,IAAI;QACpC,yBAAyB,EAAE,MAAM,CAAC,0BAA0B,IAAI,IAAI;QACpE,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,IAAI,IAAI;KAC7B,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,WAAmB,sBAAsB,EACzC,UAAmD,EAAE;IAErD,MAAM,EAAE,SAAS,GAAG,UAAU,CAAC,KAAK,EAAE,GAAG,OAAO,CAAC;IACjD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC,CAAC;IACnE,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,gBAAgB,CAAC,iBAAiB,EAAE,QAAQ,QAAQ,CAAC,MAAM,eAAe,QAAQ,EAAE,CAAC,CAAC;IAClG,CAAC;IACD,OAAO,mBAAmB,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;AACpD,CAAC;AAED,oDAAoD;AACpD,MAAM,CAAC,MAAM,qBAAqB,GAAwC;IACxE,EAAE,EAAE,yBAAyB;IAC7B,IAAI,EAAE,8BAA8B;IACpC,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,mEAAmE,sBAAsB,GAAG;IACzG,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CACrB,mBAAmB,CACjB,sBAAsB,EACtB,OAAO,EAAE,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CACzE;IACH,KAAK,EAAE,mBAAmB;IAC1B,WAAW,EAAE,GAAG,EAAE,CAAC,mBAAmB,CAAC,eAAe,CAAC,iCAAiC,CAAC,CAAC;CAC3F,CAAC"}
@@ -0,0 +1,43 @@
1
+ import type { UkDataAdapter } from './types.js';
2
+ /**
3
+ * Public Health Scotland's open data portal, served by CKAN. Keyless, and the
4
+ * datasets are published under the Open Government Licence v3.
5
+ */
6
+ export declare const PUBLIC_HEALTH_SCOTLAND_SOURCE_ID = "public-health-scotland";
7
+ /** The CKAN package_list call on the Public Health Scotland portal. */
8
+ export declare const PUBLIC_HEALTH_SCOTLAND_PACKAGE_LIST_URL = "https://www.opendata.nhs.scot/api/3/action/package_list";
9
+ /** One dataset in the Public Health Scotland catalogue. */
10
+ export interface PublicHealthScotlandDataset {
11
+ /** CKAN package name, the identifier used in every other CKAN call. */
12
+ name: string;
13
+ }
14
+ /** Rolled-up view of the Public Health Scotland catalogue. */
15
+ export interface PublicHealthScotlandSummary {
16
+ packageCount: number;
17
+ }
18
+ /**
19
+ * Parses a Public Health Scotland package_list payload.
20
+ *
21
+ * @param payload - the raw JSON body from the CKAN package_list call
22
+ * @returns one entry per dataset in the catalogue
23
+ */
24
+ export declare function parsePublicHealthScotlandDatasets(payload: unknown): PublicHealthScotlandDataset[];
25
+ /**
26
+ * Counts the Public Health Scotland catalogue.
27
+ *
28
+ * @param datasets - dataset names from {@link parsePublicHealthScotlandDatasets}
29
+ * @returns the number of datasets listed
30
+ */
31
+ export declare function summarizePublicHealthScotlandDatasets(datasets: PublicHealthScotlandDataset[]): PublicHealthScotlandSummary;
32
+ /**
33
+ * Lists every dataset in the Public Health Scotland catalogue.
34
+ *
35
+ * @param options - an optional fetch implementation
36
+ * @returns the package names the catalogue returns
37
+ */
38
+ export declare function fetchPublicHealthScotlandDatasets(options?: {
39
+ fetchImpl?: typeof globalThis.fetch;
40
+ }): Promise<PublicHealthScotlandDataset[]>;
41
+ /** Public Health Scotland open data catalogue, keyless. */
42
+ export declare const publicHealthScotlandAdapter: UkDataAdapter<PublicHealthScotlandDataset[]>;
43
+ //# sourceMappingURL=publicHealthScotland.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publicHealthScotland.d.ts","sourceRoot":"","sources":["../src/publicHealthScotland.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,gCAAgC,2BAA2B,CAAC;AAEzE,uEAAuE;AACvE,eAAO,MAAM,uCAAuC,4DACO,CAAC;AAE5D,2DAA2D;AAC3D,MAAM,WAAW,2BAA2B;IAC1C,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;CACd;AAED,8DAA8D;AAC9D,MAAM,WAAW,2BAA2B;IAC1C,YAAY,EAAE,MAAM,CAAC;CACtB;AAOD;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAAC,OAAO,EAAE,OAAO,GAAG,2BAA2B,EAAE,CAMjG;AAED;;;;;GAKG;AACH,wBAAgB,qCAAqC,CACnD,QAAQ,EAAE,2BAA2B,EAAE,GACtC,2BAA2B,CAE7B;AAED;;;;;GAKG;AACH,wBAAsB,iCAAiC,CACrD,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CAAO,GACpD,OAAO,CAAC,2BAA2B,EAAE,CAAC,CAUxC;AAED,2DAA2D;AAC3D,eAAO,MAAM,2BAA2B,EAAE,aAAa,CAAC,2BAA2B,EAAE,CAYpF,CAAC"}
@@ -0,0 +1,61 @@
1
+ import { z } from 'zod';
2
+ import { UkSourceApiError, UkSourceParseError } from './errors.js';
3
+ import { readFixtureJson } from './fixtures.js';
4
+ /**
5
+ * Public Health Scotland's open data portal, served by CKAN. Keyless, and the
6
+ * datasets are published under the Open Government Licence v3.
7
+ */
8
+ export const PUBLIC_HEALTH_SCOTLAND_SOURCE_ID = 'public-health-scotland';
9
+ /** The CKAN package_list call on the Public Health Scotland portal. */
10
+ export const PUBLIC_HEALTH_SCOTLAND_PACKAGE_LIST_URL = 'https://www.opendata.nhs.scot/api/3/action/package_list';
11
+ const PUBLIC_HEALTH_SCOTLAND_PACKAGE_LIST_SCHEMA = z.object({
12
+ success: z.boolean(),
13
+ result: z.array(z.string()),
14
+ });
15
+ /**
16
+ * Parses a Public Health Scotland package_list payload.
17
+ *
18
+ * @param payload - the raw JSON body from the CKAN package_list call
19
+ * @returns one entry per dataset in the catalogue
20
+ */
21
+ export function parsePublicHealthScotlandDatasets(payload) {
22
+ const parsed = PUBLIC_HEALTH_SCOTLAND_PACKAGE_LIST_SCHEMA.safeParse(payload);
23
+ if (!parsed.success) {
24
+ throw new UkSourceParseError('public-health-scotland', parsed.error.message);
25
+ }
26
+ return parsed.data.result.map((name) => ({ name }));
27
+ }
28
+ /**
29
+ * Counts the Public Health Scotland catalogue.
30
+ *
31
+ * @param datasets - dataset names from {@link parsePublicHealthScotlandDatasets}
32
+ * @returns the number of datasets listed
33
+ */
34
+ export function summarizePublicHealthScotlandDatasets(datasets) {
35
+ return { packageCount: datasets.length };
36
+ }
37
+ /**
38
+ * Lists every dataset in the Public Health Scotland catalogue.
39
+ *
40
+ * @param options - an optional fetch implementation
41
+ * @returns the package names the catalogue returns
42
+ */
43
+ export async function fetchPublicHealthScotlandDatasets(options = {}) {
44
+ const { fetchImpl = globalThis.fetch } = options;
45
+ const response = await fetchImpl(PUBLIC_HEALTH_SCOTLAND_PACKAGE_LIST_URL);
46
+ if (!response.ok) {
47
+ throw new UkSourceApiError('public-health-scotland', `HTTP ${response.status} listing packages`);
48
+ }
49
+ return parsePublicHealthScotlandDatasets(await response.json());
50
+ }
51
+ /** Public Health Scotland open data catalogue, keyless. */
52
+ export const publicHealthScotlandAdapter = {
53
+ id: PUBLIC_HEALTH_SCOTLAND_SOURCE_ID,
54
+ name: 'Public Health Scotland open data catalogue',
55
+ auth: 'none',
56
+ description: 'Every dataset Public Health Scotland publishes on its open data portal.',
57
+ fetchLive: (options) => fetchPublicHealthScotlandDatasets(options?.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
58
+ parse: parsePublicHealthScotlandDatasets,
59
+ loadFixture: () => parsePublicHealthScotlandDatasets(readFixtureJson('public-health-scotland-2026-10-05.json')),
60
+ };
61
+ //# sourceMappingURL=publicHealthScotland.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publicHealthScotland.js","sourceRoot":"","sources":["../src/publicHealthScotland.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,gCAAgC,GAAG,wBAAwB,CAAC;AAEzE,uEAAuE;AACvE,MAAM,CAAC,MAAM,uCAAuC,GAClD,yDAAyD,CAAC;AAa5D,MAAM,0CAA0C,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1D,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE;IACpB,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;CAC5B,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,UAAU,iCAAiC,CAAC,OAAgB;IAChE,MAAM,MAAM,GAAG,0CAA0C,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC7E,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,kBAAkB,CAAC,wBAAwB,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/E,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACtD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qCAAqC,CACnD,QAAuC;IAEvC,OAAO,EAAE,YAAY,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;AAC3C,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,iCAAiC,CACrD,UAAmD,EAAE;IAErD,MAAM,EAAE,SAAS,GAAG,UAAU,CAAC,KAAK,EAAE,GAAG,OAAO,CAAC;IACjD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,uCAAuC,CAAC,CAAC;IAC1E,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,gBAAgB,CACxB,wBAAwB,EACxB,QAAQ,QAAQ,CAAC,MAAM,mBAAmB,CAC3C,CAAC;IACJ,CAAC;IACD,OAAO,iCAAiC,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;AAClE,CAAC;AAED,2DAA2D;AAC3D,MAAM,CAAC,MAAM,2BAA2B,GAAiD;IACvF,EAAE,EAAE,gCAAgC;IACpC,IAAI,EAAE,4CAA4C;IAClD,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,yEAAyE;IACtF,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CACrB,iCAAiC,CAC/B,OAAO,EAAE,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CACzE;IACH,KAAK,EAAE,iCAAiC;IACxC,WAAW,EAAE,GAAG,EAAE,CAChB,iCAAiC,CAAC,eAAe,CAAC,wCAAwC,CAAC,CAAC;CAC/F,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAkB,aAAa,EAAE,MAAM,YAAY,CAAC;AAE/E,iEAAiE;AACjE,eAAO,MAAM,eAAe,EAAE,aAAa,CAAC,OAAO,CAAC,EAYnD,CAAC;AAEF,uCAAuC;AACvC,wBAAgB,eAAe,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,SAAS,CAE3E;AAED,mEAAmE;AACnE,wBAAsB,iBAAiB,CAAC,CAAC,EACvC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,EACzB,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CAAE,GACjE,OAAO,CAAC,aAAa,CAAC,CAwBxB;AAED,iFAAiF;AACjF,wBAAsB,qBAAqB,CAAC,OAAO,CAAC,EAAE;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACrC,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAW3B"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,aAAa,EAAkB,aAAa,EAAE,MAAM,YAAY,CAAC;AAE/E,iEAAiE;AACjE,eAAO,MAAM,eAAe,EAAE,aAAa,CAAC,OAAO,CAAC,EAuBnD,CAAC;AAEF,uCAAuC;AACvC,wBAAgB,eAAe,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,SAAS,CAE3E;AAED,mEAAmE;AACnE,wBAAsB,iBAAiB,CAAC,CAAC,EACvC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,EACzB,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CAAE,GACjE,OAAO,CAAC,aAAa,CAAC,CAwBxB;AAED,iFAAiF;AACjF,wBAAsB,qBAAqB,CAAC,OAAO,CAAC,EAAE;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACrC,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAW3B"}
package/dist/registry.js CHANGED
@@ -1,13 +1,24 @@
1
1
  import { ancientWoodlandAdapter } from './ancientWoodland.js';
2
2
  import { bankRateAdapter } from './bankRate.js';
3
3
  import { carbonIntensityAdapter } from './carbonIntensity.js';
4
+ import { exploreEducationStatisticsAdapter } from './exploreEducationStatistics.js';
5
+ import { findATenderAdapter } from './findATender.js';
6
+ import { fingertipsIndicatorsAdapter } from './fingertipsIndicators.js';
4
7
  import { floodReadingsAdapter, floodStationsAdapter } from './floodMonitoring.js';
5
8
  import { foodHygieneAuthoritiesAdapter } from './foodHygiene.js';
9
+ import { londonDatastoreAdapter } from './londonDatastore.js';
10
+ import { nhsbsaCkanAdapter } from './nhsbsaCkan.js';
11
+ import { nomisAdapter } from './nomis.js';
6
12
  import { onsDatasetsAdapter } from './onsDatasets.js';
7
13
  import { parliamentSeatsAdapter } from './parliamentSeats.js';
8
14
  import { planningDatasetsAdapter } from './planningDatasets.js';
9
15
  import { policeCrimesAdapter } from './policeCrimes.js';
16
+ import { postcodeLookupAdapter } from './postcodeLookup.js';
17
+ import { publicHealthScotlandAdapter } from './publicHealthScotland.js';
10
18
  import { tflBikePointsAdapter } from './tflBikePoints.js';
19
+ import { tflLineStatusAdapter } from './tflLineStatus.js';
20
+ import { tnaDiscoveryAdapter } from './tnaDiscovery.js';
21
+ import { ukhsaDashboardAdapter } from './ukhsaDashboard.js';
11
22
  /** Every UK data source behind the uniform adapter interface. */
12
23
  export const UK_DATA_SOURCES = [
13
24
  floodStationsAdapter,
@@ -21,6 +32,17 @@ export const UK_DATA_SOURCES = [
21
32
  policeCrimesAdapter,
22
33
  carbonIntensityAdapter,
23
34
  parliamentSeatsAdapter,
35
+ postcodeLookupAdapter,
36
+ exploreEducationStatisticsAdapter,
37
+ londonDatastoreAdapter,
38
+ tnaDiscoveryAdapter,
39
+ ukhsaDashboardAdapter,
40
+ nomisAdapter,
41
+ fingertipsIndicatorsAdapter,
42
+ findATenderAdapter,
43
+ tflLineStatusAdapter,
44
+ publicHealthScotlandAdapter,
45
+ nhsbsaCkanAdapter,
24
46
  ];
25
47
  /** Looks up a source adapter by id. */
26
48
  export function getUkDataSource(id) {
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ import type { UkDataAdapter } from './types.js';
2
+ /**
3
+ * Transport for London's live Tube line status. Keyless: the endpoint answers
4
+ * without an app key, and TfL asks for one only above the free rate limit.
5
+ * Published as TfL Open Data.
6
+ */
7
+ export declare const TFL_LINE_STATUS_SOURCE_ID = "tfl-line-status";
8
+ /** The Tube line status endpoint, covering every Tube line at once. */
9
+ export declare const TFL_LINE_STATUS_URL = "https://api.tfl.gov.uk/Line/Mode/tube/Status";
10
+ /** TfL's severity code for a line running a good service. */
11
+ export declare const TFL_LINE_STATUS_GOOD_SERVICE_SEVERITY = 10;
12
+ /** One Tube line and the service status TfL reports for it. */
13
+ export interface TflLineStatus {
14
+ /** TfL's line id, such as "bakerloo". */
15
+ id: string;
16
+ name: string;
17
+ modeName: string;
18
+ /** TfL's numeric severity, 10 for a good service. */
19
+ statusSeverity: number;
20
+ /** TfL's own wording for the severity, such as "Minor Delays". */
21
+ statusSeverityDescription: string;
22
+ /** The operator's explanation, or "" when there is nothing to explain. */
23
+ reason: string;
24
+ }
25
+ /** Rolled-up view of the Tube line status list. */
26
+ export interface TflLineStatusSummary {
27
+ lineCount: number;
28
+ /** Lines TfL reports at good-service severity. */
29
+ goodServiceCount: number;
30
+ /** The lines running below a good service, in TfL's order. */
31
+ disruptedLines: TflLineStatus[];
32
+ }
33
+ /**
34
+ * Parses a TfL line status payload into one record per line.
35
+ *
36
+ * @param payload - the raw JSON body from the line status endpoint
37
+ * @returns one record per Tube line, in TfL's order
38
+ */
39
+ export declare function parseTflLineStatuses(payload: unknown): TflLineStatus[];
40
+ /**
41
+ * Counts the lines and keeps the ones running below a good service.
42
+ *
43
+ * @param lines - lines from {@link parseTflLineStatuses}
44
+ * @returns line and good-service counts plus the disrupted lines
45
+ */
46
+ export declare function summarizeTflLineStatuses(lines: TflLineStatus[]): TflLineStatusSummary;
47
+ /**
48
+ * Reads the live status of every Tube line from TfL.
49
+ *
50
+ * @param options - an optional app key and fetch implementation
51
+ * @returns the line statuses the endpoint returns
52
+ */
53
+ export declare function fetchTflLineStatuses(options?: {
54
+ apiKey?: string;
55
+ fetchImpl?: typeof globalThis.fetch;
56
+ }): Promise<TflLineStatus[]>;
57
+ /** Transport for London Tube line status, keyless. */
58
+ export declare const tflLineStatusAdapter: UkDataAdapter<TflLineStatus[]>;
59
+ //# sourceMappingURL=tflLineStatus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tflLineStatus.d.ts","sourceRoot":"","sources":["../src/tflLineStatus.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,oBAAoB,CAAC;AAE3D,uEAAuE;AACvE,eAAO,MAAM,mBAAmB,iDAAiD,CAAC;AAElF,6DAA6D;AAC7D,eAAO,MAAM,qCAAqC,KAAK,CAAC;AAExD,+DAA+D;AAC/D,MAAM,WAAW,aAAa;IAC5B,yCAAyC;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,cAAc,EAAE,MAAM,CAAC;IACvB,kEAAkE;IAClE,yBAAyB,EAAE,MAAM,CAAC;IAClC,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,mDAAmD;AACnD,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,gBAAgB,EAAE,MAAM,CAAC;IACzB,8DAA8D;IAC9D,cAAc,EAAE,aAAa,EAAE,CAAC;CACjC;AAkBD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,aAAa,EAAE,CAgBtE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,oBAAoB,CAUrF;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CAAO,GACrE,OAAO,CAAC,aAAa,EAAE,CAAC,CAW1B;AAED,sDAAsD;AACtD,eAAO,MAAM,oBAAoB,EAAE,aAAa,CAAC,aAAa,EAAE,CAY/D,CAAC"}
@@ -0,0 +1,93 @@
1
+ import { z } from 'zod';
2
+ import { UkSourceApiError, UkSourceParseError } from './errors.js';
3
+ import { readFixtureJson } from './fixtures.js';
4
+ /**
5
+ * Transport for London's live Tube line status. Keyless: the endpoint answers
6
+ * without an app key, and TfL asks for one only above the free rate limit.
7
+ * Published as TfL Open Data.
8
+ */
9
+ export const TFL_LINE_STATUS_SOURCE_ID = 'tfl-line-status';
10
+ /** The Tube line status endpoint, covering every Tube line at once. */
11
+ export const TFL_LINE_STATUS_URL = 'https://api.tfl.gov.uk/Line/Mode/tube/Status';
12
+ /** TfL's severity code for a line running a good service. */
13
+ export const TFL_LINE_STATUS_GOOD_SERVICE_SEVERITY = 10;
14
+ const TFL_LINE_STATUS_ENTRY_SCHEMA = z.object({
15
+ id: z.number(),
16
+ statusSeverity: z.number(),
17
+ statusSeverityDescription: z.string(),
18
+ reason: z.string().optional(),
19
+ });
20
+ const TFL_LINE_SCHEMA = z.object({
21
+ id: z.string(),
22
+ name: z.string(),
23
+ modeName: z.string(),
24
+ lineStatuses: z.array(TFL_LINE_STATUS_ENTRY_SCHEMA).min(1),
25
+ });
26
+ const TFL_LINES_SCHEMA = z.array(TFL_LINE_SCHEMA);
27
+ /**
28
+ * Parses a TfL line status payload into one record per line.
29
+ *
30
+ * @param payload - the raw JSON body from the line status endpoint
31
+ * @returns one record per Tube line, in TfL's order
32
+ */
33
+ export function parseTflLineStatuses(payload) {
34
+ const parsed = TFL_LINES_SCHEMA.safeParse(payload);
35
+ if (!parsed.success) {
36
+ throw new UkSourceParseError('tfl-line-status', parsed.error.message);
37
+ }
38
+ return parsed.data.map((line) => {
39
+ const status = line.lineStatuses[0];
40
+ return {
41
+ id: line.id,
42
+ name: line.name,
43
+ modeName: line.modeName,
44
+ statusSeverity: status?.statusSeverity ?? 0,
45
+ statusSeverityDescription: status?.statusSeverityDescription ?? '',
46
+ reason: status?.reason ?? '',
47
+ };
48
+ });
49
+ }
50
+ /**
51
+ * Counts the lines and keeps the ones running below a good service.
52
+ *
53
+ * @param lines - lines from {@link parseTflLineStatuses}
54
+ * @returns line and good-service counts plus the disrupted lines
55
+ */
56
+ export function summarizeTflLineStatuses(lines) {
57
+ return {
58
+ lineCount: lines.length,
59
+ goodServiceCount: lines.filter((line) => line.statusSeverity === TFL_LINE_STATUS_GOOD_SERVICE_SEVERITY).length,
60
+ disruptedLines: lines.filter((line) => line.statusSeverity !== TFL_LINE_STATUS_GOOD_SERVICE_SEVERITY),
61
+ };
62
+ }
63
+ /**
64
+ * Reads the live status of every Tube line from TfL.
65
+ *
66
+ * @param options - an optional app key and fetch implementation
67
+ * @returns the line statuses the endpoint returns
68
+ */
69
+ export async function fetchTflLineStatuses(options = {}) {
70
+ const { apiKey, fetchImpl = globalThis.fetch } = options;
71
+ const url = apiKey === undefined
72
+ ? TFL_LINE_STATUS_URL
73
+ : `${TFL_LINE_STATUS_URL}?app_key=${encodeURIComponent(apiKey)}`;
74
+ const response = await fetchImpl(url);
75
+ if (!response.ok) {
76
+ throw new UkSourceApiError('tfl-line-status', `HTTP ${response.status} reading line status`);
77
+ }
78
+ return parseTflLineStatuses(await response.json());
79
+ }
80
+ /** Transport for London Tube line status, keyless. */
81
+ export const tflLineStatusAdapter = {
82
+ id: TFL_LINE_STATUS_SOURCE_ID,
83
+ name: 'Transport for London Tube line status',
84
+ auth: 'none',
85
+ description: 'The live service status of every Tube line, with disruption reasons.',
86
+ fetchLive: (options) => fetchTflLineStatuses({
87
+ ...(options?.apiKey === undefined ? {} : { apiKey: options.apiKey }),
88
+ ...(options?.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
89
+ }),
90
+ parse: parseTflLineStatuses,
91
+ loadFixture: () => parseTflLineStatuses(readFixtureJson('tfl-line-status-2026-10-05.json')),
92
+ };
93
+ //# sourceMappingURL=tflLineStatus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tflLineStatus.js","sourceRoot":"","sources":["../src/tflLineStatus.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ import type { UkDataAdapter } from './types.js';
2
+ /**
3
+ * Discovery, The National Archives' catalogue search API. Keyless, and the
4
+ * catalogue metadata is published under the Open Government Licence v3.
5
+ */
6
+ export declare const TNA_DISCOVERY_SOURCE_ID = "tna-discovery";
7
+ /** Base URL for the Discovery record search. */
8
+ export declare const TNA_DISCOVERY_SEARCH_URL = "https://discovery.nationalarchives.gov.uk/API/search/records";
9
+ /**
10
+ * The header Discovery expects for a JSON answer. On 2026-10-05 the endpoint
11
+ * also answered JSON without it, but the adapter sends it either way.
12
+ */
13
+ export declare const TNA_DISCOVERY_ACCEPT_HEADER = "application/json";
14
+ /** The search term the adapter asks for when the caller does not name one. */
15
+ export declare const DEFAULT_TNA_DISCOVERY_QUERY = "test";
16
+ /** One catalogue record Discovery returns for a search. */
17
+ export interface TnaDiscoveryRecord {
18
+ id: string;
19
+ /** The archive's own reference, such as a catalogue piece number. */
20
+ reference: string;
21
+ title: string;
22
+ description: string;
23
+ /** The date range the record covers, as the archive writes it. */
24
+ coveringDates: string;
25
+ /** Depth in the catalogue hierarchy, or null when the record leaves it out. */
26
+ catalogueLevel: number | null;
27
+ /** The department code the record belongs to, or "" when unset. */
28
+ department: string;
29
+ /** Repositories holding the record. */
30
+ heldBy: string[];
31
+ }
32
+ /** One page of Discovery search results plus the total hit count. */
33
+ export interface TnaDiscoverySearchResult {
34
+ /** Total records matching the query, not just this page. */
35
+ totalCount: number;
36
+ records: TnaDiscoveryRecord[];
37
+ }
38
+ /** Rolled-up view of one Discovery search page. */
39
+ export interface TnaDiscoverySearchSummary {
40
+ recordCount: number;
41
+ totalCount: number;
42
+ }
43
+ /**
44
+ * Builds a Discovery record search URL for one query.
45
+ *
46
+ * @param query - the free-text search term
47
+ * @returns the record search URL
48
+ */
49
+ export declare function buildTnaDiscoverySearchUrl(query: string): string;
50
+ /**
51
+ * Parses a Discovery record search payload.
52
+ *
53
+ * @param payload - the raw JSON body from the record search endpoint
54
+ * @returns the page of catalogue records plus the total hit count
55
+ */
56
+ export declare function parseTnaDiscoveryRecords(payload: unknown): TnaDiscoverySearchResult;
57
+ /**
58
+ * Sums one Discovery search page.
59
+ *
60
+ * @param result - a page from {@link parseTnaDiscoveryRecords}
61
+ * @returns the page size and the total hit count
62
+ */
63
+ export declare function summarizeTnaDiscoverySearch(result: TnaDiscoverySearchResult): TnaDiscoverySearchSummary;
64
+ /**
65
+ * Searches the Discovery catalogue for one query.
66
+ *
67
+ * @param options - the search term and an optional fetch implementation
68
+ * @returns the page of records the search endpoint returns
69
+ */
70
+ export declare function fetchTnaDiscoveryRecords(options?: {
71
+ query?: string;
72
+ fetchImpl?: typeof globalThis.fetch;
73
+ }): Promise<TnaDiscoverySearchResult>;
74
+ /** The National Archives Discovery catalogue search, keyless. */
75
+ export declare const tnaDiscoveryAdapter: UkDataAdapter<TnaDiscoverySearchResult>;
76
+ //# sourceMappingURL=tnaDiscovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tnaDiscovery.d.ts","sourceRoot":"","sources":["../src/tnaDiscovery.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,uBAAuB,kBAAkB,CAAC;AAEvD,gDAAgD;AAChD,eAAO,MAAM,wBAAwB,iEAC2B,CAAC;AAEjE;;;GAGG;AACH,eAAO,MAAM,2BAA2B,qBAAqB,CAAC;AAE9D,8EAA8E;AAC9E,eAAO,MAAM,2BAA2B,SAAS,CAAC;AAElD,2DAA2D;AAC3D,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,aAAa,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,qEAAqE;AACrE,MAAM,WAAW,wBAAwB;IACvC,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,kBAAkB,EAAE,CAAC;CAC/B;AAED,mDAAmD;AACnD,MAAM,WAAW,yBAAyB;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAkBD;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,wBAAwB,CAkBnF;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,wBAAwB,GAC/B,yBAAyB,CAE3B;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,wBAAwB,CAAC,CASnC;AAED,iEAAiE;AACjE,eAAO,MAAM,mBAAmB,EAAE,aAAa,CAAC,wBAAwB,CAWvE,CAAC"}