@digitalculture/ochre-sdk 0.14.6 → 0.14.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -162,7 +162,7 @@ type Link = {
162
162
  type ImageMapArea = {
163
163
  uuid: string;
164
164
  publicationDateTime: Date | null;
165
- type: string;
165
+ category: string;
166
166
  title: string;
167
167
  shape: "rectangle" | "circle" | "polygon";
168
168
  coords: Array<number>;
@@ -446,6 +446,9 @@ type PropertyValueContent<T extends PropertyValueContentType> = {
446
446
  label: string | null;
447
447
  isUncertain: boolean;
448
448
  unit: string | null;
449
+ height: number | null;
450
+ width: number | null;
451
+ fileSize: number | null;
449
452
  category: string | null;
450
453
  type: string | null;
451
454
  uuid: string | null;
@@ -631,6 +634,7 @@ type Website = {
631
634
  logoUrl: string | null;
632
635
  itemPage: {
633
636
  iiifViewer: "universal-viewer" | "clover";
637
+ isPropertyValuesGrouped: boolean;
634
638
  options: {
635
639
  contexts: PropertyContexts;
636
640
  };
@@ -747,6 +751,7 @@ type WebElementComponent = {
747
751
  itemVariant: "detailed" | "card" | "tile";
748
752
  paginationVariant: "default" | "numeric";
749
753
  layout: "image-top" | "image-bottom" | "image-start" | "image-end";
754
+ imageQuality: "high" | "low";
750
755
  isSortDisplayed: boolean;
751
756
  isUsingQueryParams: boolean;
752
757
  filter: {
@@ -811,6 +816,8 @@ type WebElementComponent = {
811
816
  component: "map";
812
817
  mapId: string;
813
818
  customBasemap: string | null;
819
+ initialBounds: [[number, number], [number, number]] | null;
820
+ maximumBounds: [[number, number], [number, number]] | null;
814
821
  isControlsDisplayed: boolean;
815
822
  isInteractive: boolean;
816
823
  isClustered: boolean;
package/dist/index.mjs CHANGED
@@ -151,6 +151,32 @@ const whitespaceSchema = z.string().transform((str) => str.split(" ")).pipe(z.ar
151
151
  * @internal
152
152
  */
153
153
  const emailSchema = z.email({ error: "Invalid email" });
154
+ /**
155
+ * Schema for parsing and validating a string in the format "[[number, number], [number, number]]"
156
+ * into an array with exactly two bounds
157
+ * @internal
158
+ */
159
+ const boundsSchema = z.string().transform((str, ctx) => {
160
+ const trimmed = str.trim();
161
+ if (!trimmed.startsWith("[[") || !trimmed.endsWith("]]")) {
162
+ ctx.addIssue({
163
+ code: "invalid_format",
164
+ format: "string",
165
+ message: "String must start with '[[' and end with ']]'"
166
+ });
167
+ return z.NEVER;
168
+ }
169
+ try {
170
+ return JSON.parse(trimmed);
171
+ } catch {
172
+ ctx.addIssue({
173
+ code: "invalid_format",
174
+ format: "string",
175
+ message: "Invalid JSON format"
176
+ });
177
+ return z.NEVER;
178
+ }
179
+ }).pipe(z.tuple([z.tuple([z.number(), z.number()]), z.tuple([z.number(), z.number()])], { message: "Must contain exactly 2 coordinate pairs" }));
154
180
 
155
181
  //#endregion
156
182
  //#region src/utils/getters.ts
@@ -1179,6 +1205,9 @@ function parseProperty(property, language = "eng") {
1179
1205
  uuid: null,
1180
1206
  publicationDateTime: null,
1181
1207
  unit: null,
1208
+ height: null,
1209
+ width: null,
1210
+ fileSize: null,
1182
1211
  href: null,
1183
1212
  slug: null
1184
1213
  };
@@ -1231,6 +1260,9 @@ function parseProperty(property, language = "eng") {
1231
1260
  uuid: value.uuid ?? null,
1232
1261
  publicationDateTime: value.publicationDateTime != null ? new Date(value.publicationDateTime) : null,
1233
1262
  unit: value.unit ?? null,
1263
+ height: value.height ?? null,
1264
+ width: value.width ?? null,
1265
+ fileSize: value.fileSize ?? null,
1234
1266
  href: value.href ?? null,
1235
1267
  slug: value.slug ?? null
1236
1268
  };
@@ -1289,7 +1321,7 @@ function parseImageMap(imageMap) {
1289
1321
  for (const area of imageMapAreasToParse) returnImageMap.area.push({
1290
1322
  uuid: area.uuid,
1291
1323
  publicationDateTime: area.publicationDateTime != null ? new Date(area.publicationDateTime) : null,
1292
- type: area.type,
1324
+ category: area.type,
1293
1325
  title: parseFakeString(area.title),
1294
1326
  shape: area.shape === "rect" ? "rectangle" : area.shape === "circle" ? "circle" : "polygon",
1295
1327
  coords: area.coords.split(",").map((coord) => Number.parseInt(coord)),
@@ -1816,6 +1848,11 @@ function parseConcepts(concepts) {
1816
1848
  for (const concept of conceptsToParse) returnConcepts.push(parseConcept(concept));
1817
1849
  return returnConcepts;
1818
1850
  }
1851
+ function parseBounds(bounds) {
1852
+ const result = boundsSchema.safeParse(bounds);
1853
+ if (!result.success) throw new Error(`Invalid bounds: ${result.error.message}`);
1854
+ return result.data;
1855
+ }
1819
1856
  /**
1820
1857
  * Parses raw web element properties into a standardized WebElementComponent structure
1821
1858
  *
@@ -1953,6 +1990,8 @@ function parseWebElementProperties(componentProperty, elementResource) {
1953
1990
  itemVariant ??= "detailed";
1954
1991
  let paginationVariant = getPropertyValueByLabel(componentProperty.properties, "pagination-variant");
1955
1992
  paginationVariant ??= "default";
1993
+ let imageQuality = getPropertyValueByLabel(componentProperty.properties, "image-quality");
1994
+ imageQuality ??= "low";
1956
1995
  let isUsingQueryParams = false;
1957
1996
  const isUsingQueryParamsProperty = getPropertyValueByLabel(componentProperty.properties, "is-using-query-params");
1958
1997
  if (isUsingQueryParamsProperty !== null) isUsingQueryParams = isUsingQueryParamsProperty === true;
@@ -2024,6 +2063,8 @@ function parseWebElementProperties(componentProperty, elementResource) {
2024
2063
  properties.variant = variant;
2025
2064
  properties.itemVariant = itemVariant;
2026
2065
  properties.paginationVariant = paginationVariant;
2066
+ properties.layout = layout;
2067
+ properties.imageQuality = imageQuality;
2027
2068
  properties.isUsingQueryParams = isUsingQueryParams;
2028
2069
  properties.filter = {
2029
2070
  isSidebarDisplayed: isFilterSidebarDisplayed,
@@ -2033,7 +2074,6 @@ function parseWebElementProperties(componentProperty, elementResource) {
2033
2074
  sidebarSort: filterSidebarSort
2034
2075
  };
2035
2076
  properties.isSortDisplayed = isSortDisplayed;
2036
- properties.layout = layout;
2037
2077
  properties.options = options;
2038
2078
  break;
2039
2079
  }
@@ -2078,7 +2118,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
2078
2118
  }
2079
2119
  case "image": {
2080
2120
  if (links.length === 0) throw new Error(`No links found for the following component: “${componentName}”`);
2081
- let imageQuality = getPropertyValueByLabel(componentProperty.properties, "quality");
2121
+ let imageQuality = getPropertyValueByLabel(componentProperty.properties, "image-quality");
2082
2122
  imageQuality ??= "high";
2083
2123
  const images = [];
2084
2124
  for (const link of links) images.push({
@@ -2184,6 +2224,12 @@ function parseWebElementProperties(componentProperty, elementResource) {
2184
2224
  let customBasemap = null;
2185
2225
  const customBasemapProperty = getPropertyValueByLabel(componentProperty.properties, "custom-basemap");
2186
2226
  if (customBasemapProperty !== null) customBasemap = customBasemapProperty;
2227
+ let initialBounds = null;
2228
+ const initialBoundsProperty = getPropertyValueByLabel(componentProperty.properties, "initial-bounds");
2229
+ if (initialBoundsProperty !== null) initialBounds = parseBounds(String(initialBoundsProperty));
2230
+ let maximumBounds = null;
2231
+ const maximumBoundsProperty = getPropertyValueByLabel(componentProperty.properties, "maximum-bounds");
2232
+ if (maximumBoundsProperty !== null) maximumBounds = parseBounds(String(maximumBoundsProperty));
2187
2233
  let isControlsDisplayed = false;
2188
2234
  const isControlsDisplayedProperty = getPropertyValueByLabel(componentProperty.properties, "controls-displayed");
2189
2235
  if (isControlsDisplayedProperty !== null) isControlsDisplayed = isControlsDisplayedProperty === true;
@@ -2191,10 +2237,12 @@ function parseWebElementProperties(componentProperty, elementResource) {
2191
2237
  const isFullHeightProperty = getPropertyValueByLabel(componentProperty.properties, "is-full-height");
2192
2238
  if (isFullHeightProperty !== null) isFullHeight = isFullHeightProperty === true;
2193
2239
  properties.mapId = mapLink.uuid;
2240
+ properties.customBasemap = customBasemap;
2241
+ properties.initialBounds = initialBounds;
2242
+ properties.maximumBounds = maximumBounds;
2194
2243
  properties.isInteractive = isInteractive;
2195
2244
  properties.isClustered = isClustered;
2196
2245
  properties.isUsingPins = isUsingPins;
2197
- properties.customBasemap = customBasemap;
2198
2246
  properties.isControlsDisplayed = isControlsDisplayed;
2199
2247
  properties.isFullHeight = isFullHeight;
2200
2248
  break;
@@ -2794,6 +2842,7 @@ function parseWebsiteProperties(properties, websiteTree) {
2794
2842
  let isFooterDisplayed = true;
2795
2843
  let isSidebarDisplayed = false;
2796
2844
  let iiifViewer = "universal-viewer";
2845
+ let isPropertyValuesGrouped = true;
2797
2846
  let supportsThemeToggle = true;
2798
2847
  let defaultTheme = null;
2799
2848
  const headerProperty = websiteProperties.find((property) => property.label === "navbar-displayed")?.values[0];
@@ -2811,6 +2860,8 @@ function parseWebsiteProperties(properties, websiteTree) {
2811
2860
  const headerSearchBarBoundElementUuid = websiteProperties.find((property) => property.label === "bound-element-navbar-search-bar")?.values[0]?.uuid ?? null;
2812
2861
  const iiifViewerProperty = websiteProperties.find((property) => property.label === "iiif-viewer")?.values[0];
2813
2862
  if (iiifViewerProperty) iiifViewer = iiifViewerProperty.content;
2863
+ const isPropertyValuesGroupedProperty = websiteProperties.find((property) => property.label === "is-property-values-grouped")?.values[0];
2864
+ if (isPropertyValuesGroupedProperty) isPropertyValuesGrouped = isPropertyValuesGroupedProperty.content === true;
2814
2865
  const supportsThemeToggleProperty = websiteProperties.find((property) => property.label === "supports-theme-toggle")?.values[0];
2815
2866
  if (supportsThemeToggleProperty) supportsThemeToggle = supportsThemeToggleProperty.content === true;
2816
2867
  const defaultThemeProperty = websiteProperties.find((property) => property.label === "default-theme")?.values[0];
@@ -2863,6 +2914,7 @@ function parseWebsiteProperties(properties, websiteTree) {
2863
2914
  logoUrl: logoUuid !== null ? `https://ochre.lib.uchicago.edu/ochre?uuid=${logoUuid}&load` : null,
2864
2915
  itemPage: {
2865
2916
  iiifViewer,
2917
+ isPropertyValuesGrouped,
2866
2918
  options: { contexts }
2867
2919
  }
2868
2920
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digitalculture/ochre-sdk",
3
- "version": "0.14.6",
3
+ "version": "0.14.8",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Node.js library for working with OCHRE (Online Cultural and Historical Research Environment) data",
@@ -43,13 +43,13 @@
43
43
  "zod": "^4.2.1"
44
44
  },
45
45
  "devDependencies": {
46
- "@antfu/eslint-config": "^6.7.1",
46
+ "@antfu/eslint-config": "^6.7.3",
47
47
  "@types/node": "^24.10.4",
48
48
  "bumpp": "^10.3.2",
49
49
  "eslint": "^9.39.2",
50
50
  "prettier": "^3.7.4",
51
51
  "terser": "^5.44.1",
52
- "tsdown": "^0.18.1",
52
+ "tsdown": "^0.18.2",
53
53
  "typescript": "^5.9.3",
54
54
  "vitest": "^4.0.16"
55
55
  },