@usa-open-data-connectors/usa-sources 0.1.8 → 0.1.9

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 (113) hide show
  1. package/README.md +225 -31
  2. package/dist/btsTransportationStats.d.ts +4 -0
  3. package/dist/btsTransportationStats.d.ts.map +1 -1
  4. package/dist/btsTransportationStats.js +3 -0
  5. package/dist/btsTransportationStats.js.map +1 -1
  6. package/dist/californiaOpenDataCatalogue.d.ts +84 -0
  7. package/dist/californiaOpenDataCatalogue.d.ts.map +1 -0
  8. package/dist/californiaOpenDataCatalogue.js +153 -0
  9. package/dist/californiaOpenDataCatalogue.js.map +1 -0
  10. package/dist/cdcSocrataCatalogue.d.ts +4 -0
  11. package/dist/cdcSocrataCatalogue.d.ts.map +1 -1
  12. package/dist/cdcSocrataCatalogue.js +3 -0
  13. package/dist/cdcSocrataCatalogue.js.map +1 -1
  14. package/dist/chicagoOpenDataCatalogue.d.ts +91 -0
  15. package/dist/chicagoOpenDataCatalogue.d.ts.map +1 -0
  16. package/dist/chicagoOpenDataCatalogue.js +133 -0
  17. package/dist/chicagoOpenDataCatalogue.js.map +1 -0
  18. package/dist/coloradoOpenDataCatalogue.d.ts +42 -0
  19. package/dist/coloradoOpenDataCatalogue.d.ts.map +1 -0
  20. package/dist/coloradoOpenDataCatalogue.js +45 -0
  21. package/dist/coloradoOpenDataCatalogue.js.map +1 -0
  22. package/dist/fccSocrataCatalogue.d.ts +91 -0
  23. package/dist/fccSocrataCatalogue.d.ts.map +1 -0
  24. package/dist/fccSocrataCatalogue.js +133 -0
  25. package/dist/fccSocrataCatalogue.js.map +1 -0
  26. package/dist/federalRegisterDocuments.d.ts +78 -0
  27. package/dist/federalRegisterDocuments.d.ts.map +1 -0
  28. package/dist/federalRegisterDocuments.js +119 -0
  29. package/dist/federalRegisterDocuments.js.map +1 -0
  30. package/dist/healthdataSocrataCatalogue.d.ts +4 -0
  31. package/dist/healthdataSocrataCatalogue.d.ts.map +1 -1
  32. package/dist/healthdataSocrataCatalogue.js +3 -0
  33. package/dist/healthdataSocrataCatalogue.js.map +1 -1
  34. package/dist/http.d.ts +14 -0
  35. package/dist/http.d.ts.map +1 -1
  36. package/dist/http.js +29 -1
  37. package/dist/http.js.map +1 -1
  38. package/dist/illinoisOpenDataCatalogue.d.ts +42 -0
  39. package/dist/illinoisOpenDataCatalogue.d.ts.map +1 -0
  40. package/dist/illinoisOpenDataCatalogue.js +45 -0
  41. package/dist/illinoisOpenDataCatalogue.js.map +1 -0
  42. package/dist/index.d.ts +76 -0
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +38 -0
  45. package/dist/index.js.map +1 -1
  46. package/dist/losAngelesOpenDataCatalogue.d.ts +42 -0
  47. package/dist/losAngelesOpenDataCatalogue.d.ts.map +1 -0
  48. package/dist/losAngelesOpenDataCatalogue.js +48 -0
  49. package/dist/losAngelesOpenDataCatalogue.js.map +1 -0
  50. package/dist/michiganOpenDataCatalogue.d.ts +42 -0
  51. package/dist/michiganOpenDataCatalogue.d.ts.map +1 -0
  52. package/dist/michiganOpenDataCatalogue.js +45 -0
  53. package/dist/michiganOpenDataCatalogue.js.map +1 -0
  54. package/dist/newJerseyOpenDataCatalogue.d.ts +42 -0
  55. package/dist/newJerseyOpenDataCatalogue.d.ts.map +1 -0
  56. package/dist/newJerseyOpenDataCatalogue.js +48 -0
  57. package/dist/newJerseyOpenDataCatalogue.js.map +1 -0
  58. package/dist/nhtsaVehicleModels.d.ts +74 -0
  59. package/dist/nhtsaVehicleModels.d.ts.map +1 -0
  60. package/dist/nhtsaVehicleModels.js +139 -0
  61. package/dist/nhtsaVehicleModels.js.map +1 -0
  62. package/dist/nihReporterProjects.d.ts +98 -0
  63. package/dist/nihReporterProjects.d.ts.map +1 -0
  64. package/dist/nihReporterProjects.js +188 -0
  65. package/dist/nihReporterProjects.js.map +1 -0
  66. package/dist/nyStateOpenDataCatalogue.d.ts +91 -0
  67. package/dist/nyStateOpenDataCatalogue.d.ts.map +1 -0
  68. package/dist/nyStateOpenDataCatalogue.js +133 -0
  69. package/dist/nyStateOpenDataCatalogue.js.map +1 -0
  70. package/dist/nycOpenDataCatalogue.d.ts +4 -0
  71. package/dist/nycOpenDataCatalogue.d.ts.map +1 -1
  72. package/dist/nycOpenDataCatalogue.js +3 -0
  73. package/dist/nycOpenDataCatalogue.js.map +1 -1
  74. package/dist/oregonOpenDataCatalogue.d.ts +42 -0
  75. package/dist/oregonOpenDataCatalogue.d.ts.map +1 -0
  76. package/dist/oregonOpenDataCatalogue.js +45 -0
  77. package/dist/oregonOpenDataCatalogue.js.map +1 -0
  78. package/dist/pennsylvaniaOpenDataCatalogue.d.ts +42 -0
  79. package/dist/pennsylvaniaOpenDataCatalogue.d.ts.map +1 -0
  80. package/dist/pennsylvaniaOpenDataCatalogue.js +48 -0
  81. package/dist/pennsylvaniaOpenDataCatalogue.js.map +1 -0
  82. package/dist/registry.d.ts.map +1 -1
  83. package/dist/registry.js +38 -0
  84. package/dist/registry.js.map +1 -1
  85. package/dist/sanFranciscoOpenDataCatalogue.d.ts +42 -0
  86. package/dist/sanFranciscoOpenDataCatalogue.d.ts.map +1 -0
  87. package/dist/sanFranciscoOpenDataCatalogue.js +48 -0
  88. package/dist/sanFranciscoOpenDataCatalogue.js.map +1 -0
  89. package/dist/seattleOpenDataCatalogue.d.ts +91 -0
  90. package/dist/seattleOpenDataCatalogue.d.ts.map +1 -0
  91. package/dist/seattleOpenDataCatalogue.js +133 -0
  92. package/dist/seattleOpenDataCatalogue.js.map +1 -0
  93. package/dist/socrataCatalogue.d.ts +121 -0
  94. package/dist/socrataCatalogue.d.ts.map +1 -0
  95. package/dist/socrataCatalogue.js +151 -0
  96. package/dist/socrataCatalogue.js.map +1 -0
  97. package/dist/socrataCatalogueMetadata.d.ts +19 -0
  98. package/dist/socrataCatalogueMetadata.d.ts.map +1 -0
  99. package/dist/socrataCatalogueMetadata.js +40 -0
  100. package/dist/socrataCatalogueMetadata.js.map +1 -0
  101. package/dist/texasOpenDataCatalogue.d.ts +91 -0
  102. package/dist/texasOpenDataCatalogue.d.ts.map +1 -0
  103. package/dist/texasOpenDataCatalogue.js +133 -0
  104. package/dist/texasOpenDataCatalogue.js.map +1 -0
  105. package/dist/vermontOpenDataCatalogue.d.ts +42 -0
  106. package/dist/vermontOpenDataCatalogue.d.ts.map +1 -0
  107. package/dist/vermontOpenDataCatalogue.js +45 -0
  108. package/dist/vermontOpenDataCatalogue.js.map +1 -0
  109. package/dist/washingtonStateOpenDataCatalogue.d.ts +42 -0
  110. package/dist/washingtonStateOpenDataCatalogue.d.ts.map +1 -0
  111. package/dist/washingtonStateOpenDataCatalogue.js +48 -0
  112. package/dist/washingtonStateOpenDataCatalogue.js.map +1 -0
  113. package/package.json +1 -1
@@ -0,0 +1,42 @@
1
+ import { type SocrataCatalogue, type SocrataCatalogueCategoryCount, type SocrataCatalogueEntry } from './socrataCatalogue.js';
2
+ /** Adapter id for the San Francisco Open Data catalogue source. */
3
+ export declare const SAN_FRANCISCO_OPEN_DATA_CATALOGUE_SOURCE_ID = "san-francisco-open-data-catalogue";
4
+ /** Base URL for the San Francisco Open Data Socrata catalogue. */
5
+ export declare const SAN_FRANCISCO_OPEN_DATA_API_BASE = "https://data.sf.gov/api/views.json";
6
+ /** How many catalogue entries one request reads. */
7
+ export declare const SAN_FRANCISCO_OPEN_DATA_CATALOGUE_LIMIT = 10;
8
+ /** One catalogue entry from the San Francisco Socrata discovery API. */
9
+ export type SanFranciscoOpenDataCatalogueEntry = SocrataCatalogueEntry;
10
+ /** One city topic and how many catalogue entries carry it. */
11
+ export type SanFranciscoOpenDataCategoryCount = SocrataCatalogueCategoryCount;
12
+ /** One page of the San Francisco catalogue, folded for a story. */
13
+ export type SanFranciscoOpenDataCatalogue = SocrataCatalogue;
14
+ /**
15
+ * Builds the request URL for one page of the San Francisco catalogue.
16
+ *
17
+ * @param options - an optional entry cap
18
+ * @returns the full request URL
19
+ */
20
+ export declare function buildSanFranciscoOpenDataCatalogueUrl(options?: {
21
+ limit?: number;
22
+ }): string;
23
+ /**
24
+ * Parses one page of the San Francisco catalogue into entries and topic counts.
25
+ *
26
+ * @param payload - the JSON body from the San Francisco Socrata discovery API
27
+ * @returns the entries in the page, the counts, and the newest entry
28
+ */
29
+ export declare function parseSanFranciscoOpenDataCataloguePayload(payload: unknown): SanFranciscoOpenDataCatalogue;
30
+ /**
31
+ * Reads one page of the San Francisco Open Data catalogue.
32
+ *
33
+ * @param options - an optional entry cap and fetch stub
34
+ * @returns the entries in the page, the counts, and the newest entry
35
+ */
36
+ export declare function fetchSanFranciscoOpenDataCatalogue(options?: {
37
+ limit?: number;
38
+ fetchImpl?: typeof globalThis.fetch;
39
+ }): Promise<SanFranciscoOpenDataCatalogue>;
40
+ /** San Francisco Open Data catalogue of datasets, maps, and filtered views, keyless. */
41
+ export declare const sanFranciscoOpenDataCatalogueAdapter: import("./types.js").UsDataAdapter<SocrataCatalogue>;
42
+ //# sourceMappingURL=sanFranciscoOpenDataCatalogue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanFranciscoOpenDataCatalogue.d.ts","sourceRoot":"","sources":["../src/sanFranciscoOpenDataCatalogue.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,gBAAgB,EACrB,KAAK,6BAA6B,EAClC,KAAK,qBAAqB,EAC3B,MAAM,uBAAuB,CAAC;AAE/B,mEAAmE;AACnE,eAAO,MAAM,2CAA2C,sCAAsC,CAAC;AAE/F,kEAAkE;AAClE,eAAO,MAAM,gCAAgC,uCAAuC,CAAC;AAErF,oDAAoD;AACpD,eAAO,MAAM,uCAAuC,KAA0B,CAAC;AAE/E,wEAAwE;AACxE,MAAM,MAAM,kCAAkC,GAAG,qBAAqB,CAAC;AAEvE,8DAA8D;AAC9D,MAAM,MAAM,iCAAiC,GAAG,6BAA6B,CAAC;AAE9E,mEAAmE;AACnE,MAAM,MAAM,6BAA6B,GAAG,gBAAgB,CAAC;AAM7D;;;;;GAKG;AACH,wBAAgB,qCAAqC,CAAC,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAE1F;AAED;;;;;GAKG;AACH,wBAAgB,yCAAyC,CACvD,OAAO,EAAE,OAAO,GACf,6BAA6B,CAE/B;AAED;;;;;GAKG;AACH,wBAAsB,kCAAkC,CAAC,OAAO,CAAC,EAAE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACrC,GAAG,OAAO,CAAC,6BAA6B,CAAC,CAQzC;AAED,wFAAwF;AACxF,eAAO,MAAM,oCAAoC,sDAO/C,CAAC"}
@@ -0,0 +1,48 @@
1
+ import { buildSocrataCatalogueUrl, createSocrataCatalogueAdapter, fetchSocrataCatalogue, parseSocrataCataloguePayload, SOCRATA_CATALOGUE_LIMIT, } from './socrataCatalogue.js';
2
+ /** Adapter id for the San Francisco Open Data catalogue source. */
3
+ export const SAN_FRANCISCO_OPEN_DATA_CATALOGUE_SOURCE_ID = 'san-francisco-open-data-catalogue';
4
+ /** Base URL for the San Francisco Open Data Socrata catalogue. */
5
+ export const SAN_FRANCISCO_OPEN_DATA_API_BASE = 'https://data.sf.gov/api/views.json';
6
+ /** How many catalogue entries one request reads. */
7
+ export const SAN_FRANCISCO_OPEN_DATA_CATALOGUE_LIMIT = SOCRATA_CATALOGUE_LIMIT;
8
+ /** Committed snapshot, so a build works when the San Francisco host is unreachable. */
9
+ const SAN_FRANCISCO_OPEN_DATA_FIXTURE_FILENAME = 'san-francisco-open-data-catalogue-2026-11-08.json';
10
+ /**
11
+ * Builds the request URL for one page of the San Francisco catalogue.
12
+ *
13
+ * @param options - an optional entry cap
14
+ * @returns the full request URL
15
+ */
16
+ export function buildSanFranciscoOpenDataCatalogueUrl(options) {
17
+ return buildSocrataCatalogueUrl(SAN_FRANCISCO_OPEN_DATA_API_BASE, options);
18
+ }
19
+ /**
20
+ * Parses one page of the San Francisco catalogue into entries and topic counts.
21
+ *
22
+ * @param payload - the JSON body from the San Francisco Socrata discovery API
23
+ * @returns the entries in the page, the counts, and the newest entry
24
+ */
25
+ export function parseSanFranciscoOpenDataCataloguePayload(payload) {
26
+ return parseSocrataCataloguePayload(SAN_FRANCISCO_OPEN_DATA_CATALOGUE_SOURCE_ID, payload);
27
+ }
28
+ /**
29
+ * Reads one page of the San Francisco Open Data catalogue.
30
+ *
31
+ * @param options - an optional entry cap and fetch stub
32
+ * @returns the entries in the page, the counts, and the newest entry
33
+ */
34
+ export async function fetchSanFranciscoOpenDataCatalogue(options) {
35
+ return fetchSocrataCatalogue({
36
+ sourceId: SAN_FRANCISCO_OPEN_DATA_CATALOGUE_SOURCE_ID,
37
+ apiBase: SAN_FRANCISCO_OPEN_DATA_API_BASE,
38
+ }, options);
39
+ }
40
+ /** San Francisco Open Data catalogue of datasets, maps, and filtered views, keyless. */
41
+ export const sanFranciscoOpenDataCatalogueAdapter = createSocrataCatalogueAdapter({
42
+ sourceId: SAN_FRANCISCO_OPEN_DATA_CATALOGUE_SOURCE_ID,
43
+ name: 'San Francisco Open Data catalogue',
44
+ description: 'The San Francisco Open Data Socrata catalogue, one row per published dataset, map, or filtered view, with its city topic, view count, and download count.',
45
+ apiBase: SAN_FRANCISCO_OPEN_DATA_API_BASE,
46
+ fixtureFilename: SAN_FRANCISCO_OPEN_DATA_FIXTURE_FILENAME,
47
+ });
48
+ //# sourceMappingURL=sanFranciscoOpenDataCatalogue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanFranciscoOpenDataCatalogue.js","sourceRoot":"","sources":["../src/sanFranciscoOpenDataCatalogue.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,6BAA6B,EAC7B,qBAAqB,EACrB,4BAA4B,EAC5B,uBAAuB,GAIxB,MAAM,uBAAuB,CAAC;AAE/B,mEAAmE;AACnE,MAAM,CAAC,MAAM,2CAA2C,GAAG,mCAAmC,CAAC;AAE/F,kEAAkE;AAClE,MAAM,CAAC,MAAM,gCAAgC,GAAG,oCAAoC,CAAC;AAErF,oDAAoD;AACpD,MAAM,CAAC,MAAM,uCAAuC,GAAG,uBAAuB,CAAC;AAW/E,uFAAuF;AACvF,MAAM,wCAAwC,GAC5C,mDAAmD,CAAC;AAEtD;;;;;GAKG;AACH,MAAM,UAAU,qCAAqC,CAAC,OAA4B;IAChF,OAAO,wBAAwB,CAAC,gCAAgC,EAAE,OAAO,CAAC,CAAC;AAC7E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,yCAAyC,CACvD,OAAgB;IAEhB,OAAO,4BAA4B,CAAC,2CAA2C,EAAE,OAAO,CAAC,CAAC;AAC5F,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,kCAAkC,CAAC,OAGxD;IACC,OAAO,qBAAqB,CAC1B;QACE,QAAQ,EAAE,2CAA2C;QACrD,OAAO,EAAE,gCAAgC;KAC1C,EACD,OAAO,CACR,CAAC;AACJ,CAAC;AAED,wFAAwF;AACxF,MAAM,CAAC,MAAM,oCAAoC,GAAG,6BAA6B,CAAC;IAChF,QAAQ,EAAE,2CAA2C;IACrD,IAAI,EAAE,mCAAmC;IACzC,WAAW,EACT,2JAA2J;IAC7J,OAAO,EAAE,gCAAgC;IACzC,eAAe,EAAE,wCAAwC;CAC1D,CAAC,CAAC"}
@@ -0,0 +1,91 @@
1
+ import type { UsDataAdapter } from './types.js';
2
+ /** Adapter id for the Seattle Open Data catalogue source. */
3
+ export declare const SEATTLE_OPEN_DATA_CATALOGUE_SOURCE_ID = "seattle-open-data-catalogue";
4
+ /** Base URL for the Seattle Open Data Socrata catalogue. */
5
+ export declare const SEATTLE_OPEN_DATA_API_BASE = "https://data.seattle.gov/api/views.json";
6
+ /** How many catalogue entries one request reads. */
7
+ export declare const SEATTLE_OPEN_DATA_CATALOGUE_LIMIT = 10;
8
+ /** One catalogue entry from the Seattle Socrata discovery API. */
9
+ export interface SeattleOpenDataCatalogueEntry {
10
+ /** Four-by-four Socrata dataset id, e.g. "k8z7-3feg". */
11
+ id: string;
12
+ /** Human-readable title of the dataset, chart, story, map, or file. */
13
+ name: string;
14
+ /** What the entry is: "dataset", "federated_href", "chart", "story", or "map". */
15
+ assetType: string;
16
+ /** City topic the entry belongs to, or null when the catalogue lists none. */
17
+ category: string | null;
18
+ /** How the entry is rendered, e.g. "tabular", "href", or "story". */
19
+ viewType: string;
20
+ /** When the entry was created, in seconds since the Unix epoch. */
21
+ createdAtEpochSeconds: number;
22
+ /** When the entry was last modified, in seconds since the Unix epoch. */
23
+ viewLastModifiedEpochSeconds: number;
24
+ /** How many times the entry has been viewed. */
25
+ viewCount: number;
26
+ /** How many times the entry has been downloaded. */
27
+ downloadCount: number;
28
+ /** Licence text or URL the portal attaches, or "" when it supplies none. */
29
+ licenceUrl: string;
30
+ /** Publishing organisation the portal attaches, or "" when it supplies none. */
31
+ attribution: string;
32
+ }
33
+ /** One city topic and how many catalogue entries carry it. */
34
+ export interface SeattleOpenDataCategoryCount {
35
+ category: string;
36
+ entryCount: number;
37
+ }
38
+ /** One page of the Seattle catalogue, folded for a story. */
39
+ export interface SeattleOpenDataCatalogue {
40
+ /** One entry per catalogue item in the page. */
41
+ entries: SeattleOpenDataCatalogueEntry[];
42
+ entryCount: number;
43
+ /** Entries whose asset type is "dataset". */
44
+ datasetCount: number;
45
+ /** Entry with the latest creation time. Ties go to the earlier list entry. */
46
+ newestEntry: SeattleOpenDataCatalogueEntry;
47
+ /**
48
+ * Categories in the page, most entries first, ties broken by name. An entry
49
+ * the catalogue lists without a category is counted under "Uncategorised".
50
+ */
51
+ categories: SeattleOpenDataCategoryCount[];
52
+ }
53
+ /**
54
+ * Builds the request URL for one page of the Seattle catalogue.
55
+ *
56
+ * The endpoint is keyless. The service answers the whole catalogue by default,
57
+ * so the adapter asks for a short page.
58
+ *
59
+ * @param options - an optional entry cap
60
+ * @returns the full request URL
61
+ */
62
+ export declare function buildSeattleOpenDataCatalogueUrl(options?: {
63
+ limit?: number;
64
+ }): string;
65
+ /**
66
+ * Parses one page of the Seattle catalogue into the entries and topic counts.
67
+ *
68
+ * An entry without an id, a name, or a creation time is a changed shape and
69
+ * stops the parse. An empty page also stops the parse, because a catalogue
70
+ * with no entries is not a usable answer.
71
+ *
72
+ * @param payload - the JSON body from the Seattle Socrata discovery API
73
+ * @returns the entries in the page, the counts, and the newest entry
74
+ */
75
+ export declare function parseSeattleOpenDataCataloguePayload(payload: unknown): SeattleOpenDataCatalogue;
76
+ /**
77
+ * Reads one page of the Seattle Open Data catalogue.
78
+ *
79
+ * One keyless request covers the page and reports what the city portal holds,
80
+ * without reading any dataset's rows.
81
+ *
82
+ * @param options - an optional entry cap and fetch stub
83
+ * @returns the entries in the page, the counts, and the newest entry
84
+ */
85
+ export declare function fetchSeattleOpenDataCatalogue(options?: {
86
+ limit?: number;
87
+ fetchImpl?: typeof globalThis.fetch;
88
+ }): Promise<SeattleOpenDataCatalogue>;
89
+ /** Seattle Open Data catalogue of datasets, maps, charts, and stories, keyless. */
90
+ export declare const seattleOpenDataCatalogueAdapter: UsDataAdapter<SeattleOpenDataCatalogue>;
91
+ //# sourceMappingURL=seattleOpenDataCatalogue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seattleOpenDataCatalogue.d.ts","sourceRoot":"","sources":["../src/seattleOpenDataCatalogue.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,6DAA6D;AAC7D,eAAO,MAAM,qCAAqC,gCAAgC,CAAC;AAEnF,4DAA4D;AAC5D,eAAO,MAAM,0BAA0B,4CAA4C,CAAC;AAEpF,oDAAoD;AACpD,eAAO,MAAM,iCAAiC,KAAK,CAAC;AAEpD,kEAAkE;AAClE,MAAM,WAAW,6BAA6B;IAC5C,yDAAyD;IACzD,EAAE,EAAE,MAAM,CAAC;IACX,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,SAAS,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,qEAAqE;IACrE,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,qBAAqB,EAAE,MAAM,CAAC;IAC9B,yEAAyE;IACzE,4BAA4B,EAAE,MAAM,CAAC;IACrC,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,aAAa,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,8DAA8D;AAC9D,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,6DAA6D;AAC7D,MAAM,WAAW,wBAAwB;IACvC,gDAAgD;IAChD,OAAO,EAAE,6BAA6B,EAAE,CAAC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,YAAY,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,WAAW,EAAE,6BAA6B,CAAC;IAC3C;;;OAGG;IACH,UAAU,EAAE,4BAA4B,EAAE,CAAC;CAC5C;AAuDD;;;;;;;;GAQG;AACH,wBAAgB,gCAAgC,CAAC,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAKrF;AAED;;;;;;;;;GASG;AACH,wBAAgB,oCAAoC,CAAC,OAAO,EAAE,OAAO,GAAG,wBAAwB,CAwC/F;AAED;;;;;;;;GAQG;AACH,wBAAsB,6BAA6B,CAAC,OAAO,CAAC,EAAE;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACrC,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAOpC;AAED,mFAAmF;AACnF,eAAO,MAAM,+BAA+B,EAAE,aAAa,CAAC,wBAAwB,CAanF,CAAC"}
@@ -0,0 +1,133 @@
1
+ import { z } from 'zod';
2
+ import { UsSourceParseError } from './errors.js';
3
+ import { readFixtureJson } from './fixtures.js';
4
+ import { httpGet } from './http.js';
5
+ import { parseSocrataCatalogueMetadata } from './socrataCatalogueMetadata.js';
6
+ /** Adapter id for the Seattle Open Data catalogue source. */
7
+ export const SEATTLE_OPEN_DATA_CATALOGUE_SOURCE_ID = 'seattle-open-data-catalogue';
8
+ /** Base URL for the Seattle Open Data Socrata catalogue. */
9
+ export const SEATTLE_OPEN_DATA_API_BASE = 'https://data.seattle.gov/api/views.json';
10
+ /** How many catalogue entries one request reads. */
11
+ export const SEATTLE_OPEN_DATA_CATALOGUE_LIMIT = 10;
12
+ /** Committed snapshot, so a build works when the Seattle host is unreachable. */
13
+ const SEATTLE_OPEN_DATA_FIXTURE_FILENAME = 'seattle-open-data-catalogue-2026-11-08.json';
14
+ /** Category bucket the adapter uses for an entry the catalogue lists without one. */
15
+ const SEATTLE_OPEN_DATA_UNCATEGORISED = 'Uncategorised';
16
+ // The discovery API sends a bare JSON array. A value the catalogue does not
17
+ // carry arrives as null, and every count arrives as a number.
18
+ const SEATTLE_OPEN_DATA_ENTRY_SCHEMA = z.object({
19
+ id: z.string().optional(),
20
+ name: z.string().optional(),
21
+ assetType: z.string().optional(),
22
+ category: z.string().nullable().optional(),
23
+ viewType: z.string().optional(),
24
+ createdAt: z.number().optional(),
25
+ viewLastModified: z.number().optional(),
26
+ viewCount: z.number().optional(),
27
+ downloadCount: z.number().optional(),
28
+ metadata: z.unknown().optional(),
29
+ });
30
+ const SEATTLE_OPEN_DATA_PAYLOAD_SCHEMA = z.array(SEATTLE_OPEN_DATA_ENTRY_SCHEMA);
31
+ /** Counts entries per category, most entries first, ties by name. */
32
+ function countSeattleOpenDataCategories(entries) {
33
+ const counts = new Map();
34
+ for (const entry of entries) {
35
+ const category = entry.category ?? SEATTLE_OPEN_DATA_UNCATEGORISED;
36
+ counts.set(category, (counts.get(category) ?? 0) + 1);
37
+ }
38
+ return [...counts.entries()]
39
+ .sort(([leftCategory, leftCount], [rightCategory, rightCount]) => leftCount === rightCount ? leftCategory.localeCompare(rightCategory) : rightCount - leftCount)
40
+ .map(([category, entryCount]) => ({ category, entryCount }));
41
+ }
42
+ /** Picks the entry with the latest creation time, ties to the earlier entry. */
43
+ function newestSeattleOpenDataEntry(entries) {
44
+ const first = entries[0];
45
+ if (first === undefined) {
46
+ throw new UsSourceParseError(SEATTLE_OPEN_DATA_CATALOGUE_SOURCE_ID, 'No entries to summarise');
47
+ }
48
+ return entries.reduce((best, entry) => (entry.createdAtEpochSeconds > best.createdAtEpochSeconds ? entry : best), first);
49
+ }
50
+ /**
51
+ * Builds the request URL for one page of the Seattle catalogue.
52
+ *
53
+ * The endpoint is keyless. The service answers the whole catalogue by default,
54
+ * so the adapter asks for a short page.
55
+ *
56
+ * @param options - an optional entry cap
57
+ * @returns the full request URL
58
+ */
59
+ export function buildSeattleOpenDataCatalogueUrl(options) {
60
+ const params = new URLSearchParams({
61
+ limit: String(options?.limit ?? SEATTLE_OPEN_DATA_CATALOGUE_LIMIT),
62
+ });
63
+ return `${SEATTLE_OPEN_DATA_API_BASE}?${params.toString()}`;
64
+ }
65
+ /**
66
+ * Parses one page of the Seattle catalogue into the entries and topic counts.
67
+ *
68
+ * An entry without an id, a name, or a creation time is a changed shape and
69
+ * stops the parse. An empty page also stops the parse, because a catalogue
70
+ * with no entries is not a usable answer.
71
+ *
72
+ * @param payload - the JSON body from the Seattle Socrata discovery API
73
+ * @returns the entries in the page, the counts, and the newest entry
74
+ */
75
+ export function parseSeattleOpenDataCataloguePayload(payload) {
76
+ const parsed = SEATTLE_OPEN_DATA_PAYLOAD_SCHEMA.safeParse(payload);
77
+ if (!parsed.success) {
78
+ throw new UsSourceParseError(SEATTLE_OPEN_DATA_CATALOGUE_SOURCE_ID, parsed.error.message);
79
+ }
80
+ if (parsed.data.length === 0) {
81
+ throw new UsSourceParseError(SEATTLE_OPEN_DATA_CATALOGUE_SOURCE_ID, 'The response carried no entries');
82
+ }
83
+ const entries = parsed.data.map((row) => {
84
+ if (row.id === undefined || row.name === undefined || row.createdAt === undefined) {
85
+ throw new UsSourceParseError(SEATTLE_OPEN_DATA_CATALOGUE_SOURCE_ID, 'A catalogue entry arrived without its id, name, or creation time');
86
+ }
87
+ return {
88
+ id: row.id,
89
+ name: row.name,
90
+ assetType: row.assetType ?? '',
91
+ category: row.category ?? null,
92
+ viewType: row.viewType ?? '',
93
+ createdAtEpochSeconds: row.createdAt,
94
+ viewLastModifiedEpochSeconds: row.viewLastModified ?? row.createdAt,
95
+ viewCount: row.viewCount ?? 0,
96
+ downloadCount: row.downloadCount ?? 0,
97
+ ...parseSocrataCatalogueMetadata(row.metadata),
98
+ };
99
+ });
100
+ return {
101
+ entries,
102
+ entryCount: entries.length,
103
+ datasetCount: entries.filter((entry) => entry.assetType === 'dataset').length,
104
+ newestEntry: newestSeattleOpenDataEntry(entries),
105
+ categories: countSeattleOpenDataCategories(entries),
106
+ };
107
+ }
108
+ /**
109
+ * Reads one page of the Seattle Open Data catalogue.
110
+ *
111
+ * One keyless request covers the page and reports what the city portal holds,
112
+ * without reading any dataset's rows.
113
+ *
114
+ * @param options - an optional entry cap and fetch stub
115
+ * @returns the entries in the page, the counts, and the newest entry
116
+ */
117
+ export async function fetchSeattleOpenDataCatalogue(options) {
118
+ const fetchImpl = options?.fetchImpl ?? globalThis.fetch;
119
+ const url = buildSeattleOpenDataCatalogueUrl(options?.limit === undefined ? {} : { limit: options.limit });
120
+ const response = await httpGet(SEATTLE_OPEN_DATA_CATALOGUE_SOURCE_ID, url, { fetchImpl });
121
+ return parseSeattleOpenDataCataloguePayload(await response.json());
122
+ }
123
+ /** Seattle Open Data catalogue of datasets, maps, charts, and stories, keyless. */
124
+ export const seattleOpenDataCatalogueAdapter = {
125
+ id: SEATTLE_OPEN_DATA_CATALOGUE_SOURCE_ID,
126
+ name: 'Seattle Open Data catalogue',
127
+ auth: 'none',
128
+ description: 'The Seattle Open Data Socrata catalogue, one row per published dataset, map, chart, or story, with its city topic, view count, and download count.',
129
+ fetchLive: async (options) => fetchSeattleOpenDataCatalogue(options?.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
130
+ parse: (payload) => parseSeattleOpenDataCataloguePayload(payload),
131
+ loadFixture: () => parseSeattleOpenDataCataloguePayload(readFixtureJson(SEATTLE_OPEN_DATA_FIXTURE_FILENAME)),
132
+ };
133
+ //# sourceMappingURL=seattleOpenDataCatalogue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seattleOpenDataCatalogue.js","sourceRoot":"","sources":["../src/seattleOpenDataCatalogue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,121 @@
1
+ import type { UsDataAdapter } from './types.js';
2
+ /** Default number of catalogue entries one request reads. */
3
+ export declare const SOCRATA_CATALOGUE_LIMIT = 10;
4
+ /** Category bucket used when a catalogue entry carries no category. */
5
+ export declare const SOCRATA_UNCATEGORISED = "Uncategorised";
6
+ /** One catalogue entry from a Socrata discovery API. */
7
+ export interface SocrataCatalogueEntry {
8
+ /** Socrata four-by-four id, e.g. "p4pq-bxn9". */
9
+ id: string;
10
+ /** Human-readable title of the dataset, chart, story, map, or file. */
11
+ name: string;
12
+ /** What the entry is, e.g. "dataset", "chart", "story", "map", or "file". */
13
+ assetType: string;
14
+ /** Source topic the entry belongs to, or null when the catalogue lists none. */
15
+ category: string | null;
16
+ /** How the entry is rendered, e.g. "tabular" or "story". */
17
+ viewType: string;
18
+ /** When the entry was created, in seconds since the Unix epoch. */
19
+ createdAtEpochSeconds: number;
20
+ /** When the entry was last modified, in seconds since the Unix epoch. */
21
+ viewLastModifiedEpochSeconds: number;
22
+ /** How many times the entry has been viewed. */
23
+ viewCount: number;
24
+ /** How many times the entry has been downloaded. */
25
+ downloadCount: number;
26
+ /** Licence text or URL the portal attaches, or "" when it supplies none. */
27
+ licenceUrl: string;
28
+ /** Publishing organisation the portal attaches, or "" when it supplies none. */
29
+ attribution: string;
30
+ }
31
+ /** One catalogue topic and how many entries carry it. */
32
+ export interface SocrataCatalogueCategoryCount {
33
+ category: string;
34
+ entryCount: number;
35
+ }
36
+ /** One page of a Socrata catalogue, folded for a story. */
37
+ export interface SocrataCatalogue {
38
+ /** One entry per catalogue item in the page. */
39
+ entries: SocrataCatalogueEntry[];
40
+ entryCount: number;
41
+ /** Entries whose asset type is "dataset". */
42
+ datasetCount: number;
43
+ /** Entry with the latest creation time. Ties go to the earlier list entry. */
44
+ newestEntry: SocrataCatalogueEntry;
45
+ /**
46
+ * Categories in the page, most entries first, ties broken by name. An entry
47
+ * the catalogue lists without a category is counted under the configured
48
+ * uncategorised label.
49
+ */
50
+ categories: SocrataCatalogueCategoryCount[];
51
+ }
52
+ /** Configuration for one Socrata catalogue source. */
53
+ export interface SocrataCatalogueSource {
54
+ /** Adapter id, used in errors and the registry. */
55
+ sourceId: string;
56
+ /** Base URL of the Socrata discovery API, without the limit parameter. */
57
+ apiBase: string;
58
+ /** Default entry cap. Defaults to {@link SOCRATA_CATALOGUE_LIMIT}. */
59
+ limit?: number;
60
+ /** Category bucket for entries without a category. Defaults to "Uncategorised". */
61
+ uncategorisedLabel?: string;
62
+ }
63
+ /** Configuration for one Socrata catalogue adapter. */
64
+ export interface SocrataCatalogueAdapterConfig extends SocrataCatalogueSource {
65
+ /** Human-readable source name. */
66
+ name: string;
67
+ /** What the adapter reads, in one sentence. */
68
+ description: string;
69
+ /** Filename inside src/fixtures for the committed snapshot. */
70
+ fixtureFilename: string;
71
+ }
72
+ /**
73
+ * Builds the request URL for one page of a Socrata catalogue.
74
+ *
75
+ * The endpoint is keyless. The service answers the whole catalogue by default,
76
+ * so the adapter asks for a short page unless the caller sets a cap.
77
+ *
78
+ * @param apiBase - the Socrata discovery API URL, without query parameters
79
+ * @param options - an optional entry cap
80
+ * @returns the full request URL
81
+ */
82
+ export declare function buildSocrataCatalogueUrl(apiBase: string, options?: {
83
+ limit?: number;
84
+ }): string;
85
+ /**
86
+ * Parses one page of a Socrata catalogue into entries and topic counts.
87
+ *
88
+ * An entry without an id, a name, or a creation time is a changed shape and
89
+ * stops the parse. An empty page also stops the parse, because a catalogue
90
+ * with no entries is not a usable answer.
91
+ *
92
+ * @param sourceId - adapter id used in parse errors
93
+ * @param payload - the JSON body from the Socrata discovery API
94
+ * @param options - an optional category label for entries without one
95
+ * @returns the entries in the page, the counts, and the newest entry
96
+ */
97
+ export declare function parseSocrataCataloguePayload(sourceId: string, payload: unknown, options?: {
98
+ uncategorisedLabel?: string;
99
+ }): SocrataCatalogue;
100
+ /**
101
+ * Reads one page of a Socrata catalogue.
102
+ *
103
+ * One keyless request covers the page and reports what the portal holds,
104
+ * without reading any dataset's rows.
105
+ *
106
+ * @param source - source id, API base, and optional defaults
107
+ * @param options - an optional entry cap and fetch stub
108
+ * @returns the entries in the page, the counts, and the newest entry
109
+ */
110
+ export declare function fetchSocrataCatalogue(source: SocrataCatalogueSource, options?: {
111
+ limit?: number;
112
+ fetchImpl?: typeof globalThis.fetch;
113
+ }): Promise<SocrataCatalogue>;
114
+ /**
115
+ * Creates an adapter around one Socrata catalogue endpoint.
116
+ *
117
+ * @param config - source id, endpoint, fixture, and the text the API shows
118
+ * @returns an adapter that fetches, parses, and loads the committed snapshot
119
+ */
120
+ export declare function createSocrataCatalogueAdapter(config: SocrataCatalogueAdapterConfig): UsDataAdapter<SocrataCatalogue>;
121
+ //# sourceMappingURL=socrataCatalogue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socrataCatalogue.d.ts","sourceRoot":"","sources":["../src/socrataCatalogue.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,6DAA6D;AAC7D,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAE1C,uEAAuE;AACvE,eAAO,MAAM,qBAAqB,kBAAkB,CAAC;AAErD,wDAAwD;AACxD,MAAM,WAAW,qBAAqB;IACpC,iDAAiD;IACjD,EAAE,EAAE,MAAM,CAAC;IACX,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,qBAAqB,EAAE,MAAM,CAAC;IAC9B,yEAAyE;IACzE,4BAA4B,EAAE,MAAM,CAAC;IACrC,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,aAAa,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,yDAAyD;AACzD,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,2DAA2D;AAC3D,MAAM,WAAW,gBAAgB;IAC/B,gDAAgD;IAChD,OAAO,EAAE,qBAAqB,EAAE,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,YAAY,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,WAAW,EAAE,qBAAqB,CAAC;IACnC;;;;OAIG;IACH,UAAU,EAAE,6BAA6B,EAAE,CAAC;CAC7C;AAED,sDAAsD;AACtD,MAAM,WAAW,sBAAsB;IACrC,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mFAAmF;IACnF,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,uDAAuD;AACvD,MAAM,WAAW,6BAA8B,SAAQ,sBAAsB;IAC3E,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,eAAe,EAAE,MAAM,CAAC;CACzB;AAmDD;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAK9F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE;IAAE,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE,GACxC,gBAAgB,CAwClB;AAED;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,sBAAsB,EAC9B,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CAAE,GAChE,OAAO,CAAC,gBAAgB,CAAC,CAU3B;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,6BAA6B,GACpC,aAAa,CAAC,gBAAgB,CAAC,CAoCjC"}
@@ -0,0 +1,151 @@
1
+ import { z } from 'zod';
2
+ import { UsSourceParseError } from './errors.js';
3
+ import { readFixtureJson } from './fixtures.js';
4
+ import { httpGet } from './http.js';
5
+ import { parseSocrataCatalogueMetadata } from './socrataCatalogueMetadata.js';
6
+ /** Default number of catalogue entries one request reads. */
7
+ export const SOCRATA_CATALOGUE_LIMIT = 10;
8
+ /** Category bucket used when a catalogue entry carries no category. */
9
+ export const SOCRATA_UNCATEGORISED = 'Uncategorised';
10
+ // The discovery API sends a bare JSON array. A value the catalogue does not
11
+ // carry arrives as null, and every count arrives as a number.
12
+ const SOCRATA_CATALOGUE_ENTRY_SCHEMA = z.object({
13
+ id: z.string().optional(),
14
+ name: z.string().optional(),
15
+ assetType: z.string().optional(),
16
+ category: z.string().nullable().optional(),
17
+ viewType: z.string().optional(),
18
+ createdAt: z.number().optional(),
19
+ viewLastModified: z.number().optional(),
20
+ viewCount: z.number().optional(),
21
+ downloadCount: z.number().optional(),
22
+ metadata: z.unknown().optional(),
23
+ });
24
+ const SOCRATA_CATALOGUE_PAYLOAD_SCHEMA = z.array(SOCRATA_CATALOGUE_ENTRY_SCHEMA);
25
+ /** Counts entries per category, most entries first, ties by name. */
26
+ function countSocrataCategories(entries, uncategorisedLabel) {
27
+ const counts = new Map();
28
+ for (const entry of entries) {
29
+ const category = entry.category ?? uncategorisedLabel;
30
+ counts.set(category, (counts.get(category) ?? 0) + 1);
31
+ }
32
+ return [...counts.entries()]
33
+ .sort(([leftCategory, leftCount], [rightCategory, rightCount]) => leftCount === rightCount ? leftCategory.localeCompare(rightCategory) : rightCount - leftCount)
34
+ .map(([category, entryCount]) => ({ category, entryCount }));
35
+ }
36
+ /** Picks the entry with the latest creation time, ties to the earlier entry. */
37
+ function newestSocrataEntry(sourceId, entries) {
38
+ const first = entries[0];
39
+ if (first === undefined) {
40
+ throw new UsSourceParseError(sourceId, 'No entries to summarise');
41
+ }
42
+ return entries.reduce((best, entry) => (entry.createdAtEpochSeconds > best.createdAtEpochSeconds ? entry : best), first);
43
+ }
44
+ /**
45
+ * Builds the request URL for one page of a Socrata catalogue.
46
+ *
47
+ * The endpoint is keyless. The service answers the whole catalogue by default,
48
+ * so the adapter asks for a short page unless the caller sets a cap.
49
+ *
50
+ * @param apiBase - the Socrata discovery API URL, without query parameters
51
+ * @param options - an optional entry cap
52
+ * @returns the full request URL
53
+ */
54
+ export function buildSocrataCatalogueUrl(apiBase, options) {
55
+ const params = new URLSearchParams({
56
+ limit: String(options?.limit ?? SOCRATA_CATALOGUE_LIMIT),
57
+ });
58
+ return `${apiBase}?${params.toString()}`;
59
+ }
60
+ /**
61
+ * Parses one page of a Socrata catalogue into entries and topic counts.
62
+ *
63
+ * An entry without an id, a name, or a creation time is a changed shape and
64
+ * stops the parse. An empty page also stops the parse, because a catalogue
65
+ * with no entries is not a usable answer.
66
+ *
67
+ * @param sourceId - adapter id used in parse errors
68
+ * @param payload - the JSON body from the Socrata discovery API
69
+ * @param options - an optional category label for entries without one
70
+ * @returns the entries in the page, the counts, and the newest entry
71
+ */
72
+ export function parseSocrataCataloguePayload(sourceId, payload, options) {
73
+ const parsed = SOCRATA_CATALOGUE_PAYLOAD_SCHEMA.safeParse(payload);
74
+ if (!parsed.success) {
75
+ throw new UsSourceParseError(sourceId, parsed.error.message);
76
+ }
77
+ if (parsed.data.length === 0) {
78
+ throw new UsSourceParseError(sourceId, 'The response carried no entries');
79
+ }
80
+ const entries = parsed.data.map((row) => {
81
+ if (row.id === undefined || row.name === undefined || row.createdAt === undefined) {
82
+ throw new UsSourceParseError(sourceId, 'A catalogue entry arrived without its id, name, or creation time');
83
+ }
84
+ return {
85
+ id: row.id,
86
+ name: row.name,
87
+ assetType: row.assetType ?? '',
88
+ category: row.category ?? null,
89
+ viewType: row.viewType ?? '',
90
+ createdAtEpochSeconds: row.createdAt,
91
+ viewLastModifiedEpochSeconds: row.viewLastModified ?? row.createdAt,
92
+ viewCount: row.viewCount ?? 0,
93
+ downloadCount: row.downloadCount ?? 0,
94
+ ...parseSocrataCatalogueMetadata(row.metadata),
95
+ };
96
+ });
97
+ return {
98
+ entries,
99
+ entryCount: entries.length,
100
+ datasetCount: entries.filter((entry) => entry.assetType === 'dataset').length,
101
+ newestEntry: newestSocrataEntry(sourceId, entries),
102
+ categories: countSocrataCategories(entries, options?.uncategorisedLabel ?? SOCRATA_UNCATEGORISED),
103
+ };
104
+ }
105
+ /**
106
+ * Reads one page of a Socrata catalogue.
107
+ *
108
+ * One keyless request covers the page and reports what the portal holds,
109
+ * without reading any dataset's rows.
110
+ *
111
+ * @param source - source id, API base, and optional defaults
112
+ * @param options - an optional entry cap and fetch stub
113
+ * @returns the entries in the page, the counts, and the newest entry
114
+ */
115
+ export async function fetchSocrataCatalogue(source, options) {
116
+ const fetchImpl = options?.fetchImpl ?? globalThis.fetch;
117
+ const limit = options?.limit ?? source.limit;
118
+ const url = buildSocrataCatalogueUrl(source.apiBase, limit === undefined ? {} : { limit });
119
+ const response = await httpGet(source.sourceId, url, { fetchImpl });
120
+ return parseSocrataCataloguePayload(source.sourceId, await response.json(), source.uncategorisedLabel === undefined ? {} : { uncategorisedLabel: source.uncategorisedLabel });
121
+ }
122
+ /**
123
+ * Creates an adapter around one Socrata catalogue endpoint.
124
+ *
125
+ * @param config - source id, endpoint, fixture, and the text the API shows
126
+ * @returns an adapter that fetches, parses, and loads the committed snapshot
127
+ */
128
+ export function createSocrataCatalogueAdapter(config) {
129
+ const source = {
130
+ sourceId: config.sourceId,
131
+ apiBase: config.apiBase,
132
+ ...(config.limit === undefined ? {} : { limit: config.limit }),
133
+ ...(config.uncategorisedLabel === undefined
134
+ ? {}
135
+ : { uncategorisedLabel: config.uncategorisedLabel }),
136
+ };
137
+ return {
138
+ id: config.sourceId,
139
+ name: config.name,
140
+ auth: 'none',
141
+ description: config.description,
142
+ fetchLive: async (options) => fetchSocrataCatalogue(source, options?.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
143
+ parse: (payload) => parseSocrataCataloguePayload(source.sourceId, payload, source.uncategorisedLabel === undefined
144
+ ? {}
145
+ : { uncategorisedLabel: source.uncategorisedLabel }),
146
+ loadFixture: () => parseSocrataCataloguePayload(source.sourceId, readFixtureJson(config.fixtureFilename), source.uncategorisedLabel === undefined
147
+ ? {}
148
+ : { uncategorisedLabel: source.uncategorisedLabel }),
149
+ };
150
+ }
151
+ //# sourceMappingURL=socrataCatalogue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socrataCatalogue.js","sourceRoot":"","sources":["../src/socrataCatalogue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /** Source-supplied licence and attribution metadata for one Socrata entry. */
2
+ export interface SocrataCatalogueMetadata {
3
+ /** Licence URL the portal attaches to the entry, or "" when it supplies none. */
4
+ licenceUrl: string;
5
+ /** Publishing organisation the portal attaches to the entry, or "" when it supplies none. */
6
+ attribution: string;
7
+ }
8
+ /**
9
+ * Reads the licence and attribution values Socrata attaches to a catalogue entry.
10
+ *
11
+ * Portals use "Common Core" for older entries and "Common Core 3" for newer
12
+ * ones. A missing or malformed block returns empty strings, because the portal
13
+ * did not supply the value rather than the adapter knowing better.
14
+ *
15
+ * @param metadata - the entry's Socrata metadata block
16
+ * @returns the source-supplied licence URL and publisher
17
+ */
18
+ export declare function parseSocrataCatalogueMetadata(metadata: unknown): SocrataCatalogueMetadata;
19
+ //# sourceMappingURL=socrataCatalogueMetadata.d.ts.map