ochre-sdk 1.1.2 → 1.1.4

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.
@@ -4,14 +4,14 @@ import { gallerySchema } from "../schemas.mjs";
4
4
  import { parseRequestedLanguages, resolveContentLanguages } from "../parsers/languages.mjs";
5
5
  import { parseGallery } from "../parsers/index.mjs";
6
6
  import { XMLGalleryData } from "../xml/schemas.mjs";
7
- import { compileOchreQuery, stringLiteral } from "../xquery.mjs";
7
+ import { OCHRE_RESPONSE_PADDING, compileOchreQuery, stringLiteral } from "../xquery.mjs";
8
8
  import * as v from "valibot";
9
9
  //#region src/fetchers/gallery.ts
10
10
  function buildXQuery(parameters) {
11
11
  const { uuid, filter, page, perPage } = parameters;
12
12
  const start = (page - 1) * perPage + 1;
13
13
  const filterLiteral = stringLiteral(filter?.trim() ?? "");
14
- return compileOchreQuery({ body: ({ omitSupplemental }) => `<ochre>{
14
+ return compileOchreQuery({ body: ({ omitSupplemental }) => `<ochre>${OCHRE_RESPONSE_PADDING}{
15
15
  for $q in doc()/ochre[@uuid=${stringLiteral(uuid)}]
16
16
  let $filter := ${filterLiteral}
17
17
  let $resources := $q//items/resource
@@ -5,7 +5,7 @@ import { uuidSchema } from "../schemas.mjs";
5
5
  import { parseRequestedLanguages, resolveContentLanguages } from "../parsers/languages.mjs";
6
6
  import { parseLinkedItems } from "../parsers/index.mjs";
7
7
  import { XMLItemLinksData } from "../xml/schemas.mjs";
8
- import { compileOchreQuery, stringLiteral } from "../xquery.mjs";
8
+ import { OCHRE_RESPONSE_PADDING, compileOchreQuery, stringLiteral } from "../xquery.mjs";
9
9
  import * as v from "valibot";
10
10
  //#region src/fetchers/item-children.ts
11
11
  function buildXQuery(uuid, category) {
@@ -49,7 +49,7 @@ let $children :=
49
49
  else if ($category = "resource") then $item/resource
50
50
  else ()
51
51
  return
52
- <ochre>
52
+ <ochre>${OCHRE_RESPONSE_PADDING}
53
53
  <items>{${omitSupplemental("$children")}}</items>
54
54
  </ochre>`
55
55
  });
@@ -5,7 +5,7 @@ import { uuidSchema } from "../schemas.mjs";
5
5
  import { parseRequestedLanguages, resolveContentLanguages } from "../parsers/languages.mjs";
6
6
  import { parseLinkedItems } from "../parsers/index.mjs";
7
7
  import { XMLItemLinksData } from "../xml/schemas.mjs";
8
- import { compileOchreQuery, stringLiteral } from "../xquery.mjs";
8
+ import { OCHRE_RESPONSE_PADDING, compileOchreQuery, stringLiteral } from "../xquery.mjs";
9
9
  import * as v from "valibot";
10
10
  //#region src/fetchers/item-links.ts
11
11
  /**
@@ -24,7 +24,7 @@ function buildXQuery(uuid) {
24
24
  return `if (${ITEM_CATEGORY_ALIASES[category].map((alias) => `$category = ${stringLiteral(alias)}`).join(" or ")}) then fn:collection("ochre/${category}")/ochre/${category}[@uuid = $uuid]`;
25
25
  }).join("\n else ")}
26
26
  else ()`;
27
- return compileOchreQuery({ body: ({ omitSupplemental }) => `<ochre>{let $item-uuid := ${stringLiteral(uuid)}
27
+ return compileOchreQuery({ body: ({ omitSupplemental }) => `<ochre>${OCHRE_RESPONSE_PADDING}{let $item-uuid := ${stringLiteral(uuid)}
28
28
 
29
29
  let $source-items := (
30
30
  ${OCHRE_COLLECTION_CATEGORIES.map((category) => ` fn:collection("ochre/${category}")/ochre[@uuid = $item-uuid]/${category}`).join(",\n")}
@@ -1,7 +1,7 @@
1
1
  import { getErrorOutput } from "../errors.mjs";
2
2
  import { requestOchre } from "./request.mjs";
3
3
  import { itemOcrDataParametersSchema } from "../schemas.mjs";
4
- import { stringLiteral } from "../xquery.mjs";
4
+ import { OCHRE_RESPONSE_PADDING, stringLiteral } from "../xquery.mjs";
5
5
  import { buildOcrWordPath } from "../ocr.mjs";
6
6
  import * as v from "valibot";
7
7
  //#region src/fetchers/item-ocr-data.ts
@@ -62,10 +62,8 @@ function parseOcrStringVertices(value) {
62
62
  * these elements and may serve them in a namespace. A plain `//ocr//string`
63
63
  * name test silently matches nothing in either of those cases.
64
64
  *
65
- * The matches are wrapped in an `<ocrStrings>` element rather than returned
66
- * directly under `<ochre>`: the API collapses an `<ochre>` element that has no
67
- * element children down to a bare `<ochre/>`, which would drop the `found`
68
- * flag and make "no such item" indistinguishable from "no matches".
65
+ * The matches are wrapped in an `<ocrStrings>` element carrying a `found`
66
+ * flag, which tells "no such item" apart from "no matches".
69
67
  * @param parameters - The parameters for the fetch
70
68
  * @param parameters.uuid - The UUID of the OCHRE item to read the OCR layer of
71
69
  * @param parameters.terms - The whitespace-separated search terms to match against, already lowercased for case-insensitive matching
@@ -95,7 +93,7 @@ let $ocrStrings :=
95
93
  height="{string($string/@HEIGHT)}"
96
94
  vertices="{string($string/@VERTICES)}"/>
97
95
 
98
- return <ochre><ocrStrings found="{exists($ochre)}">{$ocrStrings}</ocrStrings></ochre>`;
96
+ return <ochre>${OCHRE_RESPONSE_PADDING}<ocrStrings found="{exists($ochre)}">{$ocrStrings}</ocrStrings></ochre>`;
99
97
  }
100
98
  /**
101
99
  * Fetches and parses the OCR strings of an OCHRE item that match a search value
@@ -5,7 +5,7 @@ import { uuidSchema } from "../schemas.mjs";
5
5
  import { parseRequestedLanguages } from "../parsers/languages.mjs";
6
6
  import { parseItem } from "../parsers/index.mjs";
7
7
  import { XMLData } from "../xml/schemas.mjs";
8
- import { compileOchreQuery, stringLiteral } from "../xquery.mjs";
8
+ import { OCHRE_RESPONSE_PADDING, compileOchreQuery, stringLiteral } from "../xquery.mjs";
9
9
  import { parseWebpageView } from "../parsers/website/index.mjs";
10
10
  import * as v from "valibot";
11
11
  //#region src/fetchers/item.ts
@@ -48,7 +48,7 @@ ${ITEM_CATEGORIES_WITH_EMBEDDED_ITEMS.map((category) => ` $ochre/${category}`).
48
48
  }
49
49
  return compileOchreQuery({ body: ({ omitSupplemental }) => `${letClauses.join("\n")}
50
50
  return
51
- if (empty($ochre)) then ()
51
+ if (empty($ochre)) then <ochre>${OCHRE_RESPONSE_PADDING}</ochre>
52
52
  else element ochre {
53
53
  $ochre/@*,
54
54
  ${omitSupplemental(itemNodesExpression)}
@@ -21,7 +21,7 @@ export type OchreRequestOptions = {
21
21
  * @param parameters.label - What is being decoded, used in failure messages
22
22
  * @param parameters.checkRawData - Guard run against the parsed XML before validation
23
23
  * @returns The validated response, with XML source metadata restored
24
- * @throws When the guard rejects or validation fails
24
+ * @throws When the query failed on the server, the guard rejects, or validation fails
25
25
  * @internal
26
26
  */
27
27
  export declare function decodeOchreResponse<TOutput>(parameters: {
@@ -27,11 +27,12 @@ function resolveSignal(options) {
27
27
  * @param parameters.label - What is being decoded, used in failure messages
28
28
  * @param parameters.checkRawData - Guard run against the parsed XML before validation
29
29
  * @returns The validated response, with XML source metadata restored
30
- * @throws When the guard rejects or validation fails
30
+ * @throws When the query failed on the server, the guard rejects, or validation fails
31
31
  * @internal
32
32
  */
33
33
  function decodeOchreResponse(parameters) {
34
34
  const { xml, schema, label, checkRawData } = parameters;
35
+ if (xml.trim() === "<result><ochre/></result>") throw new Error(`Failed to fetch ${label}: the OCHRE API could not run the query`);
35
36
  const data = xmlParser.parse(xml);
36
37
  checkRawData?.(data);
37
38
  const { success, issues, output } = v.safeParse(schema, data);
@@ -4,7 +4,7 @@ import { parseStringLike } from "../parsers/helpers.mjs";
4
4
  import { parseMetadataLanguages, parseRequestedLanguages, resolveLanguages } from "../parsers/languages.mjs";
5
5
  import { parseIdentification, parseSimplifiedProperties } from "../parsers/index.mjs";
6
6
  import { XMLWebsiteData } from "../xml/schemas.mjs";
7
- import { compileOchreQuery, stringLiteral } from "../xquery.mjs";
7
+ import { OCHRE_RESPONSE_PADDING, compileOchreQuery, stringLiteral } from "../xquery.mjs";
8
8
  import { websitePresentationReader } from "../parsers/website/reader.mjs";
9
9
  import { WEBSITE_WALK_DECLARATIONS } from "../parsers/website/walk.mjs";
10
10
  //#region src/fetchers/website-metadata.ts
@@ -82,7 +82,10 @@ declare function local:matching-pages($resources, $target-slug, $slug-prefix) {
82
82
  return local:matching-pages(
83
83
  local:resource-items($segment/items/resource),
84
84
  $target-slug,
85
- $page-slug
85
+ local:prefix-slug(
86
+ $segment/identification/abbreviation/content/string,
87
+ $page-slug
88
+ )
86
89
  )
87
90
  )
88
91
  };
@@ -115,6 +118,7 @@ return
115
118
  $website/@belongsTo,
116
119
  $website/@publicationDateTime,
117
120
  $website/@languages,
121
+ ${OCHRE_RESPONSE_PADDING},
118
122
  ${omitSupplemental(`(
119
123
  $website/metadata,
120
124
  local:metadata-tree($website/tree[1], $target-slug, "")
@@ -2,7 +2,7 @@ import { getErrorOutput } from "../errors.mjs";
2
2
  import { isOchreJsonAccepted, requestOchre } from "./request.mjs";
3
3
  import { parseLanguages } from "../parsers/languages.mjs";
4
4
  import { XMLWebsiteData } from "../xml/schemas.mjs";
5
- import { compileOchreQuery, stringLiteral } from "../xquery.mjs";
5
+ import { OCHRE_RESPONSE_PADDING, compileOchreQuery, stringLiteral } from "../xquery.mjs";
6
6
  import { parseWebsite } from "../parsers/website/index.mjs";
7
7
  //#region src/fetchers/website.ts
8
8
  async function areWebsiteCredentialsValid(uuid, credentials, options) {
@@ -26,8 +26,10 @@ async function areWebsiteCredentialsValid(uuid, credentials, options) {
26
26
  * @returns An XQuery string
27
27
  */
28
28
  function buildXQuery(abbreviation) {
29
- return compileOchreQuery({ body: ({ omitSupplemental }) => `for $ochre in collection("ochre/tree")/ochre[tree/identification/abbreviation/content/string = ${stringLiteral(abbreviation)}]
30
- return element ochre { $ochre/@*, ${omitSupplemental("$ochre/node()")} }` });
29
+ return compileOchreQuery({ body: ({ omitSupplemental }) => `let $ochre := collection("ochre/tree")/ochre[tree/identification/abbreviation/content/string = ${stringLiteral(abbreviation)}][1]
30
+ return
31
+ if (empty($ochre)) then <ochre>${OCHRE_RESPONSE_PADDING}</ochre>
32
+ else element ochre { $ochre/@*, ${omitSupplemental("$ochre/node()")} }` });
31
33
  }
32
34
  /**
33
35
  * Fetches and parses a website configuration from the OCHRE API.
@@ -56,8 +56,11 @@ export declare function childSlugPrefix(pageSlug: string, slugPrefix: string | u
56
56
  * The XQuery counterpart of {@link cleanWebsitePageSlug},
57
57
  * {@link prefixSlug} and {@link childSlugPrefix}
58
58
  *
59
- * Declares `local:clean-slug`, `local:page-slug` and
59
+ * Declares `local:clean-slug`, `local:prefix-slug`, `local:page-slug` and
60
60
  * `local:page-child-slug-prefix`. "No prefix" is the empty string here.
61
+ * `local:prefix-slug` takes a slug value rather than a resource, because a
62
+ * segment's own slug comes from its abbreviation instead of a `@slug`
63
+ * attribute.
61
64
  * @internal
62
65
  */
63
66
  export declare const WEBSITE_PAGE_SLUG_DECLARATIONS: string;
@@ -57,20 +57,27 @@ function childSlugPrefix(pageSlug, slugPrefix) {
57
57
  * The XQuery counterpart of {@link cleanWebsitePageSlug},
58
58
  * {@link prefixSlug} and {@link childSlugPrefix}
59
59
  *
60
- * Declares `local:clean-slug`, `local:page-slug` and
60
+ * Declares `local:clean-slug`, `local:prefix-slug`, `local:page-slug` and
61
61
  * `local:page-child-slug-prefix`. "No prefix" is the empty string here.
62
+ * `local:prefix-slug` takes a slug value rather than a resource, because a
63
+ * segment's own slug comes from its abbreviation instead of a `@slug`
64
+ * attribute.
62
65
  * @internal
63
66
  */
64
67
  const WEBSITE_PAGE_SLUG_DECLARATIONS = `declare function local:clean-slug($slug) {
65
68
  replace(string($slug), ${stringLiteral(SEGMENT_UNIQUE_SLUG_PREFIX_PATTERN)}, "")
66
69
  };
67
70
 
68
- declare function local:page-slug($resource, $slug-prefix) {
69
- let $slug := local:clean-slug($resource/@slug)
71
+ declare function local:prefix-slug($slug, $slug-prefix) {
72
+ let $slug-string := string(($slug)[1])
70
73
  return
71
- if ($slug-prefix = "") then $slug
72
- else if ($slug = "") then $slug-prefix
73
- else concat($slug-prefix, ${stringLiteral("/")}, $slug)
74
+ if ($slug-prefix = "") then $slug-string
75
+ else if ($slug-string = "") then $slug-prefix
76
+ else concat($slug-prefix, ${stringLiteral("/")}, $slug-string)
77
+ };
78
+
79
+ declare function local:page-slug($resource, $slug-prefix) {
80
+ local:prefix-slug(local:clean-slug($resource/@slug), $slug-prefix)
74
81
  };
75
82
 
76
83
  declare function local:page-child-slug-prefix($resource, $slug-prefix) {
package/dist/query.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { BELONGS_TO_COLLECTION_UUID } from "./constants.mjs";
2
- import { compileOchreQuery, stringLiteral } from "./xquery.mjs";
2
+ import { OCHRE_RESPONSE_PADDING, compileOchreQuery, stringLiteral } from "./xquery.mjs";
3
3
  import { OCR_WORD_CONTENT_ATTRIBUTE, OCR_WORD_QNAMES, buildOcrWordPath } from "./ocr.mjs";
4
4
  //#region src/query.ts
5
5
  const CTS_INCLUDES_STOP_WORDS = /* @__PURE__ */ new Set([
@@ -517,13 +517,15 @@ function buildOcrValueQueryExpression(parameters) {
517
517
  })})`;
518
518
  }
519
519
  /**
520
- * Compile an OCR text search into a query over the `<ocr>` layer of a Resource
521
- * document
520
+ * Compile an OCR text search into a query over the `<ocr>` layers of a
521
+ * Resource document
522
522
  *
523
- * Each word node in that layer holds a single OCR word in its `CONTENT`
523
+ * Each word node in a layer holds a single OCR word in its `CONTENT`
524
524
  * attribute, so `includes` matches every search term as a word inside that
525
- * attribute anywhere in the layer, and `exact` requires every term to equal a
526
- * whole `CONTENT` value.
525
+ * attribute, and `exact` requires every term to equal a whole `CONTENT` value.
526
+ * A Resource carries one layer per page, so each term is its own element query
527
+ * and the terms may fall on different pages, which is also all the indexes can
528
+ * tell apart.
527
529
  *
528
530
  * The conjunction is only an index narrowing for `exact`. Attribute values
529
531
  * carry no word positions, so `cts:near-query` over them silently degenerates
@@ -533,20 +535,13 @@ function buildOcrValueQueryExpression(parameters) {
533
535
  */
534
536
  function buildOcrQueryExpression(query) {
535
537
  const { value, matchMode, isCaseSensitive } = query;
536
- if (matchMode === "exact") {
537
- const terms = tokenizeOcrExactValue(value);
538
- if (terms.length === 0) return "cts:false-query()";
539
- return buildNestedElementQuery(["ocr"], buildAndCtsQueryExpressionInternal(Array.from(terms, (term) => buildOcrValueQueryExpression({
540
- value: searchValue(term),
541
- isCaseSensitive
542
- }))));
543
- }
544
- const terms = tokenizeIncludesSearchValue({
538
+ const terms = matchMode === "exact" ? tokenizeOcrExactValue(value) : tokenizeIncludesSearchValue({
545
539
  value,
546
540
  isCaseSensitive
547
541
  });
548
542
  if (terms.length === 0) return "cts:false-query()";
549
- return buildNestedElementQuery(["ocr"], buildAndCtsQueryExpressionInternal(Array.from(terms, (term) => buildOcrWordQueryExpression({
543
+ const buildTermQueryExpression = matchMode === "exact" ? buildOcrValueQueryExpression : buildOcrWordQueryExpression;
544
+ return buildAndCtsQueryExpressionInternal(Array.from(terms, (term) => buildNestedElementQuery(["ocr"], buildTermQueryExpression({
550
545
  value: searchValue(term),
551
546
  isCaseSensitive
552
547
  }))));
@@ -592,12 +587,13 @@ function registerOcrBinding(context, query) {
592
587
  const queryExpression = buildOcrQueryExpression(query);
593
588
  const phraseTerms = query.matchMode === "exact" ? tokenizeOcrExactValue(query.value) : [];
594
589
  context.ocrBindingNamesByKey.set(key, name);
595
- const searchExpression = `cts:search(/ochre/resource, ${buildAndCtsQueryExpressionInternal([queryExpression, `cts:document-query(${context.baseItemsExpression}/@uuid/string())`])})`;
590
+ const scopedQueryExpression = buildAndCtsQueryExpressionInternal([queryExpression, `cts:document-query(${context.baseItemsExpression}/@uuid/string())`]);
596
591
  const phraseHelperName = phraseTerms.length > 1 ? registerOcrPhraseHelper(context) : null;
597
592
  context.ocrBindings.push({
598
593
  name,
599
- expression: queryExpression === "cts:false-query()" ? "()" : phraseHelperName == null ? `${searchExpression}/@uuid/string()` : `for $ocrResource in ${searchExpression}
594
+ expression: queryExpression === "cts:false-query()" ? "()" : phraseHelperName != null ? `for $ocrResource in cts:search(/ochre/resource, ${scopedQueryExpression}, "unfiltered")
600
595
  where ${phraseHelperName}($ocrResource, (${phraseTerms.map((term) => stringLiteral(term)).join(", ")}), ${query.isCaseSensitive ? "true()" : "false()"})
596
+ return string($ocrResource/@uuid)` : query.matchMode === "includes" && !query.isCaseSensitive ? `cts:uris((), (), ${scopedQueryExpression})` : `for $ocrResource in cts:search(/ochre/resource, ${scopedQueryExpression})
601
597
  return string($ocrResource/@uuid)`
602
598
  });
603
599
  return name;
@@ -1226,7 +1222,7 @@ function compileContainerItemsQuery(parameters) {
1226
1222
  `declare variable ${scopeVariable} := (${Array.from(scopeUuids, (uuid) => stringLiteral(uuid)).join(", ")});`,
1227
1223
  ...plan.prolog === "" ? [] : [plan.prolog]
1228
1224
  ],
1229
- body: (context) => `<ochre>{
1225
+ body: (context) => `<ochre>${OCHRE_RESPONSE_PADDING}{
1230
1226
  ${plan.itemsClause}
1231
1227
  ${body({
1232
1228
  ...context,
@@ -776,10 +776,22 @@ const XMLWebsiteSegment = v.lazy(() => v.object({
776
776
  uuid: v.pipe(v.string("XMLWebsiteSegment: uuid is string and required"), v.check(isPseudoUuid, "XMLWebsiteSegment: uuid is not a valid pseudo-UUID")),
777
777
  publicationDateTime: v.optional(customDateTime("XMLWebsiteSegment: publicationDateTime is not a valid datetime"))
778
778
  }, "XMLWebsiteSegment: Shape error"));
779
+ /**
780
+ * A website resource item
781
+ *
782
+ * The member order is load-bearing, because a union returns its first match
783
+ * and every member is an object schema, which drops the keys its own shape
784
+ * does not name. {@link XMLWebsiteSegment} goes first: every entry on
785
+ * {@link XMLWebsiteResource} other than `uuid` is optional, so a segment
786
+ * wrapper satisfies that schema too and would come back without its
787
+ * `segments`. {@link XMLWebsiteResourceGroup} goes last for the mirror
788
+ * reason, since a resource holding children satisfies the group shape and
789
+ * would lose its own slug and properties.
790
+ */
779
791
  const XMLWebsiteResourceItem = v.lazy(() => v.union([
792
+ XMLWebsiteSegment,
780
793
  XMLWebsiteResource,
781
- XMLWebsiteResourceGroup,
782
- XMLWebsiteSegment
794
+ XMLWebsiteResourceGroup
783
795
  ]));
784
796
  const XMLWebsiteResource = v.lazy(() => v.object({
785
797
  ...XMLBaseItem.entries,
package/dist/xquery.d.mts CHANGED
@@ -6,6 +6,17 @@
6
6
  * @internal
7
7
  */
8
8
  export declare function stringLiteral(value: string): string;
9
+ /**
10
+ * A comment every query puts inside the `<ochre>` element it returns
11
+ *
12
+ * The API answers a failed query with a bare `<result><ochre/></result>`, and
13
+ * sends the same response whenever the returned `<ochre>` element holds fewer
14
+ * than 25 characters. Padding keeps an empty or not-found result above that
15
+ * cutoff, so the bare response only ever means failure. The XML parser drops
16
+ * comments, so no schema sees it.
17
+ * @internal
18
+ */
19
+ export declare const OCHRE_RESPONSE_PADDING = "<!--ochre-sdk: keeps an empty result distinct from a failed query-->";
9
20
  /**
10
21
  * What a query body can ask the surrounding document for
11
22
  *
package/dist/xquery.mjs CHANGED
@@ -9,6 +9,17 @@ function stringLiteral(value) {
9
9
  return `"${value.replaceAll("\"", "\"\"")}"`;
10
10
  }
11
11
  /**
12
+ * A comment every query puts inside the `<ochre>` element it returns
13
+ *
14
+ * The API answers a failed query with a bare `<result><ochre/></result>`, and
15
+ * sends the same response whenever the returned `<ochre>` element holds fewer
16
+ * than 25 characters. Padding keeps an empty or not-found result above that
17
+ * cutoff, so the bare response only ever means failure. The XML parser drops
18
+ * comments, so no schema sees it.
19
+ * @internal
20
+ */
21
+ const OCHRE_RESPONSE_PADDING = "<!--ochre-sdk: keeps an empty result distinct from a failed query-->";
22
+ /**
12
23
  * XQuery prolog declaring `local:omit-supplemental`, which drops every element
13
24
  * carrying `supplemental="true"` from a node sequence, at any depth.
14
25
  *
@@ -63,4 +74,4 @@ ${body({
63
74
  })}`;
64
75
  }
65
76
  //#endregion
66
- export { compileOchreQuery, stringLiteral };
77
+ export { OCHRE_RESPONSE_PADDING, compileOchreQuery, stringLiteral };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ochre-sdk",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
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",
@@ -45,23 +45,23 @@
45
45
  "dist"
46
46
  ],
47
47
  "dependencies": {
48
- "fast-equals": "^6.0.3",
48
+ "fast-equals": "^6.0.4",
49
49
  "fast-xml-parser": "^5.11.1",
50
50
  "valibot": "^1.5.0"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@antfu/eslint-config": "^9.5.1",
54
- "@types/node": "^24.13.4",
54
+ "@types/node": "^24.13.6",
55
55
  "bumpp": "^12.3.0",
56
- "eslint": "^10.10.0",
57
- "eslint-plugin-erasable-syntax-only": "^0.7.1",
56
+ "eslint": "^10.11.0",
57
+ "eslint-plugin-erasable-syntax-only": "^0.7.2",
58
58
  "eslint-plugin-slop": "^0.1.3",
59
- "eslint-plugin-sonarjs": "^4.2.0",
60
- "knip": "^6.35.1",
61
- "oxfmt": "^0.67.0",
59
+ "eslint-plugin-sonarjs": "^4.2.1",
60
+ "knip": "^6.38.0",
61
+ "oxfmt": "^0.70.0",
62
62
  "tsdown": "^0.23.0",
63
63
  "typescript": "^6.0.3",
64
- "vitest": "^5.0.0"
64
+ "vitest": "^5.0.1"
65
65
  },
66
66
  "scripts": {
67
67
  "dev": "tsdown src/index.ts --watch",