ochre-sdk 0.22.21 → 0.22.23

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
@@ -1288,6 +1288,29 @@ declare function fetchGallery(params: {
1288
1288
  error: string;
1289
1289
  }>;
1290
1290
  //#endregion
1291
+ //#region src/utils/fetchers/item-links.d.ts
1292
+ /**
1293
+ * Fetches and parses an OCHRE item links from the OCHRE API
1294
+ *
1295
+ * @param uuid - The UUID of the OCHRE item to fetch
1296
+ * @param category - The category of the OCHRE item to fetch
1297
+ * @param itemCategories - The categories of the OCHRE linked items to fetch
1298
+ * @param options - The options for the fetch
1299
+ * @param options.fetch - The fetch function to use
1300
+ * @param options.version - The version of the OCHRE API to use
1301
+ * @returns Object containing the parsed OCHRE item links, or an error message if the fetch/parse fails
1302
+ */
1303
+ declare function fetchItemLinks<T extends DataCategory = DataCategory, U extends DataCategory | Array<DataCategory> = (T extends "tree" ? Exclude<DataCategory, "tree"> : T extends "set" ? Array<DataCategory> : never)>(uuid: string, category?: T, itemCategories?: U, options?: {
1304
+ fetch?: (input: string | URL | globalThis.Request, init?: RequestInit) => Promise<Response>;
1305
+ version?: ApiVersion;
1306
+ }): Promise<{
1307
+ error: null;
1308
+ items: Array<Item<T, U>>;
1309
+ } | {
1310
+ error: string;
1311
+ items: never;
1312
+ }>;
1313
+ //#endregion
1291
1314
  //#region src/utils/fetchers/item.d.ts
1292
1315
  /**
1293
1316
  * Fetches and parses an OCHRE item from the OCHRE API
@@ -1601,4 +1624,4 @@ declare const DEFAULT_PAGE_SIZE = 48;
1601
1624
  */
1602
1625
  declare function flattenItemProperties<T extends DataCategory = DataCategory, U extends DataCategory | Array<DataCategory> = (T extends "tree" ? Exclude<DataCategory, "tree"> : T extends "set" ? Array<DataCategory> : never)>(item: Item<T, U>): Item<T, U>;
1603
1626
  //#endregion
1604
- export { ApiVersion, Bibliography, Concept, Context, ContextItem, ContextNode, ContextTree, ContextTreeFilterLevel, ContextTreeLevel, ContextTreeLevelItem, Coordinate, DEFAULT_API_VERSION, DEFAULT_PAGE_SIZE, Data, DataCategory, Event, FileFormat, Gallery, Identification, Image, ImageMap, ImageMapArea, Interpretation, Item, License, Link, Metadata, Note, Observation, Period, Person, Property, PropertyValue, PropertyValueContent, PropertyValueContentType, PropertyValueQueryItem, PropertyVariable, Query, QueryGroup, QueryLeaf, Resource, Scope, Section, Set, SetAttributeValueQueryItem, SetItemsSort, SetItemsSortDirection, SpatialUnit, Style, StylesheetCategory, StylesheetItem, Text, Tree, WebBlock, WebBlockLayout, WebElement, WebElementComponent, WebImage, WebSegment, WebSegmentItem, WebTitle, Webpage, Website, WebsitePropertyQuery, WebsitePropertyQueryNode, WebsiteType, fetchGallery, fetchItem, fetchSetItems, fetchSetPropertyValues, fetchWebsite, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByLabel, getPropertyByLabelAndValue, getPropertyByLabelAndValueContent, getPropertyByLabelAndValueContents, getPropertyByLabelAndValues, getPropertyByUuid, getPropertyValueByLabel, getPropertyValueByUuid, getPropertyValueContentByLabel, getPropertyValueContentByUuid, getPropertyValueContentsByUuid, getPropertyValuesByLabel, getPropertyValuesByUuid, getUniqueProperties, getUniquePropertyLabels };
1627
+ export { ApiVersion, Bibliography, Concept, Context, ContextItem, ContextNode, ContextTree, ContextTreeFilterLevel, ContextTreeLevel, ContextTreeLevelItem, Coordinate, DEFAULT_API_VERSION, DEFAULT_PAGE_SIZE, Data, DataCategory, Event, FileFormat, Gallery, Identification, Image, ImageMap, ImageMapArea, Interpretation, Item, License, Link, Metadata, Note, Observation, Period, Person, Property, PropertyValue, PropertyValueContent, PropertyValueContentType, PropertyValueQueryItem, PropertyVariable, Query, QueryGroup, QueryLeaf, Resource, Scope, Section, Set, SetAttributeValueQueryItem, SetItemsSort, SetItemsSortDirection, SpatialUnit, Style, StylesheetCategory, StylesheetItem, Text, Tree, WebBlock, WebBlockLayout, WebElement, WebElementComponent, WebImage, WebSegment, WebSegmentItem, WebTitle, Webpage, Website, WebsitePropertyQuery, WebsitePropertyQueryNode, WebsiteType, fetchGallery, fetchItem, fetchItemLinks, fetchSetItems, fetchSetPropertyValues, fetchWebsite, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByLabel, getPropertyByLabelAndValue, getPropertyByLabelAndValueContent, getPropertyByLabelAndValueContents, getPropertyByLabelAndValues, getPropertyByUuid, getPropertyValueByLabel, getPropertyValueByUuid, getPropertyValueContentByLabel, getPropertyValueContentByUuid, getPropertyValueContentsByUuid, getPropertyValuesByLabel, getPropertyValuesByUuid, getUniqueProperties, getUniquePropertyLabels };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import * as z from "zod";
1
+ import * as v from "valibot";
2
2
  import { parseISO, set } from "date-fns";
3
3
  import { UTCDate } from "@date-fns/utc";
4
4
  import { deepEqual } from "fast-equals";
@@ -48,7 +48,7 @@ function parseEmail(string) {
48
48
  const index = string.indexOf(cleanString);
49
49
  const before = string.slice(0, index);
50
50
  const after = string.slice(index + cleanString.length);
51
- if (emailSchema.safeParse(cleanString).success) {
51
+ if (v.safeParse(emailSchema, cleanString).success) {
52
52
  returnSplitString.push(`${before}<ExternalLink href="mailto:${cleanString}">${cleanString}</ExternalLink>${after}`);
53
53
  continue;
54
54
  }
@@ -66,12 +66,12 @@ function parseEmail(string) {
66
66
  */
67
67
  function parseRenderOptions(contentString, renderString) {
68
68
  let returnString = contentString;
69
- const result = renderOptionsSchema.safeParse(renderString);
69
+ const result = v.safeParse(renderOptionsSchema, renderString);
70
70
  if (!result.success) {
71
71
  console.warn(`Invalid render options string provided: “${renderString}”`);
72
72
  return contentString;
73
73
  }
74
- for (const option of result.data) switch (option) {
74
+ for (const option of result.output) switch (option) {
75
75
  case "bold":
76
76
  returnString = `**${returnString}**`;
77
77
  break;
@@ -94,12 +94,12 @@ function parseRenderOptions(contentString, renderString) {
94
94
  */
95
95
  function parseWhitespace(contentString, whitespace) {
96
96
  let returnString = contentString;
97
- const result = whitespaceSchema.safeParse(whitespace);
97
+ const result = v.safeParse(whitespaceSchema, whitespace);
98
98
  if (!result.success) {
99
99
  console.warn(`Invalid whitespace string provided: “${whitespace}”`);
100
100
  return contentString;
101
101
  }
102
- for (const option of result.data) switch (option) {
102
+ for (const option of result.output) switch (option) {
103
103
  case "newline":
104
104
  if (returnString.trim() === "***") returnString = `${returnString}\n`;
105
105
  else returnString = `<br />\n${returnString}`;
@@ -447,7 +447,7 @@ const PSEUDO_UUID_REGEX = /^[\da-f]{8}(?:-[\da-f]{4}){3}-[\da-f]{12}$/i;
447
447
  * @internal
448
448
  */
449
449
  function getItemCategory(keys) {
450
- const categoryFound = keys.find((key) => categorySchema.safeParse(key).success);
450
+ const categoryFound = keys.find((key) => v.safeParse(categorySchema, key).success);
451
451
  if (!categoryFound) {
452
452
  const unknownKey = keys.find((key) => ![
453
453
  "uuid",
@@ -459,7 +459,7 @@ function getItemCategory(keys) {
459
459
  ].includes(key));
460
460
  throw new Error(`Invalid OCHRE data; found unexpected "${unknownKey}" key`);
461
461
  }
462
- return categorySchema.parse(categoryFound);
462
+ return v.parse(categorySchema, categoryFound);
463
463
  }
464
464
  /**
465
465
  * Get the categories of items from the OCHRE API response
@@ -468,9 +468,9 @@ function getItemCategory(keys) {
468
468
  * @internal
469
469
  */
470
470
  function getItemCategories(keys) {
471
- const categories = keys.map((key) => categorySchema.safeParse(key));
472
- if (categories.some((result) => !result.success)) throw new Error(`Invalid OCHRE data; found unexpected keys: ${categories.filter((result) => !result.success).map((result) => result.error.message).join(", ")}`);
473
- return categories.filter((result) => result.success).map((result) => result.data);
471
+ const categories = keys.map((key) => v.safeParse(categorySchema, key));
472
+ if (categories.some((result) => !result.success)) throw new Error(`Invalid OCHRE data; found unexpected keys: ${categories.filter((result) => !result.success).flatMap((result) => result.issues.map((issue) => issue.message)).join(", ")}`);
473
+ return categories.filter((result) => result.success).map((result) => result.output);
474
474
  }
475
475
  /**
476
476
  * Validates a pseudo-UUID string
@@ -601,54 +601,58 @@ function flattenItemProperties(item) {
601
601
  }
602
602
  //#endregion
603
603
  //#region src/schemas.ts
604
+ const positiveNumber = (message) => v.pipe(v.number(), v.minValue(1, message));
605
+ const defaultString = (value) => v.optional(v.string(), value);
606
+ const defaultBoolean = (value) => v.optional(v.boolean(), value);
607
+ const sortDirectionSchema = v.optional(v.picklist(["asc", "desc"]), "asc");
604
608
  /**
605
609
  * Schema for validating UUIDs
606
610
  * @internal
607
611
  */
608
- const uuidSchema = z.string().refine(isPseudoUuid, { error: "Invalid pseudo-UUID" });
609
- const fakeStringSchema = z.union([
610
- z.string(),
611
- z.number(),
612
- z.boolean()
612
+ const uuidSchema = v.pipe(v.string(), v.check(isPseudoUuid, "Invalid pseudo-UUID"));
613
+ const fakeStringSchema = v.union([
614
+ v.string(),
615
+ v.number(),
616
+ v.boolean()
613
617
  ]);
614
- const richTextStringContentSchema = z.union([fakeStringSchema, z.object({
615
- content: fakeStringSchema.optional(),
616
- rend: z.string().optional(),
617
- whitespace: z.string().optional()
618
+ const richTextStringContentSchema = v.union([fakeStringSchema, v.object({
619
+ content: v.optional(fakeStringSchema),
620
+ rend: v.optional(v.string()),
621
+ whitespace: v.optional(v.string())
618
622
  })]);
619
623
  /**
620
624
  * Schema for validating rich text string content
621
625
  * @internal
622
626
  */
623
- const richTextStringSchema = z.object({
624
- string: z.union([
627
+ const richTextStringSchema = v.object({
628
+ string: v.union([
625
629
  fakeStringSchema,
626
630
  richTextStringContentSchema,
627
- z.array(richTextStringContentSchema)
631
+ v.array(richTextStringContentSchema)
628
632
  ]),
629
- lang: z.string().optional()
633
+ lang: v.optional(v.string())
630
634
  });
631
- z.object({
632
- label: z.object({ content: z.union([richTextStringSchema, z.array(richTextStringSchema)]) }),
633
- abbreviation: z.object({ content: z.union([richTextStringSchema, z.array(richTextStringSchema)]).optional() }),
634
- code: z.string().optional()
635
+ v.object({
636
+ label: v.object({ content: v.union([richTextStringSchema, v.array(richTextStringSchema)]) }),
637
+ abbreviation: v.object({ content: v.optional(v.union([richTextStringSchema, v.array(richTextStringSchema)])) }),
638
+ code: v.optional(v.string())
635
639
  });
636
- z.string().optional();
637
- z.object({
638
- filter: z.string().optional().default(""),
639
- start: z.number().positive({ error: "Start must be positive" }).optional().default(1),
640
- limit: z.number().positive({ error: "Limit must be positive" }).optional().default(40)
641
- }).optional().default({
640
+ v.optional(v.string());
641
+ v.optional(v.object({
642
+ filter: defaultString(""),
643
+ start: v.optional(positiveNumber("Start must be positive"), 1),
644
+ limit: v.optional(positiveNumber("Limit must be positive"), 40)
645
+ }), {
642
646
  filter: "",
643
647
  start: 1,
644
648
  limit: 40
645
649
  });
646
- const apiVersionSuffixSchema = z.enum(["-v1", "-v2"]).transform((suffix) => Number.parseInt(suffix.replace("-v", ""), 10));
650
+ const apiVersionSuffixSchema = v.pipe(v.picklist(["-v1", "-v2"]), v.transform((suffix) => Number.parseInt(suffix.replace("-v", ""), 10)));
647
651
  /**
648
652
  * Valid component types for web elements
649
653
  * @internal
650
654
  */
651
- const componentSchema = z.enum([
655
+ const componentSchema = v.picklist([
652
656
  "3d-viewer",
653
657
  "advanced-search",
654
658
  "annotated-document",
@@ -670,12 +674,12 @@ const componentSchema = z.enum([
670
674
  "text",
671
675
  "timeline",
672
676
  "video"
673
- ], { error: "Invalid component" });
677
+ ], "Invalid component");
674
678
  /**
675
679
  * Schema for validating data categories
676
680
  * @internal
677
681
  */
678
- const categorySchema = z.enum([
682
+ const categorySchema = v.picklist([
679
683
  "resource",
680
684
  "spatialUnit",
681
685
  "concept",
@@ -692,7 +696,7 @@ const categorySchema = z.enum([
692
696
  * Schema for validating property value content types
693
697
  * @internal
694
698
  */
695
- const propertyValueContentTypeSchema = z.enum([
699
+ const propertyValueContentTypeSchema = v.picklist([
696
700
  "string",
697
701
  "integer",
698
702
  "decimal",
@@ -707,7 +711,7 @@ const propertyValueContentTypeSchema = z.enum([
707
711
  * Schema for validating and parsing render options
708
712
  * @internal
709
713
  */
710
- const renderOptionsSchema = z.string().transform((str) => str.split(" ")).pipe(z.array(z.enum([
714
+ const renderOptionsSchema = v.pipe(v.string(), v.transform((str) => str.split(" ")), v.array(v.picklist([
711
715
  "bold",
712
716
  "italic",
713
717
  "underline"
@@ -716,7 +720,7 @@ const renderOptionsSchema = z.string().transform((str) => str.split(" ")).pipe(z
716
720
  * Schema for validating and parsing whitespace options
717
721
  * @internal
718
722
  */
719
- const whitespaceSchema = z.string().transform((str) => str.split(" ")).pipe(z.array(z.enum([
723
+ const whitespaceSchema = v.pipe(v.string(), v.transform((str) => str.split(" ")), v.array(v.picklist([
720
724
  "newline",
721
725
  "trailing",
722
726
  "leading"
@@ -725,42 +729,41 @@ const whitespaceSchema = z.string().transform((str) => str.split(" ")).pipe(z.ar
725
729
  * Schema for validating email addresses
726
730
  * @internal
727
731
  */
728
- const emailSchema = z.email({ error: "Invalid email" });
732
+ const emailSchema = v.pipe(v.string(), v.email("Invalid email"));
729
733
  /**
730
734
  * Schema for parsing and validating a string in the format "[[number, number], [number, number]]"
731
735
  * into an array with exactly two bounds
732
736
  * @internal
733
737
  */
734
- const boundsSchema = z.string().transform((str, ctx) => {
735
- const trimmed = str.trim();
738
+ const boundsSchema = v.pipe(v.string(), v.rawTransform(({ dataset, addIssue, NEVER }) => {
739
+ const trimmed = dataset.value.trim();
736
740
  if (!trimmed.startsWith("[[") || !trimmed.endsWith("]]")) {
737
- ctx.addIssue({
738
- code: "invalid_format",
739
- format: "string",
740
- message: "String must start with '[[' and end with ']]'"
741
- });
742
- return z.NEVER;
741
+ addIssue({ message: "String must start with '[[' and end with ']]'" });
742
+ return NEVER;
743
743
  }
744
744
  try {
745
745
  return JSON.parse(trimmed);
746
746
  } catch {
747
- ctx.addIssue({
748
- code: "invalid_format",
749
- format: "string",
750
- message: "Invalid JSON format"
751
- });
752
- return z.NEVER;
747
+ addIssue({ message: "Invalid JSON format" });
748
+ return NEVER;
753
749
  }
754
- }).pipe(z.tuple([z.tuple([z.number(), z.number()]), z.tuple([z.number(), z.number()])], { message: "Must contain exactly 2 coordinate pairs" }));
750
+ }), v.tuple([v.tuple([v.number(), v.number()]), v.tuple([v.number(), v.number()])], "Must contain exactly 2 coordinate pairs"));
751
+ const dateDataTypeSchema = v.picklist(["date", "dateTime"]);
752
+ const standardQueryFields = {
753
+ matchMode: v.picklist(["includes", "exact"]),
754
+ isCaseSensitive: v.boolean(),
755
+ language: defaultString("eng"),
756
+ isNegated: defaultBoolean(false)
757
+ };
755
758
  /**
756
759
  * Shared schema for Set queries
757
760
  * @internal
758
761
  */
759
- const setQueryLeafSchema = z.union([
760
- z.object({
761
- target: z.literal("property"),
762
- propertyVariable: uuidSchema.optional(),
763
- dataType: z.enum([
762
+ const setQueryLeafSchema = v.union([
763
+ v.pipe(v.strictObject({
764
+ target: v.literal("property"),
765
+ propertyVariable: v.optional(uuidSchema),
766
+ dataType: v.picklist([
764
767
  "string",
765
768
  "integer",
766
769
  "decimal",
@@ -768,73 +771,50 @@ const setQueryLeafSchema = z.union([
768
771
  "time",
769
772
  "IDREF"
770
773
  ]),
771
- value: z.string().optional(),
772
- matchMode: z.enum(["includes", "exact"]),
773
- isCaseSensitive: z.boolean(),
774
- language: z.string().default("eng"),
775
- isNegated: z.boolean().optional().default(false)
776
- }).strict().superRefine((value, ctx) => {
777
- if (value.propertyVariable == null && value.value == null) ctx.addIssue({
778
- code: "custom",
779
- message: "Property queries must include at least one propertyVariable or value"
780
- });
781
- }),
782
- z.object({
783
- target: z.literal("property"),
774
+ value: v.optional(v.string()),
775
+ ...standardQueryFields
776
+ }), v.check((value) => value.propertyVariable != null || value.value != null, "Property queries must include at least one propertyVariable or value")),
777
+ v.strictObject({
778
+ target: v.literal("property"),
784
779
  propertyVariable: uuidSchema,
785
- dataType: z.enum(["date", "dateTime"]),
786
- value: z.string(),
787
- from: z.never().optional(),
788
- to: z.never().optional(),
789
- matchMode: z.enum(["includes", "exact"]),
790
- isCaseSensitive: z.boolean(),
791
- language: z.string().default("eng"),
792
- isNegated: z.boolean().optional().default(false)
793
- }).strict(),
794
- z.object({
795
- target: z.literal("property"),
780
+ dataType: dateDataTypeSchema,
781
+ value: v.string(),
782
+ from: v.optional(v.never()),
783
+ to: v.optional(v.never()),
784
+ ...standardQueryFields
785
+ }),
786
+ v.strictObject({
787
+ target: v.literal("property"),
796
788
  propertyVariable: uuidSchema,
797
- dataType: z.enum(["date", "dateTime"]),
798
- value: z.never().optional(),
799
- from: z.string(),
800
- to: z.string().optional(),
801
- matchMode: z.enum(["includes", "exact"]),
802
- isCaseSensitive: z.boolean(),
803
- language: z.string().default("eng"),
804
- isNegated: z.boolean().optional().default(false)
805
- }).strict(),
806
- z.object({
807
- target: z.literal("property"),
789
+ dataType: dateDataTypeSchema,
790
+ value: v.optional(v.never()),
791
+ from: v.string(),
792
+ to: v.optional(v.string()),
793
+ ...standardQueryFields
794
+ }),
795
+ v.strictObject({
796
+ target: v.literal("property"),
808
797
  propertyVariable: uuidSchema,
809
- dataType: z.enum(["date", "dateTime"]),
810
- value: z.never().optional(),
811
- from: z.string().optional(),
812
- to: z.string(),
813
- matchMode: z.enum(["includes", "exact"]),
814
- isCaseSensitive: z.boolean(),
815
- language: z.string().default("eng"),
816
- isNegated: z.boolean().optional().default(false)
817
- }).strict(),
818
- z.object({
819
- target: z.literal("property"),
820
- propertyVariable: uuidSchema.optional(),
821
- dataType: z.literal("all"),
822
- value: z.string(),
823
- matchMode: z.enum(["includes", "exact"]),
824
- isCaseSensitive: z.boolean(),
825
- language: z.string().default("eng"),
826
- isNegated: z.boolean().optional().default(false)
827
- }).strict(),
828
- z.object({
829
- target: z.literal("string"),
830
- value: z.string(),
831
- matchMode: z.enum(["includes", "exact"]),
832
- isCaseSensitive: z.boolean(),
833
- language: z.string().default("eng"),
834
- isNegated: z.boolean().optional().default(false)
835
- }).strict(),
836
- z.object({
837
- target: z.enum([
798
+ dataType: dateDataTypeSchema,
799
+ value: v.optional(v.never()),
800
+ from: v.optional(v.string()),
801
+ to: v.string(),
802
+ ...standardQueryFields
803
+ }),
804
+ v.strictObject({
805
+ target: v.literal("property"),
806
+ propertyVariable: v.optional(uuidSchema),
807
+ dataType: v.literal("all"),
808
+ value: v.string(),
809
+ ...standardQueryFields
810
+ }),
811
+ v.strictObject({
812
+ target: v.literal("string"),
813
+ value: v.string(),
814
+ ...standardQueryFields
815
+ }),
816
+ v.strictObject({
817
+ target: v.picklist([
838
818
  "title",
839
819
  "description",
840
820
  "image",
@@ -842,30 +822,27 @@ const setQueryLeafSchema = z.union([
842
822
  "bibliography",
843
823
  "notes"
844
824
  ]),
845
- value: z.string(),
846
- matchMode: z.enum(["includes", "exact"]),
847
- isCaseSensitive: z.boolean(),
848
- language: z.string().default("eng"),
849
- isNegated: z.boolean().optional().default(false)
850
- }).strict()
825
+ value: v.string(),
826
+ ...standardQueryFields
827
+ })
851
828
  ]);
852
- const setQuerySchema = z.lazy(() => z.union([
829
+ const setQuerySchema = v.lazy(() => v.union([
853
830
  setQueryLeafSchema,
854
- z.object({ and: z.array(setQuerySchema).min(1, "AND groups must contain at least one query") }).strict(),
855
- z.object({ or: z.array(setQuerySchema).min(1, "OR groups must contain at least one query") }).strict()
831
+ v.strictObject({ and: v.pipe(v.array(setQuerySchema), v.minLength(1, "AND groups must contain at least one query")) }),
832
+ v.strictObject({ or: v.pipe(v.array(setQuerySchema), v.minLength(1, "OR groups must contain at least one query")) })
856
833
  ]));
857
- const setQueriesSchema = setQuerySchema.nullable().default(null);
858
- const setItemsSortSchema = z.discriminatedUnion("target", [
859
- z.object({ target: z.literal("none") }).strict(),
860
- z.object({
861
- target: z.literal("title"),
862
- direction: z.enum(["asc", "desc"]).default("asc"),
863
- language: z.string().default("eng")
864
- }).strict(),
865
- z.object({
866
- target: z.literal("propertyValue"),
834
+ const setQueriesSchema = v.optional(v.nullable(setQuerySchema), null);
835
+ const setItemsSortSchema = v.optional(v.variant("target", [
836
+ v.strictObject({ target: v.literal("none") }),
837
+ v.strictObject({
838
+ target: v.literal("title"),
839
+ direction: sortDirectionSchema,
840
+ language: defaultString("eng")
841
+ }),
842
+ v.strictObject({
843
+ target: v.literal("propertyValue"),
867
844
  propertyVariableUuid: uuidSchema,
868
- dataType: z.enum([
845
+ dataType: v.picklist([
869
846
  "string",
870
847
  "integer",
871
848
  "decimal",
@@ -875,34 +852,34 @@ const setItemsSortSchema = z.discriminatedUnion("target", [
875
852
  "time",
876
853
  "IDREF"
877
854
  ]),
878
- direction: z.enum(["asc", "desc"]).default("asc"),
879
- language: z.string().default("eng")
880
- }).strict()
881
- ]).default({ target: "none" });
855
+ direction: sortDirectionSchema,
856
+ language: defaultString("eng")
857
+ })
858
+ ]), { target: "none" });
882
859
  /**
883
860
  * Schema for validating the parameters for the Set property values fetching function
884
861
  * @internal
885
862
  */
886
- const setPropertyValuesParamsSchema = z.object({
887
- setScopeUuids: z.array(uuidSchema).min(1, "At least one set scope UUID is required"),
888
- belongsToCollectionScopeUuids: z.array(uuidSchema).default([]),
863
+ const setPropertyValuesParamsSchema = v.object({
864
+ setScopeUuids: v.pipe(v.array(uuidSchema), v.minLength(1, "At least one set scope UUID is required")),
865
+ belongsToCollectionScopeUuids: v.optional(v.array(uuidSchema), []),
889
866
  queries: setQueriesSchema,
890
- attributes: z.object({
891
- bibliographies: z.boolean().default(false),
892
- periods: z.boolean().default(false)
893
- }).default({
867
+ attributes: v.optional(v.object({
868
+ bibliographies: defaultBoolean(false),
869
+ periods: defaultBoolean(false)
870
+ }), {
894
871
  bibliographies: false,
895
872
  periods: false
896
873
  }),
897
- isLimitedToLeafPropertyValues: z.boolean().default(false)
874
+ isLimitedToLeafPropertyValues: defaultBoolean(false)
898
875
  });
899
- const setItemsParamsSchema = z.object({
900
- setScopeUuids: z.array(uuidSchema).min(1, "At least one set scope UUID is required"),
901
- belongsToCollectionScopeUuids: z.array(uuidSchema).default([]),
876
+ const setItemsParamsSchema = v.object({
877
+ setScopeUuids: v.pipe(v.array(uuidSchema), v.minLength(1, "At least one set scope UUID is required")),
878
+ belongsToCollectionScopeUuids: v.optional(v.array(uuidSchema), []),
902
879
  queries: setQueriesSchema,
903
880
  sort: setItemsSortSchema,
904
- page: z.number().min(1, "Page must be positive").default(1),
905
- pageSize: z.number().min(1, "Page size must be positive").default(48)
881
+ page: v.optional(positiveNumber("Page must be positive"), 1),
882
+ pageSize: v.optional(positiveNumber("Page size must be positive"), 48)
906
883
  });
907
884
  //#endregion
908
885
  //#region src/utils/parse/index.ts
@@ -1352,9 +1329,9 @@ function parseProperty(property, language = "eng") {
1352
1329
  } else {
1353
1330
  let parsedType = "string";
1354
1331
  if (value.dataType != null) {
1355
- const { data, error } = propertyValueContentTypeSchema.safeParse(value.dataType);
1356
- if (error) throw new Error(`Invalid property value content type: "${value.dataType}"`);
1357
- parsedType = data;
1332
+ const result = v.safeParse(propertyValueContentTypeSchema, value.dataType);
1333
+ if (!result.success) throw new Error(`Invalid property value content type: "${value.dataType}"`);
1334
+ parsedType = result.output;
1358
1335
  }
1359
1336
  switch (parsedType) {
1360
1337
  case "integer":
@@ -1984,11 +1961,11 @@ function parseConcepts(concepts) {
1984
1961
  /**
1985
1962
  * Schema for validating gallery parameters
1986
1963
  */
1987
- const galleryParamsSchema = z.object({
1964
+ const galleryParamsSchema = v.object({
1988
1965
  uuid: uuidSchema,
1989
- filter: z.string().optional(),
1990
- page: z.number().positive({ error: "Page must be positive" }),
1991
- pageSize: z.number().positive({ error: "Page size must be positive" })
1966
+ filter: v.optional(v.string()),
1967
+ page: v.pipe(v.number(), v.minValue(1, "Page must be positive")),
1968
+ pageSize: v.pipe(v.number(), v.minValue(1, "Page size must be positive"))
1992
1969
  });
1993
1970
  /**
1994
1971
  * Fetches and parses a gallery from the OCHRE API
@@ -2006,7 +1983,7 @@ const galleryParamsSchema = z.object({
2006
1983
  async function fetchGallery(params, options) {
2007
1984
  try {
2008
1985
  const version = options?.version ?? 2;
2009
- const { uuid, filter, page, pageSize } = galleryParamsSchema.parse(params);
1986
+ const { uuid, filter, page, pageSize } = v.parse(galleryParamsSchema, params);
2010
1987
  const response = await (options?.fetch ?? fetch)(`${version === 2 ? "https://ochre.lib.uchicago.edu/ochre/v2/ochre.php" : "https://ochre.lib.uchicago.edu/ochre"}?xquery=${encodeURIComponent(`<ochre>{
2011
1988
  for $q in ${version === 2 ? "doc()" : "input()"}/ochre[@uuid='${uuid}']
2012
1989
  let $filtered := $q//items/resource[contains(lower-case(identification/label), lower-case('${filter}'))]
@@ -2038,6 +2015,99 @@ async function fetchGallery(params, options) {
2038
2015
  }
2039
2016
  }
2040
2017
  //#endregion
2018
+ //#region src/utils/fetchers/item-links.ts
2019
+ /**
2020
+ * Build an XQuery string to fetch item links from the OCHRE API
2021
+ * @param params - The parameters for the fetch
2022
+ * @param params.uuid - The UUID of the OCHRE item to fetch
2023
+ * @returns An XQuery string
2024
+ */
2025
+ function buildXQuery$2(params) {
2026
+ const { uuid } = params;
2027
+ return `<ochre>{${`let $item-uuid := "${uuid}"
2028
+
2029
+ let $uuids :=
2030
+ distinct-values((
2031
+
2032
+ (: Direct links on most item categories :)
2033
+ fn:collection("ochre/resource")/ochre[@uuid = $item-uuid]/resource/links/*/@uuid/string(),
2034
+ fn:collection("ochre/bibliography")/ochre[@uuid = $item-uuid]/bibliography/links/*/@uuid/string(),
2035
+ fn:collection("ochre/period")/ochre[@uuid = $item-uuid]/period/links/*/@uuid/string(),
2036
+ fn:collection("ochre/person")/ochre[@uuid = $item-uuid]/person/links/*/@uuid/string(),
2037
+ fn:collection("ochre/propertyVariable")/ochre[@uuid = $item-uuid]/propertyVariable/links/*/@uuid/string(),
2038
+ fn:collection("ochre/propertyValue")/ochre[@uuid = $item-uuid]/propertyValue/links/*/@uuid/string(),
2039
+ fn:collection("ochre/text")/ochre[@uuid = $item-uuid]/text/links/*/@uuid/string(),
2040
+ fn:collection("ochre/tree")/ochre[@uuid = $item-uuid]/tree/links/*/@uuid/string(),
2041
+ fn:collection("ochre/set")/ochre[@uuid = $item-uuid]/set/links/*/@uuid/string(),
2042
+
2043
+ (: Special category structures :)
2044
+ fn:collection("ochre/spatialUnit")/ochre[@uuid = $item-uuid]/spatialUnit/observations/observation/links/*/@uuid/string(),
2045
+ fn:collection("ochre/concept")/ochre[@uuid = $item-uuid]/concept/interpretations/interpretation/links/*/@uuid/string()
2046
+ ))
2047
+
2048
+ return
2049
+ <items>{(
2050
+ fn:collection("ochre/resource")/ochre/resource[@uuid = $uuids],
2051
+ fn:collection("ochre/bibliography")/ochre/bibliography[@uuid = $uuids],
2052
+ fn:collection("ochre/period")/ochre/period[@uuid = $uuids],
2053
+ fn:collection("ochre/person")/ochre/person[@uuid = $uuids],
2054
+ fn:collection("ochre/propertyVariable")/ochre/propertyVariable[@uuid = $uuids],
2055
+ fn:collection("ochre/propertyValue")/ochre/propertyValue[@uuid = $uuids],
2056
+ fn:collection("ochre/text")/ochre/text[@uuid = $uuids],
2057
+ fn:collection("ochre/tree")/ochre/tree[@uuid = $uuids],
2058
+ fn:collection("ochre/set")/ochre/set[@uuid = $uuids],
2059
+ fn:collection("ochre/spatialUnit")/ochre/spatialUnit[@uuid = $uuids],
2060
+ fn:collection("ochre/concept")/ochre/concept[@uuid = $uuids]
2061
+ )}</items>`}}</ochre>`;
2062
+ }
2063
+ /**
2064
+ * Fetches and parses an OCHRE item links from the OCHRE API
2065
+ *
2066
+ * @param uuid - The UUID of the OCHRE item to fetch
2067
+ * @param category - The category of the OCHRE item to fetch
2068
+ * @param itemCategories - The categories of the OCHRE linked items to fetch
2069
+ * @param options - The options for the fetch
2070
+ * @param options.fetch - The fetch function to use
2071
+ * @param options.version - The version of the OCHRE API to use
2072
+ * @returns Object containing the parsed OCHRE item links, or an error message if the fetch/parse fails
2073
+ */
2074
+ async function fetchItemLinks(uuid, category, itemCategories, options) {
2075
+ try {
2076
+ if (options?.version != null && options.version !== 2) throw new Error("Set item queries only support API version 2");
2077
+ const xquery = buildXQuery$2({ uuid });
2078
+ const response = await (options?.fetch ?? fetch)("https://ochre.lib.uchicago.edu/ochre/v2/ochre.php?xquery&format=json", {
2079
+ method: "POST",
2080
+ body: xquery,
2081
+ headers: { "Content-Type": "application/xquery" }
2082
+ });
2083
+ if (!response.ok) throw new Error(`OCHRE API responded with status: ${response.status}`);
2084
+ const data = await response.json();
2085
+ if (Array.isArray(data.result) || Object.keys(data.result).length === 0) throw new Error("Invalid OCHRE API response");
2086
+ const rawItems = data.result.ochre.items;
2087
+ const items = [];
2088
+ if (rawItems.resource != null) items.push(...parseResources(ensureArray(rawItems.resource)));
2089
+ if (rawItems.spatialUnit != null) items.push(...parseSpatialUnits(ensureArray(rawItems.spatialUnit)));
2090
+ if (rawItems.concept != null) items.push(...parseConcepts(ensureArray(rawItems.concept)));
2091
+ if (rawItems.period != null) items.push(...parsePeriods(ensureArray(rawItems.period)));
2092
+ if (rawItems.bibliography != null) items.push(...parseBibliographies(ensureArray(rawItems.bibliography)));
2093
+ if (rawItems.person != null) items.push(...parsePersons(ensureArray(rawItems.person)));
2094
+ if (rawItems.propertyVariable != null) items.push(...parsePropertyVariables(ensureArray(rawItems.propertyVariable)));
2095
+ if (rawItems.propertyValue != null) items.push(...parsePropertyValues(ensureArray(rawItems.propertyValue)));
2096
+ if (rawItems.text != null) items.push(...parseTexts(ensureArray(rawItems.text)));
2097
+ if (rawItems.set != null) for (const linkedSet of ensureArray(rawItems.set)) items.push(parseSet(linkedSet, itemCategories));
2098
+ if (rawItems.tree != null) for (const linkedTree of ensureArray(rawItems.tree)) items.push(parseTree(linkedTree, itemCategories));
2099
+ return {
2100
+ error: null,
2101
+ items
2102
+ };
2103
+ } catch (error) {
2104
+ return {
2105
+ error: error instanceof Error ? error.message : "Unknown error",
2106
+ items: void 0
2107
+ };
2108
+ }
2109
+ }
2110
+ //#endregion
2041
2111
  //#region src/utils/fetchers/uuid.ts
2042
2112
  /**
2043
2113
  * Fetches raw OCHRE data by UUID from the OCHRE API
@@ -2049,7 +2119,7 @@ async function fetchGallery(params, options) {
2049
2119
  async function fetchByUuid(uuid, options) {
2050
2120
  try {
2051
2121
  const version = options?.version ?? 2;
2052
- const parsedUuid = uuidSchema.parse(uuid);
2122
+ const parsedUuid = v.parse(uuidSchema, uuid);
2053
2123
  const response = await (options?.fetch ?? fetch)(version === 2 ? `https://ochre.lib.uchicago.edu/ochre/v2/ochre.php?uuid=${parsedUuid}&format=json&lang="*"` : `https://ochre.lib.uchicago.edu/ochre?uuid=${parsedUuid}&format=json&lang="*"`);
2054
2124
  if (!response.ok) throw new Error("Failed to fetch OCHRE data");
2055
2125
  const dataRaw = await response.json();
@@ -3151,7 +3221,7 @@ ${itemsClause}
3151
3221
  async function fetchSetItems(params, itemCategories, options) {
3152
3222
  try {
3153
3223
  if (options?.version != null && options.version !== 2) throw new Error("Set item queries only support API version 2");
3154
- const { setScopeUuids, belongsToCollectionScopeUuids, queries, sort, page, pageSize } = setItemsParamsSchema.parse(params);
3224
+ const { setScopeUuids, belongsToCollectionScopeUuids, queries, sort, page, pageSize } = v.parse(setItemsParamsSchema, params);
3155
3225
  const xquery = buildXQuery$1({
3156
3226
  setScopeUuids,
3157
3227
  belongsToCollectionScopeUuids,
@@ -3267,11 +3337,11 @@ function sortAttributeValues(values) {
3267
3337
  return a.content.localeCompare(b.content);
3268
3338
  });
3269
3339
  }
3270
- const countSchema = z.union([z.number(), z.string()]).optional().transform((val) => {
3271
- if (val == null || val === "") return 1;
3340
+ const countSchema = v.pipe(v.optional(v.union([v.number(), v.string()]), 1), v.transform((val) => {
3341
+ if (val === "") return 1;
3272
3342
  const count = Number(val);
3273
3343
  return Number.isFinite(count) ? count : 1;
3274
- });
3344
+ }));
3275
3345
  function getPropertyVariableUuidsFromQueries(queries) {
3276
3346
  const propertyVariableUuids = /* @__PURE__ */ new Set();
3277
3347
  if (queries == null) return [];
@@ -3306,20 +3376,20 @@ function getItemFilterQueriesFromPropertyValueQueries(queries) {
3306
3376
  /**
3307
3377
  * Schema for a single property value query item in the OCHRE API response
3308
3378
  */
3309
- const propertyValueQueryItemSchema = z.object({
3310
- uuid: z.string(),
3311
- scope: z.enum(["global", "variable"]).default("global"),
3312
- variableUuid: z.string().optional(),
3379
+ const propertyValueQueryItemSchema = v.pipe(v.object({
3380
+ uuid: v.string(),
3381
+ scope: v.optional(v.picklist(["global", "variable"]), "global"),
3382
+ variableUuid: v.optional(v.string()),
3313
3383
  count: countSchema,
3314
- globalCount: countSchema.nullish(),
3315
- dataType: z.string(),
3316
- rawValue: fakeStringSchema.optional(),
3317
- content: z.union([
3384
+ globalCount: v.nullish(countSchema),
3385
+ dataType: v.string(),
3386
+ rawValue: v.optional(fakeStringSchema),
3387
+ content: v.optional(v.union([
3318
3388
  fakeStringSchema,
3319
3389
  richTextStringSchema,
3320
- z.array(richTextStringSchema)
3321
- ]).optional()
3322
- }).transform((val) => {
3390
+ v.array(richTextStringSchema)
3391
+ ]))
3392
+ }), v.transform((val) => {
3323
3393
  const returnValue = {
3324
3394
  scope: val.scope,
3325
3395
  variableUuid: val.variableUuid != null && val.variableUuid !== "" ? val.variableUuid : null,
@@ -3353,23 +3423,23 @@ const propertyValueQueryItemSchema = z.object({
3353
3423
  break;
3354
3424
  }
3355
3425
  return returnValue;
3356
- });
3357
- const attributeValueQueryItemSchema = z.object({
3358
- attributeType: z.enum(["bibliographies", "periods"]),
3426
+ }));
3427
+ const attributeValueQueryItemSchema = v.pipe(v.object({
3428
+ attributeType: v.picklist(["bibliographies", "periods"]),
3359
3429
  count: countSchema,
3360
- content: z.string().optional()
3361
- }).transform((val) => ({
3430
+ content: v.optional(v.string())
3431
+ }), v.transform((val) => ({
3362
3432
  attributeType: val.attributeType,
3363
3433
  count: val.count,
3364
3434
  content: val.content != null && val.content !== "" ? val.content : null
3365
- }));
3435
+ })));
3366
3436
  /**
3367
3437
  * Schema for the property values OCHRE API response
3368
3438
  */
3369
- const responseSchema = z.object({ result: z.union([z.object({ ochre: z.object({
3370
- propertyValue: z.union([propertyValueQueryItemSchema, z.array(propertyValueQueryItemSchema)]).optional(),
3371
- attributeValue: z.union([attributeValueQueryItemSchema, z.array(attributeValueQueryItemSchema)]).optional()
3372
- }) }), z.array(z.unknown()).length(0)]) });
3439
+ const responseSchema = v.object({ result: v.union([v.object({ ochre: v.object({
3440
+ propertyValue: v.optional(v.union([propertyValueQueryItemSchema, v.array(propertyValueQueryItemSchema)])),
3441
+ attributeValue: v.optional(v.union([attributeValueQueryItemSchema, v.array(attributeValueQueryItemSchema)]))
3442
+ }) }), v.pipe(v.array(v.unknown()), v.length(0))]) });
3373
3443
  /**
3374
3444
  * Build an XQuery string to fetch property values from the OCHRE API
3375
3445
  * @param params - The parameters for the fetch
@@ -3608,7 +3678,7 @@ return (${returnedSequences.join(", ")})
3608
3678
  async function fetchSetPropertyValues(params, options) {
3609
3679
  try {
3610
3680
  if (options?.version != null && options.version !== 2) throw new Error("Set property value queries only support API version 2");
3611
- const { setScopeUuids, belongsToCollectionScopeUuids, queries, attributes, isLimitedToLeafPropertyValues } = setPropertyValuesParamsSchema.parse(params);
3681
+ const { setScopeUuids, belongsToCollectionScopeUuids, queries, attributes, isLimitedToLeafPropertyValues } = v.parse(setPropertyValuesParamsSchema, params);
3612
3682
  const propertyVariableUuids = getPropertyVariableUuidsFromQueries(queries);
3613
3683
  if (propertyVariableUuids.length === 0 && !attributes.bibliographies && !attributes.periods) return {
3614
3684
  propertyValues: [],
@@ -3634,7 +3704,7 @@ async function fetchSetPropertyValues(params, options) {
3634
3704
  });
3635
3705
  if (!response.ok) throw new Error(`OCHRE API responded with status: ${response.status}`);
3636
3706
  const data = await response.json();
3637
- const parsedResultRaw = responseSchema.parse(data);
3707
+ const parsedResultRaw = v.parse(responseSchema, data);
3638
3708
  const parsedPropertyValues = [];
3639
3709
  const parsedAttributeValues = [];
3640
3710
  if (!Array.isArray(parsedResultRaw.result)) {
@@ -4103,9 +4173,9 @@ function parseResponsiveCssStyles(properties) {
4103
4173
  * @returns Parsed bounds object
4104
4174
  */
4105
4175
  function parseBounds(bounds) {
4106
- const result = boundsSchema.safeParse(bounds);
4107
- if (!result.success) throw new Error(`Invalid bounds: ${result.error.message}`);
4108
- return result.data;
4176
+ const result = v.safeParse(boundsSchema, bounds);
4177
+ if (!result.success) throw new Error(`Invalid bounds: ${result.issues.map((issue) => issue.message).join(", ")}`);
4178
+ return result.output;
4109
4179
  }
4110
4180
  /**
4111
4181
  * Parses all context option arrays from an options object.
@@ -4181,7 +4251,8 @@ function parseStylesheets(styles) {
4181
4251
  */
4182
4252
  function parseWebElementProperties(componentProperty, elementResource) {
4183
4253
  const unparsedComponentName = componentProperty.values[0].content;
4184
- const { data: componentName } = componentSchema.safeParse(unparsedComponentName);
4254
+ const componentNameResult = v.safeParse(componentSchema, unparsedComponentName);
4255
+ const componentName = componentNameResult.success ? componentNameResult.output : void 0;
4185
4256
  let properties = null;
4186
4257
  const links = elementResource.links ? parseLinks(ensureArray(elementResource.links)) : [];
4187
4258
  switch (componentName) {
@@ -5436,11 +5507,11 @@ function parseApiVersionSuffix(abbreviation) {
5436
5507
  abbreviation,
5437
5508
  version: 2
5438
5509
  };
5439
- const result = apiVersionSuffixSchema.safeParse(abbreviation.slice(-3));
5510
+ const result = v.safeParse(apiVersionSuffixSchema, abbreviation.slice(-3));
5440
5511
  if (!result.success) throw new Error("Invalid API version suffix");
5441
5512
  return {
5442
- abbreviation: abbreviation.replace(`-v${result.data}`, ""),
5443
- version: result.data
5513
+ abbreviation: abbreviation.replace(`-v${result.output}`, ""),
5514
+ version: result.output
5444
5515
  };
5445
5516
  }
5446
5517
  /**
@@ -5495,4 +5566,4 @@ async function fetchWebsite(abbreviation, options) {
5495
5566
  }
5496
5567
  }
5497
5568
  //#endregion
5498
- export { DEFAULT_API_VERSION, DEFAULT_PAGE_SIZE, fetchGallery, fetchItem, fetchSetItems, fetchSetPropertyValues, fetchWebsite, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByLabel, getPropertyByLabelAndValue, getPropertyByLabelAndValueContent, getPropertyByLabelAndValueContents, getPropertyByLabelAndValues, getPropertyByUuid, getPropertyValueByLabel, getPropertyValueByUuid, getPropertyValueContentByLabel, getPropertyValueContentByUuid, getPropertyValueContentsByUuid, getPropertyValuesByLabel, getPropertyValuesByUuid, getUniqueProperties, getUniquePropertyLabels };
5569
+ export { DEFAULT_API_VERSION, DEFAULT_PAGE_SIZE, fetchGallery, fetchItem, fetchItemLinks, fetchSetItems, fetchSetPropertyValues, fetchWebsite, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByLabel, getPropertyByLabelAndValue, getPropertyByLabelAndValueContent, getPropertyByLabelAndValueContents, getPropertyByLabelAndValues, getPropertyByUuid, getPropertyValueByLabel, getPropertyValueByUuid, getPropertyValueContentByLabel, getPropertyValueContentByUuid, getPropertyValueContentsByUuid, getPropertyValuesByLabel, getPropertyValuesByUuid, getUniqueProperties, getUniquePropertyLabels };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ochre-sdk",
3
- "version": "0.22.21",
3
+ "version": "0.22.23",
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",
@@ -46,13 +46,13 @@
46
46
  "@date-fns/utc": "^2.1.1",
47
47
  "date-fns": "^4.1.0",
48
48
  "fast-equals": "^6.0.0",
49
- "zod": "^4.4.1"
49
+ "valibot": "^1.3.1"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@antfu/eslint-config": "^8.2.0",
53
53
  "@types/node": "^24.12.2",
54
54
  "bumpp": "^11.0.1",
55
- "eslint": "^10.2.1",
55
+ "eslint": "^10.3.0",
56
56
  "prettier": "^3.8.3",
57
57
  "tsdown": "^0.21.10",
58
58
  "typescript": "^6.0.3",