ochre-sdk 0.22.22 → 0.22.24
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 +1 -0
- package/dist/index.mjs +187 -206
- package/package.json +8 -8
package/dist/index.d.mts
CHANGED
|
@@ -864,6 +864,7 @@ type Website = {
|
|
|
864
864
|
properties: {
|
|
865
865
|
type: WebsiteType;
|
|
866
866
|
status: "development" | "preview" | "production";
|
|
867
|
+
versionLabel: "experimental" | "alpha" | "beta" | "test" | "staging" | "pre-release" | "release";
|
|
867
868
|
privacy: "public" | "password" | "private";
|
|
868
869
|
contact: {
|
|
869
870
|
name: string;
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
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 (
|
|
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 =
|
|
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.
|
|
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 =
|
|
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.
|
|
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) =>
|
|
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
|
|
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) =>
|
|
472
|
-
if (categories.some((result) => !result.success)) throw new Error(`Invalid OCHRE data; found unexpected keys: ${categories.filter((result) => !result.success).
|
|
473
|
-
return categories.filter((result) => result.success).map((result) => result.
|
|
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 =
|
|
609
|
-
const fakeStringSchema =
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
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 =
|
|
615
|
-
content:
|
|
616
|
-
rend:
|
|
617
|
-
whitespace:
|
|
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 =
|
|
624
|
-
string:
|
|
627
|
+
const richTextStringSchema = v.object({
|
|
628
|
+
string: v.union([
|
|
625
629
|
fakeStringSchema,
|
|
626
630
|
richTextStringContentSchema,
|
|
627
|
-
|
|
631
|
+
v.array(richTextStringContentSchema)
|
|
628
632
|
]),
|
|
629
|
-
lang:
|
|
633
|
+
lang: v.optional(v.string())
|
|
630
634
|
});
|
|
631
|
-
|
|
632
|
-
label:
|
|
633
|
-
abbreviation:
|
|
634
|
-
code:
|
|
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
|
-
|
|
637
|
-
|
|
638
|
-
filter:
|
|
639
|
-
start:
|
|
640
|
-
limit:
|
|
641
|
-
})
|
|
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 =
|
|
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 =
|
|
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
|
-
],
|
|
677
|
+
], "Invalid component");
|
|
674
678
|
/**
|
|
675
679
|
* Schema for validating data categories
|
|
676
680
|
* @internal
|
|
677
681
|
*/
|
|
678
|
-
const categorySchema =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
735
|
-
const trimmed =
|
|
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
|
-
|
|
738
|
-
|
|
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
|
-
|
|
748
|
-
|
|
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
|
-
}).
|
|
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 =
|
|
760
|
-
|
|
761
|
-
target:
|
|
762
|
-
propertyVariable:
|
|
763
|
-
dataType:
|
|
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:
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
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:
|
|
786
|
-
value:
|
|
787
|
-
from:
|
|
788
|
-
to:
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
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:
|
|
798
|
-
value:
|
|
799
|
-
from:
|
|
800
|
-
to:
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
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:
|
|
810
|
-
value:
|
|
811
|
-
from:
|
|
812
|
-
to:
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
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:
|
|
846
|
-
|
|
847
|
-
|
|
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 =
|
|
829
|
+
const setQuerySchema = v.lazy(() => v.union([
|
|
853
830
|
setQueryLeafSchema,
|
|
854
|
-
|
|
855
|
-
|
|
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 =
|
|
858
|
-
const setItemsSortSchema =
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
target:
|
|
862
|
-
direction:
|
|
863
|
-
language:
|
|
864
|
-
})
|
|
865
|
-
|
|
866
|
-
target:
|
|
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:
|
|
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:
|
|
879
|
-
language:
|
|
880
|
-
})
|
|
881
|
-
])
|
|
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 =
|
|
887
|
-
setScopeUuids:
|
|
888
|
-
belongsToCollectionScopeUuids:
|
|
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:
|
|
891
|
-
bibliographies:
|
|
892
|
-
periods:
|
|
893
|
-
})
|
|
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:
|
|
874
|
+
isLimitedToLeafPropertyValues: defaultBoolean(false)
|
|
898
875
|
});
|
|
899
|
-
const setItemsParamsSchema =
|
|
900
|
-
setScopeUuids:
|
|
901
|
-
belongsToCollectionScopeUuids:
|
|
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:
|
|
905
|
-
pageSize:
|
|
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
|
|
1356
|
-
if (
|
|
1357
|
-
parsedType =
|
|
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 =
|
|
1964
|
+
const galleryParamsSchema = v.object({
|
|
1988
1965
|
uuid: uuidSchema,
|
|
1989
|
-
filter:
|
|
1990
|
-
page:
|
|
1991
|
-
pageSize:
|
|
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 } =
|
|
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}'))]
|
|
@@ -2142,7 +2119,7 @@ async function fetchItemLinks(uuid, category, itemCategories, options) {
|
|
|
2142
2119
|
async function fetchByUuid(uuid, options) {
|
|
2143
2120
|
try {
|
|
2144
2121
|
const version = options?.version ?? 2;
|
|
2145
|
-
const parsedUuid =
|
|
2122
|
+
const parsedUuid = v.parse(uuidSchema, uuid);
|
|
2146
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="*"`);
|
|
2147
2124
|
if (!response.ok) throw new Error("Failed to fetch OCHRE data");
|
|
2148
2125
|
const dataRaw = await response.json();
|
|
@@ -3244,7 +3221,7 @@ ${itemsClause}
|
|
|
3244
3221
|
async function fetchSetItems(params, itemCategories, options) {
|
|
3245
3222
|
try {
|
|
3246
3223
|
if (options?.version != null && options.version !== 2) throw new Error("Set item queries only support API version 2");
|
|
3247
|
-
const { setScopeUuids, belongsToCollectionScopeUuids, queries, sort, page, pageSize } =
|
|
3224
|
+
const { setScopeUuids, belongsToCollectionScopeUuids, queries, sort, page, pageSize } = v.parse(setItemsParamsSchema, params);
|
|
3248
3225
|
const xquery = buildXQuery$1({
|
|
3249
3226
|
setScopeUuids,
|
|
3250
3227
|
belongsToCollectionScopeUuids,
|
|
@@ -3360,11 +3337,11 @@ function sortAttributeValues(values) {
|
|
|
3360
3337
|
return a.content.localeCompare(b.content);
|
|
3361
3338
|
});
|
|
3362
3339
|
}
|
|
3363
|
-
const countSchema =
|
|
3364
|
-
if (val
|
|
3340
|
+
const countSchema = v.pipe(v.optional(v.union([v.number(), v.string()]), 1), v.transform((val) => {
|
|
3341
|
+
if (val === "") return 1;
|
|
3365
3342
|
const count = Number(val);
|
|
3366
3343
|
return Number.isFinite(count) ? count : 1;
|
|
3367
|
-
});
|
|
3344
|
+
}));
|
|
3368
3345
|
function getPropertyVariableUuidsFromQueries(queries) {
|
|
3369
3346
|
const propertyVariableUuids = /* @__PURE__ */ new Set();
|
|
3370
3347
|
if (queries == null) return [];
|
|
@@ -3399,20 +3376,20 @@ function getItemFilterQueriesFromPropertyValueQueries(queries) {
|
|
|
3399
3376
|
/**
|
|
3400
3377
|
* Schema for a single property value query item in the OCHRE API response
|
|
3401
3378
|
*/
|
|
3402
|
-
const propertyValueQueryItemSchema =
|
|
3403
|
-
uuid:
|
|
3404
|
-
scope:
|
|
3405
|
-
variableUuid:
|
|
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()),
|
|
3406
3383
|
count: countSchema,
|
|
3407
|
-
globalCount:
|
|
3408
|
-
dataType:
|
|
3409
|
-
rawValue:
|
|
3410
|
-
content:
|
|
3384
|
+
globalCount: v.nullish(countSchema),
|
|
3385
|
+
dataType: v.string(),
|
|
3386
|
+
rawValue: v.optional(fakeStringSchema),
|
|
3387
|
+
content: v.optional(v.union([
|
|
3411
3388
|
fakeStringSchema,
|
|
3412
3389
|
richTextStringSchema,
|
|
3413
|
-
|
|
3414
|
-
])
|
|
3415
|
-
}).transform((val) => {
|
|
3390
|
+
v.array(richTextStringSchema)
|
|
3391
|
+
]))
|
|
3392
|
+
}), v.transform((val) => {
|
|
3416
3393
|
const returnValue = {
|
|
3417
3394
|
scope: val.scope,
|
|
3418
3395
|
variableUuid: val.variableUuid != null && val.variableUuid !== "" ? val.variableUuid : null,
|
|
@@ -3446,23 +3423,23 @@ const propertyValueQueryItemSchema = z.object({
|
|
|
3446
3423
|
break;
|
|
3447
3424
|
}
|
|
3448
3425
|
return returnValue;
|
|
3449
|
-
});
|
|
3450
|
-
const attributeValueQueryItemSchema =
|
|
3451
|
-
attributeType:
|
|
3426
|
+
}));
|
|
3427
|
+
const attributeValueQueryItemSchema = v.pipe(v.object({
|
|
3428
|
+
attributeType: v.picklist(["bibliographies", "periods"]),
|
|
3452
3429
|
count: countSchema,
|
|
3453
|
-
content:
|
|
3454
|
-
}).transform((val) => ({
|
|
3430
|
+
content: v.optional(v.string())
|
|
3431
|
+
}), v.transform((val) => ({
|
|
3455
3432
|
attributeType: val.attributeType,
|
|
3456
3433
|
count: val.count,
|
|
3457
3434
|
content: val.content != null && val.content !== "" ? val.content : null
|
|
3458
|
-
}));
|
|
3435
|
+
})));
|
|
3459
3436
|
/**
|
|
3460
3437
|
* Schema for the property values OCHRE API response
|
|
3461
3438
|
*/
|
|
3462
|
-
const responseSchema =
|
|
3463
|
-
propertyValue:
|
|
3464
|
-
attributeValue:
|
|
3465
|
-
}) }),
|
|
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))]) });
|
|
3466
3443
|
/**
|
|
3467
3444
|
* Build an XQuery string to fetch property values from the OCHRE API
|
|
3468
3445
|
* @param params - The parameters for the fetch
|
|
@@ -3701,7 +3678,7 @@ return (${returnedSequences.join(", ")})
|
|
|
3701
3678
|
async function fetchSetPropertyValues(params, options) {
|
|
3702
3679
|
try {
|
|
3703
3680
|
if (options?.version != null && options.version !== 2) throw new Error("Set property value queries only support API version 2");
|
|
3704
|
-
const { setScopeUuids, belongsToCollectionScopeUuids, queries, attributes, isLimitedToLeafPropertyValues } =
|
|
3681
|
+
const { setScopeUuids, belongsToCollectionScopeUuids, queries, attributes, isLimitedToLeafPropertyValues } = v.parse(setPropertyValuesParamsSchema, params);
|
|
3705
3682
|
const propertyVariableUuids = getPropertyVariableUuidsFromQueries(queries);
|
|
3706
3683
|
if (propertyVariableUuids.length === 0 && !attributes.bibliographies && !attributes.periods) return {
|
|
3707
3684
|
propertyValues: [],
|
|
@@ -3727,7 +3704,7 @@ async function fetchSetPropertyValues(params, options) {
|
|
|
3727
3704
|
});
|
|
3728
3705
|
if (!response.ok) throw new Error(`OCHRE API responded with status: ${response.status}`);
|
|
3729
3706
|
const data = await response.json();
|
|
3730
|
-
const parsedResultRaw =
|
|
3707
|
+
const parsedResultRaw = v.parse(responseSchema, data);
|
|
3731
3708
|
const parsedPropertyValues = [];
|
|
3732
3709
|
const parsedAttributeValues = [];
|
|
3733
3710
|
if (!Array.isArray(parsedResultRaw.result)) {
|
|
@@ -4196,9 +4173,9 @@ function parseResponsiveCssStyles(properties) {
|
|
|
4196
4173
|
* @returns Parsed bounds object
|
|
4197
4174
|
*/
|
|
4198
4175
|
function parseBounds(bounds) {
|
|
4199
|
-
const result =
|
|
4200
|
-
if (!result.success) throw new Error(`Invalid bounds: ${result.
|
|
4201
|
-
return result.
|
|
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;
|
|
4202
4179
|
}
|
|
4203
4180
|
/**
|
|
4204
4181
|
* Parses all context option arrays from an options object.
|
|
@@ -4274,7 +4251,8 @@ function parseStylesheets(styles) {
|
|
|
4274
4251
|
*/
|
|
4275
4252
|
function parseWebElementProperties(componentProperty, elementResource) {
|
|
4276
4253
|
const unparsedComponentName = componentProperty.values[0].content;
|
|
4277
|
-
const
|
|
4254
|
+
const componentNameResult = v.safeParse(componentSchema, unparsedComponentName);
|
|
4255
|
+
const componentName = componentNameResult.success ? componentNameResult.output : void 0;
|
|
4278
4256
|
let properties = null;
|
|
4279
4257
|
const links = elementResource.links ? parseLinks(ensureArray(elementResource.links)) : [];
|
|
4280
4258
|
switch (componentName) {
|
|
@@ -5317,11 +5295,14 @@ function parseWebsiteProperties(properties, websiteTree, sidebar) {
|
|
|
5317
5295
|
type ??= "traditional";
|
|
5318
5296
|
let status = getPropertyValueContentByLabel(websiteProperties, "status");
|
|
5319
5297
|
status ??= "development";
|
|
5298
|
+
let versionLabel = getPropertyValueContentByLabel(websiteProperties, "version-label");
|
|
5299
|
+
versionLabel ??= "release";
|
|
5320
5300
|
let privacy = getPropertyValueContentByLabel(websiteProperties, "privacy");
|
|
5321
5301
|
privacy ??= "public";
|
|
5322
5302
|
const returnProperties = {
|
|
5323
5303
|
type,
|
|
5324
5304
|
status,
|
|
5305
|
+
versionLabel,
|
|
5325
5306
|
privacy,
|
|
5326
5307
|
contact: null,
|
|
5327
5308
|
loadingVariant: "spinner",
|
|
@@ -5529,11 +5510,11 @@ function parseApiVersionSuffix(abbreviation) {
|
|
|
5529
5510
|
abbreviation,
|
|
5530
5511
|
version: 2
|
|
5531
5512
|
};
|
|
5532
|
-
const result =
|
|
5513
|
+
const result = v.safeParse(apiVersionSuffixSchema, abbreviation.slice(-3));
|
|
5533
5514
|
if (!result.success) throw new Error("Invalid API version suffix");
|
|
5534
5515
|
return {
|
|
5535
|
-
abbreviation: abbreviation.replace(`-v${result.
|
|
5536
|
-
version: result.
|
|
5516
|
+
abbreviation: abbreviation.replace(`-v${result.output}`, ""),
|
|
5517
|
+
version: result.output
|
|
5537
5518
|
};
|
|
5538
5519
|
}
|
|
5539
5520
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ochre-sdk",
|
|
3
|
-
"version": "0.22.
|
|
3
|
+
"version": "0.22.24",
|
|
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,17 +46,17 @@
|
|
|
46
46
|
"@date-fns/utc": "^2.1.1",
|
|
47
47
|
"date-fns": "^4.1.0",
|
|
48
48
|
"fast-equals": "^6.0.0",
|
|
49
|
-
"
|
|
49
|
+
"valibot": "^1.4.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@antfu/eslint-config": "^
|
|
53
|
-
"@types/node": "^24.12.
|
|
54
|
-
"bumpp": "^11.0
|
|
55
|
-
"eslint": "^10.
|
|
52
|
+
"@antfu/eslint-config": "^9.0.0",
|
|
53
|
+
"@types/node": "^24.12.3",
|
|
54
|
+
"bumpp": "^11.1.0",
|
|
55
|
+
"eslint": "^10.3.0",
|
|
56
56
|
"prettier": "^3.8.3",
|
|
57
|
-
"tsdown": "^0.
|
|
57
|
+
"tsdown": "^0.22.0",
|
|
58
58
|
"typescript": "^6.0.3",
|
|
59
|
-
"vitest": "^4.1.
|
|
59
|
+
"vitest": "^4.1.6"
|
|
60
60
|
},
|
|
61
61
|
"scripts": {
|
|
62
62
|
"dev": "tsdown src/index.ts --watch",
|